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:
@@ -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
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
`
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user