entgql: schema-qualify M2M join table in totalCount loader - #636
Conversation
17ccd50 to
31b1a58
Compare
|
cc @chinhnguyenh for review too. |
There was a problem hiding this comment.
Pull request overview
This PR fixes schema qualification for M2M join tables in the totalCount loader generated by entgql, ensuring queries work correctly when Ent’s sql/schemaconfig feature is enabled (avoiding runtime relation does not exist errors due to unqualified join tables).
Changes:
- Hooks the
dialect/sql/query/eagerloading/join/*template extension point into the M2MtotalCountloader path. - Ensures the join-table builder (
joinT := sql.Table(...)) can be modified by the same join-schema logic used by Ent core eager-loading queries. - Keeps behavior a no-op when no matching join templates are present (e.g., feature disabled).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Look good to me. |
Hi, @chinhnguyenh, are you on Discord? If so, can I reach out there? I have a few questions about the best way to add a test. If we want to create a new multischema project, we'll need MySQL to test it. Otherwise, we can limit the test to reading the generated code. Edit: I've added each option as a separate commit. If you'd like to discuss either option, please feel free to message me on Discord. |
31b1a58 to
8defc40
Compare
The gql_collection.go totalCount loader for M2M edges builds the join table via `sql.Table(...)` but never calls `joinT.Schema(...)`. With the `sql/schemaconfig` feature enabled, this emits an unqualified join table in the generated SQL while the rest of the query is correctly schema- qualified, producing `relation does not exist` errors at runtime. Hook the same `dialect/sql/query/eagerloading/join/*` template extension point that ent core's query.tmpl uses for the loader path, so the join table picks up its schema from `schemaConfig`. No-op when the feature is disabled (verified: all 6 integration tests regenerate byte-identically). Co-authored-by: Isaac
Add a test (entgql/template_test.go) that renders the collection template with and without the sql/schemaconfig feature and asserts the M2M totalCount join table is schema-qualified only when the feature is enabled. Covers the fix from the preceding commit at the codegen level and runs in CI against SQLite.
8defc40 to
d3a3d97
Compare
Add internal/multischema, a minimal Group<->User M2M project with the sql/schemaconfig feature, plus a MySQL-backed functional test that places the join table in a separate schema and drives totalCount through the gqlgen + ent runtime. ent omits schema qualifiers for SQLite (see (*sql.Builder).writeSchema), so the schema-qualified join is only observable on a schema-aware database; the test skips when MySQL is unreachable. Add a mysql8 service to the CI test job (mirroring ent's integration CI) so the test runs instead of skipping, and the go-sql-driver/mysql dependency it requires. Co-authored-by: Isaac
d3a3d97 to
659006e
Compare
We don't need to test it with MySQL, verifing the generated code is enough. |
| // TestCollection_M2MTotalCountSchemaConfig verifies that the M2M totalCount | ||
| // loader schema-qualifies its join table when the sql/schemaconfig feature is | ||
| // enabled, and leaves it unqualified otherwise. | ||
| func TestCollection_M2MTotalCountSchemaConfig(t *testing.T) { |
There was a problem hiding this comment.
Create gen_test.go in the example project and create tests there instead.
There was a problem hiding this comment.
If we're testing only the generated code, do we need the new project? Can I drop my last commit?
There was a problem hiding this comment.
The example project is what CI regenerates and diffs. The test only reads the output, but the project is what keeps that output committed, compilable, and in sync with the templates.
There was a problem hiding this comment.
Anyway, it's just a nice-to-have.
* entgql: fix field arguments collection (ent#495) * entgql: collect interafce/union selection fields of unique edges (ent#498) * entproto: support enum values with special characters (ent#487) * build(deps): bump golang.org/x/tools from 0.7.0 to 0.9.1 (ent#504) Bumps [golang.org/x/tools](https://github.com/golang/tools) from 0.7.0 to 0.9.1. - [Release notes](https://github.com/golang/tools/releases) - [Commits](golang/tools@v0.7.0...v0.9.1) --- updated-dependencies: - dependency-name: golang.org/x/tools dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * entgql: support collecting fields of renamed types (ent#505) * entgql: implement interfaces and collect all node implementors (ent#507) * entgql: support generating non-optional Map fields (ent#508) * feat: add SkipGenFile option (ent#499) * entgql: fixed Paginate query for count (ent#512) * entgql: fixed Paginate query for count * Update entgql/template/pagination.tmpl Co-authored-by: Ariel Mashraki <7413593+a8m@users.noreply.github.com> * entgql: codegen --------- Co-authored-by: Ariel Mashraki <7413593+a8m@users.noreply.github.com> * entgql/internal/todo: add example for json as mutation inputs (ent#513) * entproto/cmd: fix setting target path (ent#521) * entproto: add support for int slices (ent#522) * entproto: support json for integer type slices * adding int slices to grpc test suite --------- Co-authored-by: jamslinger <80337165+jamslinger@users.noreply.github.com> * entgql: privatize columns used in cursors predicates (ent#537) * privatize columns used in cursors predicates * add tests * entgql: avoid naming conflicts in toCursor template (ent#538) * fix: rename variable when iterating through p.order to prevent conflict with $r that starts with "O" character * fix: run go generate on entgql * entgql: upgrade gqlgen and disable getters (ent#544) * entgql: upgrade gqlgen and disable getters * entgql: codegen * chore: fixed go.mod * add AllowClientUUIDs for client UUIDs in POSTs (ent#541) * chore: upgrade ent and atlas (ent#554) * chore: upgrade ent and atlas * fix: bump go version to 1.20 * .ci: upgrade golangci * chore: codegen * entgql: fixed go-fmt (ent#555) * all: upgrade ent and gqlgen to latest (ent#564) * entgql: ensure order fields are prefixed with type name (ent#565) Also when order field is set on an edge * entgql: add missing directive's argument (ent#567) * entgql: avoid using cte queries for single node paths (ent#569) No need to limit per node, when a single node is returned in a path * entgql: support skipping tx-opening by operation or field name (ent#571) * entgql: improve var name collision avoidance in toCursor (ent#572) Improves variable name collision avoidance in the `toCursor` method of the pager types in the `gql_pagination` template by suffixing all hard-coded variables names with an underscore. * fix tests * fix * go: update gqlgen (ent#583) * update gqlgen pkg * run code gen * update proto * gen protobuf * fix tests * update protoc version in ci * update back protoc version * entgql/template: improve goimports time by adding missing imports (ent#584) * ci: use node20 actions because node16 actions are deprecated (ent#588) * all: bump ent and atlas to latest version (ent#596) * all: bump ent and atlas to latest version * chore: update test due to msgpack upgrade * entgql: add annotation Deprecated for deprecated field (ent#595) * entgql: support SkipMutationCreateInput (and update) on entity (ent#598) * entgql/internal/examples: fix template rendering for pulid example (ent#599) * entgql: fixed zero value on `first`/`last` when receive `null` input (ent#601) * entgql: use dynamic Value/GetValue method name in pagination with edge order fields (ent#603) Updates to use the `ValueName` method to get the name of the dynamic `Value`/`GetValue` method name for a type instead of using the hard-coded name `Value` in the `pagination.tmpl` file. * go: use go-viper/mapstructure/v2 over archived mitchellh/mapstructure (ent#606) * entgql/templates: ability to add extra fields and methods to mutation inputs (ent#608) * ability to add additonal fields to mutation input * Update mutation_input.tmpl removed the model keyword * chore: bump go to 1.23.4 and gqlgen to v0.17.51 (ent#607) * chore: bump go to 1.23.4 and gqlgen to v0.17.51 gqlgen v0.17.52 breaks field collection see 99designs/gqlgen@f81239e * chore: bump golangci and go version * entgql: upgrade to 99designs/gqlgen@v0.17.62 and vektah/gqlparser/v2@v2.5.21 (ent#609) * Update github.com/99designs/gqlgen@v0.17.61 and github.com/vektah/gqlparser/v2@v2.5.21 Signed-off-by: Steve Coffman <steve@khanacademy.org> * Re-generate Signed-off-by: Steve Coffman <steve@khanacademy.org> * Re-generate with correct protobuf versions Signed-off-by: Steve Coffman <steve@khanacademy.org> * Try again with protoc v3.19.4 Signed-off-by: Steve Coffman <steve@khanacademy.org> * minor tweak to go.mod and avoid pager getting stuck Signed-off-by: Steve Coffman <steve@khanacademy.org> * Update gqlgen to v0.17.62 Signed-off-by: Steve Coffman <steve@khanacademy.org> * regenerate? Signed-off-by: Steve Coffman <steve@khanacademy.org> * Minor tweak Signed-off-by: Steve Coffman <steve@khanacademy.org> * re-re-generate Signed-off-by: Steve Coffman <steve@khanacademy.org> * Add tools.go and run go mod tidy Signed-off-by: Steve Coffman <steve@khanacademy.org> * Generate using nektos/act -j generate Signed-off-by: Steve Coffman <steve@khanacademy.org> * Go generate again Signed-off-by: Steve Coffman <steve@khanacademy.org> * Generate using nektos/act -j generate Signed-off-by: Steve Coffman <steve@khanacademy.org> * go clean --modcache and then go mod tidy Signed-off-by: Steve Coffman <steve@khanacademy.org> --------- Signed-off-by: Steve Coffman <steve@khanacademy.org> * entgql: bump gqlgen version (ent#610) * fix: regenerate resolvers on codegen regeneration is required so that new ent fields and schemas are included * chore: bump gqlgen to v0.17.63 and regenerate code * entgql: support global id feature from ent (ent#611) * entgql: bump entgo and update template for receiver logic (ent#617) * entgql: bump entgo and update template for receiver logic * entgql: codegen * entoas: codegen * entproto: codegen * schemast: codegen * .github/workflows: update ci.yml workflow * entgql: bump gqlgen to latest version (ent#618) * entgql: add the CollectedFor annotation (ent#623) * fix: remove duplicate graphql import in generated files (ent#629) * entgql: prevent panic in case of a missing operation context (ent#630) * entgql: expose TableName for sql/global is feature (ent#632) * entgql: support collecting multiple ent fields for GraphQL field (ent#633) * entgql: replace golang.org/x/exp/slices import with standard slices package (ent#634) * entgql: fix relay connection eager-load on union/interface fragments (ent#635) Walk nested connection selections from the connection field with the current type condition instead of from the resolver field context with nil satisfies, which merged inline fragments and caused wrong eager loads. * entgql: schema-qualify M2M join table in totalCount loader (ent#636) * entgql: schema-qualify M2M join table in totalCount loader The gql_collection.go totalCount loader for M2M edges builds the join table via `sql.Table(...)` but never calls `joinT.Schema(...)`. With the `sql/schemaconfig` feature enabled, this emits an unqualified join table in the generated SQL while the rest of the query is correctly schema- qualified, producing `relation does not exist` errors at runtime. Hook the same `dialect/sql/query/eagerloading/join/*` template extension point that ent core's query.tmpl uses for the loader path, so the join table picks up its schema from `schemaConfig`. No-op when the feature is disabled (verified: all 6 integration tests regenerate byte-identically). Co-authored-by: Isaac * entgql: add codegen test for M2M totalCount schema qualification Add a test (entgql/template_test.go) that renders the collection template with and without the sql/schemaconfig feature and asserts the M2M totalCount join table is schema-qualified only when the feature is enabled. Covers the fix from the preceding commit at the codegen level and runs in CI against SQLite. * entgql: add multischema project with MySQL test for M2M totalCount Add internal/multischema, a minimal Group<->User M2M project with the sql/schemaconfig feature, plus a MySQL-backed functional test that places the join table in a separate schema and drives totalCount through the gqlgen + ent runtime. ent omits schema qualifiers for SQLite (see (*sql.Builder).writeSchema), so the schema-qualified join is only observable on a schema-aware database; the test skips when MySQL is unreachable. Add a mysql8 service to the CI test job (mirroring ent's integration CI) so the test runs instead of skipping, and the go-sql-driver/mysql dependency it requires. Co-authored-by: Isaac * entgql: rename multischema project to todoschema, drop MySQL test (ent#637) --------- Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: Steve Coffman <steve@khanacademy.org> Co-authored-by: Ariel Mashraki <7413593+a8m@users.noreply.github.com> Co-authored-by: jamslinger <80337165+jamslinger@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Zxilly <zxilly@outlook.com> Co-authored-by: Giau. Tran Minh <giau.tmg@gmail.com> Co-authored-by: Rotem Tamir <rotemtamir@gmail.com> Co-authored-by: Amr Tamimi <amrnt@users.noreply.github.com> Co-authored-by: Tantatorn Suksangwarn <timefear007@gmail.com> Co-authored-by: Giau. Tran Minh <12751435+giautm@users.noreply.github.com> Co-authored-by: A B <bartke@users.noreply.github.com> Co-authored-by: Henry Woody <github@henrywoody.com> Co-authored-by: Ronen Lubin <63970571+ronenlu@users.noreply.github.com> Co-authored-by: ASAKURA Kazuki <32762324+Arthur1@users.noreply.github.com> Co-authored-by: Tran Minh Luan <tranminhluan1206@gmail.com> Co-authored-by: Jeffrey Stiles <jbstiles@gmail.com> Co-authored-by: Kai Dinghofer <10863868+kdevo@users.noreply.github.com> Co-authored-by: Henry Woody <git@henrywoody.com> Co-authored-by: Justin Cummins <sul3n3t@gmail.com> Co-authored-by: Aman Bansal <khanakia@gmail.com> Co-authored-by: Michael Caulley <me@mikecaulley.com> Co-authored-by: Steve Coffman <StevenACoffman@users.noreply.github.com> Co-authored-by: Michael Caulley <michael.caulley@databricks.com> Co-authored-by: Jannik Clausen <12862103+masseelch@users.noreply.github.com> Co-authored-by: Noam Cattan <62568565+noamcattan@users.noreply.github.com> Co-authored-by: Chinh Nguyen <monkeynhucci@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
The gql_collection.go totalCount loader for M2M edges builds the join table via
sql.Table(...)but never callsjoinT.Schema(...). With thesql/schemaconfigfeature enabled, this emits an unqualified join table in the generated SQL while the rest of the query is correctly schema- qualified, producingrelation does not existerrors at runtime.Hook the same
dialect/sql/query/eagerloading/join/*template extension point that ent core's query.tmpl uses for the loader path, so the join table picks up its schema fromschemaConfig. No-op when the feature is disabled (verified: all 6 integration tests regenerate byte-identically).