diff --git a/backend/controller/cronjobs/cronjobs_integration_test.go b/backend/controller/cronjobs/cronjobs_integration_test.go index debc018f36..54e0a92d3a 100644 --- a/backend/controller/cronjobs/cronjobs_integration_test.go +++ b/backend/controller/cronjobs/cronjobs_integration_test.go @@ -4,19 +4,13 @@ package cronjobs import ( "context" - "sync" "testing" "time" - "connectrpc.com/connect" db "github.com/TBD54566975/ftl/backend/controller/dal" "github.com/TBD54566975/ftl/backend/controller/sql/sqltest" - ftlv1 "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/v1" - "github.com/TBD54566975/ftl/backend/schema" "github.com/TBD54566975/ftl/internal/log" - "github.com/TBD54566975/ftl/internal/model" "github.com/alecthomas/assert/v2" - "github.com/alecthomas/types/optional" "github.com/benbjohnson/clock" ) diff --git a/go-runtime/compile/schema.go b/go-runtime/compile/schema.go index 926cf19b0b..a40db0b982 100644 --- a/go-runtime/compile/schema.go +++ b/go-runtime/compile/schema.go @@ -33,11 +33,12 @@ var ( return mustLoadRef("builtin", "error").Type().Underlying().(*types.Interface) //nolint:forcetypeassert }) - ftlCallFuncPath = "github.com/TBD54566975/ftl/go-runtime/ftl.Call" - ftlConfigFuncPath = "github.com/TBD54566975/ftl/go-runtime/ftl.Config" - ftlSecretFuncPath = "github.com/TBD54566975/ftl/go-runtime/ftl.Secret" //nolint:gosec - ftlUnitTypePath = "github.com/TBD54566975/ftl/go-runtime/ftl.Unit" - aliasFieldTag = "json" + ftlCallFuncPath = "github.com/TBD54566975/ftl/go-runtime/ftl.Call" + ftlConfigFuncPath = "github.com/TBD54566975/ftl/go-runtime/ftl.Config" + ftlSecretFuncPath = "github.com/TBD54566975/ftl/go-runtime/ftl.Secret" //nolint:gosec + ftlDatabaseFuncPath = "github.com/TBD54566975/ftl/go-runtime/ftl.PostgresDatabase" + ftlUnitTypePath = "github.com/TBD54566975/ftl/go-runtime/ftl.Unit" + aliasFieldTag = "json" ) // NativeNames is a map of top-level declarations to their native Go names. @@ -181,6 +182,8 @@ func visitCallExpr(pctx *parseContext, node *ast.CallExpr) { case ftlConfigFuncPath, ftlSecretFuncPath: // Secret/config declaration: ftl.Config[]() parseConfigDecl(pctx, node, fn) + case ftlDatabaseFuncPath: + parseDatabaseDecl(pctx, node) } } @@ -227,6 +230,7 @@ func parseConfigDecl(pctx *parseContext, node *ast.CallExpr, fn *types.Func) { } if name == "" { pctx.errors.add(errorf(node, "config and secret declarations must have a single string literal argument")) + return } index := node.Fun.(*ast.IndexExpr) //nolint:forcetypeassert @@ -256,6 +260,29 @@ func parseConfigDecl(pctx *parseContext, node *ast.CallExpr, fn *types.Func) { pctx.module.Decls = append(pctx.module.Decls, decl) } +func parseDatabaseDecl(pctx *parseContext, node *ast.CallExpr) { + var name string + if len(node.Args) == 1 { + if literal, ok := node.Args[0].(*ast.BasicLit); ok && literal.Kind == token.STRING { + var err error + name, err = strconv.Unquote(literal.Value) + if err != nil { + pctx.errors.add(wrapf(node, err, "")) + return + } + } + } + if name == "" { + pctx.errors.add(errorf(node, "config and secret declarations must have a single string literal argument")) + return + } + decl := &schema.Database{ + Pos: goPosToSchemaPos(node.Pos()), + Name: name, + } + pctx.module.Decls = append(pctx.module.Decls, decl) +} + func visitFile(pctx *parseContext, node *ast.File) { if node.Doc == nil { return diff --git a/go-runtime/compile/schema_test.go b/go-runtime/compile/schema_test.go index 9854882684..914f42c664 100644 --- a/go-runtime/compile/schema_test.go +++ b/go-runtime/compile/schema_test.go @@ -50,6 +50,8 @@ func TestExtractModuleSchema(t *testing.T) { config configValue one.Config secret secretValue String + database testDb + enum Color(String) { Red("Red") Blue("Blue") diff --git a/go-runtime/compile/testdata/one/one.go b/go-runtime/compile/testdata/one/one.go index 37b8c7ff94..164916de61 100644 --- a/go-runtime/compile/testdata/one/one.go +++ b/go-runtime/compile/testdata/one/one.go @@ -75,6 +75,7 @@ type Config struct { var configValue = ftl.Config[Config]("configValue") var secretValue = ftl.Secret[string]("secretValue") +var testDb = ftl.PostgresDatabase("testDb") //ftl:export func Verb(ctx context.Context, req Req) (Resp, error) { diff --git a/integration/testdata/go/database/echo.go b/integration/testdata/go/database/echo.go index 047072de2a..21cd719a6f 100644 --- a/integration/testdata/go/database/echo.go +++ b/integration/testdata/go/database/echo.go @@ -16,7 +16,7 @@ type InsertResponse struct{} //ftl:export func Insert(ctx context.Context, req InsertRequest) (InsertResponse, error) { - err := persistRequest(req) + err := persistRequest(ctx, req) if err != nil { return InsertResponse{}, err } @@ -24,8 +24,8 @@ func Insert(ctx context.Context, req InsertRequest) (InsertResponse, error) { return InsertResponse{}, nil } -func persistRequest(req InsertRequest) error { - _, err := db.Exec(`CREATE TABLE IF NOT EXISTS requests +func persistRequest(ctx context.Context, req InsertRequest) error { + _, err := db.Get(ctx).Exec(`CREATE TABLE IF NOT EXISTS requests ( data TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT (NOW() AT TIME ZONE 'utc'), @@ -34,7 +34,7 @@ func persistRequest(req InsertRequest) error { if err != nil { return err } - _, err = db.Exec("INSERT INTO requests (data) VALUES ($1);", req.Data) + _, err = db.Get(ctx).Exec("INSERT INTO requests (data) VALUES ($1);", req.Data) if err != nil { return err }