Add read-only support for PostgreSQL array columns#3402
Add read-only support for PostgreSQL array columns#3402bilby91 wants to merge 8 commits intoAzure:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Adds read-only support for PostgreSQL array columns in DAB so schema introspection and runtime initialization no longer fail when encountering int[], text[], boolean[], bigint[], etc. The change threads array-awareness through metadata, GraphQL schema generation, and the EDM model while keeping arrays excluded from mutation inputs.
Changes:
- Detect PostgreSQL array columns during metadata introspection, resolve array element CLR types, and mark array columns read-only.
- Expose array columns as GraphQL list types and represent them as EDM collection properties.
- Add/extend unit + PostgreSQL e2e test coverage plus schema/config updates for a new
array_type_tabletest entity.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Config/DatabasePrimitives/DatabaseObject.cs | Extends ColumnDefinition with IsArrayType/ElementSystemType to carry array metadata. |
| src/Core/Services/MetadataProviders/SqlMetadataProvider.cs | Detects array-typed columns from provider schema and marks them read-only. |
| src/Core/Services/MetadataProviders/PostgreSqlMetadataProvider.cs | Resolves PostgreSQL array element types via information_schema (udt_name) and updates ColumnDefinition. |
| src/Service.GraphQLBuilder/Sql/SchemaConverter.cs | Generates GraphQL fields as ListTypeNode for array columns and adds array-aware system type mapping. |
| src/Core/Parsers/EdmModelBuilder.cs | Emits EDM collection properties for array columns to support OData model building. |
| src/Core/Services/TypeHelper.cs | Adds fallback handling for abstract System.Array in EDM primitive type mapping. |
| src/Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs | Adds unit tests for array→GraphQL list type generation, nullability, directives, and byte[] exclusion. |
| src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLArrayTypesTests.cs | Adds PostgreSQL e2e GraphQL tests validating array values and null handling. |
| src/Service.Tests/DatabaseSchema-PostgreSql.sql | Adds array_type_table DDL + seed data for PostgreSQL integration tests. |
| src/Service.Tests/dab-config.PostgreSql.json | Adds ArrayType entity configuration (read-only permissions) for PostgreSQL test runs. |
| src/Service.Tests/UnitTests/SerializationDeserializationTests.cs | Updates serialization test expectations to account for added ColumnDefinition fields. |
src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLArrayTypesTests.cs
Outdated
Show resolved
Hide resolved
src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLArrayTypesTests.cs
Show resolved
Hide resolved
src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLArrayTypesTests.cs
Outdated
Show resolved
Hide resolved
5bb9456 to
29833c7
Compare
|
/azp run |
|
Azure Pipelines successfully started running 6 pipeline(s). |
|
@aaronburtle Thanks for approving CI. I'll take a look at the failing tests and address them. |
|
@aaronburtle I think fixes should be in place. |
|
/azp run |
|
Azure Pipelines successfully started running 6 pipeline(s). |
|
Looks like we are missing tests on the REST side of things. Should add some simple tests to validate REST works with array types, eg. |
|
The PG_SQL Integration test failures are from mismatched configs, need to add the new section to |
PostgreSQL array columns (int[], text[], boolean[], bigint[], etc.) were previously unsupported and caused initialization failures. This change adds read-only support so array columns are exposed as list types in GraphQL ([Int], [String], etc.) and as JSON arrays in REST responses. Array columns are marked read-only and excluded from mutation input types until write support is implemented. The implementation adds generic array plumbing in the shared SQL layers and PostgreSQL-specific element type resolution via information_schema udt_name mapping. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add ArrayType entity to postgresql-commands.txt so CI's config generator includes it, and skip list-type fields in InputTypeBuilder filter/orderby generation to prevent array columns from being incorrectly processed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add _json, _jsonb, _money to PostgreSQL array type mapping dictionary - Add json[], jsonb[], money[] columns to array_type_table test schema - Add REST integration tests for array type endpoints (list, by PK, nulls) - Update GraphQL array tests to cover new array column types - Update PostgreSQL snapshot to include ArrayType entity Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
I handle most of the stuff already. Need to replicate the Cosmos issue locally and get it fixed. Will update when I have that aspect ready. |
b9e3435 to
684ced5
Compare
…orderby The previous change to skip list-type fields was too broad — it excluded all list types, which broke Cosmos DB nested object array filtering (e.g., additionalAttributes, moons). Narrowed the condition to only skip scalar list types (IsListType && IsBuiltInType) so PostgreSQL array columns (int[], text[]) are still excluded while Cosmos nested arrays remain filterable. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@aaronburtle I think CI should pass now :) |
|
/azp run |
|
Azure Pipelines will not run the associated pipelines, because the pull request was updated after the run command was issued. Review the pull request again and issue a new run command. |
|
/azp run |
|
Azure Pipelines successfully started running 6 pipeline(s). |
|
Great progress on the fix @bilby91! The
The issue is that I think the fix here is to use the So in with I think that will solve the problem. Thanks again for working on this! |
The previous fix used IsListType() && IsBuiltInType() to skip PostgreSQL array columns from filter generation, but this also excluded Cosmos scalar arrays (e.g., tags: [String]) which support ARRAY_CONTAINS filtering. Added @autogenerated directive check so only SQL read-only array columns are skipped — Cosmos fields lack this directive. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@aaronburtle Thanks a lot for you help and guidance during all the PR :) I had identified the issue last night and forgot to push it. I had some issues with CosmoDb simulator crushing in my environment so I was not able to run the entire suite. I was able to confirm the relevant tests are passing. Thanks again! |
|
/azp run |
|
Azure Pipelines successfully started running 6 pipeline(s). |
|
@aaronburtle All green :) Thanks again. |
Thanks for the quick iterations, taking another pass and will need another reviewer, hopefully will get this merged soon! |
RubenCerna2079
left a comment
There was a problem hiding this comment.
So I am half-way through the PR, will try to finish it by tomorrow
| { | ||
| // Array columns are represented as EDM collection types (e.g., Collection(Edm.Int32) for int[]). | ||
| sqlMetadataProvider.TryGetExposedColumnName(entityAndDbObject.Key, column, out exposedColumnName!); | ||
| EdmPrimitiveTypeReference elementTypeRef = new(EdmCoreModel.Instance.GetPrimitiveType(type), isNullable: true); |
There was a problem hiding this comment.
Is there a reason why we want isNullable to be true?
There was a problem hiding this comment.
isNullable: true is used because PostgreSQL arrays can contain NULL elements ('{1,NULL,3}'::int[] is valid). The element type reference should reflect this.
It's also consistent with how non-PK columns are handled in the same method — line 140 uses isNullable: true for regular structural properties. Only primary keys use isNullable: false.
I verified that changing to isNullable: false doesn't cause a runtime failure — DAB's OData pipeline doesn't enforce element-level nullability in collections at serialization time. So this is about correctness of the EDM model representation rather than a breaking behavior difference.
I added a test row (id=4) with NULL elements inside arrays ('{1,NULL,3}', '{hello,NULL,world}', etc.) and two new tests that query it:
- QueryArrayColumnsWithNullElements (GraphQL)
- GetArrayTypeWithNullElementsInsideArrays (REST)
Both pass with isNullable: true and also with false, confirming the pipeline handles both.
…mment
Add test row (id=4) with NULL elements inside arrays (e.g., '{1,NULL,3}')
and two new tests (GraphQL and REST) that verify null elements within arrays
are handled correctly. Update the EdmModelBuilder block comment to document
the array column branch.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
aaronburtle
left a comment
There was a problem hiding this comment.
LGTM! Thanks again for so diligently working on this one @bilby91 <3
Summary
int[],text[],boolean[],bigint[], etc.) which previously caused initialization failures[Int],[String], etc.) and returned as JSON arrays in REST/MCP responsesChanges
Core plumbing (database-agnostic):
ColumnDefinition: newIsArrayTypeandElementSystemTypepropertiesSqlMetadataProvider: detect array types (System.Array) during schema introspectionSchemaConverter: unwrap array element types and generateListTypeNodefor GraphQL fieldsEdmModelBuilder: represent array columns asEdmCollectionTypeReferencein OData modelTypeHelper: fallback handling for unresolvedSystem.ArraytypePostgreSQL-specific:
PostgreSqlMetadataProvider: overridePopulateColumnDefinitionWithHasDefaultAndDbTypeto resolve element types frominformation_schemaudt_name(_int4→int,_text→string, etc.)Tests:
array_type_tableentityLimitations
$filter: filtering on array columns is not supported (no OData array operators)Test plan