Seed from go-template-repo, renamed to simplexcalc
The template's files at a77fd30, without its history or LICENSE, after script/rename simplexcalc. Model: opus-5-5
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
// Go has no UUID in the standard library as of go1.25 — checked
|
||||
// against this repo's toolchain, not assumed. Swap this import for
|
||||
// the stdlib package the moment one lands; nothing else here
|
||||
// depends on the implementation.
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// timeFormat matches the strftime pattern the schema uses for its
|
||||
// defaults, so rows written by Go and rows written by a DEFAULT sort
|
||||
// against each other correctly.
|
||||
const timeFormat = "2006-01-02T15:04:05.000Z"
|
||||
|
||||
// Widget is the example row type. It exists so that the migration
|
||||
// runner, the query layer, the templates and the tests all exercise
|
||||
// real data. Delete it when seeding a real project.
|
||||
type Widget struct {
|
||||
ID string
|
||||
Name string
|
||||
SizeBytes int64
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
// CreateWidget inserts a widget and returns it as stored.
|
||||
func (d *Database) CreateWidget(
|
||||
ctx context.Context, name string, size int64,
|
||||
) (*Widget, error) {
|
||||
w := &Widget{
|
||||
ID: uuid.NewString(),
|
||||
Name: name,
|
||||
SizeBytes: size,
|
||||
CreatedAt: time.Now().UTC(),
|
||||
}
|
||||
|
||||
_, err := d.db.ExecContext(ctx,
|
||||
`INSERT INTO widgets (id, name, size_bytes, created_at) VALUES (?, ?, ?, ?)`,
|
||||
w.ID, w.Name, w.SizeBytes, w.CreatedAt.Format(timeFormat),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("inserting widget: %w", err)
|
||||
}
|
||||
|
||||
return w, nil
|
||||
}
|
||||
|
||||
// ListWidgets returns the most recently created widgets, newest first,
|
||||
// up to limit.
|
||||
func (d *Database) ListWidgets(ctx context.Context, limit int) ([]Widget, error) {
|
||||
rows, err := d.db.QueryContext(ctx,
|
||||
`SELECT id, name, size_bytes, created_at
|
||||
FROM widgets
|
||||
ORDER BY created_at DESC, id DESC
|
||||
LIMIT ?`,
|
||||
limit,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("listing widgets: %w", err)
|
||||
}
|
||||
defer func() { _ = rows.Close() }()
|
||||
|
||||
widgets := []Widget{}
|
||||
|
||||
for rows.Next() {
|
||||
var (
|
||||
w Widget
|
||||
createdAt string
|
||||
)
|
||||
|
||||
scanErr := rows.Scan(&w.ID, &w.Name, &w.SizeBytes, &createdAt)
|
||||
if scanErr != nil {
|
||||
return nil, fmt.Errorf("scanning widget: %w", scanErr)
|
||||
}
|
||||
|
||||
w.CreatedAt, scanErr = time.Parse(timeFormat, createdAt)
|
||||
if scanErr != nil {
|
||||
return nil, fmt.Errorf("parsing widget created_at %q: %w", createdAt, scanErr)
|
||||
}
|
||||
|
||||
widgets = append(widgets, w)
|
||||
}
|
||||
|
||||
err = rows.Err()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("iterating widgets: %w", err)
|
||||
}
|
||||
|
||||
return widgets, nil
|
||||
}
|
||||
|
||||
// CountWidgets returns the number of widgets stored.
|
||||
func (d *Database) CountWidgets(ctx context.Context) (int, error) {
|
||||
var n int
|
||||
|
||||
err := d.db.QueryRowContext(ctx, `SELECT COUNT(*) FROM widgets`).Scan(&n)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("counting widgets: %w", err)
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
Reference in New Issue
Block a user