private static EdmModel BuildEdmModel(Schema schema, PartitionResolver partitionResolver) { var model = new EdmModel(); var container = new EdmEntityContainer("Squidex", "Container"); var schemaType = schema.BuildEdmType(partitionResolver, x => { model.AddElement(x); return(x); }); var entityType = new EdmEntityType("Squidex", schema.Name); entityType.AddStructuralProperty("data", new EdmComplexTypeReference(schemaType, false)); entityType.AddStructuralProperty("version", EdmPrimitiveTypeKind.Int32); entityType.AddStructuralProperty("created", EdmPrimitiveTypeKind.DateTimeOffset); entityType.AddStructuralProperty("createdBy", EdmPrimitiveTypeKind.String); entityType.AddStructuralProperty("lastModified", EdmPrimitiveTypeKind.DateTimeOffset); entityType.AddStructuralProperty("lastModifiedBy", EdmPrimitiveTypeKind.String); model.AddElement(container); model.AddElement(schemaType); model.AddElement(entityType); container.AddEntitySet("ContentSet", entityType); return(model); }
private void AddData(Schema schema, PartitionResolver partitionResolver) { foreach (var field in schema.Fields.Where(x => x.IsForApi(true))) { var description = $"The values of the '{field.DisplayName()}' field."; AddObject(field.Name, $"The values of the '{field.DisplayName()}' field.", () => { foreach (var partition in partitionResolver(field.Partitioning).AllKeys) { var description = $"The '{partition}' value of the '{field.DisplayName()}' field."; if (field is ArrayField arrayField) { AddObject(partition, description, () => { foreach (var nestedField in arrayField.Fields.Where(x => x.IsForApi(true))) { var description = $"The value of the '{nestedField.DisplayName()}' nested field."; AddAny(field.Name, description); } }); } else { AddAny(partition, description); } } }); } }
public static JsonSchema4 BuildJsonSchema(this Schema schema, PartitionResolver partitionResolver, Func <string, JsonSchema4, JsonSchema4> schemaResolver) { Guard.NotNull(schemaResolver, nameof(schemaResolver)); Guard.NotNull(partitionResolver, nameof(partitionResolver)); var schemaName = schema.Name.ToPascalCase(); var jsonTypeVisitor = new JsonTypeVisitor(schemaResolver); var jsonSchema = new JsonSchema4 { Type = JsonObjectType.Object }; foreach (var field in schema.Fields.Where(x => !x.IsHidden)) { var partitionProperty = CreateProperty(field); var partitionObject = new JsonSchema4 { Type = JsonObjectType.Object, AllowAdditionalProperties = false }; var partition = partitionResolver(field.Partitioning); foreach (var partitionItem in partition) { var partitionItemProperty = field.Visit(jsonTypeVisitor); partitionItemProperty.Description = partitionItem.Name; partitionObject.Properties.Add(partitionItem.Key, partitionItemProperty); } partitionProperty.Reference = schemaResolver($"{schemaName}{field.Name.ToPascalCase()}Property", partitionObject); jsonSchema.Properties.Add(field.Name, partitionProperty); } return(jsonSchema); }
public void AddToJsonSchema(JsonSchema4 schema, PartitionResolver partitionResolver, string schemaName, Func <string, JsonSchema4, JsonSchema4> schemaResolver) { Guard.NotNull(schema, nameof(schema)); Guard.NotNull(schemaResolver, nameof(schemaResolver)); Guard.NotNull(partitionResolver, nameof(partitionResolver)); var partitionProperty = CreateProperty(); var partitionObject = new JsonSchema4 { Type = JsonObjectType.Object, AllowAdditionalProperties = false }; var partition = partitionResolver(partitioning); foreach (var partitionItem in partition) { var partitionItemProperty = new JsonProperty { Description = partitionItem.Name, IsRequired = RawProperties.IsRequired }; PrepareJsonSchema(partitionItemProperty, schemaResolver); partitionObject.Properties.Add(partitionItem.Key, partitionItemProperty); } partitionProperty.Reference = schemaResolver($"{schemaName}{Name.ToPascalCase()}Property", partitionObject); schema.Properties.Add(Name, partitionProperty); }
public static EdmComplexType BuildEdmType(this Schema schema, PartitionResolver partitionResolver, Func <EdmComplexType, EdmComplexType> typeResolver) { Guard.NotNull(typeResolver, nameof(typeResolver)); Guard.NotNull(partitionResolver, nameof(partitionResolver)); var schemaName = schema.Name.ToPascalCase(); var edmType = new EdmComplexType("Squidex", schemaName); foreach (var field in schema.FieldsByName.Values.Where(x => !x.IsHidden)) { var edmValueType = EdmTypeVisitor.CreateEdmType(field); if (edmValueType == null) { continue; } var partitionType = typeResolver(new EdmComplexType("Squidex", $"{schemaName}{field.Name.ToPascalCase()}Property")); var partition = partitionResolver(field.Partitioning); foreach (var partitionItem in partition) { partitionType.AddStructuralProperty(partitionItem.Key, edmValueType); } edmType.AddStructuralProperty(field.Name.EscapeEdmField(), new EdmComplexTypeReference(partitionType, false)); } return(edmType); }
public GraphQLModel(IAppEntity app, IEnumerable <ISchemaEntity> schemas, int pageSizeContents, int pageSizeAssets, IUrlGenerator urlGenerator, ISemanticLog log) { this.log = log; partitionResolver = app.PartitionResolver(); CanGenerateAssetSourceUrl = urlGenerator.CanGenerateAssetSourceUrl; assetType = new AssetGraphType(this); assetListType = new ListGraphType(new NonNullGraphType(assetType)); graphQLTypeVisitor = new GraphQLTypeVisitor(contentTypes, this, assetListType); var allSchemas = schemas.Where(x => x.SchemaDef.IsPublished).ToList(); BuildSchemas(allSchemas); graphQLSchema = BuildSchema(this, pageSizeContents, pageSizeAssets, allSchemas); graphQLSchema.RegisterValueConverter(JsonConverter.Instance); graphQLSchema.RegisterValueConverter(InstantConverter.Instance); InitializeContentTypes(allSchemas, pageSizeContents); }
public Builder(IAppEntity app) { partitionResolver = app.PartitionResolver(); fieldVisitor = new FieldVisitor(this); fieldInputVisitor = new FieldInputVisitor(this); }
public static JsonSchema BuildJsonSchemaFlat(this Schema schema, PartitionResolver partitionResolver, ResolvedComponents components, JsonTypeFactory?factory = null, bool withHidden = false, bool withComponents = false) { Guard.NotNull(partitionResolver); Guard.NotNull(components); factory ??= DefaultFactory; var jsonSchema = JsonTypeBuilder.Object(); foreach (var field in schema.Fields.ForApi(withHidden)) { var property = JsonTypeVisitor.BuildProperty( field, components, schema, factory, withHidden, withComponents); // Property is null for UI fields. if (property != null) { property.SetRequired(false); property.SetDescription(field); jsonSchema.Properties.Add(field.Name, property); } } return(jsonSchema); }
public static JsonSchema BuildJsonSchema(this Schema schema, PartitionResolver partitionResolver, ResolvedComponents components, JsonTypeFactory?factory = null, bool withHidden = false, bool withComponents = false) { Guard.NotNull(partitionResolver); Guard.NotNull(components); factory ??= DefaultFactory; var jsonSchema = JsonTypeBuilder.Object(); foreach (var field in schema.Fields.ForApi(withHidden)) { var typeName = $"{schema.TypeName()}{field.Name.ToPascalCase()}PropertyDto"; // Create a reference to give it a nice name in code generation. var(reference, actual) = factory(typeName); if (actual != null) { var partitioning = partitionResolver(field.Partitioning); foreach (var partitionKey in partitioning.AllKeys) { var property = JsonTypeVisitor.BuildProperty( field, components, schema, factory, withHidden, withComponents); // Property is null for UI fields. if (property != null) { var isOptional = partitioning.IsOptional(partitionKey); var name = partitioning.GetName(partitionKey); // Required if property is required and language/partitioning is not optional. property.SetRequired(field.RawProperties.IsRequired && !isOptional); property.SetDescription(name); actual.Properties.Add(partitionKey, property); } } } var propertyReference = JsonTypeBuilder.ReferenceProperty(reference) .SetDescription(field) .SetRequired(field.RawProperties.IsRequired); jsonSchema.Properties.Add(field.Name, propertyReference); } return(jsonSchema); }
public static ContentData Enrich(this ContentData data, Schema schema, PartitionResolver partitionResolver) { var enricher = new ContentEnricher(schema, partitionResolver); enricher.Enrich(data); return(data); }
public ContentValidator(Schema schema, PartitionResolver partitionResolver, ValidationContext context) { Guard.NotNull(schema, nameof(schema)); Guard.NotNull(partitionResolver, nameof(partitionResolver)); this.schema = schema; this.context = context; this.partitionResolver = partitionResolver; }
public Builder(IAppEntity app, SharedTypes sharedTypes) { this.sharedTypes = sharedTypes; partitionResolver = app.PartitionResolver(); fieldVisitor = new FieldVisitor(this); fieldInputVisitor = new FieldInputVisitor(this); }
public ContentEnricher(Schema schema, PartitionResolver partitionResolver) { Guard.NotNull(schema, nameof(schema)); Guard.NotNull(partitionResolver, nameof(partitionResolver)); this.schema = schema; this.partitionResolver = partitionResolver; }
public DefaultValueGenerator(Schema schema, PartitionResolver partitionResolver) { Guard.NotNull(schema, nameof(schema)); Guard.NotNull(partitionResolver, nameof(partitionResolver)); this.schema = schema; this.partitionResolver = partitionResolver; }
public ContentValidator(PartitionResolver partitionResolver, ValidationContext context, IEnumerable <IValidatorsFactory> factories) { Guard.NotNull(context, nameof(context)); Guard.NotNull(factories, nameof(factories)); Guard.NotNull(partitionResolver, nameof(partitionResolver)); this.context = context; this.factories = factories; this.partitionResolver = partitionResolver; }
public async Task RoundRobinDistributesFairlyWhenCalledConcurrently(string[] partitions) { var concurrentCount = 4; var assignmentsPerPartition = 20; var iterationCount = partitions.Length * assignmentsPerPartition; var resolver = new PartitionResolver(); var assigned = new List <string>(); var activeTasks = new List <Task>(); // Create a function that assigns partitions in a loop and track them. Task roundRobin() { for (var index = 0; index < iterationCount; index++) { assigned.Add(resolver.AssignRoundRobin(partitions)); } return(Task.CompletedTask); } // Run assignment concurrently. for (var concurrentIndex = 0; concurrentIndex < concurrentCount; ++concurrentIndex) { activeTasks.Add(roundRobin()); } await Task.WhenAll(activeTasks); // When grouped, the count of each partition should equal the iteration count for each // concurrent invocation. var partitionAssignments = assigned .GroupBy(item => item) .Select(group => new { Key = group.Key, Count = group.Count() }); var assignmentHash = new HashSet <string>(); var expectedAssignmentCount = (concurrentCount * assignmentsPerPartition); // Verify that each assignment is for a valid partition and has the expected distribution. foreach (var partitionAssignment in partitionAssignments) { Assert.That(partitionAssignment.Count, Is.EqualTo(expectedAssignmentCount), $"The count for key: [{ partitionAssignment.Key}] should match the total number of iterations."); assignmentHash.Add(partitionAssignment.Key); } // Verify that all partitions were assigned. foreach (var partition in partitions) { Assert.That(assignmentHash.Contains(partition), Is.True, $"Partition: [{ partition }] should have had assignments."); } }
public void PartitionResolverResolvePartitionTest() { PartitionResolver pr = new PartitionResolver(); AspSessionPersistence persist = new AspSessionPersistence(); string cnx_str = pr.ResolvePartition(persist.GenerateSessionId()); bool isAssertOk = cnx_str.Contains("Initial Catalog="); Assert.AreEqual(isAssertOk, true); isAssertOk = cnx_str.Contains("Data Source="); Assert.AreEqual(isAssertOk, true); }
public static async Task ValidateAsync(this ContentData data, Schema schema, PartitionResolver partitionResolver, IList <ValidationError> errors) { var validator = new ContentValidator(schema, partitionResolver); await validator.ValidateAsync(data); foreach (var error in validator.Errors) { errors.Add(error); } }
public void DeleteSessionTest() { PartitionResolver pr = new PartitionResolver(); AspSessionPersistence persist = new AspSessionPersistence(); var sessionid = persist.GenerateSessionId(); persist.DeleteSession(sessionid); var sessionSaved = persist.LoadSession(sessionid); Assert.IsNull(sessionSaved, null); }
public static FilterSchema BuildDataSchema(this Schema schema, PartitionResolver partitionResolver, ResolvedComponents components) { Guard.NotNull(partitionResolver); Guard.NotNull(components); var fields = new List <FilterField>(); var schemaName = schema.DisplayName(); foreach (var field in schema.Fields.ForApi(true)) { var fieldSchema = FilterVisitor.BuildProperty(field, components); if (fieldSchema == null) { continue; } var partitioning = partitionResolver(field.Partitioning); var partitionFields = new List <FilterField>(); foreach (var partitionKey in partitioning.AllKeys) { var partitionDescription = FieldPartitionDescription(field, partitioning.GetName(partitionKey) ?? partitionKey); var partitionField = new FilterField( fieldSchema, partitionKey, partitionDescription, true); partitionFields.Add(partitionField); } var filterable = new FilterField( new FilterSchema(FilterSchemaType.Object) { Fields = partitionFields.ToReadonlyList() }, field.Name, FieldDescription(schemaName, field)); fields.Add(filterable); } var dataSchema = new FilterSchema(FilterSchemaType.Object) { Fields = fields.ToReadonlyList() }; return(dataSchema); }
public void PartitionKeyAssignmentIsStable(string[] partitions) { var iterationCount = 25; var key = "this-is-a-key-1"; var resolver = new PartitionResolver(); var expected = resolver.AssignForPartitionKey(key, partitions); for (var index = 0; index < iterationCount; ++index) { Assert.That(resolver.AssignForPartitionKey(key, partitions), Is.EqualTo(expected), $"The assignment for iteration: [{ index }] was unstable."); } }
public void RoundRobinDistributesFairly(string[] partitions) { var resolver = new PartitionResolver(); for (var index = 0; index < 100; index++) { var expected = partitions[index % partitions.Length]; var assigned = resolver.AssignRoundRobin(partitions); Assert.That(assigned, Is.EqualTo(expected), $"The assignment was unexpected for index: [{ index }]."); } }
internal Builder(IAppEntity app, OpenApiDocument document, OpenApiSchemaResolver schemaResolver, OpenApiSchemaGenerator schemaGenerator) { this.partitionResolver = app.PartitionResolver(); Document = document; AppName = app.Name; ChangeStatusSchema = schemaGenerator.GenerateWithReference <JsonSchema>(typeof(ChangeStatusDto).ToContextualType(), schemaResolver); }
public async Task <IEnumerable <ShortEntityId> > QueryObservablesAsync(GatewayRequest request) { try { // Validates parameter if (string.IsNullOrWhiteSpace(request?.Topic)) { throw new ArgumentException($"Parameter {nameof(request)} is null or invalid.", nameof(request)); } // Gets service proxy IRegistryService proxy = GetServiceProxy( PartitionResolver.Resolve(request.Topic, OwinCommunicationListener.RegistryServicePartitionCount), OwinCommunicationListener.RegistryServiceUri); if (proxy == null) { throw new ApplicationException("The ServiceProxy cannot be null."); } // Invokes actor using proxy ServiceEventSource.Current.Message($"Retrieving observables...\r\n[Publication]: Topic=[{request.Topic}]"); IEnumerable <EntityId> entityIds = await proxy.QueryObservablesAsync( request.Topic, (request.FilterExpressions != null) && request.FilterExpressions.Any() ?request.FilterExpressions.First() : null); if ((entityIds == null) || !entityIds.Any()) { return(null); } return(entityIds.Select(e => new ShortEntityId(e))); } catch (AggregateException ex) { if (!(ex.InnerExceptions?.Count > 0)) { throw new HttpResponseException(this.Request.CreateErrorResponse(HttpStatusCode.NotFound, ex.Message)); } foreach (Exception exception in ex.InnerExceptions) { ServiceEventSource.Current.Message(exception.Message); } throw new HttpResponseException(this.Request.CreateErrorResponse(HttpStatusCode.NotFound, ex.Message)); } catch (Exception ex) { ServiceEventSource.Current.Message(ex.Message); throw new HttpResponseException(this.Request.CreateErrorResponse(HttpStatusCode.NotFound, ex.Message)); } }
public static async Task ValidateAsync(this NamedContentData data, PartitionResolver partitionResolver, IList <ValidationError> errors, Schema?schema = null, ValidationMode mode = ValidationMode.Default, Func <ValidationContext, ValidationContext>?updater = null) { var context = CreateContext(schema, mode, updater); var validator = new ContentValidator(partitionResolver, context, Enumerable.Repeat(Factory, 1)); await validator.ValidateInputAsync(data); foreach (var error in validator.Errors) { errors.Add(error); } }
public void RefreshSessionTest() { PartitionResolver pr = new PartitionResolver(); AspSessionPersistence persist = new AspSessionPersistence(); AspSessionContents st = new AspSessionContents(); this.CreateSessionState(st); var sessionid = persist.GenerateSessionId(); persist.SaveSession(sessionid, st, 20); persist.RefreshSession(sessionid); var sessionSaved = persist.LoadSession(sessionid); Assert.IsNotNull(sessionSaved); }
public GraphQLModel(IAppEntity app, IEnumerable <ISchemaEntity> schemas, IGraphQLUrlGenerator urlGenerator) { this.app = app; partitionResolver = app.PartitionResolver(); CanGenerateAssetSourceUrl = urlGenerator.CanGenerateAssetSourceUrl; assetType = new AssetGraphType(this); schemasById = schemas.ToDictionary(x => x.Id); schemaTypes = new QueryGraphTypeVisitor(GetContentType, new ListGraphType(new NonNullGraphType(assetType))); graphQLSchema = BuildSchema(this); InitializeContentTypes(); }
public EdmComplexType BuildEdmType(PartitionResolver partitionResolver, Func <EdmComplexType, EdmComplexType> typeResolver) { Guard.NotNull(typeResolver, nameof(typeResolver)); Guard.NotNull(partitionResolver, nameof(partitionResolver)); var schemaName = Name.ToPascalCase(); var edmType = new EdmComplexType("Squidex", schemaName); foreach (var field in fieldsByName.Values.Where(x => !x.IsHidden)) { field.AddToEdmType(edmType, partitionResolver, schemaName, typeResolver); } return(edmType); }
public OperationsBuilder Schema(Schema schema, PartitionResolver partitionResolver, ResolvedComponents components, bool flat) { var typeName = schema.TypeName(); var dataSchema = RegisterReference($"{typeName}DataDto", _ => { return(schema.BuildJsonSchemaDynamic(partitionResolver, components, CreateReference, false, true)); }); var contentDataSchema = dataSchema; if (flat) { contentDataSchema = RegisterReference($"{typeName}FlatDataDto", _ => { return(schema.BuildJsonSchemaFlat(partitionResolver, components, CreateReference, false, true)); }); } var contentSchema = RegisterReference($"{typeName}ContentDto", _ => { return(ContentJsonSchema.Build(contentDataSchema, true)); }); var contentsSchema = RegisterReference($"{typeName}ContentResultDto", _ => { return(BuildResult(contentSchema)); }); var path = $"api/content/{AppName}/{schema.Name}"; var builder = new OperationsBuilder { ContentSchema = contentSchema, ContentsSchema = contentsSchema, DataSchema = dataSchema, Path = path, Parent = this, SchemaDisplayName = schema.DisplayName(), SchemaName = schema.Name, SchemaTypeName = typeName }; builder.AddTag("API endpoints for [schema] content items."); return(builder); }
public void SaveSessionTest() { PartitionResolver pr = new PartitionResolver(); AspSessionPersistence persist = new AspSessionPersistence(); AspSessionContents st = new AspSessionContents(); this.CreateSessionState(st); var sessionid = persist.GenerateSessionId(); persist.SaveSession(sessionid, st, 20); var sessionSaved = persist.LoadSession(sessionid); foreach (var item in sessionSaved) { Assert.AreEqual(item.Value, st[item.Key]); } }