From f5a3b18ae917ece393e788d40d09f436c01aea4e Mon Sep 17 00:00:00 2001 From: worstell Date: Mon, 4 Nov 2024 13:08:26 -0800 Subject: [PATCH] revert: "feat: inject DB verb resources (#2985)" (#3323) reverting to unblock upgrading customers while we consider/implement [this](https://github.com/TBD54566975/ftl/pull/3153#issuecomment-2452728347) --------- Co-authored-by: github-actions[bot] --- .../admin/testdata/go/dischema/go.mod | 1 + .../admin/testdata/go/dischema/go.sum | 2 + .../console/testdata/go/console/go.mod | 1 + .../console/testdata/go/console/go.sum | 2 + .../cronjobs/testdata/go/cron/go.mod | 1 + .../cronjobs/testdata/go/cron/go.sum | 2 + .../cronjobs/testdata/go/cron/types.ftl.go | 27 ---- .../encryption/testdata/go/encryption/go.mod | 1 + .../encryption/testdata/go/encryption/go.sum | 2 + .../ingress/testdata/go/httpingress/go.mod | 1 + .../ingress/testdata/go/httpingress/go.sum | 2 + .../pubsub/testdata/go/publisher/go.mod | 1 + .../pubsub/testdata/go/publisher/go.sum | 2 + .../controller/pubsub/testdata/go/slow/go.mod | 1 + .../controller/pubsub/testdata/go/slow/go.sum | 2 + .../pubsub/testdata/go/subscriber/go.mod | 1 + .../pubsub/testdata/go/subscriber/go.sum | 2 + .../sql/testdata/go/database/database.go | 12 +- .../sql/testdata/go/database/database_test.go | 22 +--- .../sql/testdata/go/database/types.ftl.go | 20 --- backend/provisioner/testdata/go/echo/echo.go | 8 +- backend/provisioner/testdata/go/echo/go.mod | 1 + backend/provisioner/testdata/go/echo/go.sum | 2 + docs/content/docs/reference/unittests.md | 9 +- examples/go/cron/go.mod | 1 + examples/go/cron/go.sum | 2 + examples/go/http/go.mod | 1 + examples/go/http/go.sum | 2 + examples/go/pubsub/go.mod | 1 + examples/go/pubsub/go.sum | 2 + frontend/cli/testdata/go/echo/go.mod | 1 + frontend/cli/testdata/go/echo/go.sum | 2 + frontend/cli/testdata/go/time/go.mod | 1 + frontend/cli/testdata/go/time/go.sum | 2 + .../.ftl.tmpl/go/main/main.go.tmpl | 11 -- .../compile/build-template/types.ftl.go.tmpl | 11 -- go-runtime/compile/build.go | 76 +---------- .../compile/compile_integration_test.go | 4 +- .../testdata/go/notexportedverb/go.mod | 1 + .../testdata/go/notexportedverb/go.sum | 2 + go-runtime/compile/testdata/go/one/go.mod | 1 + go-runtime/compile/testdata/go/one/go.sum | 2 + go-runtime/compile/testdata/go/one/one.go | 7 +- .../compile/testdata/go/undefinedverb/go.mod | 1 + .../compile/testdata/go/undefinedverb/go.sum | 2 + .../encoding/testdata/go/omitempty/go.mod | 1 + .../encoding/testdata/go/omitempty/go.sum | 2 + go-runtime/ftl/database.go | 95 +++++++------- go-runtime/ftl/ftltest/ftltest.go | 55 +++----- go-runtime/ftl/reflection/database.go | 49 -------- go-runtime/ftl/reflection/singleton.go | 8 -- .../testdata/go/runtimereflection/go.mod | 1 + .../testdata/go/runtimereflection/go.sum | 2 + go-runtime/ftl/reflection/type_registry.go | 2 - go-runtime/ftl/testdata/go/echo/go.mod | 1 + go-runtime/ftl/testdata/go/echo/go.sum | 2 + go-runtime/goplugin/testdata/another/go.mod | 1 + go-runtime/goplugin/testdata/another/go.sum | 2 + go-runtime/goplugin/testdata/other/go.mod | 1 + go-runtime/goplugin/testdata/other/go.sum | 2 + go-runtime/internal/testdata/go/mapper/go.mod | 1 + go-runtime/internal/testdata/go/mapper/go.sum | 2 + go-runtime/schema/common/common.go | 76 ++++------- go-runtime/schema/common/fact.go | 31 +---- go-runtime/schema/config/analyzer.go | 114 ----------------- go-runtime/schema/database/analyzer.go | 73 +++-------- go-runtime/schema/extract.go | 7 +- go-runtime/schema/initialize/analyzer.go | 42 ++----- .../schema/schema_fuzz_integration_test.go | 8 +- go-runtime/schema/schema_integration_test.go | 79 ++++++------ .../schema/testdata/failing/child/child.go | 7 +- go-runtime/schema/testdata/failing/failing.go | 7 +- go-runtime/schema/testdata/failing/go.mod | 1 + go-runtime/schema/testdata/failing/go.sum | 2 + go-runtime/schema/testdata/fsm/types.ftl.go | 32 ----- go-runtime/schema/testdata/one/go.mod | 14 --- go-runtime/schema/testdata/one/go.sum | 24 ---- go-runtime/schema/testdata/one/one.go | 7 +- go-runtime/schema/testdata/one/types.ftl.go | 2 - go-runtime/schema/testdata/parent/go.mod | 1 + go-runtime/schema/testdata/parent/go.sum | 2 + go-runtime/schema/testdata/pubsub/go.mod | 1 + go-runtime/schema/testdata/pubsub/go.sum | 2 + go-runtime/schema/testdata/subscriber/go.mod | 1 + go-runtime/schema/testdata/subscriber/go.sum | 2 + go-runtime/schema/testdata/two/two.go | 8 +- go-runtime/schema/testdata/two/types.ftl.go | 2 - go-runtime/schema/testdata/validation/go.mod | 1 + go-runtime/schema/testdata/validation/go.sum | 2 + go-runtime/schema/verb/analyzer.go | 82 ++---------- go-runtime/server/database.go | 71 ----------- go-runtime/server/server.go | 118 +++++++++--------- .../testdata/go/plugintest/go.mod | 1 + .../testdata/go/plugintest/go.sum | 2 + internal/buildengine/testdata/another/go.mod | 1 + internal/buildengine/testdata/another/go.sum | 2 + internal/buildengine/testdata/other/go.mod | 1 + internal/buildengine/testdata/other/go.sum | 2 + internal/modulecontext/module_context.go | 2 +- .../projectconfig/testdata/go/echo/go.mod | 1 + .../projectconfig/testdata/go/echo/go.sum | 2 + .../testdata/go/findconfig/go.mod | 1 + .../testdata/go/findconfig/go.sum | 2 + .../testdata/go/validateconfig/go.mod | 1 + .../testdata/go/validateconfig/go.sum | 2 + internal/schema/verb.go | 9 -- internal/watch/testdata/another/go.mod | 1 + internal/watch/testdata/another/go.sum | 2 + internal/watch/testdata/other/go.mod | 1 + internal/watch/testdata/other/go.sum | 2 + jvm-runtime/testdata/go/gomodule/go.mod | 1 + jvm-runtime/testdata/go/gomodule/go.sum | 2 + smoketest/origin/go.mod | 1 + smoketest/origin/go.sum | 2 + smoketest/relay/relay.go | 2 + 115 files changed, 372 insertions(+), 975 deletions(-) delete mode 100644 backend/controller/cronjobs/testdata/go/cron/types.ftl.go delete mode 100644 backend/controller/sql/testdata/go/database/types.ftl.go delete mode 100644 go-runtime/ftl/reflection/database.go delete mode 100644 go-runtime/schema/config/analyzer.go delete mode 100644 go-runtime/schema/testdata/fsm/types.ftl.go delete mode 100644 go-runtime/server/database.go diff --git a/backend/controller/admin/testdata/go/dischema/go.mod b/backend/controller/admin/testdata/go/dischema/go.mod index 6fb04263c5..bb9ee02347 100644 --- a/backend/controller/admin/testdata/go/dischema/go.mod +++ b/backend/controller/admin/testdata/go/dischema/go.mod @@ -9,6 +9,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/backend/controller/admin/testdata/go/dischema/go.sum b/backend/controller/admin/testdata/go/dischema/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/backend/controller/admin/testdata/go/dischema/go.sum +++ b/backend/controller/admin/testdata/go/dischema/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/backend/controller/console/testdata/go/console/go.mod b/backend/controller/console/testdata/go/console/go.mod index 7711cca5d9..48032787b9 100644 --- a/backend/controller/console/testdata/go/console/go.mod +++ b/backend/controller/console/testdata/go/console/go.mod @@ -9,6 +9,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/backend/controller/console/testdata/go/console/go.sum b/backend/controller/console/testdata/go/console/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/backend/controller/console/testdata/go/console/go.sum +++ b/backend/controller/console/testdata/go/console/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/backend/controller/cronjobs/testdata/go/cron/go.mod b/backend/controller/cronjobs/testdata/go/cron/go.mod index 5a17dcd854..1e1f5ed0ac 100644 --- a/backend/controller/cronjobs/testdata/go/cron/go.mod +++ b/backend/controller/cronjobs/testdata/go/cron/go.mod @@ -9,6 +9,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/backend/controller/cronjobs/testdata/go/cron/go.sum b/backend/controller/cronjobs/testdata/go/cron/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/backend/controller/cronjobs/testdata/go/cron/go.sum +++ b/backend/controller/cronjobs/testdata/go/cron/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/backend/controller/cronjobs/testdata/go/cron/types.ftl.go b/backend/controller/cronjobs/testdata/go/cron/types.ftl.go deleted file mode 100644 index 9f1d69404a..0000000000 --- a/backend/controller/cronjobs/testdata/go/cron/types.ftl.go +++ /dev/null @@ -1,27 +0,0 @@ -// Code generated by FTL. DO NOT EDIT. -package cron - -import ( - "context" - "github.com/TBD54566975/ftl/go-runtime/ftl/reflection" -) - -type CronClient func(context.Context) error - -type FiveMinutesClient func(context.Context) error - -type SaturdayClient func(context.Context) error - -func init() { - reflection.Register( - reflection.ProvideResourcesForVerb( - Cron, - ), - reflection.ProvideResourcesForVerb( - FiveMinutes, - ), - reflection.ProvideResourcesForVerb( - Saturday, - ), - ) -} diff --git a/backend/controller/encryption/testdata/go/encryption/go.mod b/backend/controller/encryption/testdata/go/encryption/go.mod index e3ef981cd8..f07de1349d 100644 --- a/backend/controller/encryption/testdata/go/encryption/go.mod +++ b/backend/controller/encryption/testdata/go/encryption/go.mod @@ -9,6 +9,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/backend/controller/encryption/testdata/go/encryption/go.sum b/backend/controller/encryption/testdata/go/encryption/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/backend/controller/encryption/testdata/go/encryption/go.sum +++ b/backend/controller/encryption/testdata/go/encryption/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/backend/controller/ingress/testdata/go/httpingress/go.mod b/backend/controller/ingress/testdata/go/httpingress/go.mod index 32be9ab390..2cf3436741 100644 --- a/backend/controller/ingress/testdata/go/httpingress/go.mod +++ b/backend/controller/ingress/testdata/go/httpingress/go.mod @@ -9,6 +9,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/backend/controller/ingress/testdata/go/httpingress/go.sum b/backend/controller/ingress/testdata/go/httpingress/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/backend/controller/ingress/testdata/go/httpingress/go.sum +++ b/backend/controller/ingress/testdata/go/httpingress/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/backend/controller/pubsub/testdata/go/publisher/go.mod b/backend/controller/pubsub/testdata/go/publisher/go.mod index 146a2a4173..c79c6f9deb 100644 --- a/backend/controller/pubsub/testdata/go/publisher/go.mod +++ b/backend/controller/pubsub/testdata/go/publisher/go.mod @@ -9,6 +9,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/backend/controller/pubsub/testdata/go/publisher/go.sum b/backend/controller/pubsub/testdata/go/publisher/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/backend/controller/pubsub/testdata/go/publisher/go.sum +++ b/backend/controller/pubsub/testdata/go/publisher/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/backend/controller/pubsub/testdata/go/slow/go.mod b/backend/controller/pubsub/testdata/go/slow/go.mod index 13bb0989e5..3dec55631a 100644 --- a/backend/controller/pubsub/testdata/go/slow/go.mod +++ b/backend/controller/pubsub/testdata/go/slow/go.mod @@ -9,6 +9,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/backend/controller/pubsub/testdata/go/slow/go.sum b/backend/controller/pubsub/testdata/go/slow/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/backend/controller/pubsub/testdata/go/slow/go.sum +++ b/backend/controller/pubsub/testdata/go/slow/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/backend/controller/pubsub/testdata/go/subscriber/go.mod b/backend/controller/pubsub/testdata/go/subscriber/go.mod index 70955a3116..87eb676332 100644 --- a/backend/controller/pubsub/testdata/go/subscriber/go.mod +++ b/backend/controller/pubsub/testdata/go/subscriber/go.mod @@ -12,6 +12,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect github.com/alecthomas/types v0.16.0 // indirect diff --git a/backend/controller/pubsub/testdata/go/subscriber/go.sum b/backend/controller/pubsub/testdata/go/subscriber/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/backend/controller/pubsub/testdata/go/subscriber/go.sum +++ b/backend/controller/pubsub/testdata/go/subscriber/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/backend/controller/sql/testdata/go/database/database.go b/backend/controller/sql/testdata/go/database/database.go index 399d6d6aa3..692319a411 100644 --- a/backend/controller/sql/testdata/go/database/database.go +++ b/backend/controller/sql/testdata/go/database/database.go @@ -6,11 +6,7 @@ import ( "github.com/TBD54566975/ftl/go-runtime/ftl" // Import the FTL SDK. ) -type MyDbConfig struct { - ftl.DefaultPostgresDatabaseConfig -} - -func (MyDbConfig) Name() string { return "testdb" } +var db = ftl.PostgresDatabase("testdb") type InsertRequest struct { Data string @@ -19,8 +15,8 @@ type InsertRequest struct { type InsertResponse struct{} //ftl:verb -func Insert(ctx context.Context, req InsertRequest, db ftl.DatabaseHandle[MyDbConfig]) (InsertResponse, error) { - err := persistRequest(ctx, req, db) +func Insert(ctx context.Context, req InsertRequest) (InsertResponse, error) { + err := persistRequest(ctx, req) if err != nil { return InsertResponse{}, err } @@ -28,7 +24,7 @@ func Insert(ctx context.Context, req InsertRequest, db ftl.DatabaseHandle[MyDbCo return InsertResponse{}, nil } -func persistRequest(ctx context.Context, req InsertRequest, db ftl.DatabaseHandle[MyDbConfig]) error { +func persistRequest(ctx context.Context, req InsertRequest) error { _, err := db.Get(ctx).Exec(`CREATE TABLE IF NOT EXISTS requests ( data TEXT, diff --git a/backend/controller/sql/testdata/go/database/database_test.go b/backend/controller/sql/testdata/go/database/database_test.go index c443db9cfe..d5b026600f 100644 --- a/backend/controller/sql/testdata/go/database/database_test.go +++ b/backend/controller/sql/testdata/go/database/database_test.go @@ -11,26 +11,22 @@ import ( func TestDatabase(t *testing.T) { ctx := ftltest.Context( - ftltest.WithCallsAllowedWithinModule(), ftltest.WithProjectFile("ftl-project.toml"), - ftltest.WithDatabase[MyDbConfig](), + ftltest.WithDatabase(db), ) - _, err := ftltest.Call[InsertClient, InsertRequest, InsertResponse](ctx, InsertRequest{Data: "unit test 1"}) - assert.NoError(t, err) + Insert(ctx, InsertRequest{Data: "unit test 1"}) list, err := getAll(ctx) assert.NoError(t, err) assert.Equal(t, 1, len(list)) assert.Equal(t, "unit test 1", list[0]) ctx = ftltest.Context( - ftltest.WithCallsAllowedWithinModule(), ftltest.WithProjectFile("ftl-project.toml"), - ftltest.WithDatabase[MyDbConfig](), + ftltest.WithDatabase(db), ) - _, err = ftltest.Call[InsertClient, InsertRequest, InsertResponse](ctx, InsertRequest{Data: "unit test 2"}) - assert.NoError(t, err) + Insert(ctx, InsertRequest{Data: "unit test 2"}) list, err = getAll(ctx) assert.NoError(t, err) assert.Equal(t, 1, len(list)) @@ -39,13 +35,11 @@ func TestDatabase(t *testing.T) { func TestOptionOrdering(t *testing.T) { ctx := ftltest.Context( - ftltest.WithCallsAllowedWithinModule(), - ftltest.WithDatabase[MyDbConfig](), // <--- consumes DSNs + ftltest.WithDatabase(db), // <--- consumes DSNs ftltest.WithProjectFile("ftl-project.toml"), // <--- provides DSNs ) - _, err := ftltest.Call[InsertClient, InsertRequest, InsertResponse](ctx, InsertRequest{Data: "unit test 1"}) - assert.NoError(t, err) + Insert(ctx, InsertRequest{Data: "unit test 1"}) list, err := getAll(ctx) assert.NoError(t, err) assert.Equal(t, 1, len(list)) @@ -53,10 +47,6 @@ func TestOptionOrdering(t *testing.T) { } func getAll(ctx context.Context) ([]string, error) { - db, err := ftltest.GetDatabaseHandle[MyDbConfig]() - if err != nil { - return nil, err - } rows, err := db.Get(ctx).Query("SELECT data FROM requests ORDER BY created_at;") if err != nil { return nil, err diff --git a/backend/controller/sql/testdata/go/database/types.ftl.go b/backend/controller/sql/testdata/go/database/types.ftl.go deleted file mode 100644 index 56c4357978..0000000000 --- a/backend/controller/sql/testdata/go/database/types.ftl.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by FTL. DO NOT EDIT. -package database - -import ( - "context" - "github.com/TBD54566975/ftl/go-runtime/ftl/reflection" - "github.com/TBD54566975/ftl/go-runtime/server" -) - -type InsertClient func(context.Context, InsertRequest) (InsertResponse, error) - -func init() { - reflection.Register( - reflection.Database[MyDbConfig](server.InitPostgres), - reflection.ProvideResourcesForVerb( - Insert, - server.PostgresDatabaseHandle[MyDbConfig](), - ), - ) -} diff --git a/backend/provisioner/testdata/go/echo/echo.go b/backend/provisioner/testdata/go/echo/echo.go index c4a98d24ef..dd48baa478 100644 --- a/backend/provisioner/testdata/go/echo/echo.go +++ b/backend/provisioner/testdata/go/echo/echo.go @@ -9,16 +9,12 @@ import ( "github.com/TBD54566975/ftl/go-runtime/ftl" ) -type EchoDBConfig struct { - ftl.DefaultPostgresDatabaseConfig -} - -func (EchoDBConfig) Name() string { return "echodb" } +var db = ftl.PostgresDatabase("echodb") // Echo returns a greeting with the current time. // //ftl:verb export -func Echo(ctx context.Context, req string, db ftl.DatabaseHandle[EchoDBConfig]) (string, error) { +func Echo(ctx context.Context, req string) (string, error) { _, err := db.Get(ctx).Exec(`CREATE TABLE IF NOT EXISTS messages( message TEXT );`) diff --git a/backend/provisioner/testdata/go/echo/go.mod b/backend/provisioner/testdata/go/echo/go.mod index 28d1407c41..edf186ec10 100644 --- a/backend/provisioner/testdata/go/echo/go.mod +++ b/backend/provisioner/testdata/go/echo/go.mod @@ -11,6 +11,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/backend/provisioner/testdata/go/echo/go.sum b/backend/provisioner/testdata/go/echo/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/backend/provisioner/testdata/go/echo/go.sum +++ b/backend/provisioner/testdata/go/echo/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/docs/content/docs/reference/unittests.md b/docs/content/docs/reference/unittests.md index c92226999f..16641a3152 100644 --- a/docs/content/docs/reference/unittests.md +++ b/docs/content/docs/reference/unittests.md @@ -60,22 +60,19 @@ ctx := ftltest.Context( ``` ### Databases +By default, calling `Get(ctx)` on a database panics. + To enable database access in a test, you must first [provide a DSN via a project file](#project-files-configs-and-secrets). You can then set up a test database: ```go ctx := ftltest.Context( ftltest.WithDefaultProjectFile(), - ftltest.WithDatabase[MyDBConfig](), + ftltest.WithDatabase(db), ) ``` This will: - Take the provided DSN and appends `_test` to the database name. Eg: `accounts` becomes `accounts_test` - Wipe all tables in the database so each test run happens on a clean database -You can access the database in your test using its handle: -```go -db, err := ftltest.GetDatabaseHandle[MyDBConfig]() -db.Get(ctx).Exec(...) -``` ### Maps By default, calling `Get(ctx)` on a map handle will panic. diff --git a/examples/go/cron/go.mod b/examples/go/cron/go.mod index a3793bfa08..8a1896a998 100644 --- a/examples/go/cron/go.mod +++ b/examples/go/cron/go.mod @@ -11,6 +11,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/examples/go/cron/go.sum b/examples/go/cron/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/examples/go/cron/go.sum +++ b/examples/go/cron/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/examples/go/http/go.mod b/examples/go/http/go.mod index 31a1d8b75e..ac18729b82 100644 --- a/examples/go/http/go.mod +++ b/examples/go/http/go.mod @@ -11,6 +11,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/examples/go/http/go.sum b/examples/go/http/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/examples/go/http/go.sum +++ b/examples/go/http/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/examples/go/pubsub/go.mod b/examples/go/pubsub/go.mod index 888c07c704..4be89a775e 100644 --- a/examples/go/pubsub/go.mod +++ b/examples/go/pubsub/go.mod @@ -14,6 +14,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/examples/go/pubsub/go.sum b/examples/go/pubsub/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/examples/go/pubsub/go.sum +++ b/examples/go/pubsub/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/frontend/cli/testdata/go/echo/go.mod b/frontend/cli/testdata/go/echo/go.mod index a446e79869..12ea5b75d1 100644 --- a/frontend/cli/testdata/go/echo/go.mod +++ b/frontend/cli/testdata/go/echo/go.mod @@ -11,6 +11,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/frontend/cli/testdata/go/echo/go.sum b/frontend/cli/testdata/go/echo/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/frontend/cli/testdata/go/echo/go.sum +++ b/frontend/cli/testdata/go/echo/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/frontend/cli/testdata/go/time/go.mod b/frontend/cli/testdata/go/time/go.mod index 6001f4166f..43f6271d06 100644 --- a/frontend/cli/testdata/go/time/go.mod +++ b/frontend/cli/testdata/go/time/go.mod @@ -11,6 +11,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/frontend/cli/testdata/go/time/go.sum b/frontend/cli/testdata/go/time/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/frontend/cli/testdata/go/time/go.sum +++ b/frontend/cli/testdata/go/time/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/go-runtime/compile/build-template/.ftl.tmpl/go/main/main.go.tmpl b/go-runtime/compile/build-template/.ftl.tmpl/go/main/main.go.tmpl index 5a413f8cd1..7febb945a2 100644 --- a/go-runtime/compile/build-template/.ftl.tmpl/go/main/main.go.tmpl +++ b/go-runtime/compile/build-template/.ftl.tmpl/go/main/main.go.tmpl @@ -1,5 +1,4 @@ {{- $verbs := .Verbs -}} -{{- $dbs := .Databases -}} {{- $name := .Name -}} {{- with .MainCtx -}} @@ -25,11 +24,6 @@ func init() { {{- range .ExternalTypes}} reflection.ExternalType(*new({{.TypeName}})), {{- end}} -{{- range $dbs}} - {{- if eq .Type "postgres" }} - reflection.Database[{{.TypeName}}]("{{.Name}}", server.InitPostgres), - {{- end }} -{{- end}} {{- range $verbs}} reflection.ProvideResourcesForVerb( {{.TypeName}}, @@ -44,11 +38,6 @@ func init() { {{- else }} server.VerbClient[{{.TypeName}}, {{.Request.TypeName}}, {{.Response.TypeName}}](), {{- end -}} - {{- end }} - {{- with getDatabaseHandle . }} - {{- if eq .Type "postgres" }} - server.PostgresDatabaseHandle[{{.TypeName}}](), - {{- end }} {{- end }} {{- end}} ), diff --git a/go-runtime/compile/build-template/types.ftl.go.tmpl b/go-runtime/compile/build-template/types.ftl.go.tmpl index 7dd99d09c8..4d30ea5267 100644 --- a/go-runtime/compile/build-template/types.ftl.go.tmpl +++ b/go-runtime/compile/build-template/types.ftl.go.tmpl @@ -1,5 +1,4 @@ {{- $verbs := .Verbs -}} -{{- $dbs := .Databases -}} {{- $name := .Name -}} {{- with .TypesCtx -}} {{- $moduleName := .MainModulePkg -}} @@ -43,11 +42,6 @@ func init() { {{- range .ExternalTypes}} reflection.ExternalType(*new({{.TypeName}})), {{- end}} -{{- range $dbs}} - {{- if eq .Type "postgres" }} - reflection.Database[{{ trimModuleQualifier $moduleName .TypeName }}]("{{.Name}}", server.InitPostgres), - {{- end }} -{{- end}} {{- range $verbs}} reflection.ProvideResourcesForVerb( {{ trimModuleQualifier $moduleName .TypeName }}, @@ -64,11 +58,6 @@ func init() { {{- else }} server.VerbClient[{{$verb}}, {{.Request.LocalTypeName}}, {{.Response.LocalTypeName}}](), {{- end }} - {{- end }} - {{- with getDatabaseHandle . }} - {{- if eq .Type "postgres" }} - server.PostgresDatabaseHandle[{{ trimModuleQualifier $moduleName .TypeName }}](), - {{- end }} {{- end }} {{- end}} ), diff --git a/go-runtime/compile/build.go b/go-runtime/compile/build.go index 5968a0b9dc..71002beccc 100644 --- a/go-runtime/compile/build.go +++ b/go-runtime/compile/build.go @@ -45,7 +45,6 @@ type mainModuleContext struct { Name string SharedModulesPaths []string Verbs []goVerb - Databases []goDBHandle Replacements []*modfile.Replace MainCtx mainFileContext TypesCtx typesFileContext @@ -89,9 +88,6 @@ func (c *mainModuleContext) generateTypesImports(mainModuleImport string) []stri if len(c.Verbs) > 0 { imports.Add(`"context"`) } - if len(c.Databases) > 0 { - imports.Add(`"github.com/TBD54566975/ftl/go-runtime/server"`) - } for _, st := range c.TypesCtx.SumTypes { imports.Add(st.importStatement()) for _, v := range st.Variants { @@ -242,18 +238,10 @@ type verbClient struct { func (v verbClient) resource() {} -type goDBHandle struct { - Type string - Name string - Module string - - nativeType -} - -func (d goDBHandle) resource() {} - -func (d goDBHandle) getNativeType() nativeType { - return d.nativeType +type ModifyFilesTransaction interface { + Begin() error + ModifiedFiles(paths ...string) error + End() error } const buildDirName = ".ftl" @@ -428,7 +416,6 @@ func (b *mainModuleContextBuilder) build(goModVersion, ftlVersion, projectName s SharedModulesPaths: sharedModulesPaths, Replacements: replacements, Verbs: make([]goVerb, 0, len(b.mainModule.Decls)), - Databases: make([]goDBHandle, 0, len(b.mainModule.Decls)), MainCtx: mainFileContext{ ProjectName: projectName, SumTypes: []goSumType{}, @@ -511,8 +498,6 @@ func (b *mainModuleContextBuilder) visit( case goExternalType: ctx.TypesCtx.ExternalTypes = append(ctx.TypesCtx.ExternalTypes, n) ctx.MainCtx.ExternalTypes = append(ctx.MainCtx.ExternalTypes, n) - case goDBHandle: - ctx.Databases = append(ctx.Databases, n) } return next() }) @@ -550,15 +535,6 @@ func (b *mainModuleContextBuilder) getGoType(module *schema.Module, node schema. return optional.None[goType](), isLocal, nil } return b.processExternalTypeAlias(n), isLocal, nil - case *schema.Database: - if !isLocal { - return optional.None[goType](), false, nil - } - dbHandle, err := b.processDatabase(module.Name, n) - if err != nil { - return optional.None[goType](), isLocal, err - } - return optional.Some[goType](dbHandle), isLocal, nil default: } @@ -657,26 +633,6 @@ func (b *mainModuleContextBuilder) processVerb(verb *schema.Verb) (goVerb, error calleeverb, }) } - case *schema.MetadataDatabases: - for _, call := range md.Calls { - resolved, ok := b.sch.Resolve(call).Get() - if !ok { - return goVerb{}, fmt.Errorf("failed to resolve %s database, used by %s.%s", call, - b.mainModule.Name, verb.Name) - } - db, ok := resolved.(*schema.Database) - if !ok { - return goVerb{}, fmt.Errorf("%s.%s uses %s database handle, but %s is not a database", - b.mainModule.Name, verb.Name, call, call) - } - - dbHandle, err := b.processDatabase(call.Module, db) - if err != nil { - return goVerb{}, err - } - resources = append(resources, dbHandle) - } - default: // TODO: implement other resources } @@ -689,24 +645,6 @@ func (b *mainModuleContextBuilder) processVerb(verb *schema.Verb) (goVerb, error return b.getGoVerb(nativeName, verb, resources...) } -func (b *mainModuleContextBuilder) processDatabase(moduleName string, db *schema.Database) (goDBHandle, error) { - nn, ok := b.nativeNames[db] - if !ok { - return goDBHandle{}, fmt.Errorf("missing native name for database %s.%s", moduleName, db.Name) - } - - nt, err := b.getNativeType(nn) - if err != nil { - return goDBHandle{}, err - } - return goDBHandle{ - Name: db.Name, - Module: moduleName, - Type: db.Type, - nativeType: nt, - }, nil -} - func (b *mainModuleContextBuilder) getGoVerb(nativeName string, verb *schema.Verb, resources ...verbResource) (goVerb, error) { nt, err := b.getNativeType(nativeName) if err != nil { @@ -892,12 +830,6 @@ var scaffoldFuncs = scaffolder.FuncMap{ } return nil }, - "getDatabaseHandle": func(resource verbResource) *goDBHandle { - if c, ok := resource.(goDBHandle); ok { - return &c - } - return nil - }, } // returns the import path and the directory name for a type alias if there is an associated go library diff --git a/go-runtime/compile/compile_integration_test.go b/go-runtime/compile/compile_integration_test.go index def686ff89..e90fe6b74b 100644 --- a/go-runtime/compile/compile_integration_test.go +++ b/go-runtime/compile/compile_integration_test.go @@ -20,7 +20,7 @@ func TestNonExportedDecls(t *testing.T) { in.CopyModule("notexportedverb"), in.ExpectError( in.ExecWithOutput("ftl", []string{"deploy", "notexportedverb"}, func(_ string) {}), - `unsupported verb parameter type; verbs must have the signature func(Context, Request?, Resources...)`, + `unsupported verb parameter type &{"echo" "EchoClient"}; verbs must have the signature func(Context, Request?, Resources...)`, ), ) } @@ -34,7 +34,7 @@ func TestUndefinedExportedDecls(t *testing.T) { in.CopyModule("undefinedverb"), in.ExpectError( in.ExecWithOutput("ftl", []string{"deploy", "undefinedverb"}, func(_ string) {}), - `unsupported verb parameter type; verbs must have the signature func(Context, Request?, Resources...)`, + `unsupported verb parameter type &{"echo" "UndefinedClient"}; verbs must have the signature func(Context, Request?, Resources...)`, ), ) } diff --git a/go-runtime/compile/testdata/go/notexportedverb/go.mod b/go-runtime/compile/testdata/go/notexportedverb/go.mod index 5ac5779b78..7b1ef69997 100644 --- a/go-runtime/compile/testdata/go/notexportedverb/go.mod +++ b/go-runtime/compile/testdata/go/notexportedverb/go.mod @@ -9,6 +9,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/go-runtime/compile/testdata/go/notexportedverb/go.sum b/go-runtime/compile/testdata/go/notexportedverb/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/go-runtime/compile/testdata/go/notexportedverb/go.sum +++ b/go-runtime/compile/testdata/go/notexportedverb/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/go-runtime/compile/testdata/go/one/go.mod b/go-runtime/compile/testdata/go/one/go.mod index 0363e62cff..e31f404759 100644 --- a/go-runtime/compile/testdata/go/one/go.mod +++ b/go-runtime/compile/testdata/go/one/go.mod @@ -11,6 +11,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/go-runtime/compile/testdata/go/one/go.sum b/go-runtime/compile/testdata/go/one/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/go-runtime/compile/testdata/go/one/go.sum +++ b/go-runtime/compile/testdata/go/one/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/go-runtime/compile/testdata/go/one/one.go b/go-runtime/compile/testdata/go/one/one.go index 74e0de09af..2e07d9466d 100644 --- a/go-runtime/compile/testdata/go/one/one.go +++ b/go-runtime/compile/testdata/go/one/one.go @@ -133,12 +133,7 @@ type ExportedData struct { var configValue = ftl.Config[Config]("configValue") var secretValue = ftl.Secret[string]("secretValue") - -type MyDbConfig struct { - ftl.DefaultPostgresDatabaseConfig -} - -func (MyDbConfig) Name() string { return "testDb" } +var testDb = ftl.PostgresDatabase("testDb") //ftl:verb func Verb(ctx context.Context, req Req) (Resp, error) { diff --git a/go-runtime/compile/testdata/go/undefinedverb/go.mod b/go-runtime/compile/testdata/go/undefinedverb/go.mod index 5ac5779b78..7b1ef69997 100644 --- a/go-runtime/compile/testdata/go/undefinedverb/go.mod +++ b/go-runtime/compile/testdata/go/undefinedverb/go.mod @@ -9,6 +9,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/go-runtime/compile/testdata/go/undefinedverb/go.sum b/go-runtime/compile/testdata/go/undefinedverb/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/go-runtime/compile/testdata/go/undefinedverb/go.sum +++ b/go-runtime/compile/testdata/go/undefinedverb/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/go-runtime/encoding/testdata/go/omitempty/go.mod b/go-runtime/encoding/testdata/go/omitempty/go.mod index 154f92be8a..abe00848e9 100644 --- a/go-runtime/encoding/testdata/go/omitempty/go.mod +++ b/go-runtime/encoding/testdata/go/omitempty/go.mod @@ -9,6 +9,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/go-runtime/encoding/testdata/go/omitempty/go.sum b/go-runtime/encoding/testdata/go/omitempty/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/go-runtime/encoding/testdata/go/omitempty/go.sum +++ b/go-runtime/encoding/testdata/go/omitempty/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/go-runtime/ftl/database.go b/go-runtime/ftl/database.go index c963636353..e434e3f94a 100644 --- a/go-runtime/ftl/database.go +++ b/go-runtime/ftl/database.go @@ -4,74 +4,69 @@ import ( "context" "database/sql" "fmt" + "time" + "github.com/XSAM/otelsql" "github.com/alecthomas/types/once" _ "github.com/jackc/pgx/v5/stdlib" // Register Postgres driver + "go.opentelemetry.io/otel/attribute" + semconv "go.opentelemetry.io/otel/semconv/v1.4.0" + + "github.com/TBD54566975/ftl/internal/log" + "github.com/TBD54566975/ftl/internal/modulecontext" ) -type DatabaseConfig interface { - // Name returns the name of the database. - Name() string - /* - // RAM returns the amount of memory (in bytes) allocated to the database. - RAM() int64 - // Disk returns the path or identifier for the disk where the database data is stored. - Disk() string - // Timeout returns the timeout value (in milliseconds) for database operations, such as queries or connections. - Timeout() int64 - // MaxConnections returns the maximum number of concurrent database connections allowed. - MaxConnections() int - */ - db() -} +type Database struct { + Name string + DBType modulecontext.DBType -type PostgresDatabaseConfig interface { - DatabaseConfig - pg() + db *once.Handle[*sql.DB] } -// DefaultPostgresDatabaseConfig is a default implementation of PostgresDatabaseConfig. It does not provide -// an implementation for the Name method and should be embedded in a struct that does. -type DefaultPostgresDatabaseConfig struct{} - -func (DefaultPostgresDatabaseConfig) db() {} //nolint:unused -func (DefaultPostgresDatabaseConfig) pg() {} //nolint:unused +// PostgresDatabase returns a handler for the named database. +func PostgresDatabase(name string) Database { + return Database{ + Name: name, + DBType: modulecontext.DBTypePostgres, + db: once.Once(func(ctx context.Context) (*sql.DB, error) { + logger := log.FromContext(ctx) -type DatabaseType string + provider := modulecontext.FromContext(ctx).CurrentContext() + dsn, err := provider.GetDatabase(name, modulecontext.DBTypePostgres) + if err != nil { + return nil, fmt.Errorf("failed to get database %q: %w", name, err) + } -const ( - DatabaseTypePostgres DatabaseType = "postgres" -) - -type DatabaseHandle[T DatabaseConfig] struct { - name string - _type DatabaseType - db *once.Handle[*sql.DB] -} + logger.Debugf("Opening database: %s", name) + db, err := otelsql.Open("pgx", dsn) + if err != nil { + return nil, fmt.Errorf("failed to open database %q: %w", name, err) + } -// Name returns the name of the database. -func (d DatabaseHandle[T]) Name() string { return d.name } - -// Type returns the type of the database, e.g. "postgres" -func (d DatabaseHandle[T]) Type() DatabaseType { - return d._type + // sets db.system and db.name attributes + metricAttrs := otelsql.WithAttributes( + semconv.DBSystemPostgreSQL, + semconv.DBNameKey.String(name), + attribute.Bool("ftl.is_user_service", true), + ) + err = otelsql.RegisterDBStatsMetrics(db, metricAttrs) + if err != nil { + return nil, fmt.Errorf("failed to register database metrics: %w", err) + } + db.SetConnMaxIdleTime(time.Minute) + db.SetMaxOpenConns(20) + return db, nil + }), + } } -// String returns a string representation of the database handle. -func (d DatabaseHandle[T]) String() string { - return fmt.Sprintf("database %q", d.name) -} +func (d Database) String() string { return fmt.Sprintf("database %q", d.Name) } // Get returns the SQL DB connection for the database. -func (d DatabaseHandle[T]) Get(ctx context.Context) *sql.DB { +func (d Database) Get(ctx context.Context) *sql.DB { db, err := d.db.Get(ctx) if err != nil { panic(err) } return db } - -// NewDatabaseHandle is managed by FTL. -func NewDatabaseHandle[T DatabaseConfig](config T, dbType DatabaseType, db *once.Handle[*sql.DB]) DatabaseHandle[T] { - return DatabaseHandle[T]{name: config.Name(), db: db, _type: dbType} -} diff --git a/go-runtime/ftl/ftltest/ftltest.go b/go-runtime/ftl/ftltest/ftltest.go index 1c5681cd82..1bddf6ff63 100644 --- a/go-runtime/ftl/ftltest/ftltest.go +++ b/go-runtime/ftl/ftltest/ftltest.go @@ -217,16 +217,21 @@ func WithSecret[T ftl.SecretType](secret ftl.SecretValue[T], value T) Option { } // WithDatabase sets up a database for testing by appending "_test" to the DSN and emptying all tables -func WithDatabase[T ftl.DatabaseConfig]() Option { +// +// To be used when setting up a context for a test: +// +// ctx := ftltest.Context( +// ftltest.WithDatabase(db), +// // ... other options +// ) +func WithDatabase(dbHandle ftl.Database) Option { return Option{ rank: other, apply: func(ctx context.Context, state *OptionsState) error { - cfg := defaultDatabaseConfig[T]() - name := cfg.Name() fftl := internal.FromContext(ctx) - originalDSN, err := getDSNFromSecret(fftl, moduleGetter(), name) + originalDSN, err := getDSNFromSecret(fftl, moduleGetter(), dbHandle.Name) if err != nil { - return fmt.Errorf("could not get DSN for database %q, try adding ftltest.WithProject[MyConfig] as an option with ftltest.Context(...): %w", name, err) + return err } // convert DSN by appending "_test" to table name @@ -237,7 +242,7 @@ func WithDatabase[T ftl.DatabaseConfig]() Option { return fmt.Errorf("could not parse DSN: %w", err) } if dsnURL.Path == "" { - return fmt.Errorf("DSN for %s must include table name: %s", name, originalDSN) + return fmt.Errorf("DSN for %s must include table name: %s", dbHandle.Name, originalDSN) } dsnURL.Path += "_test" dsn := dsnURL.String() @@ -245,7 +250,7 @@ func WithDatabase[T ftl.DatabaseConfig]() Option { // connect to db and clear out the contents of each table sqlDB, err := sql.Open("pgx", dsn) if err != nil { - return fmt.Errorf("could not create database %q with DSN %q: %w", name, dsn, err) + return fmt.Errorf("could not create database %q with DSN %q: %w", dbHandle.Name, dsn, err) } _, err = sqlDB.ExecContext(ctx, `DO $$ DECLARE @@ -259,15 +264,15 @@ func WithDatabase[T ftl.DatabaseConfig]() Option { END LOOP; END $$;`) if err != nil { - return fmt.Errorf("could not clear tables in database %q: %w", name, err) + return fmt.Errorf("could not clear tables in database %q: %w", dbHandle.Name, err) } // replace original database with test database replacementDB, err := modulecontext.NewTestDatabase(modulecontext.DBTypePostgres, dsn) if err != nil { - return fmt.Errorf("could not create database %q with DSN %q: %w", name, dsn, err) + return fmt.Errorf("could not create database %q with DSN %q: %w", dbHandle.Name, dsn, err) } - state.databases[name] = replacementDB + state.databases[dbHandle.Name] = replacementDB return nil }, } @@ -521,23 +526,6 @@ func CallEmpty[VerbClient any](ctx context.Context) error { return err } -// GetDatabaseHandle returns a database handle using the given database config. -func GetDatabaseHandle[T ftl.DatabaseConfig]() (ftl.DatabaseHandle[T], error) { - reflectedDB := reflection.GetDatabase[T]() - if reflectedDB == nil { - return ftl.DatabaseHandle[T]{}, fmt.Errorf("could not find database for config") - } - - var dbType ftl.DatabaseType - switch reflectedDB.DBType { - case "postgres": - dbType = ftl.DatabaseTypePostgres - default: - return ftl.DatabaseHandle[T]{}, fmt.Errorf("unsupported database type %v", reflectedDB.DBType) - } - return ftl.NewDatabaseHandle[T](defaultDatabaseConfig[T](), dbType, reflectedDB.DB), nil -} - func call[VerbClient, Req, Resp any](ctx context.Context, req Req) (resp Resp, err error) { ref := reflection.ClientRef[VerbClient]() // always allow direct behavior for the verb triggered by this call @@ -546,7 +534,7 @@ func call[VerbClient, Req, Resp any](ctx context.Context, req Req) (resp Resp, e ).AddAllowedDirectVerb(ref).Build() ctx = mcu.MakeDynamic(ctx, moduleCtx).ApplyToContext(ctx) - inline := server.InvokeVerb[Req, Resp](ref) + inline := server.Call[Req, Resp](ref) override, err := moduleCtx.BehaviorForVerb(schema.Ref{Module: ref.Module, Name: ref.Name}) if err != nil { return resp, fmt.Errorf("test harness failed to retrieve behavior for verb %s: %w", ref, err) @@ -573,14 +561,3 @@ func widenVerb[Req, Resp any](verb ftl.Verb[Req, Resp]) ftl.Verb[any, any] { return verb(ctx, req) } } - -func defaultDatabaseConfig[T ftl.DatabaseConfig]() T { - typ := reflect.TypeFor[T]() - var cfg T - if typ.Kind() == reflect.Ptr { - cfg = reflect.New(typ.Elem()).Interface().(T) //nolint:forcetypeassert - } else { - cfg = reflect.New(typ).Elem().Interface().(T) //nolint:forcetypeassert - } - return cfg -} diff --git a/go-runtime/ftl/reflection/database.go b/go-runtime/ftl/reflection/database.go deleted file mode 100644 index f08199cca6..0000000000 --- a/go-runtime/ftl/reflection/database.go +++ /dev/null @@ -1,49 +0,0 @@ -package reflection - -import ( - "database/sql" - "fmt" - "reflect" - - "github.com/alecthomas/types/once" -) - -type ReflectedDatabaseHandle struct { - DBType string - DB *once.Handle[*sql.DB] - - // configs - Name string -} - -func Database[T any](dbname string, init func(ref Ref) *ReflectedDatabaseHandle) Registree { - ref := Ref{ - Module: moduleForType(reflect.TypeFor[T]()), - Name: dbname, - } - return func(t *TypeRegistry) { - t.databases[ref] = init(ref) - } -} - -func getDatabaseName[T any]() string { - typ := reflect.TypeFor[T]() - var config T - if typ.Kind() == reflect.Ptr { - config = reflect.New(typ.Elem()).Interface().(T) //nolint:forcetypeassert - } else { - config = reflect.New(typ).Elem().Interface().(T) //nolint:forcetypeassert - } - - nameMethod := reflect.ValueOf(config).MethodByName("Name") - if !nameMethod.IsValid() { - panic(fmt.Sprintf("type %T must implement ftl.DatabaseConfig but does not have a Name() method", config)) - } - nameResult := nameMethod.Call(nil) - name, ok := nameResult[0].Interface().(string) - if !ok { - panic(fmt.Sprintf("Name() method of type %T must return a string, but returned %T", config, - nameResult[0].Interface())) - } - return name -} diff --git a/go-runtime/ftl/reflection/singleton.go b/go-runtime/ftl/reflection/singleton.go index 1744996049..a3b9e06337 100644 --- a/go-runtime/ftl/reflection/singleton.go +++ b/go-runtime/ftl/reflection/singleton.go @@ -34,14 +34,6 @@ func GetVariantByName(discriminator reflect.Type, name string) optional.Option[r return singletonTypeRegistry.getVariantByName(discriminator, name) } -func GetDatabase[T any]() *ReflectedDatabaseHandle { - ref := Ref{ - Module: moduleForType(reflect.TypeFor[T]()), - Name: getDatabaseName[T](), - } - return singletonTypeRegistry.databases[ref] -} - // GetDiscriminatorByVariant returns the discriminator type for the given variant type. func GetDiscriminatorByVariant(variant reflect.Type) optional.Option[reflect.Type] { return singletonTypeRegistry.getDiscriminatorByVariant(variant) diff --git a/go-runtime/ftl/reflection/testdata/go/runtimereflection/go.mod b/go-runtime/ftl/reflection/testdata/go/runtimereflection/go.mod index 062d1dd763..ba2e23828e 100644 --- a/go-runtime/ftl/reflection/testdata/go/runtimereflection/go.mod +++ b/go-runtime/ftl/reflection/testdata/go/runtimereflection/go.mod @@ -12,6 +12,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/go-runtime/ftl/reflection/testdata/go/runtimereflection/go.sum b/go-runtime/ftl/reflection/testdata/go/runtimereflection/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/go-runtime/ftl/reflection/testdata/go/runtimereflection/go.sum +++ b/go-runtime/ftl/reflection/testdata/go/runtimereflection/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/go-runtime/ftl/reflection/type_registry.go b/go-runtime/ftl/reflection/type_registry.go index ab56eefad4..6b00664397 100644 --- a/go-runtime/ftl/reflection/type_registry.go +++ b/go-runtime/ftl/reflection/type_registry.go @@ -15,7 +15,6 @@ type TypeRegistry struct { variantsToDiscriminators map[reflect.Type]reflect.Type externalTypes map[reflect.Type]struct{} verbCalls map[Ref]verbCall - databases map[Ref]*ReflectedDatabaseHandle } type sumTypeVariant struct { @@ -54,7 +53,6 @@ func newTypeRegistry(options ...Registree) *TypeRegistry { variantsToDiscriminators: map[reflect.Type]reflect.Type{}, externalTypes: map[reflect.Type]struct{}{}, verbCalls: map[Ref]verbCall{}, - databases: map[Ref]*ReflectedDatabaseHandle{}, } for _, o := range options { o(t) diff --git a/go-runtime/ftl/testdata/go/echo/go.mod b/go-runtime/ftl/testdata/go/echo/go.mod index 9a24428ca5..9ee4527d0c 100644 --- a/go-runtime/ftl/testdata/go/echo/go.mod +++ b/go-runtime/ftl/testdata/go/echo/go.mod @@ -11,6 +11,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/go-runtime/ftl/testdata/go/echo/go.sum b/go-runtime/ftl/testdata/go/echo/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/go-runtime/ftl/testdata/go/echo/go.sum +++ b/go-runtime/ftl/testdata/go/echo/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/go-runtime/goplugin/testdata/another/go.mod b/go-runtime/goplugin/testdata/another/go.mod index cfa2842f52..2a995e671d 100644 --- a/go-runtime/goplugin/testdata/another/go.mod +++ b/go-runtime/goplugin/testdata/another/go.mod @@ -9,6 +9,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/go-runtime/goplugin/testdata/another/go.sum b/go-runtime/goplugin/testdata/another/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/go-runtime/goplugin/testdata/another/go.sum +++ b/go-runtime/goplugin/testdata/another/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/go-runtime/goplugin/testdata/other/go.mod b/go-runtime/goplugin/testdata/other/go.mod index 4418b9c19d..d5f0150c12 100644 --- a/go-runtime/goplugin/testdata/other/go.mod +++ b/go-runtime/goplugin/testdata/other/go.mod @@ -9,6 +9,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/go-runtime/goplugin/testdata/other/go.sum b/go-runtime/goplugin/testdata/other/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/go-runtime/goplugin/testdata/other/go.sum +++ b/go-runtime/goplugin/testdata/other/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/go-runtime/internal/testdata/go/mapper/go.mod b/go-runtime/internal/testdata/go/mapper/go.mod index 9cf63b7151..f28b2ea7d5 100644 --- a/go-runtime/internal/testdata/go/mapper/go.mod +++ b/go-runtime/internal/testdata/go/mapper/go.mod @@ -11,6 +11,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/go-runtime/internal/testdata/go/mapper/go.sum b/go-runtime/internal/testdata/go/mapper/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/go-runtime/internal/testdata/go/mapper/go.sum +++ b/go-runtime/internal/testdata/go/mapper/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/go-runtime/schema/common/common.go b/go-runtime/schema/common/common.go index 7fcf192163..f81b3bef45 100644 --- a/go-runtime/schema/common/common.go +++ b/go-runtime/schema/common/common.go @@ -70,18 +70,15 @@ func NewDeclExtractor[T schema.Decl, N ast.Node](name string, extractFunc Extrac // NewResourceDeclExtractor creates a new schema declaration extractor to extract resources, e.g. Database, Subscription, // Topics. // -// Only resources where the provided `matchFunc` returns true will be visited for extraction. These resources are -// typically extracted on the basis of their underlying type, e.g. ftl.DatabaseConfig, rather than +// Resources are extracted on the basis of their underlying type, e.g. ftl.PostgresDatabaseHandle, rather than // an FTL directive. -func NewResourceDeclExtractor[T schema.Decl](name string, extractFunc ExtractResourceDeclFunc[T], matchFn matchFunc) *analysis.Analyzer { +func NewResourceDeclExtractor[T schema.Decl](name string, extractFunc ExtractResourceDeclFunc[T], typePaths ...string) *analysis.Analyzer { type Tag struct{} // Tag uniquely identifies the fact type for this extractor. - return NewExtractor(name, (*DefaultFact[Tag])(nil), runExtractResourceDeclsFunc[T](extractFunc, matchFn)) + return NewExtractor(name, (*DefaultFact[Tag])(nil), runExtractResourceDeclsFunc[T](extractFunc, typePaths...)) } -type matchFunc func(pass *analysis.Pass, node ast.Node) bool - -// ExtractResourceDeclFunc extracts a schema resource declaration from the given node. -type ExtractResourceDeclFunc[T schema.Decl] func(pass *analysis.Pass, object types.Object, node *ast.TypeSpec) optional.Option[T] +// ExtractResourceDeclFunc extracts a schema declaration from the given node, providing the path to the underlying resource type. +type ExtractResourceDeclFunc[T schema.Decl] func(pass *analysis.Pass, object types.Object, node *ast.TypeSpec, typePath string) optional.Option[T] // ExtractCallDeclFunc extracts a schema declaration from the given node. type ExtractCallDeclFunc[T schema.Decl] func(pass *analysis.Pass, object types.Object, node *ast.GenDecl, callExpr *ast.CallExpr, callPath string) optional.Option[T] @@ -141,7 +138,7 @@ func runExtractDeclsFunc[T schema.Decl, N ast.Node](extractFunc ExtractDeclFunc[ } } -func runExtractResourceDeclsFunc[T schema.Decl](extractFunc ExtractResourceDeclFunc[T], matchFunc matchFunc) func(pass *analysis.Pass) (interface{}, error) { +func runExtractResourceDeclsFunc[T schema.Decl](extractFunc ExtractResourceDeclFunc[T], typePaths ...string) func(pass *analysis.Pass) (interface{}, error) { return func(pass *analysis.Pass) (interface{}, error) { nodeFilter := []ast.Node{ (*ast.TypeSpec)(nil), @@ -157,10 +154,24 @@ func runExtractResourceDeclsFunc[T schema.Decl](extractFunc ExtractResourceDeclF return } - if !matchFunc(pass, node) { + typeObj, ok := GetObjectForNode(pass.TypesInfo, node.Type).Get() + if !ok { + return + } + if typeObj.Pkg() == nil { + return + } + typePath := typeObj.Pkg().Path() + "." + typeObj.Name() + var matchesType bool + for _, path := range typePaths { + if typePath == path { + matchesType = true + } + } + if !matchesType { return } - decl := extractFunc(pass, obj, node) + decl := extractFunc(pass, obj, node, typePath) if d, ok := decl.Get(); ok { MarkSchemaDecl(pass, obj, d) } @@ -360,8 +371,6 @@ func extractType(pass *analysis.Pass, node ast.Node) optional.Option[schema.Type for _, idx := range typ.Indices { if param, ok := ExtractType(pass, idx).Get(); ok { params = append(params, param) - } else { - Errorf(pass, idx, "unsupported type for type argument") } } ref.TypeParameters = params @@ -777,47 +786,6 @@ func CallExprFromVar(node *ast.GenDecl) optional.Option[*ast.CallExpr] { return optional.Some(callExpr) } -// IsDatabaseConfigType will return true if the provided type implements the `DatabaseConfig` type. -func IsDatabaseConfigType(pass *analysis.Pass, typ types.Type) bool { - return implementsType(pass, typ, "github.com/TBD54566975/ftl/go-runtime/ftl", "DatabaseConfig") -} - -// IsPostgresDatabaseConfigType will return true if the provided type implements the `DatabaseConfig` type. -func IsPostgresDatabaseConfigType(pass *analysis.Pass, typ types.Type) bool { - return implementsType(pass, typ, "github.com/TBD54566975/ftl/go-runtime/ftl", "PostgresDatabaseConfig") -} - -func implementsType(pass *analysis.Pass, typ types.Type, pkg string, name string) bool { - ityp, ok := loadRefFromImports(pass, pkg, name).Get() - if !ok { - return false - } - res := types.Implements(typ, ityp) || types.Implements(types.NewPointer(typ), ityp) - return res -} - -// Lazy load the compile-time reference from a package if it is imported by the package in this pass. -func loadRefFromImports(pass *analysis.Pass, pkg, name string) optional.Option[*types.Interface] { - var importedPkg *types.Package - for _, p := range pass.Pkg.Imports() { - if p.Path() == pkg { - importedPkg = p - } - } - if importedPkg == nil { - return optional.None[*types.Interface]() - } - obj := importedPkg.Scope().Lookup(name) - if obj == nil { - return optional.None[*types.Interface]() - } - ifaceType, ok := obj.Type().Underlying().(*types.Interface) - if !ok { - return optional.None[*types.Interface]() - } - return optional.Some(ifaceType) -} - // FuncPathEquals checks if the function call expression is a call to the given path. func FuncPathEquals(pass *analysis.Pass, callExpr *ast.CallExpr, path string) bool { _, fn := Deref[*types.Func](pass, callExpr.Fun) diff --git a/go-runtime/schema/common/fact.go b/go-runtime/schema/common/fact.go index 45a936f8bf..ed8dd23398 100644 --- a/go-runtime/schema/common/fact.go +++ b/go-runtime/schema/common/fact.go @@ -128,27 +128,6 @@ type IncludeNativeName struct { func (*IncludeNativeName) schemaFactValue() {} -type DatabaseConfigMethod int - -const ( - DatabaseConfigMethodName DatabaseConfigMethod = iota -) - -type DatabaseType string - -const ( - DatabaseTypePostgres DatabaseType = "postgres" -) - -// DatabaseConfig marks a database node with an extracted configuration value. -type DatabaseConfig struct { - Type DatabaseType - Method DatabaseConfigMethod - Value any -} - -func (*DatabaseConfig) schemaFactValue() {} - // MarkSchemaDecl marks the given object as having been extracted to the given schema decl. func MarkSchemaDecl(pass *analysis.Pass, obj types.Object, decl schema.Decl) { fact := newFact(pass, obj) @@ -212,14 +191,6 @@ func MarkIncludeNativeName(pass *analysis.Pass, obj types.Object, node schema.No pass.ExportObjectFact(obj, fact) } -// MarkDatabaseConfig marks the given database object with an extracted config value. -func MarkDatabaseConfig(pass *analysis.Pass, obj types.Object, dbType DatabaseType, - method DatabaseConfigMethod, value any) { - fact := newFact(pass, obj) - fact.Add(&DatabaseConfig{Type: dbType, Method: method, Value: value}) - pass.ExportObjectFact(obj, fact) -} - // GetAllFactsExtractionStatus merges schema facts inclusive of all available results and the present pass facts. // For a given object, it provides the current extraction status. // @@ -320,7 +291,7 @@ func GetFactForObject[T SchemaFactValue](pass *analysis.Pass, obj types.Object) return optional.None[T]() } -// GetFactsForObject returns all facts of the provided type marked on the object. +// GetFactsForObject returns the all facts of the provided type marked on the object. func GetFactsForObject[T SchemaFactValue](pass *analysis.Pass, obj types.Object) []T { facts := []T{} for _, fact := range allFacts(pass) { diff --git a/go-runtime/schema/config/analyzer.go b/go-runtime/schema/config/analyzer.go deleted file mode 100644 index fca0648051..0000000000 --- a/go-runtime/schema/config/analyzer.go +++ /dev/null @@ -1,114 +0,0 @@ -package config - -import ( - "go/ast" - "go/types" - "strconv" - - "github.com/TBD54566975/golang-tools/go/analysis" - "github.com/TBD54566975/golang-tools/go/analysis/passes/inspect" - "github.com/TBD54566975/golang-tools/go/ast/inspector" - - "github.com/TBD54566975/ftl/go-runtime/schema/common" -) - -// Extractor extracts config values relating to another decl, e.g. database configurations associated with a -// database decl. -// -// Configs follow a pattern where they implement an interface, like `ftl.DatabaseConfig`. -// We extract values by looking at known receiver methods. For example: -// -// type FooConfig struct{} -// -// func (f FooConfig) Name() string { -// return "foo" -// } -// -// From this, we'd extract the "foo" value as the database name for `FooConfig`. -var Extractor = common.NewExtractor("config", (*Fact)(nil), Extract) - -type Tag struct{} // Tag uniquely identifies the fact type for this extractor. -type Fact = common.DefaultFact[Tag] - -func Extract(pass *analysis.Pass) (interface{}, error) { - in := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) //nolint:forcetypeassert - nodeFilter := []ast.Node{ - (*ast.FuncDecl)(nil), - } - - in.Preorder(nodeFilter, func(n ast.Node) { - fn := n.(*ast.FuncDecl) //nolint:forcetypeassert - - // skip if there is no receiver - if fn.Recv == nil || len(fn.Recv.List) == 0 { - return - } - - // handle both pointer and non-pointer receivers - var ident *ast.Ident - var ok bool - switch expr := fn.Recv.List[0].Type.(type) { - case *ast.StarExpr: - ident, ok = expr.X.(*ast.Ident) - if !ok { - return - } - case *ast.Ident: - ident = expr - default: - return - } - - recType := pass.TypesInfo.TypeOf(ident) - if recType == nil { - return - } - - // receiver implements ftl.DatabaseConfig - if common.IsDatabaseConfigType(pass, recType) { - extractDatabaseConfig(pass, getDBType(pass, ident, recType), fn, ident) - } - - }) - return common.NewExtractorResult(pass), nil -} - -func extractDatabaseConfig(pass *analysis.Pass, dbType common.DatabaseType, fn *ast.FuncDecl, receiver *ast.Ident) { - obj, ok := common.GetObjectForNode(pass.TypesInfo, receiver).Get() - if !ok { - return - } - if len(fn.Body.List) == 0 { - return - } - returnStmt, ok := fn.Body.List[0].(*ast.ReturnStmt) - if !ok || returnStmt.Results == nil || len(returnStmt.Results) == 0 { - return - } - - switch fn.Name.Name { - case "Name": - lit, ok := returnStmt.Results[0].(*ast.BasicLit) - if !ok { - common.Errorf(pass, fn, "unexpected return type; must implement ftl.DatabaseConfig") - return - } - name, err := strconv.Unquote(lit.Value) - if err != nil { - common.Errorf(pass, fn, "unexpected return type; must implement ftl.DatabaseConfig") - return - } - common.MarkDatabaseConfig(pass, obj, dbType, common.DatabaseConfigMethodName, name) - - default: - return - } -} - -func getDBType(pass *analysis.Pass, receiver *ast.Ident, receiverType types.Type) common.DatabaseType { - if common.IsPostgresDatabaseConfigType(pass, receiverType) { - return common.DatabaseTypePostgres - } - common.Errorf(pass, receiver, "unsupported database type") - return "" -} diff --git a/go-runtime/schema/database/analyzer.go b/go-runtime/schema/database/analyzer.go index 5b26ce0f5d..8ce7ed7011 100644 --- a/go-runtime/schema/database/analyzer.go +++ b/go-runtime/schema/database/analyzer.go @@ -11,76 +11,43 @@ import ( "github.com/TBD54566975/ftl/internal/schema" ) +const ftlPostgresDBFuncPath = "github.com/TBD54566975/ftl/go-runtime/ftl.PostgresDatabase" + // Extractor extracts databases to the module schema. -var Extractor = common.NewResourceDeclExtractor[*schema.Database]("database", Extract, matchFunc) +var Extractor = common.NewCallDeclExtractor[*schema.Database]("database", Extract, ftlPostgresDBFuncPath) -func Extract(pass *analysis.Pass, obj types.Object, node *ast.TypeSpec) optional.Option[*schema.Database] { +func Extract(pass *analysis.Pass, obj types.Object, node *ast.GenDecl, callExpr *ast.CallExpr, + callPath string) optional.Option[*schema.Database] { var comments []string if md, ok := common.GetFactForObject[*common.ExtractedMetadata](pass, obj).Get(); ok { comments = md.Comments } - switch getDBType(pass, node) { - case postgres: - return extractDatabase(pass, obj, node, schema.PostgresDatabaseType, comments) - default: - return optional.None[*schema.Database]() + if callPath == ftlPostgresDBFuncPath { + return extractDatabase(pass, callExpr, schema.PostgresDatabaseType, comments) } + return optional.None[*schema.Database]() } func extractDatabase( pass *analysis.Pass, - obj types.Object, - node *ast.TypeSpec, + node *ast.CallExpr, dbType string, comments []string, ) optional.Option[*schema.Database] { - db := &schema.Database{ - Pos: common.GoPosToSchemaPos(pass.Fset, node.Pos()), - Comments: comments, - Type: dbType, + name := common.ExtractStringLiteralArg(pass, node, 0) + if name == "" { + return optional.None[*schema.Database]() } - for _, cfg := range common.GetFactsForObject[*common.DatabaseConfig](pass, obj) { - if cfg.Method == common.DatabaseConfigMethodName { - name, ok := cfg.Value.(string) - if !ok { - common.Errorf(pass, node, "database name must be a string, was %T", cfg.Value) - return optional.None[*schema.Database]() - } - if !schema.ValidateName(name) { - common.Errorf(pass, node, "invalid database name %q", name) - return optional.None[*schema.Database]() - } - db.Name = name - } - } - if db.Name == "" { - common.Errorf(pass, node.Type, "database config must provide a name") + if !schema.ValidateName(name) { + common.Errorf(pass, node, "invalid database name %q", name) return optional.None[*schema.Database]() } - return optional.Some(db) -} - -func matchFunc(pass *analysis.Pass, node ast.Node) bool { - return getDBType(pass, node) != none -} - -type dbType int - -const ( - none dbType = iota - postgres -) - -func getDBType(pass *analysis.Pass, node ast.Node) dbType { - ts := node.(*ast.TypeSpec) //nolint:forcetypeassert - typ, ok := common.GetTypeInfoForNode(ts.Name, pass.TypesInfo).Get() - if !ok { - return none - } - if common.IsPostgresDatabaseConfigType(pass, typ) { - return postgres - } - return none + return optional.Some(&schema.Database{ + Pos: common.GoPosToSchemaPos(pass.Fset, node.Pos()), + Comments: comments, + Name: name, + Type: dbType, + }) } diff --git a/go-runtime/schema/extract.go b/go-runtime/schema/extract.go index cac3b76e12..cec828575c 100644 --- a/go-runtime/schema/extract.go +++ b/go-runtime/schema/extract.go @@ -15,7 +15,6 @@ import ( "github.com/TBD54566975/ftl/go-runtime/schema/call" "github.com/TBD54566975/ftl/go-runtime/schema/common" - "github.com/TBD54566975/ftl/go-runtime/schema/config" "github.com/TBD54566975/ftl/go-runtime/schema/configsecret" "github.com/TBD54566975/ftl/go-runtime/schema/data" "github.com/TBD54566975/ftl/go-runtime/schema/database" @@ -50,7 +49,6 @@ var extractors = [][]*analysis.Analyzer{ metadata.Extractor, }, { - config.Extractor, // must run before typeenumvariant.Extractor; typeenum.Extractor determines all possible discriminator // interfaces and typeenumvariant.Extractor determines any types that implement these typeenum.Extractor, @@ -63,6 +61,7 @@ var extractors = [][]*analysis.Analyzer{ typealias.Extractor, typeenumvariant.Extractor, valueenumvariant.Extractor, + verb.Extractor, }, { call.Extractor, @@ -70,7 +69,6 @@ var extractors = [][]*analysis.Analyzer{ // visits a node and aggregates its enum variants if present enum.Extractor, subscription.Extractor, - verb.Extractor, }, { transitive.Extractor, @@ -312,9 +310,6 @@ func combineAllPackageResults(results map[*analysis.Analyzer][]any, diagnostics return Result{}, fmt.Errorf("schema extraction finalizer result not found") } for _, r := range fResults { - if r == nil { - return Result{}, fmt.Errorf("schema extraction failed") - } fr, ok := r.(finalize.Result) if !ok { return Result{}, fmt.Errorf("unexpected schema extraction result type: %T", r) diff --git a/go-runtime/schema/initialize/analyzer.go b/go-runtime/schema/initialize/analyzer.go index 750ad7cb58..b410281c7b 100644 --- a/go-runtime/schema/initialize/analyzer.go +++ b/go-runtime/schema/initialize/analyzer.go @@ -27,8 +27,8 @@ type Result struct { types map[string]*types.Interface } -// IsStdlibErrorType will return true if the provided type is assertable to the stdlib `error` type. -func (r Result) IsStdlibErrorType(typ types.Type) bool { +// IsFtlErrorType will return true if the provided type is assertable to the `builtin.error` type. +func (r Result) IsFtlErrorType(typ types.Type) bool { return r.assertableToType(typ, "builtin", "error") } @@ -46,11 +46,11 @@ func (r Result) assertableToType(typ types.Type, pkg string, name string) bool { } func Run(pass *analysis.Pass) (interface{}, error) { - ctxType, err := loadRef(pass, "context", "Context") + ctxType, err := loadRef("context", "Context") if err != nil { return nil, err } - errType, err := loadRef(pass, "builtin", "error") + errType, err := loadRef("builtin", "error") if err != nil { return nil, err } @@ -61,33 +61,17 @@ func Run(pass *analysis.Pass) (interface{}, error) { }}, nil } -// Lazy load the compile-time reference from a package. First attempts to derive the package from imports, then if not -// found attempts to load the package directly. -func loadRef(pass *analysis.Pass, pkg, name string) (*types.Interface, error) { - var importedPkg *types.Package - for _, p := range pass.Pkg.Imports() { - if p.Path() == pkg { - importedPkg = p - } - } - - // if the package is not imported, attempt to load it. - if importedPkg == nil { - pkgs, err := packages.Load(&packages.Config{Fset: token.NewFileSet(), Mode: packages.NeedTypes}, pkg) - if err != nil { - return nil, fmt.Errorf("failed to load package %q: %w", pkg, err) - } - if len(pkgs) != 1 { - return nil, fmt.Errorf("expected one package, got %s", - strings.Join(slices.Map(pkgs, func(p *packages.Package) string { return p.Name }), ", ")) - } - importedPkg = pkgs[0].Types +// Lazy load the compile-time reference from a package. +func loadRef(pkg, name string) (*types.Interface, error) { + pkgs, err := packages.Load(&packages.Config{Fset: token.NewFileSet(), Mode: packages.NeedTypes}, pkg) + if err != nil { + return nil, fmt.Errorf("failed to load package %q: %w", pkg, err) } - if importedPkg == nil { - return nil, fmt.Errorf("package %q not found", pkg) + if len(pkgs) != 1 { + return nil, fmt.Errorf("expected one package, got %s", + strings.Join(slices.Map(pkgs, func(p *packages.Package) string { return p.Name }), ", ")) } - - obj := importedPkg.Scope().Lookup(name) + obj := pkgs[0].Types.Scope().Lookup(name) if obj == nil { return nil, fmt.Errorf("interface %q not found", name) } diff --git a/go-runtime/schema/schema_fuzz_integration_test.go b/go-runtime/schema/schema_fuzz_integration_test.go index 0b81daf0bb..c55a7d85fa 100644 --- a/go-runtime/schema/schema_fuzz_integration_test.go +++ b/go-runtime/schema/schema_fuzz_integration_test.go @@ -143,11 +143,7 @@ func DataFunc(ctx context.Context, req Data) (Data, error) { } -type MyDbConfig struct { - ftl.DefaultPostgresDatabaseConfig -} - -func (MyDbConfig) Name() string { return "testdb" } +var db = ftl.PostgresDatabase("testDb") ` + (func() string { if symbol == "int" || symbol == "string" { @@ -340,7 +336,7 @@ module test { config cfg {{.TypeName}} secret secret {{.TypeName}} - database postgres testdb + database postgres testDb export topic exportedTopic {{.TypeName}} topic topic {{.TypeName}} diff --git a/go-runtime/schema/schema_integration_test.go b/go-runtime/schema/schema_integration_test.go index 936f1fb101..c4c323d1ba 100644 --- a/go-runtime/schema/schema_integration_test.go +++ b/go-runtime/schema/schema_integration_test.go @@ -209,8 +209,6 @@ func testExtractModuleSchemaTwo(t *testing.T) { } actual := schema.Normalise(r.Module) expected := `module two { - database postgres foo - typealias BackoffAlias Any +typemap go "github.com/jpillora/backoff.Backoff" typealias ExplicitAliasAlias Any @@ -300,7 +298,6 @@ func testExtractModuleSchemaTwo(t *testing.T) { export verb three(two.Payload) two.Payload export verb two(two.Payload) two.Payload - +database calls two.foo } ` assert.Equal(t, normaliseString(expected), normaliseString(actual.String())) @@ -533,43 +530,43 @@ func testErrorReporting(t *testing.T) { `12:13-34: expected string literal for argument at index 0`, `15:18: duplicate config declaration for "failing.FTL_CONFIG_ENDPOINT"; already declared at "37:18"`, `18:18: duplicate secret declaration for "failing.FTL_SECRET_ENDPOINT"; already declared at "38:18"`, - `20:6: duplicate database declaration for "failing.testdb"; already declared at "42:6"`, - `27:2-10: unsupported type "error" for field "BadParam"`, - `30:2-17: unsupported type "uint64" for field "AnotherBadParam"`, - `33:3: unexpected directive "ftl:export" attached for verb, did you mean to use '//ftl:verb export' instead?`, - `39:45: unsupported request type "ftl/failing.Request"`, - `39:54-66: unsupported verb parameter type; verbs must have the signature func(Context, Request?, Resources...)`, - `39:69: unsupported response type "ftl/failing.Response"`, - `44:22-27: first parameter must be of type context.Context but is ftl/failing.Request`, - `44:53: unsupported response type "ftl/failing.Response"`, - `49:43-47: second parameter must not be ftl.Unit`, - `49:59: unsupported response type "ftl/failing.Response"`, - `54:1-2: first parameter must be context.Context`, - `54:18: unsupported response type "ftl/failing.Response"`, - `59:1-2: must have at most two results (, error)`, - `59:45: unsupported request type "ftl/failing.Request"`, - `64:1-2: must at least return an error`, - `64:40: unsupported request type "ftl/failing.Request"`, - `68:39: unsupported request type "ftl/failing.Request"`, - `68:48: must return an error but is "ftl/failing.Response"`, - `73:45: unsupported request type "ftl/failing.Request"`, - `73:63: must return an error but is "string"`, - `73:63: second result must not be ftl.Unit`, - `84:3: unexpected directive "ftl:verb"`, - `93:6-18: "BadValueEnum" is a value enum and cannot be tagged as a variant of type enum "TypeEnum" directly`, - `102:6-35: "BadValueEnumOrderDoesntMatter" is a value enum and cannot be tagged as a variant of type enum "TypeEnum" directly`, - `114:6: schema declaration with name "PrivateData" already exists for module "failing"; previously declared at "40:25"`, - `118:21-60: config names must be valid identifiers`, - `124:1: schema declaration contains conflicting directives`, - `124:1-26: only one directive expected when directive "ftl:enum" is present, found multiple`, - `146:6-45: enum discriminator "TypeEnum3" cannot contain exported methods`, - `149:6-35: enum discriminator "NoMethodsTypeEnum" must define at least one method`, - `161:3-14: unexpected token "d"`, - `168:2-62: can not publish directly to topics in other modules`, - `174:2-12: struct field unexported must be exported by starting with an uppercase letter`, - `178:6: unsupported type "ftl/failing/child.BadChildStruct" for field "child"`, - `183:6: duplicate data declaration for "failing.Redeclared"; already declared at "27:6"`, - `200:9: direct verb calls are not allowed; use the provided EmptyClient instead. See https://tbd54566975.github.io/ftl/docs/reference/verbs/#calling-verbs`, + `21:14: duplicate database declaration for "failing.testDb"; already declared at "41:14"`, + `24:2-10: unsupported type "error" for field "BadParam"`, + `27:2-17: unsupported type "uint64" for field "AnotherBadParam"`, + `30:3: unexpected directive "ftl:export" attached for verb, did you mean to use '//ftl:verb export' instead?`, + `36:45: unsupported request type "ftl/failing.Request"`, + `36:54-66: unsupported verb parameter type "Request"; verbs must have the signature func(Context, Request?, Resources...)`, + `36:69: unsupported response type "ftl/failing.Response"`, + `41:22-27: first parameter must be of type context.Context but is ftl/failing.Request`, + `41:53: unsupported response type "ftl/failing.Response"`, + `46:43-47: second parameter must not be ftl.Unit`, + `46:59: unsupported response type "ftl/failing.Response"`, + `51:1-2: first parameter must be context.Context`, + `51:18: unsupported response type "ftl/failing.Response"`, + `56:1-2: must have at most two results (, error)`, + `56:45: unsupported request type "ftl/failing.Request"`, + `61:1-2: must at least return an error`, + `61:40: unsupported request type "ftl/failing.Request"`, + `65:39: unsupported request type "ftl/failing.Request"`, + `65:48: must return an error but is ftl/failing.Response`, + `70:45: unsupported request type "ftl/failing.Request"`, + `70:63: must return an error but is string`, + `70:63: second result must not be ftl.Unit`, + `81:3: unexpected directive "ftl:verb"`, + `90:6-18: "BadValueEnum" is a value enum and cannot be tagged as a variant of type enum "TypeEnum" directly`, + `99:6-35: "BadValueEnumOrderDoesntMatter" is a value enum and cannot be tagged as a variant of type enum "TypeEnum" directly`, + `111:6: schema declaration with name "PrivateData" already exists for module "failing"; previously declared at "40:25"`, + `115:21-60: config names must be valid identifiers`, + `121:1: schema declaration contains conflicting directives`, + `121:1-26: only one directive expected when directive "ftl:enum" is present, found multiple`, + `143:6-45: enum discriminator "TypeEnum3" cannot contain exported methods`, + `146:6-35: enum discriminator "NoMethodsTypeEnum" must define at least one method`, + `158:3-14: unexpected token "d"`, + `165:2-62: can not publish directly to topics in other modules`, + `171:2-12: struct field unexported must be exported by starting with an uppercase letter`, + `175:6: unsupported type "ftl/failing/child.BadChildStruct" for field "child"`, + `180:6: duplicate data declaration for "failing.Redeclared"; already declared at "27:6"`, + `197:9: direct verb calls are not allowed; use the provided EmptyClient instead. See https://tbd54566975.github.io/ftl/docs/reference/verbs/#calling-verbs`, } // failing/child/child.go @@ -579,7 +576,7 @@ func testErrorReporting(t *testing.T) { `14:8: unsupported external type "github.com/TBD54566975/ftl/go-runtime/schema/testdata.NonFTLType"; see FTL docs on using external types: tbd54566975.github.io/ftl/docs/reference/externaltypes/`, `19:6-41: declared type github.com/blah.lib.NonFTLType in typemap does not match native type github.com/TBD54566975/ftl/go-runtime/schema/testdata.lib.NonFTLType`, `24:6: multiple Go type mappings found for "ftl/failing/child.MultipleMappings"`, - `34:2-13: enum variant "SameVariant" conflicts with existing enum variant of "EnumVariantConflictParent" at "190:2"`, + `34:2-13: enum variant "SameVariant" conflicts with existing enum variant of "EnumVariantConflictParent" at "187:2"`, } assert.Equal(t, expectedParent, actualParent) assert.Equal(t, expectedChild, actualChild) diff --git a/go-runtime/schema/testdata/failing/child/child.go b/go-runtime/schema/testdata/failing/child/child.go index 0170cc0626..e51e75175d 100644 --- a/go-runtime/schema/testdata/failing/child/child.go +++ b/go-runtime/schema/testdata/failing/child/child.go @@ -38,9 +38,4 @@ var duplConfig = ftl.Config[string]("FTL_CONFIG_ENDPOINT") var duplSecret = ftl.Secret[string]("FTL_SECRET_ENDPOINT") var duplicateDeclName = ftl.Config[string]("PrivateData") - -type DuplDbConfig struct { - ftl.DefaultPostgresDatabaseConfig -} - -func (DuplDbConfig) Name() string { return "testdb" } +var duplDB = ftl.PostgresDatabase("testDb") diff --git a/go-runtime/schema/testdata/failing/failing.go b/go-runtime/schema/testdata/failing/failing.go index 868e17fedd..85aabcf0c0 100644 --- a/go-runtime/schema/testdata/failing/failing.go +++ b/go-runtime/schema/testdata/failing/failing.go @@ -17,11 +17,8 @@ var goodConfig = ftl.Config[string]("FTL_CONFIG_ENDPOINT") // var duplSecret = ftl.Secret[string]("FTL_ENDPOINT") var goodSecret = ftl.Secret[string]("FTL_SECRET_ENDPOINT") -type DuplDbConfig struct { - ftl.DefaultPostgresDatabaseConfig -} - -func (DuplDbConfig) Name() string { return "testdb" } +// var duplDB = ftl.PostgresDatabase("testDb") +var goodDB = ftl.PostgresDatabase("testDb") type Request struct { BadParam error diff --git a/go-runtime/schema/testdata/failing/go.mod b/go-runtime/schema/testdata/failing/go.mod index 5d3dd361c4..45983b84a1 100644 --- a/go-runtime/schema/testdata/failing/go.mod +++ b/go-runtime/schema/testdata/failing/go.mod @@ -11,6 +11,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/go-runtime/schema/testdata/failing/go.sum b/go-runtime/schema/testdata/failing/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/go-runtime/schema/testdata/failing/go.sum +++ b/go-runtime/schema/testdata/failing/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/go-runtime/schema/testdata/fsm/types.ftl.go b/go-runtime/schema/testdata/fsm/types.ftl.go deleted file mode 100644 index 02cf3f9ff3..0000000000 --- a/go-runtime/schema/testdata/fsm/types.ftl.go +++ /dev/null @@ -1,32 +0,0 @@ -// Code generated by FTL. DO NOT EDIT. -package fsm - -import ( - "context" - "github.com/TBD54566975/ftl/go-runtime/ftl/reflection" -) - -type CreatedClient func(context.Context, OnlinePaymentCreated) error - -type PaidClient func(context.Context, OnlinePaymentPaid) error - -type CompletedClient func(context.Context, OnlinePaymentCompleted) error - -type FailedClient func(context.Context, OnlinePaymentFailed) error - -func init() { - reflection.Register( - reflection.ProvideResourcesForVerb( - Created, - ), - reflection.ProvideResourcesForVerb( - Paid, - ), - reflection.ProvideResourcesForVerb( - Completed, - ), - reflection.ProvideResourcesForVerb( - Failed, - ), - ) -} diff --git a/go-runtime/schema/testdata/one/go.mod b/go-runtime/schema/testdata/one/go.mod index 370a4d231b..704031f62f 100644 --- a/go-runtime/schema/testdata/one/go.mod +++ b/go-runtime/schema/testdata/one/go.mod @@ -14,18 +14,14 @@ require ( github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect - github.com/alecthomas/kong v1.3.0 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect github.com/alecthomas/types v0.16.0 // indirect github.com/benbjohnson/clock v1.3.5 // indirect - github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/danieljoos/wincred v1.2.2 // indirect github.com/deckarep/golang-set/v2 v2.6.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect github.com/hashicorp/cronexpr v1.1.2 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect @@ -40,15 +36,8 @@ require ( github.com/swaggest/refl v1.3.0 // indirect github.com/zalando/go-keyring v0.2.6 // indirect go.opentelemetry.io/otel v1.31.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.31.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.31.0 // indirect go.opentelemetry.io/otel/metric v1.31.0 // indirect - go.opentelemetry.io/otel/sdk v1.31.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.31.0 // indirect go.opentelemetry.io/otel/trace v1.31.0 // indirect - go.opentelemetry.io/proto/otlp v1.3.1 // indirect - go.uber.org/automaxprocs v1.6.0 // indirect golang.org/x/crypto v0.28.0 // indirect golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect golang.org/x/mod v0.21.0 // indirect @@ -56,8 +45,5 @@ require ( golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.26.0 // indirect golang.org/x/text v0.19.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9 // indirect - google.golang.org/grpc v1.67.1 // indirect google.golang.org/protobuf v1.35.1 // indirect ) diff --git a/go-runtime/schema/testdata/one/go.sum b/go-runtime/schema/testdata/one/go.sum index 3584716293..91fa4d7a80 100644 --- a/go-runtime/schema/testdata/one/go.sum +++ b/go-runtime/schema/testdata/one/go.sum @@ -16,8 +16,6 @@ github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELk github.com/alecthomas/atomic v0.1.0-alpha2/go.mod h1:zD6QGEyw49HIq19caJDc2NMXAy8rNi9ROrxtMXATfyI= github.com/alecthomas/concurrency v0.0.2 h1:Q3kGPtLbleMbH9lHX5OBFvJygfyFw29bXZKBg+IEVuo= github.com/alecthomas/concurrency v0.0.2/go.mod h1:GmuQb/iHX7mbNtPlC/WDzEFxDMB0HYFer2Qda9QTs7w= -github.com/alecthomas/kong v1.3.0 h1:YJKuU6/TV2XOBtymafSeuzDvLAFR8cYMZiXVNLhAO6g= -github.com/alecthomas/kong v1.3.0/go.mod h1:IDc8HyiouDdpdiEiY81iaEJM8rSIW6LzX8On4FCO0bE= github.com/alecthomas/participle/v2 v2.1.1 h1:hrjKESvSqGHzRb4yW1ciisFJ4p3MGYih6icjJvbsmV8= github.com/alecthomas/participle/v2 v2.1.1/go.mod h1:Y1+hAs8DHPmc3YUFzqllV+eSQ9ljPTk0ZkPMtEdAx2c= github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= @@ -30,8 +28,6 @@ github.com/bool64/dev v0.2.35 h1:M17TLsO/pV2J7PYI/gpe3Ua26ETkzZGb+dC06eoMqlk= github.com/bool64/dev v0.2.35/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= github.com/bool64/shared v0.1.5 h1:fp3eUhBsrSjNCQPcSdQqZxxh9bBwrYiZ+zOKFkM0/2E= github.com/bool64/shared v0.1.5/go.mod h1:081yz68YC9jeFB3+Bbmno2RFWvGKv1lPKkMP6MHJlPs= -github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= -github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/danieljoos/wincred v1.2.2 h1:774zMFJrqaeYCK2W57BgAem/MLi6mtSE47MB6BOJ0i0= github.com/danieljoos/wincred v1.2.2/go.mod h1:w7w4Utbrz8lqeMbDAK0lkNJUv5sAOkFi7nd/ogr0Uh8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -72,8 +68,6 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaU github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= github.com/hashicorp/cronexpr v1.1.2 h1:wG/ZYIKT+RT3QkOdgYc+xsKWVRgnxJ1OJtjjy84fJ9A= github.com/hashicorp/cronexpr v1.1.2/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= @@ -118,8 +112,6 @@ github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU= github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= -github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/puzpuzpuz/xsync/v3 v3.4.0 h1:DuVBAdXuGFHv8adVXjWWZ63pJq+NRXOWVXlKDBZ+mJ4= github.com/puzpuzpuz/xsync/v3 v3.4.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= @@ -153,12 +145,6 @@ github.com/zalando/go-keyring v0.2.6 h1:r7Yc3+H+Ux0+M72zacZoItR3UDxeWfKTcabvkI8u github.com/zalando/go-keyring v0.2.6/go.mod h1:2TCrxYrbUNYfNS/Kgy/LSrkSQzZ5UPVH85RwfczwvcI= go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY= go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.31.0 h1:FZ6ei8GFW7kyPYdxJaV2rgI6M+4tvZzhYsQ2wgyVC08= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.31.0/go.mod h1:MdEu/mC6j3D+tTEfvI15b5Ci2Fn7NneJ71YMoiS3tpI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0 h1:K0XaT3DwHAcV4nKLzcQvwAgSyisUghWoY20I7huthMk= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0/go.mod h1:B5Ki776z/MBnVha1Nzwp5arlzBbE3+1jk+pGmaP5HME= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.31.0 h1:FFeLy03iVTXP6ffeN2iXrxfGsZGCjVx0/4KlizjyBwU= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.31.0/go.mod h1:TMu73/k1CP8nBUpDLc71Wj/Kf7ZS9FK5b53VapRsP9o= go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE= go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk= @@ -167,12 +153,6 @@ go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4Jjx go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8= go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys= go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= -go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= -go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= -go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= -go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= -go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= -go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= @@ -196,10 +176,6 @@ golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9 h1:T6rh4haD3GVYsgEfWExoCZA2o2FmbNyKpTuAxbEFPTg= google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:wp2WsuBYj6j8wUdo3ToZsdxxixbvQNAHqVJrTgi5E5M= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9 h1:QCqS/PdaHTSWGvupk2F/ehwHtGc0/GYkT+3GAcR1CCc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= -google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= -google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/go-runtime/schema/testdata/one/one.go b/go-runtime/schema/testdata/one/one.go index c924584c3d..56f02c0116 100644 --- a/go-runtime/schema/testdata/one/one.go +++ b/go-runtime/schema/testdata/one/one.go @@ -134,12 +134,7 @@ type ExportedData struct { var configValue = ftl.Config[Config]("configValue") var secretValue = ftl.Secret[string]("secretValue") - -type MyDbConfig struct { - ftl.DefaultPostgresDatabaseConfig -} - -func (MyDbConfig) Name() string { return "testDb" } +var testDb = ftl.PostgresDatabase("testDb") //ftl:verb func Verb(ctx context.Context, req Req) (Resp, error) { diff --git a/go-runtime/schema/testdata/one/types.ftl.go b/go-runtime/schema/testdata/one/types.ftl.go index cb73650e2d..981057bd21 100644 --- a/go-runtime/schema/testdata/one/types.ftl.go +++ b/go-runtime/schema/testdata/one/types.ftl.go @@ -6,7 +6,6 @@ import ( ftlbuiltin "ftl/builtin" "github.com/TBD54566975/ftl/go-runtime/ftl" "github.com/TBD54566975/ftl/go-runtime/ftl/reflection" - "github.com/TBD54566975/ftl/go-runtime/server" stdtime "time" ) @@ -41,7 +40,6 @@ func init() { *new(Option), *new(ValueEnum), ), - reflection.Database[MyDbConfig]("testDb", server.InitPostgres), reflection.ProvideResourcesForVerb( BatchStringToTime, ), diff --git a/go-runtime/schema/testdata/parent/go.mod b/go-runtime/schema/testdata/parent/go.mod index db1928a3e8..1c8f2f36d3 100644 --- a/go-runtime/schema/testdata/parent/go.mod +++ b/go-runtime/schema/testdata/parent/go.mod @@ -9,6 +9,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/go-runtime/schema/testdata/parent/go.sum b/go-runtime/schema/testdata/parent/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/go-runtime/schema/testdata/parent/go.sum +++ b/go-runtime/schema/testdata/parent/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/go-runtime/schema/testdata/pubsub/go.mod b/go-runtime/schema/testdata/pubsub/go.mod index 401fe1635e..1efea13409 100644 --- a/go-runtime/schema/testdata/pubsub/go.mod +++ b/go-runtime/schema/testdata/pubsub/go.mod @@ -9,6 +9,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/go-runtime/schema/testdata/pubsub/go.sum b/go-runtime/schema/testdata/pubsub/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/go-runtime/schema/testdata/pubsub/go.sum +++ b/go-runtime/schema/testdata/pubsub/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/go-runtime/schema/testdata/subscriber/go.mod b/go-runtime/schema/testdata/subscriber/go.mod index 9761018e63..1168f1d967 100644 --- a/go-runtime/schema/testdata/subscriber/go.mod +++ b/go-runtime/schema/testdata/subscriber/go.mod @@ -9,6 +9,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/go-runtime/schema/testdata/subscriber/go.sum b/go-runtime/schema/testdata/subscriber/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/go-runtime/schema/testdata/subscriber/go.sum +++ b/go-runtime/schema/testdata/subscriber/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/go-runtime/schema/testdata/two/two.go b/go-runtime/schema/testdata/two/two.go index 581fe1101f..1f949568e3 100644 --- a/go-runtime/schema/testdata/two/two.go +++ b/go-runtime/schema/testdata/two/two.go @@ -10,12 +10,6 @@ import ( "ftl/builtin" ) -type FooConfig struct { - ftl.DefaultPostgresDatabaseConfig -} - -func (FooConfig) Name() string { return "foo" } - //ftl:enum export type TwoEnum string @@ -59,7 +53,7 @@ type UserResponse struct { } //ftl:verb export -func Two(ctx context.Context, req Payload[string], handle ftl.DatabaseHandle[FooConfig]) (Payload[string], error) { +func Two(ctx context.Context, req Payload[string]) (Payload[string], error) { return Payload[string]{}, nil } diff --git a/go-runtime/schema/testdata/two/types.ftl.go b/go-runtime/schema/testdata/two/types.ftl.go index 504b312d0f..a946d86462 100644 --- a/go-runtime/schema/testdata/two/types.ftl.go +++ b/go-runtime/schema/testdata/two/types.ftl.go @@ -33,14 +33,12 @@ func init() { ), reflection.ExternalType(*new(backoff.Backoff)), reflection.ExternalType(*new(lib.NonFTLType)), - reflection.Database[FooConfig]("foo", server.InitPostgres), reflection.ProvideResourcesForVerb( CallsTwo, server.VerbClient[TwoClient, Payload[string], Payload[string]](), ), reflection.ProvideResourcesForVerb( Two, - server.PostgresDatabaseHandle[FooConfig](), ), reflection.ProvideResourcesForVerb( CallsTwoAndThree, diff --git a/go-runtime/schema/testdata/validation/go.mod b/go-runtime/schema/testdata/validation/go.mod index 7189298ba7..c94ac80cf9 100644 --- a/go-runtime/schema/testdata/validation/go.mod +++ b/go-runtime/schema/testdata/validation/go.mod @@ -11,6 +11,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/go-runtime/schema/testdata/validation/go.sum b/go-runtime/schema/testdata/validation/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/go-runtime/schema/testdata/validation/go.sum +++ b/go-runtime/schema/testdata/validation/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/go-runtime/schema/verb/analyzer.go b/go-runtime/schema/verb/analyzer.go index 573cb96c45..373fadecaa 100644 --- a/go-runtime/schema/verb/analyzer.go +++ b/go-runtime/schema/verb/analyzer.go @@ -20,7 +20,6 @@ type resourceType int const ( none resourceType = iota verbClient - databaseHandle ) // Extractor extracts verbs to the module schema. @@ -32,8 +31,6 @@ func Extract(pass *analysis.Pass, node *ast.FuncDecl, obj types.Object) optional Name: strcase.ToLowerCamel(node.Name.Name), } - loaded := pass.ResultOf[initialize.Analyzer].(initialize.Result) //nolint:forcetypeassert - hasRequest := false if !common.ApplyMetadata[*schema.Verb](pass, obj, func(md *common.ExtractedMetadata) { verb.Comments = md.Comments @@ -41,11 +38,11 @@ func Extract(pass *analysis.Pass, node *ast.FuncDecl, obj types.Object) optional verb.Metadata = md.Metadata for idx, param := range node.Type.Params.List { paramObj, hasObj := common.GetObjectForNode(pass.TypesInfo, param.Type).Get() - switch getParamResourceType(pass, paramObj) { + switch getParamResourceType(paramObj) { case none: if idx > 1 { - common.Errorf(pass, param, "unsupported verb parameter type; verbs must have the "+ - "signature func(Context, Request?, Resources...)") + common.Errorf(pass, param, "unsupported verb parameter type %q; verbs must have the "+ + "signature func(Context, Request?, Resources...)", param.Type) continue } if idx == 1 { @@ -53,37 +50,13 @@ func Extract(pass *analysis.Pass, node *ast.FuncDecl, obj types.Object) optional } case verbClient: if !hasObj { - common.Errorf(pass, param, "unsupported verb parameter type") + common.Errorf(pass, param, "unsupported verb parameter type %q", param.Type) continue } calleeRef := getResourceRef(paramObj, pass, param) calleeRef.Name = strings.TrimSuffix(calleeRef.Name, "Client") verb.AddCall(calleeRef) common.MarkIncludeNativeName(pass, paramObj, calleeRef) - case databaseHandle: - idxExpr, ok := param.Type.(*ast.IndexExpr) - if !ok { - common.Errorf(pass, param, "unsupported verb parameter type") - continue - } - idxObj, ok := common.GetObjectForNode(pass.TypesInfo, idxExpr.Index).Get() - if !ok { - common.Errorf(pass, param, "unsupported verb parameter type") - continue - } - decl, ok := common.GetFactForObject[*common.ExtractedDecl](pass, idxObj).Get() - if !ok { - common.Errorf(pass, param, "unsupported verb parameter type") - continue - } - db, ok := decl.Decl.(*schema.Database) - if !ok { - common.Errorf(pass, param, "no database found for config provided to database handle") - continue - } - ref := getResourceRef(idxObj, pass, param) - ref.Name = db.Name - verb.AddDatabase(ref) } } }) { @@ -97,7 +70,7 @@ func Extract(pass *analysis.Pass, node *ast.FuncDecl, obj types.Object) optional return optional.None[*schema.Verb]() } - reqt, respt := checkSignature(pass, loaded, node, sig, hasRequest) + reqt, respt := checkSignature(pass, node, sig, hasRequest) req := optional.Some[schema.Type](&schema.Unit{}) if reqt.Ok() { req = common.ExtractType(pass, node.Type.Params.List[1].Type) @@ -124,13 +97,7 @@ func Extract(pass *analysis.Pass, node *ast.FuncDecl, obj types.Object) optional return optional.Some(verb) } -func checkSignature( - pass *analysis.Pass, - loaded initialize.Result, - node *ast.FuncDecl, - sig *types.Signature, - hasRequest bool, -) (req, resp optional.Option[*types.Var]) { +func checkSignature(pass *analysis.Pass, node *ast.FuncDecl, sig *types.Signature, hasRequest bool) (req, resp optional.Option[*types.Var]) { if node.Name.Name == "" { common.Errorf(pass, node, "verb function must be named") return optional.None[*types.Var](), optional.None[*types.Var]() @@ -142,6 +109,7 @@ func checkSignature( params := sig.Params() results := sig.Results() + loaded := pass.ResultOf[initialize.Analyzer].(initialize.Result) //nolint:forcetypeassert if params.Len() == 0 { common.Errorf(pass, node, "first parameter must be context.Context") } else if !loaded.IsContextType(params.At(0).Type()) { @@ -163,8 +131,8 @@ func checkSignature( } if results.Len() == 0 { common.Errorf(pass, node, "must at least return an error") - } else if !loaded.IsStdlibErrorType(results.At(results.Len() - 1).Type()) { - common.TokenErrorf(pass, results.At(results.Len()-1).Pos(), results.At(results.Len()-1).Name(), "must return an error but is %q", results.At(0).Type()) + } else if !loaded.IsFtlErrorType(results.At(results.Len() - 1).Type()) { + common.TokenErrorf(pass, results.At(results.Len()-1).Pos(), results.At(results.Len()-1).Name(), "must return an error but is %s", results.At(0).Type()) } if results.Len() == 2 { if results.At(1).Type().String() == common.FtlUnitTypePath { @@ -175,32 +143,18 @@ func checkSignature( return req, resp } -func getParamResourceType(pass *analysis.Pass, paramObj types.Object) resourceType { +func getParamResourceType(paramObj types.Object) resourceType { if paramObj == nil { return none } - if paramObj.Pkg() == nil { - return none - } switch t := paramObj.Type().(type) { case *types.Named: - if isDatabaseHandleType(pass, t) { - return databaseHandle - } - if _, ok := t.Underlying().(*types.Signature); !ok { return none } return verbClient - case *types.Alias: - named, ok := t.Rhs().(*types.Named) - if !ok { - return none - } - return getParamResourceType(pass, named.Obj()) - default: return none } @@ -209,7 +163,7 @@ func getParamResourceType(pass *analysis.Pass, paramObj types.Object) resourceTy func getResourceRef(paramObj types.Object, pass *analysis.Pass, param *ast.Field) *schema.Ref { paramModule, err := common.FtlModuleFromGoPackage(paramObj.Pkg().Path()) if err != nil { - common.Errorf(pass, param, "failed to resolve module for type: %v", err) + common.Errorf(pass, param, "failed to resolve module for type %q: %v", paramObj.String(), err) } dbRef := &schema.Ref{ Module: paramModule, @@ -217,17 +171,3 @@ func getResourceRef(paramObj types.Object, pass *analysis.Pass, param *ast.Field } return dbRef } - -func isDatabaseHandleType(pass *analysis.Pass, named *types.Named) bool { - if named.Obj().Pkg().Path()+"."+named.Obj().Name() != "github.com/TBD54566975/ftl/go-runtime/ftl.DatabaseHandle" { - return false - } - - if named.TypeParams().Len() != 1 { - return false - } - typeArg := named.TypeParams().At(0) - - // type argument implements `DatabaseConfig`, e.g. DatabaseHandle[MyConfig] where MyConfig implements DatabaseConfig - return common.IsDatabaseConfigType(pass, typeArg) -} diff --git a/go-runtime/server/database.go b/go-runtime/server/database.go deleted file mode 100644 index a0bb81c2c5..0000000000 --- a/go-runtime/server/database.go +++ /dev/null @@ -1,71 +0,0 @@ -package server - -import ( - "context" - "database/sql" - "fmt" - "reflect" - "time" - - "github.com/XSAM/otelsql" - "github.com/alecthomas/types/once" - "go.opentelemetry.io/otel/attribute" - semconv "go.opentelemetry.io/otel/semconv/v1.4.0" - - "github.com/TBD54566975/ftl/go-runtime/ftl" - "github.com/TBD54566975/ftl/go-runtime/ftl/reflection" - "github.com/TBD54566975/ftl/internal/log" - "github.com/TBD54566975/ftl/internal/modulecontext" -) - -func PostgresDatabaseHandle[T ftl.DatabaseConfig]() reflection.VerbResource { - typ := reflect.TypeFor[T]() - var config T - if typ.Kind() == reflect.Ptr { - config = reflect.New(typ.Elem()).Interface().(T) //nolint:forcetypeassert - } else { - config = reflect.New(typ).Elem().Interface().(T) //nolint:forcetypeassert - } - - return func() reflect.Value { - reflectedDB := reflection.GetDatabase[T]() - db := ftl.NewDatabaseHandle(config, ftl.DatabaseTypePostgres, reflectedDB.DB) - return reflect.ValueOf(db) - } -} - -func InitPostgres(ref reflection.Ref) *reflection.ReflectedDatabaseHandle { - return &reflection.ReflectedDatabaseHandle{ - Name: ref.Name, - DBType: "postgres", - DB: once.Once(func(ctx context.Context) (*sql.DB, error) { - logger := log.FromContext(ctx) - - provider := modulecontext.FromContext(ctx).CurrentContext() - dsn, err := provider.GetDatabase(ref.Name, modulecontext.DBTypePostgres) - if err != nil { - return nil, fmt.Errorf("failed to get database %q: %w", ref.Name, err) - } - - logger.Debugf("Opening database: %s", ref.Name) - db, err := otelsql.Open("pgx", dsn) - if err != nil { - return nil, fmt.Errorf("failed to open database %q: %w", ref.Name, err) - } - - // sets db.system and db.name attributes - metricAttrs := otelsql.WithAttributes( - semconv.DBSystemPostgreSQL, - semconv.DBNameKey.String(ref.Name), - attribute.Bool("ftl.is_user_service", true), - ) - err = otelsql.RegisterDBStatsMetrics(db, metricAttrs) - if err != nil { - return nil, fmt.Errorf("failed to register database metrics: %w", err) - } - db.SetConnMaxIdleTime(time.Minute) - db.SetMaxOpenConns(20) - return db, nil - }), - } -} diff --git a/go-runtime/server/server.go b/go-runtime/server/server.go index 8f107cbc79..bd3487321f 100644 --- a/go-runtime/server/server.go +++ b/go-runtime/server/server.go @@ -81,8 +81,8 @@ func HandleCall[Req, Resp any](verb any) Handler { } ctx = observability.AddSpanContextToLogger(ctx) - // InvokeVerb Verb. - resp, err := InvokeVerb[Req, Resp](ref)(ctx, req) + // Call Verb. + resp, err := Call[Req, Resp](ref)(ctx, req) if err != nil { return nil, fmt.Errorf("call to verb %s failed: %w", ref, err) } @@ -109,29 +109,56 @@ func HandleEmpty(verb any) Handler { return HandleCall[ftl.Unit, ftl.Unit](verb) } -func InvokeVerb[Req, Resp any](ref reflection.Ref) func(ctx context.Context, req Req) (resp Resp, err error) { +func call[Verb, Req, Resp any]() func(ctx context.Context, req Req) (resp Resp, err error) { + typ := reflect.TypeFor[Verb]() + if typ.Kind() != reflect.Func { + panic(fmt.Sprintf("Cannot register %s: expected function, got %s", typ, typ.Kind())) + } + callee := reflection.TypeRef[Verb]() + callee.Name = strings.TrimSuffix(callee.Name, "Client") return func(ctx context.Context, req Req) (resp Resp, err error) { - request := optional.Some[any](req) - if reflect.TypeFor[Req]() == reflect.TypeFor[ftl.Unit]() { - request = optional.None[any]() + ref := reflection.Ref{Module: callee.Module, Name: callee.Name} + moduleCtx := modulecontext.FromContext(ctx).CurrentContext() + override, err := moduleCtx.BehaviorForVerb(schema.Ref{Module: ref.Module, Name: ref.Name}) + if err != nil { + return resp, fmt.Errorf("%s: %w", ref, err) + } + if behavior, ok := override.Get(); ok { + uncheckedResp, err := behavior.Call(ctx, modulecontext.Verb(widenVerb(Call[Req, Resp](ref))), req) + if err != nil { + return resp, fmt.Errorf("%s: %w", ref, err) + } + if r, ok := uncheckedResp.(Resp); ok { + return r, nil + } + return resp, fmt.Errorf("%s: overridden verb had invalid response type %T, expected %v", ref, + uncheckedResp, reflect.TypeFor[Resp]()) } - out, err := reflection.CallVerb(reflection.Ref{Module: ref.Module, Name: ref.Name})(ctx, request) + reqData, err := encoding.Marshal(req) if err != nil { - return resp, err + return resp, fmt.Errorf("%s: failed to marshal request: %w", callee, err) } - var respValue any - if r, ok := out.Get(); ok { - respValue = r - } else { - respValue = ftl.Unit{} + client := rpc.ClientFromContext[ftlv1connect.VerbServiceClient](ctx) + cresp, err := client.Call(ctx, connect.NewRequest(&ftlv1.CallRequest{Verb: callee.ToProto(), Body: reqData})) + if err != nil { + return resp, fmt.Errorf("%s: failed to call Verb: %w", callee, err) } - resp, ok := respValue.(Resp) - if !ok { - return resp, fmt.Errorf("unexpected response type from verb %s: %T", ref, resp) + switch cresp := cresp.Msg.Response.(type) { + case *ftlv1.CallResponse_Error_: + return resp, fmt.Errorf("%s: %s", callee, cresp.Error.Message) + + case *ftlv1.CallResponse_Body: + err = encoding.Unmarshal(cresp.Body, &resp) + if err != nil { + return resp, fmt.Errorf("%s: failed to decode response: %w", callee, err) + } + return resp, nil + + default: + panic(fmt.Sprintf("%s: invalid response type %T", callee, cresp)) } - return resp, err } } @@ -174,56 +201,29 @@ func EmptyClient[Verb any]() reflection.VerbResource { } } -func call[Verb, Req, Resp any]() func(ctx context.Context, req Req) (resp Resp, err error) { - typ := reflect.TypeFor[Verb]() - if typ.Kind() != reflect.Func { - panic(fmt.Sprintf("Cannot register %s: expected function, got %s", typ, typ.Kind())) - } - callee := reflection.TypeRef[Verb]() - callee.Name = strings.TrimSuffix(callee.Name, "Client") +func Call[Req, Resp any](ref reflection.Ref) func(ctx context.Context, req Req) (resp Resp, err error) { return func(ctx context.Context, req Req) (resp Resp, err error) { - ref := reflection.Ref{Module: callee.Module, Name: callee.Name} - moduleCtx := modulecontext.FromContext(ctx).CurrentContext() - override, err := moduleCtx.BehaviorForVerb(schema.Ref{Module: ref.Module, Name: ref.Name}) - if err != nil { - return resp, fmt.Errorf("%s: %w", ref, err) - } - if behavior, ok := override.Get(); ok { - uncheckedResp, err := behavior.Call(ctx, modulecontext.Verb(widenVerb(InvokeVerb[Req, Resp](ref))), req) - if err != nil { - return resp, fmt.Errorf("%s: %w", ref, err) - } - if r, ok := uncheckedResp.(Resp); ok { - return r, nil - } - return resp, fmt.Errorf("%s: overridden verb had invalid response type %T, expected %v", ref, - uncheckedResp, reflect.TypeFor[Resp]()) + request := optional.Some[any](req) + if reflect.TypeFor[Req]() == reflect.TypeFor[ftl.Unit]() { + request = optional.None[any]() } - reqData, err := encoding.Marshal(req) + out, err := reflection.CallVerb(reflection.Ref{Module: ref.Module, Name: ref.Name})(ctx, request) if err != nil { - return resp, fmt.Errorf("%s: failed to marshal request: %w", callee, err) + return resp, err } - client := rpc.ClientFromContext[ftlv1connect.VerbServiceClient](ctx) - cresp, err := client.Call(ctx, connect.NewRequest(&ftlv1.CallRequest{Verb: callee.ToProto(), Body: reqData})) - if err != nil { - return resp, fmt.Errorf("%s: failed to call Verb: %w", callee, err) + var respValue any + if r, ok := out.Get(); ok { + respValue = r + } else { + respValue = ftl.Unit{} } - switch cresp := cresp.Msg.Response.(type) { - case *ftlv1.CallResponse_Error_: - return resp, fmt.Errorf("%s: %s", callee, cresp.Error.Message) - - case *ftlv1.CallResponse_Body: - err = encoding.Unmarshal(cresp.Body, &resp) - if err != nil { - return resp, fmt.Errorf("%s: failed to decode response: %w", callee, err) - } - return resp, nil - - default: - panic(fmt.Sprintf("%s: invalid response type %T", callee, cresp)) + resp, ok := respValue.(Resp) + if !ok { + return resp, fmt.Errorf("unexpected response type from verb %s: %T", ref, resp) } + return resp, err } } diff --git a/internal/buildengine/languageplugin/testdata/go/plugintest/go.mod b/internal/buildengine/languageplugin/testdata/go/plugintest/go.mod index f2f51a8c18..36aa6e83b2 100644 --- a/internal/buildengine/languageplugin/testdata/go/plugintest/go.mod +++ b/internal/buildengine/languageplugin/testdata/go/plugintest/go.mod @@ -9,6 +9,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/internal/buildengine/languageplugin/testdata/go/plugintest/go.sum b/internal/buildengine/languageplugin/testdata/go/plugintest/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/internal/buildengine/languageplugin/testdata/go/plugintest/go.sum +++ b/internal/buildengine/languageplugin/testdata/go/plugintest/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/internal/buildengine/testdata/another/go.mod b/internal/buildengine/testdata/another/go.mod index cfa2842f52..2a995e671d 100644 --- a/internal/buildengine/testdata/another/go.mod +++ b/internal/buildengine/testdata/another/go.mod @@ -9,6 +9,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/internal/buildengine/testdata/another/go.sum b/internal/buildengine/testdata/another/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/internal/buildengine/testdata/another/go.sum +++ b/internal/buildengine/testdata/another/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/internal/buildengine/testdata/other/go.mod b/internal/buildengine/testdata/other/go.mod index 4418b9c19d..d5f0150c12 100644 --- a/internal/buildengine/testdata/other/go.mod +++ b/internal/buildengine/testdata/other/go.mod @@ -9,6 +9,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/internal/buildengine/testdata/other/go.sum b/internal/buildengine/testdata/other/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/internal/buildengine/testdata/other/go.sum +++ b/internal/buildengine/testdata/other/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/internal/modulecontext/module_context.go b/internal/modulecontext/module_context.go index 4d4e6a22a0..93350a7382 100644 --- a/internal/modulecontext/module_context.go +++ b/internal/modulecontext/module_context.go @@ -165,7 +165,7 @@ func (m ModuleContext) GetDatabase(name string, dbType DBType) (string, error) { return "", fmt.Errorf("database %s does not match expected type of %s", name, dbType) } if m.isTesting && !db.isTestDB { - return "", fmt.Errorf("accessing non-test database %q while testing: try adding ftltest.WithDatabase[MyConfig]() as an option with ftltest.Context(...)", name) + return "", fmt.Errorf("accessing non-test database %q while testing: try adding ftltest.WithDatabase(db) as an option with ftltest.Context(...)", name) } return db.DSN, nil } diff --git a/internal/projectconfig/testdata/go/echo/go.mod b/internal/projectconfig/testdata/go/echo/go.mod index d3407d6c1b..9017349724 100644 --- a/internal/projectconfig/testdata/go/echo/go.mod +++ b/internal/projectconfig/testdata/go/echo/go.mod @@ -9,6 +9,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/internal/projectconfig/testdata/go/echo/go.sum b/internal/projectconfig/testdata/go/echo/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/internal/projectconfig/testdata/go/echo/go.sum +++ b/internal/projectconfig/testdata/go/echo/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/internal/projectconfig/testdata/go/findconfig/go.mod b/internal/projectconfig/testdata/go/findconfig/go.mod index 9eca60700f..e962463088 100644 --- a/internal/projectconfig/testdata/go/findconfig/go.mod +++ b/internal/projectconfig/testdata/go/findconfig/go.mod @@ -9,6 +9,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/internal/projectconfig/testdata/go/findconfig/go.sum b/internal/projectconfig/testdata/go/findconfig/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/internal/projectconfig/testdata/go/findconfig/go.sum +++ b/internal/projectconfig/testdata/go/findconfig/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/internal/projectconfig/testdata/go/validateconfig/go.mod b/internal/projectconfig/testdata/go/validateconfig/go.mod index 900ad13a5a..9bc5836ed2 100644 --- a/internal/projectconfig/testdata/go/validateconfig/go.mod +++ b/internal/projectconfig/testdata/go/validateconfig/go.mod @@ -9,6 +9,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/internal/projectconfig/testdata/go/validateconfig/go.sum b/internal/projectconfig/testdata/go/validateconfig/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/internal/projectconfig/testdata/go/validateconfig/go.sum +++ b/internal/projectconfig/testdata/go/validateconfig/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/internal/schema/verb.go b/internal/schema/verb.go index a9d6c9113f..3fb5f0425b 100644 --- a/internal/schema/verb.go +++ b/internal/schema/verb.go @@ -126,15 +126,6 @@ func (v *Verb) AddSecret(secret *Ref) { v.Metadata = append(v.Metadata, &MetadataSecrets{Secrets: []*Ref{secret}}) } -// AddDatabase adds a DB reference to the Verb. -func (v *Verb) AddDatabase(db *Ref) { - if c, ok := slices.FindVariant[*MetadataDatabases](v.Metadata); ok { - c.Calls = append(c.Calls, db) - return - } - v.Metadata = append(v.Metadata, &MetadataDatabases{Calls: []*Ref{db}}) -} - func (v *Verb) GetMetadataIngress() optional.Option[*MetadataIngress] { if m, ok := slices.FindVariant[*MetadataIngress](v.Metadata); ok { return optional.Some(m) diff --git a/internal/watch/testdata/another/go.mod b/internal/watch/testdata/another/go.mod index cfa2842f52..2a995e671d 100644 --- a/internal/watch/testdata/another/go.mod +++ b/internal/watch/testdata/another/go.mod @@ -9,6 +9,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/internal/watch/testdata/another/go.sum b/internal/watch/testdata/another/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/internal/watch/testdata/another/go.sum +++ b/internal/watch/testdata/another/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/internal/watch/testdata/other/go.mod b/internal/watch/testdata/other/go.mod index 4418b9c19d..d5f0150c12 100644 --- a/internal/watch/testdata/other/go.mod +++ b/internal/watch/testdata/other/go.mod @@ -9,6 +9,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/internal/watch/testdata/other/go.sum b/internal/watch/testdata/other/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/internal/watch/testdata/other/go.sum +++ b/internal/watch/testdata/other/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/jvm-runtime/testdata/go/gomodule/go.mod b/jvm-runtime/testdata/go/gomodule/go.mod index fbdc05eea5..49a624161b 100644 --- a/jvm-runtime/testdata/go/gomodule/go.mod +++ b/jvm-runtime/testdata/go/gomodule/go.mod @@ -14,6 +14,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/jvm-runtime/testdata/go/gomodule/go.sum b/jvm-runtime/testdata/go/gomodule/go.sum index a35014485f..0c7555c6e8 100644 --- a/jvm-runtime/testdata/go/gomodule/go.sum +++ b/jvm-runtime/testdata/go/gomodule/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert v1.0.0 h1:3XmGh/PSuLzDbK3W2gUbRXwgW5lqPkuqvRgeQ30FI5o= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= diff --git a/smoketest/origin/go.mod b/smoketest/origin/go.mod index 5e6b4d9f0d..11ab8afdde 100644 --- a/smoketest/origin/go.mod +++ b/smoketest/origin/go.mod @@ -9,6 +9,7 @@ require ( connectrpc.com/connect v1.16.2 // indirect connectrpc.com/grpcreflect v1.2.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect + github.com/XSAM/otelsql v0.35.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect diff --git a/smoketest/origin/go.sum b/smoketest/origin/go.sum index 3f6403960b..91fa4d7a80 100644 --- a/smoketest/origin/go.sum +++ b/smoketest/origin/go.sum @@ -8,6 +8,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= diff --git a/smoketest/relay/relay.go b/smoketest/relay/relay.go index ad781bbc3d..30011acad9 100644 --- a/smoketest/relay/relay.go +++ b/smoketest/relay/relay.go @@ -13,6 +13,8 @@ import ( var logFile = ftl.Config[string]("log_file") +// var db = ftl.PostgresDatabase("exemplardb") + // PubSub var _ = ftl.Subscription(origin.AgentBroadcast, "agentConsumer")