Skip to content

feat: @oneOf typed blueprint definitions with SuperCase node type keys#857

Merged
pyramation merged 1 commit intomainfrom
devin/1774002241-blueprint-typed-sdk
Mar 20, 2026
Merged

feat: @oneOf typed blueprint definitions with SuperCase node type keys#857
pyramation merged 1 commit intomainfrom
devin/1774002241-blueprint-typed-sdk

Conversation

@pyramation
Copy link
Contributor

Summary

Adds infrastructure for generating fully-typed GraphQL @oneOf input types for blueprint definitions, using SuperCase node type names (e.g., DataTimestamps, AuthzEntityMembership) as discriminant keys. This enables SDK autocomplete and compile-time validation for blueprint parameters.

Three layers of changes:

  1. PostGraphile plugin (graphile-settings/src/plugins/blueprint-types/): A factory that accepts NodeTypeRegistryEntry[] and generates a type hierarchy:

    • Per-node-type params inputs (e.g., DataTimestampsParams) derived from parameter_schema via JSON Schema → GraphQL conversion
    • BlueprintNodeInput @oneOf — discriminated union of all non-relation node types + shorthand: String
    • BlueprintRelationInput @oneOf — discriminated union of relation node types
    • BlueprintTableInput and BlueprintDefinitionInput wrapping types
  2. Codegen (graphql/codegen/, graphql/query/): Detects isOneOf on INPUT_OBJECT types from introspection and generates TypeScript discriminated unions instead of interfaces:

    // Generated output for @oneOf types:
    export type BlueprintNodeInput =
      | { shorthand: string }
      | { DataId: DataIdParams }
      | { DataTimestamps: DataTimestampsParams };
  3. Introspection: Adds isOneOf field to the schema introspection query and propagates it through the type registry transform pipeline.

Note: The plugin is exported but not yet wired into the production schema build — it requires a caller to query node_type_registry at build time and pass the entries to createBlueprintTypesPlugin(). This is a deliberate separation; wiring happens in a follow-up.

Review & Testing Checklist for Human

  • Verify isOneOf introspection compatibility: The introspection query now requests isOneOf on all types. Confirm your GraphQL server (PostGraphile v5 / graphql-js version) supports this field — if not, introspection queries may fail or return errors for non-__Type fields. Test by running the introspection query against a live endpoint.
  • Review as GraphQLInputType casts in plugin.ts (lines 288, 315, 340, 385-390): build.getTypeByName() returns GraphQLNamedType and we cast to GraphQLInputType. If a type name ever collides with a non-input type, this would cause a runtime error. Verify this is safe given the plugin-controlled naming (*Params, Blueprint*Input).
  • Empty params placeholder UX: Node types with no parameter_schema properties get a _: Boolean placeholder field, meaning SDK users would write { DataId: { _: true } }. Evaluate whether this is the desired DX vs. allowing empty objects.
  • Run pnpm build at repo root to confirm all packages compile cleanly with the new isOneOf additions across graphql/query, graphql/codegen, and graphile/graphile-settings.
  • End-to-end test plan: After wiring the plugin into the production preset, run codegen against a live schema and verify the generated TypeScript types show correct discriminated unions with SuperCase keys matching node_type_registry entries.

Notes

  • The BuildLike interface in json-schema-to-graphql.ts uses any for GraphQLNonNull/GraphQLList constructor params to work around graphql-js type variance. This is intentional — the alternative is duplicating graphql-js's internal generic constraints.
  • isOneOf is added to the ResolvedType interface in both graphql/query and graphql/codegen packages (they share the same interface shape but are separate files).

Link to Devin session: https://app.devin.ai/sessions/5d550def7a314c97854ec12fa09dd4ca
Requested by: @pyramation

- PostGraphile plugin (blueprint-types): reads node_type_registry entries and
  generates @OneOf typed GraphQL input types using SuperCase names as
  discriminant keys (BlueprintNodeInput, BlueprintRelationInput, etc.)
- JSON Schema to GraphQL converter: translates parameter_schema from
  node_type_registry into typed GraphQL input fields
- Codegen: detects isOneOf on INPUT_OBJECT types and generates TypeScript
  discriminated union types instead of interfaces
- Introspection: adds isOneOf field to schema introspection query
- Tests: 12 plugin unit tests + 7 codegen tests (including @OneOf snapshot)
@devin-ai-integration
Copy link
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

devin-ai-integration bot pushed a commit that referenced this pull request Mar 20, 2026
Query node_type_registry at schema build time and pass entries to
BlueprintTypesPreset so @OneOf typed blueprint input types with
SuperCase node type names are generated in the live GraphQL schema.

Changes:
- Add fetchNodeTypeRegistry() utility that queries metaschema_public.node_type_registry
  (gracefully returns [] if table doesn't exist yet)
- Wire BlueprintTypesPreset into production server (graphile.ts)
- Wire BlueprintTypesPreset into build-schema (codegen path)
- Wire BlueprintTypesPreset into query executor
- Wire BlueprintTypesPreset into explorer server

Builds on PR #857 which added the plugin, codegen support, and tests.
@pyramation pyramation merged commit def809b into main Mar 20, 2026
44 checks passed
@pyramation pyramation deleted the devin/1774002241-blueprint-typed-sdk branch March 20, 2026 12:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant