-- name: CreateFolder :one INSERT INTO folders (path, parentId, clientId, createdBy) VALUES ($1, $2, $3, $4) RETURNING *; -- name: GetFolderByID :one SELECT * FROM folders WHERE id = $1; -- name: GetFolderByPath :one SELECT * FROM folders WHERE clientId = $1 AND path = $2; -- name: GetFoldersByClientID :many SELECT * FROM folders WHERE clientId = $1 ORDER BY path; -- name: GetFoldersByParentID :many SELECT * FROM folders WHERE parentId = $1 ORDER BY path; -- name: RenameFolder :exec UPDATE folders SET path = $2 WHERE id = $1; -- name: GetFolderTree :many WITH RECURSIVE folder_tree AS ( -- Base case: start with the target folder SELECT id, path, parentId, clientId, createdAt, createdBy FROM folders WHERE id = $1 UNION ALL -- Recursive case: find all child folders SELECT f.id, f.path, f.parentId, f.clientId, f.createdAt, f.createdBy FROM folders f INNER JOIN folder_tree ft ON f.parentId = ft.id ) SELECT id, path, parentId, clientId, createdAt, createdBy FROM folder_tree ORDER BY path; -- name: GetRootFolders :many -- Returns folders with null parentId (should only be the "/" root folder for each client) SELECT * FROM folders WHERE clientId = $1 AND parentId IS NULL ORDER BY path; -- name: GetTopLevelFolders :many -- Returns folders that are direct children of the root folder "/" -- These are the user-visible top-level folders (e.g., /folder1, /folder2) SELECT f.* FROM folders f INNER JOIN folders root ON f.parentId = root.id WHERE f.clientId = $1 AND root.path = '/' ORDER BY f.path; -- name: GetClientRootFolder :one -- Returns the root folder "/" for a client SELECT * FROM folders WHERE clientId = $1 AND path = '/'; -- name: GetDocumentsByFolder :many SELECT * FROM documents WHERE folderId = $1 ORDER BY id; -- name: CountDocumentsByFolder :one SELECT COUNT(*) as total FROM documents WHERE folderId = $1; -- name: GetFolderLabelCounts :many SELECT dl.label, COUNT(DISTINCT dl.documentId) as count FROM documents d INNER JOIN documentLabels dl ON d.id = dl.documentId WHERE d.folderId = $1 GROUP BY dl.label ORDER BY dl.label; -- name: UpsertFolder :one -- Insert a folder if it doesn't exist, or return the existing one -- Used for auto-creating folder hierarchies during document upload INSERT INTO folders (path, parentId, clientId, createdBy) VALUES ($1, $2, $3, $4) ON CONFLICT (clientId, path) DO UPDATE SET path = EXCLUDED.path RETURNING *; -- name: GetDocumentsByFolderEnriched :many -- Gets documents in a folder with all enriched metadata fields SELECT d.id, d.hash, d.folderId, d.filename, d.originalPath, d.file_size_bytes 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);