chore(repo): reinitialize repository
This commit is contained in:
@@ -0,0 +1,178 @@
|
||||
package sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"inbox/internal/domain/topic"
|
||||
)
|
||||
|
||||
func (s *Store) CreateTopic(ctx context.Context, value topic.Record) (topic.Record, error) {
|
||||
if err := value.Validate(); err != nil {
|
||||
return topic.Record{}, err
|
||||
}
|
||||
if value.ID == "" {
|
||||
id, err := s.newID("topic")
|
||||
if err != nil {
|
||||
return topic.Record{}, err
|
||||
}
|
||||
value.ID = id
|
||||
}
|
||||
now := s.now()
|
||||
value.CreatedAt = coalesceString(value.CreatedAt, now)
|
||||
value.UpdatedAt = now
|
||||
|
||||
if _, err := s.db.ExecContext(ctx, `
|
||||
INSERT INTO topics(id, workspace_id, slug, title, space, status, summary, created_at, updated_at, closed_at)
|
||||
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`, value.ID, value.WorkspaceID, value.Slug, value.Title, string(value.Space), value.Status, value.Summary, value.CreatedAt, value.UpdatedAt, nullableString(value.ClosedAt)); err != nil {
|
||||
return topic.Record{}, fmt.Errorf("create topic: %w", err)
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (s *Store) ListTopics(ctx context.Context, workspaceID string) ([]topic.Record, error) {
|
||||
var (
|
||||
rows *sql.Rows
|
||||
err error
|
||||
)
|
||||
if strings.TrimSpace(workspaceID) == "" {
|
||||
rows, err = s.db.QueryContext(ctx, `
|
||||
SELECT id, workspace_id, slug, title, space, status, summary, created_at, updated_at, closed_at
|
||||
FROM topics
|
||||
ORDER BY updated_at DESC, created_at DESC, slug
|
||||
`)
|
||||
} else {
|
||||
rows, err = s.db.QueryContext(ctx, `
|
||||
SELECT id, workspace_id, slug, title, space, status, summary, created_at, updated_at, closed_at
|
||||
FROM topics
|
||||
WHERE workspace_id = ?
|
||||
ORDER BY updated_at DESC, created_at DESC, slug
|
||||
`, workspaceID)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list topics: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var out []topic.Record
|
||||
for rows.Next() {
|
||||
item, err := scanTopic(rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, item)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, fmt.Errorf("iterate topics: %w", err)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (s *Store) ListTopicsBySpace(ctx context.Context, workspaceID string, space topic.Space) ([]topic.Record, error) {
|
||||
rows, err := s.db.QueryContext(ctx, `
|
||||
SELECT id, workspace_id, slug, title, space, status, summary, created_at, updated_at, closed_at
|
||||
FROM topics
|
||||
WHERE workspace_id = ? AND space = ?
|
||||
ORDER BY updated_at DESC, created_at DESC, slug
|
||||
`, workspaceID, string(space))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list topics by space: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var out []topic.Record
|
||||
for rows.Next() {
|
||||
item, err := scanTopic(rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, item)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, fmt.Errorf("iterate topics by space: %w", err)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (s *Store) GetTopic(ctx context.Context, topicID string) (topic.Record, error) {
|
||||
row := s.db.QueryRowContext(ctx, `
|
||||
SELECT id, workspace_id, slug, title, space, status, summary, created_at, updated_at, closed_at
|
||||
FROM topics
|
||||
WHERE id = ?
|
||||
`, topicID)
|
||||
return scanTopic(row)
|
||||
}
|
||||
|
||||
func (s *Store) GetTopicBySlugOrTitle(ctx context.Context, workspaceID, value string, spaces ...topic.Space) (topic.Record, error) {
|
||||
args := []any{workspaceID, value, value}
|
||||
query := `
|
||||
SELECT id, workspace_id, slug, title, space, status, summary, created_at, updated_at, closed_at
|
||||
FROM topics
|
||||
WHERE workspace_id = ? AND (slug = ? OR title = ?)
|
||||
`
|
||||
if len(spaces) > 0 {
|
||||
query += " AND space IN (" + placeholders(len(spaces)) + ")"
|
||||
for _, space := range spaces {
|
||||
args = append(args, string(space))
|
||||
}
|
||||
}
|
||||
query += `
|
||||
ORDER BY CASE WHEN slug = ? THEN 0 ELSE 1 END, updated_at DESC, created_at DESC
|
||||
LIMIT 1
|
||||
`
|
||||
args = append(args, value)
|
||||
row := s.db.QueryRowContext(ctx, query, args...)
|
||||
return scanTopic(row)
|
||||
}
|
||||
|
||||
func (s *Store) UpdateTopic(ctx context.Context, value topic.Record) (topic.Record, error) {
|
||||
if value.ID == "" {
|
||||
return topic.Record{}, fmt.Errorf("topic id is required")
|
||||
}
|
||||
current, err := s.GetTopic(ctx, value.ID)
|
||||
if err != nil {
|
||||
return topic.Record{}, err
|
||||
}
|
||||
value.CreatedAt = current.CreatedAt
|
||||
value.UpdatedAt = s.now()
|
||||
if err := value.Validate(); err != nil {
|
||||
return topic.Record{}, err
|
||||
}
|
||||
result, err := s.db.ExecContext(ctx, `
|
||||
UPDATE topics
|
||||
SET workspace_id = ?, slug = ?, title = ?, space = ?, status = ?, summary = ?, updated_at = ?, closed_at = ?
|
||||
WHERE id = ?
|
||||
`, value.WorkspaceID, value.Slug, value.Title, string(value.Space), value.Status, value.Summary, value.UpdatedAt, nullableString(value.ClosedAt), value.ID)
|
||||
if err != nil {
|
||||
return topic.Record{}, fmt.Errorf("update topic: %w", err)
|
||||
}
|
||||
if err := ensureAffected(result, sql.ErrNoRows); err != nil {
|
||||
return topic.Record{}, err
|
||||
}
|
||||
return s.GetTopic(ctx, value.ID)
|
||||
}
|
||||
|
||||
func (s *Store) DeleteTopic(ctx context.Context, topicID string) error {
|
||||
result, err := s.db.ExecContext(ctx, `DELETE FROM topics WHERE id = ?`, topicID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("delete topic: %w", err)
|
||||
}
|
||||
return ensureAffected(result, sql.ErrNoRows)
|
||||
}
|
||||
|
||||
func scanTopic(s scanner) (topic.Record, error) {
|
||||
var item topic.Record
|
||||
var space string
|
||||
var closedAt sql.NullString
|
||||
if err := s.Scan(&item.ID, &item.WorkspaceID, &item.Slug, &item.Title, &space, &item.Status, &item.Summary, &item.CreatedAt, &item.UpdatedAt, &closedAt); err != nil {
|
||||
return topic.Record{}, err
|
||||
}
|
||||
item.Space = topic.Space(space)
|
||||
if closedAt.Valid {
|
||||
item.ClosedAt = closedAt.String
|
||||
}
|
||||
return item, nil
|
||||
}
|
||||
Reference in New Issue
Block a user