/// <summary> /// Runs the creation mutation /// </summary> /// <param name="connection">The connection</param> /// <param name="request">The request</param> /// <param name="field"> /// The connection field /// </param> /// <param name="context"> /// The context. /// </param> /// <param name="argumentsSerializer"> /// The arguments serializer. /// </param> /// <param name="onErrorCallback"> /// The on error callback. /// </param> /// <returns>The resolved data</returns> private async Task <JObject> MutationCreate( INodeConnection <T> connection, ApiRequest request, ApiField field, RequestContext context, JsonSerializer argumentsSerializer, Action <Exception> onErrorCallback) { var serializedData = ((JObject)request.Arguments)?.Property("newNode")?.Value as JObject; var newNode = serializedData?.ToObject <T>(); var result = await connection.Create(newNode); var mutationCreate = (JObject) await mutationResultResolver.ResolveQuery( result, request, field, context, argumentsSerializer, onErrorCallback); SetLog(request, field, context, EnConnectionAction.Create); return(mutationCreate); }
/// <summary> /// Adds a new filter condition /// </summary> /// <param name="name">The name of condition</param> /// <param name="expression">The expression generator</param> /// <param name="field">The field to check</param> /// <param name="description">The filter description</param> private static void AddFilterExpression( string name, Func <JProperty, Expression> expression, ApiField field, string description) { FilterChecks[name] = expression; description = string.Format(description, field.Name); var filterDescription = !string.IsNullOrWhiteSpace(field.Description) ? $"{description}, {field.Name}: {field.Description}" : description; if (field.ScalarType != EnScalarType.None) { FilterType.Fields.Add( ApiField.Scalar( name, field.ScalarType, EnFieldFlags.Queryable | EnFieldFlags.CanBeUsedInInput, description: filterDescription)); } else { FilterType.Fields.Add( ApiField.Object( name, field.TypeName, EnFieldFlags.Queryable | EnFieldFlags.CanBeUsedInInput, description: filterDescription)); } }
protected virtual void Process(HierarchyObject parent, ApiField field) { var hierarchyField = CreateHierarchyElementInternal <HierarchyField> (parent); hierarchyField.Init(field); AddLocationComment(field, hierarchyField); parent.AddMember(hierarchyField); }
public FieldModel(ApiField field) { if (field == null) { throw new ArgumentNullException(nameof(field)); } _field = field; }
/// <inheritdoc /> public Task <JToken> ResolveQuery( object source, ApiRequest request, ApiField apiField, RequestContext context, JsonSerializer argumentsSerializer, Action <Exception> onErrorCallback) { return(Task.FromResult <JToken>(null)); }
public override void Init(ApiElement apiElement) { base.Init(apiElement); apiField = EnsureApiElementType <ApiField> (apiElement); Transient = apiField.Transient; Type = apiField.Type; TypeGenericAware = apiField.TypeGenericAware; Value = apiField.Value; Volatile = apiField.Volatile; }
/// <summary> /// Initializes a new instance of the <see cref="MergedUntypedMutationResult"/> class. /// </summary> /// <param name="originalReturnType"> /// The original mutation return type. /// </param> /// <param name="root"> /// The root. /// </param> /// <param name="provider"> /// The provider. /// </param> /// <param name="field"> /// The original field description /// </param> public MergedUntypedMutationResult( MergedType originalReturnType, MergedApiRoot root, ApiProvider provider, ApiField field) : base(originalReturnType.OriginalTypeName) { this.OriginalReturnType = originalReturnType; this.root = root; this.field = field; this.Provider = provider; }
public async Task EnumApiTest() { var enumType = new ApiEnumType("EnumType", new[] { "item1", "item2" }); var api = new ApiDescription( "TestApi1", "0.0.0.1", new ApiType[] { enumType }, new[] { ApiField.Object("enumField", enumType.TypeName) }); var provider = new MoqProvider { Description = api, Data = "{\"enumField\": \"item2\"}" }; var schema = SchemaGenerator.Generate(new List <ApiProvider> { provider }); using (var printer = new SchemaPrinter(schema)) { var description = printer.Print(); this.output.WriteLine("-------- Schema -----------"); this.output.WriteLine(description); Assert.False(string.IsNullOrWhiteSpace(description)); } Assert.NotNull(schema.Query); Assert.Equal(3, schema.Query.Fields.Count()); Assert.True(schema.Query.HasField("api")); var result = await new DocumentExecuter().ExecuteAsync( r => { r.Schema = schema; r.Query = "query { api { enumField } } "; }).ConfigureAwait(true); this.output.WriteLine("-------- Response -----------"); var response = new DocumentWriter(true).Write(result); this.output.WriteLine(response); var expectedResponse = @"{ ""data"": { ""api"": { ""enumField"": ""item2"" } } }"; Assert.Equal(CleanResponse(expectedResponse), CleanResponse(response)); }
/// <summary> /// Resolves query /// </summary> /// <param name="requests"> /// The query request /// </param> /// <param name="context"> /// The request context. /// </param> /// <param name="onErrorCallback"> /// The method that will be called in case of errors /// </param> /// <returns> /// Resolved query /// </returns> public virtual Task <JToken> ResolveQuery( List <ApiRequest> requests, RequestContext context, Action <Exception> onErrorCallback) { return(this.resolver.ResolveQuery( this, new ApiRequest { Fields = requests }, ApiField.Object("root", this.ApiDescription.ApiName), context, this.argumentsSerializer, onErrorCallback)); }
/// <inheritdoc /> public Task <JObject> ResolveMutation( object nodeConnection, ApiRequest request, ApiField field, RequestContext context, JsonSerializer argumentsSerializer, Action <Exception> onErrorCallback) { var connection = nodeConnection as INodeConnection <T>; if (connection == null) { return(Task.FromResult <JObject>(null)); } switch (request.FieldName) { case "create": return(this.MutationCreate( connection, request, field, context, argumentsSerializer, onErrorCallback)); case "update": return(this.MutationUpdate( connection, request, field, context, argumentsSerializer, onErrorCallback)); case "delete": return(this.MutationDelete( connection, request, field, context, argumentsSerializer, onErrorCallback)); default: return(Task.FromResult <JObject>(null)); } }
/// <summary> /// Initializes a new instance of the <see cref="MergedField"/> class. /// </summary> /// <param name="name"> /// The field name. /// </param> /// <param name="type"> /// The type. /// </param> /// <param name="provider"> /// The api provider for the field /// </param> /// <param name="field">The original field description</param> /// <param name="flags"> /// The flags. /// </param> /// <param name="arguments"> /// The field arguments (in case the field is method). /// </param> /// <param name="description"> /// The field description /// </param> public MergedField( string name, MergedType type, ApiProvider provider, ApiField field, EnFieldFlags flags = EnFieldFlags.None, IReadOnlyDictionary <string, MergedField> arguments = null, string description = null) { this.FieldName = name; this.Type = type; this.Flags = flags; this.Arguments = (arguments ?? new Dictionary <string, MergedField>()).ToImmutableDictionary(); this.Description = description; this.AddProvider(provider, field); }
public static string ToCSharpPropertyName(this ApiField subject, string?containingType) { var propertyName = CSharpIdentifier.ForClassOrNamespace(subject.Name); return(subject.Type switch { ApiFieldType.Primitive primitive when primitive.ToCSharpPrimitiveType() == CSharpType.Bool && !propertyName.StartsWith("Is") && !propertyName.StartsWith("Can") => $"Is{propertyName}", // Resolve CS0542 - Member names cannot be the same as their enclosing type by adding prefix/suffix ApiFieldType.Array _ when string.Equals(propertyName, containingType, StringComparison.OrdinalIgnoreCase) => $"{propertyName}Items", _ => propertyName });
/// <summary> /// Gets the generated arguments /// </summary> /// <returns>The list of arguments</returns> public static IEnumerable <ApiField> GetArguments() { if (FilterType.Fields.Count > 2) { yield return (FilterType.CreateField( "filter", EnFieldFlags.CanBeUsedInInput | EnFieldFlags.Queryable | EnFieldFlags.IsTypeArgument)); } if (SortType.Values.Any()) { const EnFieldFlags SortFlags = EnFieldFlags.CanBeUsedInInput | EnFieldFlags.Queryable | EnFieldFlags.IsTypeArgument | EnFieldFlags.IsArray; yield return(ApiField.Object("sort", SortType.TypeName, SortFlags)); } if (NodeMetaData.KeyProperty != null) { var keyMetadata = TypeMetadata.GenerateTypeMetadata( NodeMetaData.KeyProperty.PropertyType, NodeMetaData.KeyProperty.GetCustomAttribute <PublishToApiAttribute>()); if (keyMetadata.ScalarType != EnScalarType.None) { yield return (ApiField.Scalar( "id", keyMetadata.ScalarType, EnFieldFlags.CanBeUsedInInput | EnFieldFlags.Queryable | EnFieldFlags.IsTypeArgument)); } } yield return (ApiField.Scalar( "limit", EnScalarType.Integer, EnFieldFlags.CanBeUsedInInput | EnFieldFlags.Queryable | EnFieldFlags.IsTypeArgument)); yield return (ApiField.Scalar( "offset", EnScalarType.Integer, EnFieldFlags.CanBeUsedInInput | EnFieldFlags.Queryable | EnFieldFlags.IsTypeArgument)); }
private string GenerateExtensionMethodsFor( string currentDtoType, string currentPartialType, ApiField apiField) { var indent = new Indent(); var builder = new StringBuilder(); var propertyName = apiField.ToCSharpPropertyName(currentDtoType); var apiFieldName = apiField.Name; // Field builder.AppendLine($"{indent}public static {currentPartialType} With{propertyName}(this {currentPartialType} it)"); indent.Increment(); builder.AppendLine($"{indent}=> it.AddFieldName(\"{apiFieldName}\");"); indent.Decrement(); builder.AppendLine($"{indent}"); var currentFieldInnerType = GenerateCSharpTypeFrom(apiField.Type); var isPrimitiveOrObject = apiField.Type is ApiFieldType.Primitive || apiField.Type is ApiFieldType.Object; var isArrayOfPrimitive = apiField.Type is ApiFieldType.Array arrayField && arrayField.ElementType is ApiFieldType.Primitive; if (!isPrimitiveOrObject && !isArrayOfPrimitive && !string.IsNullOrEmpty(currentFieldInnerType)) { // Recursive field? if (currentDtoType == currentFieldInnerType) { builder.AppendLine($"{indent}public static {currentPartialType} With{propertyName}Recursive(this {currentPartialType} it)"); indent.Increment(); builder.AppendLine($"{indent}=> it.AddFieldName(\"{apiFieldName}!\");"); indent.Decrement(); builder.AppendLine($"{indent}"); } // Field with partial builder builder.AppendLine($"{indent}public static {currentPartialType} With{propertyName}(this {currentPartialType} it, Func<Partial<{currentFieldInnerType}>, Partial<{currentFieldInnerType}>> partialBuilder)"); indent.Increment(); builder.AppendLine($"{indent}=> it.AddFieldName(\"{apiFieldName}\", partialBuilder(new Partial<{currentFieldInnerType}>(it)));"); indent.Decrement(); builder.AppendLine($"{indent}"); } return(builder.ToString()); }
/// <summary> /// Sets the operation log /// </summary> /// <param name="request"> /// The initial request /// </param> /// <param name="apiField"> /// The connection field /// </param> /// <param name="context"> /// The request context /// </param> /// <param name="action"> /// The action performed /// </param> protected static void SetLog( ApiRequest request, ApiField apiField, RequestContext context, EnConnectionAction action) { if (apiField.LogAccessRules == null || !apiField.LogAccessRules.Any()) { return; } var rule = apiField.LogAccessRules.OrderByDescending(r => r.Severity) .FirstOrDefault(r => r.ConnectionActions.HasFlag(action)); if (rule == null) { return; } var operationGranted = EnSecurityLogType.OperationGranted; switch (action) { case EnConnectionAction.Create: operationGranted = EnSecurityLogType.DataCreateGranted; break; case EnConnectionAction.Update: operationGranted = EnSecurityLogType.DataUpdateGranted; break; case EnConnectionAction.Delete: operationGranted = EnSecurityLogType.DataDeleteGranted; break; } SecurityLog.CreateRecord( operationGranted, rule.Severity, context, rule.LogMessage, ((JObject)request.Arguments).ToString(Formatting.None)); }
/// <summary> /// Runs the creation mutation /// </summary> /// <param name="connection">The connection</param> /// <param name="request">The request</param> /// <param name="field"> /// The connection field /// </param> /// <param name="context"> /// The context. /// </param> /// <param name="argumentsSerializer"> /// The arguments serializer. /// </param> /// <param name="onErrorCallback"> /// The on error callback. /// </param> /// <returns>The resolved data</returns> private async Task <JObject> MutationUpdate( INodeConnection <T> connection, ApiRequest request, ApiField field, RequestContext context, JsonSerializer argumentsSerializer, Action <Exception> onErrorCallback) { var serializedData = ((JObject)request.Arguments)?.Property("newNode")?.Value as JObject; var serializedId = ((JObject)request.Arguments)?.Property("id")?.Value; var id = serializedId?.ToObject(NodeMetaData.KeyProperty.PropertyType); if (id == null) { return(null); } var newNode = serializedData?.ToObject <T>(); var result = await connection.Update(id, newNode, request); var mutationUpdate = (JObject) await mutationResultResolver.ResolveQuery( result, request, field, context, argumentsSerializer, onErrorCallback); if (result.Result != null) { if (!id.Equals(GetIdValue(result.Result))) { mutationUpdate.Add("__deletedId", JToken.FromObject(id)); } } SetLog(request, field, context, EnConnectionAction.Update); return(mutationUpdate); }
/// <inheritdoc /> public async Task <JToken> ResolveQuery(object source, ApiRequest request, ApiField apiField, RequestContext context, JsonSerializer argumentsSerializer, Action <Exception> onErrorCallback) { if (source == null) { return(JValue.CreateNull()); } var collection = source as IEnumerable; if (collection == null) { onErrorCallback?.Invoke(new InvalidOperationException($"{source.GetType().FullName} is not a collection")); return(JValue.CreateNull()); } var result = new JArray(); foreach (var value in collection) { result.Add(await this.elementResolver.ResolveQuery(value, request, apiField, context, argumentsSerializer, onErrorCallback)); } return(result); }
public async Task ArraysApiTest() { var viewerFields = new[] { ApiField.Scalar("id", EnScalarType.Guid, EnFieldFlags.Queryable | EnFieldFlags.IsKey), ApiField.Scalar("name", EnScalarType.String), ApiField.Scalar("numbers", EnScalarType.Integer, EnFieldFlags.IsArray | EnFieldFlags.Queryable) }; var viewerType = new ApiObjectType("viewer", viewerFields); var objectFields = new[] { ApiField.Scalar("id", EnScalarType.Integer, EnFieldFlags.IsKey | EnFieldFlags.Queryable), ApiField.Scalar("name", EnScalarType.String) }; var objectType = new ApiObjectType("object", objectFields); var api = new ApiDescription( "TestApi1", "0.0.0.1", new[] { viewerType, objectType }, new[] { viewerType.CreateField("viewer"), objectType.CreateField("object", EnFieldFlags.IsConnection | EnFieldFlags.Queryable) }); var provider = new MoqProvider { Description = api, Data = @"{ ""viewer"": { ""__id"": ""FD73BAFB-3698-4FA1-81F5-27C8C83BB4F0"", ""name"": ""test name"", ""numbers"": [1, 2, 3] }, ""object"": { ""count"": 2, ""edges"": [ {""__id"": 10, ""node___id"": 10}, {""__id"": 20, ""node___id"": 20} ] } }" }; var schema = SchemaGenerator.Generate(new List <ApiProvider> { provider }); using (var printer = new SchemaPrinter(schema)) { var description = printer.Print(); this.output.WriteLine("-------- Schema -----------"); this.output.WriteLine(description); Assert.False(string.IsNullOrWhiteSpace(description)); } Assert.NotNull(schema.Query); Assert.Equal(3, schema.Query.Fields.Count()); Assert.True(schema.Query.HasField("api")); var result = await new DocumentExecuter().ExecuteAsync( r => { r.Schema = schema; r.Query = @" query { api { viewer { __id, name, numbers }, object { count, edges { cursor, node { __id } } } } } "; }).ConfigureAwait(true); this.output.WriteLine("-------- Response -----------"); var response = new DocumentWriter(true).Write(result); this.output.WriteLine(response); var expectedResponse = @"{ ""data"": { ""api"": { ""viewer"": { ""__id"": ""fd73bafb-3698-4fa1-81f5-27c8c83bb4f0"", ""name"": ""test name"", ""numbers"": [1, 2, 3] }, ""object"": { ""count"": 2, ""edges"": [ { ""cursor"": 10, ""node"": { ""__id"": 10 } }, { ""cursor"": 20, ""node"": { ""__id"": 20 } } ] } } } }"; Assert.Equal(CleanResponse(expectedResponse), CleanResponse(response)); }
/// <summary> /// Adds a provider to the provider list /// </summary> /// <param name="provider">The provider</param> /// <param name="field">The original field description</param> public void AddProvider(ApiProvider provider, ApiField field) { this.providers.Add(provider); this.OriginalFields[provider.Description.ApiName] = field; }
private string GenerateDtoFieldDefinition(string typeNameForDto, ApiField apiField) { var indent = new Indent(); var builder = new StringBuilder(); var propertyNameForField = apiField.ToCSharpPropertyName(typeNameForDto); var backingFieldNameForField = apiField.ToCSharpBackingFieldName(); // Backing field builder.Append($"{indent}private PropertyValue<"); builder.Append(apiField.Type.ToCSharpType(_codeGenerationContext)); if (apiField.Type.Nullable) { builder.Append("?"); } builder.Append("> "); builder.Append($"{backingFieldNameForField} = new PropertyValue<"); builder.Append(apiField.Type.ToCSharpType(_codeGenerationContext)); if (apiField.Type.Nullable) { builder.Append("?"); } builder.AppendLine($">(nameof({typeNameForDto}), nameof({propertyNameForField}));"); builder.AppendLine($"{indent}"); // Property if (!apiField.Optional && !apiField.Type.Nullable) { builder.AppendLine($"{indent}[Required]"); } if (apiField.Deprecation != null) { builder.AppendLine(apiField.Deprecation.ToCSharpDeprecation()); } builder.AppendLine($"{indent}[JsonPropertyName(\"{apiField.Name}\")]"); if (apiField.Type is ApiFieldType.Primitive apiFieldTypePrimitive) { var csharpType = apiFieldTypePrimitive.ToCSharpPrimitiveType(); if (csharpType.JsonConverter != null) { builder.AppendLine($"{indent}[JsonConverter(typeof({csharpType.JsonConverter.Name}))]"); } } builder.Append($"{indent}public "); builder.Append(apiField.Type.ToCSharpType(_codeGenerationContext)); if (apiField.Type.Nullable) { builder.Append("?"); } builder.Append(" "); builder.AppendLine($"{indent}{propertyNameForField}"); builder.AppendLine($"{indent}{{"); indent.Increment(); builder.AppendLine($"{indent}get => {backingFieldNameForField}.GetValue();"); builder.AppendLine($"{indent}set => {backingFieldNameForField}.SetValue(value);"); indent.Decrement(); builder.AppendLine($"{indent}}}"); return(builder.ToString()); }
/// <inheritdoc /> public async Task <JToken> ResolveQuery( object source, ApiRequest request, ApiField apiField, RequestContext context, JsonSerializer argumentsSerializer, Action <Exception> onErrorCallback) { var arguments = (JObject)request.Arguments; var id = arguments?.Property("id"); var filterArgument = arguments?.Property("filter")?.Value as JObject; var sortArgument = arguments?.Property("sort")?.Value as JArray; var limit = (int?)(arguments?.Property("limit")?.Value as JValue); var offset = (int?)(arguments?.Property("offset")?.Value as JValue); var filter = CreateFilter(filterArgument, id); var sort = sortArgument != null?this.CreateSort(sortArgument) : null; var items = await this.GetQueryResult(source, request, filter, sort, limit, offset); if (items == null) { onErrorCallback?.Invoke(new Exception("Source is not a node connection")); return(JValue.CreateNull()); } SetLog(request, apiField, context, EnConnectionAction.Query); var result = new JObject(); var fields = request.Fields.GroupBy(f => f.Alias ?? f.FieldName).Select( g => { var f = g.First(); if (f.Fields == null) { return(f); } return(new ApiRequest { Alias = f.Alias, Arguments = f.Arguments, FieldName = f.FieldName, Fields = g.SelectMany(sr => sr.Fields).ToList() }); }); foreach (var requestField in fields) { switch (requestField.FieldName) { case "count": result.Add(requestField.Alias ?? requestField.FieldName, new JValue(items.Count)); break; case "items": { var itemsValue = await new SimpleCollectionResolver(this.NodeResolver).ResolveQuery( items.Items, requestField, apiField, context, argumentsSerializer, onErrorCallback); result.Add(requestField.Alias ?? requestField.FieldName, itemsValue); } break; } } return(result); }
/// <inheritdoc /> public Task <JToken> ResolveQuery(object source, ApiRequest request, ApiField apiField, RequestContext context, JsonSerializer argumentsSerializer, Action <Exception> onErrorCallback) { var result = source as JToken; return(Task.FromResult(result ?? JValue.CreateNull())); }
public static string ToCSharpVariableName(this ApiField subject) => CSharpIdentifier.ForVariable(subject.Name);
public static string ToCSharpBackingFieldName(this ApiField subject) => CSharpIdentifier.ForBackingField(subject.Name);
public async Task SchemaDescriptionTest() { var checkAttributeArguments = new[] { ApiField.Scalar( "attribute", EnScalarType.String, description: "attribute to check") }; var objectFields = new[] { ApiField.Scalar( "uid", EnScalarType.Guid, description: "The object unique identifier"), ApiField.Scalar("name", EnScalarType.String, description: "The object name"), ApiField.Scalar( "attributes", EnScalarType.String, EnFieldFlags.IsArray, description: "The object attributes"), ApiField.Scalar( "checkAttribute", EnScalarType.Boolean, arguments: checkAttributeArguments, description: "checks the attribute") }; var objectType = new ApiObjectType("object", objectFields) { Description = "Some abstract object" }; var apiField = objectType.CreateField( "new", description: "The new object data"); var mutations = new[] { ApiMutation.CreateFromField( ApiField.Object( "objects_create", "object", arguments: new[] { apiField }, description: "creates a new object"), ApiMutation.EnType.ConnectionCreate, new List <ApiRequest>()) }; var api = new ApiDescription( "TestApi", "0.0.0.1", new[] { objectType }, new[] { objectType.CreateField("objects", EnFieldFlags.IsConnection, "The objects dataset") }, mutations) { Description = "The test api" }; var provider = new MoqProvider { Description = api }; var schema = SchemaGenerator.Generate(new List <ApiProvider> { provider }); var errors = SchemaGenerator.CheckSchema(schema).Select(e => $"Schema type error: {e}") .Union(SchemaGenerator.CheckSchemaIntrospection(schema)) .Select(e => $"Schema introspection error: {e}"); var hasErrors = false; foreach (var error in errors) { hasErrors = true; this.output.WriteLine(error); } using (var printer = new SchemaPrinter(schema)) { var description = printer.Print(); this.output.WriteLine("-------- Schema -----------"); this.output.WriteLine(description); Assert.False(string.IsNullOrWhiteSpace(description)); } Assert.False(hasErrors); var query = BaseInstaller.ReadTextResource( this.GetType().GetTypeInfo().Assembly, "KlusterKite.Web.Tests.GraphQL.Resources.IntrospectionQuery.txt"); var result = await new DocumentExecuter().ExecuteAsync( r => { r.Schema = schema; r.Query = query; }).ConfigureAwait(true); var response = new DocumentWriter(true).Write(result); this.output.WriteLine(response); var expectedResponse = BaseInstaller.ReadTextResource( this.GetType().GetTypeInfo().Assembly, "KlusterKite.Web.Tests.GraphQL.Resources.SchemaDescriptionTestSnapshot.txt"); Assert.Equal(CleanResponse(expectedResponse), CleanResponse(response)); }
public async Task NonEmptyApiTest() { var viewerType = new ApiObjectType( "viewer", new[] { ApiField.Scalar("id", EnScalarType.Integer), ApiField.Scalar("name", EnScalarType.String) }); var api = new ApiDescription( "TestApi1", "0.0.0.1", new[] { viewerType }, new[] { viewerType.CreateField("viewer") }); var provider = new MoqProvider { Description = api, Data = "{\"viewer\": {\"__id\": 1, \"name\": \"test name\"}}" }; var schema = SchemaGenerator.Generate(new List <ApiProvider> { provider }); using (var printer = new SchemaPrinter(schema)) { var description = printer.Print(); this.output.WriteLine("-------- Schema -----------"); this.output.WriteLine(description); Assert.False(string.IsNullOrWhiteSpace(description)); } Assert.NotNull(schema.Query); Assert.Equal(3, schema.Query.Fields.Count()); Assert.True(schema.Query.HasField("api")); var result = await new DocumentExecuter().ExecuteAsync( r => { r.Schema = schema; r.Query = @" query { api { viewer { __id, name } } } "; }).ConfigureAwait(true); this.output.WriteLine("-------- Response -----------"); var response = new DocumentWriter(true).Write(result); this.output.WriteLine(response); var expectedResponse = @"{ ""data"": { ""api"": { ""viewer"": { ""__id"": 1, ""name"": ""test name"" } } } }"; Assert.Equal(CleanResponse(expectedResponse), CleanResponse(response)); }
/// <inheritdoc /> public Task <JToken> ResolveQuery(object source, ApiRequest request, ApiField apiField, RequestContext context, JsonSerializer argumentsSerializer, Action <Exception> onErrorCallback) { var value = hasFlags ? new JValue((long)source) : new JValue(source.ToString()); return(Task.FromResult <JToken>(value)); }
/// <summary> /// Creates field from api description /// </summary> /// <param name="provider">The api provider</param> /// <param name="apiField">The api field description</param> /// <param name="complexField">The same field merged from previous api descriptions</param> /// <param name="path">The list of processed types</param> /// <param name="createAsInput">A value indicating that an input type is assembled</param> /// <param name="typesCreated">The list of already created types</param> /// <returns>The field description</returns> private static MergedType CreateMergedType( ApiProvider provider, ApiField apiField, MergedField complexField, ICollection <string> path, bool createAsInput, Dictionary <string, MergedType> typesCreated) { MergedType createdType; if (apiField.ScalarType != EnScalarType.None) { return(CreateScalarType(apiField.ScalarType, typesCreated)); } var apiType = provider.Description.Types.FirstOrDefault(t => t.TypeName == apiField.TypeName); if (apiType == null) { throw new Exception("type was not found"); } var apiEnumType = apiType as ApiEnumType; if (apiEnumType != null) { return(CreateEnumType(apiEnumType, provider, typesCreated)); } var apiObjectType = (ApiObjectType)apiType; if (apiField.Flags.HasFlag(EnFieldFlags.IsConnection)) { var typedArgumentNames = apiField.Arguments.Where(a => a.Flags.HasFlag(EnFieldFlags.IsTypeArgument)) .Select(f => f.Name) .ToList(); return(CreateConnectionType(apiObjectType, provider, typesCreated, typedArgumentNames)); } var objectType = (complexField?.Type as MergedObjectType)?.Clone() ?? (createAsInput ? new MergedInputType($"{provider.Description.ApiName}_{apiField.TypeName}") : new MergedObjectType($"{provider.Description.ApiName}_{apiField.TypeName}")); objectType.AddProvider(new FieldProvider { FieldType = apiObjectType, Provider = provider }); if (complexField != null) { objectType.Category = MergedObjectType.EnCategory.MultipleApiType; } if (typesCreated.TryGetValue(objectType.ComplexTypeName, out createdType)) { return(createdType); } typesCreated[objectType.ComplexTypeName] = objectType; MergeFields( objectType, apiObjectType.Fields, provider, path.Union(new[] { apiObjectType.TypeName }).ToList(), createAsInput, typesCreated); objectType.Initialize(); return(objectType); }
private async void AddItemCommandHandler(object p) { // Prompt to create the new item var dialog = new AddItemDialog(); // Show the dialog and wait for a response var result = await dialog.ShowAsync(); if (result == ContentDialogResult.Primary) { try { // Get the category var category = p as ApiCategory; // Create an item var item = new ApiItem() { Name = dialog.ItemName }; // Save the item to the api var r = await KryptPadApi.SaveItemAsync(category.Id, item); // Set the item item.Id = r.Id; // If a template was selected, create a couple of fields to start with if (dialog.SelectedItemTemplate != null) { var templateFields = dialog.SelectedItemTemplate.Fields; // A template was selected, add all the fields from the template foreach (var templateField in templateFields) { // Create field var field = new ApiField() { Name = templateField.Name, FieldType = templateField.FieldType }; // Send to api await KryptPadApi.SaveFieldAsync(category.Id, item.Id, field); } } // Navigate to item edit page NavigationHelper.Navigate(typeof(NewItemPage), new EditItemPageParams() { Category = category, Item = item }); } catch (WebException ex) { // Something went wrong in the api await DialogHelper.ShowMessageDialogAsync(ex.Message); } catch (Exception ex) { // Failed await DialogHelper.ShowGenericErrorDialogAsync(ex); } } }
private string GenerateDtoFieldDefinition(string typeNameForDto, ApiField apiField) { var indent = new Indent(); var builder = new StringBuilder(); var propertyNameForField = apiField.ToCSharpPropertyName(typeNameForDto); var backingFieldNameForField = apiField.ToCSharpBackingFieldName(); // Backing field builder.Append($"{indent}private PropertyValue<"); builder.Append(apiField.Type.ToCSharpType(_codeGenerationContext)); if (apiField.Type.Nullable) { builder.Append("?"); } builder.Append("> "); builder.Append($"{backingFieldNameForField} = new PropertyValue<"); builder.Append(apiField.Type.ToCSharpType(_codeGenerationContext)); if (apiField.Type.Nullable) { builder.Append("?"); } // For non-nullable List<> and Dictionary<>, make sure the field is initialized. // We do this by setting a temporary default value for this pass. var overrideDefaultValue = !apiField.Type.Nullable && apiField.DefaultValue == null; if (overrideDefaultValue) { // TODO When switching to records (.NET 6 LTS), replace this construct to be immutable. apiField.DefaultValue = apiField.Type switch { ApiFieldType.Array _ => new ApiDefaultValue.Collection(), ApiFieldType.Map _ => new ApiDefaultValue.Map(), _ => apiField.DefaultValue }; } var initialValueForAssignment = apiField.ToCSharpDefaultValueForAssignment(_codeGenerationContext); if (initialValueForAssignment != null) { builder.AppendLine($">(nameof({typeNameForDto}), nameof({propertyNameForField}), {initialValueForAssignment});"); } else { builder.AppendLine($">(nameof({typeNameForDto}), nameof({propertyNameForField}));"); } builder.AppendLine($"{indent}"); // Restore null default value if (overrideDefaultValue) { apiField.DefaultValue = null; } // Property if (!apiField.Optional && !apiField.Type.Nullable) { builder.AppendLine($"{indent}[Required]"); } if (apiField.Deprecation != null) { builder.AppendLine(apiField.Deprecation.ToCSharpDeprecation()); } builder.AppendLine($"{indent}[JsonPropertyName(\"{apiField.Name}\")]"); if (apiField.Type is ApiFieldType.Primitive apiFieldTypePrimitive) { var csharpType = apiFieldTypePrimitive.ToCSharpPrimitiveType(); if (csharpType.JsonConverter != null) { builder.AppendLine($"{indent}[JsonConverter(typeof({csharpType.JsonConverter.Name}))]"); } } builder.Append($"{indent}public "); builder.Append(apiField.Type.ToCSharpType(_codeGenerationContext)); if (apiField.Type.Nullable) { builder.Append("?"); } builder.Append(" "); builder.AppendLine($"{indent}{propertyNameForField}"); builder.AppendLine($"{indent}{{"); indent.Increment(); builder.AppendLine($"{indent}get => {backingFieldNameForField}.GetValue();"); builder.AppendLine($"{indent}set => {backingFieldNameForField}.SetValue(value);"); indent.Decrement(); builder.AppendLine($"{indent}}}"); return(builder.ToString()); }