Skip to content

[Phase 3b] MSSQL JSON - return json as string on read + OpenAPI/GraphQL tests - #3738

Open
souvikghosh04 wants to merge 4 commits into
mainfrom
Usr/sogh/mssql-json-phase3b
Open

[Phase 3b] MSSQL JSON - return json as string on read + OpenAPI/GraphQL tests#3738
souvikghosh04 wants to merge 4 commits into
mainfrom
Usr/sogh/mssql-json-phase3b

Conversation

@souvikghosh04

@souvikghosh04 souvikghosh04 commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Why

Part of MSSQL native JSON support (#2768). Started as Phase 3b schema-discovery tests, but review (thanks @aaronburtle) surfaced a real product inconsistency that this PR now also fixes.

The problem: #2768 requires a JSON column to be treated as a normal string for input and output. But the MSSQL read path (FOR JSON PATH) was inlining a native json column as a nested JSON object. Consequences:

  • REST returned "metadata": {"role":"admin"} (object) instead of "metadata": "{\"role\":\"admin\"}" (string).
  • A GraphQL read of the String-typed field threw a GraphQLMapping error — the String leaf resolver calls JsonElement.GetString(), which fails on an object. So schema introspection could pass while profile_by_pk(id:1){ metadata } failed at runtime.
  • OpenAPI/GraphQL advertised string, contradicting the object runtime — generated clients would mis-model the field.

What

Engine fix (MsSqlQueryBuilder): the read path now casts a native json column (SqlDbType.Json) to NVARCHAR(MAX) in WrappedColumns, so FOR JSON PATH emits it as an escaped JSON string rather than inlining it as an object. This is the single choke point for REST and GraphQL reads. Regular nvarchar columns are untouched. Mutations already return json as a string via the tabular OUTPUT clause, so no change was needed there.

Tests:

Layer Test Asserts
OpenAPI JsonTypeSchemaTests metadata is type: string with no format in the response and both request-body schemas (Profile_NoAutoPK for POST, Profile_NoPK for PUT/PATCH)
GraphQL introspection MsSqlGraphQLJsonSchemaTests Profile.metadata is the built-in String scalar (no custom JSON scalar)
GraphQL read (new) MsSqlGraphQLJsonSchemaTests profile_by_pk(id:1){ metadata } returns the payload as a JSON string — guards against introspection passing while a real read throws
REST MsSqlRestJsonTypesTests (updated) flipped back to the string contract: metadata is returned as a JSON string (ParseMetadata/GetJsonTypeList assert JsonValueKind.String)

Note: DAB's OpenAPI documentor does not emit Nullable on the property schema for any column type, so the schema tests assert type: string + no format (not nullability).

Intentionally omitted

  • MCP describe_entities (T010): it projects only the config field name/description, not DB column data types, so there is no JSON-specific behavior to assert.

Notes

  • This PR now includes a product (engine) change, not tests only.
  • Requires SQL Server 2025 / Azure SQL (native json); CI already runs SQL 2025.
  • Cannot be run locally (no SQL 2025 here) — relying on CI.

Delivery plan

Phase What Status
1 .NET 10 + SqlClient 6.x ✅ Merged (#3697/#3656)
2 JSON type + error mapping (engine) ✅ Merged (#3691)
3 Test fixture + REST CRUD tests ✅ Merged (#3720)
3b json-as-string read fix + OpenAPI/GraphQL discovery & read tests (this PR) 🚧
4 Error/filter edge cases + regression + polish Next

… 3b)

Proves the 'JSON is treated as a normal string' contract at the schema-discovery layer, complementing the merged REST round-trip tests (#3720).

- JsonTypeSchemaTests (T008): the profiles.metadata json column is exposed in the OpenAPI document as type:string, nullable, with no bespoke format.

- MsSqlGraphQLJsonSchemaTests (T009): GraphQL introspection reports Profile.metadata as the built-in nullable String scalar (no custom JSON scalar).

MCP describe_entities (T010) is intentionally omitted: describe_entities projects only config field name/description, not DB column data types, so there is no JSON-specific behavior to assert there.
@souvikghosh04 souvikghosh04 self-assigned this Jul 28, 2026
@souvikghosh04 souvikghosh04 added this to the July 2026 milestone Jul 28, 2026
@souvikghosh04 souvikghosh04 moved this from Todo to Review In Progress in Data API builder Jul 28, 2026
@souvikghosh04
souvikghosh04 marked this pull request as ready for review July 28, 2026 08:07
Copilot AI review requested due to automatic review settings July 28, 2026 08:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds schema-discovery test coverage for SQL Server 2025 native json columns to ensure DAB continues to expose them exactly like normal nullable string fields at the OpenAPI and GraphQL layers (no bespoke JSON scalar/format), aligning with the Phase 3b goals.

Changes:

  • Adds an OpenAPI component-schema assertion that profiles.metadata is type: string, nullable: true, with no format.
  • Adds a GraphQL introspection assertion that Profile.metadata is the built-in nullable String scalar (no custom JSON scalar).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/Service.Tests/SqlTests/GraphQLQueryTests/MsSqlGraphQLJsonSchemaTests.cs New GraphQL introspection test validating json columns map to built-in nullable String.
src/Service.Tests/OpenApiDocumentor/JsonTypeSchemaTests.cs New OpenAPI generation test validating json columns are described as nullable string with no format.

@souvikghosh04 souvikghosh04 linked an issue Jul 28, 2026 that may be closed by this pull request
2 tasks
…ocumentor)

CI failure: JsonColumn Nullable assertion failed. DAB's OpenApiDocumentor builds each column property schema with only Type/Format/Description/Items and never sets Nullable for any column (nullability is expressed via request-body required lists, not the property schema). The assertion was wrong and not JSON-specific. Keep the meaningful 'nothing special' assertions: type==string and no format. Renamed the test to JsonColumn_IsDescribedAsStringWithoutFormat.
Comment thread src/Service.Tests/OpenApiDocumentor/JsonTypeSchemaTests.cs Outdated
Comment thread src/Service.Tests/OpenApiDocumentor/JsonTypeSchemaTests.cs Outdated
…review

Per #2768, a JSON column must be treated as a string for input AND output. But the MSSQL read path (FOR JSON PATH) was inlining a native json column as a nested JSON object, so REST returned an object and a GraphQL read of the String-typed field threw a GraphQLMapping error (String leaf resolver calls JsonElement.GetString(), which fails on an object).

Engine: MsSqlQueryBuilder.WrappedColumns now casts a native json column (SqlDbType.Json) to NVARCHAR(MAX) so FOR JSON PATH emits it as an escaped JSON string. Mutations already return json as a string via the tabular OUTPUT clause, so no change was needed there. Regular nvarchar columns are untouched.

Tests (addresses aaronburtle review on #3738):

- Flip MsSqlRestJsonTypesTests back to the string contract (ParseMetadata/GetJsonTypeList assert JsonValueKind.String).

- Add GraphQL end-to-end read (profile_by_pk metadata) asserting the payload returns as a JSON string - guards against introspection passing while a real read throws.

- OpenAPI test now asserts metadata is type:string with no format in the response AND the POST/PUT-PATCH request-body components (Profile_NoAutoPK/Profile_NoPK).
@souvikghosh04 souvikghosh04 changed the title [Phase 3b] MSSQL JSON - OpenAPI + GraphQL schema-discovery tests [Phase 3b] MSSQL JSON - return json as string on read + OpenAPI/GraphQL tests Jul 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Review In Progress

Development

Successfully merging this pull request may close these issues.

[Phase 3b] MSSQL JSON - OpenAPI + GraphQL schema-discovery tests

4 participants