← back to kjm99d__MonkeyPlanner

Function bodies 254 total

All specs Real LLM only Function bodies
ReorderIssues method · go · L270-L282 (13 LOC)
backend/internal/storage/postgres/repo.go
func (r *issueRepo) ReorderIssues(ctx context.Context, issueIDs []string) error {
	tx, err := r.db.BeginTx(ctx, nil)
	if err != nil {
		return fmt.Errorf("postgres: begin: %w", err)
	}
	defer tx.Rollback()
	for pos, id := range issueIDs {
		if _, err := tx.ExecContext(ctx, `UPDATE issues SET position=$1 WHERE id=$2`, pos, id); err != nil {
			return fmt.Errorf("postgres: reorder issue: %w", err)
		}
	}
	return tx.Commit()
}
GetDayStats method · go · L284-L310 (27 LOC)
backend/internal/storage/postgres/repo.go
func (r *issueRepo) GetDayStats(ctx context.Context, day time.Time) (storage.DayStats, error) {
	start := time.Date(day.Year(), day.Month(), day.Day(), 0, 0, 0, 0, time.UTC)
	end := start.AddDate(0, 0, 1)
	qBy := func(column string) ([]domain.Issue, error) {
		rows, err := r.db.QueryContext(ctx, selectIssueCols+
			fmt.Sprintf(` WHERE %s IS NOT NULL AND %s >= $1 AND %s < $2 ORDER BY %s ASC`, column, column, column, column),
			start, end)
		if err != nil {
			return nil, fmt.Errorf("postgres: day stats %s: %w", column, err)
		}
		defer rows.Close()
		return collectIssues(rows)
	}
	created, err := qBy("created_at")
	if err != nil {
		return storage.DayStats{}, err
	}
	approved, err := qBy("approved_at")
	if err != nil {
		return storage.DayStats{}, err
	}
	completed, err := qBy("completed_at")
	if err != nil {
		return storage.DayStats{}, err
	}
	return storage.DayStats{Created: created, Approved: approved, Completed: completed}, nil
}
AddDependency method · go · L312-L320 (9 LOC)
backend/internal/storage/postgres/repo.go
func (r *issueRepo) AddDependency(ctx context.Context, blockerID, blockedID string) error {
	_, err := r.db.ExecContext(ctx,
		`INSERT INTO issue_dependencies (blocker_id, blocked_id) VALUES ($1, $2) ON CONFLICT DO NOTHING`,
		blockerID, blockedID)
	if err != nil {
		return fmt.Errorf("postgres: add dependency: %w", err)
	}
	return nil
}
RemoveDependency method · go · L322-L330 (9 LOC)
backend/internal/storage/postgres/repo.go
func (r *issueRepo) RemoveDependency(ctx context.Context, blockerID, blockedID string) error {
	_, err := r.db.ExecContext(ctx,
		`DELETE FROM issue_dependencies WHERE blocker_id = $1 AND blocked_id = $2`,
		blockerID, blockedID)
	if err != nil {
		return fmt.Errorf("postgres: remove dependency: %w", err)
	}
	return nil
}
GetBlockedBy method · go · L332-L348 (17 LOC)
backend/internal/storage/postgres/repo.go
func (r *issueRepo) GetBlockedBy(ctx context.Context, issueID string) ([]string, error) {
	rows, err := r.db.QueryContext(ctx,
		`SELECT blocker_id FROM issue_dependencies WHERE blocked_id = $1`, issueID)
	if err != nil {
		return nil, fmt.Errorf("postgres: get blocked by: %w", err)
	}
	defer rows.Close()
	var out []string
	for rows.Next() {
		var id string
		if err := rows.Scan(&id); err != nil {
			return nil, err
		}
		out = append(out, id)
	}
	return out, rows.Err()
}
scanIssue function · go · L356-L395 (40 LOC)
backend/internal/storage/postgres/repo.go
func scanIssue(row interface{ Scan(...any) error }) (domain.Issue, error) {
	var i domain.Issue
	var parent sql.NullString
	var propsBytes, criteriaBytes []byte
	var approvedAt, completedAt sql.NullTime
	err := row.Scan(&i.ID, &i.BoardID, &parent, &i.Title, &i.Body, &i.Instructions, &i.Status, &propsBytes, &criteriaBytes, &i.Position, &i.CreatedAt, &i.UpdatedAt, &approvedAt, &completedAt)
	if err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			return domain.Issue{}, storage.ErrNotFound
		}
		return domain.Issue{}, fmt.Errorf("postgres: scan issue: %w", err)
	}
	if len(propsBytes) > 0 {
		_ = json.Unmarshal(propsBytes, &i.Properties)
	}
	if i.Properties == nil {
		i.Properties = map[string]any{}
	}
	if len(criteriaBytes) > 0 {
		_ = json.Unmarshal(criteriaBytes, &i.Criteria)
	}
	if i.Criteria == nil {
		i.Criteria = []domain.Criterion{}
	}
	if parent.Valid {
		p := parent.String
		i.ParentID = &p
	}
	if approvedAt.Valid {
		t := approvedAt.Time.UTC()
		i.ApprovedAt = &t
	}
	if complete
collectIssues function · go · L397-L407 (11 LOC)
backend/internal/storage/postgres/repo.go
func collectIssues(rows *sql.Rows) ([]domain.Issue, error) {
	var out []domain.Issue
	for rows.Next() {
		i, err := scanIssue(rows)
		if err != nil {
			return nil, err
		}
		out = append(out, i)
	}
	return out, rows.Err()
}
Open data scored by Repobility · https://repobility.com
utcPtr function · go · L409-L415 (7 LOC)
backend/internal/storage/postgres/repo.go
func utcPtr(t *time.Time) any {
	if t == nil {
		return nil
	}
	u := t.UTC()
	return u
}
detectCycleTx function · go · L417-L434 (18 LOC)
backend/internal/storage/postgres/repo.go
func detectCycleTx(ctx context.Context, tx *sql.Tx, self, target string) (bool, error) {
	q := `
		WITH RECURSIVE ancestors(id) AS (
			SELECT parent_id FROM issues WHERE id = $1
			UNION ALL
			SELECT i.parent_id FROM issues i JOIN ancestors a ON i.id = a.id WHERE i.parent_id IS NOT NULL
		)
		SELECT 1 FROM ancestors WHERE id = $2 LIMIT 1`
	var hit int
	err := tx.QueryRowContext(ctx, q, target, self).Scan(&hit)
	if err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			return false, nil
		}
		return false, fmt.Errorf("postgres: cycle detect: %w", err)
	}
	return hit == 1, nil
}
Create method · go · L442-L450 (9 LOC)
backend/internal/storage/postgres/repo.go
func (r *boardRepo) Create(ctx context.Context, b domain.Board) (domain.Board, error) {
	_, err := r.db.ExecContext(ctx,
		`INSERT INTO boards (id, name, view_type, created_at) VALUES ($1,$2,$3,$4)`,
		b.ID, b.Name, b.ViewType, b.CreatedAt.UTC())
	if err != nil {
		return domain.Board{}, fmt.Errorf("postgres: create board: %w", err)
	}
	return b, nil
}
GetByID method · go · L452-L465 (14 LOC)
backend/internal/storage/postgres/repo.go
func (r *boardRepo) GetByID(ctx context.Context, id string) (domain.Board, error) {
	var b domain.Board
	err := r.db.QueryRowContext(ctx,
		`SELECT id, name, view_type, created_at FROM boards WHERE id = $1`, id).
		Scan(&b.ID, &b.Name, &b.ViewType, &b.CreatedAt)
	if err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			return domain.Board{}, storage.ErrNotFound
		}
		return domain.Board{}, fmt.Errorf("postgres: get board: %w", err)
	}
	b.CreatedAt = b.CreatedAt.UTC()
	return b, nil
}
List method · go · L467-L484 (18 LOC)
backend/internal/storage/postgres/repo.go
func (r *boardRepo) List(ctx context.Context) ([]domain.Board, error) {
	rows, err := r.db.QueryContext(ctx,
		`SELECT id, name, view_type, created_at FROM boards ORDER BY created_at ASC`)
	if err != nil {
		return nil, fmt.Errorf("postgres: list boards: %w", err)
	}
	defer rows.Close()
	var out []domain.Board
	for rows.Next() {
		var b domain.Board
		if err := rows.Scan(&b.ID, &b.Name, &b.ViewType, &b.CreatedAt); err != nil {
			return nil, err
		}
		b.CreatedAt = b.CreatedAt.UTC()
		out = append(out, b)
	}
	return out, rows.Err()
}
Update method · go · L486-L504 (19 LOC)
backend/internal/storage/postgres/repo.go
func (r *boardRepo) Update(ctx context.Context, id string, name *string, viewType *domain.ViewType) (domain.Board, error) {
	cur, err := r.GetByID(ctx, id)
	if err != nil {
		return domain.Board{}, err
	}
	if name != nil {
		cur.Name = *name
	}
	if viewType != nil {
		cur.ViewType = *viewType
	}
	_, err = r.db.ExecContext(ctx,
		`UPDATE boards SET name=$1, view_type=$2 WHERE id=$3`,
		cur.Name, cur.ViewType, id)
	if err != nil {
		return domain.Board{}, fmt.Errorf("postgres: update board: %w", err)
	}
	return cur, nil
}
Delete method · go · L506-L516 (11 LOC)
backend/internal/storage/postgres/repo.go
func (r *boardRepo) Delete(ctx context.Context, id string) error {
	res, err := r.db.ExecContext(ctx, `DELETE FROM boards WHERE id = $1`, id)
	if err != nil {
		return fmt.Errorf("postgres: delete board: %w", err)
	}
	n, _ := res.RowsAffected()
	if n == 0 {
		return storage.ErrNotFound
	}
	return nil
}
Create method · go · L19-L33 (15 LOC)
backend/internal/storage/sqlite/comment_repo.go
func (r *commentRepo) Create(ctx context.Context, issueID, body string) (*domain.Comment, error) {
	c := &domain.Comment{
		ID:        uuid.NewString(),
		IssueID:   issueID,
		Body:      body,
		CreatedAt: time.Now().UTC(),
	}
	_, err := r.db.ExecContext(ctx,
		`INSERT INTO comments (id, issue_id, body, created_at) VALUES (?, ?, ?, ?)`,
		c.ID, c.IssueID, c.Body, c.CreatedAt)
	if err != nil {
		return nil, fmt.Errorf("sqlite: create comment: %w", err)
	}
	return c, nil
}
Methodology: Repobility · https://repobility.com/research/state-of-ai-code-2026/
List method · go · L35-L53 (19 LOC)
backend/internal/storage/sqlite/comment_repo.go
func (r *commentRepo) List(ctx context.Context, issueID string) ([]domain.Comment, error) {
	rows, err := r.db.QueryContext(ctx,
		`SELECT id, issue_id, body, created_at FROM comments WHERE issue_id = ? ORDER BY created_at ASC`,
		issueID)
	if err != nil {
		return nil, fmt.Errorf("sqlite: list comments: %w", err)
	}
	defer rows.Close()
	var out []domain.Comment
	for rows.Next() {
		var c domain.Comment
		if err := rows.Scan(&c.ID, &c.IssueID, &c.Body, &c.CreatedAt); err != nil {
			return nil, fmt.Errorf("sqlite: scan comment: %w", err)
		}
		c.CreatedAt = c.CreatedAt.UTC()
		out = append(out, c)
	}
	return out, rows.Err()
}
Delete method · go · L55-L65 (11 LOC)
backend/internal/storage/sqlite/comment_repo.go
func (r *commentRepo) Delete(ctx context.Context, commentID string) error {
	res, err := r.db.ExecContext(ctx, `DELETE FROM comments WHERE id = ?`, commentID)
	if err != nil {
		return fmt.Errorf("sqlite: delete comment: %w", err)
	}
	n, _ := res.RowsAffected()
	if n == 0 {
		return storage.ErrNotFound
	}
	return nil
}
runMigrations function · go · L14-L23 (10 LOC)
backend/internal/storage/sqlite/migrations.go
func runMigrations(db *sql.DB) error {
	goose.SetBaseFS(migrationsFS)
	if err := goose.SetDialect("sqlite3"); err != nil {
		return fmt.Errorf("sqlite: set dialect: %w", err)
	}
	if err := goose.Up(db, "migrations"); err != nil {
		return fmt.Errorf("sqlite: goose up: %w", err)
	}
	return nil
}
Create method · go · L20-L35 (16 LOC)
backend/internal/storage/sqlite/property_repo.go
func (r *boardPropertyRepo) Create(ctx context.Context, p domain.BoardProperty) (domain.BoardProperty, error) {
	if p.ID == "" {
		p.ID = uuid.NewString()
	}
	if p.CreatedAt.IsZero() {
		p.CreatedAt = time.Now().UTC()
	}
	opts, _ := json.Marshal(p.Options)
	_, err := r.db.ExecContext(ctx,
		`INSERT INTO board_properties (id, board_id, name, type, options, position, created_at) VALUES (?,?,?,?,?,?,?)`,
		p.ID, p.BoardID, p.Name, p.Type, string(opts), p.Position, p.CreatedAt.UTC())
	if err != nil {
		return domain.BoardProperty{}, fmt.Errorf("sqlite: create board_property: %w", err)
	}
	return p, nil
}
List method · go · L37-L59 (23 LOC)
backend/internal/storage/sqlite/property_repo.go
func (r *boardPropertyRepo) List(ctx context.Context, boardID string) ([]domain.BoardProperty, error) {
	rows, err := r.db.QueryContext(ctx,
		`SELECT id, board_id, name, type, options, position, created_at FROM board_properties WHERE board_id = ? ORDER BY position ASC`, boardID)
	if err != nil {
		return nil, fmt.Errorf("sqlite: list board_properties: %w", err)
	}
	defer rows.Close()
	var out []domain.BoardProperty
	for rows.Next() {
		var p domain.BoardProperty
		var opts string
		if err := rows.Scan(&p.ID, &p.BoardID, &p.Name, &p.Type, &opts, &p.Position, &p.CreatedAt); err != nil {
			return nil, err
		}
		_ = json.Unmarshal([]byte(opts), &p.Options)
		if p.Options == nil {
			p.Options = []string{}
		}
		p.CreatedAt = p.CreatedAt.UTC()
		out = append(out, p)
	}
	return out, rows.Err()
}
Update method · go · L61-L93 (33 LOC)
backend/internal/storage/sqlite/property_repo.go
func (r *boardPropertyRepo) Update(ctx context.Context, id string, name *string, options *[]string, position *int) (domain.BoardProperty, error) {
	// Get current
	var p domain.BoardProperty
	var opts string
	err := r.db.QueryRowContext(ctx,
		`SELECT id, board_id, name, type, options, position, created_at FROM board_properties WHERE id = ?`, id).
		Scan(&p.ID, &p.BoardID, &p.Name, &p.Type, &opts, &p.Position, &p.CreatedAt)
	if err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			return domain.BoardProperty{}, storage.ErrNotFound
		}
		return domain.BoardProperty{}, err
	}
	_ = json.Unmarshal([]byte(opts), &p.Options)

	if name != nil {
		p.Name = *name
	}
	if options != nil {
		p.Options = *options
	}
	if position != nil {
		p.Position = *position
	}
	newOpts, _ := json.Marshal(p.Options)
	_, err = r.db.ExecContext(ctx,
		`UPDATE board_properties SET name=?, options=?, position=? WHERE id=?`,
		p.Name, string(newOpts), p.Position, id)
	if err != nil {
		return domain.BoardProperty{}, 
Delete method · go · L95-L105 (11 LOC)
backend/internal/storage/sqlite/property_repo.go
func (r *boardPropertyRepo) Delete(ctx context.Context, id string) error {
	res, err := r.db.ExecContext(ctx, `DELETE FROM board_properties WHERE id = ?`, id)
	if err != nil {
		return fmt.Errorf("sqlite: delete board_property: %w", err)
	}
	n, _ := res.RowsAffected()
	if n == 0 {
		return storage.ErrNotFound
	}
	return nil
}
Open function · go · L29-L50 (22 LOC)
backend/internal/storage/sqlite/repo.go
func Open(dsn string) (*Repo, error) {
	db, err := sql.Open("sqlite", dsn+"?_pragma=foreign_keys(1)&_pragma=journal_mode(WAL)")
	if err != nil {
		return nil, fmt.Errorf("sqlite open: %w", err)
	}
	if err := db.Ping(); err != nil {
		_ = db.Close()
		return nil, fmt.Errorf("sqlite ping: %w", err)
	}
	if err := runMigrations(db); err != nil {
		_ = db.Close()
		return nil, err
	}
	return &Repo{
		db:       db,
		issues:   &issueRepo{db: db},
		boards:   &boardRepo{db: db},
		props:    &boardPropertyRepo{db: db},
		webhooks: &webhookRepo{db: db},
		comments: &commentRepo{db: db},
	}, nil
}
Want this analysis on your repo? https://repobility.com/scan/
Create method · go · L65-L83 (19 LOC)
backend/internal/storage/sqlite/repo.go
func (r *issueRepo) Create(ctx context.Context, i domain.Issue) (domain.Issue, error) {
	if i.Properties == nil {
		i.Properties = map[string]any{}
	}
	if i.Criteria == nil {
		i.Criteria = []domain.Criterion{}
	}
	propsJSON, _ := json.Marshal(i.Properties)
	criteriaJSON, _ := json.Marshal(i.Criteria)
	_, err := r.db.ExecContext(ctx, `
		INSERT INTO issues (id, board_id, parent_id, title, body, instructions, status, properties, criteria, position, created_at, updated_at, approved_at, completed_at)
		VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
		i.ID, i.BoardID, i.ParentID, i.Title, i.Body, i.Instructions, i.Status, string(propsJSON), string(criteriaJSON), i.Position,
		i.CreatedAt.UTC(), i.UpdatedAt.UTC(), utcPtr(i.ApprovedAt), utcPtr(i.CompletedAt))
	if err != nil {
		return domain.Issue{}, fmt.Errorf("sqlite: create issue: %w", err)
	}
	return i, nil
}
GetByID method · go · L85-L88 (4 LOC)
backend/internal/storage/sqlite/repo.go
func (r *issueRepo) GetByID(ctx context.Context, id string) (domain.Issue, error) {
	row := r.db.QueryRowContext(ctx, selectIssueCols+` WHERE id = ?`, id)
	return scanIssue(row)
}
ListChildren method · go · L90-L97 (8 LOC)
backend/internal/storage/sqlite/repo.go
func (r *issueRepo) ListChildren(ctx context.Context, parentID string) ([]domain.Issue, error) {
	rows, err := r.db.QueryContext(ctx, selectIssueCols+` WHERE parent_id = ? ORDER BY created_at ASC`, parentID)
	if err != nil {
		return nil, fmt.Errorf("sqlite: list children: %w", err)
	}
	defer rows.Close()
	return collectIssues(rows)
}
List method · go · L99-L125 (27 LOC)
backend/internal/storage/sqlite/repo.go
func (r *issueRepo) List(ctx context.Context, f storage.IssueFilter) ([]domain.Issue, error) {
	q := selectIssueCols + ` WHERE 1=1`
	var args []any
	if f.BoardID != nil {
		q += ` AND board_id = ?`
		args = append(args, *f.BoardID)
	}
	if f.Status != nil {
		q += ` AND status = ?`
		args = append(args, string(*f.Status))
	}
	if f.ParentID != nil {
		if *f.ParentID == "" {
			q += ` AND parent_id IS NULL`
		} else {
			q += ` AND parent_id = ?`
			args = append(args, *f.ParentID)
		}
	}
	q += ` ORDER BY position ASC, created_at DESC`
	rows, err := r.db.QueryContext(ctx, q, args...)
	if err != nil {
		return nil, fmt.Errorf("sqlite: list issues: %w", err)
	}
	defer rows.Close()
	return collectIssues(rows)
}
Update method · go · L127-L191 (65 LOC)
backend/internal/storage/sqlite/repo.go
func (r *issueRepo) Update(ctx context.Context, id string, p storage.IssuePatch) (domain.Issue, error) {
	tx, err := r.db.BeginTx(ctx, nil)
	if err != nil {
		return domain.Issue{}, fmt.Errorf("sqlite: begin: %w", err)
	}
	defer tx.Rollback()

	cur, err := scanIssue(tx.QueryRowContext(ctx, selectIssueCols+` WHERE id = ?`, id))
	if err != nil {
		return domain.Issue{}, err
	}

	if p.Title != nil {
		cur.Title = *p.Title
	}
	if p.Body != nil {
		cur.Body = *p.Body
	}
	if p.Status != nil {
		cur.Status = *p.Status
	}
	if p.Properties != nil {
		cur.Properties = *p.Properties
	}
	if p.Instructions != nil {
		cur.Instructions = *p.Instructions
	}
	if p.Criteria != nil {
		cur.Criteria = *p.Criteria
	}
	if p.ParentID != nil {
		newParent := *p.ParentID
		if newParent != nil {
			if *newParent == id {
				return domain.Issue{}, storage.ErrCycle
			}
			// Recursive CTE로 순환 탐지
			hasCycle, err := detectCycleTx(ctx, tx, id, *newParent)
			if err != nil {
				return domain.Issue{}, err
			}
			i
Delete method · go · L193-L203 (11 LOC)
backend/internal/storage/sqlite/repo.go
func (r *issueRepo) Delete(ctx context.Context, id string) error {
	res, err := r.db.ExecContext(ctx, `DELETE FROM issues WHERE id = ?`, id)
	if err != nil {
		return fmt.Errorf("sqlite: delete issue: %w", err)
	}
	n, _ := res.RowsAffected()
	if n == 0 {
		return storage.ErrNotFound
	}
	return nil
}
Approve method · go · L205-L218 (14 LOC)
backend/internal/storage/sqlite/repo.go
func (r *issueRepo) Approve(ctx context.Context, id string, now time.Time) (domain.Issue, error) {
	// 멱등: 이미 Approved면 approved_at 유지, 상태만 확정
	_, err := r.db.ExecContext(ctx, `
		UPDATE issues
		SET status='Approved',
		    approved_at = COALESCE(approved_at, ?),
		    updated_at = ?
		WHERE id = ? AND status IN ('Pending','Approved')`,
		now.UTC(), now.UTC(), id)
	if err != nil {
		return domain.Issue{}, fmt.Errorf("sqlite: approve: %w", err)
	}
	return r.GetByID(ctx, id)
}
Complete method · go · L220-L243 (24 LOC)
backend/internal/storage/sqlite/repo.go
func (r *issueRepo) Complete(ctx context.Context, id string, now time.Time) (domain.Issue, error) {
	res, err := r.db.ExecContext(ctx, `
		UPDATE issues
		SET status='Done',
		    completed_at = COALESCE(completed_at, ?),
		    updated_at = ?
		WHERE id = ? AND status = 'QA'`,
		now.UTC(), now.UTC(), id)
	if err != nil {
		return domain.Issue{}, fmt.Errorf("sqlite: complete: %w", err)
	}
	n, _ := res.RowsAffected()
	if n == 0 {
		cur, err := r.GetByID(ctx, id)
		if err != nil {
			return domain.Issue{}, err
		}
		if cur.Status == domain.StatusDone {
			return cur, nil // 멱등
		}
		return domain.Issue{}, storage.ErrConflict
	}
	return r.GetByID(ctx, id)
}
Repobility · open methodology · https://repobility.com/research/
GetMonthStats method · go · L245-L284 (40 LOC)
backend/internal/storage/sqlite/repo.go
func (r *issueRepo) GetMonthStats(ctx context.Context, year int, month time.Month) ([]storage.DayCount, error) {
	start := time.Date(year, month, 1, 0, 0, 0, 0, time.UTC)
	end := start.AddDate(0, 1, 0)
	q := `
		WITH days AS (
			SELECT substr(created_at, 1, 10) AS d, 1 AS c, 0 AS a, 0 AS f FROM issues
			WHERE created_at >= ? AND created_at < ?
			UNION ALL
			SELECT substr(approved_at, 1, 10) AS d, 0, 1, 0 FROM issues
			WHERE approved_at IS NOT NULL AND approved_at >= ? AND approved_at < ?
			UNION ALL
			SELECT substr(completed_at, 1, 10) AS d, 0, 0, 1 FROM issues
			WHERE completed_at IS NOT NULL AND completed_at >= ? AND completed_at < ?
		)
		SELECT d, SUM(c), SUM(a), SUM(f)
		FROM days
		GROUP BY d
		ORDER BY d`
	rows, err := r.db.QueryContext(ctx, q, start, end, start, end, start, end)
	if err != nil {
		return nil, fmt.Errorf("sqlite: month stats: %w", err)
	}
	defer rows.Close()
	var out []storage.DayCount
	for rows.Next() {
		var dateStr sql.NullString
		var c storage.DayCo
GetDayStats method · go · L286-L312 (27 LOC)
backend/internal/storage/sqlite/repo.go
func (r *issueRepo) GetDayStats(ctx context.Context, day time.Time) (storage.DayStats, error) {
	start := time.Date(day.Year(), day.Month(), day.Day(), 0, 0, 0, 0, time.UTC)
	end := start.AddDate(0, 0, 1)
	qBy := func(column string) ([]domain.Issue, error) {
		rows, err := r.db.QueryContext(ctx, selectIssueCols+
			fmt.Sprintf(` WHERE %s IS NOT NULL AND %s >= ? AND %s < ? ORDER BY %s ASC`, column, column, column, column),
			start, end)
		if err != nil {
			return nil, fmt.Errorf("sqlite: day stats %s: %w", column, err)
		}
		defer rows.Close()
		return collectIssues(rows)
	}
	created, err := qBy("created_at")
	if err != nil {
		return storage.DayStats{}, err
	}
	approved, err := qBy("approved_at")
	if err != nil {
		return storage.DayStats{}, err
	}
	completed, err := qBy("completed_at")
	if err != nil {
		return storage.DayStats{}, err
	}
	return storage.DayStats{Created: created, Approved: approved, Completed: completed}, nil
}
ReorderIssues method · go · L314-L326 (13 LOC)
backend/internal/storage/sqlite/repo.go
func (r *issueRepo) ReorderIssues(ctx context.Context, issueIDs []string) error {
	tx, err := r.db.BeginTx(ctx, nil)
	if err != nil {
		return fmt.Errorf("sqlite: begin: %w", err)
	}
	defer tx.Rollback()
	for pos, id := range issueIDs {
		if _, err := tx.ExecContext(ctx, `UPDATE issues SET position=? WHERE id=?`, pos, id); err != nil {
			return fmt.Errorf("sqlite: reorder issue: %w", err)
		}
	}
	return tx.Commit()
}
AddDependency method · go · L328-L336 (9 LOC)
backend/internal/storage/sqlite/repo.go
func (r *issueRepo) AddDependency(ctx context.Context, blockerID, blockedID string) error {
	_, err := r.db.ExecContext(ctx,
		`INSERT OR IGNORE INTO issue_dependencies (blocker_id, blocked_id) VALUES (?, ?)`,
		blockerID, blockedID)
	if err != nil {
		return fmt.Errorf("sqlite: add dependency: %w", err)
	}
	return nil
}
RemoveDependency method · go · L338-L346 (9 LOC)
backend/internal/storage/sqlite/repo.go
func (r *issueRepo) RemoveDependency(ctx context.Context, blockerID, blockedID string) error {
	_, err := r.db.ExecContext(ctx,
		`DELETE FROM issue_dependencies WHERE blocker_id = ? AND blocked_id = ?`,
		blockerID, blockedID)
	if err != nil {
		return fmt.Errorf("sqlite: remove dependency: %w", err)
	}
	return nil
}
GetBlockedBy method · go · L348-L364 (17 LOC)
backend/internal/storage/sqlite/repo.go
func (r *issueRepo) GetBlockedBy(ctx context.Context, issueID string) ([]string, error) {
	rows, err := r.db.QueryContext(ctx,
		`SELECT blocker_id FROM issue_dependencies WHERE blocked_id = ?`, issueID)
	if err != nil {
		return nil, fmt.Errorf("sqlite: get blocked by: %w", err)
	}
	defer rows.Close()
	var out []string
	for rows.Next() {
		var id string
		if err := rows.Scan(&id); err != nil {
			return nil, err
		}
		out = append(out, id)
	}
	return out, rows.Err()
}
scanIssue function · go · L372-L411 (40 LOC)
backend/internal/storage/sqlite/repo.go
func scanIssue(row interface{ Scan(...any) error }) (domain.Issue, error) {
	var i domain.Issue
	var parent sql.NullString
	var propsStr, criteriaStr string
	var approvedAt, completedAt sql.NullTime
	err := row.Scan(&i.ID, &i.BoardID, &parent, &i.Title, &i.Body, &i.Instructions, &i.Status, &propsStr, &criteriaStr, &i.Position, &i.CreatedAt, &i.UpdatedAt, &approvedAt, &completedAt)
	if err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			return domain.Issue{}, storage.ErrNotFound
		}
		return domain.Issue{}, fmt.Errorf("sqlite: scan issue: %w", err)
	}
	if propsStr != "" {
		_ = json.Unmarshal([]byte(propsStr), &i.Properties)
	}
	if criteriaStr != "" {
		_ = json.Unmarshal([]byte(criteriaStr), &i.Criteria)
	}
	if i.Criteria == nil {
		i.Criteria = []domain.Criterion{}
	}
	if i.Properties == nil {
		i.Properties = map[string]any{}
	}
	if parent.Valid {
		p := parent.String
		i.ParentID = &p
	}
	if approvedAt.Valid {
		t := approvedAt.Time.UTC()
		i.ApprovedAt = &t
	}
	if completedAt.Vali
collectIssues function · go · L413-L423 (11 LOC)
backend/internal/storage/sqlite/repo.go
func collectIssues(rows *sql.Rows) ([]domain.Issue, error) {
	var out []domain.Issue
	for rows.Next() {
		i, err := scanIssue(rows)
		if err != nil {
			return nil, err
		}
		out = append(out, i)
	}
	return out, rows.Err()
}
Open data scored by Repobility · https://repobility.com
utcPtr function · go · L425-L431 (7 LOC)
backend/internal/storage/sqlite/repo.go
func utcPtr(t *time.Time) any {
	if t == nil {
		return nil
	}
	u := t.UTC()
	return u
}
detectCycleTx function · go · L434-L451 (18 LOC)
backend/internal/storage/sqlite/repo.go
func detectCycleTx(ctx context.Context, tx *sql.Tx, self, target string) (bool, error) {
	q := `
		WITH RECURSIVE ancestors(id) AS (
			SELECT parent_id FROM issues WHERE id = ?
			UNION ALL
			SELECT i.parent_id FROM issues i JOIN ancestors a ON i.id = a.id WHERE i.parent_id IS NOT NULL
		)
		SELECT 1 FROM ancestors WHERE id = ? LIMIT 1`
	var hit int
	err := tx.QueryRowContext(ctx, q, target, self).Scan(&hit)
	if err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			return false, nil
		}
		return false, fmt.Errorf("sqlite: cycle detect: %w", err)
	}
	return hit == 1, nil
}
Create method · go · L459-L467 (9 LOC)
backend/internal/storage/sqlite/repo.go
func (r *boardRepo) Create(ctx context.Context, b domain.Board) (domain.Board, error) {
	_, err := r.db.ExecContext(ctx,
		`INSERT INTO boards (id, name, view_type, created_at) VALUES (?, ?, ?, ?)`,
		b.ID, b.Name, b.ViewType, b.CreatedAt.UTC())
	if err != nil {
		return domain.Board{}, fmt.Errorf("sqlite: create board: %w", err)
	}
	return b, nil
}
GetByID method · go · L469-L482 (14 LOC)
backend/internal/storage/sqlite/repo.go
func (r *boardRepo) GetByID(ctx context.Context, id string) (domain.Board, error) {
	var b domain.Board
	err := r.db.QueryRowContext(ctx,
		`SELECT id, name, view_type, created_at FROM boards WHERE id = ?`, id).
		Scan(&b.ID, &b.Name, &b.ViewType, &b.CreatedAt)
	if err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			return domain.Board{}, storage.ErrNotFound
		}
		return domain.Board{}, fmt.Errorf("sqlite: get board: %w", err)
	}
	b.CreatedAt = b.CreatedAt.UTC()
	return b, nil
}
List method · go · L484-L501 (18 LOC)
backend/internal/storage/sqlite/repo.go
func (r *boardRepo) List(ctx context.Context) ([]domain.Board, error) {
	rows, err := r.db.QueryContext(ctx,
		`SELECT id, name, view_type, created_at FROM boards ORDER BY created_at ASC`)
	if err != nil {
		return nil, fmt.Errorf("sqlite: list boards: %w", err)
	}
	defer rows.Close()
	var out []domain.Board
	for rows.Next() {
		var b domain.Board
		if err := rows.Scan(&b.ID, &b.Name, &b.ViewType, &b.CreatedAt); err != nil {
			return nil, err
		}
		b.CreatedAt = b.CreatedAt.UTC()
		out = append(out, b)
	}
	return out, rows.Err()
}
Update method · go · L503-L521 (19 LOC)
backend/internal/storage/sqlite/repo.go
func (r *boardRepo) Update(ctx context.Context, id string, name *string, viewType *domain.ViewType) (domain.Board, error) {
	cur, err := r.GetByID(ctx, id)
	if err != nil {
		return domain.Board{}, err
	}
	if name != nil {
		cur.Name = *name
	}
	if viewType != nil {
		cur.ViewType = *viewType
	}
	_, err = r.db.ExecContext(ctx,
		`UPDATE boards SET name=?, view_type=? WHERE id=?`,
		cur.Name, cur.ViewType, id)
	if err != nil {
		return domain.Board{}, fmt.Errorf("sqlite: update board: %w", err)
	}
	return cur, nil
}
Delete method · go · L523-L533 (11 LOC)
backend/internal/storage/sqlite/repo.go
func (r *boardRepo) Delete(ctx context.Context, id string) error {
	res, err := r.db.ExecContext(ctx, `DELETE FROM boards WHERE id = ?`, id)
	if err != nil {
		return fmt.Errorf("sqlite: delete board: %w", err)
	}
	n, _ := res.RowsAffected()
	if n == 0 {
		return storage.ErrNotFound
	}
	return nil
}
Create method · go · L20-L39 (20 LOC)
backend/internal/storage/sqlite/webhook_repo.go
func (r *webhookRepo) Create(ctx context.Context, wh domain.Webhook) (domain.Webhook, error) {
	if wh.ID == "" {
		wh.ID = uuid.NewString()
	}
	if wh.CreatedAt.IsZero() {
		wh.CreatedAt = time.Now().UTC()
	}
	evts, _ := json.Marshal(wh.Events)
	enabled := 0
	if wh.Enabled {
		enabled = 1
	}
	_, err := r.db.ExecContext(ctx,
		`INSERT INTO webhooks (id, board_id, name, url, events, enabled, created_at) VALUES (?,?,?,?,?,?,?)`,
		wh.ID, wh.BoardID, wh.Name, wh.URL, string(evts), enabled, wh.CreatedAt.UTC())
	if err != nil {
		return domain.Webhook{}, fmt.Errorf("sqlite: create webhook: %w", err)
	}
	return wh, nil
}
Methodology: Repobility · https://repobility.com/research/state-of-ai-code-2026/
List method · go · L41-L49 (9 LOC)
backend/internal/storage/sqlite/webhook_repo.go
func (r *webhookRepo) List(ctx context.Context, boardID string) ([]domain.Webhook, error) {
	rows, err := r.db.QueryContext(ctx,
		`SELECT id, board_id, name, url, events, enabled, created_at FROM webhooks WHERE board_id = ? ORDER BY created_at ASC`, boardID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	return scanWebhooks(rows)
}
ListByEvent method · go · L51-L69 (19 LOC)
backend/internal/storage/sqlite/webhook_repo.go
func (r *webhookRepo) ListByEvent(ctx context.Context, boardID string, event domain.WebhookEvent) ([]domain.Webhook, error) {
	all, err := r.List(ctx, boardID)
	if err != nil {
		return nil, err
	}
	var out []domain.Webhook
	for _, wh := range all {
		if !wh.Enabled {
			continue
		}
		for _, e := range wh.Events {
			if e == event {
				out = append(out, wh)
				break
			}
		}
	}
	return out, nil
}
Update method · go · L71-L100 (30 LOC)
backend/internal/storage/sqlite/webhook_repo.go
func (r *webhookRepo) Update(ctx context.Context, id string, name *string, url *string, events *[]domain.WebhookEvent, enabled *bool) (domain.Webhook, error) {
	wh, err := r.getByID(ctx, id)
	if err != nil {
		return domain.Webhook{}, err
	}
	if name != nil {
		wh.Name = *name
	}
	if url != nil {
		wh.URL = *url
	}
	if events != nil {
		wh.Events = *events
	}
	if enabled != nil {
		wh.Enabled = *enabled
	}
	evts, _ := json.Marshal(wh.Events)
	en := 0
	if wh.Enabled {
		en = 1
	}
	_, err = r.db.ExecContext(ctx,
		`UPDATE webhooks SET name=?, url=?, events=?, enabled=? WHERE id=?`,
		wh.Name, wh.URL, string(evts), en, id)
	if err != nil {
		return domain.Webhook{}, err
	}
	return wh, nil
}
‹ prevpage 3 / 6next ›