From 07b03562b1d96c8a6e95a4ac702cd68bc2527348 Mon Sep 17 00:00:00 2001 From: m Date: Mon, 13 Jul 2026 16:54:12 +0200 Subject: [PATCH] display folders --- backend/internal/db/files.sql.go | 66 ++++++++++++++++--- .../db/migrations/007_add_is_folder.down.sql | 1 + .../db/migrations/007_add_is_folder.up.sql | 2 + backend/internal/db/models.go | 1 + backend/internal/db/queries/files.sql | 11 +++- backend/internal/db/tags.sql.go | 3 +- backend/internal/handler/files.go | 2 + backend/internal/model/file.go | 3 +- backend/internal/service/file.go | 1 + mobile/types/index.ts | 3 +- 10 files changed, 78 insertions(+), 15 deletions(-) create mode 100644 backend/internal/db/migrations/007_add_is_folder.down.sql create mode 100644 backend/internal/db/migrations/007_add_is_folder.up.sql diff --git a/backend/internal/db/files.sql.go b/backend/internal/db/files.sql.go index eb28325..54e5bb8 100644 --- a/backend/internal/db/files.sql.go +++ b/backend/internal/db/files.sql.go @@ -7,6 +7,7 @@ package db import ( "context" + "database/sql" "github.com/lib/pq" ) @@ -14,7 +15,7 @@ import ( const createFile = `-- name: CreateFile :one INSERT INTO files (id, name, mime_type, size, storage_key, checksum, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) -RETURNING id, name, mime_type, size, storage_key, checksum, ocr_text, created_at, updated_at, parent_file_id +RETURNING id, name, mime_type, size, storage_key, checksum, ocr_text, created_at, updated_at, parent_file_id, is_folder ` type CreateFileParams struct { @@ -47,14 +48,15 @@ func (q *Queries) CreateFile(ctx context.Context, arg CreateFileParams) (File, e &i.CreatedAt, &i.UpdatedAt, &i.ParentFileID, + &i.IsFolder, ) return i, err } const createFolder = `-- name: CreateFolder :one -INSERT INTO files (id, name, created_at, updated_at) -VALUES ($1, $2, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) -RETURNING id, name, mime_type, size, storage_key, checksum, ocr_text, created_at, updated_at, parent_file_id +INSERT INTO files (id, name, is_folder, created_at, updated_at) +VALUES ($1, $2, true, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) +RETURNING id, name, mime_type, size, storage_key, checksum, ocr_text, created_at, updated_at, parent_file_id, is_folder ` type CreateFolderParams struct { @@ -76,6 +78,7 @@ func (q *Queries) CreateFolder(ctx context.Context, arg CreateFolderParams) (Fil &i.CreatedAt, &i.UpdatedAt, &i.ParentFileID, + &i.IsFolder, ) return i, err } @@ -91,7 +94,7 @@ func (q *Queries) DeleteFile(ctx context.Context, id string) error { } const getFile = `-- name: GetFile :one -SELECT id, name, mime_type, size, storage_key, checksum, ocr_text, created_at, updated_at, parent_file_id FROM files +SELECT id, name, mime_type, size, storage_key, checksum, ocr_text, created_at, updated_at, parent_file_id, is_folder FROM files WHERE id = $1 LIMIT 1 ` @@ -109,12 +112,13 @@ func (q *Queries) GetFile(ctx context.Context, id string) (File, error) { &i.CreatedAt, &i.UpdatedAt, &i.ParentFileID, + &i.IsFolder, ) return i, err } const listFiles = `-- name: ListFiles :many -SELECT id, name, mime_type, size, storage_key, checksum, ocr_text, created_at, updated_at, parent_file_id FROM files +SELECT id, name, mime_type, size, storage_key, checksum, ocr_text, created_at, updated_at, parent_file_id, is_folder FROM files WHERE parent_file_id IS NULL ORDER BY created_at DESC ` @@ -139,6 +143,7 @@ func (q *Queries) ListFiles(ctx context.Context) ([]File, error) { &i.CreatedAt, &i.UpdatedAt, &i.ParentFileID, + &i.IsFolder, ); err != nil { return nil, err } @@ -154,7 +159,7 @@ func (q *Queries) ListFiles(ctx context.Context) ([]File, error) { } const listFilesByID = `-- name: ListFilesByID :many -SELECT id, name, mime_type, size, storage_key, checksum, ocr_text, created_at, updated_at, parent_file_id FROM files +SELECT id, name, mime_type, size, storage_key, checksum, ocr_text, created_at, updated_at, parent_file_id, is_folder FROM files WHERE id = ANY($1::text[]) ORDER BY created_at DESC ` @@ -179,6 +184,48 @@ func (q *Queries) ListFilesByID(ctx context.Context, dollar_1 []string) ([]File, &i.CreatedAt, &i.UpdatedAt, &i.ParentFileID, + &i.IsFolder, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listFilesByParentID = `-- name: ListFilesByParentID :many +SELECT id, name, mime_type, size, storage_key, checksum, ocr_text, created_at, updated_at, parent_file_id, is_folder FROM files +WHERE parent_file_id = $1 +ORDER BY is_folder DESC, created_at DESC +` + +func (q *Queries) ListFilesByParentID(ctx context.Context, parentFileID sql.NullString) ([]File, error) { + rows, err := q.db.QueryContext(ctx, listFilesByParentID, parentFileID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []File + for rows.Next() { + var i File + if err := rows.Scan( + &i.ID, + &i.Name, + &i.MimeType, + &i.Size, + &i.StorageKey, + &i.Checksum, + &i.OcrText, + &i.CreatedAt, + &i.UpdatedAt, + &i.ParentFileID, + &i.IsFolder, ); err != nil { return nil, err } @@ -194,8 +241,8 @@ func (q *Queries) ListFilesByID(ctx context.Context, dollar_1 []string) ([]File, } const listFolders = `-- name: ListFolders :many -SELECT id, name, mime_type, size, storage_key, checksum, ocr_text, created_at, updated_at, parent_file_id FROM files -WHERE parent_file_id IS NOT NULL +SELECT id, name, mime_type, size, storage_key, checksum, ocr_text, created_at, updated_at, parent_file_id, is_folder FROM files +WHERE is_folder = true ORDER BY created_at DESC ` @@ -219,6 +266,7 @@ func (q *Queries) ListFolders(ctx context.Context) ([]File, error) { &i.CreatedAt, &i.UpdatedAt, &i.ParentFileID, + &i.IsFolder, ); err != nil { return nil, err } diff --git a/backend/internal/db/migrations/007_add_is_folder.down.sql b/backend/internal/db/migrations/007_add_is_folder.down.sql new file mode 100644 index 0000000..c8c7736 --- /dev/null +++ b/backend/internal/db/migrations/007_add_is_folder.down.sql @@ -0,0 +1 @@ +ALTER TABLE files DROP COLUMN IF EXISTS is_folder; diff --git a/backend/internal/db/migrations/007_add_is_folder.up.sql b/backend/internal/db/migrations/007_add_is_folder.up.sql new file mode 100644 index 0000000..421f503 --- /dev/null +++ b/backend/internal/db/migrations/007_add_is_folder.up.sql @@ -0,0 +1,2 @@ +-- VaultDrop 007: re-add is_folder to distinguish folders from files +ALTER TABLE files ADD COLUMN is_folder BOOLEAN NOT NULL DEFAULT false; diff --git a/backend/internal/db/models.go b/backend/internal/db/models.go index 06a88c8..a54cc01 100644 --- a/backend/internal/db/models.go +++ b/backend/internal/db/models.go @@ -20,6 +20,7 @@ type File struct { CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` ParentFileID sql.NullString `json:"parent_file_id"` + IsFolder bool `json:"is_folder"` } type FileTag struct { diff --git a/backend/internal/db/queries/files.sql b/backend/internal/db/queries/files.sql index 9f99ebc..ca5b9ba 100644 --- a/backend/internal/db/queries/files.sql +++ b/backend/internal/db/queries/files.sql @@ -9,7 +9,7 @@ ORDER BY created_at DESC; -- name: ListFolders :many SELECT * FROM files -WHERE parent_file_id IS NOT NULL +WHERE is_folder = true ORDER BY created_at DESC; -- name: ListFilesByID :many @@ -23,10 +23,15 @@ VALUES ($1, $2, $3, $4, $5, $6, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) RETURNING *; -- name: CreateFolder :one -INSERT INTO files (id, name, created_at, updated_at) -VALUES ($1, $2, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) +INSERT INTO files (id, name, is_folder, created_at, updated_at) +VALUES ($1, $2, true, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) RETURNING *; +-- name: ListFilesByParentID :many +SELECT * FROM files +WHERE parent_file_id = $1 +ORDER BY is_folder DESC, created_at DESC; + -- name: UpdateFile :exec UPDATE files SET name = $1, mime_type = $2, ocr_text = $3, updated_at = CURRENT_TIMESTAMP diff --git a/backend/internal/db/tags.sql.go b/backend/internal/db/tags.sql.go index 1ee2194..44e40e8 100644 --- a/backend/internal/db/tags.sql.go +++ b/backend/internal/db/tags.sql.go @@ -64,7 +64,7 @@ func (q *Queries) DeleteTag(ctx context.Context, id string) error { } const getFilesByTagID = `-- name: GetFilesByTagID :many -SELECT f.id, f.name, f.mime_type, f.size, f.storage_key, f.checksum, f.ocr_text, f.created_at, f.updated_at, f.parent_file_id FROM files f +SELECT f.id, f.name, f.mime_type, f.size, f.storage_key, f.checksum, f.ocr_text, f.created_at, f.updated_at, f.parent_file_id, f.is_folder FROM files f JOIN file_tags ft ON f.id = ft.file_id WHERE ft.tag_id = $1 ORDER BY f.created_at DESC @@ -90,6 +90,7 @@ func (q *Queries) GetFilesByTagID(ctx context.Context, tagID sql.NullString) ([] &i.CreatedAt, &i.UpdatedAt, &i.ParentFileID, + &i.IsFolder, ); err != nil { return nil, err } diff --git a/backend/internal/handler/files.go b/backend/internal/handler/files.go index bef7a01..67cbe43 100644 --- a/backend/internal/handler/files.go +++ b/backend/internal/handler/files.go @@ -73,6 +73,7 @@ func (h *FileHandler) List(c *gin.Context) { MimeType string `json:"mimeType"` OcrText string `json:"ocrText,omitempty"` ParentFileID string `json:"parentFileID,omitempty"` + IsFolder bool `json:"isFolder"` UpdatedAt string `json:"updatedAt"` } @@ -99,6 +100,7 @@ func (h *FileHandler) List(c *gin.Context) { CreatedAt: f.CreatedAt, ParentFileID: f.ParentFileID, OcrText: f.OcrText, + IsFolder: f.IsFolder, UpdatedAt: f.UpdatedAt, MimeType: f.MimeType, } diff --git a/backend/internal/model/file.go b/backend/internal/model/file.go index e5c4362..741753e 100644 --- a/backend/internal/model/file.go +++ b/backend/internal/model/file.go @@ -15,9 +15,10 @@ type File struct { Checksum string `json:"-"` OcrText string `json:"ocrText,omitempty"` Tags []Tag `json:"tags"` + IsFolder bool `json:"isFolder"` + ParentFileID string `json:"parentFileId,omitempty"` CreatedAt string `json:"createdAt"` UpdatedAt string `json:"updatedAt"` - ParentFileID string `json:"parentFileID,omitempty"` } type UploadResult struct { diff --git a/backend/internal/service/file.go b/backend/internal/service/file.go index ec45ceb..6026b8e 100644 --- a/backend/internal/service/file.go +++ b/backend/internal/service/file.go @@ -176,6 +176,7 @@ func dbToModel(f db.File, dbTags []db.Tag) model.File { StorageKey: f.StorageKey, Checksum: f.Checksum, OcrText: f.OcrText, + IsFolder: f.IsFolder, ParentFileID: f.ParentFileID.String, Tags: tags, CreatedAt: f.CreatedAt.String(), diff --git a/mobile/types/index.ts b/mobile/types/index.ts index f3e1619..d555765 100644 --- a/mobile/types/index.ts +++ b/mobile/types/index.ts @@ -7,12 +7,13 @@ export interface FileItem { updatedAt: string; ocrText?: string; tags: Tag[]; + isFolder: boolean; parentFileId?: string; url?: string; } export function isFolder(file: FileItem): boolean { - return file.parentFileId != null; + return file.isFolder; } export interface Tag {