unique validator
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
using Raven.Client.Documents.Session;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using zero.Core.Api;
|
||||
using zero.Core.Entities;
|
||||
|
||||
namespace zero.Core.Extensions
|
||||
{
|
||||
public static class RavenAsyncDocumentQueryExtensions
|
||||
{
|
||||
static Type _appAwareEntity = typeof(IAppAwareEntity);
|
||||
|
||||
public static IAsyncDocumentQuery<T> Scope<T>(this IAsyncDocumentQuery<T> source, string appId, bool includeShared = true)
|
||||
{
|
||||
if (appId.IsNullOrEmpty() || !_appAwareEntity.IsAssignableFrom(typeof(T)))
|
||||
{
|
||||
return source;
|
||||
}
|
||||
|
||||
HashSet<string> ids = new HashSet<string>();
|
||||
ids.Add(appId);
|
||||
|
||||
if (includeShared)
|
||||
{
|
||||
ids.Add(Constants.Database.SharedAppId);
|
||||
}
|
||||
|
||||
return source.WhereIn(nameof(IAppAwareEntity.AppId), ids);
|
||||
}
|
||||
|
||||
|
||||
public static IAsyncDocumentQuery<T> Scope<T>(this IAsyncDocumentQuery<T> source, ApiScope scope)
|
||||
{
|
||||
if (scope == null || scope.IsShared)
|
||||
{
|
||||
return source;
|
||||
}
|
||||
|
||||
if (scope.AppId.IsNullOrEmpty() || !_appAwareEntity.IsAssignableFrom(typeof(T)))
|
||||
{
|
||||
return source;
|
||||
}
|
||||
|
||||
HashSet<string> ids = new HashSet<string>();
|
||||
ids.Add(scope.AppId);
|
||||
|
||||
if (scope.IncludeShared)
|
||||
{
|
||||
ids.Add(Constants.Database.SharedAppId);
|
||||
}
|
||||
|
||||
return source.WhereIn(nameof(IAppAwareEntity.AppId), ids);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,6 +89,15 @@ namespace zero.Core.Extensions
|
||||
return input;
|
||||
}
|
||||
|
||||
public static string ToPascalCase(this string input)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(input) && input.Length > 1)
|
||||
{
|
||||
return Char.ToUpperInvariant(input[0]) + input.Substring(1);
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
public static string ToCamelCaseId(this string input)
|
||||
{
|
||||
if (String.IsNullOrEmpty(input))
|
||||
@@ -105,5 +114,23 @@ namespace zero.Core.Extensions
|
||||
|
||||
return String.Join(".", parts.Select(x => x.ToCamelCase()));
|
||||
}
|
||||
|
||||
|
||||
public static string ToPascalCaseId(this string input)
|
||||
{
|
||||
if (String.IsNullOrEmpty(input))
|
||||
{
|
||||
return input;
|
||||
}
|
||||
|
||||
if (input.Length < 2)
|
||||
{
|
||||
return input.ToUpperInvariant();
|
||||
}
|
||||
|
||||
string[] parts = input.Split('.');
|
||||
|
||||
return String.Join(".", parts.Select(x => x.ToPascalCase()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,19 +100,21 @@ namespace zero.Core.Extensions
|
||||
/// <summary>
|
||||
/// Check if this value is unique within a collection
|
||||
/// </summary>
|
||||
public static IRuleBuilderOptions<T, object> Unique<T>(this IRuleBuilder<T, object> ruleBuilder, IBackofficeStore store, bool includeShared = true) where T : IZeroIdEntity
|
||||
public static IRuleBuilderOptions<T, object> Unique<T>(this IRuleBuilder<T, object> ruleBuilder, IBackofficeStore store) where T : IZeroIdEntity
|
||||
{
|
||||
return ruleBuilder.MustAsync(async (entity, value, context, cancellation) =>
|
||||
{
|
||||
bool includeShared = typeof(IAppAwareShareableEntity).IsAssignableFrom(typeof(T));
|
||||
|
||||
using IAsyncDocumentSession session = store.Raven.OpenAsyncSession();
|
||||
|
||||
int count = await session.Advanced.AsyncDocumentQuery<T>()
|
||||
.WhereNotEquals("Id", ((T)entity).Id, true)
|
||||
.WhereEquals(context.Rule.PropertyName, value, true)
|
||||
.CountAsync();
|
||||
bool any = await session.Advanced.AsyncDocumentQuery<T>()
|
||||
.Scope(store.AppContext.AppId, includeShared)
|
||||
.WhereNotEquals(nameof(IZeroIdEntity.Id), entity.Id)
|
||||
.WhereEquals(context.Rule.PropertyName.ToPascalCaseId(), value)
|
||||
.AnyAsync(cancellation);
|
||||
|
||||
return count < 1;
|
||||
//.Scope(store.AppContext.AppId, includeShared)
|
||||
return !any;
|
||||
}).WithMessage("@errors.forms.not_unique");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,30 +2,14 @@
|
||||
using zero.Core.Api;
|
||||
using zero.Core.Entities;
|
||||
using zero.Core.Extensions;
|
||||
using Raven.Client.Documents.Session;
|
||||
using Raven.Client.Documents;
|
||||
|
||||
namespace zero.Core.Validation
|
||||
{
|
||||
public class CountryValidator : ZeroValidator<ICountry, Country>
|
||||
{
|
||||
public CountryValidator(IBackofficeStore store) : base(store)
|
||||
public CountryValidator(IBackofficeStore store)
|
||||
{
|
||||
RuleFor(x => x.Code).Length(2);
|
||||
|
||||
RuleFor(x => x.Code).Unique(store);
|
||||
|
||||
//RuleFor(x => x.Code).Query<ICountry, Country>(store, async (query, entity) =>
|
||||
//{
|
||||
// return !(await query.Scope(store.AppContext.AppId, true).AnyAsync(x => x.Id != entity.Id && x.Code == value));
|
||||
//});
|
||||
|
||||
//RuleFor(x => x.Code).MustAsync(async (entity, value, ct) =>
|
||||
//{
|
||||
// using IAsyncDocumentSession session = Raven.OpenAsyncSession();
|
||||
// return !(await session.Query<ICountry>().Scope(store.AppContext.AppId, true).AnyAsync(x => x.Id != entity.Id && x.Code == value));
|
||||
//});
|
||||
|
||||
RuleFor(x => x.Code).Length(2).Unique(store);
|
||||
RuleFor(x => x.Name).Length(2, 120);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
using FluentValidation.Validators;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace zero.Core.Validation
|
||||
{
|
||||
public class UniqueValidator : PropertyValidator
|
||||
{
|
||||
public UniqueValidator() : base("@errors.forms.not_unique")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override bool IsValid(PropertyValidatorContext context)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,17 +10,6 @@ namespace zero.Core.Validation
|
||||
{
|
||||
public abstract class ZeroValidator<TInterface, TImplementation> : AbstractValidator<TImplementation>, IValidator<TInterface> where TImplementation : TInterface
|
||||
{
|
||||
protected IBackofficeStore Store { get; private set; }
|
||||
|
||||
protected IDocumentStore Raven { get; private set; }
|
||||
|
||||
|
||||
public ZeroValidator(IBackofficeStore store)
|
||||
{
|
||||
Store = store;
|
||||
Raven = store.Raven;
|
||||
}
|
||||
|
||||
public ValidationResult Validate(TInterface instance)
|
||||
{
|
||||
if (!(instance is TImplementation))
|
||||
|
||||
@@ -169,6 +169,7 @@
|
||||
{
|
||||
this.setState('success');
|
||||
this.setDirty(false);
|
||||
this.setErrors(null);
|
||||
resolve(response);
|
||||
|
||||
if (response.model && this.route && this.$route.name !== this.route)
|
||||
|
||||
@@ -167,7 +167,7 @@
|
||||
"emails_invalid": "The email address(es) is/are not valid",
|
||||
"hex_format": "The input is not in a valid HEX #aabbcc format",
|
||||
"url_format": "The input is no well-formed URL",
|
||||
"not_unique": "The property \"{PropertyName}\" must be unique in this collection"
|
||||
"not_unique": "The property must be unique in this collection"
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user