package {{.PackageName}} import ( "database/sql" "errors" "iter" "github.com/mattn/go-sqlite3" ) var ( ErrConstraint = errors.New("constraint violation") ErrNotFound = errors.New("not found") ) func translateError(err error) error { if err == nil { return nil } if e, ok := err.(sqlite3.Error); ok && e.Code == 19 { return errors.Join(ErrConstraint, err) } if errors.Is(err, sql.ErrNoRows) { return errors.Join(ErrNotFound, err) } return err } type TX interface { Exec(query string, args ...any) (sql.Result, error) Query(query string, args ...any) (*sql.Rows, error) QueryRow(query string, args ...any) *sql.Row } {{range .Schema.Tables}} // ---------------------------------------------------------------------------- // Table: {{.Name}} // ---------------------------------------------------------------------------- type {{.Type}} struct { {{- range .Columns}} {{.Name}} {{.Type}}{{end}} } const {{.Type}}_SelectQuery = "{{.SelectQuery}}" {{if not .NoInsert -}} func {{.Type}}_Insert( tx TX, row *{{.Type}}, ) (err error) { {{.Type}}_Sanitize(row) if err = {{.Type}}_Validate(row); err != nil { return err } _, err = tx.Exec("{{.InsertQuery}}", {{.InsertArgs}}) return translateError(err) } {{- end}} {{/* if not .NoInsert */}} {{if not .NoUpdate -}} {{if .UpdateCols -}} func {{.Type}}_Update( tx TX, row *{{.Type}}, ) (err error) { {{.Type}}_Sanitize(row) if err = {{.Type}}_Validate(row); err != nil { return err } result, err := tx.Exec("{{.UpdateQuery}}", {{.UpdateArgs}}) if err != nil { return translateError(err) } n, err := result.RowsAffected() if err != nil { panic(err) } switch n { case 0: return ErrNotFound case 1: return nil default: panic("multiple rows updated") } } {{- end}} {{if .UpdateFullCols -}} func {{.Type}}_UpdateFull( tx TX, row *{{.Type}}, ) (err error) { {{.Type}}_Sanitize(row) if err = {{.Type}}_Validate(row); err != nil { return err } result, err := tx.Exec("{{.UpdateFullQuery}}", {{.UpdateFullArgs}}) if err != nil { return translateError(err) } n, err := result.RowsAffected() if err != nil { panic(err) } switch n { case 0: return ErrNotFound case 1: return nil default: panic("multiple rows updated") } } {{- end}} {{- end}} {{/* if not .NoUpdate */}} {{if not .NoDelete -}} func {{.Type}}_Delete( tx TX, {{.PKFunctionArgs -}} ) (err error) { result, err := tx.Exec("{{.DeleteQuery}}", {{.DeleteArgs}}) if err != nil { return translateError(err) } n, err := result.RowsAffected() if err != nil { panic(err) } switch n { case 0: return ErrNotFound case 1: return nil default: panic("multiple rows deleted") } } {{- end}} func {{.Type}}_Get( tx TX, {{.PKFunctionArgs -}} ) ( row *{{.Type}}, err error, ) { row = &{{.Type}}{} r := tx.QueryRow("{{.GetQuery}}", {{.DeleteArgs}}) err = translateError(r.Scan({{.ScanArgs}})) return } func {{.Type}}_GetWhere( tx TX, query string, args ...any, ) ( row *{{.Type}}, err error, ) { row = &{{.Type}}{} r := tx.QueryRow(query, args...) err = translateError(r.Scan({{.ScanArgs}})) return } func {{.Type}}_Iterate( tx TX, query string, args ...any, ) ( iter.Seq2[*{{.Type}}, error], ) { rows, err := tx.Query(query, args...) if err != nil { return func(yield func(*{{.Type}}, error) bool) { yield(nil, err) } } return func(yield func(*{{.Type}}, error) bool) { defer rows.Close() for rows.Next() { row := &{{.Type}}{} err := translateError(rows.Scan({{.ScanArgs}})) if !yield(row, err) { return } } } } func {{.Type}}_List( tx TX, query string, args ...any, ) ( l []*{{.Type}}, err error, ) { for row, err := range {{.Type}}_Iterate(tx, query, args...) { if err != nil { return nil, err } l = append(l, row) } return l, nil } {{end}} {{/* range .Schema.Tables */}}