Skip to content

Conversation

@anushakolan
Copy link
Contributor

@anushakolan anushakolan commented Oct 21, 2025

Why make this change?

This change introduces richer metadata for entity fields and keys in the Data API Builder configuration. The goal is to enable semantic metadata for documentation, client generation, and MCP tools, and to begin deprecating the legacy mappings and source.key-fields properties.

What is this change?

  • Introduces a new fields property for entities in the config schema.
  • Each field supports:
    • name: database column name (required)
    • alias: exposed name for the field (optional)
    • description: field description (optional)
    • primary-key: whether the field is a primary key (optional)
  • Updates the JSON schema to enforce that fields cannot be used with legacy mappings or source.key-fields.
  • Updates CLI commands (dab add, dab update) to support specifying field alias, description, and primary-key.
  • Updates dab validate to warn if fields are missing and MCP is enabled.
  • Updates OpenAPI, GraphQL, and MCP describe_entities responses to include field descriptions.
  • Adds auto-migration logic to convert legacy mappings and source.key-fields to the new fields format when relevant CLI flags are used.
  • Maintains backward compatibility: legacy properties are still supported, but validation enforces that fields and legacy props are not mixed.

How was this tested?

Manually tested with following queries:

  1. Update Entity with Field Mappings and Key Fields
    dotnet C:\DAB\data-api-builder\src\out\cli\net8.0\Microsoft.DataApiBuilder.dll update BookAuthor --map "BookID:book_id,AuthorID:author_id" --source.key-fields "BookID,AuthorID" --config "C:\DAB\data-api-builder\src\Service\dab-config.json"

Validate the Configuration

dotnet C:\DAB\data-api-builder\src\out\cli\net8.0\Microsoft.DataApiBuilder.dll validate -c "C:\DAB\data-api-builder\src\Service\dab-config.json"


Update Entity Field Metadata (Primary Key)

dotnet C:\DAB\data-api-builder\src\out\cli\net8.0\Microsoft.DataApiBuilder.dll update Todo --fields.name owner_id --fields.primary-key True --config C:\DAB\data-api-builder\src\Service\dab-config.json


Update Entity Key Fields Only

dotnet C:\DAB\data-api-builder\src\out\cli\net8.0\Microsoft.DataApiBuilder.dll update BookAuthor --source.key-fields "BookID"


Sample new format

"fields": [ { "name": "id", "alias": "id", "description": "The unique identifier for a todo item", "primary-key": true }, { "name": "title", "alias": "title", "description": "The title of the todo item", "primary-key": false }, { "name": "completed", "alias": "completed", "description": "Indicates whether the todo item is completed", "primary-key": false }, { "name": "owner_id", "alias": "owner", "description": "Hello", "primary-key": true }, { "name": "position", "alias": "position", "description": "The position of the todo item in the list", "primary-key": false } ],


GraphQL Introspection Example

Query

{ __type(name: "Todo") { name description fields { name description } } }

Result
{ "data": { "__type": { "name": "Todo", "description": "Represents a todo item in the system", "fields": [ { "name": "id", "description": "The unique identifier for a todo item" }, { "name": "title", "description": "The title of the todo item" }, { "name": "completed", "description": "Indicates whether the todo item is completed" }, { "name": "owner", "description": "Hello" }, { "name": "position", "description": "The position of the todo item in the list" } ] } } }


OpenAPI Schema Example

"Todo": { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier for a todo item", "format": "" }, "title": { "type": "string", "description": "The title of the todo item", "format": "" }, "completed": { "type": "boolean", "description": "Indicates whether the todo item is completed", "format": "" }, "owner_id": { "type": "string", "description": "Hello", "format": "" }, "position": { "type": "number", "description": "The position of the todo item in the list", "format": "" } }, "description": "Represents a todo item in the system" }

@anushakolan
Copy link
Contributor Author

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 6 pipeline(s).

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR introduces a new fields section for entities as part of the Model Context Protocol (MCP) implementation. The change consolidates the legacy mappings and key-fields properties into a unified fields array that provides richer metadata (aliases, descriptions, primary key designation) for entity columns.

Key Changes

  • Added FieldMetadata class to represent field-level configuration including name, alias, description, and primary key status
  • Updated Entity constructor and configuration to include optional Fields property
  • Modified CLI commands to support field configuration through new command-line options
  • Converted legacy mappings and key-fields usage to the new fields structure in update operations

Reviewed Changes

Copilot reviewed 48 out of 48 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/Config/ObjectModel/FieldMetadata.cs New class defining field metadata structure
src/Config/ObjectModel/Entity.cs Added Fields property to Entity record
src/Cli/ConfigGenerator.cs Implemented field validation, conversion from legacy properties, and MCP-related warnings
src/Cli/Commands/EntityOptions.cs Added CLI options for field configuration
src/Cli/Commands/AddOptions.cs Updated constructor to accept field-related parameters
src/Cli/Commands/UpdateOptions.cs Updated constructor to accept field-related parameters
src/Service.GraphQLBuilder/Sql/SchemaConverter.cs Updated to use Fields instead of Mappings for aliases and descriptions
src/Core/Services/OpenAPI/OpenApiDocumentor.cs Enhanced to include field descriptions from Fields metadata
src/Core/Services/MetadataProviders/SqlMetadataProvider.cs Updated GraphQL reserved name checking to use Fields; removed unused helper method
src/Core/Services/MetadataProviders/MsSqlMetadataProvider.cs Added Fields: null to linking entity creation
schemas/dab.draft.schema.json Added schema definition for fields array with mutual exclusivity constraints
Multiple test files Updated test entity instantiations to include Fields: null parameter
Multiple snapshot files Updated snapshots showing conversion of mappings/key-fields to Fields structure

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

"not": {
"anyOf": [
{ "required": ["mappings"] },
{ "properties": { "source": { "properties": { "key-fields": { } }, "required": ["key-fields"] } } }
Copy link

Copilot AI Oct 21, 2025

Choose a reason for hiding this comment

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

The JSON schema constraint to prevent fields and key-fields coexistence is incorrect. The nested structure doesn't properly check for the presence of key-fields in the source object. It should be: { \"properties\": { \"source\": { \"required\": [\"key-fields\"] } } }.

Suggested change
{ "properties": { "source": { "properties": { "key-fields": { } }, "required": ["key-fields"] } } }
{ "properties": { "source": { "required": ["key-fields"] } } }

Copilot uses AI. Check for mistakes.
@anushakolan
Copy link
Contributor Author

One pending follow up task, is to check if the given field is a valid column in the entity. Will add this check as part of a follow up PR.

@anushakolan
Copy link
Contributor Author

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 6 pipeline(s).

@anushakolan
Copy link
Contributor Author

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 6 pipeline(s).

]
Type: View
},
Fields: [
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should ensure the new fields section is well-documented. Please create a doc task for @JerryNixon

@anushakolan
Copy link
Contributor Author

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 6 pipeline(s).

@anushakolan
Copy link
Contributor Author

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 6 pipeline(s).

@anushakolan
Copy link
Contributor Author

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 6 pipeline(s).

@anushakolan
Copy link
Contributor Author

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 6 pipeline(s).

@souvikghosh04
Copy link
Contributor

/azp run

@azure-pipelines
Copy link

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.

@souvikghosh04
Copy link
Contributor

/azp run

"name": { "type": "string", "description": "Database column name." },
"alias": { "type": "string", "description": "Exposed name for the field." },
"description": { "type": "string", "description": "Field description." },
"primary-key": { "type": "boolean", "description": "Is this field a primary key?" }
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this a question for someone? I think we should change this description

Source: {
Object: s001.book,
Type: Table,
KeyFields: [
Copy link
Contributor

Choose a reason for hiding this comment

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

Is KeyFields a different name for mappings just to specify that it is a primary key? Please also mention this parameter in the PR description

Comment on lines +49 to +52
fieldsNameCollection: [],
fieldsAliasCollection: [],
fieldsDescriptionCollection: [],
fieldsPrimaryKeyCollection: []
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a reason to make these parameters empty and not null?

Copy link
Contributor

Choose a reason for hiding this comment

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

The same question applies to the other instances where this change was made.

Comment on lines +33 to +34
string? config
)
Copy link
Contributor

Choose a reason for hiding this comment

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

nit:

Suggested change
string? config
)
string? config)

else
{
fields = [];
_logger.LogWarning("Using legacy 'mappings' and 'key-fields' properties. Consider using 'fields' for new entities.");
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this warning should be in the else if (hasMappings || hasKeyFields) section

Comment on lines 1131 to 1200
// Resolve PKs from fields first
List<string>? pkFields = entity.Fields?
.Where(f => f.PrimaryKey)
.Select(f => f.Name)
.ToList();

// Fallback to key-fields from config
if (pkFields == null || pkFields.Count == 0)
{
pkFields = entity.Source.KeyFields?.ToList();
}

// If still empty, fallback to DB schema PKs
if (pkFields == null || pkFields.Count == 0)
{
DataTable dataTable = await GetTableWithSchemaFromDataSetAsync(
entityName,
GetSchemaName(entityName),
GetDatabaseObjectName(entityName));

pkFields = dataTable.PrimaryKey.Select(pk => pk.ColumnName).ToList();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I see that this code is the same as the one above. Couldn't we make a helper function out of it in order to not have repeated code?

@anushakolan anushakolan force-pushed the dev/anushakolan/mcp/add-field-description branch from 0045c97 to 89dd7f3 Compare October 24, 2025 07:58
@anushakolan
Copy link
Contributor Author

/azp run

@azure-pipelines
Copy link

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.

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.

4 participants