package db import ( "context" "database/sql" "encoding/json" "time" ) type UploadedFile struct { ID string `json:"id"` UserID string `json:"userId"` Filename string `json:"filename"` FileType string `json:"fileType"` FileSize int64 `json:"fileSize"` StoragePath string `json:"storagePath"` ExtractedText string `json:"extractedText,omitempty"` Metadata map[string]interface{} `json:"metadata"` CreatedAt time.Time `json:"createdAt"` } type FileRepository struct { db *PostgresDB } func NewFileRepository(db *PostgresDB) *FileRepository { return &FileRepository{db: db} } func (r *FileRepository) Create(ctx context.Context, f *UploadedFile) error { metadataJSON, _ := json.Marshal(f.Metadata) query := ` INSERT INTO uploaded_files (user_id, filename, file_type, file_size, storage_path, extracted_text, metadata) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING id, created_at ` return r.db.db.QueryRowContext(ctx, query, f.UserID, f.Filename, f.FileType, f.FileSize, f.StoragePath, f.ExtractedText, metadataJSON, ).Scan(&f.ID, &f.CreatedAt) } func (r *FileRepository) GetByID(ctx context.Context, id string) (*UploadedFile, error) { query := ` SELECT id, user_id, filename, file_type, file_size, storage_path, extracted_text, metadata, created_at FROM uploaded_files WHERE id = $1 ` var f UploadedFile var metadataJSON []byte err := r.db.db.QueryRowContext(ctx, query, id).Scan( &f.ID, &f.UserID, &f.Filename, &f.FileType, &f.FileSize, &f.StoragePath, &f.ExtractedText, &metadataJSON, &f.CreatedAt, ) if err == sql.ErrNoRows { return nil, nil } if err != nil { return nil, err } json.Unmarshal(metadataJSON, &f.Metadata) return &f, nil } func (r *FileRepository) GetByUserID(ctx context.Context, userID string, limit, offset int) ([]*UploadedFile, error) { query := ` SELECT id, user_id, filename, file_type, file_size, storage_path, extracted_text, metadata, created_at FROM uploaded_files WHERE user_id = $1 ORDER BY created_at DESC LIMIT $2 OFFSET $3 ` rows, err := r.db.db.QueryContext(ctx, query, userID, limit, offset) if err != nil { return nil, err } defer rows.Close() var files []*UploadedFile for rows.Next() { var f UploadedFile var metadataJSON []byte if err := rows.Scan( &f.ID, &f.UserID, &f.Filename, &f.FileType, &f.FileSize, &f.StoragePath, &f.ExtractedText, &metadataJSON, &f.CreatedAt, ); err != nil { return nil, err } json.Unmarshal(metadataJSON, &f.Metadata) files = append(files, &f) } return files, nil } func (r *FileRepository) UpdateExtractedText(ctx context.Context, id, text, userID string) error { result, err := r.db.db.ExecContext(ctx, "UPDATE uploaded_files SET extracted_text = $2 WHERE id = $1 AND user_id = $3", id, text, userID, ) if err != nil { return err } rows, _ := result.RowsAffected() if rows == 0 { return ErrNotFound } return nil } func (r *FileRepository) Delete(ctx context.Context, id, userID string) error { result, err := r.db.db.ExecContext(ctx, "DELETE FROM uploaded_files WHERE id = $1 AND user_id = $2", id, userID) if err != nil { return err } rows, _ := result.RowsAffected() if rows == 0 { return ErrNotFound } return nil } func (r *FileRepository) GetByIDs(ctx context.Context, ids []string, userID string) ([]*UploadedFile, error) { if len(ids) == 0 { return nil, nil } query := ` SELECT id, user_id, filename, file_type, file_size, storage_path, extracted_text, metadata, created_at FROM uploaded_files WHERE id = ANY($1) AND user_id = $2 ` rows, err := r.db.db.QueryContext(ctx, query, ids, userID) if err != nil { return nil, err } defer rows.Close() var files []*UploadedFile for rows.Next() { var f UploadedFile var metadataJSON []byte if err := rows.Scan( &f.ID, &f.UserID, &f.Filename, &f.FileType, &f.FileSize, &f.StoragePath, &f.ExtractedText, &metadataJSON, &f.CreatedAt, ); err != nil { return nil, err } json.Unmarshal(metadataJSON, &f.Metadata) files = append(files, &f) } return files, nil }