feat: add relational/nested insert support and DataBulk node type for graphile-bulk-mutations#1142
Merged
Merged
Conversation
Adds a PostGraphile v5 plugin for bulk insert, upsert, update, and delete mutations with ON CONFLICT handling. Features: - bulkCreateX: INSERT ... VALUES with optional ON CONFLICT DO NOTHING - bulkUpsertX: INSERT ... ON CONFLICT DO UPDATE SET (per-column control) - bulkUpdateX: UPDATE ... SET ... WHERE (connection-filter conditions) - bulkDeleteX: DELETE ... WHERE (connection-filter conditions) Design decisions: - Opt-in per table via smart tags (@behavior +bulkInsert etc.) - Three-layer gating: database enable_bulk + api enable_bulk + smart tags - Configurable naming: bulk (default), pluralized, many - Auto-batch at PostgreSQL 32K parameter limit - Per-table constraint enums and column enums for ON CONFLICT - Safety guards: bulkMaxRows (1000), bulkRequireWhere (true) Closes constructive-io/constructive-planning#844
- Fix plan functions: use getRaw('input') for proper Grafast step resolution
- Fix constraint targeting: use column-based ON CONFLICT (col1, col2) instead of
constraint names, since PgResourceUnique doesn't store PG constraint names
- Fix WHERE clause builder: support both simple equality (Condition type) and
operator-based (Filter type) conditions
- Fix sql-builder: use conflictColumns instead of constraintName
- Add integration tests: 4 schema generation + 3 insert + 1 upsert + 1 update + 1 delete
- Add test seed SQL with smart tags for bulk behavior opt-in
- Align README with other graphile packages (logo, badges, examples)
- Remove debug logging
- Column-level SELECT grant safety (RETURNING <pk> + follow-up SELECT)
- Add BulkRelationalPlugin for nested insert support on bulk create/upsert - Discovers FK relations via pgRegistry.pgRelations (one-to-many) - Registers nested input types with FK columns excluded (auto-populated) - Layered execution: parent insert → child inserts with FK auto-fill - Validates ON CONFLICT cannot coexist with nested inserts - Opt-in via preset: bulkRelational: true - Fix returning field type resolution across all bulk mutation payloads - Use pgSelectFromRecords + access from grafast/\@dataplan/pg - Properly wraps raw SQL results into PgSelectStep instances - Resolves the '.get is not a function' error - Add DataBulk node type to node-type-registry - Per-operation flags: insert, upsert, update, delete - Auto-generates @behavior smart tags during blueprint provisioning - Registered in data/index.ts exports - Add test schema: orders (parent) + order_items (child with FK) - Add 4 relational insert tests (schema introspection, execution, empty arrays, FK exclusion) - All 14 tests passing
Contributor
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Extends the
graphile-bulk-mutationsplugin (from PR #1140) with two major features:1. Relational/Nested Inserts (
BulkRelationalPlugin)Supports nested
createfields on bulk insert mutations, so you can create parent + child rows in a single GraphQL mutation:How it works:
pgRegistry.pgRelations(isReferencee: true)onConflictcannot coexist with nested insertsbulkRelational: true2. Returning Field Fix
Fixed type resolution for the
returningfield across all bulk mutation payloads:pgSelectFromRecords+accessfromgrafast/@dataplan/pgto properly wrap raw SQL results intoPgSelectStepinstances3. DataBulk Node Type (
node-type-registry)New
DataBulknode type for blueprint provisioning:insert,upsert,update,delete@behavior +bulkInsert +bulkUpsertetc. smart tags during provisioningpackages/node-type-registry/src/data/data-bulk.tsFiles Changed
src/plugins/BulkRelationalPlugin.ts— relation discovery + nested input type registrationsrc/utils/relations.ts—discoverNestedRelations()utilitypackages/node-type-registry/src/data/data-bulk.ts— DataBulk node typeBulkInsertPlugin.ts— layered nested insert executionBulkTypesPlugin.ts—pgSelectFromRecordsplan for returning fieldaugmentations.ts,preset.ts,index.ts— new plugin/type exportsReview & Testing Checklist for Human
bulkCreateOrdersmutation with nestedorderItemsagainst a real database.onConflictand nested children throws an appropriate error.returning { id customerName }works correctly on all bulk mutation types (insert, upsert, update, delete), especially with column-level SELECT grants.DataBulkappears in the node type registry exports and has the correct parameter schema.orderItems: []is a no-op (no child inserts executed).Notes
mainand includes all changes from feat: add graphile-bulk-mutations plugin #1140 plus the relational/nested insert support and DataBulk node type.blueprint-types.generated.tsfile was NOT regenerated in this PR — runningpnpm run generate:typesin node-type-registry would pick up DataBulk, but the codegen has pre-existing issues with Check* types that are unrelated to this PR.Link to Devin session: https://app.devin.ai/sessions/b5701e74c8b44bbf89db370f3323acf2
Requested by: @pyramation