1package main 2 3import ( 4 "context" 5 "database/sql" 6 "encoding/json" 7 "fmt" 8 "strings" 9 10 sdk "github.com/apteva/app-sdk" 11) 12 13// ─── tables_create ───────────────────────────────────────────────── 14 15func (a *App) toolTablesCreate(ctx *sdk.AppCtx, args map[string]any) (any, error) { 16 ctx, finish, err := a.beginOperation(ctx, args, "tables_create", true) 17 if err != nil { 18 return nil, err 19 } 20 defer finish() 21 pid, err := resolveProjectFromArgs(args) 22 if err != nil { 23 return nil, err 24 } 25 name := strArg(args, "name") 26 if err := validateIdentifier("table", name); err != nil { 27 return nil, err 28 } 29 scope := strArg(args, "scope") 30 if scope == "" { 31 scope = "project" 32 } 33 if scope != "project" { 34 return nil, errf("table scope must be 'project'; install the app globally to serve multiple projects while keeping each project's tables isolated") 35 } 36 37 rawCols := sliceArg(args, "columns") 38 if len(rawCols) == 0 { 39 return nil, errf("at least one column is required") 40 } 41 if err := checkBatchBytes(ctx, rawCols); err != nil { 42 return nil, err 43 } 44 cols, err := parseColumnDefs(rawCols) 45 if err != nil { 46 return nil, err 47 } 48 for _, c := range cols { 49 if c.Default == nil { 50 continue 51 } 52 v, _ := coerceForStorage(c, c.Default) 53 if err := validateStoredValueSize(ctx, c, v); err != nil { 54 return nil, errf("column %q default: %v", c.Name, err) 55 } 56 } 57 58 tx, err := beginWrite(ctx) 59 if err != nil { 60 return nil, err