// internal/repository/document.go
type DocumentRepository interface {
Create(ctx context.Context, doc *Document) error
GetByID(ctx context.Context, id string) (*Document, error)
Update(ctx context.Context, doc *Document) error
Delete(ctx context.Context, id string) error
List(ctx context.Context, workspaceID string, opts ListOptions) ([]*Document, int64, error)
Search(ctx context.Context, workspaceID, query string) ([]*Document, error)
}
type documentRepository struct {
db *sqlx.DB
}
func (r *documentRepository) GetByID(ctx context.Context, id string) (*Document, error) {
var doc Document
query := `
SELECT id, title, content, workspace_id, owner_id, version,
created_at, updated_at, deleted_at
FROM documents
WHERE id = $1 AND deleted_at IS NULL
`
if err := r.db.GetContext(ctx, &doc, query, id); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, ErrDocumentNotFound
}
return nil, fmt.Errorf("failed to get document: %w", err)
}
return &doc, nil
}
func (r *documentRepository) Search(ctx context.Context, workspaceID, query string) ([]*Document, error) {
var docs []*Document
searchQuery := `
SELECT id, title, content, workspace_id, owner_id, version,
created_at, updated_at,
ts_rank(search_vector, plainto_tsquery('english', $1)) as rank
FROM documents
WHERE workspace_id = $2
AND deleted_at IS NULL
AND search_vector @@ plainto_tsquery('english', $1)
ORDER BY rank DESC
LIMIT 50
`
if err := r.db.SelectContext(ctx, &docs, searchQuery, query, workspaceID); err != nil {
return nil, fmt.Errorf("failed to search documents: %w", err)
}
return docs, nil
}