diff --git a/config-generators/config-generator.ps1 b/config-generators/config-generator.ps1 index 5b7cfbe9ee..a338a35181 100644 --- a/config-generators/config-generator.ps1 +++ b/config-generators/config-generator.ps1 @@ -70,4 +70,18 @@ foreach($databaseType in $databaseTypes){ $commandToExecute = "dotnet " + $pathToDabDLL + " " + $command; Invoke-Expression $commandToExecute; } + + # Post-process MsSql and DwSql configs to fix stored procedure GraphQL operations + # The CLI currently ignores --graphql.operation parameter for stored procedures, + # defaulting them to 'mutation'. We manually fix specific procedures that should be 'query'. + if($databaseType -eq "mssql" -or $databaseType -eq "dwsql"){ + $configContent = Get-Content $configFile -Raw | ConvertFrom-Json; + if($configContent.entities.GetBooks){ + $configContent.entities.GetBooks.graphql.operation = "query"; + } + if($configContent.entities.GetPublisher){ + $configContent.entities.GetPublisher.graphql.operation = "query"; + } + $configContent | ConvertTo-Json -Depth 100 | Set-Content $configFile -Encoding UTF8; + } } diff --git a/config-generators/config-generator.sh b/config-generators/config-generator.sh index 30e0dd8a66..4f0c87db62 100755 --- a/config-generators/config-generator.sh +++ b/config-generators/config-generator.sh @@ -73,4 +73,22 @@ do eval $command; done <$commandFileNameWithPath; + # Post-process MsSql and DwSql config files to set stored procedures as query operations + if [[ $databaseType == "mssql" || $databaseType == "dwsql" ]]; then + # Use jq to modify the operation field for GetBooks and GetPublisher + if command -v jq &> /dev/null; then + tmp_file="${configFile}.tmp" + jq ' + if .entities.GetBooks then + .entities.GetBooks.graphql.operation = "query" + else . end | + if .entities.GetPublisher then + .entities.GetPublisher.graphql.operation = "query" + else . end + ' "$configFile" > "$tmp_file" && mv "$tmp_file" "$configFile" + else + echo "Warning: jq not found. Skipping stored procedure operation post-processing." + fi + fi + done diff --git a/config-generators/dwsql-commands.txt b/config-generators/dwsql-commands.txt index df4940ae59..aef7f58682 100644 --- a/config-generators/dwsql-commands.txt +++ b/config-generators/dwsql-commands.txt @@ -27,7 +27,7 @@ add Journal --config "dab-config.DwSql.json" --source "journals" --rest true --g add ArtOfWar --config "dab-config.DwSql.json" --source "aow" --rest true --graphql false --permissions "anonymous:*" --source.key-fields "NoteNum" add stocks_view_selected --config "dab-config.DwSql.json" --source stocks_view_selected --source.type "view" --source.key-fields "categoryid,pieceid" --permissions "anonymous:*" --rest true --graphql true add GetBook --config "dab-config.DwSql.json" --source "get_book_by_id" --source.type "stored-procedure" --permissions "anonymous:execute" --rest true --graphql false -add GetBooks --config "dab-config.DwSql.json" --source "get_books" --source.type "stored-procedure" --permissions "anonymous:execute" --rest true --graphql true +add GetBooks --config "dab-config.DwSql.json" --source "get_books" --source.type "stored-procedure" --permissions "anonymous:execute" --rest true --graphql true --graphql.operation "query" add GetPublisher --config "dab-config.DwSql.json" --source "get_publisher_by_id" --source.type "stored-procedure" --permissions "anonymous:execute" --rest true --graphql true --graphql.operation "query" add GetAuthorsHistoryByFirstName --config "dab-config.DwSql.json" --source "get_authors_history_by_first_name" --source.type "stored-procedure" --source.params "firstName:Aaron" --permissions "anonymous:execute" --rest true --graphql SearchAuthorByFirstName add CountBooks --config "dab-config.DwSql.json" --source "count_books" --source.type "stored-procedure" --permissions "anonymous:execute" --rest true --graphql true @@ -152,8 +152,8 @@ update InsertBook --config "dab-config.DwSql.json" --permissions "authenticated: update DeleteLastInsertedBook --config "dab-config.DwSql.json" --permissions "authenticated:execute" update UpdateBookTitle --config "dab-config.DwSql.json" --permissions "authenticated:execute" update InsertAndDisplayAllBooksUnderGivenPublisher --config "dab-config.DwSql.json" --permissions "authenticated:execute" -update GetPublisher --config "dab-config.DwSql.json" --permissions "authenticated:execute" -update GetBooks --config "dab-config.DwSql.json" --permissions "authenticated:execute" --graphql.operation "Query" --rest.methods "Get" +update GetPublisher --config "dab-config.DwSql.json" --permissions "authenticated:execute" --graphql.operation "query" +update GetBooks --config "dab-config.DwSql.json" --permissions "authenticated:execute" --graphql.operation "query" --rest.methods "Get" update GetBook --config "dab-config.DwSql.json" --permissions "authenticated:execute" --rest.methods "Get" update CountBooks --config "dab-config.DwSql.json" --permissions "authenticated:execute" update Sales --config "dab-config.DwSql.json" --permissions "authenticated:*" diff --git a/config-generators/mssql-commands.txt b/config-generators/mssql-commands.txt index cecc6b522c..eb39634916 100644 --- a/config-generators/mssql-commands.txt +++ b/config-generators/mssql-commands.txt @@ -41,7 +41,7 @@ add User_AutogenRelationshipColumn --config "dab-config.MsSql.json" --source "us add User_AutogenToNonAutogenRelationshipColumn --config "dab-config.MsSql.json" --source "users" --permissions "anonymous:*" --rest true --graphql true add User_RepeatedReferencingColumnToOneEntity --config "dab-config.MsSql.json" --source "users" --permissions "anonymous:*" --rest true --graphql true add UserProfile_RepeatedReferencingColumnToTwoEntities --config "dab-config.MsSql.json" --source "user_profiles" --permissions "anonymous:*" --rest true --graphql true -add GetBooks --config "dab-config.MsSql.json" --source "get_books" --source.type "stored-procedure" --permissions "anonymous:execute" --rest true --graphql true +add GetBooks --config "dab-config.MsSql.json" --source "get_books" --source.type "stored-procedure" --permissions "anonymous:execute" --rest true --graphql true --graphql.operation "query" add GetBook --config "dab-config.MsSql.json" --source "get_book_by_id" --source.type "stored-procedure" --permissions "anonymous:execute" --rest true --graphql false add GetPublisher --config "dab-config.MsSql.json" --source "get_publisher_by_id" --source.type "stored-procedure" --permissions "anonymous:execute" --rest true --graphql true --graphql.operation "query" add InsertBook --config "dab-config.MsSql.json" --source "insert_book" --source.type "stored-procedure" --source.params "title:randomX,publisher_id:1234" --permissions "anonymous:execute" --rest true --graphql true @@ -176,8 +176,8 @@ update User_RepeatedReferencingColumnToOneEntity --config "dab-config.MsSql.json update UserProfile_RepeatedReferencingColumnToTwoEntities --config "dab-config.MsSql.json" --relationship book --target.entity Book --cardinality one --relationship.fields "userid:id" update UserProfile_RepeatedReferencingColumnToTwoEntities --config "dab-config.MsSql.json" --relationship publisher --target.entity Publisher --cardinality one --relationship.fields "userid:id" update GetBook --config "dab-config.MsSql.json" --permissions "authenticated:execute" --rest.methods "Get" -update GetPublisher --config "dab-config.MsSql.json" --permissions "authenticated:execute" -update GetBooks --config "dab-config.MsSql.json" --permissions "authenticated:execute" --graphql.operation "Query" --rest.methods "Get" +update GetPublisher --config "dab-config.MsSql.json" --permissions "authenticated:execute" --graphql.operation "query" +update GetBooks --config "dab-config.MsSql.json" --permissions "authenticated:execute" --graphql.operation "query" --rest.methods "Get" update InsertBook --config "dab-config.MsSql.json" --permissions "authenticated:execute" update CountBooks --config "dab-config.MsSql.json" --permissions "authenticated:execute" update DeleteLastInsertedBook --config "dab-config.MsSql.json" --permissions "authenticated:execute" diff --git a/schemas/dab.draft.schema.json b/schemas/dab.draft.schema.json index 80cfd953ad..493de4ef74 100644 --- a/schemas/dab.draft.schema.json +++ b/schemas/dab.draft.schema.json @@ -747,7 +747,7 @@ "properties": { "type": { "type": "string", - "enum": ["table", "view", "stored-procedure"], + "enum": [ "table", "view", "stored-procedure" ], "description": "Database object type" }, "object": { @@ -774,12 +774,24 @@ "description": "Array of parameter objects with metadata", "items": { "type": "object", - "required": ["name"], + "required": [ "name" ], "properties": { - "name": { "type": "string", "description": "Parameter name" }, - "required": { "type": "boolean", "description": "Is parameter required" }, - "default": { "type": ["string", "number", "boolean", "null"], "description": "Default value" }, - "description": { "type": "string", "description": "Parameter description. Since descriptions for multiple parameters are provided as a comma-separated string, individual parameter descriptions must not contain a comma (',')." } + "name": { + "type": "string", + "description": "Parameter name" + }, + "required": { + "type": "boolean", + "description": "Is parameter required" + }, + "default": { + "type": [ "string", "number", "boolean", "null" ], + "description": "Default value" + }, + "description": { + "type": "string", + "description": "Parameter description. Since descriptions for multiple parameters are provided as a comma-separated string, individual parameter descriptions must not contain a comma (',')." + } } } } @@ -793,7 +805,7 @@ "description": "List of fields to be used as primary keys. Mandatory field for views when generated through the CLI." } }, - "required": ["type", "object"] + "required": [ "type", "object" ] } ] }, @@ -803,12 +815,24 @@ "items": { "type": "object", "properties": { - "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": "Indicates whether this field is a primary key." } + "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": "Indicates whether this field is a primary key." + } }, - "required": ["name"] + "required": [ "name" ] }, "uniqueItems": true }, @@ -828,7 +852,7 @@ "type": "array", "items": { "type": "string", - "enum": ["get", "post", "put", "patch", "delete"] + "enum": [ "get", "post", "put", "patch", "delete" ] } }, "enabled": { @@ -839,13 +863,13 @@ }, "anyOf": [ { - "required": ["path"] + "required": [ "path" ] }, { - "required": ["methods"] + "required": [ "methods" ] }, { - "required": ["enabled"] + "required": [ "enabled" ] } ] } @@ -865,7 +889,7 @@ }, "operation": { "type": "string", - "enum": ["mutation", "query"] + "enum": [ "mutation", "query" ] }, "enabled": { "type": "boolean", @@ -875,18 +899,43 @@ }, "anyOf": [ { - "required": ["type"] + "required": [ "type" ] }, { - "required": ["operation"] + "required": [ "operation" ] }, { - "required": ["enabled"] + "required": [ "enabled" ] } ] } ] }, + "mcp": { + "oneOf": [ + { + "type": "boolean", + "description": "Enable/disable DML tools. When true, all DML tools are enabled. When false, all DML tools are disabled. For stored procedures only: true also enables custom-tool as false by default." + }, + { + "type": "object", + "description": "Granular MCP configuration. For stored procedures: can specify both custom-tool and dml-tools. For tables/views: only dml-tools is allowed.", + "additionalProperties": false, + "properties": { + "custom-tool": { + "type": "boolean", + "description": "Enable/disable the custom tool. Only applicable for stored-procedure entities.", + "default": false + }, + "dml-tools": { + "type": "boolean", + "description": "Enable/disable the dml-tools.", + "default": true + } + } + } + ] + }, "permissions": { "type": "array", "description": "Permissions assigned to this entity" @@ -908,7 +957,7 @@ "properties": { "cardinality": { "type": "string", - "enum": ["one", "many"] + "enum": [ "one", "many" ] }, "target.entity": { "type": "string" @@ -942,7 +991,7 @@ } } }, - "required": ["cardinality", "target.entity"] + "required": [ "cardinality", "target.entity" ] } } }, @@ -1145,6 +1194,48 @@ ] } } + }, + { + "if": { + "properties": { + "source": { + "type": "object", + "properties": { + "type": { + "const": "stored-procedure" + } + } + } + } + }, + "then": { + "comment": "For stored procedures, both custom-tool and dml-tools are allowed in mcp" + }, + "else": { + "comment": "For tables and views, only dml-tools is allowed in mcp", + "if": { + "properties": { + "mcp": { + "type": "object" + } + } + }, + "then": { + "properties": { + "mcp": { + "type": "object", + "additionalProperties": false, + "properties": { + "dml-tools": { + "type": "boolean", + "description": "Enable/disable the dml-tools.", + "default": true + } + } + } + } + } + } } ] } diff --git a/src/Cli.Tests/AddEntityTests.cs b/src/Cli.Tests/AddEntityTests.cs index 9386916f7f..8c5d265f23 100644 --- a/src/Cli.Tests/AddEntityTests.cs +++ b/src/Cli.Tests/AddEntityTests.cs @@ -53,8 +53,9 @@ public Task AddNewEntityWhenEntitiesEmpty() fieldsNameCollection: [], fieldsAliasCollection: [], fieldsDescriptionCollection: [], - fieldsPrimaryKeyCollection: [] - ); + fieldsPrimaryKeyCollection: [], + mcpCustomToolEnabled: null, + mcpDmlToolsEnabled: null); return ExecuteVerifyTest(options); } @@ -90,8 +91,9 @@ public Task AddNewEntityWhenEntitiesNotEmpty() fieldsNameCollection: [], fieldsAliasCollection: [], fieldsDescriptionCollection: [], - fieldsPrimaryKeyCollection: [] - ); + fieldsPrimaryKeyCollection: [], + mcpCustomToolEnabled: null, + mcpDmlToolsEnabled: null); string initialConfiguration = AddPropertiesToJson(INITIAL_CONFIG, GetFirstEntityConfiguration()); @@ -130,8 +132,9 @@ public void AddDuplicateEntity() fieldsNameCollection: [], fieldsAliasCollection: [], fieldsDescriptionCollection: [], - fieldsPrimaryKeyCollection: [] - ); + fieldsPrimaryKeyCollection: [], + mcpCustomToolEnabled: null, + mcpDmlToolsEnabled: null); string initialConfiguration = AddPropertiesToJson(INITIAL_CONFIG, GetFirstEntityConfiguration()); Assert.IsTrue(RuntimeConfigLoader.TryParseConfig(initialConfiguration, out RuntimeConfig? runtimeConfig), "Loaded config"); @@ -174,8 +177,9 @@ public Task AddEntityWithAnExistingNameButWithDifferentCase() fieldsNameCollection: [], fieldsAliasCollection: [], fieldsDescriptionCollection: [], - fieldsPrimaryKeyCollection: [] - ); + fieldsPrimaryKeyCollection: [], + mcpCustomToolEnabled: null, + mcpDmlToolsEnabled: null); string initialConfiguration = AddPropertiesToJson(INITIAL_CONFIG, GetFirstEntityConfiguration()); return ExecuteVerifyTest(options, initialConfiguration); @@ -213,8 +217,9 @@ public Task AddEntityWithCachingEnabled() fieldsNameCollection: [], fieldsAliasCollection: [], fieldsDescriptionCollection: [], - fieldsPrimaryKeyCollection: [] - ); + fieldsPrimaryKeyCollection: [], + mcpCustomToolEnabled: null, + mcpDmlToolsEnabled: null); return ExecuteVerifyTest(options); } @@ -258,8 +263,9 @@ public Task AddEntityWithPolicyAndFieldProperties( fieldsNameCollection: [], fieldsAliasCollection: [], fieldsDescriptionCollection: [], - fieldsPrimaryKeyCollection: [] - ); + fieldsPrimaryKeyCollection: [], + mcpCustomToolEnabled: null, + mcpDmlToolsEnabled: null); // Create VerifySettings and add all arguments to the method as parameters VerifySettings verifySettings = new(); @@ -299,8 +305,9 @@ public Task AddNewEntityWhenEntitiesWithSourceAsStoredProcedure() fieldsNameCollection: [], fieldsAliasCollection: [], fieldsDescriptionCollection: [], - fieldsPrimaryKeyCollection: [] - ); + fieldsPrimaryKeyCollection: [], + mcpCustomToolEnabled: null, + mcpDmlToolsEnabled: null); return ExecuteVerifyTest(options); } @@ -339,8 +346,9 @@ public Task TestAddStoredProcedureWithRestMethodsAndGraphQLOperations() fieldsNameCollection: [], fieldsAliasCollection: [], fieldsDescriptionCollection: [], - fieldsPrimaryKeyCollection: [] - ); + fieldsPrimaryKeyCollection: [], + mcpCustomToolEnabled: null, + mcpDmlToolsEnabled: null); return ExecuteVerifyTest(options); } @@ -375,8 +383,9 @@ public void AddEntityWithDescriptionAndVerifyInConfig() fieldsNameCollection: [], fieldsAliasCollection: [], fieldsDescriptionCollection: [], - fieldsPrimaryKeyCollection: [] - ); + fieldsPrimaryKeyCollection: [], + mcpCustomToolEnabled: null, + mcpDmlToolsEnabled: null); string config = INITIAL_CONFIG; Assert.IsTrue(RuntimeConfigLoader.TryParseConfig(config, out RuntimeConfig? runtimeConfig), "Loaded base config."); @@ -438,8 +447,9 @@ public void TestAddNewEntityWithSourceObjectHavingValidFields( fieldsNameCollection: [], fieldsAliasCollection: [], fieldsDescriptionCollection: [], - fieldsPrimaryKeyCollection: [] - ); + fieldsPrimaryKeyCollection: [], + mcpCustomToolEnabled: null, + mcpDmlToolsEnabled: null); RuntimeConfigLoader.TryParseConfig(INITIAL_CONFIG, out RuntimeConfig? runtimeConfig); @@ -506,8 +516,9 @@ public Task TestAddNewSpWithDifferentRestAndGraphQLOptions( fieldsNameCollection: [], fieldsAliasCollection: [], fieldsDescriptionCollection: [], - fieldsPrimaryKeyCollection: [] - ); + fieldsPrimaryKeyCollection: [], + mcpCustomToolEnabled: null, + mcpDmlToolsEnabled: null); VerifySettings settings = new(); settings.UseHashedParameters(restMethods, graphQLOperation, restRoute, graphQLType); @@ -550,8 +561,9 @@ public void TestAddStoredProcedureWithConflictingRestGraphQLOptions( fieldsNameCollection: [], fieldsAliasCollection: [], fieldsDescriptionCollection: [], - fieldsPrimaryKeyCollection: [] - ); + fieldsPrimaryKeyCollection: [], + mcpCustomToolEnabled: null, + mcpDmlToolsEnabled: null); RuntimeConfigLoader.TryParseConfig(INITIAL_CONFIG, out RuntimeConfig? runtimeConfig); @@ -597,8 +609,9 @@ public void TestAddEntityPermissionWithInvalidOperation(IEnumerable perm fieldsNameCollection: [], fieldsAliasCollection: [], fieldsDescriptionCollection: [], - fieldsPrimaryKeyCollection: [] - ); + fieldsPrimaryKeyCollection: [], + mcpCustomToolEnabled: null, + mcpDmlToolsEnabled: null); RuntimeConfigLoader.TryParseConfig(INITIAL_CONFIG, out RuntimeConfig? runtimeConfig); @@ -635,3 +648,4 @@ private Task ExecuteVerifyTest(AddOptions options, string config = INITIAL_CONFI } } } + diff --git a/src/Cli.Tests/EndToEndTests.cs b/src/Cli.Tests/EndToEndTests.cs index 5dbf97ca5e..10a2abaf69 100644 --- a/src/Cli.Tests/EndToEndTests.cs +++ b/src/Cli.Tests/EndToEndTests.cs @@ -773,11 +773,11 @@ public void TestUpdateEntity() CollectionAssert.AreEqual(new string[] { "todo_id" }, relationship.LinkingSourceFields); CollectionAssert.AreEqual(new string[] { "id" }, relationship.LinkingTargetFields); - Assert.IsNotNull(entity.Fields); - Assert.AreEqual(2, entity.Fields.Count); - Assert.AreEqual(entity.Fields[0].Alias, "identity"); - Assert.AreEqual(entity.Fields[1].Alias, "Company Name"); - Assert.IsNull(entity.Mappings); + Assert.IsNotNull(entity.Mappings); + Assert.AreEqual(2, entity.Mappings.Count); + Assert.AreEqual("identity", entity.Mappings["id"]); + Assert.AreEqual("Company Name", entity.Mappings["name"]); + Assert.IsNull(entity.Fields); } /// diff --git a/src/Cli.Tests/Snapshots/EndToEndTests.TestUpdatingStoredProcedureWithRestMethods.verified.txt b/src/Cli.Tests/Snapshots/EndToEndTests.TestUpdatingStoredProcedureWithRestMethods.verified.txt index a04dc2fe36..9715b7491b 100644 --- a/src/Cli.Tests/Snapshots/EndToEndTests.TestUpdatingStoredProcedureWithRestMethods.verified.txt +++ b/src/Cli.Tests/Snapshots/EndToEndTests.TestUpdatingStoredProcedureWithRestMethods.verified.txt @@ -1,4 +1,4 @@ -{ +{ DataSource: { DatabaseType: MSSQL, Options: { @@ -73,7 +73,7 @@ Singular: MyEntity, Plural: MyEntities, Enabled: true, - Operation: Query + Operation: Mutation }, Rest: { Methods: [ diff --git a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestConversionOfSourceObject_036a859f50ce167c.verified.txt b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestConversionOfSourceObject_036a859f50ce167c.verified.txt index 260eecd0c9..a78465898d 100644 --- a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestConversionOfSourceObject_036a859f50ce167c.verified.txt +++ b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestConversionOfSourceObject_036a859f50ce167c.verified.txt @@ -27,18 +27,12 @@ MyEntity: { Source: { Object: s001.book, - Type: View + Type: View, + KeyFields: [ + col1, + col2 + ] }, - Fields: [ - { - Name: col1, - PrimaryKey: true - }, - { - Name: col2, - PrimaryKey: true - } - ], GraphQL: { Singular: MyEntity, Plural: MyEntities, diff --git a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestConversionOfSourceObject_103655d39b48d89f.verified.txt b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestConversionOfSourceObject_103655d39b48d89f.verified.txt index 80f61e17ac..d3ed32cf42 100644 --- a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestConversionOfSourceObject_103655d39b48d89f.verified.txt +++ b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestConversionOfSourceObject_103655d39b48d89f.verified.txt @@ -27,18 +27,12 @@ MyEntity: { Source: { Object: s001.book, - Type: Table + Type: Table, + KeyFields: [ + id, + name + ] }, - Fields: [ - { - Name: id, - PrimaryKey: true - }, - { - Name: name, - PrimaryKey: true - } - ], GraphQL: { Singular: MyEntity, Plural: MyEntities, diff --git a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestConversionOfSourceObject_442649c7ef2176bd.verified.txt b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestConversionOfSourceObject_442649c7ef2176bd.verified.txt index 260eecd0c9..a78465898d 100644 --- a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestConversionOfSourceObject_442649c7ef2176bd.verified.txt +++ b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestConversionOfSourceObject_442649c7ef2176bd.verified.txt @@ -27,18 +27,12 @@ MyEntity: { Source: { Object: s001.book, - Type: View + Type: View, + KeyFields: [ + col1, + col2 + ] }, - Fields: [ - { - Name: col1, - PrimaryKey: true - }, - { - Name: col2, - PrimaryKey: true - } - ], GraphQL: { Singular: MyEntity, Plural: MyEntities, diff --git a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestConversionOfSourceObject_a70c086a74142c82.verified.txt b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestConversionOfSourceObject_a70c086a74142c82.verified.txt index 21759deeed..8933a6fdbb 100644 --- a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestConversionOfSourceObject_a70c086a74142c82.verified.txt +++ b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestConversionOfSourceObject_a70c086a74142c82.verified.txt @@ -56,8 +56,15 @@ Methods: [ Post ], + Path: /api, Enabled: true }, + Mcp: { + CustomToolEnabled: false, + DmlToolEnabled: true, + UserProvidedCustomToolEnabled: true, + UserProvidedDmlToolsEnabled: true + }, Permissions: [ { Role: anonymous, diff --git a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestConversionOfSourceObject_c26902b0e44f97cd.verified.txt b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestConversionOfSourceObject_c26902b0e44f97cd.verified.txt index 2d00804545..0f766bb7c3 100644 --- a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestConversionOfSourceObject_c26902b0e44f97cd.verified.txt +++ b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestConversionOfSourceObject_c26902b0e44f97cd.verified.txt @@ -29,16 +29,6 @@ Object: s001.book, Type: stored-procedure }, - Fields: [ - { - Name: id, - PrimaryKey: true - }, - { - Name: name, - PrimaryKey: true - } - ], GraphQL: { Singular: MyEntity, Plural: MyEntities, @@ -49,8 +39,15 @@ Methods: [ Post ], + Path: /api, Enabled: true }, + Mcp: { + CustomToolEnabled: false, + DmlToolEnabled: true, + UserProvidedCustomToolEnabled: true, + UserProvidedDmlToolsEnabled: true + }, Permissions: [ { Role: anonymous, diff --git a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateEntityWithMappings.verified.txt b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateEntityWithMappings.verified.txt index 54d9077f1c..63ba7e2898 100644 --- a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateEntityWithMappings.verified.txt +++ b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateEntityWithMappings.verified.txt @@ -33,18 +33,6 @@ Object: MyTable, Type: Table }, - Fields: [ - { - Name: id, - Alias: Identity, - PrimaryKey: false - }, - { - Name: name, - Alias: Company Name, - PrimaryKey: false - } - ], GraphQL: { Singular: MyEntity, Plural: MyEntities, @@ -65,7 +53,11 @@ } ] } - ] + ], + Mappings: { + id: Identity, + name: Company Name + } } } ] diff --git a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateEntityWithSpecialCharacterInMappings.verified.txt b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateEntityWithSpecialCharacterInMappings.verified.txt index 1906f87425..8dcadec7b1 100644 --- a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateEntityWithSpecialCharacterInMappings.verified.txt +++ b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateEntityWithSpecialCharacterInMappings.verified.txt @@ -33,28 +33,6 @@ Object: MyTable, Type: Table }, - Fields: [ - { - Name: Macaroni, - Alias: Mac & Cheese, - PrimaryKey: false - }, - { - Name: region, - Alias: United State's Region, - PrimaryKey: false - }, - { - Name: russian, - Alias: русский, - PrimaryKey: false - }, - { - Name: chinese, - Alias: 中文, - PrimaryKey: false - } - ], GraphQL: { Singular: MyEntity, Plural: MyEntities, @@ -75,7 +53,13 @@ } ] } - ] + ], + Mappings: { + chinese: 中文, + Macaroni: Mac & Cheese, + region: United State's Region, + russian: русский + } } } ] diff --git a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateExistingMappings.verified.txt b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateExistingMappings.verified.txt index 56ce5b55c3..456e85ea53 100644 --- a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateExistingMappings.verified.txt +++ b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateExistingMappings.verified.txt @@ -33,23 +33,6 @@ Object: MyTable, Type: Table }, - Fields: [ - { - Name: name, - Alias: Company Name, - PrimaryKey: false - }, - { - Name: addr, - Alias: Company Address, - PrimaryKey: false - }, - { - Name: number, - Alias: Contact Details, - PrimaryKey: false - } - ], GraphQL: { Singular: MyEntity, Plural: MyEntities, @@ -70,7 +53,13 @@ } ] } - ] + ], + Mappings: { + addr: Company Address, + id: Identity, + name: Company Name, + number: Contact Details + } } } ] diff --git a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateRestAndGraphQLSettingsForStoredProcedures_5e9ddd8c7c740efd.verified.txt b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateRestAndGraphQLSettingsForStoredProcedures_5e9ddd8c7c740efd.verified.txt index 13beb6bc7c..b87e804456 100644 --- a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateRestAndGraphQLSettingsForStoredProcedures_5e9ddd8c7c740efd.verified.txt +++ b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateRestAndGraphQLSettingsForStoredProcedures_5e9ddd8c7c740efd.verified.txt @@ -33,7 +33,7 @@ Singular: book, Plural: books, Enabled: true, - Operation: Query + Operation: Mutation }, Rest: { Methods: [ diff --git a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateRestAndGraphQLSettingsForStoredProcedures_d19603117eb8b51b.verified.txt b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateRestAndGraphQLSettingsForStoredProcedures_d19603117eb8b51b.verified.txt index 13beb6bc7c..b87e804456 100644 --- a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateRestAndGraphQLSettingsForStoredProcedures_d19603117eb8b51b.verified.txt +++ b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateRestAndGraphQLSettingsForStoredProcedures_d19603117eb8b51b.verified.txt @@ -33,7 +33,7 @@ Singular: book, Plural: books, Enabled: true, - Operation: Query + Operation: Mutation }, Rest: { Methods: [ diff --git a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateRestAndGraphQLSettingsForStoredProcedures_ef8cc721c9dfc7e4.verified.txt b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateRestAndGraphQLSettingsForStoredProcedures_ef8cc721c9dfc7e4.verified.txt index 87b7a7697c..7484bb5b52 100644 --- a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateRestAndGraphQLSettingsForStoredProcedures_ef8cc721c9dfc7e4.verified.txt +++ b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateRestAndGraphQLSettingsForStoredProcedures_ef8cc721c9dfc7e4.verified.txt @@ -33,7 +33,7 @@ Singular: MyEntity, Plural: MyEntities, Enabled: true, - Operation: Query + Operation: Mutation }, Rest: { Methods: [ diff --git a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateRestAndGraphQLSettingsForStoredProcedures_f3897e2254996db0.verified.txt b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateRestAndGraphQLSettingsForStoredProcedures_f3897e2254996db0.verified.txt index 18c5f966c5..c7cb996d03 100644 --- a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateRestAndGraphQLSettingsForStoredProcedures_f3897e2254996db0.verified.txt +++ b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateRestAndGraphQLSettingsForStoredProcedures_f3897e2254996db0.verified.txt @@ -33,7 +33,7 @@ Singular: MyEntity, Plural: MyEntities, Enabled: true, - Operation: Query + Operation: Mutation }, Rest: { Methods: [ diff --git a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateRestAndGraphQLSettingsForStoredProcedures_f4cadb897fc5b0fe.verified.txt b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateRestAndGraphQLSettingsForStoredProcedures_f4cadb897fc5b0fe.verified.txt index 612a65c14a..125d622159 100644 --- a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateRestAndGraphQLSettingsForStoredProcedures_f4cadb897fc5b0fe.verified.txt +++ b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateRestAndGraphQLSettingsForStoredProcedures_f4cadb897fc5b0fe.verified.txt @@ -33,7 +33,7 @@ Singular: book, Plural: books, Enabled: true, - Operation: Query + Operation: Mutation }, Rest: { Methods: [ diff --git a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateSourceStringToDatabaseSourceObject_574e1995f787740f.verified.txt b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateSourceStringToDatabaseSourceObject_574e1995f787740f.verified.txt index 260eecd0c9..a78465898d 100644 --- a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateSourceStringToDatabaseSourceObject_574e1995f787740f.verified.txt +++ b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateSourceStringToDatabaseSourceObject_574e1995f787740f.verified.txt @@ -27,18 +27,12 @@ MyEntity: { Source: { Object: s001.book, - Type: View + Type: View, + KeyFields: [ + col1, + col2 + ] }, - Fields: [ - { - Name: col1, - PrimaryKey: true - }, - { - Name: col2, - PrimaryKey: true - } - ], GraphQL: { Singular: MyEntity, Plural: MyEntities, diff --git a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateSourceStringToDatabaseSourceObject_a13a9ca73b21f261.verified.txt b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateSourceStringToDatabaseSourceObject_a13a9ca73b21f261.verified.txt index 80f61e17ac..d3ed32cf42 100644 --- a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateSourceStringToDatabaseSourceObject_a13a9ca73b21f261.verified.txt +++ b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateSourceStringToDatabaseSourceObject_a13a9ca73b21f261.verified.txt @@ -27,18 +27,12 @@ MyEntity: { Source: { Object: s001.book, - Type: Table + Type: Table, + KeyFields: [ + id, + name + ] }, - Fields: [ - { - Name: id, - PrimaryKey: true - }, - { - Name: name, - PrimaryKey: true - } - ], GraphQL: { Singular: MyEntity, Plural: MyEntities, diff --git a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateSourceStringToDatabaseSourceObject_a5ce76c8bea25cc8.verified.txt b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateSourceStringToDatabaseSourceObject_a5ce76c8bea25cc8.verified.txt index 80f61e17ac..d3ed32cf42 100644 --- a/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateSourceStringToDatabaseSourceObject_a5ce76c8bea25cc8.verified.txt +++ b/src/Cli.Tests/Snapshots/UpdateEntityTests.TestUpdateSourceStringToDatabaseSourceObject_a5ce76c8bea25cc8.verified.txt @@ -27,18 +27,12 @@ MyEntity: { Source: { Object: s001.book, - Type: Table + Type: Table, + KeyFields: [ + id, + name + ] }, - Fields: [ - { - Name: id, - PrimaryKey: true - }, - { - Name: name, - PrimaryKey: true - } - ], GraphQL: { Singular: MyEntity, Plural: MyEntities, diff --git a/src/Cli.Tests/Snapshots/UpdateEntityTests.UpdateDatabaseSourceKeyFields.verified.txt b/src/Cli.Tests/Snapshots/UpdateEntityTests.UpdateDatabaseSourceKeyFields.verified.txt index 544a3484f9..697074cedf 100644 --- a/src/Cli.Tests/Snapshots/UpdateEntityTests.UpdateDatabaseSourceKeyFields.verified.txt +++ b/src/Cli.Tests/Snapshots/UpdateEntityTests.UpdateDatabaseSourceKeyFields.verified.txt @@ -27,18 +27,12 @@ MyEntity: { Source: { Object: s001.book, - Type: Table + Type: Table, + KeyFields: [ + col1, + col2 + ] }, - Fields: [ - { - Name: col1, - PrimaryKey: true - }, - { - Name: col2, - PrimaryKey: true - } - ], GraphQL: { Singular: MyEntity, Plural: MyEntities, diff --git a/src/Cli.Tests/UpdateEntityTests.cs b/src/Cli.Tests/UpdateEntityTests.cs index 3a106c0adc..cac06cb5aa 100644 --- a/src/Cli.Tests/UpdateEntityTests.cs +++ b/src/Cli.Tests/UpdateEntityTests.cs @@ -1033,6 +1033,7 @@ public void EnsureFailure_AddRelationshipToEntityWithDisabledGraphQL() Fields: null, Rest: new(Enabled: true), GraphQL: new("SOURCE1", "SOURCE1s"), + Mcp: null, Permissions: new[] { permissionForEntity }, Relationships: null, Mappings: null @@ -1044,6 +1045,7 @@ public void EnsureFailure_AddRelationshipToEntityWithDisabledGraphQL() Fields: null, Rest: new(Enabled: true), GraphQL: new("SOURCE2", "SOURCE2s", false), + Mcp: null, Permissions: new[] { permissionForEntity }, Relationships: null, Mappings: null @@ -1197,7 +1199,9 @@ private static UpdateOptions GenerateBaseUpdateOptions( fieldsNameCollection: null, fieldsAliasCollection: null, fieldsDescriptionCollection: null, - fieldsPrimaryKeyCollection: null + fieldsPrimaryKeyCollection: null, + mcpCustomToolEnabled: null, + mcpDmlToolsEnabled: null ); } diff --git a/src/Cli/Commands/AddOptions.cs b/src/Cli/Commands/AddOptions.cs index b7d9fbeb08..da2fcc7570 100644 --- a/src/Cli/Commands/AddOptions.cs +++ b/src/Cli/Commands/AddOptions.cs @@ -3,6 +3,7 @@ using System.IO.Abstractions; using Azure.DataApiBuilder.Config; +using Azure.DataApiBuilder.Config.ObjectModel; using Azure.DataApiBuilder.Product; using Cli.Constants; using CommandLine; @@ -43,6 +44,8 @@ public AddOptions( IEnumerable? fieldsAliasCollection, IEnumerable? fieldsDescriptionCollection, IEnumerable? fieldsPrimaryKeyCollection, + CliBool? mcpCustomToolEnabled, + CliBool? mcpDmlToolsEnabled, string? config ) : base( @@ -69,6 +72,8 @@ public AddOptions( fieldsAliasCollection, fieldsDescriptionCollection, fieldsPrimaryKeyCollection, + mcpCustomToolEnabled, + mcpDmlToolsEnabled, config ) { diff --git a/src/Cli/Commands/EntityOptions.cs b/src/Cli/Commands/EntityOptions.cs index 7f26816800..899e2031b5 100644 --- a/src/Cli/Commands/EntityOptions.cs +++ b/src/Cli/Commands/EntityOptions.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using Azure.DataApiBuilder.Config.ObjectModel; using CommandLine; namespace Cli.Commands @@ -34,6 +35,8 @@ public EntityOptions( IEnumerable? fieldsAliasCollection, IEnumerable? fieldsDescriptionCollection, IEnumerable? fieldsPrimaryKeyCollection, + CliBool? mcpCustomToolEnabled, + CliBool? mcpDmlToolsEnabled, string? config ) : base(config) @@ -61,6 +64,8 @@ public EntityOptions( FieldsAliasCollection = fieldsAliasCollection; FieldsDescriptionCollection = fieldsDescriptionCollection; FieldsPrimaryKeyCollection = fieldsPrimaryKeyCollection; + McpCustomToolEnabled = mcpCustomToolEnabled; + McpDmlToolsEnabled = mcpDmlToolsEnabled; } // Entity is required but we have made required as false to have custom error message (more user friendly), if not provided. @@ -132,5 +137,11 @@ public EntityOptions( [Option("fields.primary-key", Required = false, Separator = ',', HelpText = "Set this field as a primary key.")] public IEnumerable? FieldsPrimaryKeyCollection { get; } + + [Option("mcp.custom-tool", Required = false, HelpText = "Enable this stored procedure as a custom MCP tool. Valid values: true, false")] + public CliBool? McpCustomToolEnabled { get; } + + [Option("mcp.dml-tools", Required = false, HelpText = "Enable DML tools for this entity. Valid values: true, false")] + public CliBool? McpDmlToolsEnabled { get; } } } diff --git a/src/Cli/Commands/UpdateOptions.cs b/src/Cli/Commands/UpdateOptions.cs index fe1664c5bb..3acd935a94 100644 --- a/src/Cli/Commands/UpdateOptions.cs +++ b/src/Cli/Commands/UpdateOptions.cs @@ -3,6 +3,7 @@ using System.IO.Abstractions; using Azure.DataApiBuilder.Config; +using Azure.DataApiBuilder.Config.ObjectModel; using Azure.DataApiBuilder.Product; using Cli.Constants; using CommandLine; @@ -51,8 +52,11 @@ public UpdateOptions( IEnumerable? fieldsAliasCollection, IEnumerable? fieldsDescriptionCollection, IEnumerable? fieldsPrimaryKeyCollection, + CliBool? mcpCustomToolEnabled, + CliBool? mcpDmlToolsEnabled, string? config) - : base(entity, + : base( + entity, sourceType, sourceParameters, sourceKeyFields, @@ -75,6 +79,8 @@ public UpdateOptions( fieldsAliasCollection, fieldsDescriptionCollection, fieldsPrimaryKeyCollection, + mcpCustomToolEnabled, + mcpDmlToolsEnabled, config) { Source = source; diff --git a/src/Cli/ConfigGenerator.cs b/src/Cli/ConfigGenerator.cs index 7c35335089..f8d47c0347 100644 --- a/src/Cli/ConfigGenerator.cs +++ b/src/Cli/ConfigGenerator.cs @@ -450,12 +450,34 @@ public static bool TryAddNewEntity(AddOptions options, RuntimeConfig initialRunt EntityGraphQLOptions graphqlOptions = ConstructGraphQLTypeDetails(options.GraphQLType, graphQLOperationsForStoredProcedures); EntityCacheOptions? cacheOptions = ConstructCacheOptions(options.CacheEnabled, options.CacheTtl); + // Validate and construct MCP options + EntityMcpOptions? mcpOptions = null; + + if (options.McpCustomToolEnabled is not null and not CliBool.None) + { + if (!isStoredProcedure) + { + _logger.LogError("--mcp.custom-tool can only be configured for stored procedures."); + return false; + } + } + + // Construct MCP options if any MCP-related flags are provided + // For stored procedures: both custom-tool and dml-tools can be set + // For other entity types: only dml-tools can be set + if (options.McpCustomToolEnabled is not null and not CliBool.None || + options.McpDmlToolsEnabled is not null and not CliBool.None) + { + mcpOptions = ConstructMcpOptions(options.McpCustomToolEnabled, options.McpDmlToolsEnabled); + } + // Create new entity. Entity entity = new( Source: source, Fields: null, Rest: restOptions, GraphQL: graphqlOptions, + Mcp: mcpOptions, Permissions: permissionSettings, Relationships: null, Mappings: null, @@ -1583,20 +1605,32 @@ public static bool TryUpdateExistingEntity(UpdateOptions options, RuntimeConfig // Validations to ensure that REST methods and GraphQL operations can be configured only // for stored procedures - if (options.GraphQLOperationForStoredProcedure is not null && - !(isCurrentEntityStoredProcedure || doOptionsRepresentStoredProcedure)) + if (options.GraphQLOperationForStoredProcedure is not null && !isCurrentEntityStoredProcedure) { _logger.LogError("--graphql.operation can be configured only for stored procedures."); return false; } if ((options.RestMethodsForStoredProcedure is not null && options.RestMethodsForStoredProcedure.Any()) - && !(isCurrentEntityStoredProcedure || doOptionsRepresentStoredProcedure)) + && !isCurrentEntityStoredProcedure) { _logger.LogError("--rest.methods can be configured only for stored procedures."); return false; } + // Validate MCP custom-tool is only for stored procedures + if (options.McpCustomToolEnabled is not null and not CliBool.None) + { + bool willBeStoredProcedure = (isCurrentEntityStoredProcedure && options.SourceType is null) || + (options.SourceType is not null && IsStoredProcedure(options)); + + if (!willBeStoredProcedure) + { + _logger.LogError("--mcp.custom-tool can only be configured for stored procedures."); + return false; + } + } + if (isCurrentEntityStoredProcedure || doOptionsRepresentStoredProcedure) { if (CheckConflictingGraphQLConfigurationForStoredProcedures(options)) @@ -1614,251 +1648,174 @@ public static bool TryUpdateExistingEntity(UpdateOptions options, RuntimeConfig EntityRestOptions updatedRestDetails = ConstructUpdatedRestDetails(entity, options, initialConfig.DataSource.DatabaseType == DatabaseType.CosmosDB_NoSQL); EntityGraphQLOptions updatedGraphQLDetails = ConstructUpdatedGraphQLDetails(entity, options); - EntityPermission[]? updatedPermissions = entity!.Permissions; - Dictionary? updatedRelationships = entity.Relationships; - Dictionary? updatedMappings = entity.Mappings; - EntityActionPolicy? updatedPolicy = GetPolicyForOperation(options.PolicyRequest, options.PolicyDatabase); - EntityActionFields? updatedFields = GetFieldsForOperation(options.FieldsToInclude, options.FieldsToExclude); - EntityCacheOptions? updatedCacheOptions = ConstructCacheOptions(options.CacheEnabled, options.CacheTtl); + EntityMcpOptions? updatedMcpOptions = ConstructUpdatedMcpOptions(entity, options); - if (!updatedGraphQLDetails.Enabled) + // Add these missing variable definitions + EntityActionPolicy? policy = GetPolicyForOperation(options.PolicyRequest, options.PolicyDatabase); + EntityActionFields? field = GetFieldsForOperation(options.FieldsToInclude, options.FieldsToExclude); + + // Validate that permissions are provided when using field include/exclude + if (field is not null && (options.Permissions is null || !options.Permissions.Any())) { - _logger.LogWarning("Disabling GraphQL for this entity will restrict its usage in relationships"); + _logger.LogError("Permissions must be specified when using --fields.include or --fields.exclude options."); + return false; } - EntitySourceType? updatedSourceType = updatedSource.Type; + EntityPermission[]? updatedPermissions; if (options.Permissions is not null && options.Permissions.Any()) { - // Get the Updated Permission Settings - updatedPermissions = GetUpdatedPermissionSettings(entity, options.Permissions, updatedPolicy, updatedFields, updatedSourceType); + updatedPermissions = GetUpdatedPermissionSettings(entity, options.Permissions, policy, field, updatedSource.Type); + // Only fail if we tried to update permissions and it failed if (updatedPermissions is null) { - _logger.LogError("Failed to update permissions."); + _logger.LogError("Failed to update entity permissions."); return false; } } else { + updatedPermissions = entity.Permissions; + } - if (options.FieldsToInclude is not null && options.FieldsToInclude.Any() - || options.FieldsToExclude is not null && options.FieldsToExclude.Any()) - { - _logger.LogInformation("--permissions is mandatory with --fields.include and --fields.exclude."); - return false; - } + // Handle relationships + Dictionary? updatedRelationships = null; - if (options.PolicyRequest is not null || options.PolicyDatabase is not null) + // Only verify and update relationships if relationship options are provided + if (options.Cardinality is not null || options.TargetEntity is not null) + { + if (VerifyCanUpdateRelationship(initialConfig, options.Cardinality, options.TargetEntity)) { - _logger.LogInformation("--permissions is mandatory with --policy-request and --policy-database."); - return false; + EntityRelationship? newRelationship = CreateNewRelationshipWithUpdateOptions(options); + if (newRelationship is not null) + { + updatedRelationships = entity.Relationships is null + ? new Dictionary { { options.Relationship ?? options.TargetEntity!, newRelationship } } + : new Dictionary(entity.Relationships) { [options.Relationship ?? options.TargetEntity!] = newRelationship }; + } } - - if (updatedSourceType is EntitySourceType.StoredProcedure && - !VerifyPermissionOperationsForStoredProcedures(entity.Permissions)) + else { return false; } } - - if (options.Relationship is not null) + else { - if (!VerifyCanUpdateRelationship(initialConfig, options.Cardinality, options.TargetEntity)) - { - return false; - } - - if (updatedRelationships is null) - { - updatedRelationships = new(); - } - - EntityRelationship? new_relationship = CreateNewRelationshipWithUpdateOptions(options); - if (new_relationship is null) - { - return false; - } - - updatedRelationships[options.Relationship] = new_relationship; + updatedRelationships = entity.Relationships; } - bool hasFields = options.FieldsNameCollection != null && options.FieldsNameCollection.Count() > 0; - bool hasMappings = options.Map != null && options.Map.Any(); - bool hasKeyFields = options.SourceKeyFields != null && options.SourceKeyFields.Any(); + // Handle mappings + Dictionary? updatedMappings; - List? fields; - if (hasFields) + if (options.Map is not null && options.Map.Any()) { - if (hasMappings && hasKeyFields) - { - _logger.LogError("Entity cannot define 'fields', 'mappings', and 'key-fields' together. Please use only one."); - return false; - } - - if (hasMappings) - { - _logger.LogError("Entity cannot define both 'fields' and 'mappings'. Please use only one."); - return false; - } - - if (hasKeyFields) - { - _logger.LogError("Entity cannot define both 'fields' and 'key-fields'. Please use only one."); - return false; - } - - // Merge updated fields with existing fields - List existingFields = entity.Fields?.ToList() ?? []; - List updatedFieldsList = ComposeFieldsFromOptions(options); - Dictionary updatedFieldsDict = updatedFieldsList.ToDictionary(f => f.Name, f => f); - List mergedFields = []; - - foreach (FieldMetadata field in existingFields) - { - if (updatedFieldsDict.TryGetValue(field.Name, out FieldMetadata? updatedField)) - { - mergedFields.Add(new FieldMetadata - { - Name = updatedField.Name, - Alias = updatedField.Alias ?? field.Alias, - Description = updatedField.Description ?? field.Description, - PrimaryKey = updatedField.PrimaryKey - }); - updatedFieldsDict.Remove(field.Name); // Remove so only new fields remain - } - else - { - mergedFields.Add(field); // Keep existing field - } - } - - // Add any new fields that didn't exist before - mergedFields.AddRange(updatedFieldsDict.Values); + updatedMappings = new Dictionary(); - fields = mergedFields; - - // If user didn't mark any PK in fields, carry over existing source key-fields - if (!fields.Any(f => f.PrimaryKey) && updatedSource.KeyFields is { Length: > 0 }) + // Parse the mapping strings (format: "backendName:exposedName") + foreach (string mapping in options.Map) { - foreach (string k in updatedSource.KeyFields) + string[] parts = mapping.Split(':'); + if (parts.Length != 2) { - FieldMetadata? f = fields.FirstOrDefault(f => string.Equals(f.Name, k, StringComparison.OrdinalIgnoreCase)); - if (f is not null) - { - f.PrimaryKey = true; - } - else - { - fields.Add(new FieldMetadata { Name = k, PrimaryKey = true }); - } + _logger.LogError("Invalid mapping format: {mapping}. Expected format: 'backendName:exposedName'", mapping); + return false; } - } - // Remove legacy props if fields present - updatedSource = updatedSource with { KeyFields = null }; - updatedMappings = null; - } - else if (hasMappings || hasKeyFields) - { - // If mappings or key-fields are provided, convert them to fields and remove legacy props - // Start with existing fields - List existingFields = entity.Fields?.ToList() ?? new List(); - - // Build a dictionary for quick lookup and merging - Dictionary fieldDict = existingFields - .ToDictionary(f => f.Name, StringComparer.OrdinalIgnoreCase); + string backendName = parts[0].Trim(); + string exposedName = parts[1].Trim(); - // Parse mappings from options - if (hasMappings) - { - if (options.Map is null || !TryParseMappingDictionary(options.Map, out updatedMappings)) + if (string.IsNullOrEmpty(backendName) || string.IsNullOrEmpty(exposedName)) { - _logger.LogError("Failed to parse mappings from --map option."); + _logger.LogError("Invalid mapping: both backend name and exposed name must be non-empty."); return false; } - foreach (KeyValuePair mapping in updatedMappings) - { - if (fieldDict.TryGetValue(mapping.Key, out FieldMetadata? existing) && existing != null) - { - // Update alias, preserve PK and description - existing.Alias = mapping.Value ?? existing.Alias; - } - else - { - // New field from mapping - fieldDict[mapping.Key] = new FieldMetadata - { - Name = mapping.Key, - Alias = mapping.Value - }; - } - } + updatedMappings[backendName] = exposedName; } - // Always carry over existing PKs on the entity/update, not only when the user re-supplies --source.key-fields. - string[]? existingKeys = updatedSource.KeyFields; - if (existingKeys is not null && existingKeys.Length > 0) + // Merge with existing mappings + if (entity.Mappings is not null) { - foreach (string key in existingKeys) + foreach (KeyValuePair existingMapping in entity.Mappings) { - if (fieldDict.TryGetValue(key, out FieldMetadata? pkField) && pkField != null) - { - pkField.PrimaryKey = true; - } - else + if (!updatedMappings.ContainsKey(existingMapping.Key)) { - fieldDict[key] = new FieldMetadata { Name = key, PrimaryKey = true }; + updatedMappings[existingMapping.Key] = existingMapping.Value; } } } + } + else + { + updatedMappings = entity.Mappings; + } - // Final merged list, no duplicates - fields = fieldDict.Values.ToList(); - - // Remove legacy props only after we have safely embedded PKs into fields. - updatedSource = updatedSource with { KeyFields = null }; - updatedMappings = null; + // Handle cache options + EntityCacheOptions? updatedCacheOptions = entity.Cache; + if (!string.IsNullOrEmpty(options.CacheEnabled) || !string.IsNullOrEmpty(options.CacheTtl)) + { + updatedCacheOptions = ConstructCacheOptions(options.CacheEnabled, options.CacheTtl); } - else if (!hasFields && !hasMappings && !hasKeyFields && entity.Source.KeyFields?.Length > 0) + + // Handle fields + List? fields; + + if (options.FieldsNameCollection != null && options.FieldsNameCollection.Any()) { - // If no fields, mappings, or key-fields are provided with update command, use the entity's key-fields added using add command. - fields = entity.Source.KeyFields.Select(k => new FieldMetadata + fields = ComposeFieldsFromOptions(options); + if (!ValidateFields(fields, out string errorMessage)) { - Name = k, - PrimaryKey = true - }).ToList(); - - updatedSource = updatedSource with { KeyFields = null }; - updatedMappings = null; + _logger.LogError(errorMessage); + return false; + } } else { - fields = entity.Fields?.ToList() ?? new List(); - if (entity.Mappings is not null || entity.Source?.KeyFields is not null) + fields = entity.Fields; + } + + // If entity is being converted to stored procedure, default the REST settings + if (IsEntityBeingConvertedToStoredProcedure(entity, options)) + { + // Check if REST path is valid + if (updatedRestDetails.Path == null || string.IsNullOrEmpty(updatedRestDetails.Path) || !IsRouteValid(updatedRestDetails.Path)) { - _logger.LogWarning("Using legacy 'mappings' and 'key-fields' properties. Consider using 'fields' for new entities."); + updatedRestDetails = updatedRestDetails with { Path = RestRuntimeOptions.DEFAULT_PATH }; } } - if (!ValidateFields(fields, out string errorMessage)) + // If entity is being converted from stored procedure, clear the GraphQL operation + if (isCurrentEntityStoredProcedure && !doOptionsRepresentStoredProcedure) { - _logger.LogError(errorMessage); - return false; + updatedGraphQLDetails = updatedGraphQLDetails with { Operation = null }; } + // Check for GraphQL multiple create options + bool isMultipleCreateEnabledForGraphQL = initialConfig.IsMultipleCreateOperationEnabled(); + + // We log a warning when enabling GraphQL for SP entity without multiple-create option as it may not be supported. + if (updatedGraphQLDetails.Enabled + && updatedGraphQLDetails.Operation is GraphQLOperation.Mutation + && !isMultipleCreateEnabledForGraphQL) + { + _logger.LogWarning("Enabling GraphQL mutation for this entity without the multiple-create option. The current configuration may not be optimal."); + } + + // Create entity with updated details Entity updatedEntity = new( Source: updatedSource, Fields: fields, Rest: updatedRestDetails, GraphQL: updatedGraphQLDetails, + Mcp: updatedMcpOptions, Permissions: updatedPermissions, Relationships: updatedRelationships, Mappings: updatedMappings, Cache: updatedCacheOptions, Description: string.IsNullOrWhiteSpace(options.Description) ? entity.Description : options.Description - ); + ); + IDictionary entities = new Dictionary(initialConfig.Entities.Entities) { [options.Entity] = updatedEntity @@ -2489,7 +2446,7 @@ private static bool TryAddGraphQLOperationForStoredProcedure(EntityOptions optio /// Input from update command /// Boolean -> when the entity's REST configuration is true/false. /// RestEntitySettings -> when a non stored procedure entity is configured with granular REST settings (Path). - /// RestStoredProcedureEntitySettings -> when a stored procedure entity is configured with explicit SupportedRestMethods. + /// RestStoredProcedureEntitySettings-> when a stored procedure entity is configured with explicit SupportedRestMethods. /// RestStoredProcedureEntityVerboseSettings-> when a stored procedure entity is configured with explicit SupportedRestMethods and Path settings. private static EntityRestOptions ConstructUpdatedRestDetails(Entity entity, EntityOptions options, bool isCosmosDbNoSql) { @@ -2862,5 +2819,120 @@ private static bool ValidateFields( return true; } + + /// + /// Constructs MCP options for an entity based on the provided CLI options. + /// Only applicable for stored-procedure entities. + /// + /// Whether to enable this entity as a custom MCP tool. + /// Whether to enable DML tools for this entity. + /// EntityMcpOptions or null if no MCP options are specified. + private static EntityMcpOptions? ConstructMcpOptions(CliBool? customToolEnabled, CliBool? dmlToolsEnabled) + { + // If neither option is specified, return null (use defaults from schema) + if ((customToolEnabled is null or CliBool.None) && (dmlToolsEnabled is null or CliBool.None)) + { + return null; + } + + bool? customTool = customToolEnabled switch + { + CliBool.True => true, + CliBool.False => false, + _ => null + }; + + bool? dmlTools = dmlToolsEnabled switch + { + CliBool.True => true, + CliBool.False => false, + _ => null + }; + + return new EntityMcpOptions(customTool, dmlTools); + } + + /// + /// Constructs the updated MCP settings based on the input from update command and + /// existing MCP configuration for an entity + /// + /// Entity for which MCP settings are updated + /// Input from update command + /// Updated EntityMcpOptions or null + private static EntityMcpOptions? ConstructUpdatedMcpOptions(Entity entity, UpdateOptions options) + { + // Get the current and potential new entity types + bool isCurrentEntityStoredProcedure = IsStoredProcedure(entity); + bool isBecomingStoredProcedure = options.SourceType is not null && IsStoredProcedure(options); + + // MCP custom-tool is only applicable for stored procedures + if (!isCurrentEntityStoredProcedure && !isBecomingStoredProcedure) + { + // Not a stored procedure, MCP custom-tool not applicable + if (options.McpCustomToolEnabled is not null and not CliBool.None) + { + _logger.LogWarning("--mcp.custom-tool is only applicable for stored procedures and will be ignored."); + } + + // Preserve existing MCP options (likely null for non-SP entities) + return entity.Mcp; + } + + // Start with existing MCP options or create new if converting to stored procedure + EntityMcpOptions? existingMcp = entity.Mcp; + + bool? customToolEnabled = existingMcp?.CustomToolEnabled; + bool? dmlToolsEnabled = existingMcp?.DmlToolEnabled; + + // Update custom-tool if provided + if (options.McpCustomToolEnabled is not null and not CliBool.None) + { + customToolEnabled = options.McpCustomToolEnabled == CliBool.True; + } + + // Update dml-tools if provided + if (options.McpDmlToolsEnabled is not null and not CliBool.None) + { + dmlToolsEnabled = options.McpDmlToolsEnabled == CliBool.True; + } + + // If converting from stored procedure to table/view, clear MCP options + if (isCurrentEntityStoredProcedure && options.SourceType is not null && !isBecomingStoredProcedure) + { + return null; + } + + // If converting to stored procedure and no MCP options specified, use defaults + if (!isCurrentEntityStoredProcedure && isBecomingStoredProcedure) + { + // Converting to stored procedure - apply defaults if no values specified + if (customToolEnabled == null && options.McpCustomToolEnabled is null or CliBool.None) + { + customToolEnabled = false; // default + } + + if (dmlToolsEnabled == null && options.McpDmlToolsEnabled is null or CliBool.None) + { + dmlToolsEnabled = true; // default + } + } + + // Return updated MCP options if any values are set + if (customToolEnabled != null || dmlToolsEnabled != null) + { + return new EntityMcpOptions(customToolEnabled, dmlToolsEnabled); + } + + return null; + } + + /// + /// Validates if a REST route is valid. + /// + private static bool IsRouteValid(string route) + { + // Basic validation for route + return !string.IsNullOrWhiteSpace(route) && route.StartsWith("/"); + } } } diff --git a/src/Config/Converters/EntityMcpOptionsConverterFactory.cs b/src/Config/Converters/EntityMcpOptionsConverterFactory.cs new file mode 100644 index 0000000000..25d0c9487f --- /dev/null +++ b/src/Config/Converters/EntityMcpOptionsConverterFactory.cs @@ -0,0 +1,127 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Text.Json; +using System.Text.Json.Serialization; +using Azure.DataApiBuilder.Config.ObjectModel; + +namespace Azure.DataApiBuilder.Config.Converters; + +/// +/// Factory for creating EntityMcpOptions converters. +/// +internal class EntityMcpOptionsConverterFactory : JsonConverterFactory +{ + public override bool CanConvert(Type typeToConvert) + { + return typeToConvert == typeof(EntityMcpOptions); + } + + public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) + { + return new EntityMcpOptionsConverter(); + } + + /// + /// Converter for EntityMcpOptions that handles both boolean and object representations. + /// When boolean: true enables dml-tools, false disables dml-tools. + /// When object: can specify individual properties (custom-tool and dml-tools). + /// + private class EntityMcpOptionsConverter : JsonConverter + { + public override EntityMcpOptions? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + return null; + } + + // Handle boolean shorthand: true/false + if (reader.TokenType == JsonTokenType.True || reader.TokenType == JsonTokenType.False) + { + bool value = reader.GetBoolean(); + // Boolean true means: dml-tools=true, custom-tool=false (default) + // Boolean false means: dml-tools=false, custom-tool=false + return new EntityMcpOptions( + customToolEnabled: false, + dmlToolsEnabled: value + ); + } + + // Handle object representation + if (reader.TokenType == JsonTokenType.StartObject) + { + bool? customToolEnabled = null; + bool? dmlToolsEnabled = null; + + while (reader.Read()) + { + if (reader.TokenType == JsonTokenType.EndObject) + { + break; + } + + if (reader.TokenType == JsonTokenType.PropertyName) + { + string? propertyName = reader.GetString(); + reader.Read(); // Move to the value + + if (propertyName == "custom-tool") + { + customToolEnabled = reader.TokenType == JsonTokenType.True; + } + else if (propertyName == "dml-tools") + { + dmlToolsEnabled = reader.TokenType == JsonTokenType.True; + } + } + } + + return new EntityMcpOptions(customToolEnabled, dmlToolsEnabled); + } + + throw new JsonException($"Unexpected token type {reader.TokenType} for EntityMcpOptions"); + } + + public override void Write(Utf8JsonWriter writer, EntityMcpOptions value, JsonSerializerOptions options) + { + if (value == null) + { + writer.WriteNullValue(); + return; + } + + // Check if we should write as boolean shorthand + // Write as boolean if: only dml-tools is set (or custom-tool is default false) + bool writeAsBoolean = !value.UserProvidedCustomToolEnabled && value.UserProvidedDmlToolsEnabled; + + if (writeAsBoolean) + { + // Write as boolean shorthand + writer.WriteBooleanValue(value.DmlToolEnabled ?? true); + } + else if (value.UserProvidedCustomToolEnabled || value.UserProvidedDmlToolsEnabled) + { + // Write as object + writer.WriteStartObject(); + + if (value.UserProvidedCustomToolEnabled) + { + writer.WriteBoolean("custom-tool", value.CustomToolEnabled ?? false); + } + + if (value.UserProvidedDmlToolsEnabled) + { + writer.WriteBoolean("dml-tools", value.DmlToolEnabled ?? true); + } + + writer.WriteEndObject(); + } + else + { + // Nothing provided, write null (will be omitted by DefaultIgnoreCondition) + writer.WriteNullValue(); + } + } + } +} diff --git a/src/Config/ObjectModel/Entity.cs b/src/Config/ObjectModel/Entity.cs index c9f247e0f6..e3995232ce 100644 --- a/src/Config/ObjectModel/Entity.cs +++ b/src/Config/ObjectModel/Entity.cs @@ -13,6 +13,7 @@ namespace Azure.DataApiBuilder.Config.ObjectModel; /// Health check configuration for the entity. /// The underlying database object to which the exposed entity is connected to. /// The JSON may represent this as a bool or a string and we use a custom JsonConverter to convert that into the .NET type. +/// MCP tool configuration for the entity. /// The JSON may represent this as a bool or a string and we use a custom JsonConverter to convert that into the .NET type. /// Permissions assigned to this entity. /// Defines how an entity is related to other exposed @@ -33,6 +34,7 @@ public record Entity public List? Fields { get; init; } public EntityGraphQLOptions GraphQL { get; init; } public EntityRestOptions Rest { get; init; } + public EntityMcpOptions? Mcp { get; init; } public EntityPermission[] Permissions { get; init; } public Dictionary? Mappings { get; init; } public Dictionary? Relationships { get; init; } @@ -48,6 +50,7 @@ public Entity( EntityGraphQLOptions GraphQL, List? Fields, EntityRestOptions Rest, + EntityMcpOptions? Mcp, EntityPermission[] Permissions, Dictionary? Mappings, Dictionary? Relationships, @@ -61,6 +64,7 @@ public Entity( this.Fields = Fields; this.GraphQL = GraphQL; this.Rest = Rest; + this.Mcp = Mcp; this.Permissions = Permissions; this.Mappings = Mappings; this.Relationships = Relationships; diff --git a/src/Config/ObjectModel/EntityMcpOptions.cs b/src/Config/ObjectModel/EntityMcpOptions.cs new file mode 100644 index 0000000000..9101eec247 --- /dev/null +++ b/src/Config/ObjectModel/EntityMcpOptions.cs @@ -0,0 +1,61 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Text.Json.Serialization; + +namespace Azure.DataApiBuilder.Config.ObjectModel +{ + /// + /// Options for Model Context Protocol (MCP) tools at the entity level of stored-procedure types. + /// + public record EntityMcpOptions + { + /// + /// Indicates whether custom tools are enabled for this entity. + /// + [JsonPropertyName("custom-tool")] + public bool? CustomToolEnabled { get; init; } = false; + + /// + /// Indicates whether DML tools are enabled for this entity. + /// + [JsonPropertyName("dml-tools")] + public bool? DmlToolEnabled { get; init; } = true; + + /// + /// Flag which informs CLI and JSON serializer whether to write the CustomToolEnabled + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Always)] + public bool UserProvidedCustomToolEnabled { get; init; } = false; + + /// + /// Flag which informs CLI and JSON serializer whether to write the DmlToolEnabled + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Always)] + public bool UserProvidedDmlToolsEnabled { get; init; } = false; + + /// + /// Constructor for EntityMcpOptions + /// + /// The custom tool enabled flag. + /// The DML tools enabled flag. + public EntityMcpOptions(bool? customToolEnabled, bool? dmlToolsEnabled) + { + if (customToolEnabled is not null) + { + this.CustomToolEnabled = customToolEnabled; + this.UserProvidedCustomToolEnabled = true; + } + + if (dmlToolsEnabled is not null) + { + this.DmlToolEnabled = dmlToolsEnabled; + this.UserProvidedDmlToolsEnabled = true; + } + else + { + this.DmlToolEnabled = true; + } + } + } +} diff --git a/src/Config/RuntimeConfigLoader.cs b/src/Config/RuntimeConfigLoader.cs index bad5aa8680..26405e7952 100644 --- a/src/Config/RuntimeConfigLoader.cs +++ b/src/Config/RuntimeConfigLoader.cs @@ -308,6 +308,7 @@ public static JsonSerializerOptions GetSerializationOptions( options.Converters.Add(new GraphQLRuntimeOptionsConverterFactory(replacementSettings)); options.Converters.Add(new McpRuntimeOptionsConverterFactory(replacementSettings)); options.Converters.Add(new DmlToolsConfigConverter()); + options.Converters.Add(new EntityMcpOptionsConverterFactory()); options.Converters.Add(new EntitySourceConverterFactory(replacementSettings)); options.Converters.Add(new EntityGraphQLOptionsConverterFactory(replacementSettings)); options.Converters.Add(new EntityRestOptionsConverterFactory(replacementSettings)); diff --git a/src/Core/Services/MetadataProviders/MsSqlMetadataProvider.cs b/src/Core/Services/MetadataProviders/MsSqlMetadataProvider.cs index 7d02798427..d00b3747e8 100644 --- a/src/Core/Services/MetadataProviders/MsSqlMetadataProvider.cs +++ b/src/Core/Services/MetadataProviders/MsSqlMetadataProvider.cs @@ -256,6 +256,7 @@ protected override void PopulateMetadataForLinkingObject( Fields: null, Rest: new(Array.Empty(), Enabled: false), GraphQL: new(Singular: linkingEntityName, Plural: linkingEntityName, Enabled: false), + Mcp: null, // null for auto-generated entities Permissions: Array.Empty(), Relationships: null, Mappings: new(), diff --git a/src/Service.Tests/Authorization/AuthorizationHelpers.cs b/src/Service.Tests/Authorization/AuthorizationHelpers.cs index bdd5630a50..39c253d57a 100644 --- a/src/Service.Tests/Authorization/AuthorizationHelpers.cs +++ b/src/Service.Tests/Authorization/AuthorizationHelpers.cs @@ -116,6 +116,7 @@ public static RuntimeConfig InitRuntimeConfig( Rest: new(Array.Empty()), GraphQL: new(entityName.Singularize(), entityName.Pluralize()), Permissions: new EntityPermission[] { permissionForEntity }, + Mcp: null, Relationships: null, Mappings: null ); diff --git a/src/Service.Tests/Authorization/AuthorizationResolverUnitTests.cs b/src/Service.Tests/Authorization/AuthorizationResolverUnitTests.cs index 0dff3ac016..826a2ab283 100644 --- a/src/Service.Tests/Authorization/AuthorizationResolverUnitTests.cs +++ b/src/Service.Tests/Authorization/AuthorizationResolverUnitTests.cs @@ -1428,6 +1428,7 @@ private static RuntimeConfig BuildTestRuntimeConfig(EntityPermission[] permissio Rest: new(Enabled: true), GraphQL: new("", ""), Permissions: permissions, + Mcp: null, Relationships: null, Mappings: null); @@ -1502,3 +1503,4 @@ private async static Task CreateClaimsPrincipal(Dictionary + @@ -81,6 +82,11 @@ true PreserveNewest + + PreserveNewest + true + PreserveNewest + Always diff --git a/src/Service.Tests/Caching/DabCacheServiceIntegrationTests.cs b/src/Service.Tests/Caching/DabCacheServiceIntegrationTests.cs index 02b7ca6492..0f7ce4db13 100644 --- a/src/Service.Tests/Caching/DabCacheServiceIntegrationTests.cs +++ b/src/Service.Tests/Caching/DabCacheServiceIntegrationTests.cs @@ -744,6 +744,7 @@ private static Mock CreateMockRuntimeConfigProvider(strin GraphQL: new EntityGraphQLOptions(string.Empty, string.Empty), Rest: new EntityRestOptions(), Permissions: Array.Empty(), + Mcp: null, Mappings: new Dictionary(), Relationships: new Dictionary(), Cache: new EntityCacheOptions { Enabled = true }, @@ -948,3 +949,4 @@ private static DabCacheService CreateDabCacheService(FusionCache cache) } } } + diff --git a/src/Service.Tests/Caching/HealthEndpointCachingTests.cs b/src/Service.Tests/Caching/HealthEndpointCachingTests.cs index fcc3e097e5..b422f58e2f 100644 --- a/src/Service.Tests/Caching/HealthEndpointCachingTests.cs +++ b/src/Service.Tests/Caching/HealthEndpointCachingTests.cs @@ -124,7 +124,8 @@ private static void SetupCachingTest(int? cacheTtlSeconds) Rest: new(Enabled: true), GraphQL: new("book", "books", true), Permissions: new[] { ConfigurationTests.GetMinimalPermissionConfig(AuthorizationResolver.ROLE_ANONYMOUS) }, - Relationships: null, + Mcp: null, + Relationships: null, Mappings: null); Dictionary entityMap = new() @@ -168,3 +169,4 @@ private static void CreateCustomConfigFile(Dictionary entityMap, } } + diff --git a/src/Service.Tests/Configuration/ConfigurationTests.cs b/src/Service.Tests/Configuration/ConfigurationTests.cs index 0614e7688f..92314bf396 100644 --- a/src/Service.Tests/Configuration/ConfigurationTests.cs +++ b/src/Service.Tests/Configuration/ConfigurationTests.cs @@ -1617,6 +1617,7 @@ public async Task TestSqlMetadataForInvalidConfigEntities() Rest: null, GraphQL: new(Singular: "book", Plural: "books"), Permissions: new[] { GetMinimalPermissionConfig(AuthorizationResolver.ROLE_ANONYMOUS) }, + Mcp: null, Relationships: null, Mappings: null ); @@ -1627,6 +1628,7 @@ public async Task TestSqlMetadataForInvalidConfigEntities() Rest: null, GraphQL: new(Singular: "publisher", Plural: "publishers"), Permissions: new[] { GetMinimalPermissionConfig(AuthorizationResolver.ROLE_AUTHENTICATED) }, + Mcp: null, Relationships: null, Mappings: null ); @@ -1690,6 +1692,7 @@ public async Task TestSqlMetadataValidationForEntitiesWithInvalidSource() Rest: null, GraphQL: new(Singular: "book", Plural: "books"), Permissions: new[] { GetMinimalPermissionConfig(AuthorizationResolver.ROLE_ANONYMOUS) }, + Mcp: null, Relationships: null, Mappings: null ); @@ -1701,6 +1704,7 @@ public async Task TestSqlMetadataValidationForEntitiesWithInvalidSource() Rest: null, GraphQL: new(Singular: "publisher", Plural: "publishers"), Permissions: new[] { GetMinimalPermissionConfig(AuthorizationResolver.ROLE_ANONYMOUS) }, + Mcp: null, Relationships: new Dictionary() { {"books", new ( Cardinality: Cardinality.Many, TargetEntity: "Book", @@ -2660,6 +2664,7 @@ public async Task ValidateErrorMessageForMutationWithoutReadPermission() Rest: null, GraphQL: new(Singular: "Stock", Plural: "Stocks"), Permissions: permissions, + Mcp: null, Relationships: null, Mappings: null); @@ -2963,6 +2968,7 @@ public async Task ValidateInheritanceOfReadPermissionFromAnonymous() Rest: null, GraphQL: new(Singular: "Stock", Plural: "Stocks"), Permissions: permissions, + Mcp: null, Relationships: null, Mappings: null); @@ -3092,6 +3098,7 @@ public async Task ValidateLocationHeaderFieldForPostRequests(EntitySourceType en Rest: new(new SupportedHttpVerb[] { SupportedHttpVerb.Get, SupportedHttpVerb.Post }), GraphQL: null, Permissions: new[] { GetMinimalPermissionConfig(AuthorizationResolver.ROLE_ANONYMOUS) }, + Mcp: null, Relationships: null, Mappings: null ); @@ -3192,6 +3199,7 @@ public async Task ValidateLocationHeaderWhenBaseRouteIsConfigured( Rest: new(new SupportedHttpVerb[] { SupportedHttpVerb.Get, SupportedHttpVerb.Post }), GraphQL: null, Permissions: new[] { GetMinimalPermissionConfig(AuthorizationResolver.ROLE_ANONYMOUS) }, + Mcp: null, Relationships: null, Mappings: null ); @@ -3371,6 +3379,7 @@ public async Task TestEngineSupportViewsWithoutKeyFieldsInConfigForMsSQL() Rest: new(Enabled: true), GraphQL: new("", ""), Permissions: new[] { GetMinimalPermissionConfig(AuthorizationResolver.ROLE_ANONYMOUS) }, + Mcp: null, Relationships: null, Mappings: null ); @@ -3711,6 +3720,7 @@ public void TestInvalidDatabaseColumnNameHandling( Rest: new(Enabled: false), GraphQL: new("graphql_incompatible", "graphql_incompatibles", entityGraphQLEnabled), Permissions: new[] { GetMinimalPermissionConfig(AuthorizationResolver.ROLE_ANONYMOUS) }, + Mcp: null, Relationships: null, Mappings: mappings ); @@ -4337,6 +4347,7 @@ public async Task OpenApi_GlobalEntityRestPath(bool globalRestEnabled, bool expe Rest: new(Enabled: false), GraphQL: new("book", "books"), Permissions: new[] { GetMinimalPermissionConfig(AuthorizationResolver.ROLE_ANONYMOUS) }, + Mcp: null, Relationships: null, Mappings: null); @@ -4399,6 +4410,7 @@ public async Task HealthEndpoint_ValidateContents() Rest: new(Enabled: false), GraphQL: new("book", "books"), Permissions: new[] { GetMinimalPermissionConfig(AuthorizationResolver.ROLE_ANONYMOUS) }, + Mcp: null, Relationships: null, Mappings: null); @@ -4449,6 +4461,7 @@ public async Task OpenApi_EntityLevelRestEndpoint() Rest: new(Enabled: true), GraphQL: new("", "", false), Permissions: new[] { GetMinimalPermissionConfig(AuthorizationResolver.ROLE_ANONYMOUS) }, + Mcp: null, Relationships: null, Mappings: null); @@ -4458,6 +4471,7 @@ public async Task OpenApi_EntityLevelRestEndpoint() Rest: new(Enabled: false), GraphQL: new("publisher", "publishers", true), Permissions: new[] { GetMinimalPermissionConfig(AuthorizationResolver.ROLE_ANONYMOUS) }, + Mcp: null, Relationships: null, Mappings: null); @@ -4541,6 +4555,7 @@ public async Task ValidateNextLinkUsage(bool isNextLinkRelative) Rest: new(Enabled: true), GraphQL: new(Singular: "", Plural: "", Enabled: false), Permissions: new[] { GetMinimalPermissionConfig(AuthorizationResolver.ROLE_ANONYMOUS) }, + Mcp: null, Relationships: null, Mappings: null); @@ -4667,6 +4682,7 @@ public async Task ValidateNextLinkRespectsXForwardedHostAndProto(string forwarde Rest: new(Enabled: true), GraphQL: new(Singular: "", Plural: "", Enabled: false), Permissions: new[] { GetMinimalPermissionConfig(AuthorizationResolver.ROLE_ANONYMOUS) }, + Mcp: null, Relationships: null, Mappings: null); @@ -5384,6 +5400,7 @@ public static RuntimeConfig InitialzieRuntimeConfigForMultipleCreateTests(bool i Rest: null, GraphQL: new(Singular: "book", Plural: "books"), Permissions: permissions, + Mcp: null, Relationships: new Dictionary() { { "publishers", bookRelationship } }, Mappings: null); @@ -5408,6 +5425,7 @@ public static RuntimeConfig InitialzieRuntimeConfigForMultipleCreateTests(bool i Rest: null, GraphQL: new(Singular: "publisher", Plural: "publishers"), Permissions: permissions, + Mcp: null, Relationships: new Dictionary() { { "books", publisherRelationship } }, Mappings: null); @@ -5442,6 +5460,7 @@ public static RuntimeConfig InitMinimalRuntimeConfig( Rest: null, GraphQL: new(Singular: "book", Plural: "books"), Permissions: new[] { GetMinimalPermissionConfig(AuthorizationResolver.ROLE_ANONYMOUS) }, + Mcp: null, Relationships: null, Mappings: null ); @@ -5460,6 +5479,7 @@ public static RuntimeConfig InitMinimalRuntimeConfig( Rest: null, GraphQL: new(Singular: "publisher", Plural: "publishers"), Permissions: new[] { GetMinimalPermissionConfig(AuthorizationResolver.ROLE_AUTHENTICATED) }, + Mcp: null, Relationships: null, Mappings: null ); @@ -5568,6 +5588,7 @@ private static RuntimeConfig CreateBasicRuntimeConfigWithSingleEntityAndAuthOpti Rest: null, GraphQL: new(Singular: "book", Plural: "books"), Permissions: new[] { GetMinimalPermissionConfig(AuthorizationResolver.ROLE_ANONYMOUS) }, + Mcp: null, Relationships: null, Mappings: null ); @@ -5610,3 +5631,4 @@ private bool HandleException(Exception e) where T : Exception } } } + diff --git a/src/Service.Tests/Configuration/HealthEndpointRolesTests.cs b/src/Service.Tests/Configuration/HealthEndpointRolesTests.cs index 9ad36bfa15..ffdc6d8947 100644 --- a/src/Service.Tests/Configuration/HealthEndpointRolesTests.cs +++ b/src/Service.Tests/Configuration/HealthEndpointRolesTests.cs @@ -54,6 +54,7 @@ public async Task ComprehensiveHealthEndpoint_RolesTests(string role, HostMode h Rest: new(Enabled: true), GraphQL: new("book", "books", true), Permissions: new[] { ConfigurationTests.GetMinimalPermissionConfig(AuthorizationResolver.ROLE_ANONYMOUS) }, + Mcp: null, Relationships: null, Mappings: null); @@ -139,3 +140,4 @@ private static void CreateCustomConfigFile(Dictionary entityMap, } } } + diff --git a/src/Service.Tests/Configuration/HealthEndpointTests.cs b/src/Service.Tests/Configuration/HealthEndpointTests.cs index 1eac7416e3..2ab0f0c86f 100644 --- a/src/Service.Tests/Configuration/HealthEndpointTests.cs +++ b/src/Service.Tests/Configuration/HealthEndpointTests.cs @@ -523,6 +523,7 @@ private static RuntimeConfig SetupCustomConfigFile(bool enableGlobalHealth, bool Rest: new(Enabled: enableEntityRest), GraphQL: new("book", "bookLists", enableEntityGraphQL), Permissions: new[] { ConfigurationTests.GetMinimalPermissionConfig(AuthorizationResolver.ROLE_ANONYMOUS) }, + Mcp: null, Relationships: null, Mappings: null); @@ -573,3 +574,4 @@ private static void WriteToCustomConfigFile(RuntimeConfig runtimeConfig) } #endregion } + diff --git a/src/Service.Tests/Configuration/HotReload/AuthorizationResolverHotReloadTests.cs b/src/Service.Tests/Configuration/HotReload/AuthorizationResolverHotReloadTests.cs index 2175c8ac83..6e3c53ff19 100644 --- a/src/Service.Tests/Configuration/HotReload/AuthorizationResolverHotReloadTests.cs +++ b/src/Service.Tests/Configuration/HotReload/AuthorizationResolverHotReloadTests.cs @@ -69,6 +69,7 @@ public async Task ValidateAuthorizationResolver_HotReload() Rest: new(Enabled: true), GraphQL: new(Singular: "", Plural: "", Enabled: false), Permissions: new[] { permissionsHR }, + Mcp: null, Relationships: null, Mappings: null); @@ -183,6 +184,7 @@ public static async Task ClassInitializeAsync(TestContext context) Rest: new(Enabled: true), GraphQL: new(Singular: "", Plural: "", Enabled: false), Permissions: new[] { permissions }, + Mcp: null, Relationships: null, Mappings: null); @@ -224,3 +226,4 @@ public static void ClassCleanup() _testClient.Dispose(); } } + diff --git a/src/Service.Tests/CosmosTests/MutationTests.cs b/src/Service.Tests/CosmosTests/MutationTests.cs index de931dcf22..a632fc5c01 100644 --- a/src/Service.Tests/CosmosTests/MutationTests.cs +++ b/src/Service.Tests/CosmosTests/MutationTests.cs @@ -546,6 +546,7 @@ type Planet @model(name:""Planet"") { Rest: null, GraphQL: new(Singular: "Planet", Plural: "Planets"), Permissions: permissions, + Mcp: null, Relationships: null, Mappings: null); @@ -677,6 +678,7 @@ type Planet @model(name:""Planet"") { Rest: null, GraphQL: new(Singular: "Planet", Plural: "Planets"), Permissions: permissions, + Mcp: null, Relationships: null, Mappings: null); @@ -1116,3 +1118,4 @@ public void TestFixtureTearDown() } } } + diff --git a/src/Service.Tests/CosmosTests/QueryTests.cs b/src/Service.Tests/CosmosTests/QueryTests.cs index 52afa8e788..66367cb151 100644 --- a/src/Service.Tests/CosmosTests/QueryTests.cs +++ b/src/Service.Tests/CosmosTests/QueryTests.cs @@ -714,6 +714,7 @@ type Planet @model(name:""Planet"") { Rest: null, GraphQL: new(Singular: "Planet", Plural: "Planets"), Permissions: permissions, + Mcp: null, Relationships: null, Mappings: null, Cache: new EntityCacheOptions() @@ -748,3 +749,4 @@ public void TestFixtureTearDown() } } } + diff --git a/src/Service.Tests/CosmosTests/SchemaGeneratorFactoryTests.cs b/src/Service.Tests/CosmosTests/SchemaGeneratorFactoryTests.cs index f10ac17354..dbe077869f 100644 --- a/src/Service.Tests/CosmosTests/SchemaGeneratorFactoryTests.cs +++ b/src/Service.Tests/CosmosTests/SchemaGeneratorFactoryTests.cs @@ -87,6 +87,7 @@ public async Task ExportGraphQLFromCosmosDB_GeneratesSchemaSuccessfully(string g Rest: new(Enabled: false), GraphQL: new("Container1", "Container1s"), Permissions: new EntityPermission[] {}, + Mcp: null, Relationships: null, Mappings: null) }, {"Container2", new Entity( @@ -95,6 +96,7 @@ public async Task ExportGraphQLFromCosmosDB_GeneratesSchemaSuccessfully(string g Rest: new(Enabled: false), GraphQL: new("Container2", "Container2s"), Permissions: new EntityPermission[] {}, + Mcp: null, Relationships: null, Mappings: null) }, {"Container0", new Entity( @@ -103,6 +105,7 @@ public async Task ExportGraphQLFromCosmosDB_GeneratesSchemaSuccessfully(string g Rest: new(Enabled: false), GraphQL: new("Container0", "Container0s"), Permissions: new EntityPermission[] {}, + Mcp: null, Relationships: null, Mappings: null) } }) @@ -186,3 +189,4 @@ private static ResponseMessage GetResponse() } } } + diff --git a/src/Service.Tests/GraphQLBuilder/Helpers/GraphQLTestHelpers.cs b/src/Service.Tests/GraphQLBuilder/Helpers/GraphQLTestHelpers.cs index 737e29f48f..06cc2d477d 100644 --- a/src/Service.Tests/GraphQLBuilder/Helpers/GraphQLTestHelpers.cs +++ b/src/Service.Tests/GraphQLBuilder/Helpers/GraphQLTestHelpers.cs @@ -83,6 +83,7 @@ public static Entity GenerateEmptyEntity(EntitySourceType sourceType = EntitySou Fields: null, Rest: new(Array.Empty()), GraphQL: new("", ""), + Mcp: null, Permissions: Array.Empty(), Relationships: new(), Mappings: new()); @@ -110,6 +111,7 @@ public static Entity GenerateStoredProcedureEntity( Fields: null, Rest: new(Array.Empty()), GraphQL: new(Singular: graphQLTypeName, Plural: "", Enabled: true, Operation: graphQLOperation), + Mcp: null, Permissions: new[] { new EntityPermission(Role: "anonymous", Actions: actions.ToArray()) }, Relationships: new(), Mappings: new()); @@ -128,6 +130,7 @@ public static Entity GenerateEntityWithSingularPlural(string singularNameForEnti Fields: null, Rest: new(Array.Empty()), GraphQL: new(singularNameForEntity, pluralNameForEntity), + Mcp: null, Permissions: Array.Empty(), Relationships: new(), Mappings: new()); @@ -145,6 +148,7 @@ public static Entity GenerateEntityWithStringType(string singularGraphQLName, En Fields: null, Rest: new(Array.Empty()), GraphQL: new(singularGraphQLName, ""), + Mcp: null, Permissions: Array.Empty(), Relationships: new(), Mappings: new()); @@ -188,3 +192,4 @@ public static void ValidateAuthorizeDirectivePresence(string ObjectType, IEnumer } } } + diff --git a/src/Service.Tests/GraphQLBuilder/MutationBuilderTests.cs b/src/Service.Tests/GraphQLBuilder/MutationBuilderTests.cs index a1478093dd..c9425ae71f 100644 --- a/src/Service.Tests/GraphQLBuilder/MutationBuilderTests.cs +++ b/src/Service.Tests/GraphQLBuilder/MutationBuilderTests.cs @@ -49,6 +49,7 @@ private static Entity GenerateEmptyEntity() Rest: new(Enabled: false), GraphQL: new("Foo", "Foos", Enabled: true), Permissions: Array.Empty(), + Mcp: null, Relationships: new(), Mappings: new()); } @@ -1350,3 +1351,4 @@ type StoredProcedureType @model(name:""MyStoredProcedure"") { } } } + diff --git a/src/Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs b/src/Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs index 84806adc78..9d9d70259b 100644 --- a/src/Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs +++ b/src/Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs @@ -747,6 +747,7 @@ public static Entity GenerateEmptyEntity(string entityName) Rest: new(Enabled: true), GraphQL: new(entityName, ""), Permissions: Array.Empty(), + Mcp: null, Relationships: new(), Mappings: new() ); @@ -952,3 +953,4 @@ type Book @model(name:""Book"") { } } } + diff --git a/src/Service.Tests/OpenApiDocumentor/DocumentVerbosityTests.cs b/src/Service.Tests/OpenApiDocumentor/DocumentVerbosityTests.cs index fa43617f4f..63ec7c78ce 100644 --- a/src/Service.Tests/OpenApiDocumentor/DocumentVerbosityTests.cs +++ b/src/Service.Tests/OpenApiDocumentor/DocumentVerbosityTests.cs @@ -46,6 +46,7 @@ public async Task ResponseObjectSchemaIncludesTypeProperty() GraphQL: new(Singular: null, Plural: null, Enabled: false), Rest: new(Methods: EntityRestOptions.DEFAULT_SUPPORTED_VERBS), Permissions: OpenApiTestBootstrap.CreateBasicPermissions(), + Mcp: null, Mappings: null, Relationships: null); @@ -86,3 +87,4 @@ public async Task ResponseObjectSchemaIncludesTypeProperty() } } } + diff --git a/src/Service.Tests/OpenApiDocumentor/ParameterValidationTests.cs b/src/Service.Tests/OpenApiDocumentor/ParameterValidationTests.cs index 7c0e0225ae..5a10e4a46d 100644 --- a/src/Service.Tests/OpenApiDocumentor/ParameterValidationTests.cs +++ b/src/Service.Tests/OpenApiDocumentor/ParameterValidationTests.cs @@ -238,6 +238,7 @@ private async static Task GenerateOpenApiDocumentForGivenEntity GraphQL: new(Singular: null, Plural: null, Enabled: false), Rest: new(Methods: supportedHttpMethods ?? EntityRestOptions.DEFAULT_SUPPORTED_VERBS), Permissions: OpenApiTestBootstrap.CreateBasicPermissions(), + Mcp: null, Mappings: null, Relationships: null); @@ -293,3 +294,4 @@ public async Task ValidateHeaderParametersForEntity(string entityName, string ob } } } + diff --git a/src/Service.Tests/OpenApiDocumentor/PathValidationTests.cs b/src/Service.Tests/OpenApiDocumentor/PathValidationTests.cs index 5f478b3b80..398fff6467 100644 --- a/src/Service.Tests/OpenApiDocumentor/PathValidationTests.cs +++ b/src/Service.Tests/OpenApiDocumentor/PathValidationTests.cs @@ -49,6 +49,7 @@ public async Task ValidateEntityRestPath(string entityName, string configuredRes GraphQL: new(Singular: null, Plural: null, Enabled: false), Rest: new(Methods: EntityRestOptions.DEFAULT_SUPPORTED_VERBS, Path: configuredRestPath), Permissions: OpenApiTestBootstrap.CreateBasicPermissions(), + Mcp: null, Mappings: null, Relationships: null); @@ -73,3 +74,4 @@ public async Task ValidateEntityRestPath(string entityName, string configuredRes } } } + diff --git a/src/Service.Tests/OpenApiDocumentor/StoredProcedureGeneration.cs b/src/Service.Tests/OpenApiDocumentor/StoredProcedureGeneration.cs index ffd5aaadde..b626be6ade 100644 --- a/src/Service.Tests/OpenApiDocumentor/StoredProcedureGeneration.cs +++ b/src/Service.Tests/OpenApiDocumentor/StoredProcedureGeneration.cs @@ -59,6 +59,7 @@ public static void CreateEntities() GraphQL: new(Singular: null, Plural: null, Enabled: false), Rest: new(Methods: EntityRestOptions.DEFAULT_SUPPORTED_VERBS), Permissions: OpenApiTestBootstrap.CreateBasicPermissions(), + Mcp: null, Mappings: null, Relationships: null, Description: "Represents a stored procedure for books"); @@ -300,3 +301,4 @@ public static Dictionary ResolveConfiguredOperations(Entity } } } + diff --git a/src/Service.Tests/Snapshots/ConfigurationTests.TestReadingRuntimeConfigForMsSql.verified.txt b/src/Service.Tests/Snapshots/ConfigurationTests.TestReadingRuntimeConfigForMsSql.verified.txt index 52f4035868..65e14013cb 100644 --- a/src/Service.Tests/Snapshots/ConfigurationTests.TestReadingRuntimeConfigForMsSql.verified.txt +++ b/src/Service.Tests/Snapshots/ConfigurationTests.TestReadingRuntimeConfigForMsSql.verified.txt @@ -525,18 +525,6 @@ Object: books, Type: Table }, - Fields: [ - { - Name: id, - Alias: id, - PrimaryKey: false - }, - { - Name: title, - Alias: title, - PrimaryKey: false - } - ], GraphQL: { Singular: book, Plural: books, @@ -921,6 +909,10 @@ ] } ], + Mappings: { + id: id, + title: title + }, Relationships: { authors: { Cardinality: Many, @@ -1648,13 +1640,6 @@ Object: type_table, Type: Table }, - Fields: [ - { - Name: id, - Alias: typeid, - PrimaryKey: false - } - ], GraphQL: { Singular: SupportedType, Plural: SupportedTypes, @@ -1698,7 +1683,10 @@ } ] } - ] + ], + Mappings: { + id: typeid + } } }, { @@ -1793,18 +1781,6 @@ Object: trees, Type: Table }, - Fields: [ - { - Name: species, - Alias: Scientific Name, - PrimaryKey: false - }, - { - Name: region, - Alias: United State's Region, - PrimaryKey: false - } - ], GraphQL: { Singular: Tree, Plural: Trees, @@ -1848,7 +1824,11 @@ } ] } - ] + ], + Mappings: { + region: United State's Region, + species: Scientific Name + } } }, { @@ -1857,13 +1837,6 @@ Object: trees, Type: Table }, - Fields: [ - { - Name: species, - Alias: fancyName, - PrimaryKey: false - } - ], GraphQL: { Singular: Shrub, Plural: Shrubs, @@ -1909,6 +1882,9 @@ ] } ], + Mappings: { + species: fancyName + }, Relationships: { fungus: { TargetEntity: Fungus, @@ -1928,13 +1904,6 @@ Object: fungi, Type: Table }, - Fields: [ - { - Name: spores, - Alias: hazards, - PrimaryKey: false - } - ], GraphQL: { Singular: fungus, Plural: fungi, @@ -1995,6 +1964,9 @@ ] } ], + Mappings: { + spores: hazards + }, Relationships: { Shrub: { TargetEntity: Shrub, @@ -2012,14 +1984,11 @@ books_view_all: { Source: { Object: books_view_all, - Type: View + Type: View, + KeyFields: [ + id + ] }, - Fields: [ - { - Name: id, - PrimaryKey: true - } - ], GraphQL: { Singular: books_view_all, Plural: books_view_alls, @@ -2061,15 +2030,11 @@ books_view_with_mapping: { Source: { Object: books_view_with_mapping, - Type: View + Type: View, + KeyFields: [ + id + ] }, - Fields: [ - { - Name: id, - Alias: book_id, - PrimaryKey: true - } - ], GraphQL: { Singular: books_view_with_mapping, Plural: books_view_with_mappings, @@ -2087,25 +2052,22 @@ } ] } - ] + ], + Mappings: { + id: book_id + } } }, { stocks_view_selected: { Source: { Object: stocks_view_selected, - Type: View + Type: View, + KeyFields: [ + categoryid, + pieceid + ] }, - Fields: [ - { - Name: categoryid, - PrimaryKey: true - }, - { - Name: pieceid, - PrimaryKey: true - } - ], GraphQL: { Singular: stocks_view_selected, Plural: stocks_view_selecteds, @@ -2147,18 +2109,12 @@ books_publishers_view_composite: { Source: { Object: books_publishers_view_composite, - Type: View + Type: View, + KeyFields: [ + id, + pub_id + ] }, - Fields: [ - { - Name: id, - PrimaryKey: true - }, - { - Name: pub_id, - PrimaryKey: true - } - ], GraphQL: { Singular: books_publishers_view_composite, Plural: books_publishers_view_composites, @@ -2412,28 +2368,6 @@ Object: aow, Type: Table }, - Fields: [ - { - Name: DetailAssessmentAndPlanning, - Alias: 始計, - PrimaryKey: false - }, - { - Name: WagingWar, - Alias: 作戰, - PrimaryKey: false - }, - { - Name: StrategicAttack, - Alias: 謀攻, - PrimaryKey: false - }, - { - Name: NoteNum, - Alias: ┬─┬ノ( º _ ºノ), - PrimaryKey: false - } - ], GraphQL: { Singular: ArtOfWar, Plural: ArtOfWars, @@ -2459,7 +2393,13 @@ } ] } - ] + ], + Mappings: { + DetailAssessmentAndPlanning: 始計, + NoteNum: ┬─┬ノ( º _ ºノ), + StrategicAttack: 謀攻, + WagingWar: 作戰 + } } }, { @@ -3186,18 +3126,6 @@ Object: GQLmappings, Type: Table }, - Fields: [ - { - Name: __column1, - Alias: column1, - PrimaryKey: false - }, - { - Name: __column2, - Alias: column2, - PrimaryKey: false - } - ], GraphQL: { Singular: GQLmappings, Plural: GQLmappings, @@ -3223,7 +3151,11 @@ } ] } - ] + ], + Mappings: { + __column1: column1, + __column2: column2 + } } }, { @@ -3266,18 +3198,6 @@ Object: mappedbookmarks, Type: Table }, - Fields: [ - { - Name: id, - Alias: bkid, - PrimaryKey: false - }, - { - Name: bkname, - Alias: name, - PrimaryKey: false - } - ], GraphQL: { Singular: MappedBookmarks, Plural: MappedBookmarks, @@ -3303,7 +3223,11 @@ } ] } - ] + ], + Mappings: { + bkname: name, + id: bkid + } } }, { @@ -3509,18 +3433,6 @@ Object: books, Type: Table }, - Fields: [ - { - Name: id, - Alias: id, - PrimaryKey: false - }, - { - Name: title, - Alias: title, - PrimaryKey: false - } - ], GraphQL: { Singular: bookNF, Plural: booksNF, @@ -3593,6 +3505,10 @@ ] } ], + Mappings: { + id: id, + title: title + }, Relationships: { authors: { Cardinality: Many, diff --git a/src/Service.Tests/Snapshots/ConfigurationTests.TestReadingRuntimeConfigForMySql.verified.txt b/src/Service.Tests/Snapshots/ConfigurationTests.TestReadingRuntimeConfigForMySql.verified.txt index 6a3a4c226c..f26f5f8c09 100644 --- a/src/Service.Tests/Snapshots/ConfigurationTests.TestReadingRuntimeConfigForMySql.verified.txt +++ b/src/Service.Tests/Snapshots/ConfigurationTests.TestReadingRuntimeConfigForMySql.verified.txt @@ -390,18 +390,6 @@ Object: books, Type: Table }, - Fields: [ - { - Name: id, - Alias: id, - PrimaryKey: false - }, - { - Name: title, - Alias: title, - PrimaryKey: false - } - ], GraphQL: { Singular: book, Plural: books, @@ -763,6 +751,10 @@ ] } ], + Mappings: { + id: id, + title: title + }, Relationships: { authors: { Cardinality: Many, @@ -1167,13 +1159,6 @@ Object: type_table, Type: Table }, - Fields: [ - { - Name: id, - Alias: typeid, - PrimaryKey: false - } - ], GraphQL: { Singular: SupportedType, Plural: SupportedTypes, @@ -1217,7 +1202,10 @@ } ] } - ] + ], + Mappings: { + id: typeid + } } }, { @@ -1269,18 +1257,6 @@ Object: trees, Type: Table }, - Fields: [ - { - Name: species, - Alias: Scientific Name, - PrimaryKey: false - }, - { - Name: region, - Alias: United State's Region, - PrimaryKey: false - } - ], GraphQL: { Singular: Tree, Plural: Trees, @@ -1324,7 +1300,11 @@ } ] } - ] + ], + Mappings: { + region: United State's Region, + species: Scientific Name + } } }, { @@ -1333,13 +1313,6 @@ Object: trees, Type: Table }, - Fields: [ - { - Name: species, - Alias: fancyName, - PrimaryKey: false - } - ], GraphQL: { Singular: Shrub, Plural: Shrubs, @@ -1385,6 +1358,9 @@ ] } ], + Mappings: { + species: fancyName + }, Relationships: { fungus: { TargetEntity: Fungus, @@ -1404,13 +1380,6 @@ Object: fungi, Type: Table }, - Fields: [ - { - Name: spores, - Alias: hazards, - PrimaryKey: false - } - ], GraphQL: { Singular: fungus, Plural: fungi, @@ -1471,6 +1440,9 @@ ] } ], + Mappings: { + spores: hazards + }, Relationships: { Shrub: { TargetEntity: Shrub, @@ -1488,14 +1460,11 @@ books_view_all: { Source: { Object: books_view_all, - Type: View + Type: View, + KeyFields: [ + id + ] }, - Fields: [ - { - Name: id, - PrimaryKey: true - } - ], GraphQL: { Singular: books_view_all, Plural: books_view_alls, @@ -1537,15 +1506,11 @@ books_view_with_mapping: { Source: { Object: books_view_with_mapping, - Type: View + Type: View, + KeyFields: [ + id + ] }, - Fields: [ - { - Name: id, - Alias: book_id, - PrimaryKey: true - } - ], GraphQL: { Singular: books_view_with_mapping, Plural: books_view_with_mappings, @@ -1563,25 +1528,22 @@ } ] } - ] + ], + Mappings: { + id: book_id + } } }, { stocks_view_selected: { Source: { Object: stocks_view_selected, - Type: View + Type: View, + KeyFields: [ + categoryid, + pieceid + ] }, - Fields: [ - { - Name: categoryid, - PrimaryKey: true - }, - { - Name: pieceid, - PrimaryKey: true - } - ], GraphQL: { Singular: stocks_view_selected, Plural: stocks_view_selecteds, @@ -1623,18 +1585,12 @@ books_publishers_view_composite: { Source: { Object: books_publishers_view_composite, - Type: View + Type: View, + KeyFields: [ + id, + pub_id + ] }, - Fields: [ - { - Name: id, - PrimaryKey: true - }, - { - Name: pub_id, - PrimaryKey: true - } - ], GraphQL: { Singular: books_publishers_view_composite, Plural: books_publishers_view_composites, @@ -1888,28 +1844,6 @@ Object: aow, Type: Table }, - Fields: [ - { - Name: DetailAssessmentAndPlanning, - Alias: 始計, - PrimaryKey: false - }, - { - Name: WagingWar, - Alias: 作戰, - PrimaryKey: false - }, - { - Name: StrategicAttack, - Alias: 謀攻, - PrimaryKey: false - }, - { - Name: NoteNum, - Alias: ┬─┬ノ( º _ ºノ), - PrimaryKey: false - } - ], GraphQL: { Singular: ArtOfWar, Plural: ArtOfWars, @@ -1935,7 +1869,13 @@ } ] } - ] + ], + Mappings: { + DetailAssessmentAndPlanning: 始計, + NoteNum: ┬─┬ノ( º _ ºノ), + StrategicAttack: 謀攻, + WagingWar: 作戰 + } } }, { @@ -2149,18 +2089,6 @@ Object: GQLmappings, Type: Table }, - Fields: [ - { - Name: __column1, - Alias: column1, - PrimaryKey: false - }, - { - Name: __column2, - Alias: column2, - PrimaryKey: false - } - ], GraphQL: { Singular: GQLmappings, Plural: GQLmappings, @@ -2186,7 +2114,11 @@ } ] } - ] + ], + Mappings: { + __column1: column1, + __column2: column2 + } } }, { @@ -2229,18 +2161,6 @@ Object: mappedbookmarks, Type: Table }, - Fields: [ - { - Name: id, - Alias: bkid, - PrimaryKey: false - }, - { - Name: bkname, - Alias: name, - PrimaryKey: false - } - ], GraphQL: { Singular: MappedBookmarks, Plural: MappedBookmarks, @@ -2266,7 +2186,11 @@ } ] } - ] + ], + Mappings: { + bkname: name, + id: bkid + } } }, { diff --git a/src/Service.Tests/Snapshots/ConfigurationTests.TestReadingRuntimeConfigForPostgreSql.verified.txt b/src/Service.Tests/Snapshots/ConfigurationTests.TestReadingRuntimeConfigForPostgreSql.verified.txt index 4373b266f4..28df6ae193 100644 --- a/src/Service.Tests/Snapshots/ConfigurationTests.TestReadingRuntimeConfigForPostgreSql.verified.txt +++ b/src/Service.Tests/Snapshots/ConfigurationTests.TestReadingRuntimeConfigForPostgreSql.verified.txt @@ -423,18 +423,6 @@ Object: books, Type: Table }, - Fields: [ - { - Name: id, - Alias: id, - PrimaryKey: false - }, - { - Name: title, - Alias: title, - PrimaryKey: false - } - ], GraphQL: { Singular: book, Plural: books, @@ -796,6 +784,10 @@ ] } ], + Mappings: { + id: id, + title: title + }, Relationships: { authors: { Cardinality: Many, @@ -1217,13 +1209,6 @@ Object: type_table, Type: Table }, - Fields: [ - { - Name: id, - Alias: typeid, - PrimaryKey: false - } - ], GraphQL: { Singular: SupportedType, Plural: SupportedTypes, @@ -1267,7 +1252,10 @@ } ] } - ] + ], + Mappings: { + id: typeid + } } }, { @@ -1340,18 +1328,6 @@ Object: trees, Type: Table }, - Fields: [ - { - Name: species, - Alias: Scientific Name, - PrimaryKey: false - }, - { - Name: region, - Alias: United State's Region, - PrimaryKey: false - } - ], GraphQL: { Singular: Tree, Plural: Trees, @@ -1395,7 +1371,11 @@ } ] } - ] + ], + Mappings: { + region: United State's Region, + species: Scientific Name + } } }, { @@ -1404,13 +1384,6 @@ Object: trees, Type: Table }, - Fields: [ - { - Name: species, - Alias: fancyName, - PrimaryKey: false - } - ], GraphQL: { Singular: Shrub, Plural: Shrubs, @@ -1456,6 +1429,9 @@ ] } ], + Mappings: { + species: fancyName + }, Relationships: { fungus: { TargetEntity: Fungus, @@ -1475,13 +1451,6 @@ Object: fungi, Type: Table }, - Fields: [ - { - Name: spores, - Alias: hazards, - PrimaryKey: false - } - ], GraphQL: { Singular: fungus, Plural: fungi, @@ -1542,6 +1511,9 @@ ] } ], + Mappings: { + spores: hazards + }, Relationships: { Shrub: { TargetEntity: Shrub, @@ -1727,15 +1699,11 @@ books_view_with_mapping: { Source: { Object: books_view_with_mapping, - Type: View + Type: View, + KeyFields: [ + id + ] }, - Fields: [ - { - Name: id, - Alias: book_id, - PrimaryKey: true - } - ], GraphQL: { Singular: books_view_with_mapping, Plural: books_view_with_mappings, @@ -1753,7 +1721,10 @@ } ] } - ] + ], + Mappings: { + id: book_id + } } }, { @@ -2031,28 +2002,6 @@ Object: aow, Type: Table }, - Fields: [ - { - Name: DetailAssessmentAndPlanning, - Alias: 始計, - PrimaryKey: false - }, - { - Name: WagingWar, - Alias: 作戰, - PrimaryKey: false - }, - { - Name: StrategicAttack, - Alias: 謀攻, - PrimaryKey: false - }, - { - Name: NoteNum, - Alias: ┬─┬ノ( º _ ºノ), - PrimaryKey: false - } - ], GraphQL: { Singular: ArtOfWar, Plural: ArtOfWars, @@ -2078,7 +2027,13 @@ } ] } - ] + ], + Mappings: { + DetailAssessmentAndPlanning: 始計, + NoteNum: ┬─┬ノ( º _ ºノ), + StrategicAttack: 謀攻, + WagingWar: 作戰 + } } }, { @@ -2196,18 +2151,6 @@ Object: gqlmappings, Type: Table }, - Fields: [ - { - Name: __column1, - Alias: column1, - PrimaryKey: false - }, - { - Name: __column2, - Alias: column2, - PrimaryKey: false - } - ], GraphQL: { Singular: GQLmappings, Plural: GQLmappings, @@ -2233,7 +2176,11 @@ } ] } - ] + ], + Mappings: { + __column1: column1, + __column2: column2 + } } }, { @@ -2276,18 +2223,6 @@ Object: mappedbookmarks, Type: Table }, - Fields: [ - { - Name: id, - Alias: bkid, - PrimaryKey: false - }, - { - Name: bkname, - Alias: name, - PrimaryKey: false - } - ], GraphQL: { Singular: MappedBookmarks, Plural: MappedBookmarks, @@ -2313,7 +2248,11 @@ } ] } - ] + ], + Mappings: { + bkname: name, + id: bkid + } } }, { @@ -2467,18 +2406,6 @@ Object: books, Type: Table }, - Fields: [ - { - Name: id, - Alias: id, - PrimaryKey: false - }, - { - Name: title, - Alias: title, - PrimaryKey: false - } - ], GraphQL: { Singular: bookNF, Plural: booksNF, @@ -2538,6 +2465,10 @@ ] } ], + Mappings: { + id: id, + title: title + }, Relationships: { authors: { Cardinality: Many, @@ -2659,18 +2590,6 @@ Object: dimaccount, Type: Table }, - Fields: [ - { - Name: parentaccountkey, - Alias: ParentAccountKey, - PrimaryKey: false - }, - { - Name: accountkey, - Alias: AccountKey, - PrimaryKey: false - } - ], GraphQL: { Singular: dbo_DimAccount, Plural: dbo_DimAccounts, @@ -2689,6 +2608,10 @@ ] } ], + Mappings: { + accountkey: AccountKey, + parentaccountkey: ParentAccountKey + }, Relationships: { child_accounts: { Cardinality: Many, diff --git a/src/Service.Tests/SqlTests/GraphQLQueryTests/GraphQLQueryTestBase.cs b/src/Service.Tests/SqlTests/GraphQLQueryTests/GraphQLQueryTestBase.cs index 16c1a878fa..fb0fce8211 100644 --- a/src/Service.Tests/SqlTests/GraphQLQueryTests/GraphQLQueryTestBase.cs +++ b/src/Service.Tests/SqlTests/GraphQLQueryTests/GraphQLQueryTestBase.cs @@ -2299,6 +2299,7 @@ public virtual async Task TestConfigTakesPrecedenceForRelationshipFieldsOverDB( Rest: new(Enabled: true), GraphQL: new("club", "clubs"), Permissions: new[] { ConfigurationTests.GetMinimalPermissionConfig(AuthorizationResolver.ROLE_ANONYMOUS) }, + Mcp: null, Relationships: null, Mappings: null ); @@ -2309,6 +2310,7 @@ public virtual async Task TestConfigTakesPrecedenceForRelationshipFieldsOverDB( Rest: new(Enabled: true), GraphQL: new("player", "players"), Permissions: new[] { ConfigurationTests.GetMinimalPermissionConfig(AuthorizationResolver.ROLE_ANONYMOUS) }, + Mcp: null, Relationships: new Dictionary() { {"clubs", new ( Cardinality: Cardinality.One, TargetEntity: "Club", @@ -2371,4 +2373,3 @@ public virtual async Task TestConfigTakesPrecedenceForRelationshipFieldsOverDB( #endregion } } - diff --git a/src/Service.Tests/SqlTests/GraphQLQueryTests/MsSqlGraphQLQueryTests.cs b/src/Service.Tests/SqlTests/GraphQLQueryTests/MsSqlGraphQLQueryTests.cs index 1d90a4c6f1..3b5962db37 100644 --- a/src/Service.Tests/SqlTests/GraphQLQueryTests/MsSqlGraphQLQueryTests.cs +++ b/src/Service.Tests/SqlTests/GraphQLQueryTests/MsSqlGraphQLQueryTests.cs @@ -873,7 +873,8 @@ private static Entity CreateEntityWithDescription(string description) gqlOptions, null, restOptions, - [], + null, + Array.Empty(), null, null, null, diff --git a/src/Service.Tests/TestHelper.cs b/src/Service.Tests/TestHelper.cs index b94470b96b..ef5840a362 100644 --- a/src/Service.Tests/TestHelper.cs +++ b/src/Service.Tests/TestHelper.cs @@ -95,6 +95,7 @@ public static RuntimeConfig AddMissingEntitiesToConfig(RuntimeConfig config, str Fields: fields, GraphQL: new(entityKey, entityKey.Pluralize()), Rest: new(Enabled: true), + Mcp: null, Permissions: new[] { new EntityPermission("anonymous", new EntityAction[] { @@ -371,3 +372,4 @@ public static string AddPropertiesToJson(string configuration, string entityProp } } } + diff --git a/src/Service.Tests/UnitTests/ConfigValidationUnitTests.cs b/src/Service.Tests/UnitTests/ConfigValidationUnitTests.cs index 119e6637c6..553adec3b5 100644 --- a/src/Service.Tests/UnitTests/ConfigValidationUnitTests.cs +++ b/src/Service.Tests/UnitTests/ConfigValidationUnitTests.cs @@ -120,6 +120,7 @@ public void InvalidCRUDForStoredProcedure( Rest: new(EntityRestOptions.DEFAULT_HTTP_VERBS_ENABLED_FOR_SP), GraphQL: new(AuthorizationHelpers.TEST_ENTITY, AuthorizationHelpers.TEST_ENTITY + "s"), Permissions: permissionSettings.ToArray(), + Mcp: null, Relationships: null, Mappings: null ); @@ -1005,6 +1006,7 @@ public void TestOperationValidityAndCasing(string operationName, bool exceptionE Rest: null, GraphQL: null, Permissions: new[] { permissionForEntity }, + Mcp: null, Relationships: null, Mappings: null ); @@ -1543,6 +1545,7 @@ private static Entity GetSampleEntityUsingSourceAndRelationshipMap( Rest: restDetails ?? new(Enabled: false), GraphQL: graphQLDetails, Permissions: new[] { permissionForEntity }, + Mcp: null, Relationships: relationshipMap, Mappings: null ); @@ -2019,6 +2022,7 @@ public void ValidateRestMethodsForEntityInConfig( Rest: new(Methods: methods), GraphQL: new(entityName, ""), Permissions: Array.Empty(), + Mcp: null, Relationships: new(), Mappings: new()); entityMap.Add(entityName, entity); @@ -2345,6 +2349,7 @@ public void TestRuntimeConfigSetupWithNonJsonConstructor() GraphQL: null, Rest: null, Permissions: null, + Mcp: null, Mappings: null, Relationships: null); @@ -2519,3 +2524,4 @@ private static RuntimeConfigValidator InitializeRuntimeConfigValidator() } } } + diff --git a/src/Service.Tests/UnitTests/RequestValidatorUnitTests.cs b/src/Service.Tests/UnitTests/RequestValidatorUnitTests.cs index 5be1375c0f..d4dc7e3735 100644 --- a/src/Service.Tests/UnitTests/RequestValidatorUnitTests.cs +++ b/src/Service.Tests/UnitTests/RequestValidatorUnitTests.cs @@ -361,7 +361,7 @@ public static void PerformTest( ), Entities: new(new Dictionary() { - { DEFAULT_NAME, new Entity(entitySource, new EntityGraphQLOptions(findRequestContext.EntityName, findRequestContext.EntityName), null, new EntityRestOptions(new SupportedHttpVerb[0]), null, null, null) } + { DEFAULT_NAME, new Entity(entitySource, new EntityGraphQLOptions(findRequestContext.EntityName, findRequestContext.EntityName), null, new EntityRestOptions(new SupportedHttpVerb[0]), null, null, null, null) } }) ); MockFileSystem fileSystem = new(); @@ -492,3 +492,4 @@ public static DatabaseObject GetDbo(string schema, string name) } } } + diff --git a/src/Service.Tests/UnitTests/SqlMetadataProviderUnitTests.cs b/src/Service.Tests/UnitTests/SqlMetadataProviderUnitTests.cs index 8b4ed68f60..3e9c343608 100644 --- a/src/Service.Tests/UnitTests/SqlMetadataProviderUnitTests.cs +++ b/src/Service.Tests/UnitTests/SqlMetadataProviderUnitTests.cs @@ -351,6 +351,7 @@ public void ValidateGraphQLReservedNaming_DatabaseColumns(string dbColumnName, s Rest: new(Enabled: false), GraphQL: new("", ""), Permissions: new EntityPermission[] { ConfigurationTests.GetMinimalPermissionConfig(AuthorizationResolver.ROLE_ANONYMOUS) }, + Mcp: null, Relationships: null, Mappings: columnNameMappings ); @@ -427,6 +428,7 @@ public async Task ValidateExceptionForInvalidResultFieldNames(string invalidFiel Fields: null, Rest: new(Enabled: true), GraphQL: new("get_book_by_id", "get_book_by_ids", Enabled: true), + Mcp: null, Permissions: new EntityPermission[] { new( Role: "anonymous", @@ -590,3 +592,4 @@ private static async Task SetupTestFixtureAndInferMetadata() } } } + diff --git a/src/Service.Tests/dab-config.CosmosDb_NoSql.json b/src/Service.Tests/dab-config.CosmosDb_NoSql.json index 5704dc19be..c83c8adba4 100644 --- a/src/Service.Tests/dab-config.CosmosDb_NoSql.json +++ b/src/Service.Tests/dab-config.CosmosDb_NoSql.json @@ -20,6 +20,10 @@ "path": "/graphql", "allow-introspection": true }, + "mcp": { + "enabled": true, + "path": "/mcp" + }, "host": { "cors": { "origins": [ @@ -31,12 +35,6 @@ "provider": "StaticWebApps" }, "mode": "development" - }, - "telemetry": { - "app-insights": { - "enabled": true, - "connection-string": "InstrumentationKey=00000000-0000-0000-0000-000000000000;IngestionEndpoint=https://dc.services.visualstudio.com/v2/track" - } } }, "entities": { @@ -44,6 +42,9 @@ "source": { "object": "graphqldb.planet" }, + "rest": { + "enabled": false + }, "graphql": { "enabled": true, "type": { @@ -51,9 +52,6 @@ "plural": "Planets" } }, - "rest": { - "enabled": false - }, "permissions": [ { "role": "anonymous", @@ -117,6 +115,9 @@ "source": { "object": "graphqldb.planet" }, + "rest": { + "enabled": false + }, "graphql": { "enabled": true, "type": { @@ -124,9 +125,6 @@ "plural": "Characters" } }, - "rest": { - "enabled": false - }, "permissions": [ { "role": "anonymous", @@ -159,6 +157,9 @@ "source": { "object": "graphqldb.planet" }, + "rest": { + "enabled": false + }, "graphql": { "enabled": true, "type": { @@ -166,9 +167,6 @@ "plural": "Stars" } }, - "rest": { - "enabled": false - }, "permissions": [ { "role": "anonymous", @@ -210,6 +208,9 @@ "source": { "object": "graphqldb.planet" }, + "rest": { + "enabled": false + }, "graphql": { "enabled": true, "type": { @@ -217,9 +218,6 @@ "plural": "Tags" } }, - "rest": { - "enabled": false - }, "permissions": [ { "role": "anonymous", @@ -244,6 +242,9 @@ "source": { "object": "graphqldb.planet" }, + "rest": { + "enabled": false + }, "graphql": { "enabled": true, "type": { @@ -251,9 +252,6 @@ "plural": "Moons" } }, - "rest": { - "enabled": false - }, "permissions": [ { "role": "anonymous", @@ -295,6 +293,9 @@ "source": { "object": "graphqldb.planet" }, + "rest": { + "enabled": false + }, "graphql": { "enabled": true, "type": { @@ -302,9 +303,6 @@ "plural": "Earths" } }, - "rest": { - "enabled": false - }, "permissions": [ { "role": "field-mutation-with-read-permission", @@ -390,6 +388,9 @@ "source": { "object": "graphqldb.planet" }, + "rest": { + "enabled": false + }, "graphql": { "enabled": true, "type": { @@ -397,9 +398,6 @@ "plural": "Suns" } }, - "rest": { - "enabled": false - }, "permissions": [ { "role": "anonymous", @@ -432,6 +430,9 @@ "source": { "object": "graphqldb.planet" }, + "rest": { + "enabled": false + }, "graphql": { "enabled": true, "type": { @@ -439,9 +440,6 @@ "plural": "AdditionalAttributes" } }, - "rest": { - "enabled": false - }, "permissions": [ { "role": "anonymous", @@ -468,6 +466,9 @@ "source": { "object": "graphqldb.planet" }, + "rest": { + "enabled": false + }, "graphql": { "enabled": true, "type": { @@ -475,9 +476,6 @@ "plural": "MoonAdditionalAttributes" } }, - "rest": { - "enabled": false - }, "permissions": [ { "role": "anonymous", @@ -504,6 +502,9 @@ "source": { "object": "graphqldb.planet" }, + "rest": { + "enabled": false + }, "graphql": { "enabled": true, "type": { @@ -511,9 +512,6 @@ "plural": "MoreAttributes" } }, - "rest": { - "enabled": false - }, "permissions": [ { "role": "anonymous", @@ -576,6 +574,9 @@ "source": { "object": "graphqldb.newcontainer" }, + "rest": { + "enabled": false + }, "graphql": { "enabled": true, "type": { @@ -583,9 +584,6 @@ "plural": "PlanetAgains" } }, - "rest": { - "enabled": false - }, "permissions": [ { "role": "field-mutation-with-read-permission", @@ -731,6 +729,9 @@ "source": { "object": "graphqldb.invalidAuthModelContainer" }, + "rest": { + "enabled": false + }, "graphql": { "enabled": true, "type": { @@ -738,9 +739,6 @@ "plural": "InvalidAuthModels" } }, - "rest": { - "enabled": false - }, "permissions": [ { "role": "anonymous", @@ -800,4 +798,4 @@ ] } } -} +} \ No newline at end of file diff --git a/src/Service.Tests/dab-config.DwSql.json b/src/Service.Tests/dab-config.DwSql.json index 78f9e91480..737964cc04 100644 --- a/src/Service.Tests/dab-config.DwSql.json +++ b/src/Service.Tests/dab-config.DwSql.json @@ -1,2721 +1,2871 @@ -{ - "$schema": "https://github.com/Azure/data-api-builder/releases/download/vmajor.minor.patch/dab.draft.schema.json", - "data-source": { - "database-type": "dwsql", - "connection-string": "Server=tcp:127.0.0.1,1433;Persist Security Info=False;User ID=sa;Password=REPLACEME;MultipleActiveResultSets=False;Connection Timeout=5;", - "options": { - "set-session-context": true - } - }, - "runtime": { - "rest": { - "enabled": true, - "path": "/api", - "request-body-strict": true - }, - "graphql": { - "enabled": true, - "path": "/graphql", - "allow-introspection": true - }, - "host": { - "cors": { - "origins": [ - "http://localhost:5000" - ], - "allow-credentials": false - }, - "authentication": { - "provider": "StaticWebApps" - }, - "mode": "development" - } - }, - "entities": { - "Publisher": { - "source": { - "object": "publishers", - "type": "table", - "key-fields": [ - "id" - ] - }, - "graphql": { - "enabled": true, - "type": { - "singular": "Publisher", - "plural": "Publishers" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "read" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "policy_tester_01", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.id eq 1940" - } - }, - { - "action": "update", - "fields": { - "exclude": [], - "include": [ - "*" - ] - } - }, - { - "action": "create" - }, - { - "action": "delete" - } - ] - }, - { - "role": "policy_tester_02", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.id ne 1940" - } - }, - { - "action": "update", - "fields": { - "exclude": [], - "include": [ - "*" - ] - } - }, - { - "action": "create" - }, - { - "action": "delete" - } - ] - }, - { - "role": "policy_tester_03", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.id ne 1940" - } - }, - { - "action": "update", - "fields": { - "exclude": [], - "include": [ - "*" - ] - } - }, - { - "action": "create" - }, - { - "action": "delete" - } - ] - }, - { - "role": "policy_tester_04", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.id eq 1940" - } - }, - { - "action": "update", - "fields": { - "exclude": [], - "include": [ - "*" - ] - } - }, - { - "action": "create" - }, - { - "action": "delete" - } - ] - }, - { - "role": "policy_tester_06", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.id eq 1940" - } - }, - { - "action": "update", - "fields": { - "exclude": [], - "include": [ - "*" - ] - } - }, - { - "action": "create" - }, - { - "action": "delete" - } - ] - }, - { - "role": "database_policy_tester", - "actions": [ - { - "action": "create", - "policy": { - "database": "@item.name ne 'New publisher'" - } - }, - { - "action": "update", - "policy": { - "database": "@item.id ne 1234" - } - }, - { - "action": "read", - "policy": { - "database": "@item.id ne 1234 or @item.id gt 1940" - } - } - ] - } - ], - "relationships": { - "books": { - "cardinality": "many", - "target.entity": "Book", - "source.fields": [ - "id" - ], - "target.fields": [ - "publisher_id" - ], - "linking.source.fields": [], - "linking.target.fields": [] - } - } - }, - "Stock": { - "source": { - "object": "stocks", - "type": "table", - "key-fields": [ - "categoryid", - "pieceid" - ] - }, - "graphql": { - "enabled": true, - "type": { - "singular": "Stock", - "plural": "Stocks" - } - }, - "rest": { - "enabled": true, - "path": "/commodities" - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "TestNestedFilterFieldIsNull_ColumnForbidden", - "actions": [ - { - "action": "read" - } - ] - }, - { - "role": "TestNestedFilterFieldIsNull_EntityReadForbidden", - "actions": [ - { - "action": "read" - } - ] - }, - { - "role": "database_policy_tester", - "actions": [ - { - "action": "read" - }, - { - "action": "update", - "policy": { - "database": "@item.pieceid ne 1" - } - } - ] - }, - { - "role": "test_role_with_noread", - "actions": [ - { - "action": "create" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "test_role_with_excluded_fields", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [ - "categoryName" - ] - } - }, - { - "action": "create" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "test_role_with_policy_excluded_fields", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [ - "categoryName" - ] - }, - "policy": { - "database": "@item.piecesAvailable ne 0" - } - }, - { - "action": "create" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - } - ] - }, - "stocks_price": { - "source": { - "object": "stocks_price", - "type": "table", - "key-fields": [ - "categoryid", - "pieceid", - "instant" - ] - }, - "graphql": { - "enabled": true, - "type": { - "singular": "stocks_price", - "plural": "stocks_prices" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "anonymous", - "actions": [ - { - "action": "read" - } - ] - }, - { - "role": "TestNestedFilterFieldIsNull_ColumnForbidden", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [ - "price" - ] - } - } - ] - }, - { - "role": "TestNestedFilterFieldIsNull_EntityReadForbidden", - "actions": [ - { - "action": "create" - } - ] - } - ] - }, - "Book": { - "source": { - "object": "books", - "type": "table", - "key-fields": [ - "id" - ] - }, - "graphql": { - "enabled": true, - "type": { - "singular": "book", - "plural": "books" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "policy_tester_01", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.title eq 'Policy-Test-01'" - } - }, - { - "action": "update", - "fields": { - "exclude": [], - "include": [ - "*" - ] - } - }, - { - "action": "create" - }, - { - "action": "delete" - } - ] - }, - { - "role": "policy_tester_02", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.title ne 'Policy-Test-01'" - } - }, - { - "action": "update", - "fields": { - "exclude": [], - "include": [ - "*" - ] - } - }, - { - "action": "create" - }, - { - "action": "delete" - } - ] - }, - { - "role": "policy_tester_03", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.title eq 'Policy-Test-01'" - } - }, - { - "action": "update", - "fields": { - "exclude": [], - "include": [ - "*" - ] - } - }, - { - "action": "create" - }, - { - "action": "delete" - } - ] - }, - { - "role": "policy_tester_04", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.title ne 'Policy-Test-01'" - } - }, - { - "action": "update", - "fields": { - "exclude": [], - "include": [ - "*" - ] - } - }, - { - "action": "create" - }, - { - "action": "delete" - } - ] - }, - { - "role": "policy_tester_05", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.id ne 9" - } - }, - { - "action": "update", - "fields": { - "exclude": [], - "include": [ - "*" - ] - } - }, - { - "action": "create" - }, - { - "action": "delete" - } - ] - }, - { - "role": "policy_tester_06", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.id ne 10" - } - }, - { - "action": "create" - }, - { - "action": "delete" - }, - { - "action": "update", - "fields": { - "exclude": [], - "include": [ - "*" - ] - } - } - ] - }, - { - "role": "policy_tester_07", - "actions": [ - { - "action": "delete", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.id ne 9" - } - }, - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - } - }, - { - "action": "update", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.id ne 9" - } - }, - { - "action": "create" - } - ] - }, - { - "role": "policy_tester_08", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - } - }, - { - "action": "delete", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.id eq 9" - } - }, - { - "action": "update", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.id eq 9" - } - }, - { - "action": "create" - } - ] - }, - { - "role": "test_role_with_noread", - "actions": [ - { - "action": "create" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "test_role_with_excluded_fields", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [ - "publisher_id" - ] - } - }, - { - "action": "create" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "test_role_with_policy_excluded_fields", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [ - "publisher_id" - ] - }, - "policy": { - "database": "@item.title ne 'Test'" - } - }, - { - "action": "create" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - } - ], - "mappings": { - "id": "id", - "title": "title" - }, - "relationships": { - "websiteplacement": { - "cardinality": "one", - "target.entity": "BookWebsitePlacement", - "source.fields": [ - "id" - ], - "target.fields": [ - "book_id" - ], - "linking.source.fields": [], - "linking.target.fields": [] - }, - "publishers": { - "cardinality": "one", - "target.entity": "Publisher", - "source.fields": [ - "publisher_id" - ], - "target.fields": [ - "id" - ], - "linking.source.fields": [], - "linking.target.fields": [] - }, - "reviews": { - "cardinality": "many", - "target.entity": "Review", - "source.fields": [ - "id" - ], - "target.fields": [ - "book_id" - ], - "linking.source.fields": [], - "linking.target.fields": [] - }, - "authors": { - "cardinality": "many", - "target.entity": "Author", - "source.fields": [ - "id" - ], - "target.fields": [ - "id" - ], - "linking.object": "book_author_link", - "linking.source.fields": [ - "book_id" - ], - "linking.target.fields": [ - "author_id" - ] - } - } - }, - "BookWebsitePlacement": { - "source": { - "object": "book_website_placements", - "type": "table", - "key-fields": [ - "id" - ] - }, - "graphql": { - "enabled": true, - "type": { - "singular": "BookWebsitePlacement", - "plural": "BookWebsitePlacements" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "read" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "delete", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@claims.userId eq @item.id" - } - }, - { - "action": "create" - }, - { - "action": "update" - } - ] - } - ], - "relationships": { - "books": { - "cardinality": "one", - "target.entity": "Book", - "source.fields": [ - "book_id" - ], - "target.fields": [ - "id" - ], - "linking.source.fields": [], - "linking.target.fields": [] - } - } - }, - "Author": { - "source": { - "object": "authors", - "type": "table", - "key-fields": [ - "id" - ] - }, - "graphql": { - "enabled": true, - "type": { - "singular": "Author", - "plural": "Authors" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "read" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - } - ], - "relationships": { - "books": { - "cardinality": "many", - "target.entity": "Book", - "source.fields": [ - "id" - ], - "target.fields": [ - "id" - ], - "linking.object": "book_author_link", - "linking.source.fields": [ - "author_id" - ], - "linking.target.fields": [ - "book_id" - ] - } - } - }, - "Review": { - "source": { - "object": "reviews", - "type": "table", - "key-fields": [ - "book_id", - "id" - ] - }, - "graphql": { - "enabled": true, - "type": { - "singular": "review", - "plural": "reviews" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - } - ], - "relationships": { - "books": { - "cardinality": "one", - "target.entity": "Book", - "source.fields": [ - "book_id" - ], - "target.fields": [ - "id" - ], - "linking.source.fields": [], - "linking.target.fields": [] - } - } - }, - "Comic": { - "source": { - "object": "comics", - "type": "table", - "key-fields": [ - "id" - ] - }, - "graphql": { - "enabled": true, - "type": { - "singular": "Comic", - "plural": "Comics" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "TestNestedFilterManyOne_ColumnForbidden", - "actions": [ - { - "action": "read" - } - ] - }, - { - "role": "TestNestedFilterManyOne_EntityReadForbidden", - "actions": [ - { - "action": "read" - } - ] - }, - { - "role": "TestNestedFilterOneMany_ColumnForbidden", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [ - "categoryName" - ] - } - } - ] - }, - { - "role": "TestNestedFilterOneMany_EntityReadForbidden", - "actions": [ - { - "action": "create" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - } - ], - "relationships": { - "myseries": { - "cardinality": "one", - "target.entity": "series", - "source.fields": [ - "series_id" - ], - "target.fields": [ - "id" - ], - "linking.source.fields": [], - "linking.target.fields": [] - } - } - }, - "Broker": { - "source": { - "object": "brokers", - "type": "table", - "key-fields": [ - "ID Number" - ] - }, - "graphql": { - "enabled": false, - "type": { - "singular": "Broker", - "plural": "Brokers" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "read" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "update" - }, - { - "action": "read" - }, - { - "action": "delete" - } - ] - } - ] - }, - "WebsiteUser": { - "source": { - "object": "website_users", - "type": "table", - "key-fields": [ - "id" - ] - }, - "graphql": { - "enabled": true, - "type": { - "singular": "websiteUser", - "plural": "websiteUsers" - } - }, - "rest": { - "enabled": false - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "delete" - }, - { - "action": "update" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "delete" - }, - { - "action": "update" - } - ] - } - ] - }, - "SupportedType": { - "source": { - "object": "type_table", - "type": "table", - "key-fields": [ - "id" - ] - }, - "graphql": { - "enabled": true, - "type": { - "singular": "SupportedType", - "plural": "SupportedTypes" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "delete" - }, - { - "action": "update" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "delete" - }, - { - "action": "update" - } - ] - } - ], - "mappings": { - "id": "typeid" - } - }, - "Tree": { - "source": { - "object": "trees", - "type": "table", - "key-fields": [ - "treeId" - ] - }, - "graphql": { - "enabled": false, - "type": { - "singular": "Tree", - "plural": "Trees" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - } - ], - "mappings": { - "species": "Scientific Name", - "region": "United State's Region" - } - }, - "Shrub": { - "source": { - "object": "trees", - "type": "table", - "key-fields": [ - "treeId" - ] - }, - "graphql": { - "enabled": true, - "type": { - "singular": "Shrub", - "plural": "Shrubs" - } - }, - "rest": { - "enabled": true, - "path": "/plants" - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - } - ], - "mappings": { - "species": "fancyName" - }, - "relationships": { - "fungus": { - "cardinality": "one", - "target.entity": "Fungus", - "source.fields": [ - "species" - ], - "target.fields": [ - "habitat" - ], - "linking.source.fields": [], - "linking.target.fields": [] - } - } - }, - "Fungus": { - "source": { - "object": "fungi", - "type": "table", - "key-fields": [ - "speciesid" - ] - }, - "graphql": { - "enabled": true, - "type": { - "singular": "fungus", - "plural": "fungi" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "policy_tester_01", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.region ne 'northeast'" - } - } - ] - } - ], - "mappings": { - "spores": "hazards" - }, - "relationships": { - "Shrub": { - "cardinality": "one", - "target.entity": "Shrub", - "source.fields": [ - "habitat" - ], - "target.fields": [ - "species" - ], - "linking.source.fields": [], - "linking.target.fields": [] - } - } - }, - "books_view_all": { - "source": { - "object": "books_view_all", - "type": "view", - "key-fields": [ - "id" - ] - }, - "graphql": { - "enabled": true, - "type": { - "singular": "books_view_all", - "plural": "books_view_alls" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - } - ] - }, - "books_view_with_mapping": { - "source": { - "object": "books_view_with_mapping", - "type": "view", - "key-fields": [ - "id" - ] - }, - "graphql": { - "enabled": true, - "type": { - "singular": "books_view_with_mapping", - "plural": "books_view_with_mappings" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - } - ], - "mappings": { - "id": "book_id" - } - }, - "series": { - "source": { - "object": "series", - "type": "table", - "key-fields": [ - "id" - ] - }, - "graphql": { - "enabled": true, - "type": { - "singular": "series", - "plural": "series" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - }, - { - "role": "TestNestedFilterManyOne_EntityReadForbidden", - "actions": [ - { - "action": "create" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "TestNestedFilterManyOne_ColumnForbidden", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [ - "name" - ] - } - } - ] - }, - { - "role": "TestNestedFilterOneMany_ColumnForbidden", - "actions": [ - { - "action": "read" - } - ] - }, - { - "role": "TestNestedFilterOneMany_EntityReadForbidden", - "actions": [ - { - "action": "read" - } - ] - } - ], - "relationships": { - "comics": { - "cardinality": "many", - "target.entity": "Comic", - "source.fields": [ - "id" - ], - "target.fields": [ - "series_id" - ], - "linking.source.fields": [], - "linking.target.fields": [] - } - } - }, - "Sales": { - "source": { - "object": "sales", - "type": "table", - "key-fields": [ - "id" - ] - }, - "graphql": { - "enabled": true, - "type": { - "singular": "Sales", - "plural": "Sales" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "*" - } - ] - } - ] - }, - "GQLmappings": { - "source": { - "object": "GQLmappings", - "type": "table", - "key-fields": [ - "__column1" - ] - }, - "graphql": { - "enabled": true, - "type": { - "singular": "GQLmappings", - "plural": "GQLmappings" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "*" - } - ] - } - ], - "mappings": { - "__column1": "column1", - "__column2": "column2" - } - }, - "Bookmarks": { - "source": { - "object": "bookmarks", - "type": "table", - "key-fields": [ - "id" - ] - }, - "graphql": { - "enabled": true, - "type": { - "singular": "Bookmarks", - "plural": "Bookmarks" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "*" - } - ] - } - ] - }, - "MappedBookmarks": { - "source": { - "object": "mappedbookmarks", - "type": "table", - "key-fields": [ - "id" - ] - }, - "graphql": { - "enabled": true, - "type": { - "singular": "MappedBookmarks", - "plural": "MappedBookmarks" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "*" - } - ] - } - ], - "mappings": { - "id": "bkid", - "bkname": "name" - } - }, - "books_publishers_view_composite": { - "source": { - "object": "books_publishers_view_composite", - "type": "view", - "key-fields": [ - "id", - "pub_id" - ] - }, - "graphql": { - "enabled": true, - "type": { - "singular": "books_publishers_view_composite", - "plural": "books_publishers_view_composites" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - } - ] - }, - "Empty": { - "source": { - "object": "empty_table", - "type": "table", - "key-fields": [ - "id" - ] - }, - "graphql": { - "enabled": true, - "type": { - "singular": "Empty", - "plural": "Empties" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "anonymous", - "actions": [ - { - "action": "read" - } - ] - } - ] - }, - "Notebook": { - "source": { - "object": "notebooks", - "type": "table", - "key-fields": [ - "id" - ] - }, - "graphql": { - "enabled": true, - "type": { - "singular": "Notebook", - "plural": "Notebooks" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "create" - }, - { - "action": "update" - }, - { - "action": "delete" - }, - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item ne 1" - } - } - ] - } - ] - }, - "Journal": { - "source": { - "object": "journals", - "type": "table", - "key-fields": [ - "id" - ] - }, - "graphql": { - "enabled": true, - "type": { - "singular": "Journal", - "plural": "Journals" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "policy_tester_noupdate", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - } - }, - { - "action": "update", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.id ne 1" - } - }, - { - "action": "create" - }, - { - "action": "delete" - } - ] - }, - { - "role": "policy_tester_update_noread", - "actions": [ - { - "action": "delete", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.id eq 1" - } - }, - { - "action": "read", - "fields": { - "exclude": [ - "*" - ] - } - }, - { - "action": "update", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.id eq 1" - } - }, - { - "action": "create" - } - ] - }, - { - "role": "authorizationHandlerTester", - "actions": [ - { - "action": "read" - } - ] - } - ] - }, - "ArtOfWar": { - "source": { - "object": "aow", - "type": "table", - "key-fields": [ - "NoteNum" - ] - }, - "graphql": { - "enabled": false, - "type": { - "singular": "ArtOfWar", - "plural": "ArtOfWars" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "*" - } - ] - } - ], - "mappings": { - "DetailAssessmentAndPlanning": "始計", - "WagingWar": "作戰", - "StrategicAttack": "謀攻", - "NoteNum": "┬─┬ノ( º _ ºノ)" - } - }, - "stocks_view_selected": { - "source": { - "object": "stocks_view_selected", - "type": "view", - "key-fields": [ - "categoryid", - "pieceid" - ] - }, - "graphql": { - "enabled": true, - "type": { - "singular": "stocks_view_selected", - "plural": "stocks_view_selecteds" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - } - ] - }, - "GetBook": { - "source": { - "object": "get_book_by_id", - "type": "stored-procedure" - }, - "graphql": { - "enabled": false, - "operation": "mutation", - "type": { - "singular": "GetBook", - "plural": "GetBooks" - } - }, - "rest": { - "enabled": true, - "methods": [ - "get" - ] - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "execute" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "execute" - } - ] - } - ] - }, - "GetBooks": { - "source": { - "object": "get_books", - "type": "stored-procedure" - }, - "graphql": { - "enabled": true, - "operation": "query", - "type": { - "singular": "GetBooks", - "plural": "GetBooks" - } - }, - "rest": { - "enabled": true, - "methods": [ - "get" - ] - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "execute" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "execute" - } - ] - } - ] - }, - "GetPublisher": { - "source": { - "object": "get_publisher_by_id", - "type": "stored-procedure" - }, - "graphql": { - "enabled": true, - "operation": "query", - "type": { - "singular": "GetPublisher", - "plural": "GetPublishers" - } - }, - "rest": { - "enabled": true, - "methods": [ - "post" - ] - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "execute" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "execute" - } - ] - } - ] - }, - "GetAuthorsHistoryByFirstName": { - "source": { - "object": "get_authors_history_by_first_name", - "type": "stored-procedure", - "parameters": { - "firstName": "Aaron" - } - }, - "graphql": { - "enabled": true, - "operation": "mutation", - "type": { - "singular": "SearchAuthorByFirstName", - "plural": "SearchAuthorByFirstNames" - } - }, - "rest": { - "enabled": true, - "methods": [ - "post" - ] - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "execute" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "execute" - } - ] - } - ] - }, - "CountBooks": { - "source": { - "object": "count_books", - "type": "stored-procedure" - }, - "graphql": { - "enabled": true, - "operation": "mutation", - "type": { - "singular": "CountBooks", - "plural": "CountBooks" - } - }, - "rest": { - "enabled": true, - "methods": [ - "post" - ] - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "execute" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "execute" - } - ] - } - ] - }, - "InsertBook": { - "source": { - "object": "insert_book", - "type": "stored-procedure", - "parameters": { - "title": "randomX", - "publisher_id": 1234 - } - }, - "graphql": { - "enabled": true, - "operation": "mutation", - "type": { - "singular": "InsertBook", - "plural": "InsertBooks" - } - }, - "rest": { - "enabled": true, - "methods": [ - "post" - ] - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "execute" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "execute" - } - ] - } - ] - }, - "DeleteLastInsertedBook": { - "source": { - "object": "delete_last_inserted_book", - "type": "stored-procedure" - }, - "graphql": { - "enabled": true, - "operation": "mutation", - "type": { - "singular": "DeleteLastInsertedBook", - "plural": "DeleteLastInsertedBooks" - } - }, - "rest": { - "enabled": true, - "methods": [ - "post" - ] - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "execute" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "execute" - } - ] - } - ] - }, - "UpdateBookTitle": { - "source": { - "object": "update_book_title", - "type": "stored-procedure", - "parameters": { - "id": 1, - "title": "Testing Tonight" - } - }, - "graphql": { - "enabled": true, - "operation": "mutation", - "type": { - "singular": "UpdateBookTitle", - "plural": "UpdateBookTitles" - } - }, - "rest": { - "enabled": true, - "methods": [ - "post" - ] - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "execute" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "execute" - } - ] - } - ] - }, - "InsertAndDisplayAllBooksUnderGivenPublisher": { - "source": { - "object": "insert_and_display_all_books_for_given_publisher", - "type": "stored-procedure", - "parameters": { - "title": "MyTitle", - "publisher_name": "MyPublisher" - } - }, - "graphql": { - "enabled": true, - "operation": "mutation", - "type": { - "singular": "InsertAndDisplayAllBooksUnderGivenPublisher", - "plural": "InsertAndDisplayAllBooksUnderGivenPublishers" - } - }, - "rest": { - "enabled": true, - "methods": [ - "post" - ] - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "execute" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "execute" - } - ] - } - ] - }, - "DateOnlyTable": { - "source": { - "object": "date_only_table", - "type": "table", - "key-fields": [ - "event_date" - ] - }, - "graphql": { - "enabled": true, - "type": { - "singular": "DateOnlyTable", - "plural": "DateOnlyTables" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - } - ] - }, - "dbo_DimAccount": { - "source": { - "object": "DimAccount", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "dbo_DimAccount", - "plural": "dbo_DimAccounts" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - } - ], - "relationships": { - "parent_account": { - "cardinality": "one", - "target.entity": "dbo_DimAccount", - "source.fields": [ - "ParentAccountKey" - ], - "target.fields": [ - "AccountKey" - ], - "linking.source.fields": [], - "linking.target.fields": [] - }, - "child_accounts": { - "cardinality": "many", - "target.entity": "dbo_DimAccount", - "source.fields": [ - "AccountKey" - ], - "target.fields": [ - "ParentAccountKey" - ], - "linking.source.fields": [], - "linking.target.fields": [] - } - } - } - } -} \ No newline at end of file +{ + "$schema": "https://github.com/Azure/data-api-builder/releases/download/vmajor.minor.patch/dab.draft.schema.json", + "data-source": { + "database-type": "dwsql", + "connection-string": "Server=tcp:127.0.0.1,1433;Persist Security Info=False;User ID=sa;Password=REPLACEME;MultipleActiveResultSets=False;Connection Timeout=5;", + "options": { + "set-session-context": true + } + }, + "runtime": { + "rest": { + "enabled": true, + "path": "/api", + "request-body-strict": true + }, + "graphql": { + "enabled": true, + "path": "/graphql", + "allow-introspection": true + }, + "mcp": { + "enabled": true, + "path": "/mcp" + }, + "host": { + "cors": { + "origins": [ + "http://localhost:5000" + ], + "allow-credentials": false + }, + "authentication": { + "provider": "StaticWebApps" + }, + "mode": "development" + } + }, + "entities": { + "Publisher": { + "source": { + "object": "publishers", + "type": "table", + "key-fields": [ + "id" + ] + }, + "graphql": { + "enabled": true, + "type": { + "singular": "Publisher", + "plural": "Publishers" + } + }, + "rest": { + "enabled": true + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "read" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "policy_tester_01", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.id eq 1940" + } + }, + { + "action": "update", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + } + }, + { + "action": "create" + }, + { + "action": "delete" + } + ] + }, + { + "role": "policy_tester_02", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.id ne 1940" + } + }, + { + "action": "update", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + } + }, + { + "action": "create" + }, + { + "action": "delete" + } + ] + }, + { + "role": "policy_tester_03", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.id ne 1940" + } + }, + { + "action": "update", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + } + }, + { + "action": "create" + }, + { + "action": "delete" + } + ] + }, + { + "role": "policy_tester_04", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.id eq 1940" + } + }, + { + "action": "update", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + } + }, + { + "action": "create" + }, + { + "action": "delete" + } + ] + }, + { + "role": "policy_tester_06", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.id eq 1940" + } + }, + { + "action": "update", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + } + }, + { + "action": "create" + }, + { + "action": "delete" + } + ] + }, + { + "role": "database_policy_tester", + "actions": [ + { + "action": "create", + "policy": { + "database": "@item.name ne \u0027New publisher\u0027" + } + }, + { + "action": "update", + "policy": { + "database": "@item.id ne 1234" + } + }, + { + "action": "read", + "policy": { + "database": "@item.id ne 1234 or @item.id gt 1940" + } + } + ] + } + ], + "relationships": { + "books": { + "cardinality": "many", + "target.entity": "Book", + "source.fields": [ + "id" + ], + "target.fields": [ + "publisher_id" + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + } + } + }, + "Stock": { + "source": { + "object": "stocks", + "type": "table", + "key-fields": [ + "categoryid", + "pieceid" + ] + }, + "graphql": { + "enabled": true, + "type": { + "singular": "Stock", + "plural": "Stocks" + } + }, + "rest": { + "enabled": true, + "path": "/commodities" + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "TestNestedFilterFieldIsNull_ColumnForbidden", + "actions": [ + { + "action": "read" + } + ] + }, + { + "role": "TestNestedFilterFieldIsNull_EntityReadForbidden", + "actions": [ + { + "action": "read" + } + ] + }, + { + "role": "database_policy_tester", + "actions": [ + { + "action": "read" + }, + { + "action": "update", + "policy": { + "database": "@item.pieceid ne 1" + } + } + ] + }, + { + "role": "test_role_with_noread", + "actions": [ + { + "action": "create" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "test_role_with_excluded_fields", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + "categoryName" + ] + } + }, + { + "action": "create" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "test_role_with_policy_excluded_fields", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + "categoryName" + ] + }, + "policy": { + "database": "@item.piecesAvailable ne 0" + } + }, + { + "action": "create" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + } + ] + }, + "stocks_price": { + "source": { + "object": "stocks_price", + "type": "table", + "key-fields": [ + "categoryid", + "pieceid", + "instant" + ] + }, + "graphql": { + "enabled": true, + "type": { + "singular": "stocks_price", + "plural": "stocks_prices" + } + }, + "rest": { + "enabled": true + }, + "permissions": [ + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "anonymous", + "actions": [ + { + "action": "read" + } + ] + }, + { + "role": "TestNestedFilterFieldIsNull_ColumnForbidden", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + "price" + ] + } + } + ] + }, + { + "role": "TestNestedFilterFieldIsNull_EntityReadForbidden", + "actions": [ + { + "action": "create" + } + ] + } + ] + }, + "Book": { + "source": { + "object": "books", + "type": "table", + "key-fields": [ + "id" + ] + }, + "graphql": { + "enabled": true, + "type": { + "singular": "book", + "plural": "books" + } + }, + "rest": { + "enabled": true + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "policy_tester_01", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.title eq \u0027Policy-Test-01\u0027" + } + }, + { + "action": "update", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + } + }, + { + "action": "create" + }, + { + "action": "delete" + } + ] + }, + { + "role": "policy_tester_02", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.title ne \u0027Policy-Test-01\u0027" + } + }, + { + "action": "update", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + } + }, + { + "action": "create" + }, + { + "action": "delete" + } + ] + }, + { + "role": "policy_tester_03", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.title eq \u0027Policy-Test-01\u0027" + } + }, + { + "action": "update", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + } + }, + { + "action": "create" + }, + { + "action": "delete" + } + ] + }, + { + "role": "policy_tester_04", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.title ne \u0027Policy-Test-01\u0027" + } + }, + { + "action": "update", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + } + }, + { + "action": "create" + }, + { + "action": "delete" + } + ] + }, + { + "role": "policy_tester_05", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.id ne 9" + } + }, + { + "action": "update", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + } + }, + { + "action": "create" + }, + { + "action": "delete" + } + ] + }, + { + "role": "policy_tester_06", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.id ne 10" + } + }, + { + "action": "create" + }, + { + "action": "delete" + }, + { + "action": "update", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + } + } + ] + }, + { + "role": "policy_tester_07", + "actions": [ + { + "action": "delete", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.id ne 9" + } + }, + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + } + }, + { + "action": "update", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.id ne 9" + } + }, + { + "action": "create" + } + ] + }, + { + "role": "policy_tester_08", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + } + }, + { + "action": "delete", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.id eq 9" + } + }, + { + "action": "update", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.id eq 9" + } + }, + { + "action": "create" + } + ] + }, + { + "role": "test_role_with_noread", + "actions": [ + { + "action": "create" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "test_role_with_excluded_fields", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + "publisher_id" + ] + } + }, + { + "action": "create" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "test_role_with_policy_excluded_fields", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + "publisher_id" + ] + }, + "policy": { + "database": "@item.title ne \u0027Test\u0027" + } + }, + { + "action": "create" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + } + ], + "mappings": { + "id": "id", + "title": "title" + }, + "relationships": { + "websiteplacement": { + "cardinality": "one", + "target.entity": "BookWebsitePlacement", + "source.fields": [ + "id" + ], + "target.fields": [ + "book_id" + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + }, + "publishers": { + "cardinality": "one", + "target.entity": "Publisher", + "source.fields": [ + "publisher_id" + ], + "target.fields": [ + "id" + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + }, + "reviews": { + "cardinality": "many", + "target.entity": "Review", + "source.fields": [ + "id" + ], + "target.fields": [ + "book_id" + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + }, + "authors": { + "cardinality": "many", + "target.entity": "Author", + "source.fields": [ + "id" + ], + "target.fields": [ + "id" + ], + "linking.object": "book_author_link", + "linking.source.fields": [ + "book_id" + ], + "linking.target.fields": [ + "author_id" + ] + } + } + }, + "BookWebsitePlacement": { + "source": { + "object": "book_website_placements", + "type": "table", + "key-fields": [ + "id" + ] + }, + "graphql": { + "enabled": true, + "type": { + "singular": "BookWebsitePlacement", + "plural": "BookWebsitePlacements" + } + }, + "rest": { + "enabled": true + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "read" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "delete", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@claims.userId eq @item.id" + } + }, + { + "action": "create" + }, + { + "action": "update" + } + ] + } + ], + "relationships": { + "books": { + "cardinality": "one", + "target.entity": "Book", + "source.fields": [ + "book_id" + ], + "target.fields": [ + "id" + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + } + } + }, + "Author": { + "source": { + "object": "authors", + "type": "table", + "key-fields": [ + "id" + ] + }, + "graphql": { + "enabled": true, + "type": { + "singular": "Author", + "plural": "Authors" + } + }, + "rest": { + "enabled": true + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "read" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + } + ], + "relationships": { + "books": { + "cardinality": "many", + "target.entity": "Book", + "source.fields": [ + "id" + ], + "target.fields": [ + "id" + ], + "linking.object": "book_author_link", + "linking.source.fields": [ + "author_id" + ], + "linking.target.fields": [ + "book_id" + ] + } + } + }, + "Review": { + "source": { + "object": "reviews", + "type": "table", + "key-fields": [ + "book_id", + "id" + ] + }, + "graphql": { + "enabled": true, + "type": { + "singular": "review", + "plural": "reviews" + } + }, + "rest": { + "enabled": true + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + } + ], + "relationships": { + "books": { + "cardinality": "one", + "target.entity": "Book", + "source.fields": [ + "book_id" + ], + "target.fields": [ + "id" + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + } + } + }, + "Comic": { + "source": { + "object": "comics", + "type": "table", + "key-fields": [ + "id" + ] + }, + "graphql": { + "enabled": true, + "type": { + "singular": "Comic", + "plural": "Comics" + } + }, + "rest": { + "enabled": true + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "TestNestedFilterManyOne_ColumnForbidden", + "actions": [ + { + "action": "read" + } + ] + }, + { + "role": "TestNestedFilterManyOne_EntityReadForbidden", + "actions": [ + { + "action": "read" + } + ] + }, + { + "role": "TestNestedFilterOneMany_ColumnForbidden", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + "categoryName" + ] + } + } + ] + }, + { + "role": "TestNestedFilterOneMany_EntityReadForbidden", + "actions": [ + { + "action": "create" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + } + ], + "relationships": { + "myseries": { + "cardinality": "one", + "target.entity": "series", + "source.fields": [ + "series_id" + ], + "target.fields": [ + "id" + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + } + } + }, + "Broker": { + "source": { + "object": "brokers", + "type": "table", + "key-fields": [ + "ID Number" + ] + }, + "graphql": { + "enabled": false, + "type": { + "singular": "Broker", + "plural": "Brokers" + } + }, + "rest": { + "enabled": true + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "read" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "update" + }, + { + "action": "read" + }, + { + "action": "delete" + } + ] + } + ] + }, + "WebsiteUser": { + "source": { + "object": "website_users", + "type": "table", + "key-fields": [ + "id" + ] + }, + "graphql": { + "enabled": true, + "type": { + "singular": "websiteUser", + "plural": "websiteUsers" + } + }, + "rest": { + "enabled": false + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "delete" + }, + { + "action": "update" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "delete" + }, + { + "action": "update" + } + ] + } + ] + }, + "SupportedType": { + "source": { + "object": "type_table", + "type": "table", + "key-fields": [ + "id" + ] + }, + "graphql": { + "enabled": true, + "type": { + "singular": "SupportedType", + "plural": "SupportedTypes" + } + }, + "rest": { + "enabled": true + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "delete" + }, + { + "action": "update" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "delete" + }, + { + "action": "update" + } + ] + } + ], + "mappings": { + "id": "typeid" + } + }, + "Tree": { + "source": { + "object": "trees", + "type": "table", + "key-fields": [ + "treeId" + ] + }, + "graphql": { + "enabled": false, + "type": { + "singular": "Tree", + "plural": "Trees" + } + }, + "rest": { + "enabled": true + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + } + ], + "mappings": { + "species": "Scientific Name", + "region": "United State\u0027s Region" + } + }, + "Shrub": { + "source": { + "object": "trees", + "type": "table", + "key-fields": [ + "treeId" + ] + }, + "graphql": { + "enabled": true, + "type": { + "singular": "Shrub", + "plural": "Shrubs" + } + }, + "rest": { + "enabled": true, + "path": "/plants" + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + } + ], + "mappings": { + "species": "fancyName" + }, + "relationships": { + "fungus": { + "cardinality": "one", + "target.entity": "Fungus", + "source.fields": [ + "species" + ], + "target.fields": [ + "habitat" + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + } + } + }, + "Fungus": { + "source": { + "object": "fungi", + "type": "table", + "key-fields": [ + "speciesid" + ] + }, + "graphql": { + "enabled": true, + "type": { + "singular": "fungus", + "plural": "fungi" + } + }, + "rest": { + "enabled": true + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "policy_tester_01", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.region ne \u0027northeast\u0027" + } + } + ] + } + ], + "mappings": { + "spores": "hazards" + }, + "relationships": { + "Shrub": { + "cardinality": "one", + "target.entity": "Shrub", + "source.fields": [ + "habitat" + ], + "target.fields": [ + "species" + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + } + } + }, + "books_view_all": { + "source": { + "object": "books_view_all", + "type": "view", + "key-fields": [ + "id" + ] + }, + "graphql": { + "enabled": true, + "type": { + "singular": "books_view_all", + "plural": "books_view_alls" + } + }, + "rest": { + "enabled": true + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + } + ] + }, + "books_view_with_mapping": { + "source": { + "object": "books_view_with_mapping", + "type": "view", + "key-fields": [ + "id" + ] + }, + "graphql": { + "enabled": true, + "type": { + "singular": "books_view_with_mapping", + "plural": "books_view_with_mappings" + } + }, + "rest": { + "enabled": true + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + } + ], + "mappings": { + "id": "book_id" + } + }, + "series": { + "source": { + "object": "series", + "type": "table", + "key-fields": [ + "id" + ] + }, + "graphql": { + "enabled": true, + "type": { + "singular": "series", + "plural": "series" + } + }, + "rest": { + "enabled": true + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + }, + { + "role": "TestNestedFilterManyOne_EntityReadForbidden", + "actions": [ + { + "action": "create" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "TestNestedFilterManyOne_ColumnForbidden", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + "name" + ] + } + } + ] + }, + { + "role": "TestNestedFilterOneMany_ColumnForbidden", + "actions": [ + { + "action": "read" + } + ] + }, + { + "role": "TestNestedFilterOneMany_EntityReadForbidden", + "actions": [ + { + "action": "read" + } + ] + } + ], + "relationships": { + "comics": { + "cardinality": "many", + "target.entity": "Comic", + "source.fields": [ + "id" + ], + "target.fields": [ + "series_id" + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + } + } + }, + "Sales": { + "source": { + "object": "sales", + "type": "table", + "key-fields": [ + "id" + ] + }, + "graphql": { + "enabled": true, + "type": { + "singular": "Sales", + "plural": "Sales" + } + }, + "rest": { + "enabled": true + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "*" + } + ] + } + ] + }, + "GQLmappings": { + "source": { + "object": "GQLmappings", + "type": "table", + "key-fields": [ + "__column1" + ] + }, + "graphql": { + "enabled": true, + "type": { + "singular": "GQLmappings", + "plural": "GQLmappings" + } + }, + "rest": { + "enabled": true + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "*" + } + ] + } + ], + "mappings": { + "__column1": "column1", + "__column2": "column2" + } + }, + "Bookmarks": { + "source": { + "object": "bookmarks", + "type": "table", + "key-fields": [ + "id" + ] + }, + "graphql": { + "enabled": true, + "type": { + "singular": "Bookmarks", + "plural": "Bookmarks" + } + }, + "rest": { + "enabled": true + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "*" + } + ] + } + ] + }, + "MappedBookmarks": { + "source": { + "object": "mappedbookmarks", + "type": "table", + "key-fields": [ + "id" + ] + }, + "graphql": { + "enabled": true, + "type": { + "singular": "MappedBookmarks", + "plural": "MappedBookmarks" + } + }, + "rest": { + "enabled": true + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "*" + } + ] + } + ], + "mappings": { + "id": "bkid", + "bkname": "name" + } + }, + "books_publishers_view_composite": { + "source": { + "object": "books_publishers_view_composite", + "type": "view", + "key-fields": [ + "id", + "pub_id" + ] + }, + "graphql": { + "enabled": true, + "type": { + "singular": "books_publishers_view_composite", + "plural": "books_publishers_view_composites" + } + }, + "rest": { + "enabled": true + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + } + ] + }, + "Empty": { + "source": { + "object": "empty_table", + "type": "table", + "key-fields": [ + "id" + ] + }, + "graphql": { + "enabled": true, + "type": { + "singular": "Empty", + "plural": "Empties" + } + }, + "rest": { + "enabled": true + }, + "permissions": [ + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "anonymous", + "actions": [ + { + "action": "read" + } + ] + } + ] + }, + "Notebook": { + "source": { + "object": "notebooks", + "type": "table", + "key-fields": [ + "id" + ] + }, + "graphql": { + "enabled": true, + "type": { + "singular": "Notebook", + "plural": "Notebooks" + } + }, + "rest": { + "enabled": true + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "create" + }, + { + "action": "update" + }, + { + "action": "delete" + }, + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item ne 1" + } + } + ] + } + ] + }, + "Journal": { + "source": { + "object": "journals", + "type": "table", + "key-fields": [ + "id" + ] + }, + "graphql": { + "enabled": true, + "type": { + "singular": "Journal", + "plural": "Journals" + } + }, + "rest": { + "enabled": true + }, + "permissions": [ + { + "role": "policy_tester_noupdate", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + } + }, + { + "action": "update", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.id ne 1" + } + }, + { + "action": "create" + }, + { + "action": "delete" + } + ] + }, + { + "role": "policy_tester_update_noread", + "actions": [ + { + "action": "delete", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.id eq 1" + } + }, + { + "action": "read", + "fields": { + "exclude": [ + "*" + ] + } + }, + { + "action": "update", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.id eq 1" + } + }, + { + "action": "create" + } + ] + }, + { + "role": "authorizationHandlerTester", + "actions": [ + { + "action": "read" + } + ] + } + ] + }, + "ArtOfWar": { + "source": { + "object": "aow", + "type": "table", + "key-fields": [ + "NoteNum" + ] + }, + "graphql": { + "enabled": false, + "type": { + "singular": "ArtOfWar", + "plural": "ArtOfWars" + } + }, + "rest": { + "enabled": true + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "*" + } + ] + } + ], + "mappings": { + "DetailAssessmentAndPlanning": "始計", + "WagingWar": "作戰", + "StrategicAttack": "謀攻", + "NoteNum": "┬─┬ノ( º _ ºノ)" + } + }, + "stocks_view_selected": { + "source": { + "object": "stocks_view_selected", + "type": "view", + "key-fields": [ + "categoryid", + "pieceid" + ] + }, + "graphql": { + "enabled": true, + "type": { + "singular": "stocks_view_selected", + "plural": "stocks_view_selecteds" + } + }, + "rest": { + "enabled": true + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + } + ] + }, + "GetBook": { + "source": { + "object": "get_book_by_id", + "type": "stored-procedure" + }, + "graphql": { + "enabled": false, + "operation": "mutation", + "type": { + "singular": "GetBook", + "plural": "GetBooks" + } + }, + "rest": { + "enabled": true, + "methods": [ + "get" + ] + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "execute" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "execute" + } + ] + } + ] + }, + "GetBooks": { + "source": { + "object": "get_books", + "type": "stored-procedure" + }, + "graphql": { + "enabled": true, + "operation": "query", + "type": { + "singular": "GetBooks", + "plural": "GetBooks" + } + }, + "rest": { + "enabled": true, + "methods": [ + "get" + ] + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "execute" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "execute" + } + ] + } + ] + }, + "GetPublisher": { + "source": { + "object": "get_publisher_by_id", + "type": "stored-procedure" + }, + "graphql": { + "enabled": true, + "operation": "query", + "type": { + "singular": "GetPublisher", + "plural": "GetPublishers" + } + }, + "rest": { + "enabled": true, + "methods": [ + "post" + ] + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "execute" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "execute" + } + ] + } + ] + }, + "GetAuthorsHistoryByFirstName": { + "source": { + "object": "get_authors_history_by_first_name", + "type": "stored-procedure", + "parameters": [ + { + "name": "firstName", + "required": false, + "default": "Aaron" + } + ] + }, + "graphql": { + "enabled": true, + "operation": "mutation", + "type": { + "singular": "SearchAuthorByFirstName", + "plural": "SearchAuthorByFirstNames" + } + }, + "rest": { + "enabled": true, + "methods": [ + "post" + ] + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "execute" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "execute" + } + ] + } + ] + }, + "CountBooks": { + "source": { + "object": "count_books", + "type": "stored-procedure" + }, + "graphql": { + "enabled": true, + "operation": "mutation", + "type": { + "singular": "CountBooks", + "plural": "CountBooks" + } + }, + "rest": { + "enabled": true, + "methods": [ + "post" + ] + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "execute" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "execute" + } + ] + } + ] + }, + "InsertBook": { + "source": { + "object": "insert_book", + "type": "stored-procedure", + "parameters": [ + { + "name": "title", + "required": false, + "default": "randomX" + }, + { + "name": "publisher_id", + "required": false, + "default": "1234" + } + ] + }, + "graphql": { + "enabled": true, + "operation": "mutation", + "type": { + "singular": "InsertBook", + "plural": "InsertBooks" + } + }, + "rest": { + "enabled": true, + "methods": [ + "post" + ] + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "execute" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "execute" + } + ] + } + ] + }, + "DeleteLastInsertedBook": { + "source": { + "object": "delete_last_inserted_book", + "type": "stored-procedure" + }, + "graphql": { + "enabled": true, + "operation": "mutation", + "type": { + "singular": "DeleteLastInsertedBook", + "plural": "DeleteLastInsertedBooks" + } + }, + "rest": { + "enabled": true, + "methods": [ + "post" + ] + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "execute" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "execute" + } + ] + } + ] + }, + "UpdateBookTitle": { + "source": { + "object": "update_book_title", + "type": "stored-procedure", + "parameters": [ + { + "name": "id", + "required": false, + "default": "1" + }, + { + "name": "title", + "required": false, + "default": "Testing Tonight" + } + ] + }, + "graphql": { + "enabled": true, + "operation": "mutation", + "type": { + "singular": "UpdateBookTitle", + "plural": "UpdateBookTitles" + } + }, + "rest": { + "enabled": true, + "methods": [ + "post" + ] + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "execute" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "execute" + } + ] + } + ] + }, + "InsertAndDisplayAllBooksUnderGivenPublisher": { + "source": { + "object": "insert_and_display_all_books_for_given_publisher", + "type": "stored-procedure", + "parameters": [ + { + "name": "title", + "required": false, + "default": "MyTitle" + }, + { + "name": "publisher_name", + "required": false, + "default": "MyPublisher" + } + ] + }, + "graphql": { + "enabled": true, + "operation": "mutation", + "type": { + "singular": "InsertAndDisplayAllBooksUnderGivenPublisher", + "plural": "InsertAndDisplayAllBooksUnderGivenPublishers" + } + }, + "rest": { + "enabled": true, + "methods": [ + "post" + ] + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "execute" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "execute" + } + ] + } + ] + }, + "DateOnlyTable": { + "source": { + "object": "date_only_table", + "type": "table", + "key-fields": [ + "event_date" + ] + }, + "graphql": { + "enabled": true, + "type": { + "singular": "DateOnlyTable", + "plural": "DateOnlyTables" + } + }, + "rest": { + "enabled": true + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + } + ] + }, + "dbo_DimAccount": { + "source": { + "object": "DimAccount", + "type": "table" + }, + "graphql": { + "enabled": true, + "type": { + "singular": "dbo_DimAccount", + "plural": "dbo_DimAccounts" + } + }, + "rest": { + "enabled": true + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + } + ], + "relationships": { + "parent_account": { + "cardinality": "one", + "target.entity": "dbo_DimAccount", + "source.fields": [ + "ParentAccountKey" + ], + "target.fields": [ + "AccountKey" + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + }, + "child_accounts": { + "cardinality": "many", + "target.entity": "dbo_DimAccount", + "source.fields": [ + "AccountKey" + ], + "target.fields": [ + "ParentAccountKey" + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + } + } + } + } +} diff --git a/src/Service.Tests/dab-config.MsSql.json b/src/Service.Tests/dab-config.MsSql.json index d5e903d4f3..2b69b81ef9 100644 --- a/src/Service.Tests/dab-config.MsSql.json +++ b/src/Service.Tests/dab-config.MsSql.json @@ -1,3852 +1,4148 @@ -{ - "$schema": "https://github.com/Azure/data-api-builder/releases/download/vmajor.minor.patch/dab.draft.schema.json", - "data-source": { - "database-type": "mssql", - "connection-string": "Server=tcp:127.0.0.1,1433;Persist Security Info=False;User ID=sa;Password=REPLACEME;MultipleActiveResultSets=False;Connection Timeout=5;", - "options": { - "set-session-context": true - } - }, - "runtime": { - "rest": { - "enabled": true, - "path": "/api", - "request-body-strict": true - }, - "graphql": { - "enabled": true, - "path": "/graphql", - "allow-introspection": true, - "multiple-mutations": { - "create": { - "enabled": true - } - } - }, - "mcp": { - "enabled": true, - "path": "/mcp", - "dml-tools": true - }, - "host": { - "cors": { - "origins": [ - "http://localhost:5000" - ], - "allow-credentials": false - }, - "authentication": { - "provider": "StaticWebApps" - }, - "mode": "development" - } - }, - "entities": { - "Publisher": { - "source": { - "object": "publishers", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "Publisher", - "plural": "Publishers" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "read" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "policy_tester_01", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.id eq 1940" - } - }, - { - "action": "update", - "fields": { - "exclude": [], - "include": [ - "*" - ] - } - }, - { - "action": "create" - }, - { - "action": "delete" - } - ] - }, - { - "role": "policy_tester_02", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.id ne 1940" - } - }, - { - "action": "update", - "fields": { - "exclude": [], - "include": [ - "*" - ] - } - }, - { - "action": "create" - }, - { - "action": "delete" - } - ] - }, - { - "role": "policy_tester_03", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.id ne 1940" - } - }, - { - "action": "update", - "fields": { - "exclude": [], - "include": [ - "*" - ] - } - }, - { - "action": "create" - }, - { - "action": "delete" - } - ] - }, - { - "role": "policy_tester_04", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.id eq 1940" - } - }, - { - "action": "update", - "fields": { - "exclude": [], - "include": [ - "*" - ] - } - }, - { - "action": "create" - }, - { - "action": "delete" - } - ] - }, - { - "role": "policy_tester_06", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.id eq 1940" - } - }, - { - "action": "update", - "fields": { - "exclude": [], - "include": [ - "*" - ] - } - }, - { - "action": "create" - }, - { - "action": "delete" - } - ] - }, - { - "role": "database_policy_tester", - "actions": [ - { - "action": "create", - "policy": { - "database": "@item.name ne 'New publisher'" - } - }, - { - "action": "update", - "policy": { - "database": "@item.id ne 1234" - } - }, - { - "action": "read", - "policy": { - "database": "@item.id ne 1234 or @item.id gt 1940" - } - } - ] - }, - { - "role": "role_multiple_create_policy_tester", - "actions": [ - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - }, - { - "action": "create", - "policy": { - "database": "@item.name ne 'Test'" - } - } - ] - } - ], - "relationships": { - "books": { - "cardinality": "many", - "target.entity": "Book", - "source.fields": [], - "target.fields": [], - "linking.source.fields": [], - "linking.target.fields": [] - } - } - }, - "Publisher_MM": { - "source": { - "object": "publishers_mm", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "Publisher_MM", - "plural": "Publishers_MM" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "*" - } - ] - } - ], - "relationships": { - "books_mm": { - "cardinality": "many", - "target.entity": "Book_MM", - "source.fields": [ - "id" - ], - "target.fields": [ - "publisher_id" - ], - "linking.source.fields": [], - "linking.target.fields": [] - } - } - }, - "Stock": { - "source": { - "object": "stocks", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "Stock", - "plural": "Stocks" - } - }, - "rest": { - "enabled": true, - "path": "/commodities" - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "test_role_with_excluded_fields_on_create", - "actions": [ - { - "action": "create", - "fields": { - "exclude": [ - "piecesAvailable" - ] - } - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "TestNestedFilterFieldIsNull_ColumnForbidden", - "actions": [ - { - "action": "read" - } - ] - }, - { - "role": "TestNestedFilterFieldIsNull_EntityReadForbidden", - "actions": [ - { - "action": "read" - } - ] - }, - { - "role": "database_policy_tester", - "actions": [ - { - "action": "read" - }, - { - "action": "create", - "policy": { - "database": "@item.pieceid ne 6 and @item.piecesAvailable gt 0" - } - }, - { - "action": "update", - "policy": { - "database": "@item.pieceid ne 1" - } - } - ] - }, - { - "role": "test_role_with_noread", - "actions": [ - { - "action": "create" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "test_role_with_excluded_fields", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [ - "categoryName" - ] - } - }, - { - "action": "create" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "test_role_with_policy_excluded_fields", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [ - "categoryName" - ] - }, - "policy": { - "database": "@item.piecesAvailable ne 0" - } - }, - { - "action": "create" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - } - ], - "relationships": { - "stocks_price": { - "cardinality": "one", - "target.entity": "stocks_price", - "source.fields": [], - "target.fields": [], - "linking.source.fields": [], - "linking.target.fields": [] - } - } - }, - "Book": { - "source": { - "object": "books", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "book", - "plural": "books" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "policy_tester_01", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.title eq 'Policy-Test-01'" - } - }, - { - "action": "update", - "fields": { - "exclude": [], - "include": [ - "*" - ] - } - }, - { - "action": "create" - }, - { - "action": "delete" - } - ] - }, - { - "role": "policy_tester_02", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.title ne 'Policy-Test-01'" - } - }, - { - "action": "update", - "fields": { - "exclude": [], - "include": [ - "*" - ] - } - }, - { - "action": "create" - }, - { - "action": "delete" - } - ] - }, - { - "role": "policy_tester_03", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.title eq 'Policy-Test-01'" - } - }, - { - "action": "update", - "fields": { - "exclude": [], - "include": [ - "*" - ] - } - }, - { - "action": "create" - }, - { - "action": "delete" - } - ] - }, - { - "role": "policy_tester_04", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.title ne 'Policy-Test-01'" - } - }, - { - "action": "update", - "fields": { - "exclude": [], - "include": [ - "*" - ] - } - }, - { - "action": "create" - }, - { - "action": "delete" - } - ] - }, - { - "role": "policy_tester_05", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.id ne 9" - } - }, - { - "action": "update", - "fields": { - "exclude": [], - "include": [ - "*" - ] - } - }, - { - "action": "create" - }, - { - "action": "delete" - } - ] - }, - { - "role": "policy_tester_06", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.id ne 10" - } - }, - { - "action": "create" - }, - { - "action": "delete" - }, - { - "action": "update", - "fields": { - "exclude": [], - "include": [ - "*" - ] - } - } - ] - }, - { - "role": "policy_tester_07", - "actions": [ - { - "action": "delete", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.id ne 9" - } - }, - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - } - }, - { - "action": "update", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.id ne 9" - } - }, - { - "action": "create" - } - ] - }, - { - "role": "policy_tester_08", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - } - }, - { - "action": "delete", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.id eq 9" - } - }, - { - "action": "update", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.id eq 9" - } - }, - { - "action": "create" - } - ] - }, - { - "role": "test_role_with_noread", - "actions": [ - { - "action": "create" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "test_role_with_excluded_fields", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [ - "publisher_id" - ] - } - }, - { - "action": "create" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "test_role_with_policy_excluded_fields", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [ - "publisher_id" - ] - }, - "policy": { - "database": "@item.title ne 'Test'" - } - }, - { - "action": "create" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "role_multiple_create_policy_tester", - "actions": [ - { - "action": "update" - }, - { - "action": "delete" - }, - { - "action": "create", - "policy": { - "database": "@item.title ne 'Test'" - } - }, - { - "action": "read", - "policy": { - "database": "@item.publisher_id ne 1234" - } - } - ] - } - ], - "mappings": { - "id": "id", - "title": "title" - }, - "relationships": { - "publishers": { - "cardinality": "one", - "target.entity": "Publisher", - "source.fields": [], - "target.fields": [], - "linking.source.fields": [], - "linking.target.fields": [] - }, - "websiteplacement": { - "cardinality": "one", - "target.entity": "BookWebsitePlacement", - "source.fields": [], - "target.fields": [], - "linking.source.fields": [], - "linking.target.fields": [] - }, - "reviews": { - "cardinality": "many", - "target.entity": "Review", - "source.fields": [], - "target.fields": [], - "linking.source.fields": [], - "linking.target.fields": [] - }, - "authors": { - "cardinality": "many", - "target.entity": "Author", - "source.fields": [ - "id" - ], - "target.fields": [ - "id" - ], - "linking.object": "book_author_link", - "linking.source.fields": [ - "book_id" - ], - "linking.target.fields": [ - "author_id" - ] - } - } - }, - "Default_Books": { - "source": { - "object": "default_books", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "default_book", - "plural": "default_books" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - } - ] - }, - "Book_MM": { - "source": { - "object": "books_mm", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "book_mm", - "plural": "books_mm" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "*" - } - ] - } - ], - "relationships": { - "publishers": { - "cardinality": "one", - "target.entity": "Publisher_MM", - "source.fields": [ - "publisher_id" - ], - "target.fields": [ - "id" - ], - "linking.source.fields": [], - "linking.target.fields": [] - }, - "reviews": { - "cardinality": "many", - "target.entity": "Review_MM", - "source.fields": [ - "id" - ], - "target.fields": [ - "book_id" - ], - "linking.source.fields": [], - "linking.target.fields": [] - }, - "authors": { - "cardinality": "many", - "target.entity": "Author_MM", - "source.fields": [ - "id" - ], - "target.fields": [ - "id" - ], - "linking.object": "book_author_link_mm", - "linking.source.fields": [ - "book_id" - ], - "linking.target.fields": [ - "author_id" - ] - } - } - }, - "BookWebsitePlacement": { - "source": { - "object": "book_website_placements", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "BookWebsitePlacement", - "plural": "BookWebsitePlacements" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "read" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "delete", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@claims.userId eq @item.id" - } - }, - { - "action": "create" - }, - { - "action": "update" - } - ] - } - ], - "relationships": { - "books": { - "cardinality": "one", - "target.entity": "Book", - "source.fields": [], - "target.fields": [], - "linking.source.fields": [], - "linking.target.fields": [] - } - } - }, - "Author": { - "source": { - "object": "authors", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "Author", - "plural": "Authors" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "read" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - } - ], - "relationships": { - "books": { - "cardinality": "many", - "target.entity": "Book", - "source.fields": [], - "target.fields": [], - "linking.object": "book_author_link", - "linking.source.fields": [], - "linking.target.fields": [] - } - } - }, - "Author_MM": { - "source": { - "object": "authors_mm", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "author_mm", - "plural": "authors_mm" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "*" - } - ] - } - ], - "relationships": { - "books": { - "cardinality": "many", - "target.entity": "Book_MM", - "source.fields": [ - "id" - ], - "target.fields": [ - "id" - ], - "linking.object": "book_author_link_mm", - "linking.source.fields": [ - "author_id" - ], - "linking.target.fields": [ - "book_id" - ] - } - } - }, - "Revenue": { - "source": { - "object": "revenues", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "Revenue", - "plural": "Revenues" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - }, - { - "role": "database_policy_tester", - "actions": [ - { - "action": "create", - "policy": { - "database": "@item.revenue gt 1000" - } - } - ] - } - ] - }, - "Review": { - "source": { - "object": "reviews", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "review", - "plural": "reviews" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "role_multiple_create_policy_tester", - "actions": [ - { - "action": "update" - }, - { - "action": "delete" - }, - { - "action": "create", - "policy": { - "database": "@item.content ne 'Great'" - } - }, - { - "action": "read", - "policy": { - "database": "@item.websiteuser_id ne 1" - } - } - ] - } - ], - "relationships": { - "books": { - "cardinality": "one", - "target.entity": "Book", - "source.fields": [], - "target.fields": [], - "linking.source.fields": [], - "linking.target.fields": [] - }, - "website_users": { - "cardinality": "one", - "target.entity": "WebsiteUser", - "source.fields": [ - "websiteuser_id" - ], - "target.fields": [ - "id" - ], - "linking.source.fields": [], - "linking.target.fields": [] - } - } - }, - "Review_MM": { - "source": { - "object": "reviews_mm", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "review_mm", - "plural": "reviews_mm" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "*" - } - ] - } - ], - "relationships": { - "books": { - "cardinality": "one", - "target.entity": "Book_MM", - "source.fields": [ - "book_id" - ], - "target.fields": [ - "id" - ], - "linking.source.fields": [], - "linking.target.fields": [] - }, - "website_users": { - "cardinality": "one", - "target.entity": "WebsiteUser_MM", - "source.fields": [ - "websiteuser_id" - ], - "target.fields": [ - "id" - ], - "linking.source.fields": [], - "linking.target.fields": [] - } - } - }, - "Comic": { - "source": { - "object": "comics", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "Comic", - "plural": "Comics" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "TestNestedFilterManyOne_ColumnForbidden", - "actions": [ - { - "action": "read" - } - ] - }, - { - "role": "TestNestedFilterManyOne_EntityReadForbidden", - "actions": [ - { - "action": "read" - } - ] - }, - { - "role": "TestNestedFilterOneMany_ColumnForbidden", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [ - "categoryName" - ] - } - } - ] - }, - { - "role": "TestNestedFilterOneMany_EntityReadForbidden", - "actions": [ - { - "action": "create" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - } - ], - "relationships": { - "myseries": { - "cardinality": "one", - "target.entity": "series", - "source.fields": [], - "target.fields": [], - "linking.source.fields": [], - "linking.target.fields": [] - } - } - }, - "Broker": { - "source": { - "object": "brokers", - "type": "table" - }, - "graphql": { - "enabled": false, - "type": { - "singular": "Broker", - "plural": "Brokers" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "read" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "update" - }, - { - "action": "read" - }, - { - "action": "delete" - } - ] - } - ] - }, - "WebsiteUser": { - "source": { - "object": "website_users", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "websiteUser", - "plural": "websiteUsers" - } - }, - "rest": { - "enabled": false - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "delete" - }, - { - "action": "update" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "delete" - }, - { - "action": "update" - } - ] - } - ], - "relationships": { - "reviews": { - "cardinality": "many", - "target.entity": "Review", - "source.fields": [ - "id" - ], - "target.fields": [ - "websiteuser_id" - ], - "linking.source.fields": [], - "linking.target.fields": [] - } - } - }, - "WebsiteUser_MM": { - "source": { - "object": "website_users_mm", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "websiteuser_mm", - "plural": "websiteusers_mm" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "*" - } - ] - } - ], - "relationships": { - "reviews": { - "cardinality": "many", - "target.entity": "Review_MM", - "source.fields": [ - "id" - ], - "target.fields": [ - "websiteuser_id" - ], - "linking.source.fields": [], - "linking.target.fields": [] - } - } - }, - "SupportedType": { - "source": { - "object": "type_table", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "SupportedType", - "plural": "SupportedTypes" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "delete" - }, - { - "action": "update" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "delete" - }, - { - "action": "update" - } - ] - } - ], - "mappings": { - "id": "typeid" - } - }, - "stocks_price": { - "source": { - "object": "stocks_price", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "stocks_price", - "plural": "stocks_prices" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "anonymous", - "actions": [ - { - "action": "read" - } - ] - }, - { - "role": "TestNestedFilterFieldIsNull_ColumnForbidden", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [ - "price" - ] - } - } - ] - }, - { - "role": "TestNestedFilterFieldIsNull_EntityReadForbidden", - "actions": [ - { - "action": "create" - } - ] - }, - { - "role": "test_role_with_excluded_fields_on_create", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - } - ], - "relationships": { - "Stock": { - "cardinality": "one", - "target.entity": "Stock", - "source.fields": [], - "target.fields": [], - "linking.source.fields": [], - "linking.target.fields": [] - } - } - }, - "Tree": { - "source": { - "object": "trees", - "type": "table" - }, - "graphql": { - "enabled": false, - "type": { - "singular": "Tree", - "plural": "Trees" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - } - ], - "mappings": { - "species": "Scientific Name", - "region": "United State's Region" - } - }, - "Shrub": { - "source": { - "object": "trees", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "Shrub", - "plural": "Shrubs" - } - }, - "rest": { - "enabled": true, - "path": "/plants" - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - } - ], - "mappings": { - "species": "fancyName" - }, - "relationships": { - "fungus": { - "cardinality": "one", - "target.entity": "Fungus", - "source.fields": [ - "species" - ], - "target.fields": [ - "habitat" - ], - "linking.source.fields": [], - "linking.target.fields": [] - } - } - }, - "Fungus": { - "source": { - "object": "fungi", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "fungus", - "plural": "fungi" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "policy_tester_01", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.region ne 'northeast'" - } - } - ] - } - ], - "mappings": { - "spores": "hazards" - }, - "relationships": { - "Shrub": { - "cardinality": "one", - "target.entity": "Shrub", - "source.fields": [ - "habitat" - ], - "target.fields": [ - "species" - ], - "linking.source.fields": [], - "linking.target.fields": [] - } - } - }, - "books_view_all": { - "source": { - "object": "books_view_all", - "type": "view", - "key-fields": [ - "id" - ] - }, - "graphql": { - "enabled": true, - "type": { - "singular": "books_view_all", - "plural": "books_view_alls" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - } - ] - }, - "books_view_with_mapping": { - "source": { - "object": "books_view_with_mapping", - "type": "view", - "key-fields": [ - "id" - ] - }, - "graphql": { - "enabled": true, - "type": { - "singular": "books_view_with_mapping", - "plural": "books_view_with_mappings" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - } - ], - "mappings": { - "id": "book_id" - } - }, - "stocks_view_selected": { - "source": { - "object": "stocks_view_selected", - "type": "view", - "key-fields": [ - "categoryid", - "pieceid" - ] - }, - "graphql": { - "enabled": true, - "type": { - "singular": "stocks_view_selected", - "plural": "stocks_view_selecteds" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - } - ] - }, - "books_publishers_view_composite": { - "source": { - "object": "books_publishers_view_composite", - "type": "view", - "key-fields": [ - "id", - "pub_id" - ] - }, - "graphql": { - "enabled": true, - "type": { - "singular": "books_publishers_view_composite", - "plural": "books_publishers_view_composites" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - } - ] - }, - "books_publishers_view_composite_insertable": { - "source": { - "object": "books_publishers_view_composite_insertable", - "type": "view", - "key-fields": [ - "id", - "publisher_id" - ] - }, - "graphql": { - "enabled": true, - "type": { - "singular": "books_publishers_view_composite_insertable", - "plural": "books_publishers_view_composite_insertables" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - } - ] - }, - "Empty": { - "source": { - "object": "empty_table", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "Empty", - "plural": "Empties" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "anonymous", - "actions": [ - { - "action": "read" - } - ] - } - ] - }, - "Notebook": { - "source": { - "object": "notebooks", - "type": "table", - "object-description": "Table containing notebook information" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "Notebook", - "plural": "Notebooks" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "create" - }, - { - "action": "update" - }, - { - "action": "delete" - }, - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item ne 1" - } - } - ] - } - ] - }, - "Journal": { - "source": { - "object": "journals", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "Journal", - "plural": "Journals" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "policy_tester_noupdate", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [], - "include": [ - "*" - ] - } - }, - { - "action": "update", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.id ne 1" - } - }, - { - "action": "create" - }, - { - "action": "delete" - } - ] - }, - { - "role": "policy_tester_update_noread", - "actions": [ - { - "action": "delete", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.id eq 1" - } - }, - { - "action": "read", - "fields": { - "exclude": [ - "*" - ] - } - }, - { - "action": "update", - "fields": { - "exclude": [], - "include": [ - "*" - ] - }, - "policy": { - "database": "@item.id eq 1" - } - }, - { - "action": "create" - } - ] - }, - { - "role": "authorizationHandlerTester", - "actions": [ - { - "action": "read" - } - ] - } - ] - }, - "ArtOfWar": { - "source": { - "object": "aow", - "type": "table" - }, - "graphql": { - "enabled": false, - "type": { - "singular": "ArtOfWar", - "plural": "ArtOfWars" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "*" - } - ] - } - ], - "mappings": { - "DetailAssessmentAndPlanning": "始計", - "WagingWar": "作戰", - "StrategicAttack": "謀攻", - "NoteNum": "┬─┬ノ( º _ ºノ)" - } - }, - "series": { - "source": { - "object": "series", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "series", - "plural": "series" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - }, - { - "role": "TestNestedFilterManyOne_ColumnForbidden", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [ - "name" - ] - } - } - ] - }, - { - "role": "TestNestedFilterManyOne_EntityReadForbidden", - "actions": [ - { - "action": "create" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "TestNestedFilterOneMany_ColumnForbidden", - "actions": [ - { - "action": "read" - } - ] - }, - { - "role": "TestNestedFilterOneMany_EntityReadForbidden", - "actions": [ - { - "action": "read" - } - ] - } - ], - "relationships": { - "comics": { - "cardinality": "many", - "target.entity": "Comic", - "source.fields": [], - "target.fields": [], - "linking.source.fields": [], - "linking.target.fields": [] - } - } - }, - "Sales": { - "source": { - "object": "sales", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "Sales", - "plural": "Sales" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "*" - } - ] - } - ] - }, - "User_NonAutogenRelationshipColumn": { - "source": { - "object": "users", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "User_NonAutogenRelationshipColumn", - "plural": "User_NonAutogenRelationshipColumns" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - } - ], - "relationships": { - "UserProfile_NonAutogenRelationshipColumn": { - "cardinality": "one", - "target.entity": "UserProfile", - "source.fields": [ - "username" - ], - "target.fields": [ - "username" - ], - "linking.source.fields": [], - "linking.target.fields": [] - } - } - }, - "UserProfile": { - "source": { - "object": "user_profiles", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "UserProfile", - "plural": "UserProfiles" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - } - ] - }, - "User_AutogenRelationshipColumn": { - "source": { - "object": "users", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "User_AutogenRelationshipColumn", - "plural": "User_AutogenRelationshipColumns" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - } - ], - "relationships": { - "UserProfile_AutogenRelationshipColumn": { - "cardinality": "one", - "target.entity": "UserProfile", - "source.fields": [ - "userid" - ], - "target.fields": [ - "profileid" - ], - "linking.source.fields": [], - "linking.target.fields": [] - } - } - }, - "User_AutogenToNonAutogenRelationshipColumn": { - "source": { - "object": "users", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "User_AutogenToNonAutogenRelationshipColumn", - "plural": "User_AutogenToNonAutogenRelationshipColumns" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - } - ], - "relationships": { - "UserProfile_AutogenToNonAutogenRelationshipColumn": { - "cardinality": "one", - "target.entity": "UserProfile", - "source.fields": [ - "userid", - "username" - ], - "target.fields": [ - "userid", - "username" - ], - "linking.source.fields": [], - "linking.target.fields": [] - } - } - }, - "User_RepeatedReferencingColumnToOneEntity": { - "source": { - "object": "users", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "User_RepeatedReferencingColumnToOneEntity", - "plural": "User_RepeatedReferencingColumnToOneEntities" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - } - ], - "relationships": { - "UserProfile": { - "cardinality": "one", - "target.entity": "UserProfile", - "source.fields": [ - "username", - "username" - ], - "target.fields": [ - "profilepictureurl", - "username" - ], - "linking.source.fields": [], - "linking.target.fields": [] - } - } - }, - "UserProfile_RepeatedReferencingColumnToTwoEntities": { - "source": { - "object": "user_profiles", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "UserProfile_RepeatedReferencingColumnToTwoEntities", - "plural": "UserProfile_RepeatedReferencingColumnToTwoEntities" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - } - ], - "relationships": { - "book": { - "cardinality": "one", - "target.entity": "Book", - "source.fields": [ - "userid" - ], - "target.fields": [ - "id" - ], - "linking.source.fields": [], - "linking.target.fields": [] - }, - "publisher": { - "cardinality": "one", - "target.entity": "Publisher", - "source.fields": [ - "userid" - ], - "target.fields": [ - "id" - ], - "linking.source.fields": [], - "linking.target.fields": [] - } - } - }, - "GetBooks": { - "source": { - "object": "get_books", - "type": "stored-procedure" - }, - "graphql": { - "enabled": true, - "operation": "query", - "type": { - "singular": "GetBooks", - "plural": "GetBooks" - } - }, - "rest": { - "enabled": true, - "methods": [ - "get" - ] - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "execute" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "execute" - } - ] - } - ] - }, - "GetBook": { - "source": { - "object": "get_book_by_id", - "type": "stored-procedure" - }, - "graphql": { - "enabled": false, - "operation": "mutation", - "type": { - "singular": "GetBook", - "plural": "GetBooks" - } - }, - "rest": { - "enabled": true, - "methods": [ - "get" - ] - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "execute" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "execute" - } - ] - } - ] - }, - "GetPublisher": { - "source": { - "object": "get_publisher_by_id", - "type": "stored-procedure" - }, - "graphql": { - "enabled": true, - "operation": "query", - "type": { - "singular": "GetPublisher", - "plural": "GetPublishers" - } - }, - "rest": { - "enabled": true, - "methods": [ - "post" - ] - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "execute" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "execute" - } - ] - } - ] - }, - "InsertBook": { - "source": { - "object": "insert_book", - "type": "stored-procedure", - "parameters": { - "title": "randomX", - "publisher_id": 1234 - } - }, - "graphql": { - "enabled": true, - "operation": "mutation", - "type": { - "singular": "InsertBook", - "plural": "InsertBooks" - } - }, - "rest": { - "enabled": true, - "methods": [ - "post" - ] - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "execute" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "execute" - } - ] - } - ] - }, - "CountBooks": { - "source": { - "object": "count_books", - "type": "stored-procedure" - }, - "graphql": { - "enabled": true, - "operation": "mutation", - "type": { - "singular": "CountBooks", - "plural": "CountBooks" - } - }, - "rest": { - "enabled": true, - "methods": [ - "post" - ] - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "execute" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "execute" - } - ] - } - ] - }, - "DeleteLastInsertedBook": { - "source": { - "object": "delete_last_inserted_book", - "type": "stored-procedure" - }, - "graphql": { - "enabled": true, - "operation": "mutation", - "type": { - "singular": "DeleteLastInsertedBook", - "plural": "DeleteLastInsertedBooks" - } - }, - "rest": { - "enabled": true, - "methods": [ - "post" - ] - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "execute" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "execute" - } - ] - } - ] - }, - "UpdateBookTitle": { - "source": { - "object": "update_book_title", - "type": "stored-procedure", - "parameters": { - "id": 1, - "title": "Testing Tonight" - } - }, - "graphql": { - "enabled": true, - "operation": "mutation", - "type": { - "singular": "UpdateBookTitle", - "plural": "UpdateBookTitles" - } - }, - "rest": { - "enabled": true, - "methods": [ - "post" - ] - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "execute" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "execute" - } - ] - } - ] - }, - "GetAuthorsHistoryByFirstName": { - "source": { - "object": "get_authors_history_by_first_name", - "type": "stored-procedure", - "parameters": { - "firstName": "Aaron" - } - }, - "graphql": { - "enabled": true, - "operation": "mutation", - "type": { - "singular": "SearchAuthorByFirstName", - "plural": "SearchAuthorByFirstNames" - } - }, - "rest": { - "enabled": true, - "methods": [ - "post" - ] - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "execute" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "execute" - } - ] - } - ] - }, - "InsertAndDisplayAllBooksUnderGivenPublisher": { - "source": { - "object": "insert_and_display_all_books_for_given_publisher", - "type": "stored-procedure", - "parameters": { - "title": "MyTitle", - "publisher_name": "MyPublisher" - } - }, - "graphql": { - "enabled": true, - "operation": "mutation", - "type": { - "singular": "InsertAndDisplayAllBooksUnderGivenPublisher", - "plural": "InsertAndDisplayAllBooksUnderGivenPublishers" - } - }, - "rest": { - "enabled": true, - "methods": [ - "post" - ] - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "execute" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "execute" - } - ] - } - ] - }, - "GQLmappings": { - "source": { - "object": "GQLmappings", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "GQLmappings", - "plural": "GQLmappings" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "*" - } - ] - } - ], - "mappings": { - "__column1": "column1", - "__column2": "column2" - } - }, - "Bookmarks": { - "source": { - "object": "bookmarks", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "Bookmarks", - "plural": "Bookmarks" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "*" - } - ] - } - ] - }, - "MappedBookmarks": { - "source": { - "object": "mappedbookmarks", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "MappedBookmarks", - "plural": "MappedBookmarks" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - }, - { - "role": "authenticated", - "actions": [ - { - "action": "*" - } - ] - } - ], - "mappings": { - "id": "bkid", - "bkname": "name" - } - }, - "FteData": { - "source": { - "object": "fte_data", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "FteData", - "plural": "FteData" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - } - ] - }, - "InternData": { - "source": { - "object": "intern_data", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "InternData", - "plural": "InternData" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - } - ] - }, - "BooksSold": { - "source": { - "object": "books_sold", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "books_sold", - "plural": "books_sold" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - } - ] - }, - "DefaultBuiltInFunction": { - "source": { - "object": "default_with_function_table", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "DefaultBuiltInFunction", - "plural": "DefaultBuiltInFunctions" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "create", - "fields": { - "exclude": [ - "current_date", - "next_date" - ] - } - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - } - ] - }, - "PublisherNF": { - "source": { - "object": "publishers", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "PublisherNF", - "plural": "PublisherNFs" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "TestNestedFilter_EntityReadForbidden", - "actions": [ - { - "action": "read" - } - ] - }, - { - "role": "TestNestedFilter_ColumnForbidden", - "actions": [ - { - "action": "read" - } - ] - }, - { - "role": "TestNestedFilterChained_EntityReadForbidden", - "actions": [ - { - "action": "create" - } - ] - }, - { - "role": "TestNestedFilterChained_ColumnForbidden", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [ - "name" - ] - } - } - ] - } - ], - "relationships": { - "books": { - "cardinality": "many", - "target.entity": "BookNF", - "source.fields": [], - "target.fields": [], - "linking.source.fields": [], - "linking.target.fields": [] - } - } - }, - "BookNF": { - "source": { - "object": "books", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "bookNF", - "plural": "booksNF" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "TestNestedFilter_EntityReadForbidden", - "actions": [ - { - "action": "read" - } - ] - }, - { - "role": "TestNestedFilter_ColumnForbidden", - "actions": [ - { - "action": "read" - } - ] - }, - { - "role": "TestNestedFilterChained_EntityReadForbidden", - "actions": [ - { - "action": "read" - } - ] - }, - { - "role": "TestNestedFilterChained_ColumnForbidden", - "actions": [ - { - "action": "read" - } - ] - }, - { - "role": "TestFieldExcludedForAggregation", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [ - "publisher_id" - ] - } - } - ] - } - ], - "mappings": { - "id": "id", - "title": "title" - }, - "relationships": { - "publishers": { - "cardinality": "one", - "target.entity": "PublisherNF", - "source.fields": [], - "target.fields": [], - "linking.source.fields": [], - "linking.target.fields": [] - }, - "websiteplacement": { - "cardinality": "one", - "target.entity": "BookWebsitePlacement", - "source.fields": [], - "target.fields": [], - "linking.source.fields": [], - "linking.target.fields": [] - }, - "reviews": { - "cardinality": "many", - "target.entity": "Review", - "source.fields": [], - "target.fields": [], - "linking.source.fields": [], - "linking.target.fields": [] - }, - "authors": { - "cardinality": "many", - "target.entity": "AuthorNF", - "source.fields": [ - "id" - ], - "target.fields": [ - "id" - ], - "linking.object": "book_author_link", - "linking.source.fields": [ - "book_id" - ], - "linking.target.fields": [ - "author_id" - ] - } - } - }, - "AuthorNF": { - "source": { - "object": "authors", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "AuthorNF", - "plural": "AuthorNFs" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "authenticated", - "actions": [ - { - "action": "create" - }, - { - "action": "read" - }, - { - "action": "update" - }, - { - "action": "delete" - } - ] - }, - { - "role": "TestNestedFilter_EntityReadForbidden", - "actions": [ - { - "action": "create", - "fields": { - "exclude": [ - "name" - ] - } - } - ] - }, - { - "role": "TestNestedFilter_ColumnForbidden", - "actions": [ - { - "action": "read", - "fields": { - "exclude": [ - "name" - ] - } - } - ] - }, - { - "role": "TestNestedFilterChained_EntityReadForbidden", - "actions": [ - { - "action": "read" - } - ] - }, - { - "role": "TestNestedFilterChained_ColumnForbidden", - "actions": [ - { - "action": "read" - } - ] - } - ], - "relationships": { - "books": { - "cardinality": "many", - "target.entity": "BookNF", - "source.fields": [], - "target.fields": [], - "linking.object": "book_author_link", - "linking.source.fields": [], - "linking.target.fields": [] - } - } - }, - "dbo_DimAccount": { - "source": { - "object": "DimAccount", - "type": "table" - }, - "graphql": { - "enabled": true, - "type": { - "singular": "dbo_DimAccount", - "plural": "dbo_DimAccounts" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - } - ], - "relationships": { - "parent_account": { - "cardinality": "one", - "target.entity": "dbo_DimAccount", - "source.fields": [ - "ParentAccountKey" - ], - "target.fields": [ - "AccountKey" - ], - "linking.source.fields": [], - "linking.target.fields": [] - }, - "child_accounts": { - "cardinality": "many", - "target.entity": "dbo_DimAccount", - "source.fields": [ - "AccountKey" - ], - "target.fields": [ - "ParentAccountKey" - ], - "linking.source.fields": [], - "linking.target.fields": [] - } - } - }, - "DateOnlyTable": { - "source": { - "object": "date_only_table", - "type": "table", - "key-fields": [ - "event_date" - ] - }, - "graphql": { - "enabled": true, - "type": { - "singular": "DateOnlyTable", - "plural": "DateOnlyTables" - } - }, - "rest": { - "enabled": true - }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "*" - } - ] - } - ] - }, - "GetBooksAuth": { - "source": { - "object": "get_books", - "type": "stored-procedure" - }, - "graphql": { - "enabled": true, - "operation": "query", - "type": { - "singular": "GetBooksAuth", - "plural": "GetBooksAuths" - } - }, - "rest": { - "enabled": true, - "methods": [ - "get" - ] - }, - "permissions": [ - { - "role": "teststoredprocauth", - "actions": [ - { - "action": "execute" - } - ] - } - ] - } - } +{ + "$schema": "https://github.com/Azure/data-api-builder/releases/download/vmajor.minor.patch/dab.draft.schema.json", + "data-source": { + "database-type": "mssql", + "connection-string": "Server=tcp:127.0.0.1,1433;Persist Security Info=False;User ID=sa;Password=REPLACEME;MultipleActiveResultSets=False;Connection Timeout=5;", + "options": { + "set-session-context": true + } + }, + "runtime": { + "rest": { + "enabled": true, + "path": "/api", + "request-body-strict": true + }, + "graphql": { + "enabled": true, + "path": "/graphql", + "allow-introspection": true, + "multiple-mutations": { + "create": { + "enabled": true + } + } + }, + "mcp": { + "enabled": true, + "path": "/mcp" + }, + "host": { + "cors": { + "origins": [ + "http://localhost:5000" + ], + "allow-credentials": false + }, + "authentication": { + "provider": "StaticWebApps" + }, + "mode": "development" + } + }, + "entities": { + "Publisher": { + "source": { + "object": "publishers", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "Publisher", + "plural": "Publishers" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "read" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "policy_tester_01", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.id eq 1940" + } + }, + { + "action": "update", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + } + }, + { + "action": "create" + }, + { + "action": "delete" + } + ] + }, + { + "role": "policy_tester_02", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.id ne 1940" + } + }, + { + "action": "update", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + } + }, + { + "action": "create" + }, + { + "action": "delete" + } + ] + }, + { + "role": "policy_tester_03", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.id ne 1940" + } + }, + { + "action": "update", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + } + }, + { + "action": "create" + }, + { + "action": "delete" + } + ] + }, + { + "role": "policy_tester_04", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.id eq 1940" + } + }, + { + "action": "update", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + } + }, + { + "action": "create" + }, + { + "action": "delete" + } + ] + }, + { + "role": "policy_tester_06", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.id eq 1940" + } + }, + { + "action": "update", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + } + }, + { + "action": "create" + }, + { + "action": "delete" + } + ] + }, + { + "role": "database_policy_tester", + "actions": [ + { + "action": "create", + "policy": { + "database": "@item.name ne \u0027New publisher\u0027" + } + }, + { + "action": "update", + "policy": { + "database": "@item.id ne 1234" + } + }, + { + "action": "read", + "policy": { + "database": "@item.id ne 1234 or @item.id gt 1940" + } + } + ] + }, + { + "role": "role_multiple_create_policy_tester", + "actions": [ + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + }, + { + "action": "create", + "policy": { + "database": "@item.name ne \u0027Test\u0027" + } + } + ] + } + ], + "relationships": { + "books": { + "cardinality": "many", + "target.entity": "Book", + "source.fields": [ + + ], + "target.fields": [ + + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + } + } + }, + "Publisher_MM": { + "source": { + "object": "publishers_mm", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "Publisher_MM", + "plural": "Publishers_MM" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "*" + } + ] + } + ], + "relationships": { + "books_mm": { + "cardinality": "many", + "target.entity": "Book_MM", + "source.fields": [ + "id" + ], + "target.fields": [ + "publisher_id" + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + } + } + }, + "Stock": { + "source": { + "object": "stocks", + "type": "table" + }, + "rest": { + "enabled": true, + "path": "/commodities" + }, + "graphql": { + "enabled": true, + "type": { + "singular": "Stock", + "plural": "Stocks" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "test_role_with_excluded_fields_on_create", + "actions": [ + { + "action": "create", + "fields": { + "exclude": [ + "piecesAvailable" + ] + } + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "TestNestedFilterFieldIsNull_ColumnForbidden", + "actions": [ + { + "action": "read" + } + ] + }, + { + "role": "TestNestedFilterFieldIsNull_EntityReadForbidden", + "actions": [ + { + "action": "read" + } + ] + }, + { + "role": "database_policy_tester", + "actions": [ + { + "action": "read" + }, + { + "action": "create", + "policy": { + "database": "@item.pieceid ne 6 and @item.piecesAvailable gt 0" + } + }, + { + "action": "update", + "policy": { + "database": "@item.pieceid ne 1" + } + } + ] + }, + { + "role": "test_role_with_noread", + "actions": [ + { + "action": "create" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "test_role_with_excluded_fields", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + "categoryName" + ] + } + }, + { + "action": "create" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "test_role_with_policy_excluded_fields", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + "categoryName" + ] + }, + "policy": { + "database": "@item.piecesAvailable ne 0" + } + }, + { + "action": "create" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + } + ], + "relationships": { + "stocks_price": { + "cardinality": "one", + "target.entity": "stocks_price", + "source.fields": [ + + ], + "target.fields": [ + + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + } + } + }, + "Book": { + "source": { + "object": "books", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "book", + "plural": "books" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "policy_tester_01", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.title eq \u0027Policy-Test-01\u0027" + } + }, + { + "action": "update", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + } + }, + { + "action": "create" + }, + { + "action": "delete" + } + ] + }, + { + "role": "policy_tester_02", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.title ne \u0027Policy-Test-01\u0027" + } + }, + { + "action": "update", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + } + }, + { + "action": "create" + }, + { + "action": "delete" + } + ] + }, + { + "role": "policy_tester_03", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.title eq \u0027Policy-Test-01\u0027" + } + }, + { + "action": "update", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + } + }, + { + "action": "create" + }, + { + "action": "delete" + } + ] + }, + { + "role": "policy_tester_04", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.title ne \u0027Policy-Test-01\u0027" + } + }, + { + "action": "update", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + } + }, + { + "action": "create" + }, + { + "action": "delete" + } + ] + }, + { + "role": "policy_tester_05", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.id ne 9" + } + }, + { + "action": "update", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + } + }, + { + "action": "create" + }, + { + "action": "delete" + } + ] + }, + { + "role": "policy_tester_06", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.id ne 10" + } + }, + { + "action": "create" + }, + { + "action": "delete" + }, + { + "action": "update", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + } + } + ] + }, + { + "role": "policy_tester_07", + "actions": [ + { + "action": "delete", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.id ne 9" + } + }, + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + } + }, + { + "action": "update", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.id ne 9" + } + }, + { + "action": "create" + } + ] + }, + { + "role": "policy_tester_08", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + } + }, + { + "action": "delete", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.id eq 9" + } + }, + { + "action": "update", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.id eq 9" + } + }, + { + "action": "create" + } + ] + }, + { + "role": "test_role_with_noread", + "actions": [ + { + "action": "create" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "test_role_with_excluded_fields", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + "publisher_id" + ] + } + }, + { + "action": "create" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "test_role_with_policy_excluded_fields", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + "publisher_id" + ] + }, + "policy": { + "database": "@item.title ne \u0027Test\u0027" + } + }, + { + "action": "create" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "role_multiple_create_policy_tester", + "actions": [ + { + "action": "update" + }, + { + "action": "delete" + }, + { + "action": "create", + "policy": { + "database": "@item.title ne \u0027Test\u0027" + } + }, + { + "action": "read", + "policy": { + "database": "@item.publisher_id ne 1234" + } + } + ] + } + ], + "mappings": { + "id": "id", + "title": "title" + }, + "relationships": { + "publishers": { + "cardinality": "one", + "target.entity": "Publisher", + "source.fields": [ + + ], + "target.fields": [ + + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + }, + "websiteplacement": { + "cardinality": "one", + "target.entity": "BookWebsitePlacement", + "source.fields": [ + + ], + "target.fields": [ + + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + }, + "reviews": { + "cardinality": "many", + "target.entity": "Review", + "source.fields": [ + + ], + "target.fields": [ + + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + }, + "authors": { + "cardinality": "many", + "target.entity": "Author", + "source.fields": [ + "id" + ], + "target.fields": [ + "id" + ], + "linking.object": "book_author_link", + "linking.source.fields": [ + "book_id" + ], + "linking.target.fields": [ + "author_id" + ] + } + } + }, + "Default_Books": { + "source": { + "object": "default_books", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "default_book", + "plural": "default_books" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + } + ] + }, + "Book_MM": { + "source": { + "object": "books_mm", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "book_mm", + "plural": "books_mm" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "*" + } + ] + } + ], + "relationships": { + "publishers": { + "cardinality": "one", + "target.entity": "Publisher_MM", + "source.fields": [ + "publisher_id" + ], + "target.fields": [ + "id" + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + }, + "reviews": { + "cardinality": "many", + "target.entity": "Review_MM", + "source.fields": [ + "id" + ], + "target.fields": [ + "book_id" + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + }, + "authors": { + "cardinality": "many", + "target.entity": "Author_MM", + "source.fields": [ + "id" + ], + "target.fields": [ + "id" + ], + "linking.object": "book_author_link_mm", + "linking.source.fields": [ + "book_id" + ], + "linking.target.fields": [ + "author_id" + ] + } + } + }, + "BookWebsitePlacement": { + "source": { + "object": "book_website_placements", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "BookWebsitePlacement", + "plural": "BookWebsitePlacements" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "read" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "delete", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@claims.userId eq @item.id" + } + }, + { + "action": "create" + }, + { + "action": "update" + } + ] + } + ], + "relationships": { + "books": { + "cardinality": "one", + "target.entity": "Book", + "source.fields": [ + + ], + "target.fields": [ + + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + } + } + }, + "Author": { + "source": { + "object": "authors", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "Author", + "plural": "Authors" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "read" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + } + ], + "relationships": { + "books": { + "cardinality": "many", + "target.entity": "Book", + "source.fields": [ + + ], + "target.fields": [ + + ], + "linking.object": "book_author_link", + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + } + } + }, + "Author_MM": { + "source": { + "object": "authors_mm", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "author_mm", + "plural": "authors_mm" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "*" + } + ] + } + ], + "relationships": { + "books": { + "cardinality": "many", + "target.entity": "Book_MM", + "source.fields": [ + "id" + ], + "target.fields": [ + "id" + ], + "linking.object": "book_author_link_mm", + "linking.source.fields": [ + "author_id" + ], + "linking.target.fields": [ + "book_id" + ] + } + } + }, + "Revenue": { + "source": { + "object": "revenues", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "Revenue", + "plural": "Revenues" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + }, + { + "role": "database_policy_tester", + "actions": [ + { + "action": "create", + "policy": { + "database": "@item.revenue gt 1000" + } + } + ] + } + ] + }, + "Review": { + "source": { + "object": "reviews", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "review", + "plural": "reviews" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "role_multiple_create_policy_tester", + "actions": [ + { + "action": "update" + }, + { + "action": "delete" + }, + { + "action": "create", + "policy": { + "database": "@item.content ne \u0027Great\u0027" + } + }, + { + "action": "read", + "policy": { + "database": "@item.websiteuser_id ne 1" + } + } + ] + } + ], + "relationships": { + "books": { + "cardinality": "one", + "target.entity": "Book", + "source.fields": [ + + ], + "target.fields": [ + + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + }, + "website_users": { + "cardinality": "one", + "target.entity": "WebsiteUser", + "source.fields": [ + "websiteuser_id" + ], + "target.fields": [ + "id" + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + } + } + }, + "Review_MM": { + "source": { + "object": "reviews_mm", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "review_mm", + "plural": "reviews_mm" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "*" + } + ] + } + ], + "relationships": { + "books": { + "cardinality": "one", + "target.entity": "Book_MM", + "source.fields": [ + "book_id" + ], + "target.fields": [ + "id" + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + }, + "website_users": { + "cardinality": "one", + "target.entity": "WebsiteUser_MM", + "source.fields": [ + "websiteuser_id" + ], + "target.fields": [ + "id" + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + } + } + }, + "Comic": { + "source": { + "object": "comics", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "Comic", + "plural": "Comics" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "TestNestedFilterManyOne_ColumnForbidden", + "actions": [ + { + "action": "read" + } + ] + }, + { + "role": "TestNestedFilterManyOne_EntityReadForbidden", + "actions": [ + { + "action": "read" + } + ] + }, + { + "role": "TestNestedFilterOneMany_ColumnForbidden", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + "categoryName" + ] + } + } + ] + }, + { + "role": "TestNestedFilterOneMany_EntityReadForbidden", + "actions": [ + { + "action": "create" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + } + ], + "relationships": { + "myseries": { + "cardinality": "one", + "target.entity": "series", + "source.fields": [ + + ], + "target.fields": [ + + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + } + } + }, + "Broker": { + "source": { + "object": "brokers", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": false, + "type": { + "singular": "Broker", + "plural": "Brokers" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "read" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "update" + }, + { + "action": "read" + }, + { + "action": "delete" + } + ] + } + ] + }, + "WebsiteUser": { + "source": { + "object": "website_users", + "type": "table" + }, + "rest": { + "enabled": false + }, + "graphql": { + "enabled": true, + "type": { + "singular": "websiteUser", + "plural": "websiteUsers" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "delete" + }, + { + "action": "update" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "delete" + }, + { + "action": "update" + } + ] + } + ], + "relationships": { + "reviews": { + "cardinality": "many", + "target.entity": "Review", + "source.fields": [ + "id" + ], + "target.fields": [ + "websiteuser_id" + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + } + } + }, + "WebsiteUser_MM": { + "source": { + "object": "website_users_mm", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "websiteuser_mm", + "plural": "websiteusers_mm" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "*" + } + ] + } + ], + "relationships": { + "reviews": { + "cardinality": "many", + "target.entity": "Review_MM", + "source.fields": [ + "id" + ], + "target.fields": [ + "websiteuser_id" + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + } + } + }, + "SupportedType": { + "source": { + "object": "type_table", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "SupportedType", + "plural": "SupportedTypes" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "delete" + }, + { + "action": "update" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "delete" + }, + { + "action": "update" + } + ] + } + ], + "mappings": { + "id": "typeid" + } + }, + "stocks_price": { + "source": { + "object": "stocks_price", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "stocks_price", + "plural": "stocks_prices" + } + }, + "permissions": [ + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "anonymous", + "actions": [ + { + "action": "read" + } + ] + }, + { + "role": "TestNestedFilterFieldIsNull_ColumnForbidden", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + "price" + ] + } + } + ] + }, + { + "role": "TestNestedFilterFieldIsNull_EntityReadForbidden", + "actions": [ + { + "action": "create" + } + ] + }, + { + "role": "test_role_with_excluded_fields_on_create", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + } + ], + "relationships": { + "Stock": { + "cardinality": "one", + "target.entity": "Stock", + "source.fields": [ + + ], + "target.fields": [ + + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + } + } + }, + "Tree": { + "source": { + "object": "trees", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": false, + "type": { + "singular": "Tree", + "plural": "Trees" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + } + ], + "mappings": { + "species": "Scientific Name", + "region": "United State\u0027s Region" + } + }, + "Shrub": { + "source": { + "object": "trees", + "type": "table" + }, + "rest": { + "enabled": true, + "path": "/plants" + }, + "graphql": { + "enabled": true, + "type": { + "singular": "Shrub", + "plural": "Shrubs" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + } + ], + "mappings": { + "species": "fancyName" + }, + "relationships": { + "fungus": { + "cardinality": "one", + "target.entity": "Fungus", + "source.fields": [ + "species" + ], + "target.fields": [ + "habitat" + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + } + } + }, + "Fungus": { + "source": { + "object": "fungi", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "fungus", + "plural": "fungi" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "policy_tester_01", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.region ne \u0027northeast\u0027" + } + } + ] + } + ], + "mappings": { + "spores": "hazards" + }, + "relationships": { + "Shrub": { + "cardinality": "one", + "target.entity": "Shrub", + "source.fields": [ + "habitat" + ], + "target.fields": [ + "species" + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + } + } + }, + "books_view_all": { + "source": { + "object": "books_view_all", + "type": "view", + "key-fields": [ + "id" + ] + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "books_view_all", + "plural": "books_view_alls" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + } + ] + }, + "books_view_with_mapping": { + "source": { + "object": "books_view_with_mapping", + "type": "view", + "key-fields": [ + "id" + ] + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "books_view_with_mapping", + "plural": "books_view_with_mappings" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + } + ], + "mappings": { + "id": "book_id" + } + }, + "stocks_view_selected": { + "source": { + "object": "stocks_view_selected", + "type": "view", + "key-fields": [ + "categoryid", + "pieceid" + ] + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "stocks_view_selected", + "plural": "stocks_view_selecteds" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + } + ] + }, + "books_publishers_view_composite": { + "source": { + "object": "books_publishers_view_composite", + "type": "view", + "key-fields": [ + "id", + "pub_id" + ] + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "books_publishers_view_composite", + "plural": "books_publishers_view_composites" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + } + ] + }, + "books_publishers_view_composite_insertable": { + "source": { + "object": "books_publishers_view_composite_insertable", + "type": "view", + "key-fields": [ + "id", + "publisher_id" + ] + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "books_publishers_view_composite_insertable", + "plural": "books_publishers_view_composite_insertables" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + } + ] + }, + "Empty": { + "source": { + "object": "empty_table", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "Empty", + "plural": "Empties" + } + }, + "permissions": [ + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "anonymous", + "actions": [ + { + "action": "read" + } + ] + } + ] + }, + "Notebook": { + "source": { + "object": "notebooks", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "Notebook", + "plural": "Notebooks" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "create" + }, + { + "action": "update" + }, + { + "action": "delete" + }, + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item ne 1" + } + } + ] + } + ] + }, + "Journal": { + "source": { + "object": "journals", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "Journal", + "plural": "Journals" + } + }, + "permissions": [ + { + "role": "policy_tester_noupdate", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + } + }, + { + "action": "update", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.id ne 1" + } + }, + { + "action": "create" + }, + { + "action": "delete" + } + ] + }, + { + "role": "policy_tester_update_noread", + "actions": [ + { + "action": "delete", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.id eq 1" + } + }, + { + "action": "read", + "fields": { + "exclude": [ + "*" + ] + } + }, + { + "action": "update", + "fields": { + "exclude": [ + + ], + "include": [ + "*" + ] + }, + "policy": { + "database": "@item.id eq 1" + } + }, + { + "action": "create" + } + ] + }, + { + "role": "authorizationHandlerTester", + "actions": [ + { + "action": "read" + } + ] + } + ] + }, + "ArtOfWar": { + "source": { + "object": "aow", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": false, + "type": { + "singular": "ArtOfWar", + "plural": "ArtOfWars" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "*" + } + ] + } + ], + "mappings": { + "DetailAssessmentAndPlanning": "始計", + "WagingWar": "作戰", + "StrategicAttack": "謀攻", + "NoteNum": "┬─┬ノ( º _ ºノ)" + } + }, + "series": { + "source": { + "object": "series", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "series", + "plural": "series" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + }, + { + "role": "TestNestedFilterManyOne_ColumnForbidden", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + "name" + ] + } + } + ] + }, + { + "role": "TestNestedFilterManyOne_EntityReadForbidden", + "actions": [ + { + "action": "create" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "TestNestedFilterOneMany_ColumnForbidden", + "actions": [ + { + "action": "read" + } + ] + }, + { + "role": "TestNestedFilterOneMany_EntityReadForbidden", + "actions": [ + { + "action": "read" + } + ] + } + ], + "relationships": { + "comics": { + "cardinality": "many", + "target.entity": "Comic", + "source.fields": [ + + ], + "target.fields": [ + + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + } + } + }, + "Sales": { + "source": { + "object": "sales", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "Sales", + "plural": "Sales" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "*" + } + ] + } + ] + }, + "User_NonAutogenRelationshipColumn": { + "source": { + "object": "users", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "User_NonAutogenRelationshipColumn", + "plural": "User_NonAutogenRelationshipColumns" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + } + ], + "relationships": { + "UserProfile_NonAutogenRelationshipColumn": { + "cardinality": "one", + "target.entity": "UserProfile", + "source.fields": [ + "username" + ], + "target.fields": [ + "username" + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + } + } + }, + "UserProfile": { + "source": { + "object": "user_profiles", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "UserProfile", + "plural": "UserProfiles" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + } + ] + }, + "User_AutogenRelationshipColumn": { + "source": { + "object": "users", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "User_AutogenRelationshipColumn", + "plural": "User_AutogenRelationshipColumns" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + } + ], + "relationships": { + "UserProfile_AutogenRelationshipColumn": { + "cardinality": "one", + "target.entity": "UserProfile", + "source.fields": [ + "userid" + ], + "target.fields": [ + "profileid" + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + } + } + }, + "User_AutogenToNonAutogenRelationshipColumn": { + "source": { + "object": "users", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "User_AutogenToNonAutogenRelationshipColumn", + "plural": "User_AutogenToNonAutogenRelationshipColumns" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + } + ], + "relationships": { + "UserProfile_AutogenToNonAutogenRelationshipColumn": { + "cardinality": "one", + "target.entity": "UserProfile", + "source.fields": [ + "userid", + "username" + ], + "target.fields": [ + "userid", + "username" + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + } + } + }, + "User_RepeatedReferencingColumnToOneEntity": { + "source": { + "object": "users", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "User_RepeatedReferencingColumnToOneEntity", + "plural": "User_RepeatedReferencingColumnToOneEntities" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + } + ], + "relationships": { + "UserProfile": { + "cardinality": "one", + "target.entity": "UserProfile", + "source.fields": [ + "username", + "username" + ], + "target.fields": [ + "profilepictureurl", + "username" + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + } + } + }, + "UserProfile_RepeatedReferencingColumnToTwoEntities": { + "source": { + "object": "user_profiles", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "UserProfile_RepeatedReferencingColumnToTwoEntities", + "plural": "UserProfile_RepeatedReferencingColumnToTwoEntities" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + } + ], + "relationships": { + "book": { + "cardinality": "one", + "target.entity": "Book", + "source.fields": [ + "userid" + ], + "target.fields": [ + "id" + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + }, + "publisher": { + "cardinality": "one", + "target.entity": "Publisher", + "source.fields": [ + "userid" + ], + "target.fields": [ + "id" + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + } + } + }, + "GetBooks": { + "source": { + "object": "get_books", + "type": "stored-procedure" + }, + "rest": { + "enabled": true, + "methods": [ + "get" + ] + }, + "graphql": { + "enabled": true, + "operation": "query", + "type": { + "singular": "GetBooks", + "plural": "GetBooks" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "execute" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "execute" + } + ] + } + ] + }, + "GetBook": { + "source": { + "object": "get_book_by_id", + "type": "stored-procedure" + }, + "rest": { + "enabled": true, + "methods": [ + "get" + ] + }, + "graphql": { + "enabled": false, + "operation": "mutation", + "type": { + "singular": "GetBook", + "plural": "GetBooks" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "execute" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "execute" + } + ] + } + ] + }, + "GetPublisher": { + "source": { + "object": "get_publisher_by_id", + "type": "stored-procedure" + }, + "rest": { + "enabled": true, + "methods": [ + "post" + ] + }, + "graphql": { + "enabled": true, + "operation": "query", + "type": { + "singular": "GetPublisher", + "plural": "GetPublishers" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "execute" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "execute" + } + ] + } + ] + }, + "InsertBook": { + "source": { + "object": "insert_book", + "type": "stored-procedure", + "parameters": [ + { + "name": "title", + "required": false, + "default": "randomX" + }, + { + "name": "publisher_id", + "required": false, + "default": "1234" + } + ] + }, + "rest": { + "enabled": true, + "methods": [ + "post" + ] + }, + "graphql": { + "enabled": true, + "operation": "mutation", + "type": { + "singular": "InsertBook", + "plural": "InsertBooks" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "execute" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "execute" + } + ] + } + ] + }, + "CountBooks": { + "source": { + "object": "count_books", + "type": "stored-procedure" + }, + "rest": { + "enabled": true, + "methods": [ + "post" + ] + }, + "graphql": { + "enabled": true, + "operation": "mutation", + "type": { + "singular": "CountBooks", + "plural": "CountBooks" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "execute" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "execute" + } + ] + } + ] + }, + "DeleteLastInsertedBook": { + "source": { + "object": "delete_last_inserted_book", + "type": "stored-procedure" + }, + "rest": { + "enabled": true, + "methods": [ + "post" + ] + }, + "graphql": { + "enabled": true, + "operation": "mutation", + "type": { + "singular": "DeleteLastInsertedBook", + "plural": "DeleteLastInsertedBooks" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "execute" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "execute" + } + ] + } + ] + }, + "UpdateBookTitle": { + "source": { + "object": "update_book_title", + "type": "stored-procedure", + "parameters": [ + { + "name": "id", + "required": false, + "default": "1" + }, + { + "name": "title", + "required": false, + "default": "Testing Tonight" + } + ] + }, + "rest": { + "enabled": true, + "methods": [ + "post" + ] + }, + "graphql": { + "enabled": true, + "operation": "mutation", + "type": { + "singular": "UpdateBookTitle", + "plural": "UpdateBookTitles" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "execute" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "execute" + } + ] + } + ] + }, + "GetAuthorsHistoryByFirstName": { + "source": { + "object": "get_authors_history_by_first_name", + "type": "stored-procedure", + "parameters": [ + { + "name": "firstName", + "required": false, + "default": "Aaron" + } + ] + }, + "rest": { + "enabled": true, + "methods": [ + "post" + ] + }, + "graphql": { + "enabled": true, + "operation": "mutation", + "type": { + "singular": "SearchAuthorByFirstName", + "plural": "SearchAuthorByFirstNames" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "execute" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "execute" + } + ] + } + ] + }, + "InsertAndDisplayAllBooksUnderGivenPublisher": { + "source": { + "object": "insert_and_display_all_books_for_given_publisher", + "type": "stored-procedure", + "parameters": [ + { + "name": "title", + "required": false, + "default": "MyTitle" + }, + { + "name": "publisher_name", + "required": false, + "default": "MyPublisher" + } + ] + }, + "rest": { + "enabled": true, + "methods": [ + "post" + ] + }, + "graphql": { + "enabled": true, + "operation": "mutation", + "type": { + "singular": "InsertAndDisplayAllBooksUnderGivenPublisher", + "plural": "InsertAndDisplayAllBooksUnderGivenPublishers" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "execute" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "execute" + } + ] + } + ] + }, + "GQLmappings": { + "source": { + "object": "GQLmappings", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "GQLmappings", + "plural": "GQLmappings" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "*" + } + ] + } + ], + "mappings": { + "__column1": "column1", + "__column2": "column2" + } + }, + "Bookmarks": { + "source": { + "object": "bookmarks", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "Bookmarks", + "plural": "Bookmarks" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "*" + } + ] + } + ] + }, + "MappedBookmarks": { + "source": { + "object": "mappedbookmarks", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "MappedBookmarks", + "plural": "MappedBookmarks" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "*" + } + ] + } + ], + "mappings": { + "id": "bkid", + "bkname": "name" + } + }, + "FteData": { + "source": { + "object": "fte_data", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "FteData", + "plural": "FteData" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + } + ] + }, + "InternData": { + "source": { + "object": "intern_data", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "InternData", + "plural": "InternData" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + } + ] + }, + "BooksSold": { + "source": { + "object": "books_sold", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "books_sold", + "plural": "books_sold" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + } + ] + }, + "DefaultBuiltInFunction": { + "source": { + "object": "default_with_function_table", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "DefaultBuiltInFunction", + "plural": "DefaultBuiltInFunctions" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "create", + "fields": { + "exclude": [ + "current_date", + "next_date" + ] + } + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + } + ] + }, + "PublisherNF": { + "source": { + "object": "publishers", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "PublisherNF", + "plural": "PublisherNFs" + } + }, + "permissions": [ + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "TestNestedFilter_EntityReadForbidden", + "actions": [ + { + "action": "read" + } + ] + }, + { + "role": "TestNestedFilter_ColumnForbidden", + "actions": [ + { + "action": "read" + } + ] + }, + { + "role": "TestNestedFilterChained_EntityReadForbidden", + "actions": [ + { + "action": "create" + } + ] + }, + { + "role": "TestNestedFilterChained_ColumnForbidden", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + "name" + ] + } + } + ] + } + ], + "relationships": { + "books": { + "cardinality": "many", + "target.entity": "BookNF", + "source.fields": [ + + ], + "target.fields": [ + + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + } + } + }, + "BookNF": { + "source": { + "object": "books", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "bookNF", + "plural": "booksNF" + } + }, + "permissions": [ + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "TestNestedFilter_EntityReadForbidden", + "actions": [ + { + "action": "read" + } + ] + }, + { + "role": "TestNestedFilter_ColumnForbidden", + "actions": [ + { + "action": "read" + } + ] + }, + { + "role": "TestNestedFilterChained_EntityReadForbidden", + "actions": [ + { + "action": "read" + } + ] + }, + { + "role": "TestNestedFilterChained_ColumnForbidden", + "actions": [ + { + "action": "read" + } + ] + }, + { + "role": "TestFieldExcludedForAggregation", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + "publisher_id" + ] + } + } + ] + } + ], + "mappings": { + "id": "id", + "title": "title" + }, + "relationships": { + "publishers": { + "cardinality": "one", + "target.entity": "PublisherNF", + "source.fields": [ + + ], + "target.fields": [ + + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + }, + "websiteplacement": { + "cardinality": "one", + "target.entity": "BookWebsitePlacement", + "source.fields": [ + + ], + "target.fields": [ + + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + }, + "reviews": { + "cardinality": "many", + "target.entity": "Review", + "source.fields": [ + + ], + "target.fields": [ + + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + }, + "authors": { + "cardinality": "many", + "target.entity": "AuthorNF", + "source.fields": [ + "id" + ], + "target.fields": [ + "id" + ], + "linking.object": "book_author_link", + "linking.source.fields": [ + "book_id" + ], + "linking.target.fields": [ + "author_id" + ] + } + } + }, + "AuthorNF": { + "source": { + "object": "authors", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "AuthorNF", + "plural": "AuthorNFs" + } + }, + "permissions": [ + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + }, + { + "role": "TestNestedFilter_EntityReadForbidden", + "actions": [ + { + "action": "create", + "fields": { + "exclude": [ + "name" + ] + } + } + ] + }, + { + "role": "TestNestedFilter_ColumnForbidden", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + "name" + ] + } + } + ] + }, + { + "role": "TestNestedFilterChained_EntityReadForbidden", + "actions": [ + { + "action": "read" + } + ] + }, + { + "role": "TestNestedFilterChained_ColumnForbidden", + "actions": [ + { + "action": "read" + } + ] + } + ], + "relationships": { + "books": { + "cardinality": "many", + "target.entity": "BookNF", + "source.fields": [ + + ], + "target.fields": [ + + ], + "linking.object": "book_author_link", + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + } + } + }, + "dbo_DimAccount": { + "source": { + "object": "DimAccount", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "dbo_DimAccount", + "plural": "dbo_DimAccounts" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + } + ], + "relationships": { + "parent_account": { + "cardinality": "one", + "target.entity": "dbo_DimAccount", + "source.fields": [ + "ParentAccountKey" + ], + "target.fields": [ + "AccountKey" + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + }, + "child_accounts": { + "cardinality": "many", + "target.entity": "dbo_DimAccount", + "source.fields": [ + "AccountKey" + ], + "target.fields": [ + "ParentAccountKey" + ], + "linking.source.fields": [ + + ], + "linking.target.fields": [ + + ] + } + } + }, + "DateOnlyTable": { + "source": { + "object": "date_only_table", + "type": "table", + "key-fields": [ + "event_date" + ] + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "DateOnlyTable", + "plural": "DateOnlyTables" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + } + ] + }, + "GetBooksAuth": { + "source": { + "object": "get_books", + "type": "stored-procedure" + }, + "rest": { + "enabled": true, + "methods": [ + "get" + ] + }, + "graphql": { + "enabled": true, + "operation": "query", + "type": { + "singular": "GetBooksAuth", + "plural": "GetBooksAuths" + } + }, + "permissions": [ + { + "role": "teststoredprocauth", + "actions": [ + { + "action": "execute" + } + ] + } + ] + } + } } diff --git a/src/Service.Tests/dab-config.MySql.json b/src/Service.Tests/dab-config.MySql.json index a0b36b0388..b130a4a12d 100644 --- a/src/Service.Tests/dab-config.MySql.json +++ b/src/Service.Tests/dab-config.MySql.json @@ -16,6 +16,10 @@ "path": "/graphql", "allow-introspection": true }, + "mcp": { + "enabled": true, + "path": "/mcp" + }, "host": { "cors": { "origins": [ @@ -35,6 +39,9 @@ "object": "publishers", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -42,9 +49,6 @@ "plural": "Publishers" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -268,6 +272,10 @@ "object": "stocks", "type": "table" }, + "rest": { + "enabled": true, + "path": "/commodities" + }, "graphql": { "enabled": true, "type": { @@ -275,10 +283,6 @@ "plural": "Stocks" } }, - "rest": { - "enabled": true, - "path": "/commodities" - }, "permissions": [ { "role": "anonymous", @@ -392,6 +396,9 @@ "object": "books", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -399,9 +406,6 @@ "plural": "books" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -821,11 +825,49 @@ } } }, + "Default_Books": { + "source": { + "object": "default_books", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "default_book", + "plural": "default_books" + } + }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } + ] + } + ] + }, "BookNF": { "source": { "object": "books", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -833,9 +875,6 @@ "plural": "booksNF" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -852,6 +891,9 @@ "object": "book_website_placements", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -859,9 +901,6 @@ "plural": "BookWebsitePlacements" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -911,6 +950,9 @@ "object": "authors", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -918,9 +960,6 @@ "plural": "Authors" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -965,6 +1004,9 @@ "object": "reviews", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -972,9 +1014,6 @@ "plural": "reviews" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1024,6 +1063,9 @@ "object": "comics", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1031,9 +1073,6 @@ "plural": "Comics" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1083,6 +1122,9 @@ "object": "brokers", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": false, "type": { @@ -1090,9 +1132,6 @@ "plural": "Brokers" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1126,6 +1165,9 @@ "object": "website_users", "type": "table" }, + "rest": { + "enabled": false + }, "graphql": { "enabled": true, "type": { @@ -1133,9 +1175,6 @@ "plural": "websiteUsers" } }, - "rest": { - "enabled": false - }, "permissions": [ { "role": "anonymous", @@ -1178,6 +1217,9 @@ "object": "type_table", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1185,9 +1227,6 @@ "plural": "SupportedTypes" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1233,6 +1272,9 @@ "object": "stocks_price", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1240,9 +1282,6 @@ "plural": "stocks_prices" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1276,6 +1315,9 @@ "object": "trees", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": false, "type": { @@ -1283,9 +1325,6 @@ "plural": "Trees" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1332,6 +1371,10 @@ "object": "trees", "type": "table" }, + "rest": { + "enabled": true, + "path": "/plants" + }, "graphql": { "enabled": true, "type": { @@ -1339,10 +1382,6 @@ "plural": "Shrubs" } }, - "rest": { - "enabled": true, - "path": "/plants" - }, "permissions": [ { "role": "anonymous", @@ -1386,8 +1425,12 @@ "fungus": { "cardinality": "one", "target.entity": "Fungus", - "source.fields": [ "species" ], - "target.fields": [ "habitat" ], + "source.fields": [ + "species" + ], + "target.fields": [ + "habitat" + ], "linking.source.fields": [], "linking.target.fields": [] } @@ -1398,6 +1441,9 @@ "object": "fungi", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1405,9 +1451,6 @@ "plural": "fungi" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1465,11 +1508,15 @@ "spores": "hazards" }, "relationships": { - "shrub": { + "Shrub": { "cardinality": "one", "target.entity": "Shrub", - "source.fields": [ "habitat" ], - "target.fields": [ "species" ], + "source.fields": [ + "habitat" + ], + "target.fields": [ + "species" + ], "linking.source.fields": [], "linking.target.fields": [] } @@ -1483,6 +1530,9 @@ "id" ] }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1490,9 +1540,6 @@ "plural": "books_view_alls" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1529,6 +1576,9 @@ "id" ] }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1536,9 +1586,6 @@ "plural": "books_view_with_mappings" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1562,6 +1609,9 @@ "pieceid" ] }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1569,9 +1619,6 @@ "plural": "stocks_view_selecteds" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1609,6 +1656,9 @@ "pub_id" ] }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1616,9 +1666,6 @@ "plural": "books_publishers_view_composites" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1656,6 +1703,9 @@ "publisher_id" ] }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1663,9 +1713,6 @@ "plural": "books_publishers_view_composite_insertables" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1682,6 +1729,9 @@ "object": "empty_table", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1689,9 +1739,6 @@ "plural": "Empties" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "authenticated", @@ -1725,6 +1772,9 @@ "object": "notebooks", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1732,9 +1782,6 @@ "plural": "Notebooks" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1769,6 +1816,9 @@ "object": "journals", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1776,9 +1826,6 @@ "plural": "Journals" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "policy_tester_noupdate", @@ -1867,6 +1914,9 @@ "object": "aow", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": false, "type": { @@ -1874,9 +1924,6 @@ "plural": "ArtOfWars" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1907,6 +1954,9 @@ "object": "series", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1914,9 +1964,6 @@ "plural": "series" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1943,6 +1990,9 @@ "object": "sales", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1950,9 +2000,6 @@ "plural": "Sales" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1977,6 +2024,9 @@ "object": "users", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1984,9 +2034,6 @@ "plural": "User_NonAutogenRelationshipColumns" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -2017,6 +2064,9 @@ "object": "user_profiles", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -2024,9 +2074,6 @@ "plural": "UserProfiles" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -2043,6 +2090,9 @@ "object": "users", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -2050,9 +2100,6 @@ "plural": "User_AutogenRelationshipColumns" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -2083,6 +2130,9 @@ "object": "users", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -2090,9 +2140,6 @@ "plural": "User_AutogenToNonAutogenRelationshipColumns" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -2125,6 +2172,9 @@ "object": "GQLmappings", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -2132,9 +2182,6 @@ "plural": "GQLmappings" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -2163,6 +2210,9 @@ "object": "bookmarks", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -2170,9 +2220,6 @@ "plural": "Bookmarks" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -2197,6 +2244,9 @@ "object": "mappedbookmarks", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -2204,9 +2254,6 @@ "plural": "MappedBookmarks" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -2235,6 +2282,9 @@ "object": "books_sold", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -2242,9 +2292,6 @@ "plural": "books_sold" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -2261,12 +2308,16 @@ "object": "default_with_function_table", "type": "table" }, - "graphql": { - "enabled": true - }, "rest": { "enabled": true }, + "graphql": { + "enabled": true, + "type": { + "singular": "DefaultBuiltInFunction", + "plural": "DefaultBuiltInFunctions" + } + }, "permissions": [ { "role": "anonymous", @@ -2274,32 +2325,47 @@ { "action": "create", "fields": { - "include": [ - "*" - ], "exclude": [ "current_date", "next_date" ] } }, - "read", - "update", - "delete" + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" + } ] } ] }, "dbo_DimAccount": { - "source": "dimaccount", + "source": { + "object": "dimaccount", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "dbo_DimAccount", + "plural": "dbo_DimAccounts" + } + }, "permissions": [ { "role": "anonymous", "actions": [ - "read", - "create", - "update", - "delete" + { + "action": "*" + } ] } ], @@ -2312,7 +2378,9 @@ ], "target.fields": [ "AccountKey" - ] + ], + "linking.source.fields": [], + "linking.target.fields": [] }, "child_accounts": { "cardinality": "many", @@ -2322,9 +2390,11 @@ ], "target.fields": [ "ParentAccountKey" - ] + ], + "linking.source.fields": [], + "linking.target.fields": [] } } } } -} +} \ No newline at end of file diff --git a/src/Service.Tests/dab-config.PostgreSql.json b/src/Service.Tests/dab-config.PostgreSql.json index e9a8ddf5ab..0198c478e7 100644 --- a/src/Service.Tests/dab-config.PostgreSql.json +++ b/src/Service.Tests/dab-config.PostgreSql.json @@ -16,6 +16,10 @@ "path": "/graphql", "allow-introspection": true }, + "mcp": { + "enabled": true, + "path": "/mcp" + }, "host": { "cors": { "origins": [ @@ -35,6 +39,9 @@ "object": "publishers", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -42,9 +49,6 @@ "plural": "Publishers" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -268,6 +272,10 @@ "object": "stocks", "type": "table" }, + "rest": { + "enabled": true, + "path": "/commodities" + }, "graphql": { "enabled": true, "type": { @@ -275,10 +283,6 @@ "plural": "Stocks" } }, - "rest": { - "enabled": true, - "path": "/commodities" - }, "permissions": [ { "role": "anonymous", @@ -425,6 +429,9 @@ "object": "books", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -432,9 +439,6 @@ "plural": "books" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -859,6 +863,9 @@ "object": "default_books", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -866,9 +873,6 @@ "plural": "default_books" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -894,6 +898,9 @@ "object": "book_website_placements", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -901,9 +908,6 @@ "plural": "BookWebsitePlacements" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -953,6 +957,9 @@ "object": "authors", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -960,9 +967,6 @@ "plural": "Authors" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1007,6 +1011,9 @@ "object": "reviews", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1014,9 +1021,6 @@ "plural": "reviews" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1066,6 +1070,9 @@ "object": "comics", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1073,9 +1080,6 @@ "plural": "Comics" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1168,6 +1172,9 @@ "object": "brokers", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": false, "type": { @@ -1175,9 +1182,6 @@ "plural": "Brokers" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1211,6 +1215,9 @@ "object": "website_users", "type": "table" }, + "rest": { + "enabled": false + }, "graphql": { "enabled": true, "type": { @@ -1218,9 +1225,6 @@ "plural": "websiteUsers" } }, - "rest": { - "enabled": false - }, "permissions": [ { "role": "anonymous", @@ -1263,6 +1267,9 @@ "object": "type_table", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1270,9 +1277,6 @@ "plural": "SupportedTypes" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1318,6 +1322,9 @@ "object": "stocks_price", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1325,18 +1332,7 @@ "plural": "stocks_prices" } }, - "rest": { - "enabled": true - }, "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "read" - } - ] - }, { "role": "authenticated", "actions": [ @@ -1354,6 +1350,14 @@ } ] }, + { + "role": "anonymous", + "actions": [ + { + "action": "read" + } + ] + }, { "role": "TestNestedFilterFieldIsNull_ColumnForbidden", "actions": [ @@ -1382,6 +1386,9 @@ "object": "trees", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": false, "type": { @@ -1389,9 +1396,6 @@ "plural": "Trees" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1438,6 +1442,10 @@ "object": "trees", "type": "table" }, + "rest": { + "enabled": true, + "path": "/plants" + }, "graphql": { "enabled": true, "type": { @@ -1445,10 +1453,6 @@ "plural": "Shrubs" } }, - "rest": { - "enabled": true, - "path": "/plants" - }, "permissions": [ { "role": "anonymous", @@ -1492,8 +1496,12 @@ "fungus": { "cardinality": "one", "target.entity": "Fungus", - "source.fields": [ "species" ], - "target.fields": [ "habitat" ], + "source.fields": [ + "species" + ], + "target.fields": [ + "habitat" + ], "linking.source.fields": [], "linking.target.fields": [] } @@ -1504,6 +1512,9 @@ "object": "fungi", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1511,9 +1522,6 @@ "plural": "fungi" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1571,11 +1579,15 @@ "spores": "hazards" }, "relationships": { - "shrub": { + "Shrub": { "cardinality": "one", "target.entity": "Shrub", - "source.fields": [ "habitat" ], - "target.fields": [ "species" ], + "source.fields": [ + "habitat" + ], + "target.fields": [ + "species" + ], "linking.source.fields": [], "linking.target.fields": [] } @@ -1586,6 +1598,9 @@ "object": "users", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1593,9 +1608,6 @@ "plural": "User_NonAutogenRelationshipColumns" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1626,6 +1638,9 @@ "object": "user_profiles", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1633,9 +1648,6 @@ "plural": "UserProfiles" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1652,6 +1664,9 @@ "object": "users", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1659,9 +1674,6 @@ "plural": "User_AutogenRelationshipColumns" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1692,6 +1704,9 @@ "object": "users", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1699,9 +1714,6 @@ "plural": "User_AutogenToNonAutogenRelationshipColumns" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1737,6 +1749,9 @@ "id" ] }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1744,9 +1759,6 @@ "plural": "books_view_alls" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1766,6 +1778,9 @@ "id" ] }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1773,9 +1788,6 @@ "plural": "books_view_with_mappings" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1799,6 +1811,9 @@ "pieceid" ] }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1806,9 +1821,6 @@ "plural": "stocks_view_selecteds" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1829,6 +1841,9 @@ "pub_id" ] }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1836,9 +1851,6 @@ "plural": "books_publishers_view_composites" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1858,6 +1870,9 @@ "id" ] }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1865,9 +1880,6 @@ "plural": "books_publishers_view_composite_insertables" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1884,6 +1896,9 @@ "object": "empty_table", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1891,9 +1906,6 @@ "plural": "Empties" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "authenticated", @@ -1927,6 +1939,9 @@ "object": "notebooks", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1934,9 +1949,6 @@ "plural": "Notebooks" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -1971,6 +1983,9 @@ "object": "journals", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -1978,9 +1993,6 @@ "plural": "Journals" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "policy_tester_noupdate", @@ -2069,6 +2081,9 @@ "object": "aow", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": false, "type": { @@ -2076,9 +2091,6 @@ "plural": "ArtOfWars" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -2109,6 +2121,9 @@ "object": "series", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -2116,9 +2131,6 @@ "plural": "series" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -2188,6 +2200,9 @@ "object": "sales", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -2195,9 +2210,6 @@ "plural": "Sales" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -2222,6 +2234,9 @@ "object": "gqlmappings", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -2229,9 +2244,6 @@ "plural": "GQLmappings" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -2260,6 +2272,9 @@ "object": "bookmarks", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -2267,9 +2282,6 @@ "plural": "Bookmarks" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -2294,6 +2306,9 @@ "object": "mappedbookmarks", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -2301,9 +2316,6 @@ "plural": "MappedBookmarks" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "anonymous", @@ -2332,6 +2344,9 @@ "object": "books_sold", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -2339,15 +2354,53 @@ "plural": "books_sold" } }, + "permissions": [ + { + "role": "anonymous", + "actions": [ + { + "action": "*" + } + ] + } + ] + }, + "DefaultBuiltInFunction": { + "source": { + "object": "default_with_function_table", + "type": "table" + }, "rest": { "enabled": true }, + "graphql": { + "enabled": true, + "type": { + "singular": "DefaultBuiltInFunction", + "plural": "DefaultBuiltInFunctions" + } + }, "permissions": [ { "role": "anonymous", "actions": [ { - "action": "*" + "action": "create", + "fields": { + "exclude": [ + "current_date", + "next_date" + ] + } + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" } ] } @@ -2358,6 +2411,9 @@ "object": "publishers", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -2365,9 +2421,6 @@ "plural": "PublisherNFs" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "authenticated", @@ -2440,6 +2493,9 @@ "object": "books", "type": "table" }, + "rest": { + "enabled": true + }, "graphql": { "enabled": true, "type": { @@ -2447,9 +2503,6 @@ "plural": "booksNF" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "authenticated", @@ -2549,45 +2602,14 @@ } } }, - "DefaultBuiltInFunction": { + "AuthorNF": { "source": { - "object": "default_with_function_table", + "object": "authors", "type": "table" }, - "graphql": { - "enabled": true - }, "rest": { "enabled": true }, - "permissions": [ - { - "role": "anonymous", - "actions": [ - { - "action": "create", - "fields": { - "include": [ - "*" - ], - "exclude": [ - "current_date", - "next_date" - ] - } - }, - "read", - "update", - "delete" - ] - } - ] - }, - "AuthorNF": { - "source": { - "object": "authors", - "type": "table" - }, "graphql": { "enabled": true, "type": { @@ -2595,9 +2617,6 @@ "plural": "AuthorNFs" } }, - "rest": { - "enabled": true - }, "permissions": [ { "role": "authenticated", @@ -2672,21 +2691,33 @@ } }, "dbo_DimAccount": { - "source": "dimaccount", + "source": { + "object": "dimaccount", + "type": "table" + }, + "rest": { + "enabled": true + }, + "graphql": { + "enabled": true, + "type": { + "singular": "dbo_DimAccount", + "plural": "dbo_DimAccounts" + } + }, "permissions": [ { "role": "anonymous", "actions": [ - "read", - "create", - "update", - "delete" + { + "action": "*" + } ] } ], "mappings": { - "accountkey": "AccountKey", - "parentaccountkey": "ParentAccountKey" + "parentaccountkey": "ParentAccountKey", + "accountkey": "AccountKey" }, "relationships": { "parent_account": { @@ -2697,7 +2728,9 @@ ], "target.fields": [ "accountkey" - ] + ], + "linking.source.fields": [], + "linking.target.fields": [] }, "child_accounts": { "cardinality": "many", @@ -2707,9 +2740,11 @@ ], "target.fields": [ "parentaccountkey" - ] + ], + "linking.source.fields": [], + "linking.target.fields": [] } } } } -} +} \ No newline at end of file