Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion config-generators/mssql-commands.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ add Broker --config "dab-config.MsSql.json" --source brokers --permissions "anon
add WebsiteUser --config "dab-config.MsSql.json" --source website_users --permissions "anonymous:create,read,delete,update"
add WebsiteUser_MM --config "dab-config.MsSql.json" --source website_users_mm --graphql "websiteuser_mm:websiteusers_mm" --permissions "anonymous:*"
add SupportedType --config "dab-config.MsSql.json" --source type_table --permissions "anonymous:create,read,delete,update"
add VectorType --config "dab-config.MsSql.json" --source vector_type_table --rest true --graphql false --permissions "anonymous:create,read,delete,update"
add VectorType --config "dab-config.MsSql.json" --source vector_type_table --rest true --graphql true --permissions "anonymous:create,read,delete,update"
update VectorType --config "dab-config.MsSql.json" --permissions "authenticated:create,read,delete,update"
add stocks_price --config "dab-config.MsSql.json" --source stocks_price --permissions "authenticated:create,read,update,delete"
update stocks_price --config "dab-config.MsSql.json" --permissions "anonymous:read"
Expand Down
2 changes: 1 addition & 1 deletion src/Core/Resolvers/MultipleCreateOrderHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ private static RelationshipFields GetRelationshipFieldsInSourceAndTarget(
foreach (ObjectFieldNode field in fieldNodes)
{
Tuple<IValueNode?, SyntaxKind> fieldDetails = GraphQLUtils.GetFieldDetails(field.Value, context.Variables);
SyntaxKind fieldKind = fieldDetails.Item2;
SyntaxKind fieldKind = metadataProvider.TryGetUnderlyingFieldKind(entityName, field.Name.Value, out SyntaxKind arrayFieldKind) ? arrayFieldKind : fieldDetails.Item2;
if (GraphQLUtils.IsScalarField(fieldKind) && metadataProvider.TryGetBackingColumn(entityName, field.Name.Value, out string? backingColumnName))
{
backingColumnData.Add(backingColumnName, fieldDetails.Item1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -699,5 +699,22 @@ protected object GetParamAsSystemType(string fieldValue, string fieldName, Type

}
}

/// <summary>
/// Transforms the value of an object as a string.
/// Array/vector columns (e.g. SQL Server 'vector') arrive as a List<IValueNode>.
/// Calling ToString() on a list/array only yields the CLR type name, so instead extract
/// the underlying element values and serialize them into a JSON array string (e.g. "[1.5,2.5,3.5]").
/// </summary>
/// <param name="value">The value to be transformed into a string.</param>
/// <returns>A string representation of the value.</returns>
protected static string GetStringifiedValue(object value)
{
return value switch
{
IEnumerable<IValueNode> valueNodes => JsonSerializer.Serialize(valueNodes.Select(TypeHelper.GetValue)),
_ => value.ToString()!
};
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
// Licensed under the MIT License.

using System.Net;
using System.Text.Json;
using Azure.DataApiBuilder.Auth;
using Azure.DataApiBuilder.Config.DatabasePrimitives;
using Azure.DataApiBuilder.Config.ObjectModel;
using Azure.DataApiBuilder.Core.Models;
using Azure.DataApiBuilder.Core.Services;
using Azure.DataApiBuilder.Service.Exceptions;
using Azure.DataApiBuilder.Service.GraphQLBuilder.Mutations;
using HotChocolate.Language;
using HotChocolate.Resolvers;
using Microsoft.AspNetCore.Http;

Expand Down Expand Up @@ -111,8 +113,9 @@ private void PopulateColumnsAndParams(string columnName, object? value)

if (value is not null)
{
string stringValue = GetStringifiedValue(value);
paramName = MakeDbConnectionParam(
GetParamAsSystemType(value.ToString()!, columnName, GetColumnSystemType(columnName)), columnName);
GetParamAsSystemType(stringValue, columnName, GetColumnSystemType(columnName)), columnName);
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,11 +183,12 @@ private Predicate CreatePredicateForParam(KeyValuePair<string, object?> param)
}
else
{
string stringValue = GetStringifiedValue(param.Value);
predicate = new(
new PredicateOperand(
new Column(tableSchema: DatabaseObject.SchemaName, tableName: DatabaseObject.Name, backingColumn)),
PredicateOperation.Equal,
new PredicateOperand($"{MakeDbConnectionParam(GetParamAsSystemType(param.Value.ToString()!, backingColumn, GetColumnSystemType(backingColumn)), backingColumn)}"));
new PredicateOperand($"{MakeDbConnectionParam(GetParamAsSystemType(stringValue, backingColumn, GetColumnSystemType(backingColumn)), backingColumn)}"));
}

return predicate;
Expand Down
33 changes: 23 additions & 10 deletions src/Core/Resolvers/SqlMutationEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1088,7 +1088,7 @@ await queryExecutor.ExecuteQueryAsync(
string rootFieldName = isMultipleInputType ? MULTIPLE_INPUT_ARGUEMENT_NAME : SINGLE_INPUT_ARGUEMENT_NAME;

// Parse the hotchocolate input parameters into .net object types
object? parsedInputParams = GQLMultipleCreateArgumentToDictParams(context, rootFieldName, mutationInputParamsFromGQLContext);
object? parsedInputParams = GQLMultipleCreateArgumentToDictParams(context, rootFieldName, mutationInputParamsFromGQLContext, sqlMetadataProvider, entityName);

if (parsedInputParams is null)
{
Expand Down Expand Up @@ -1758,14 +1758,16 @@ private static void PopulateCurrentAndLinkingEntityParams(
internal static object? GQLMultipleCreateArgumentToDictParams(
IMiddlewareContext context,
string rootFieldName,
IDictionary<string, object?> mutationParameters)
IDictionary<string, object?> mutationParameters,
ISqlMetadataProvider metadataProvider,
string entityName)
{
if (mutationParameters.TryGetValue(rootFieldName, out object? inputParameters))
{
ObjectField fieldSchema = context.Selection.Field;
IInputValueDefinition itemsArgumentSchema = fieldSchema.Arguments[rootFieldName];
InputObjectType inputObjectType = ExecutionHelper.InputObjectTypeFromIInputField(itemsArgumentSchema);
return GQLMultipleCreateArgumentToDictParamsHelper(context, inputObjectType, inputParameters);
return GQLMultipleCreateArgumentToDictParamsHelper(context, inputObjectType, inputParameters, metadataProvider, entityName);
}
else
{
Expand Down Expand Up @@ -1813,7 +1815,9 @@ private static void PopulateCurrentAndLinkingEntityParams(
internal static object? GQLMultipleCreateArgumentToDictParamsHelper(
IMiddlewareContext context,
InputObjectType inputObjectType,
object? inputParameters)
object? inputParameters,
ISqlMetadataProvider metadataProvider,
string entityName)
{
// This condition is met for input types that accept an array of values
// where the mutation input field is 'items' such as
Expand All @@ -1835,7 +1839,9 @@ private static void PopulateCurrentAndLinkingEntityParams(
object? parsedInputFieldItem = GQLMultipleCreateArgumentToDictParamsHelper(
context: context,
inputObjectType: inputObjectType,
inputParameters: inputField.Value);
inputParameters: inputField.Value,
metadataProvider: metadataProvider,
entityName: entityName);
if (parsedInputFieldItem is not null)
{
parsedInputFieldItems.Add((IDictionary<string, object?>)parsedInputFieldItem);
Expand All @@ -1862,33 +1868,40 @@ private static void PopulateCurrentAndLinkingEntityParams(
foreach (ObjectFieldNode inputFieldNode in inputFieldNodes)
{
string fieldName = inputFieldNode.Name.Value;
SyntaxKind fieldKind = metadataProvider.TryGetUnderlyingFieldKind(entityName, fieldName, out SyntaxKind arrayFieldKind)
? arrayFieldKind : inputFieldNode.Value.Kind;

// For the mutation pointMultipleCreateExample (outlined in the method summary),
// the following condition will evaluate to true for fields 'authors' and 'reviews'.
// Fields 'authors'/'reviews' can again consist of combination of scalar and relationship fields.
// So, the input object type for 'authors'/'reviews' is fetched and the same function is
// invoked with the fetched input object type again to parse the input fields of 'authors'/'reviews'.
if (inputFieldNode.Value.Kind == SyntaxKind.ListValue)
if (fieldKind == SyntaxKind.ListValue)
{
parsedInputFields.Add(
fieldName,
GQLMultipleCreateArgumentToDictParamsHelper(
context,
GetInputObjectTypeForAField(fieldName, inputObjectType.Fields),
inputFieldNode.Value.Value));
inputFieldNode.Value.Value,
metadataProvider,
entityName));
}
// For the mutation pointMultipleCreateExample (outlined in the method summary),
// the following condition will evaluate to true for fields 'publishers'.
// Field 'publishers' can again consist of combination of scalar and relationship fields.
// So, the input object type for 'publishers' is fetched and the same function is
// invoked with the fetched input object type again to parse the input fields of 'publishers'.
else if (inputFieldNode.Value.Kind == SyntaxKind.ObjectValue)
else if (fieldKind == SyntaxKind.ObjectValue)
{
parsedInputFields.Add(
fieldName,
GQLMultipleCreateArgumentToDictParamsHelper(
context,
GetInputObjectTypeForAField(fieldName, inputObjectType.Fields),
inputFieldNode.Value.Value));
inputFieldNode.Value.Value,
metadataProvider,
entityName));
}
// The flow enters this block for all scalar input fields.
else
Expand Down Expand Up @@ -2366,7 +2379,7 @@ private void ProcessObjectFieldNodesForAuthZ(
foreach (ObjectFieldNode field in fieldNodes)
{
Tuple<IValueNode?, SyntaxKind> fieldDetails = GraphQLUtils.GetFieldDetails(field.Value, context.Variables);
SyntaxKind underlyingFieldKind = fieldDetails.Item2;
SyntaxKind underlyingFieldKind = metadataProvider.TryGetUnderlyingFieldKind(entityName, field.Name.Value, out SyntaxKind arrayFieldKind) ? arrayFieldKind : fieldDetails.Item2;

// For a column field, we do not have to recurse to process fields in the value - which is required for relationship fields.
if (GraphQLUtils.IsScalarField(underlyingFieldKind) || underlyingFieldKind is SyntaxKind.NullValue)
Expand Down
Loading
Loading