codegen: implement auto-timestamps for created_at and updated_at
Some checks failed
CI / build-docker (push) Successful in 7s
CI / build-docker-bootstrap (push) Has been skipped
CI / release-test (push) Failing after 3m7s

This commit is contained in:
wispem-wantex 2026-01-31 20:35:03 -08:00
parent 75b7662c34
commit 5973a2a4b7
3 changed files with 51 additions and 16 deletions

View File

@ -40,7 +40,9 @@ create table item_flavor (rowid integer primary key, name text not null) strict;
create table items (
rowid integer primary key,
description text not null default '',
flavor integer references item_flavor(rowid)
flavor integer references item_flavor(rowid),
created_at integer not null,
updated_at integer not null
) strict;
EOF

View File

@ -97,6 +97,9 @@ func GenerateSaveItemFunc(tbl schema.Table) *ast.FuncDecl {
insertVals := make([]string, 0, len(tbl.Columns))
updatePairs := make([]string, 0, len(tbl.Columns))
hasCreatedAt, hasUpdatedAt := tbl.HasAutoTimestamps()
// Assemble data for building SQL "insert" and "update" strings
for _, col := range tbl.Columns {
if col.Name == "rowid" {
continue
@ -107,8 +110,14 @@ func GenerateSaveItemFunc(tbl schema.Table) *ast.FuncDecl {
val = fmt.Sprintf("nullif(%s, 0)", val)
}
insertVals = append(insertVals, val)
// created_at should not be updated after creation
if col.Name == "created_at" && hasCreatedAt {
continue
}
updatePairs = append(updatePairs, col.Name+"="+val)
}
insertStmt := fmt.Sprintf("\n\t\t insert into %s (%s)\n\t\t values (%s)\n\t\t", tbl.TableName, strings.Join(insertCols, ", "), strings.Join(insertVals, ", "))
updateStmt := fmt.Sprintf("\n\t\t update %s\n\t\t set %s\n\t\t where rowid = :rowid\n\t\t", tbl.TableName, strings.Join(updatePairs, ",\n\t\t "))
hasFks := false
checkForeignKeyFailuresAssignment := &ast.AssignStmt{
@ -235,15 +244,20 @@ func GenerateSaveItemFunc(tbl schema.Table) *ast.FuncDecl {
},
}
insertStmt := fmt.Sprintf("\n\t\t insert into %s (%s)\n\t\t values (%s)\n\t\t", tbl.TableName, strings.Join(insertCols, ", "), strings.Join(insertVals, ", "))
updateStmt := fmt.Sprintf("\n\t\t update %s\n\t\t set %s\n\t\t where rowid = :rowid\n\t\t", tbl.TableName, strings.Join(updatePairs, ",\n\t\t "))
funcBody := &ast.BlockStmt{
List: func() []ast.Stmt {
ret := []ast.Stmt{}
if hasFks {
ret = append(ret, checkForeignKeyFailuresAssignment)
}
if hasUpdatedAt {
// Auto-timestamps: updated_at
ret = append(ret, &ast.AssignStmt{
Lhs: []ast.Expr{&ast.SelectorExpr{X: ast.NewIdent(tbl.VarName), Sel: ast.NewIdent("UpdatedAt")}},
Tok: token.ASSIGN,
Rhs: []ast.Expr{&ast.CallExpr{Fun: ast.NewIdent("TimestampNow"), Args: []ast.Expr{}}},
})
}
// if item.ID == 0 {...} else {...}
ret = append(ret, &ast.IfStmt{
Cond: &ast.BinaryExpr{
@ -255,6 +269,15 @@ func GenerateSaveItemFunc(tbl schema.Table) *ast.FuncDecl {
// Do create
List: append(
func() []ast.Stmt {
ret := []ast.Stmt{}
if hasCreatedAt {
// Auto-timestamps: created_at
ret = append(ret, &ast.AssignStmt{
Lhs: []ast.Expr{&ast.SelectorExpr{X: ast.NewIdent(tbl.VarName), Sel: ast.NewIdent("CreatedAt")}},
Tok: token.ASSIGN,
Rhs: []ast.Expr{&ast.CallExpr{Fun: ast.NewIdent("TimestampNow"), Args: []ast.Expr{}}},
})
}
namedExecStmt := &ast.CallExpr{
Fun: &ast.SelectorExpr{X: ast.NewIdent("db.DB"), Sel: ast.NewIdent("NamedExec")},
Args: []ast.Expr{
@ -264,19 +287,17 @@ func GenerateSaveItemFunc(tbl schema.Table) *ast.FuncDecl {
}
if !hasFks {
// No foreign key checking needed; just use `Must` for brevity
return []ast.Stmt{
&ast.AssignStmt{
Lhs: []ast.Expr{ast.NewIdent("result")},
Tok: token.DEFINE,
Rhs: []ast.Expr{&ast.CallExpr{
Fun: ast.NewIdent("Must"),
Args: []ast.Expr{namedExecStmt},
}},
},
}
return append(ret, &ast.AssignStmt{
Lhs: []ast.Expr{ast.NewIdent("result")},
Tok: token.DEFINE,
Rhs: []ast.Expr{&ast.CallExpr{
Fun: ast.NewIdent("Must"),
Args: []ast.Expr{namedExecStmt},
}},
})
}
return []ast.Stmt{
return append(ret,
// result, err := db.DB.NamedExec(`...`, u)
&ast.AssignStmt{
Lhs: []ast.Expr{
@ -329,7 +350,7 @@ func GenerateSaveItemFunc(tbl schema.Table) *ast.FuncDecl {
},
},
},
}
)
}(),
&ast.AssignStmt{
Lhs: []ast.Expr{&ast.SelectorExpr{X: ast.NewIdent(tbl.VarName), Sel: ast.NewIdent("ID")}},

View File

@ -46,6 +46,18 @@ type Table struct {
GoTypeName string
}
func (t Table) HasAutoTimestamps() (hasCreatedAt bool, hasUpdatedAt bool) {
for _, c := range t.Columns {
if c.Name == "created_at" && c.Type == "integer" {
hasCreatedAt = true
}
if c.Name == "updated_at" && c.Type == "integer" {
hasUpdatedAt = true
}
}
return
}
type Index struct {
Name string `db:"index_name"`
TableName string `db:"table_name"`