Merged in feature/add-deletes (pull request #214)

support delete for client, document and folder

* support delete

for client, document and folder

* remove batch cancel conflict

not used


Approved-by: Jacob Mathison
This commit is contained in:
Jay Brown
2026-03-04 18:30:13 +00:00
parent 62b5de5722
commit 09c61ea9b4
28 changed files with 3438 additions and 632 deletions
-6
View File
@@ -57,12 +57,6 @@ UPDATE batch_uploads
SET failed_filenames = failed_filenames || jsonb_build_array($2::text)
WHERE id = $1;
-- name: CancelBatchUpload :exec
UPDATE batch_uploads
SET status = 'cancelled',
completed_at = NOW()
WHERE id = $1 AND client_id = $2 AND status = 'processing';
-- name: GetDocumentsByBatchId :many
SELECT id, clientId, hash
FROM documents
+44
View File
@@ -14,6 +14,50 @@ UPDATE clients SET name = $1 WHERE clientId = $2;
-- name: AddClientCanSync :exec
INSERT INTO clientCanSync (canSync, clientId) VALUES ($1, $2);
-- name: GetAllDocumentIDsForClient :many
-- Get all document IDs for a client, used to cascade document deletes during client delete
SELECT id FROM documents WHERE clientId = @client_id;
-- name: DeleteCollectorMinCleanVersions :exec
-- @sqlc-vet-disable
-- Delete collector minimum clean version records for a client
DELETE FROM collectorMinCleanVersions WHERE clientId = @client_id;
-- name: DeleteCollectorActiveVersions :exec
-- @sqlc-vet-disable
-- Delete collector active version records for a client
DELETE FROM collectorActiveVersions WHERE clientId = @client_id;
-- name: DeleteCollectorVersions :exec
-- @sqlc-vet-disable
-- Delete collector version records for a client
DELETE FROM collectorVersions WHERE clientId = @client_id;
-- name: DeleteBatchUploads :exec
-- @sqlc-vet-disable
-- Delete all batch upload records for a client
DELETE FROM batch_uploads WHERE client_id = @client_id;
-- name: DeleteClientCanSync :exec
-- @sqlc-vet-disable
-- Delete clientCanSync records for a client
DELETE FROM clientCanSync WHERE clientId = @client_id;
-- name: DeleteDocumentUploadsForClient :exec
-- @sqlc-vet-disable
-- Delete all documentUploads for a client
DELETE FROM documentUploads WHERE clientId = @client_id;
-- name: DeleteAllFoldersForClient :exec
-- @sqlc-vet-disable
-- Delete all folders for a client. All documents must already be deleted to avoid FK violations.
DELETE FROM folders WHERE clientId = @client_id;
-- name: HardDeleteClient :execrows
-- @sqlc-vet-disable
-- Hard delete the client row itself. Returns the number of rows deleted (0 or 1).
DELETE FROM clients WHERE clientId = @client_id;
-- name: IsClientSynced :one
-- Text extraction has been removed. A client is considered synced when
-- all documents have completed cleaning (clean entry exists OR clean failed).
+48
View File
@@ -72,3 +72,51 @@ SELECT
d.file_size_bytes
FROM documents d
WHERE d.id = $1;
-- name: CollectDocumentS3Paths :many
-- @sqlc-vet-disable
-- Collect S3 bucket+key from documentEntries before deleting, for logging orphaned S3 objects
SELECT de.bucket, de.key FROM documentEntries de WHERE de.documentId = @document_id;
-- name: DeleteDocumentFieldExtractionArrayFields :exec
-- @sqlc-vet-disable
-- Delete array fields for all field extractions belonging to this document
DELETE FROM documentFieldExtractionArrayFields
WHERE fieldExtractionId IN (
SELECT id FROM documentFieldExtractions WHERE documentId = @document_id
);
-- name: DeleteDocumentFieldExtractionVersions :exec
-- @sqlc-vet-disable
-- Delete version entries for all field extractions belonging to this document
DELETE FROM documentFieldExtractionVersions
WHERE documentId = @document_id;
-- name: DeleteDocumentFieldExtractions :exec
-- @sqlc-vet-disable
-- Delete field extraction records for this document
DELETE FROM documentFieldExtractions WHERE documentId = @document_id;
-- name: DeleteDocumentCleanEntries :exec
-- @sqlc-vet-disable
-- Delete clean entries for all cleans belonging to this document
DELETE FROM documentCleanEntries
WHERE cleanId IN (
SELECT id FROM documentCleans WHERE documentId = @document_id
);
-- name: DeleteDocumentCleans :exec
-- @sqlc-vet-disable
-- Delete clean records for this document
DELETE FROM documentCleans WHERE documentId = @document_id;
-- name: DeleteDocumentEntries :exec
-- @sqlc-vet-disable
-- Delete S3 entry records for this document
DELETE FROM documentEntries WHERE documentId = @document_id;
-- name: HardDeleteDocument :execrows
-- @sqlc-vet-disable
-- Hard delete the document row itself. Returns the number of rows deleted (0 or 1).
-- documentLabels are removed automatically via ON DELETE CASCADE.
DELETE FROM documents WHERE id = @document_id;
+53
View File
@@ -100,3 +100,56 @@ SELECT
FROM documents d
WHERE d.folderId = $1
ORDER BY d.id;
-- name: GetFolderTreeIDs :many
-- Get all folder IDs in a folder tree (recursive) for cascade delete operations
WITH RECURSIVE folder_tree AS (
SELECT id, path FROM folders WHERE id = @folder_id
UNION ALL
SELECT f.id, f.path FROM folders f
JOIN folder_tree ft ON f.parentId = ft.id
)
SELECT id, path FROM folder_tree;
-- name: CountDocumentsInFolderTree :one
-- Count documents in a folder tree to check before deletion without include_documents
WITH RECURSIVE folder_tree AS (
SELECT id FROM folders WHERE id = @folder_id
UNION ALL
SELECT f.id FROM folders f
JOIN folder_tree ft ON f.parentId = ft.id
)
SELECT COUNT(*) FROM documents WHERE folderId IN (SELECT id FROM folder_tree);
-- name: GetDocumentIDsInFolderTree :many
-- Get all document IDs in a folder tree for cascade deletion
WITH RECURSIVE folder_tree AS (
SELECT id FROM folders WHERE id = @folder_id
UNION ALL
SELECT f.id FROM folders f
JOIN folder_tree ft ON f.parentId = ft.id
)
SELECT id FROM documents WHERE folderId IN (SELECT id FROM folder_tree);
-- name: DeleteDocumentUploadsInFolderTree :exec
-- @sqlc-vet-disable
-- Delete documentUploads rows that reference folders in the tree
WITH RECURSIVE folder_tree AS (
SELECT id FROM folders WHERE id = @folder_id
UNION ALL
SELECT f.id FROM folders f
JOIN folder_tree ft ON f.parentId = ft.id
)
DELETE FROM documentUploads WHERE folder_id IN (SELECT id FROM folder_tree);
-- name: HardDeleteFolderTree :execrows
-- @sqlc-vet-disable
-- Delete all folders in the tree. PostgreSQL handles ordering within the CTE.
-- Returns the number of rows deleted.
WITH RECURSIVE folder_tree AS (
SELECT id FROM folders WHERE id = @folder_id
UNION ALL
SELECT f.id FROM folders f
JOIN folder_tree ft ON f.parentId = ft.id
)
DELETE FROM folders WHERE id IN (SELECT id FROM folder_tree);
-23
View File
@@ -33,29 +33,6 @@ func (q *Queries) AddFailedFilename(ctx context.Context, arg *AddFailedFilenameP
return err
}
const cancelBatchUpload = `-- name: CancelBatchUpload :exec
UPDATE batch_uploads
SET status = 'cancelled',
completed_at = NOW()
WHERE id = $1 AND client_id = $2 AND status = 'processing'
`
type CancelBatchUploadParams struct {
ID uuid.UUID `db:"id"`
ClientID string `db:"client_id"`
}
// CancelBatchUpload
//
// UPDATE batch_uploads
// SET status = 'cancelled',
// completed_at = NOW()
// WHERE id = $1 AND client_id = $2 AND status = 'processing'
func (q *Queries) CancelBatchUpload(ctx context.Context, arg *CancelBatchUploadParams) error {
_, err := q.db.Exec(ctx, cancelBatchUpload, arg.ID, arg.ClientID)
return err
}
const countDocumentsByBatchId = `-- name: CountDocumentsByBatchId :one
SELECT COUNT(*) as count
FROM documents
@@ -264,47 +264,6 @@ func TestBatchUpload(t *testing.T) {
assert.Contains(t, failedFilenamesStr, "document2.pdf")
})
t.Run("CancelBatchUpload", func(t *testing.T) {
t.Parallel()
ctx := t.Context()
cfg := &serviceconfig.BaseConfig{}
test.CreateDB(t, cfg)
queries := cfg.GetDBQueries()
// Create a client
clientID := fmt.Sprintf("TEST_CLIENT_CANCEL_%s", uuid.New().String()[:8])
err := queries.CreateClient(ctx, &repository.CreateClientParams{
Name: fmt.Sprintf("Test Client Cancel %s", uuid.New().String()[:8]),
Clientid: clientID,
})
require.NoError(t, err)
// Create batch upload
batchID, err := queries.CreateBatchUpload(ctx, &repository.CreateBatchUploadParams{
ClientID: clientID,
OriginalFilename: "cancel.zip",
TotalDocuments: 10,
})
require.NoError(t, err)
// Cancel batch upload
err = queries.CancelBatchUpload(ctx, &repository.CancelBatchUploadParams{
ID: batchID,
ClientID: clientID,
})
require.NoError(t, err)
// Verify cancellation
batch, err := queries.GetBatchUpload(ctx, &repository.GetBatchUploadParams{
ID: batchID,
ClientID: clientID,
})
require.NoError(t, err)
assert.Equal(t, repository.BatchStatusCancelled, batch.Status)
assert.True(t, batch.CompletedAt.Valid)
})
t.Run("GetDocumentsByBatchId", func(t *testing.T) {
t.Parallel()
ctx := t.Context()
+136
View File
@@ -7,6 +7,8 @@ package repository
import (
"context"
"github.com/google/uuid"
)
const addClientCanSync = `-- name: AddClientCanSync :exec
@@ -43,6 +45,124 @@ func (q *Queries) CreateClient(ctx context.Context, arg *CreateClientParams) err
return err
}
const deleteAllFoldersForClient = `-- name: DeleteAllFoldersForClient :exec
DELETE FROM folders WHERE clientId = $1
`
// @sqlc-vet-disable
// Delete all folders for a client. All documents must already be deleted to avoid FK violations.
//
// DELETE FROM folders WHERE clientId = $1
func (q *Queries) DeleteAllFoldersForClient(ctx context.Context, clientID string) error {
_, err := q.db.Exec(ctx, deleteAllFoldersForClient, clientID)
return err
}
const deleteBatchUploads = `-- name: DeleteBatchUploads :exec
DELETE FROM batch_uploads WHERE client_id = $1
`
// @sqlc-vet-disable
// Delete all batch upload records for a client
//
// DELETE FROM batch_uploads WHERE client_id = $1
func (q *Queries) DeleteBatchUploads(ctx context.Context, clientID string) error {
_, err := q.db.Exec(ctx, deleteBatchUploads, clientID)
return err
}
const deleteClientCanSync = `-- name: DeleteClientCanSync :exec
DELETE FROM clientCanSync WHERE clientId = $1
`
// @sqlc-vet-disable
// Delete clientCanSync records for a client
//
// DELETE FROM clientCanSync WHERE clientId = $1
func (q *Queries) DeleteClientCanSync(ctx context.Context, clientID string) error {
_, err := q.db.Exec(ctx, deleteClientCanSync, clientID)
return err
}
const deleteCollectorActiveVersions = `-- name: DeleteCollectorActiveVersions :exec
DELETE FROM collectorActiveVersions WHERE clientId = $1
`
// @sqlc-vet-disable
// Delete collector active version records for a client
//
// DELETE FROM collectorActiveVersions WHERE clientId = $1
func (q *Queries) DeleteCollectorActiveVersions(ctx context.Context, clientID string) error {
_, err := q.db.Exec(ctx, deleteCollectorActiveVersions, clientID)
return err
}
const deleteCollectorMinCleanVersions = `-- name: DeleteCollectorMinCleanVersions :exec
DELETE FROM collectorMinCleanVersions WHERE clientId = $1
`
// @sqlc-vet-disable
// Delete collector minimum clean version records for a client
//
// DELETE FROM collectorMinCleanVersions WHERE clientId = $1
func (q *Queries) DeleteCollectorMinCleanVersions(ctx context.Context, clientID string) error {
_, err := q.db.Exec(ctx, deleteCollectorMinCleanVersions, clientID)
return err
}
const deleteCollectorVersions = `-- name: DeleteCollectorVersions :exec
DELETE FROM collectorVersions WHERE clientId = $1
`
// @sqlc-vet-disable
// Delete collector version records for a client
//
// DELETE FROM collectorVersions WHERE clientId = $1
func (q *Queries) DeleteCollectorVersions(ctx context.Context, clientID string) error {
_, err := q.db.Exec(ctx, deleteCollectorVersions, clientID)
return err
}
const deleteDocumentUploadsForClient = `-- name: DeleteDocumentUploadsForClient :exec
DELETE FROM documentUploads WHERE clientId = $1
`
// @sqlc-vet-disable
// Delete all documentUploads for a client
//
// DELETE FROM documentUploads WHERE clientId = $1
func (q *Queries) DeleteDocumentUploadsForClient(ctx context.Context, clientID string) error {
_, err := q.db.Exec(ctx, deleteDocumentUploadsForClient, clientID)
return err
}
const getAllDocumentIDsForClient = `-- name: GetAllDocumentIDsForClient :many
SELECT id FROM documents WHERE clientId = $1
`
// Get all document IDs for a client, used to cascade document deletes during client delete
//
// SELECT id FROM documents WHERE clientId = $1
func (q *Queries) GetAllDocumentIDsForClient(ctx context.Context, clientID string) ([]uuid.UUID, error) {
rows, err := q.db.Query(ctx, getAllDocumentIDsForClient, clientID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []uuid.UUID{}
for rows.Next() {
var id uuid.UUID
if err := rows.Scan(&id); err != nil {
return nil, err
}
items = append(items, id)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getClient = `-- name: GetClient :one
SELECT clientid, name, cansync FROM fullClients WHERE clientId = $1
`
@@ -57,6 +177,22 @@ func (q *Queries) GetClient(ctx context.Context, clientid string) (*Fullclient,
return &i, err
}
const hardDeleteClient = `-- name: HardDeleteClient :execrows
DELETE FROM clients WHERE clientId = $1
`
// @sqlc-vet-disable
// Hard delete the client row itself. Returns the number of rows deleted (0 or 1).
//
// DELETE FROM clients WHERE clientId = $1
func (q *Queries) HardDeleteClient(ctx context.Context, clientID string) (int64, error) {
result, err := q.db.Exec(ctx, hardDeleteClient, clientID)
if err != nil {
return 0, err
}
return result.RowsAffected(), nil
}
const isClientSynced = `-- name: IsClientSynced :one
WITH
docs AS (
@@ -64,6 +64,39 @@ func (q *Queries) AddDocumentUpload(ctx context.Context, arg *AddDocumentUploadP
return err
}
const collectDocumentS3Paths = `-- name: CollectDocumentS3Paths :many
SELECT de.bucket, de.key FROM documentEntries de WHERE de.documentId = $1
`
type CollectDocumentS3PathsRow struct {
Bucket string `db:"bucket"`
Key string `db:"key"`
}
// @sqlc-vet-disable
// Collect S3 bucket+key from documentEntries before deleting, for logging orphaned S3 objects
//
// SELECT de.bucket, de.key FROM documentEntries de WHERE de.documentId = $1
func (q *Queries) CollectDocumentS3Paths(ctx context.Context, documentID uuid.UUID) ([]*CollectDocumentS3PathsRow, error) {
rows, err := q.db.Query(ctx, collectDocumentS3Paths, documentID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []*CollectDocumentS3PathsRow{}
for rows.Next() {
var i CollectDocumentS3PathsRow
if err := rows.Scan(&i.Bucket, &i.Key); err != nil {
return nil, err
}
items = append(items, &i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const createDocument = `-- name: CreateDocument :one
INSERT INTO documents (clientId, hash, batch_id, filename, folderId, originalPath, file_size_bytes) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING id
`
@@ -96,6 +129,98 @@ func (q *Queries) CreateDocument(ctx context.Context, arg *CreateDocumentParams)
return id, err
}
const deleteDocumentCleanEntries = `-- name: DeleteDocumentCleanEntries :exec
DELETE FROM documentCleanEntries
WHERE cleanId IN (
SELECT id FROM documentCleans WHERE documentId = $1
)
`
// @sqlc-vet-disable
// Delete clean entries for all cleans belonging to this document
//
// DELETE FROM documentCleanEntries
// WHERE cleanId IN (
// SELECT id FROM documentCleans WHERE documentId = $1
// )
func (q *Queries) DeleteDocumentCleanEntries(ctx context.Context, documentID uuid.UUID) error {
_, err := q.db.Exec(ctx, deleteDocumentCleanEntries, documentID)
return err
}
const deleteDocumentCleans = `-- name: DeleteDocumentCleans :exec
DELETE FROM documentCleans WHERE documentId = $1
`
// @sqlc-vet-disable
// Delete clean records for this document
//
// DELETE FROM documentCleans WHERE documentId = $1
func (q *Queries) DeleteDocumentCleans(ctx context.Context, documentID uuid.UUID) error {
_, err := q.db.Exec(ctx, deleteDocumentCleans, documentID)
return err
}
const deleteDocumentEntries = `-- name: DeleteDocumentEntries :exec
DELETE FROM documentEntries WHERE documentId = $1
`
// @sqlc-vet-disable
// Delete S3 entry records for this document
//
// DELETE FROM documentEntries WHERE documentId = $1
func (q *Queries) DeleteDocumentEntries(ctx context.Context, documentID uuid.UUID) error {
_, err := q.db.Exec(ctx, deleteDocumentEntries, documentID)
return err
}
const deleteDocumentFieldExtractionArrayFields = `-- name: DeleteDocumentFieldExtractionArrayFields :exec
DELETE FROM documentFieldExtractionArrayFields
WHERE fieldExtractionId IN (
SELECT id FROM documentFieldExtractions WHERE documentId = $1
)
`
// @sqlc-vet-disable
// Delete array fields for all field extractions belonging to this document
//
// DELETE FROM documentFieldExtractionArrayFields
// WHERE fieldExtractionId IN (
// SELECT id FROM documentFieldExtractions WHERE documentId = $1
// )
func (q *Queries) DeleteDocumentFieldExtractionArrayFields(ctx context.Context, documentID uuid.UUID) error {
_, err := q.db.Exec(ctx, deleteDocumentFieldExtractionArrayFields, documentID)
return err
}
const deleteDocumentFieldExtractionVersions = `-- name: DeleteDocumentFieldExtractionVersions :exec
DELETE FROM documentFieldExtractionVersions
WHERE documentId = $1
`
// @sqlc-vet-disable
// Delete version entries for all field extractions belonging to this document
//
// DELETE FROM documentFieldExtractionVersions
// WHERE documentId = $1
func (q *Queries) DeleteDocumentFieldExtractionVersions(ctx context.Context, documentID uuid.UUID) error {
_, err := q.db.Exec(ctx, deleteDocumentFieldExtractionVersions, documentID)
return err
}
const deleteDocumentFieldExtractions = `-- name: DeleteDocumentFieldExtractions :exec
DELETE FROM documentFieldExtractions WHERE documentId = $1
`
// @sqlc-vet-disable
// Delete field extraction records for this document
//
// DELETE FROM documentFieldExtractions WHERE documentId = $1
func (q *Queries) DeleteDocumentFieldExtractions(ctx context.Context, documentID uuid.UUID) error {
_, err := q.db.Exec(ctx, deleteDocumentFieldExtractions, documentID)
return err
}
const getDocumentEnriched = `-- name: GetDocumentEnriched :one
SELECT
d.id,
@@ -334,6 +459,23 @@ func (q *Queries) GetDocumentUploadCurrentPart(ctx context.Context, arg *GetDocu
return &i, err
}
const hardDeleteDocument = `-- name: HardDeleteDocument :execrows
DELETE FROM documents WHERE id = $1
`
// @sqlc-vet-disable
// Hard delete the document row itself. Returns the number of rows deleted (0 or 1).
// documentLabels are removed automatically via ON DELETE CASCADE.
//
// DELETE FROM documents WHERE id = $1
func (q *Queries) HardDeleteDocument(ctx context.Context, documentID uuid.UUID) (int64, error) {
result, err := q.db.Exec(ctx, hardDeleteDocument, documentID)
if err != nil {
return 0, err
}
return result.RowsAffected(), nil
}
const listDocumentIDsBatch = `-- name: ListDocumentIDsBatch :many
SELECT id, totalCount FROM listDocumentIDs($1, $2, $3)
`
+163
View File
@@ -28,6 +28,32 @@ func (q *Queries) CountDocumentsByFolder(ctx context.Context, folderid *uuid.UUI
return total, err
}
const countDocumentsInFolderTree = `-- name: CountDocumentsInFolderTree :one
WITH RECURSIVE folder_tree AS (
SELECT id FROM folders WHERE id = $1
UNION ALL
SELECT f.id FROM folders f
JOIN folder_tree ft ON f.parentId = ft.id
)
SELECT COUNT(*) FROM documents WHERE folderId IN (SELECT id FROM folder_tree)
`
// Count documents in a folder tree to check before deletion without include_documents
//
// WITH RECURSIVE folder_tree AS (
// SELECT id FROM folders WHERE id = $1
// UNION ALL
// SELECT f.id FROM folders f
// JOIN folder_tree ft ON f.parentId = ft.id
// )
// SELECT COUNT(*) FROM documents WHERE folderId IN (SELECT id FROM folder_tree)
func (q *Queries) CountDocumentsInFolderTree(ctx context.Context, folderID *uuid.UUID) (int64, error) {
row := q.db.QueryRow(ctx, countDocumentsInFolderTree, folderID)
var count int64
err := row.Scan(&count)
return count, err
}
const createFolder = `-- name: CreateFolder :one
INSERT INTO folders (path, parentId, clientId, createdBy)
VALUES ($1, $2, $3, $4)
@@ -65,6 +91,31 @@ func (q *Queries) CreateFolder(ctx context.Context, arg *CreateFolderParams) (*F
return &i, err
}
const deleteDocumentUploadsInFolderTree = `-- name: DeleteDocumentUploadsInFolderTree :exec
WITH RECURSIVE folder_tree AS (
SELECT id FROM folders WHERE id = $1
UNION ALL
SELECT f.id FROM folders f
JOIN folder_tree ft ON f.parentId = ft.id
)
DELETE FROM documentUploads WHERE folder_id IN (SELECT id FROM folder_tree)
`
// @sqlc-vet-disable
// Delete documentUploads rows that reference folders in the tree
//
// WITH RECURSIVE folder_tree AS (
// SELECT id FROM folders WHERE id = $1
// UNION ALL
// SELECT f.id FROM folders f
// JOIN folder_tree ft ON f.parentId = ft.id
// )
// DELETE FROM documentUploads WHERE folder_id IN (SELECT id FROM folder_tree)
func (q *Queries) DeleteDocumentUploadsInFolderTree(ctx context.Context, folderID *uuid.UUID) error {
_, err := q.db.Exec(ctx, deleteDocumentUploadsInFolderTree, folderID)
return err
}
const getClientRootFolder = `-- name: GetClientRootFolder :one
SELECT id, path, parentid, clientid, createdat, createdby FROM folders
WHERE clientId = $1 AND path = '/'
@@ -88,6 +139,45 @@ func (q *Queries) GetClientRootFolder(ctx context.Context, clientid string) (*Fo
return &i, err
}
const getDocumentIDsInFolderTree = `-- name: GetDocumentIDsInFolderTree :many
WITH RECURSIVE folder_tree AS (
SELECT id FROM folders WHERE id = $1
UNION ALL
SELECT f.id FROM folders f
JOIN folder_tree ft ON f.parentId = ft.id
)
SELECT id FROM documents WHERE folderId IN (SELECT id FROM folder_tree)
`
// Get all document IDs in a folder tree for cascade deletion
//
// WITH RECURSIVE folder_tree AS (
// SELECT id FROM folders WHERE id = $1
// UNION ALL
// SELECT f.id FROM folders f
// JOIN folder_tree ft ON f.parentId = ft.id
// )
// SELECT id FROM documents WHERE folderId IN (SELECT id FROM folder_tree)
func (q *Queries) GetDocumentIDsInFolderTree(ctx context.Context, folderID *uuid.UUID) ([]uuid.UUID, error) {
rows, err := q.db.Query(ctx, getDocumentIDsInFolderTree, folderID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []uuid.UUID{}
for rows.Next() {
var id uuid.UUID
if err := rows.Scan(&id); err != nil {
return nil, err
}
items = append(items, id)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getDocumentsByFolder = `-- name: GetDocumentsByFolder :many
SELECT id, clientid, hash, batch_id, filename, folderid, originalpath, file_size_bytes FROM documents
WHERE folderId = $1
@@ -355,6 +445,50 @@ func (q *Queries) GetFolderTree(ctx context.Context, dollar_1 *uuid.UUID) ([]*Ge
return items, nil
}
const getFolderTreeIDs = `-- name: GetFolderTreeIDs :many
WITH RECURSIVE folder_tree AS (
SELECT id, path FROM folders WHERE id = $1
UNION ALL
SELECT f.id, f.path FROM folders f
JOIN folder_tree ft ON f.parentId = ft.id
)
SELECT id, path FROM folder_tree
`
type GetFolderTreeIDsRow struct {
ID uuid.UUID `db:"id"`
Path string `db:"path"`
}
// Get all folder IDs in a folder tree (recursive) for cascade delete operations
//
// WITH RECURSIVE folder_tree AS (
// SELECT id, path FROM folders WHERE id = $1
// UNION ALL
// SELECT f.id, f.path FROM folders f
// JOIN folder_tree ft ON f.parentId = ft.id
// )
// SELECT id, path FROM folder_tree
func (q *Queries) GetFolderTreeIDs(ctx context.Context, folderID *uuid.UUID) ([]*GetFolderTreeIDsRow, error) {
rows, err := q.db.Query(ctx, getFolderTreeIDs, folderID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []*GetFolderTreeIDsRow{}
for rows.Next() {
var i GetFolderTreeIDsRow
if err := rows.Scan(&i.ID, &i.Path); err != nil {
return nil, err
}
items = append(items, &i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getFoldersByClientID = `-- name: GetFoldersByClientID :many
SELECT id, path, parentid, clientid, createdat, createdby FROM folders
WHERE clientId = $1
@@ -510,6 +644,35 @@ func (q *Queries) GetTopLevelFolders(ctx context.Context, clientid string) ([]*F
return items, nil
}
const hardDeleteFolderTree = `-- name: HardDeleteFolderTree :execrows
WITH RECURSIVE folder_tree AS (
SELECT id FROM folders WHERE id = $1
UNION ALL
SELECT f.id FROM folders f
JOIN folder_tree ft ON f.parentId = ft.id
)
DELETE FROM folders WHERE id IN (SELECT id FROM folder_tree)
`
// @sqlc-vet-disable
// Delete all folders in the tree. PostgreSQL handles ordering within the CTE.
// Returns the number of rows deleted.
//
// WITH RECURSIVE folder_tree AS (
// SELECT id FROM folders WHERE id = $1
// UNION ALL
// SELECT f.id FROM folders f
// JOIN folder_tree ft ON f.parentId = ft.id
// )
// DELETE FROM folders WHERE id IN (SELECT id FROM folder_tree)
func (q *Queries) HardDeleteFolderTree(ctx context.Context, folderID *uuid.UUID) (int64, error) {
result, err := q.db.Exec(ctx, hardDeleteFolderTree, folderID)
if err != nil {
return 0, err
}
return result.RowsAffected(), nil
}
const renameFolder = `-- name: RenameFolder :exec
UPDATE folders
SET path = $2