diff --git a/src/HotChocolate/MongoDb/src/Types/BsonType.cs b/src/HotChocolate/MongoDb/src/Types/BsonType.cs new file mode 100644 index 00000000000..6087d072ce0 --- /dev/null +++ b/src/HotChocolate/MongoDb/src/Types/BsonType.cs @@ -0,0 +1,396 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using HotChocolate.Configuration; +using HotChocolate.Language; +using HotChocolate.Types.MongoDb.Resources; +using HotChocolate.Utilities; +using MongoDB.Bson; + +namespace HotChocolate.Types.MongoDb; + +/// +/// BSON is a binary format in which zero or more ordered key/value pairs are stored as a single +/// entity. +/// The results are returned as JSON objects +/// +public class BsonType : ScalarType +{ + private ITypeConverter _converter = default!; + + /// + /// Initializes a new instance of the class. + /// + public BsonType() + : this( + MongoDbScalarNames.Bson, + MongoDbTypesResources.Bson_Type_Description, + BindingBehavior.Implicit) + { + } + + /// + /// Initializes a new instance of the class. + /// + public BsonType( + NameString name, + string? description = null, + BindingBehavior bind = BindingBehavior.Explicit) + : base(name, bind) + { + SpecifiedBy = new Uri("https://bsonspec.org/spec.html"); + Description = description; + } + + /// + public override Type RuntimeType => typeof(BsonValue); + + /// + protected override void OnCompleteType( + ITypeCompletionContext context, + IDictionary contextData) + { + _converter = context.Services.GetTypeConverter(); + base.OnCompleteType(context, contextData); + } + + /// + public override bool IsInstanceOfType(IValueNode valueSyntax) + { + if (valueSyntax is null) + { + throw new ArgumentNullException(nameof(valueSyntax)); + } + + switch (valueSyntax) + { + case StringValueNode: + case IntValueNode: + case FloatValueNode: + case BooleanValueNode: + case ListValueNode: + case ObjectValueNode: + case NullValueNode: + return true; + + default: + return false; + } + } + + private BsonValue? ParseLiteralToBson(IValueNode literal) + { + switch (literal) + { + case StringValueNode svn: + return new BsonString(svn.Value); + + case IntValueNode ivn: + return new BsonInt64(long.Parse(ivn.Value, CultureInfo.InvariantCulture)); + + case FloatValueNode fvn + when double.TryParse(fvn.Value, + NumberStyles.Float | NumberStyles.Integer, + CultureInfo.InvariantCulture, + out double f): + return new BsonDouble(f); + + case FloatValueNode fvn: + return new BsonDecimal128( + decimal.Parse(fvn.Value, CultureInfo.InvariantCulture)); + + case BooleanValueNode bvn: + return new BsonBoolean(bvn.Value); + + case ListValueNode lvn: + BsonValue?[] values = new BsonValue[lvn.Items.Count]; + for (var i = 0; i < lvn.Items.Count; i++) + { + values[i] = ParseLiteralToBson(lvn.Items[i]); + } + + return new BsonArray(values); + + case ObjectValueNode ovn: + BsonDocument document = new(); + foreach (ObjectFieldNode field in ovn.Fields) + { + document.Add(field.Name.Value, ParseLiteralToBson(field.Value)); + } + + return document; + + case NullValueNode: + return BsonNull.Value; + + default: + throw ThrowHelper.Bson_CouldNotParseLiteral(this, literal); + } + } + + /// + public override object? ParseLiteral(IValueNode valueSyntax) + { + return ParseLiteralToBson(valueSyntax); + } + + /// + public override IValueNode ParseValue(object? runtimeValue) + { + if (runtimeValue is null) + { + return NullValueNode.Default; + } + + if (runtimeValue is not BsonValue value) + { + value = BsonTypeMapper.MapToBsonValue(runtimeValue); + } + + switch (value) + { + case BsonString s: + return new StringValueNode(s.Value); + + case BsonInt32 i: + return new IntValueNode(i.Value); + + case BsonInt64 l: + return new IntValueNode(l.Value); + + case BsonDouble f: + return new FloatValueNode(f.Value); + + // The range of Decimal128 is different. Therefor we have to serialize + // it as a string, or else information loss could occure + // see https://jira.mongodb.org/browse/CSHARP-2210 + case BsonDecimal128 d: + return new StringValueNode(d.Value.ToString()); + + case BsonBoolean b: + return new BooleanValueNode(b.Value); + + case BsonObjectId s: + return new StringValueNode(s.Value.ToString()); + + case BsonDateTime dateTime when _converter + .TryConvert(dateTime.ToNullableUniversalTime(), out string formatedDateTime): + return new StringValueNode(formatedDateTime); + + case BsonBinaryData bd: + return new StringValueNode(Convert.ToBase64String(bd.Bytes)); + + case BsonTimestamp timeStamp: + return new IntValueNode(timeStamp.Value); + } + + if (value is BsonDocument doc) + { + List fields = new(); + foreach (BsonElement field in doc) + { + fields.Add(new ObjectFieldNode(field.Name, ParseValue(field.Value))); + } + + return new ObjectValueNode(fields); + } + + if (value is BsonArray arr) + { + List valueList = new(); + foreach (BsonValue element in arr) + { + valueList.Add(ParseValue(element)); + } + + return new ListValueNode(valueList); + } + + var mappedValue = BsonTypeMapper.MapToDotNetValue(value); + Type type = mappedValue.GetType(); + + if (type.IsValueType && + _converter.TryConvert(type, typeof(string), mappedValue, out object? converted) && + converted is string c) + { + return new StringValueNode(c); + } + + throw ThrowHelper.Bson_CouldNotParseValue(this, runtimeValue); + } + + /// + public override IValueNode ParseResult(object? resultValue) => + ParseValue(resultValue); + + public override bool TrySerialize(object? runtimeValue, out object? resultValue) + { + resultValue = null; + if (runtimeValue is null or BsonNull) + { + return true; + } + + switch (runtimeValue) + { + case BsonArray arr: + object?[] res = new object?[arr.Count]; + for (var i = 0; i < arr.Count; i++) + { + if (!TrySerialize(arr[i], out var s)) + { + return false; + } + + res[i] = s; + } + + resultValue = res; + return true; + + case BsonDocument doc: + Dictionary docRes = new(); + foreach (BsonElement element in doc) + { + if (!TrySerialize(element.Value, out var s)) + { + return false; + } + + docRes[element.Name] = s; + } + + resultValue = docRes; + return true; + + case BsonDateTime dateTime: + DateTime? parsedDateTime = dateTime.ToNullableUniversalTime(); + if (_converter.TryConvert(parsedDateTime, out string? formatedDateTime)) + { + resultValue = formatedDateTime; + return true; + } + + return false; + + case BsonTimestamp timeStamp: + resultValue = timeStamp.Value; + return true; + + case BsonObjectId objectId: + resultValue = objectId.Value.ToString(); + return true; + + case BsonString s: + resultValue = s.Value; + return true; + + case BsonInt32 i: + resultValue = i.Value; + return true; + + case BsonInt64 l: + resultValue = l.Value; + return true; + + case BsonDouble f: + resultValue = f.Value; + return true; + + case BsonBinaryData bd: + resultValue = Convert.ToBase64String(bd.Bytes); + return true; + + // The range of Decimal128 is different. Therefor we have to serialize + // it as a string, or else information loss could occure + // see https://jira.mongodb.org/browse/CSHARP-2210 + case BsonDecimal128 d: + resultValue = d.Value.ToString(); + return true; + + case BsonBoolean b: + resultValue = b.Value; + return true; + + case BsonValue a: + var dotNetValue = BsonTypeMapper.MapToDotNetValue(a); + + Type type = dotNetValue.GetType(); + + if (type.IsValueType && + _converter.TryConvert(type, typeof(string), dotNetValue, out object? c) && + c is string casted) + { + resultValue = casted; + return true; + } + + resultValue = null; + return false; + + case IValueNode literal: + resultValue = ParseLiteral(literal); + return true; + + default: + resultValue = null; + return false; + } + } + + /// + public override bool TryDeserialize(object? resultValue, out object? runtimeValue) + { + object? elementValue; + runtimeValue = null; + switch (resultValue) + { + case IDictionary dictionary: + { + var result = new BsonDocument(); + foreach (KeyValuePair element in dictionary) + { + if (TryDeserialize(element.Value, out elementValue)) + { + result[element.Key] = (BsonValue)elementValue; + } + else + { + return false; + } + } + + runtimeValue = result; + return true; + } + + case IList list: + { + var result = new BsonValue[list.Count]; + for (var i = 0; i < list.Count; i++) + { + if (TryDeserialize(list[i], out elementValue)) + { + result[i] = (BsonValue)elementValue; + } + else + { + return false; + } + } + + runtimeValue = new BsonArray(result); + return true; + } + + case IValueNode literal: + runtimeValue = ParseLiteral(literal); + return true; + + default: + runtimeValue = BsonTypeMapper.MapToBsonValue(resultValue); + return true; + } + } +} diff --git a/src/HotChocolate/MongoDb/src/Types/HotChocolate.Types.MongoDb.csproj b/src/HotChocolate/MongoDb/src/Types/HotChocolate.Types.MongoDb.csproj index c986cf7f43b..de617ea6df4 100644 --- a/src/HotChocolate/MongoDb/src/Types/HotChocolate.Types.MongoDb.csproj +++ b/src/HotChocolate/MongoDb/src/Types/HotChocolate.Types.MongoDb.csproj @@ -10,6 +10,7 @@ + diff --git a/src/HotChocolate/MongoDb/src/Types/MongoDbScalarNames.cs b/src/HotChocolate/MongoDb/src/Types/MongoDbScalarNames.cs index 93e9cd34f7f..7612f11c70c 100644 --- a/src/HotChocolate/MongoDb/src/Types/MongoDbScalarNames.cs +++ b/src/HotChocolate/MongoDb/src/Types/MongoDbScalarNames.cs @@ -11,5 +11,11 @@ public static class MongoDbScalarNames /// sequences. /// public static readonly string ObjectId = nameof(ObjectId); + + /// + /// The name of the Bson scalar type. + /// sequences. + /// + public static readonly string Bson = nameof(Bson); } } diff --git a/src/HotChocolate/MongoDb/src/Types/MongoDbTypesRequestExecutorExtensions.cs b/src/HotChocolate/MongoDb/src/Types/MongoDbTypesRequestExecutorExtensions.cs new file mode 100644 index 00000000000..c4f56101374 --- /dev/null +++ b/src/HotChocolate/MongoDb/src/Types/MongoDbTypesRequestExecutorExtensions.cs @@ -0,0 +1,27 @@ +using HotChocolate; +using HotChocolate.Execution.Configuration; +using HotChocolate.Types.MongoDb; + +namespace Microsoft.Extensions.DependencyInjection; + +/// +/// Common extension of for MongoDb types +/// +public static class MongoDbTypesRequestExecutorBuilderExtensions +{ + /// + /// Registers on the schema + /// + /// The request executor builder + /// The request executor builder + public static IRequestExecutorBuilder AddObjectIdType(this IRequestExecutorBuilder builder) => + builder.ConfigureSchema(x => x.AddObjectIdType()); + + /// + /// Registers and binds the BSON subtypes to the scalar + /// + /// The request executor builder + /// The request executor builder + public static IRequestExecutorBuilder AddBsonType(this IRequestExecutorBuilder builder) => + builder.ConfigureSchema(x => x.AddBsonType()); +} diff --git a/src/HotChocolate/MongoDb/src/Types/MongoDbTypesSchemaBuilderExtensions.cs b/src/HotChocolate/MongoDb/src/Types/MongoDbTypesSchemaBuilderExtensions.cs new file mode 100644 index 00000000000..6670b7fa146 --- /dev/null +++ b/src/HotChocolate/MongoDb/src/Types/MongoDbTypesSchemaBuilderExtensions.cs @@ -0,0 +1,48 @@ +using HotChocolate.Types.MongoDb; +using MongoDB.Bson; +using BsonType = HotChocolate.Types.MongoDb.BsonType; + +namespace HotChocolate; + +/// +/// Common extension of for MongoDb types +/// +public static class MongoDbTypesSchemaBuilderExtensions +{ + /// + /// Registers on the schema + /// + /// The schema builder + /// The schema builder + public static ISchemaBuilder AddObjectIdType(this ISchemaBuilder builder) + { + builder.AddType(); + return builder; + } + + /// + /// Registers and binds the BSON subtypes to the scalar + /// + /// The schema builder + /// The schema builder + public static ISchemaBuilder AddBsonType(this ISchemaBuilder builder) + { + builder.AddType(); + builder.BindRuntimeType(typeof(BsonValue), typeof(BsonType)); + builder.BindRuntimeType(typeof(BsonArray), typeof(BsonType)); + builder.BindRuntimeType(typeof(BsonDocument), typeof(BsonType)); + builder.BindRuntimeType(typeof(BsonBoolean), typeof(BsonType)); + builder.BindRuntimeType(typeof(BsonDouble), typeof(BsonType)); + builder.BindRuntimeType(typeof(BsonDecimal128), typeof(BsonType)); + builder.BindRuntimeType(typeof(BsonDateTime), typeof(BsonType)); + builder.BindRuntimeType(typeof(BsonTimestamp), typeof(BsonType)); + builder.BindRuntimeType(typeof(BsonObjectId), typeof(BsonType)); + builder.BindRuntimeType(typeof(BsonBinaryData), typeof(BsonType)); + builder.BindRuntimeType(typeof(BsonInt32), typeof(BsonType)); + builder.BindRuntimeType(typeof(BsonInt64), typeof(BsonType)); + builder.BindRuntimeType(typeof(BsonNull), typeof(BsonType)); + builder.BindRuntimeType(typeof(BsonBoolean), typeof(BsonType)); + builder.BindRuntimeType(typeof(BsonString), typeof(BsonType)); + return builder; + } +} diff --git a/src/HotChocolate/MongoDb/src/Types/ObjectIdType.cs b/src/HotChocolate/MongoDb/src/Types/ObjectIdType.cs index 6645f0be2cc..3ce82b53d04 100644 --- a/src/HotChocolate/MongoDb/src/Types/ObjectIdType.cs +++ b/src/HotChocolate/MongoDb/src/Types/ObjectIdType.cs @@ -21,7 +21,6 @@ public ObjectIdType() MongoDbTypesResources.ObjectId_Type_Description, BindingBehavior.Implicit) { - SpecifiedBy = new Uri("https://docs.mongodb.com/manual/reference/bson-types/#objectid"); } /// @@ -33,6 +32,7 @@ public ObjectIdType( BindingBehavior bind = BindingBehavior.Explicit) : base(name, bind) { + SpecifiedBy = new Uri("https://docs.mongodb.com/manual/reference/bson-types/#objectid"); Description = description; } diff --git a/src/HotChocolate/MongoDb/src/Types/PublicAPI.Unshipped.txt b/src/HotChocolate/MongoDb/src/Types/PublicAPI.Unshipped.txt index e69de29bb2d..f1a653ce01c 100644 --- a/src/HotChocolate/MongoDb/src/Types/PublicAPI.Unshipped.txt +++ b/src/HotChocolate/MongoDb/src/Types/PublicAPI.Unshipped.txt @@ -0,0 +1,18 @@ +HotChocolate.MongoDbTypesSchemaBuilderExtensions +HotChocolate.Types.MongoDb.BsonType +HotChocolate.Types.MongoDb.BsonType.BsonType() -> void +HotChocolate.Types.MongoDb.BsonType.BsonType(HotChocolate.NameString name, string? description = null, HotChocolate.Types.BindingBehavior bind = HotChocolate.Types.BindingBehavior.Explicit) -> void +Microsoft.Extensions.DependencyInjection.MongoDbTypesRequestExecutorBuilderExtensions +override HotChocolate.Types.MongoDb.BsonType.IsInstanceOfType(HotChocolate.Language.IValueNode! literal) -> bool +override HotChocolate.Types.MongoDb.BsonType.OnCompleteType(HotChocolate.Configuration.ITypeCompletionContext! context, System.Collections.Generic.IDictionary! contextData) -> void +override HotChocolate.Types.MongoDb.BsonType.ParseLiteral(HotChocolate.Language.IValueNode! literal) -> object? +override HotChocolate.Types.MongoDb.BsonType.ParseResult(object? resultValue) -> HotChocolate.Language.IValueNode! +override HotChocolate.Types.MongoDb.BsonType.ParseValue(object? val) -> HotChocolate.Language.IValueNode! +override HotChocolate.Types.MongoDb.BsonType.RuntimeType.get -> System.Type! +override HotChocolate.Types.MongoDb.BsonType.TryDeserialize(object? resultValue, out object? runtimeValue) -> bool +override HotChocolate.Types.MongoDb.BsonType.TrySerialize(object? runtimeValue, out object? resultValue) -> bool +static HotChocolate.MongoDbTypesSchemaBuilderExtensions.AddBsonType(this HotChocolate.ISchemaBuilder! builder) -> HotChocolate.ISchemaBuilder! +static HotChocolate.MongoDbTypesSchemaBuilderExtensions.AddObjectIdType(this HotChocolate.ISchemaBuilder! builder) -> HotChocolate.ISchemaBuilder! +static Microsoft.Extensions.DependencyInjection.MongoDbTypesRequestExecutorBuilderExtensions.AddBsonType(this HotChocolate.Execution.Configuration.IRequestExecutorBuilder! builder) -> HotChocolate.Execution.Configuration.IRequestExecutorBuilder! +static Microsoft.Extensions.DependencyInjection.MongoDbTypesRequestExecutorBuilderExtensions.AddObjectIdType(this HotChocolate.Execution.Configuration.IRequestExecutorBuilder! builder) -> HotChocolate.Execution.Configuration.IRequestExecutorBuilder! +static readonly HotChocolate.Types.MongoDb.MongoDbScalarNames.Bson -> string! \ No newline at end of file diff --git a/src/HotChocolate/MongoDb/src/Types/Resources/MongoDbTypesResources.Designer.cs b/src/HotChocolate/MongoDb/src/Types/Resources/MongoDbTypesResources.Designer.cs index c0e0e7c192f..66c02cb1a1e 100644 --- a/src/HotChocolate/MongoDb/src/Types/Resources/MongoDbTypesResources.Designer.cs +++ b/src/HotChocolate/MongoDb/src/Types/Resources/MongoDbTypesResources.Designer.cs @@ -9,21 +9,21 @@ namespace HotChocolate.Types.MongoDb.Resources { using System; - - + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [System.Diagnostics.DebuggerNonUserCodeAttribute()] [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class MongoDbTypesResources { - + private static System.Resources.ResourceManager resourceMan; - + private static System.Globalization.CultureInfo resourceCulture; - + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal MongoDbTypesResources() { } - + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] internal static System.Resources.ResourceManager ResourceManager { get { @@ -34,7 +34,7 @@ internal static System.Resources.ResourceManager ResourceManager { return resourceMan; } } - + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] internal static System.Globalization.CultureInfo Culture { get { @@ -44,11 +44,29 @@ internal static System.Globalization.CultureInfo Culture { resourceCulture = value; } } - + internal static string ObjectId_Type_Description { get { return ResourceManager.GetString("ObjectId_Type_Description", resourceCulture); } } + + internal static string Bson_Type_Description { + get { + return ResourceManager.GetString("Bson_Type_Description", resourceCulture); + } + } + + internal static string Bson_Type_CouldNotParseValue { + get { + return ResourceManager.GetString("Bson_Type_CouldNotParseValue", resourceCulture); + } + } + + internal static string Bson_Type_CouldNotParseLiteral { + get { + return ResourceManager.GetString("Bson_Type_CouldNotParseLiteral", resourceCulture); + } + } } } diff --git a/src/HotChocolate/MongoDb/src/Types/Resources/MongoDbTypesResources.resx b/src/HotChocolate/MongoDb/src/Types/Resources/MongoDbTypesResources.resx index 42d3d2ab26a..aa769d8ee1b 100644 --- a/src/HotChocolate/MongoDb/src/Types/Resources/MongoDbTypesResources.resx +++ b/src/HotChocolate/MongoDb/src/Types/Resources/MongoDbTypesResources.resx @@ -21,4 +21,13 @@ The ObjectId scalar type represents a 12 byte ObjectId, represented as UTF-8 character sequences. + + BSON is a binary format in which zero or more ordered key/value pairs are stored as a single entity. The results are returned as JSON objects + + + Could not parse value {0} + + + Could not parse literal {0} + diff --git a/src/HotChocolate/MongoDb/src/Types/ThrowHelper.cs b/src/HotChocolate/MongoDb/src/Types/ThrowHelper.cs new file mode 100644 index 00000000000..359e93054e8 --- /dev/null +++ b/src/HotChocolate/MongoDb/src/Types/ThrowHelper.cs @@ -0,0 +1,24 @@ +using HotChocolate.Language; +using HotChocolate.Language.Utilities; +using HotChocolate.Types.MongoDb.Resources; + +namespace HotChocolate.Types.MongoDb; + +internal static class ThrowHelper +{ + public static SerializationException Bson_CouldNotParseValue( + ScalarType type, + object? value) => + new( + string.Format( + MongoDbTypesResources.Bson_Type_CouldNotParseValue, + value?.ToString() ?? "null"), + type); + + public static SerializationException Bson_CouldNotParseLiteral( + ScalarType type, + IValueNode literal) => + new( + string.Format(MongoDbTypesResources.Bson_Type_CouldNotParseLiteral, literal.Print()), + type); +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/BsonTypeTests.cs b/src/HotChocolate/MongoDb/test/Types.MongoDb/BsonTypeTests.cs new file mode 100644 index 00000000000..072add28df5 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/BsonTypeTests.cs @@ -0,0 +1,1265 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using HotChocolate.Execution; +using HotChocolate.Language; +using Microsoft.Extensions.DependencyInjection; +using MongoDB.Bson; +using Snapshooter; +using Snapshooter.Xunit; +using Xunit; +using BsonType = HotChocolate.Types.MongoDb.BsonType; + +namespace HotChocolate.Types; + +public class BsonTypeTests +{ + [Fact] + public async Task Output_Should_BindAllRuntimeTypes() + { + // arrange + IRequestExecutor executor = await new ServiceCollection() + .AddGraphQL() + .AddBsonType() + .AddQueryType() + .BuildRequestExecutorAsync(); + + // act + // assert + executor.Schema.Print().MatchSnapshot(); + } + + [Fact] + public async Task Output_Should_MatchSnapshot_When_BsonDocument() + { + // arrange + IRequestExecutor executor = await new ServiceCollection() + .AddGraphQL() + .AddBsonType() + .AddQueryType() + .BuildRequestExecutorAsync(); + + // act + IExecutionResult result = await executor.ExecuteAsync("{ document }"); + + // assert + result.ToJson().MatchSnapshot(); + } + + [Fact] + public async Task Input_Should_MatchSnapshot_When_BsonDocument() + { + // arrange + object res = "INVALID"; + IRequestExecutor executor = await new ServiceCollection() + .AddGraphQL() + .AddBsonType() + .AddQueryType(x => x.Name("Query") + .Field("in") + .Type() + .Argument("val", x => x.Type()) + .Resolve(ctx => + { + res = ctx.ArgumentValue("val"); + return "done"; + })) + .BuildRequestExecutorAsync(); + + // act + await executor.ExecuteAsync(@" + { + in(val: { + int32: 42, + int64: 42, + decimal: ""42.123456789123456789123456789"", + double: 42.23, + boolean: true, + bsonArray: [ + false, + true + ], + string: ""String"", + null: null, + nested: { + int32: 42, + int64: 42 + } + }) + } + "); + + // assert + Assert.IsType(res).ToString().MatchSnapshot(); + } + + [Fact] + public async Task Input_Should_MatchSnapshotAndType_When_DictionaryPassed() + { + // arrange + object res = "INVALID"; + IRequestExecutor executor = await new ServiceCollection() + .AddGraphQL() + .AddBsonType() + .AddQueryType(x => x.Name("Query") + .Field("in") + .Type() + .Argument("val", x => x.Type()) + .Resolve(ctx => + { + res = ctx.ArgumentValue("val"); + return "done"; + })) + .BuildRequestExecutorAsync(); + + // act + await executor.ExecuteAsync("query Test($val: Bson){ in(val:$val) }", + new Dictionary() + { + ["val"] = new Dictionary() { ["foo"] = true } + }); + + // assert + Assert.NotEqual("INVALID", res); + Assert.IsType(res).ToString().MatchSnapshot(); + } + + [Fact] + public async Task Input_Should_MatchSnapshotAndType_When_ListPassed() + { + // arrange + object res = "INVALID"; + IRequestExecutor executor = await new ServiceCollection() + .AddGraphQL() + .AddBsonType() + .AddQueryType(x => x.Name("Query") + .Field("in") + .Type() + .Argument("val", x => x.Type()) + .Resolve(ctx => + { + res = ctx.ArgumentValue("val"); + return "done"; + })) + .BuildRequestExecutorAsync(); + + // act + await executor.ExecuteAsync("query Test($val: Bson){ in(val:$val) }", + new Dictionary() { ["val"] = new List() { "foo", "bar" } }); + + // assert + Assert.NotEqual("INVALID", res); + Assert.IsType(res).ToString().MatchSnapshot(); + } + + [Theory] + [InlineData("int32")] + [InlineData("int64")] + [InlineData("decimal")] + [InlineData("double")] + [InlineData("boolean")] + [InlineData("bsonArray")] + [InlineData("string")] + [InlineData("objectId")] + [InlineData("binary")] + [InlineData("timestamp")] + [InlineData("dateTime")] + [InlineData("string")] + [InlineData("null")] + public async Task Output_Should_MatchSnapshot_When_Value(string fieldName) + { + // arrange + IRequestExecutor executor = await new ServiceCollection() + .AddGraphQL() + .AddBsonType() + .AddQueryType() + .BuildRequestExecutorAsync(); + + // act + IExecutionResult result = await executor.ExecuteAsync($"{{ {fieldName} }}"); + + // assert + result.ToJson().MatchSnapshot(new SnapshotNameExtension(fieldName)); + } + + [Theory] + [InlineData("int", "42", typeof(BsonInt64))] + [InlineData("long", long.MaxValue, typeof(BsonInt64))] + [InlineData("decimal", + "\"42.1234\"", + typeof(BsonString))] // we do not know that it should be a BsonDecimal + [InlineData("double", 43.23, typeof(BsonDouble))] + [InlineData("boolean", true, typeof(BsonBoolean))] + [InlineData("array", "[true, false]", typeof(BsonArray))] + [InlineData("string", "\"string\"", typeof(BsonString))] + public async Task Input_Should_MatchSnapshotAndType_When_Passed( + string fieldName, + object value, + Type type) + { + // arrange + object res = "INVALID"; + IRequestExecutor executor = await new ServiceCollection() + .AddGraphQL() + .AddBsonType() + .AddQueryType(x => x.Name("Query") + .Field("in") + .Type() + .Argument("val", x => x.Type()) + .Resolve(ctx => + { + res = ctx.ArgumentValue("val"); + return "done"; + })) + .BuildRequestExecutorAsync(); + + // act + await executor.ExecuteAsync($"{{ in(val:{value.ToString()!.ToLower()}) }}"); + + // assert + Assert.NotEqual("INVALID", res); + Assert.IsType(type, res); + res.MatchSnapshot(new SnapshotNameExtension(fieldName)); + } + + [Theory] + [InlineData("int", 42, typeof(BsonInt64))] + [InlineData("long", long.MaxValue, typeof(BsonInt64))] + [InlineData("double", 43.23, typeof(BsonDouble))] + [InlineData("boolean", true, typeof(BsonBoolean))] + [InlineData("string", "string", typeof(BsonString))] + public async Task Input_Should_MatchSnapshotAndType_When_PassedVariable( + string fieldName, + object value, + Type type) + { + // arrange + object res = "INVALID"; + IRequestExecutor executor = await new ServiceCollection() + .AddGraphQL() + .AddBsonType() + .AddQueryType(x => x.Name("Query") + .Field("in") + .Type() + .Argument("val", x => x.Type()) + .Resolve(ctx => + { + res = ctx.ArgumentValue("val"); + return "done"; + })) + .BuildRequestExecutorAsync(); + + // act + await executor.ExecuteAsync("query Test($val: Bson){ in(val:$val) }", + new Dictionary() { ["val"] = value }); + + // assert + Assert.NotEqual("INVALID", res); + Assert.IsType(type, res); + res.MatchSnapshot(new SnapshotNameExtension(fieldName)); + } + + [Fact] + public async Task TrySerialize_Should_ReturnNull_When_CalledWithNull() + { + // arrange + object res = "INVALID"; + BsonType type = (await new ServiceCollection() + .AddGraphQL() + .AddBsonType() + .ModifyOptions(x => x.StrictValidation = false) + .BuildSchemaAsync()).GetType("Bson"); + + // act + var serialize = type.TrySerialize(null, out var value); + + // assert + Assert.True(serialize); + Assert.Null(value); + } + + [Fact] + public async Task TrySerialize_Should_ReturnFalse_When_CalledWithNonBsonValue() + { + // arrange + object res = "INVALID"; + BsonType type = (await new ServiceCollection() + .AddGraphQL() + .AddBsonType() + .ModifyOptions(x => x.StrictValidation = false) + .BuildSchemaAsync()).GetType("Bson"); + + // act + bool result = type.TrySerialize("Failes", out _); + + // assert + Assert.False(result); + } + + [Fact] + public async Task Output_Return_Object() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Resolve(_ => new BsonDocument() { { "foo", "bar" } })) + .Create(); + + IRequestExecutor executor = schema.MakeExecutable(); + + // act + IExecutionResult result = await executor.ExecuteAsync("{ foo }"); + + // assert + result.ToJson().MatchSnapshot(); + } + + [Fact] + public async Task Output_Return_List() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Resolve(_ => new BsonArray(){ new BsonDocument() })) + .Create(); + + IRequestExecutor executor = schema.MakeExecutable(); + + // act + IExecutionResult result = await executor.ExecuteAsync("{ foo }"); + + // assert + result.ToJson().MatchSnapshot(); + } + + [Fact] + public async Task Input_Object() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + IRequestExecutor executor = schema.MakeExecutable(); + + // act + IExecutionResult result = await executor.ExecuteAsync( + "{ foo(input: { a: \"foo\" }) }"); + + // assert + result.ToJson().MatchSnapshot(); + } + + [Fact] + public async Task Input_Value_List() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + IRequestExecutor executor = schema.MakeExecutable(); + + // act + IExecutionResult result = await executor.ExecuteAsync( + "{ foo(input: [ \"foo\" ]) }"); + + // assert + result.ToJson().MatchSnapshot(); + } + + [Fact] + public async Task Input_Object_List() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + IRequestExecutor executor = schema.MakeExecutable(); + + // act + IExecutionResult result = await executor.ExecuteAsync( + "{ foo(input: [ { a: \"foo\" } ]) }"); + + // assert + result.ToJson().MatchSnapshot(); + } + + [Fact] + public async Task Input_Value_String() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + IRequestExecutor executor = schema.MakeExecutable(); + + // act + IExecutionResult result = await executor.ExecuteAsync( + "{ foo(input: \"foo\") }"); + + // assert + result.ToJson().MatchSnapshot(); + } + + [Fact] + public async Task Input_Value_Int() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + IRequestExecutor executor = schema.MakeExecutable(); + + // act + IExecutionResult result = await executor.ExecuteAsync( + "{ foo(input: 123) }"); + + // assert + result.ToJson().MatchSnapshot(); + } + + [Fact] + public async Task Input_Value_Float() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + IRequestExecutor executor = schema.MakeExecutable(); + + // act + IExecutionResult result = await executor.ExecuteAsync( + "{ foo(input: 1.2) }"); + + // assert + result.ToJson().MatchSnapshot(); + } + + [Fact] + public async Task Input_Value_Boolean() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + IRequestExecutor executor = schema.MakeExecutable(); + + // act + IExecutionResult result = await executor.ExecuteAsync( + "{ foo(input: true) }"); + + // assert + result.ToJson().MatchSnapshot(); + } + + [Fact] + public async Task Input_Value_Null() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + IRequestExecutor executor = schema.MakeExecutable(); + + // act + IExecutionResult result = await executor.ExecuteAsync( + "{ foo(input: null) }"); + + // assert + result.ToJson().MatchSnapshot(); + } + + [Fact] + public async Task Input_Value_List_As_Variable() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + IRequestExecutor executor = schema.MakeExecutable(); + + // act + IExecutionResult result = await executor.ExecuteAsync( + QueryRequestBuilder.New() + .SetQuery("query ($foo: Bson) { foo(input: $foo) }") + .SetVariableValue("foo", new List { "abc" }) + .Create()); + + // assert + result.ToJson().MatchSnapshot(); + } + + [Fact] + public async Task Input_Object_List_As_Variable() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + IRequestExecutor executor = schema.MakeExecutable(); + + // act + IExecutionResult result = await executor.ExecuteAsync( + QueryRequestBuilder.New() + .SetQuery("query ($foo: Bson) { foo(input: $foo) }") + .SetVariableValue("foo", + new List { new Dictionary { { "abc", "def" } } }) + .Create()); + + // assert + result.ToJson().MatchSnapshot(); + } + + [Fact] + public async Task Input_Value_String_As_Variable() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + IRequestExecutor executor = schema.MakeExecutable(); + + // act + IExecutionResult result = await executor.ExecuteAsync( + QueryRequestBuilder.New() + .SetQuery("query ($foo: Bson) { foo(input: $foo) }") + .SetVariableValue("foo", "bar") + .Create()); + + // assert + result.ToJson().MatchSnapshot(); + } + + [Fact] + public async Task Input_Value_Int_As_Variable() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + IRequestExecutor executor = schema.MakeExecutable(); + + // act + IExecutionResult result = await executor.ExecuteAsync( + QueryRequestBuilder.New() + .SetQuery("query ($foo: Bson) { foo(input: $foo) }") + .SetVariableValue("foo", 123) + .Create()); + + // assert + result.ToJson().MatchSnapshot(); + } + + [Fact] + public async Task Input_Value_Float_As_Variable() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + IRequestExecutor executor = schema.MakeExecutable(); + + // act + IExecutionResult result = await executor.ExecuteAsync( + QueryRequestBuilder.New() + .SetQuery("query ($foo: Bson) { foo(input: $foo) }") + .SetVariableValue("foo", 1.2) + .Create()); + + // assert + result.ToJson().MatchSnapshot(); + } + + [Fact] + public async Task Input_Value_BsonDocument_As_Variable() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentLiteral("input"))) + .Create(); + + IRequestExecutor executor = schema.MakeExecutable(); + + // act + IExecutionResult result = await executor.ExecuteAsync( + QueryRequestBuilder.New() + .SetQuery("query ($foo: Bson) { foo(input: $foo) }") + .SetVariableValue("foo", new BsonDocument { { "a", "b" } }) + .Create()); + + // assert + result.ToJson().MatchSnapshot(); + } + + [Fact] + public async Task Input_Value_Boolean_As_Variable() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + IRequestExecutor executor = schema.MakeExecutable(); + + // act + IExecutionResult result = await executor.ExecuteAsync( + QueryRequestBuilder.New() + .SetQuery("query ($foo: Bson) { foo(input: $foo) }") + .SetVariableValue("foo", false) + .Create()); + + // assert + result.ToJson().MatchSnapshot(); + } + + [Fact] + public async Task Input_Value_Null_As_Variable() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + IRequestExecutor executor = schema.MakeExecutable(); + + // act + IExecutionResult result = await executor.ExecuteAsync( + QueryRequestBuilder.New() + .SetQuery("query ($foo: Bson) { foo(input: $foo) }") + .SetVariableValue("foo", null) + .Create()); + + // assert + result.ToJson().MatchSnapshot(); + } + + [Fact] + public void IsInstanceOfType_EnumValue_False() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + BsonType type = schema.GetType("Bson"); + + // act + var result = type.IsInstanceOfType(new EnumValueNode("foo")); + + // assert + Assert.False(result); + } + + [Fact] + public void IsInstanceOfType_ObjectValue_True() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + BsonType type = schema.GetType("Bson"); + + // act + var result = type.IsInstanceOfType(new ObjectValueNode(Array.Empty())); + + // assert + Assert.True(result); + } + + [Fact] + public void IsInstanceOfType_ListValue_False() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + BsonType type = schema.GetType("Bson"); + + // act + var result = type.IsInstanceOfType(new ListValueNode(Array.Empty())); + + // assert + Assert.True(result); + } + + [Fact] + public void IsInstanceOfType_StringValue_False() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + BsonType type = schema.GetType("Bson"); + + // act + var result = type.IsInstanceOfType(new StringValueNode("foo")); + + // assert + Assert.True(result); + } + + [Fact] + public void IsInstanceOfType_IntValue_False() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + BsonType type = schema.GetType("Bson"); + + // act + var result = type.IsInstanceOfType(new IntValueNode(123)); + + // assert + Assert.True(result); + } + + [Fact] + public void IsInstanceOfType_FloatValue_False() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + BsonType type = schema.GetType("Bson"); + + // act + var result = type.IsInstanceOfType(new FloatValueNode(1.2)); + + // assert + Assert.True(result); + } + + [Fact] + public void IsInstanceOfType_BooleanValue_False() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + BsonType type = schema.GetType("Bson"); + + // act + var result = type.IsInstanceOfType(new BooleanValueNode(true)); + + // assert + Assert.True(result); + } + + [Fact] + public void IsInstanceOfType_NullValue_True() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + BsonType type = schema.GetType("Bson"); + + // act + var result = type.IsInstanceOfType(NullValueNode.Default); + + // assert + Assert.True(result); + } + + [Fact] + public void IsInstanceOfType_Null_ArgumentNullException() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + BsonType type = schema.GetType("Bson"); + + // act + void Action() => type.IsInstanceOfType(null!); + + // assert + Assert.Throws(Action); + } + + [InlineData("abc", typeof(StringValueNode))] + [InlineData((short)1, typeof(IntValueNode))] + [InlineData((int)1, typeof(IntValueNode))] + [InlineData((long)1, typeof(IntValueNode))] + [InlineData((float)1, typeof(FloatValueNode))] + [InlineData((double)1, typeof(FloatValueNode))] + [InlineData(true, typeof(BooleanValueNode))] + [InlineData(false, typeof(BooleanValueNode))] + [Theory] + public void ParseValue_ScalarValues(object value, Type expectedType) + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + BsonType type = schema.GetType("Bson"); + + // act + IValueNode literal = type.ParseValue(value); + + // assert + Assert.IsType(expectedType, literal); + } + + [Fact] + public void ParseValue_Decimal() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + BsonType type = schema.GetType("Bson"); + + // act + IValueNode literal = type.ParseValue((decimal)1); + + // assert + Assert.IsType(literal); + } + + [Fact] + public void ParseValue_List_Of_Object() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + BsonType type = schema.GetType("Bson"); + + // act + IValueNode literal = type.ParseValue(new List()); + + // assert + Assert.IsType(literal); + } + + [Fact] + public void ParseValue_List_Of_String() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + BsonType type = schema.GetType("Bson"); + + // act + IValueNode literal = type.ParseValue(new List()); + + // assert + Assert.IsType(literal); + } + + [Fact] + public void ParseValue_List_Of_Foo() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + BsonType type = schema.GetType("Bson"); + + // act + IValueNode literal = type.ParseValue(new List()); + + // assert + Assert.IsType(literal); + } + + [Fact] + public void ParseValue_Dictionary() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + BsonType type = schema.GetType("Bson"); + + // act + IValueNode literal = type.ParseValue( + new Dictionary()); + + // assert + Assert.IsType(literal); + } + + [Fact] + public void Deserialize_ValueNode() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + BsonType type = schema.GetType("Bson"); + + // act + var value = type.Deserialize(new StringValueNode("Foo")); + + // assert + Assert.Equal("Foo", Assert.IsType(value).Value); + } + + [Fact] + public void Deserialize_Dictionary() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + BsonType type = schema.GetType("Bson"); + + var toDeserialize = new Dictionary + { + { "Foo", new StringValueNode("Bar") } + }; + + // act + var value = type.Deserialize(toDeserialize); + + // assert + Assert.Equal("Bar", Assert.IsType(value)["Foo"]); + } + + [Fact] + public void Deserialize_NestedDictionary() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + BsonType type = schema.GetType("Bson"); + + var toDeserialize = new Dictionary + { + { "Foo", new Dictionary { { "Bar", new StringValueNode("Baz") } } } + }; + + // act + var value = type.Deserialize(toDeserialize); + + // assert + var innerDictionary = Assert.IsType(value)["Foo"]; + Assert.Equal("Baz", Assert.IsType(innerDictionary)["Bar"]); + } + + [Fact] + public void Deserialize_List() + { + // arrange + ISchema schema = SchemaBuilder.New() + .AddQueryType(d => d + .Name("Query") + .Field("foo") + .Type() + .Argument("input", a => a.Type()) + .Resolve(ctx => ctx.ArgumentValue("input"))) + .Create(); + + BsonType type = schema.GetType("Bson"); + var toDeserialize = + new List { new StringValueNode("Foo"), new StringValueNode("Bar") }; + + // act + var value = type.Deserialize(toDeserialize); + + // assert + Assert.Collection( + Assert.IsType(value)!, + x => Assert.Equal("Foo", x), + x => Assert.Equal("Bar", x)); + } + + public class Foo + { + public Bar Bar { get; set; } = new Bar(); + } + + public class Bar + { + public string Baz { get; set; } = "Baz"; + } + + public class QueryWithDictionary + { + [GraphQLType(typeof(BsonType))] + public IDictionary SomeObject => + new Dictionary { { "a", "b" } }; + } + + public class OutputQuery + { + public BsonInt32 Int32 => new(42); + + public BsonInt64 Int64 => new(42); + + public BsonDateTime DateTime => new(1638147536); + + public BsonTimestamp Timestamp => new(1638147536); + + public BsonObjectId ObjectId => new BsonObjectId(new ObjectId("6124e80f3f5fc839830c1f6b")); + + public BsonBinaryData Binary => new BsonBinaryData(new byte[] + { + 1, + 2, + 3, + 4, + 5, + 6 + }); + + public BsonDecimal128 Decimal => new(42.123456789123456789123456789123456789123456789m); + + public BsonDouble Double => new(42.23); + + public BsonBoolean Boolean => new(true); + + public BsonArray BsonArray => new(new[] + { + BsonBoolean.False, + BsonBoolean.True + }); + + public BsonString String => new("String"); + + public BsonNull? Null => BsonNull.Value; + + public BsonDocument Document { get; } = new() + { + ["Int32"] = new BsonInt32(42), + ["Int64"] = new BsonInt64(42), + ["Decimal"] = new BsonDecimal128(42.123456789123456789123456789123456789123456789m), + ["Double"] = new BsonDouble(42.23), + ["DateTime"] = new BsonDateTime(1638147536), + ["Timestamp"] = new BsonTimestamp(1638147536), + ["ObjectId"] = new BsonObjectId(new ObjectId("6124e80f3f5fc839830c1f6b")), + ["BinaryData"] = new BsonBinaryData(new byte[] + { + 1, + 2, + 3, + 4, + 5, + 6 + }), + ["Double"] = new BsonDouble(42.23), + ["Double"] = new BsonDouble(42.23), + ["Boolean"] = new BsonBoolean(true), + ["BsonArray"] = new BsonArray(new[] + { + BsonBoolean.False, + BsonBoolean.True + }), + ["String"] = new BsonString("String"), + ["Null"] = BsonNull.Value, + ["Nested"] = new BsonDocument() + { + ["Int32"] = new BsonInt32(42), ["Int64"] = new BsonInt64(42), + } + }; + } +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Object.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Object.snap new file mode 100644 index 00000000000..f9ba9ce8292 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Object.snap @@ -0,0 +1,7 @@ +{ + "data": { + "foo": { + "a": "foo" + } + } +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Object_List.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Object_List.snap new file mode 100644 index 00000000000..87cbe3d2d41 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Object_List.snap @@ -0,0 +1,9 @@ +{ + "data": { + "foo": [ + { + "a": "foo" + } + ] + } +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Object_List_As_Variable.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Object_List_As_Variable.snap new file mode 100644 index 00000000000..4c36a00b0e6 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Object_List_As_Variable.snap @@ -0,0 +1,9 @@ +{ + "data": { + "foo": [ + { + "abc": "def" + } + ] + } +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_DictionaryPassed.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_DictionaryPassed.snap new file mode 100644 index 00000000000..ecd5453f12e --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_DictionaryPassed.snap @@ -0,0 +1 @@ +{ "foo" : true } diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_ListPassed.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_ListPassed.snap new file mode 100644 index 00000000000..0e5af4461a9 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_ListPassed.snap @@ -0,0 +1 @@ +[foo, bar] diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_PassedVariable_boolean.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_PassedVariable_boolean.snap new file mode 100644 index 00000000000..210176424e9 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_PassedVariable_boolean.snap @@ -0,0 +1 @@ +true diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_PassedVariable_double.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_PassedVariable_double.snap new file mode 100644 index 00000000000..5b4a321d0da --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_PassedVariable_double.snap @@ -0,0 +1 @@ +43.23 diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_PassedVariable_int.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_PassedVariable_int.snap new file mode 100644 index 00000000000..68264e1ab71 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_PassedVariable_int.snap @@ -0,0 +1 @@ +42 diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_PassedVariable_long.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_PassedVariable_long.snap new file mode 100644 index 00000000000..d88ca3ca981 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_PassedVariable_long.snap @@ -0,0 +1 @@ +9223372036854775807 diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_PassedVariable_string.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_PassedVariable_string.snap new file mode 100644 index 00000000000..a4301cf2a92 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_PassedVariable_string.snap @@ -0,0 +1 @@ +"string" diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_Passed_array.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_Passed_array.snap new file mode 100644 index 00000000000..a73e153c2c0 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_Passed_array.snap @@ -0,0 +1,4 @@ +[ + true, + false +] diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_Passed_boolean.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_Passed_boolean.snap new file mode 100644 index 00000000000..210176424e9 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_Passed_boolean.snap @@ -0,0 +1 @@ +true diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_Passed_decimal.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_Passed_decimal.snap new file mode 100644 index 00000000000..7520449dc23 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_Passed_decimal.snap @@ -0,0 +1 @@ +"42.1234" diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_Passed_double.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_Passed_double.snap new file mode 100644 index 00000000000..5b4a321d0da --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_Passed_double.snap @@ -0,0 +1 @@ +43.23 diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_Passed_int.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_Passed_int.snap new file mode 100644 index 00000000000..68264e1ab71 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_Passed_int.snap @@ -0,0 +1 @@ +42 diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_Passed_long.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_Passed_long.snap new file mode 100644 index 00000000000..d88ca3ca981 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_Passed_long.snap @@ -0,0 +1 @@ +9223372036854775807 diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_Passed_string.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_Passed_string.snap new file mode 100644 index 00000000000..a4301cf2a92 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshotAndType_When_Passed_string.snap @@ -0,0 +1 @@ +"string" diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshot_When_BsonDocument.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshot_When_BsonDocument.snap new file mode 100644 index 00000000000..b0df620b0bd --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Should_MatchSnapshot_When_BsonDocument.snap @@ -0,0 +1 @@ +{ "int32" : NumberLong(42), "int64" : NumberLong(42), "decimal" : "42.123456789123456789123456789", "double" : 42.229999999999997, "boolean" : true, "bsonArray" : [false, true], "string" : "String", "null" : null, "nested" : { "int32" : NumberLong(42), "int64" : NumberLong(42) } } diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_Boolean.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_Boolean.snap new file mode 100644 index 00000000000..8369956872e --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_Boolean.snap @@ -0,0 +1,5 @@ +{ + "data": { + "foo": true + } +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_Boolean_As_Variable.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_Boolean_As_Variable.snap new file mode 100644 index 00000000000..3e7043b5456 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_Boolean_As_Variable.snap @@ -0,0 +1,5 @@ +{ + "data": { + "foo": false + } +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_BsonDocument_As_Variable.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_BsonDocument_As_Variable.snap new file mode 100644 index 00000000000..9c8525da9ae --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_BsonDocument_As_Variable.snap @@ -0,0 +1,5 @@ +{ + "data": { + "foo": "{ \u0022a\u0022 : \u0022b\u0022 }" + } +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_Float.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_Float.snap new file mode 100644 index 00000000000..4461a0095d3 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_Float.snap @@ -0,0 +1,5 @@ +{ + "data": { + "foo": 1.2 + } +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_Float_As_Variable.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_Float_As_Variable.snap new file mode 100644 index 00000000000..4461a0095d3 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_Float_As_Variable.snap @@ -0,0 +1,5 @@ +{ + "data": { + "foo": 1.2 + } +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_Int.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_Int.snap new file mode 100644 index 00000000000..fd75ee05ded --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_Int.snap @@ -0,0 +1,5 @@ +{ + "data": { + "foo": 123 + } +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_Int_As_Variable.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_Int_As_Variable.snap new file mode 100644 index 00000000000..fd75ee05ded --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_Int_As_Variable.snap @@ -0,0 +1,5 @@ +{ + "data": { + "foo": 123 + } +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_List.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_List.snap new file mode 100644 index 00000000000..7c8fe50a5a4 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_List.snap @@ -0,0 +1,7 @@ +{ + "data": { + "foo": [ + "foo" + ] + } +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_List_As_Variable.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_List_As_Variable.snap new file mode 100644 index 00000000000..7464f0d8bf8 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_List_As_Variable.snap @@ -0,0 +1,7 @@ +{ + "data": { + "foo": [ + "abc" + ] + } +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_Null.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_Null.snap new file mode 100644 index 00000000000..d5230bebb26 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_Null.snap @@ -0,0 +1,5 @@ +{ + "data": { + "foo": null + } +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_Null_As_Variable.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_Null_As_Variable.snap new file mode 100644 index 00000000000..d5230bebb26 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_Null_As_Variable.snap @@ -0,0 +1,5 @@ +{ + "data": { + "foo": null + } +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_String.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_String.snap new file mode 100644 index 00000000000..9f36622bb50 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_String.snap @@ -0,0 +1,5 @@ +{ + "data": { + "foo": "foo" + } +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_String_As_Variable.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_String_As_Variable.snap new file mode 100644 index 00000000000..0ca61aab0dc --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Input_Value_String_As_Variable.snap @@ -0,0 +1,5 @@ +{ + "data": { + "foo": "bar" + } +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Return_List.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Return_List.snap new file mode 100644 index 00000000000..02f0c560327 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Return_List.snap @@ -0,0 +1,7 @@ +{ + "data": { + "foo": [ + {} + ] + } +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Return_Object.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Return_Object.snap new file mode 100644 index 00000000000..8c56f792296 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Return_Object.snap @@ -0,0 +1,7 @@ +{ + "data": { + "foo": { + "foo": "bar" + } + } +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_BindAllRuntimeTypes.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_BindAllRuntimeTypes.snap new file mode 100644 index 00000000000..9f0d658b843 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_BindAllRuntimeTypes.snap @@ -0,0 +1,31 @@ +schema { + query: OutputQuery +} + +type OutputQuery { + int32: Bson! + int64: Bson! + dateTime: Bson! + timestamp: Bson! + objectId: Bson! + binary: Bson! + decimal: Bson! + double: Bson! + boolean: Bson! + bsonArray: [Bson]! + string: Bson! + null: Bson + document: Bson! +} + +"The `@defer` directive may be provided for fragment spreads and inline fragments to inform the executor to delay the execution of the current fragment to indicate deprioritization of the current fragment. A query with `@defer` directive will cause the request to potentially return multiple responses, where non-deferred data is delivered in the initial response and data deferred is delivered in a subsequent response. `@include` and `@skip` take precedence over `@defer`." +directive @defer("If this argument label has a value other than null, it will be passed on to the result of this defer directive. This label is intended to give client applications a way to identify to which fragment a deferred result belongs to." label: String "Deferred when true." if: Boolean) on FRAGMENT_SPREAD | INLINE_FRAGMENT + +"The `@specifiedBy` directive is used within the type system definition language to provide a URL for specifying the behavior of custom scalar definitions." +directive @specifiedBy("The specifiedBy URL points to a human-readable specification. This field will only read a result for scalar types." url: String!) on SCALAR + +"The `@stream` directive may be provided for a field of `List` type so that the backend can leverage technology such as asynchronous iterators to provide a partial list in the initial response, and additional list items in subsequent responses. `@include` and `@skip` take precedence over `@stream`." +directive @stream("If this argument label has a value other than null, it will be passed on to the result of this stream directive. This label is intended to give client applications a way to identify to which fragment a streamed result belongs to." label: String "The initial elements that shall be send down to the consumer." initialCount: Int! = 0 "Streamed when true." if: Boolean) on FIELD + +"BSON is a binary format in which zero or more ordered key\/value pairs are stored as a single entity. The results are returned as JSON objects" +scalar Bson @specifiedBy(url: "https:\/\/bsonspec.org\/spec.html") diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_BsonDocument.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_BsonDocument.snap new file mode 100644 index 00000000000..591d73dbb96 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_BsonDocument.snap @@ -0,0 +1,25 @@ +{ + "data": { + "document": { + "Int32": 42, + "Int64": 42, + "Decimal": "42.123456789123456789123456789", + "Double": 42.23, + "DateTime": "1970-01-19T23:02:27.536Z", + "Timestamp": 1638147536, + "ObjectId": "6124e80f3f5fc839830c1f6b", + "BinaryData": "AQIDBAUG", + "Boolean": true, + "BsonArray": [ + false, + true + ], + "String": "String", + "Null": null, + "Nested": { + "Int32": 42, + "Int64": 42 + } + } + } +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_binary.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_binary.snap new file mode 100644 index 00000000000..ae87688608b --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_binary.snap @@ -0,0 +1,5 @@ +{ + "data": { + "binary": "AQIDBAUG" + } +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_boolean.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_boolean.snap new file mode 100644 index 00000000000..5e4eef42856 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_boolean.snap @@ -0,0 +1,5 @@ +{ + "data": { + "boolean": true + } +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_bsonArray.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_bsonArray.snap new file mode 100644 index 00000000000..ab5d8520e0f --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_bsonArray.snap @@ -0,0 +1,8 @@ +{ + "data": { + "bsonArray": [ + false, + true + ] + } +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_dateTime.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_dateTime.snap new file mode 100644 index 00000000000..aae80feaf24 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_dateTime.snap @@ -0,0 +1,5 @@ +{ + "data": { + "dateTime": "1970-01-19T23:02:27.536Z" + } +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_decimal.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_decimal.snap new file mode 100644 index 00000000000..a67732deec0 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_decimal.snap @@ -0,0 +1,5 @@ +{ + "data": { + "decimal": "42.123456789123456789123456789" + } +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_double.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_double.snap new file mode 100644 index 00000000000..a4b1a722306 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_double.snap @@ -0,0 +1,5 @@ +{ + "data": { + "double": 42.23 + } +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_int32.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_int32.snap new file mode 100644 index 00000000000..6d2233f0699 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_int32.snap @@ -0,0 +1,5 @@ +{ + "data": { + "int32": 42 + } +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_int64.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_int64.snap new file mode 100644 index 00000000000..b98b016e626 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_int64.snap @@ -0,0 +1,5 @@ +{ + "data": { + "int64": 42 + } +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_null.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_null.snap new file mode 100644 index 00000000000..d849046753c --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_null.snap @@ -0,0 +1,5 @@ +{ + "data": { + "null": null + } +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_objectId.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_objectId.snap new file mode 100644 index 00000000000..708fb5ab6ec --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_objectId.snap @@ -0,0 +1,5 @@ +{ + "data": { + "objectId": "6124e80f3f5fc839830c1f6b" + } +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_string.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_string.snap new file mode 100644 index 00000000000..09524d31274 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_string.snap @@ -0,0 +1,5 @@ +{ + "data": { + "string": "String" + } +} diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_timestamp.snap b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_timestamp.snap new file mode 100644 index 00000000000..eb7f99282d1 --- /dev/null +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/__snapshots__/BsonTypeTests.Output_Should_MatchSnapshot_When_Value_timestamp.snap @@ -0,0 +1,5 @@ +{ + "data": { + "timestamp": 1638147536 + } +}