Skip to content

Commit f7bc95d

Browse files
Feature Flag for Nested Mutations: CLI changes (#1983)
## Why make this change? - Closes #1950 - Introduces a feature flag in the config for nested mutation operations. - Feature Flag format: ```json "runtime":{ ... "graphql": { ... "nested-mutations": { "create": { "enabled": true/false } } } } ``` - CLI Option: `--graphql.nested-create.enabled`. This option can be used along with `init` command to enable/disable nested insert operation. - By default, the nested mutation operations will be **disabled**. - Nested Mutation operations are applicable only for MsSQL database type. So, when the option `--graphql.nested-create.enabled` is used along with other database types, it is not honored and nested mutation operations will be disabled. Nested Mutation section will not be written to the config file. In addition, a warning will be logged to let users know that the option is inapplicable. ## What is this change? - `dab.draft.schema.json` - The schema file is updated to contain details about the new fields - `InitOptions` - A new option `--graphql.nested-create.enabled` is introduced for the `init` command. - `NestedCreateOptionsConverter` - Custom converter to read & write the options for nested insert operation from/to the config file respectively. - `NestedMutationOptionsConverter` - Custom converter to read & write the options for nested mutation operations from/to the config file respectively. - `GraphQLRuntimeOptionsConverterFactory` - Updates the logic for reading and writing the graphQL runtime section of the config file. Incorporates logic for reading and writing the nested mutation operation options. - `dab-config.*.json`/`Multidab-config.*.json` - All the reference config files are updated to include the new Nested Mutation options ## How was this tested? - [x] Integration Tests - [x] Unit Tests - [x] Manual Tests ## Sample Commands - **Nested Create Operations are enabled**: `dab init --database-type mssql --connection-string connString --graphql.nested-create.enabled true` ![image](https://github.com/Azure/data-api-builder/assets/11196553/c1821897-1553-46d7-97d2-bf31b7f6178d) - **Nested Create Operations are disabled**: `dab init --database-type mssql --connection-string connString --graphql.nested-create.enabled false` ![image](https://github.com/Azure/data-api-builder/assets/11196553/ea421080-beb8-4f01-a2c9-99916b8b83cc) - **When --graphql.nested-create.graphql option is not used in the init command**: `dab init --database-type mssql --connection-string connString` ![image](https://github.com/Azure/data-api-builder/assets/11196553/d6f1d56c-a553-4dbf-8ad1-e813edc4274d) - **When --graphql.nested-create.graphql option is used with a database type other than MsSQL**: ![image](https://github.com/Azure/data-api-builder/assets/11196553/f9cdda69-f0bd-4e9d-8f65-dd1f0df48402)
1 parent 04fbfae commit f7bc95d

File tree

37 files changed

+1428
-12
lines changed

37 files changed

+1428
-12
lines changed

schemas/dab.draft.schema.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,25 @@
175175
"enabled": {
176176
"type": "boolean",
177177
"description": "Allow enabling/disabling GraphQL requests for all entities."
178+
},
179+
"nested-mutations": {
180+
"type": "object",
181+
"description": "Configuration properties for nested mutation operations",
182+
"additionalProperties": false,
183+
"properties": {
184+
"create":{
185+
"type": "object",
186+
"description": "Options for nested create operations",
187+
"additionalProperties": false,
188+
"properties": {
189+
"enabled": {
190+
"type": "boolean",
191+
"description": "Allow enabling/disabling nested create operations for all entities.",
192+
"default": false
193+
}
194+
}
195+
}
196+
}
178197
}
179198
}
180199
},

src/Cli.Tests/ConfigGeneratorTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ public void TestSpecialCharactersInConnectionString()
162162
""enabled"": true,
163163
""path"": ""/An_"",
164164
""allow-introspection"": true
165-
},
165+
},
166166
""host"": {
167167
""cors"": {
168168
""origins"": [],

src/Cli.Tests/EndToEndTests.cs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,90 @@ public void TestInitializingRestAndGraphQLGlobalSettings()
131131
Assert.IsTrue(runtimeConfig.Runtime.GraphQL?.Enabled);
132132
}
133133

134+
/// <summary>
135+
/// Test to validate the usage of --graphql.nested-create.enabled option of the init command for all database types.
136+
///
137+
/// 1. Behavior for database types other than MsSQL:
138+
/// - Irrespective of whether the --graphql.nested-create.enabled option is used or not, fields related to nested-create will NOT be written to the config file.
139+
/// - As a result, after deserialization of such a config file, the Runtime.GraphQL.NestedMutationOptions is expected to be null.
140+
/// 2. Behavior for MsSQL database type:
141+
///
142+
/// a. When --graphql.nested-create.enabled option is used
143+
/// - In this case, the fields related to nested mutation and nested create operations will be written to the config file.
144+
/// "nested-mutations": {
145+
/// "create": {
146+
/// "enabled": true/false
147+
/// }
148+
/// }
149+
/// After deserializing such a config file, the Runtime.GraphQL.NestedMutationOptions is expected to be non-null and the value of the "enabled" field is expected to be the same as the value passed in the init command.
150+
///
151+
/// b. When --graphql.nested-create.enabled option is not used
152+
/// - In this case, fields related to nested mutation and nested create operations will NOT be written to the config file.
153+
/// - As a result, after deserialization of such a config file, the Runtime.GraphQL.NestedMutationOptions is expected to be null.
154+
///
155+
/// </summary>
156+
/// <param name="isNestedCreateEnabled">Value interpreted by the CLI for '--graphql.nested-create.enabled' option of the init command.
157+
/// When not used, CLI interprets the value for the option as CliBool.None
158+
/// When used with true/false, CLI interprets the value as CliBool.True/CliBool.False respectively.
159+
/// </param>
160+
/// <param name="expectedValueForNestedCreateEnabledFlag"> Expected value for the nested create enabled flag in the config file.</param>
161+
[DataTestMethod]
162+
[DataRow(CliBool.True, "mssql", DatabaseType.MSSQL, DisplayName = "Init command with '--graphql.nested-create.enabled true' for MsSql database type")]
163+
[DataRow(CliBool.False, "mssql", DatabaseType.MSSQL, DisplayName = "Init command with '--graphql.nested-create.enabled false' for MsSql database type")]
164+
[DataRow(CliBool.None, "mssql", DatabaseType.MSSQL, DisplayName = "Init command without '--graphql.nested-create.enabled' option for MsSql database type")]
165+
[DataRow(CliBool.True, "mysql", DatabaseType.MySQL, DisplayName = "Init command with '--graphql.nested-create.enabled true' for MySql database type")]
166+
[DataRow(CliBool.False, "mysql", DatabaseType.MySQL, DisplayName = "Init command with '--graphql.nested-create.enabled false' for MySql database type")]
167+
[DataRow(CliBool.None, "mysql", DatabaseType.MySQL, DisplayName = "Init command without '--graphql.nested-create.enabled' option for MySql database type")]
168+
[DataRow(CliBool.True, "postgresql", DatabaseType.PostgreSQL, DisplayName = "Init command with '--graphql.nested-create.enabled true' for PostgreSql database type")]
169+
[DataRow(CliBool.False, "postgresql", DatabaseType.PostgreSQL, DisplayName = "Init command with '--graphql.nested-create.enabled false' for PostgreSql database type")]
170+
[DataRow(CliBool.None, "postgresql", DatabaseType.PostgreSQL, DisplayName = "Init command without '--graphql.nested-create.enabled' option for PostgreSql database type")]
171+
[DataRow(CliBool.True, "dwsql", DatabaseType.DWSQL, DisplayName = "Init command with '--graphql.nested-create.enabled true' for dwsql database type")]
172+
[DataRow(CliBool.False, "dwsql", DatabaseType.DWSQL, DisplayName = "Init command with '--graphql.nested-create.enabled false' for dwsql database type")]
173+
[DataRow(CliBool.None, "dwsql", DatabaseType.DWSQL, DisplayName = "Init command without '--graphql.nested-create.enabled' option for dwsql database type")]
174+
[DataRow(CliBool.True, "cosmosdb_nosql", DatabaseType.CosmosDB_NoSQL, DisplayName = "Init command with '--graphql.nested-create.enabled true' for cosmosdb_nosql database type")]
175+
[DataRow(CliBool.False, "cosmosdb_nosql", DatabaseType.CosmosDB_NoSQL, DisplayName = "Init command with '--graphql.nested-create.enabled false' for cosmosdb_nosql database type")]
176+
[DataRow(CliBool.None, "cosmosdb_nosql", DatabaseType.CosmosDB_NoSQL, DisplayName = "Init command without '--graphql.nested-create.enabled' option for cosmosdb_nosql database type")]
177+
public void TestEnablingNestedCreateOperation(CliBool isNestedCreateEnabled, string dbType, DatabaseType expectedDbType)
178+
{
179+
List<string> args = new() { "init", "-c", TEST_RUNTIME_CONFIG_FILE, "--connection-string", SAMPLE_TEST_CONN_STRING, "--database-type", dbType };
180+
181+
if (string.Equals("cosmosdb_nosql", dbType, StringComparison.OrdinalIgnoreCase))
182+
{
183+
List<string> cosmosNoSqlArgs = new() { "--cosmosdb_nosql-database",
184+
"graphqldb", "--cosmosdb_nosql-container", "planet", "--graphql-schema", TEST_SCHEMA_FILE};
185+
args.AddRange(cosmosNoSqlArgs);
186+
}
187+
188+
if (isNestedCreateEnabled is not CliBool.None)
189+
{
190+
args.Add("--graphql.nested-create.enabled");
191+
args.Add(isNestedCreateEnabled.ToString()!);
192+
}
193+
194+
Program.Execute(args.ToArray(), _cliLogger!, _fileSystem!, _runtimeConfigLoader!);
195+
196+
Assert.IsTrue(_runtimeConfigLoader!.TryLoadConfig(
197+
TEST_RUNTIME_CONFIG_FILE,
198+
out RuntimeConfig? runtimeConfig,
199+
replaceEnvVar: true));
200+
201+
Assert.IsNotNull(runtimeConfig);
202+
Assert.AreEqual(expectedDbType, runtimeConfig.DataSource.DatabaseType);
203+
Assert.IsNotNull(runtimeConfig.Runtime);
204+
Assert.IsNotNull(runtimeConfig.Runtime.GraphQL);
205+
if (runtimeConfig.DataSource.DatabaseType is DatabaseType.MSSQL && isNestedCreateEnabled is not CliBool.None)
206+
{
207+
Assert.IsNotNull(runtimeConfig.Runtime.GraphQL.NestedMutationOptions);
208+
Assert.IsNotNull(runtimeConfig.Runtime.GraphQL.NestedMutationOptions.NestedCreateOptions);
209+
bool expectedValueForNestedCreateEnabled = isNestedCreateEnabled == CliBool.True;
210+
Assert.AreEqual(expectedValueForNestedCreateEnabled, runtimeConfig.Runtime.GraphQL.NestedMutationOptions.NestedCreateOptions.Enabled);
211+
}
212+
else
213+
{
214+
Assert.IsNull(runtimeConfig.Runtime.GraphQL.NestedMutationOptions, message: "NestedMutationOptions is expected to be null because a) DB type is not MsSQL or b) Either --graphql.nested-create.enabled option was not used or no value was provided.");
215+
}
216+
}
217+
134218
/// <summary>
135219
/// Test to verify adding a new Entity.
136220
/// </summary>

src/Cli.Tests/InitTests.cs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,89 @@ public Task GraphQLPathWithoutStartingSlashWillHaveItAdded()
409409
return ExecuteVerifyTest(options);
410410
}
411411

412+
/// <summary>
413+
/// Test to validate the contents of the config file generated when init command is used with --graphql.nested-create.enabled flag option for different database types.
414+
///
415+
/// 1. For database types other than MsSQL:
416+
/// - Irrespective of whether the --graphql.nested-create.enabled option is used or not, fields related to nested-create will NOT be written to the config file.
417+
///
418+
/// 2. For MsSQL database type:
419+
/// a. When --graphql.nested-create.enabled option is used
420+
/// - In this case, the fields related to nested mutation and nested create operations will be written to the config file.
421+
/// "nested-mutations": {
422+
/// "create": {
423+
/// "enabled": true/false
424+
/// }
425+
/// }
426+
///
427+
/// b. When --graphql.nested-create.enabled option is not used
428+
/// - In this case, fields related to nested mutation and nested create operations will NOT be written to the config file.
429+
///
430+
/// </summary>
431+
[DataTestMethod]
432+
[DataRow(DatabaseType.MSSQL, CliBool.True, DisplayName = "Init command with '--graphql.nested-create.enabled true' for MsSQL database type")]
433+
[DataRow(DatabaseType.MSSQL, CliBool.False, DisplayName = "Init command with '--graphql.nested-create.enabled false' for MsSQL database type")]
434+
[DataRow(DatabaseType.MSSQL, CliBool.None, DisplayName = "Init command without '--graphql.nested-create.enabled' option for MsSQL database type")]
435+
[DataRow(DatabaseType.PostgreSQL, CliBool.True, DisplayName = "Init command with '--graphql.nested-create.enabled true' for PostgreSQL database type")]
436+
[DataRow(DatabaseType.PostgreSQL, CliBool.False, DisplayName = "Init command with '--graphql.nested-create.enabled false' for PostgreSQL database type")]
437+
[DataRow(DatabaseType.PostgreSQL, CliBool.None, DisplayName = "Init command without '--graphql.nested-create.enabled' option for PostgreSQL database type")]
438+
[DataRow(DatabaseType.MySQL, CliBool.True, DisplayName = "Init command with '--graphql.nested-create.enabled true' for MySQL database type")]
439+
[DataRow(DatabaseType.MySQL, CliBool.False, DisplayName = "Init command with '--graphql.nested-create.enabled false' for MySQL database type")]
440+
[DataRow(DatabaseType.MySQL, CliBool.None, DisplayName = "Init command without '--graphql.nested-create.enabled' option for MySQL database type")]
441+
[DataRow(DatabaseType.CosmosDB_NoSQL, CliBool.True, DisplayName = "Init command with '--graphql.nested-create.enabled true' for CosmosDB_NoSQL database type")]
442+
[DataRow(DatabaseType.CosmosDB_NoSQL, CliBool.False, DisplayName = "Init command with '--graphql.nested-create.enabled false' for CosmosDB_NoSQL database type")]
443+
[DataRow(DatabaseType.CosmosDB_NoSQL, CliBool.None, DisplayName = "Init command without '--graphql.nested-create.enabled' option for CosmosDB_NoSQL database type")]
444+
[DataRow(DatabaseType.CosmosDB_PostgreSQL, CliBool.True, DisplayName = "Init command with '--graphql.nested-create.enabled true' for CosmosDB_PostgreSQL database type")]
445+
[DataRow(DatabaseType.CosmosDB_PostgreSQL, CliBool.False, DisplayName = "Init command with '--graphql.nested-create.enabled false' for CosmosDB_PostgreSQL database type")]
446+
[DataRow(DatabaseType.CosmosDB_PostgreSQL, CliBool.None, DisplayName = "Init command without '--graphql.nested-create.enabled' option for CosmosDB_PostgreSQL database type")]
447+
[DataRow(DatabaseType.DWSQL, CliBool.True, DisplayName = "Init command with '--graphql.nested-create.enabled true' for DWSQL database type")]
448+
[DataRow(DatabaseType.DWSQL, CliBool.False, DisplayName = "Init command with '--graphql.nested-create.enabled false' for DWSQL database type")]
449+
[DataRow(DatabaseType.DWSQL, CliBool.None, DisplayName = "Init command without '--graphql.nested-create.enabled' option for DWSQL database type")]
450+
public Task VerifyCorrectConfigGenerationWithNestedMutationOptions(DatabaseType databaseType, CliBool isNestedCreateEnabled)
451+
{
452+
InitOptions options;
453+
454+
if (databaseType is DatabaseType.CosmosDB_NoSQL)
455+
{
456+
// A schema file is added since its mandatory for CosmosDB_NoSQL
457+
((MockFileSystem)_fileSystem!).AddFile(TEST_SCHEMA_FILE, new MockFileData(""));
458+
459+
options = new(
460+
databaseType: databaseType,
461+
connectionString: "testconnectionstring",
462+
cosmosNoSqlDatabase: "testdb",
463+
cosmosNoSqlContainer: "testcontainer",
464+
graphQLSchemaPath: TEST_SCHEMA_FILE,
465+
setSessionContext: true,
466+
hostMode: HostMode.Development,
467+
corsOrigin: new List<string>() { "http://localhost:3000", "http://nolocalhost:80" },
468+
authenticationProvider: EasyAuthType.StaticWebApps.ToString(),
469+
restPath: "rest-api",
470+
config: TEST_RUNTIME_CONFIG_FILE,
471+
nestedCreateOperationEnabled: isNestedCreateEnabled);
472+
}
473+
else
474+
{
475+
options = new(
476+
databaseType: databaseType,
477+
connectionString: "testconnectionstring",
478+
cosmosNoSqlDatabase: null,
479+
cosmosNoSqlContainer: null,
480+
graphQLSchemaPath: null,
481+
setSessionContext: true,
482+
hostMode: HostMode.Development,
483+
corsOrigin: new List<string>() { "http://localhost:3000", "http://nolocalhost:80" },
484+
authenticationProvider: EasyAuthType.StaticWebApps.ToString(),
485+
restPath: "rest-api",
486+
config: TEST_RUNTIME_CONFIG_FILE,
487+
nestedCreateOperationEnabled: isNestedCreateEnabled);
488+
}
489+
490+
VerifySettings verifySettings = new();
491+
verifySettings.UseHashedParameters(databaseType, isNestedCreateEnabled);
492+
return ExecuteVerifyTest(options, verifySettings);
493+
}
494+
412495
private Task ExecuteVerifyTest(InitOptions options, VerifySettings? settings = null)
413496
{
414497
Assert.IsTrue(TryCreateRuntimeConfig(options, _runtimeConfigLoader!, _fileSystem!, out RuntimeConfig? runtimeConfig));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
DataSource: {
3+
Options: {
4+
container: testcontainer,
5+
database: testdb,
6+
schema: test-schema.gql
7+
}
8+
},
9+
Runtime: {
10+
Rest: {
11+
Enabled: false,
12+
Path: /api,
13+
RequestBodyStrict: true
14+
},
15+
GraphQL: {
16+
Enabled: true,
17+
Path: /graphql,
18+
AllowIntrospection: true
19+
},
20+
Host: {
21+
Cors: {
22+
Origins: [
23+
http://localhost:3000,
24+
http://nolocalhost:80
25+
],
26+
AllowCredentials: false
27+
},
28+
Authentication: {
29+
Provider: StaticWebApps
30+
}
31+
}
32+
},
33+
Entities: []
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
DataSource: {
3+
DatabaseType: MSSQL,
4+
Options: {
5+
set-session-context: true
6+
}
7+
},
8+
Runtime: {
9+
Rest: {
10+
Enabled: true,
11+
Path: /rest-api,
12+
RequestBodyStrict: true
13+
},
14+
GraphQL: {
15+
Enabled: true,
16+
Path: /graphql,
17+
AllowIntrospection: true
18+
},
19+
Host: {
20+
Cors: {
21+
Origins: [
22+
http://localhost:3000,
23+
http://nolocalhost:80
24+
],
25+
AllowCredentials: false
26+
},
27+
Authentication: {
28+
Provider: StaticWebApps
29+
}
30+
}
31+
},
32+
Entities: []
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
DataSource: {
3+
DatabaseType: MSSQL,
4+
Options: {
5+
set-session-context: true
6+
}
7+
},
8+
Runtime: {
9+
Rest: {
10+
Enabled: true,
11+
Path: /rest-api,
12+
RequestBodyStrict: true
13+
},
14+
GraphQL: {
15+
Enabled: true,
16+
Path: /graphql,
17+
AllowIntrospection: true,
18+
NestedMutationOptions: {
19+
NestedCreateOptions: {
20+
Enabled: true
21+
}
22+
}
23+
},
24+
Host: {
25+
Cors: {
26+
Origins: [
27+
http://localhost:3000,
28+
http://nolocalhost:80
29+
],
30+
AllowCredentials: false
31+
},
32+
Authentication: {
33+
Provider: StaticWebApps
34+
}
35+
}
36+
},
37+
Entities: []
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
DataSource: {
3+
Options: {
4+
container: testcontainer,
5+
database: testdb,
6+
schema: test-schema.gql
7+
}
8+
},
9+
Runtime: {
10+
Rest: {
11+
Enabled: false,
12+
Path: /api,
13+
RequestBodyStrict: true
14+
},
15+
GraphQL: {
16+
Enabled: true,
17+
Path: /graphql,
18+
AllowIntrospection: true
19+
},
20+
Host: {
21+
Cors: {
22+
Origins: [
23+
http://localhost:3000,
24+
http://nolocalhost:80
25+
],
26+
AllowCredentials: false
27+
},
28+
Authentication: {
29+
Provider: StaticWebApps
30+
}
31+
}
32+
},
33+
Entities: []
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
DataSource: {
3+
DatabaseType: MySQL
4+
},
5+
Runtime: {
6+
Rest: {
7+
Enabled: true,
8+
Path: /rest-api,
9+
RequestBodyStrict: true
10+
},
11+
GraphQL: {
12+
Enabled: true,
13+
Path: /graphql,
14+
AllowIntrospection: true
15+
},
16+
Host: {
17+
Cors: {
18+
Origins: [
19+
http://localhost:3000,
20+
http://nolocalhost:80
21+
],
22+
AllowCredentials: false
23+
},
24+
Authentication: {
25+
Provider: StaticWebApps
26+
}
27+
}
28+
},
29+
Entities: []
30+
}

0 commit comments

Comments
 (0)