private static PropertyValidator CreateSinglePropertyValidator(JsonValue schema, CustomTypeDefinitionProvider provider) { switch (schema) { case JsonValue.String typeName: var type = typeName.Item; var validator = fun((Func <JsonValue, bool> fn) => new PropertyValidator(x => fn(x) ? Valid : Error($"value is not a {type}"))); switch (type) { case "number": return(validator(x => x.IsNumber)); case "date": return(validator(x => DateTime.TryParse(x.AsString(), out var _))); case "string": return(validator(x => x.IsString)); case "boolean": return(validator(x => x.IsBoolean)); case "array": return(validator(x => x.IsArray)); case "object": return(validator(x => x.IsRecord)); default: return(provider(type) .Map(customType => CreateCustomTypeValidator(customType)) .IfNone(() => (JsonValue value) => Error($"custom type \"{type}\" not exists"))); } case JsonValue.Record customTypeRaw: return(customTypeRaw.GetPropertyOption("name").Bind(x => customTypeRaw.GetPropertyOption("ofType")).Match(arrayType => { var arrayValidator = CreateSinglePropertyValidator(arrayType, provider); return (x => x.AsArray().Map(i => arrayValidator(i)).Reduce((a, b) => a | b)); }, () => CreateCustomTypeValidator(CustomTypeDefinition.FromJsonValue(customTypeRaw)))); default: return((JsonValue _) => Error("unknown type definition")); } }
private static PropertyValidator CreateCustomTypeValidator(CustomTypeDefinition typeDefinition) { var validators = Enumerable.Empty <Func <JsonValue, ValidationResult> >(); if (typeDefinition.AllowedValues.Any()) { validators = validators.Append((JsonValue property) => typeDefinition.AllowedValues.Any(v => (v.IsString && property.IsString && v.AsString().ToLower() == property.AsString().ToLower()) || v.Equals(property)) ? Valid : Error($"value {property.ToString()} not in the allowed values")); } var regexValidation = Optional(typeDefinition.Validation) .Map(validation => fun((JsonValue property) => { var match = validation.IsMatch(property.AsString()); return(match ? Valid : Error($"value {property.ToString()} does not match regex")); })); validators = validators.Append(regexValidation); return(property => validators.Aggregate(Valid, (acc, validator) => acc | validator(property))); }
private SchemaValidation.Provider CreateSchemaProvider(ITweek tweek, IRulesRepository rulesProvider, SchemaValidation.Mode mode) { var logger = loggerFactory.CreateLogger("SchemaValidation.Provider"); SchemaValidation.Provider CreateValidationProvider() { logger.LogInformation("updateing schema"); var schemaIdenetities = tweek.Calculate(new[] { new ConfigurationPath($"@tweek/schema/_") }, EmptyIdentitySet, i => ContextHelpers.EmptyContext).ToDictionary(x => x.Key.Name, x => x.Value.Value); var customTypes = tweek.Calculate(new[] { new ConfigurationPath($"@tweek/custom_types/_") }, EmptyIdentitySet, i => ContextHelpers.EmptyContext).ToDictionary(x => x.Key.Name, x => CustomTypeDefinition.FromJsonValue(x.Value.Value)); return(SchemaValidation.Create(schemaIdenetities, customTypes, mode)); } var validationProvider = CreateValidationProvider(); rulesProvider.OnRulesChange += (_) => { validationProvider = CreateValidationProvider(); }; return((p) => validationProvider(p)); }