Skip to content

Commit 2e872d7

Browse files
authored
Adds @serializeAs for scalar serialization. (#8867)
1 parent 00e1c5f commit 2e872d7

File tree

37 files changed

+1710
-1667
lines changed

37 files changed

+1710
-1667
lines changed

src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationRequestBuilder.cs

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using System.Diagnostics.CodeAnalysis;
2+
using System.Runtime.CompilerServices;
3+
using System.Text.Json;
24
using HotChocolate.Features;
35
using HotChocolate.Language;
46

@@ -175,6 +177,66 @@ public OperationRequestBuilder SetVariableValues(
175177
return this;
176178
}
177179

180+
/// <summary>
181+
/// Sets the variable values for the GraphQL request.
182+
/// </summary>
183+
/// <param name="variableValues">
184+
/// The variable values for the GraphQL request.
185+
/// </param>
186+
/// <returns>
187+
/// Returns this instance of <see cref="OperationRequestBuilder" /> for configuration chaining.
188+
/// </returns>
189+
public OperationRequestBuilder SetVariableValuesJson(
190+
[StringSyntax("json")] string variableValues)
191+
{
192+
ArgumentException.ThrowIfNullOrEmpty(variableValues);
193+
194+
using var document = JsonDocument.Parse(variableValues);
195+
return SetVariableValuesJson(document);
196+
}
197+
198+
/// <summary>
199+
/// Sets the variable values for the GraphQL request.
200+
/// </summary>
201+
/// <param name="variableValues">
202+
/// The variable values for the GraphQL request.
203+
/// </param>
204+
/// <returns>
205+
/// Returns this instance of <see cref="OperationRequestBuilder" /> for configuration chaining.
206+
/// </returns>
207+
public OperationRequestBuilder SetVariableValuesJson(
208+
JsonDocument variableValues)
209+
{
210+
ArgumentNullException.ThrowIfNull(variableValues);
211+
212+
if (variableValues.RootElement.ValueKind is not (JsonValueKind.Null or JsonValueKind.Object))
213+
{
214+
throw new ArgumentException(
215+
"The JSON document must be either null or an array of variable sets.",
216+
nameof(variableValues));
217+
}
218+
219+
if (variableValues.RootElement.ValueKind is JsonValueKind.Null)
220+
{
221+
_variableValues = null;
222+
_readOnlyVariableValues = null;
223+
return this;
224+
}
225+
226+
var parser = new JsonValueParser();
227+
var objectValue = (ObjectValueNode)parser.Parse(variableValues.RootElement);
228+
var values = new Dictionary<string, object?>();
229+
230+
foreach (var field in objectValue.Fields)
231+
{
232+
values[field.Name.Value] = field.Value;
233+
}
234+
235+
_variableValues = [values];
236+
_readOnlyVariableValues = null;
237+
return this;
238+
}
239+
178240
/// <summary>
179241
/// Sets the variable values for the GraphQL request.
180242
/// </summary>
@@ -200,6 +262,78 @@ public OperationRequestBuilder SetVariableValuesSet(
200262
return this;
201263
}
202264

265+
/// <summary>
266+
/// Sets the variable values for the GraphQL request.
267+
/// </summary>
268+
/// <param name="variableValues">
269+
/// The variable values for the GraphQL request.
270+
/// </param>
271+
/// <returns>
272+
/// Returns this instance of <see cref="OperationRequestBuilder" /> for configuration chaining.
273+
/// </returns>
274+
public OperationRequestBuilder SetVariableValuesSetJson([StringSyntax("json")] string variableValues)
275+
{
276+
ArgumentException.ThrowIfNullOrEmpty(variableValues);
277+
278+
using var document = JsonDocument.Parse(variableValues);
279+
return SetVariableValuesSetJson(document);
280+
}
281+
282+
/// <summary>
283+
/// Sets the variable values for the GraphQL request.
284+
/// </summary>
285+
/// <param name="variableValues">
286+
/// The variable values for the GraphQL request.
287+
/// </param>
288+
/// <returns>
289+
/// Returns this instance of <see cref="OperationRequestBuilder" /> for configuration chaining.
290+
/// </returns>
291+
public OperationRequestBuilder SetVariableValuesSetJson(JsonDocument variableValues)
292+
{
293+
ArgumentNullException.ThrowIfNull(variableValues);
294+
295+
if (variableValues.RootElement.ValueKind is not (JsonValueKind.Null or JsonValueKind.Array))
296+
{
297+
throw new ArgumentException(
298+
"The JSON document must be either null or an array of variable sets.",
299+
nameof(variableValues));
300+
}
301+
302+
if (variableValues.RootElement.ValueKind is JsonValueKind.Null)
303+
{
304+
_variableValues = null;
305+
_readOnlyVariableValues = null;
306+
return this;
307+
}
308+
309+
var parser = new JsonValueParser();
310+
var sets = new List<IReadOnlyDictionary<string, object?>>();
311+
312+
foreach (var element in variableValues.RootElement.EnumerateArray())
313+
{
314+
if (element.ValueKind != JsonValueKind.Object)
315+
{
316+
throw new ArgumentException(
317+
"Each variable set must be a JSON object.",
318+
nameof(variableValues));
319+
}
320+
321+
var objectValue = (ObjectValueNode)parser.Parse(element);
322+
var values = new Dictionary<string, object?>();
323+
324+
foreach (var field in objectValue.Fields)
325+
{
326+
values[field.Name.Value] = field.Value;
327+
}
328+
329+
sets.Add(values);
330+
}
331+
332+
_variableValues = sets;
333+
_readOnlyVariableValues = null;
334+
return this;
335+
}
336+
203337
/// <summary>
204338
/// Sets the GraphQL request extension data.
205339
/// </summary>

src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Composite.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,6 @@ public static IRequestExecutorBuilder AddSourceSchemaDefaults(
2323
o.ApplyShareableToConnections = true;
2424
o.ApplyShareableToPageInfo = true;
2525
o.ApplyShareableToNodeFields = true;
26+
o.ApplySerializeAsToScalars = true;
2627
});
2728
}

src/HotChocolate/Core/src/Types.Abstractions/Types/IScalarTypeDefinition.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,30 @@
22

33
namespace HotChocolate.Types;
44

5+
/// <summary>
6+
/// Represents a scalar type definition in the GraphQL schema.
7+
/// </summary>
58
public interface IScalarTypeDefinition
69
: IOutputTypeDefinition
710
, IInputTypeDefinition
811
, ISyntaxNodeProvider<ScalarTypeDefinitionNode>
912
{
13+
/// <summary>
14+
/// Gets the URI that specifies the behavior and constraints of this scalar type.
15+
/// </summary>
1016
Uri? SpecifiedBy { get; }
1117

18+
/// <summary>
19+
/// Gets the possible types that this scalar can serialize to.
20+
/// </summary>
21+
ScalarSerializationType SerializationType { get; }
22+
23+
/// <summary>
24+
/// Gets the ECMA-262 regex pattern that the serialized scalar value conforms
25+
/// to if its of the serialization type <see cref="ScalarSerializationType.String"/>.
26+
/// </summary>
27+
string? Pattern { get; }
28+
1229
/// <summary>
1330
/// Checks if the value is an instance of this type.
1431
/// </summary>
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
namespace HotChocolate.Types;
2+
3+
/// <summary>
4+
/// Defines the possible serialization types for GraphQL scalar values.
5+
/// </summary>
6+
[Flags]
7+
public enum ScalarSerializationType
8+
{
9+
/// <summary>
10+
/// No serialization type is defined.
11+
/// </summary>
12+
Undefined = 0,
13+
14+
/// <summary>
15+
/// The scalar serializes to a string value.
16+
/// </summary>
17+
String = 1,
18+
19+
/// <summary>
20+
/// The scalar serializes to a boolean value.
21+
/// </summary>
22+
Boolean = 2,
23+
24+
/// <summary>
25+
/// The scalar serializes to an integer value.
26+
/// </summary>
27+
Int = 4,
28+
29+
/// <summary>
30+
/// The scalar serializes to a floating-point value.
31+
/// </summary>
32+
Float = 8,
33+
34+
/// <summary>
35+
/// The scalar serializes to an object value.
36+
/// </summary>
37+
Object = 16,
38+
39+
/// <summary>
40+
/// The scalar serializes to a list value.
41+
/// </summary>
42+
List = 32,
43+
44+
/// <summary>
45+
/// The scalar can serialize as any possible primitive type.
46+
/// </summary>
47+
Any = String | Boolean | Int | Float | Object | List
48+
}

src/HotChocolate/Core/src/Types/IReadOnlySchemaOptions.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,4 +222,9 @@ public interface IReadOnlySchemaOptions
222222
/// field when Global Object Identification is turned on.
223223
/// </summary>
224224
bool ApplyShareableToNodeFields { get; }
225+
226+
/// <summary>
227+
/// Applies the @serializeAs directive to scalar types that specify a serialization format.
228+
/// </summary>
229+
bool ApplySerializeAsToScalars { get; }
225230
}

0 commit comments

Comments
 (0)