move raven impl to package
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
using FluentValidation;
|
||||
using Raven.Client.Documents;
|
||||
using System.Globalization;
|
||||
using zero.Extensions;
|
||||
using zero.Models;
|
||||
using zero.Raven;
|
||||
|
||||
namespace zero.Raven;
|
||||
|
||||
public static class ValidatorExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Check if this value is unique within a collection
|
||||
/// </summary>
|
||||
public static IRuleBuilderOptions<T, TProperty> Unique<T, TProperty>(this IRuleBuilder<T, TProperty> ruleBuilder, IZeroStore store) where T : ZeroEntity
|
||||
{
|
||||
return ruleBuilder.MustAsync(async (entity, value, context, cancellation) =>
|
||||
{
|
||||
bool any = await store.Session().Advanced.AsyncDocumentQuery<T>()
|
||||
.WhereNotEquals(nameof(ZeroIdEntity.Id), entity.Id)
|
||||
.WhereEquals(context.PropertyName.ToPascalCaseId(), value)
|
||||
.AnyAsync(cancellation);
|
||||
|
||||
return !any;
|
||||
}).WithMessage("@errors.forms.not_unique");
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Check if this value is at least set once to the expected value within a collection
|
||||
/// </summary>
|
||||
public static IRuleBuilderOptions<T, TProperty> ExpectAnyUnique<T, TProperty>(this IRuleBuilder<T, TProperty> ruleBuilder, IZeroStore store, TProperty expectedValue) where T : ZeroEntity
|
||||
{
|
||||
return ruleBuilder.MustAsync(async (entity, value, context, cancellation) =>
|
||||
{
|
||||
return await store.Session().Advanced.AsyncDocumentQuery<T>()
|
||||
.WhereNotEquals(nameof(ZeroIdEntity.Id), entity.Id)
|
||||
.WhereEquals(context.PropertyName.ToPascalCaseId(), expectedValue)
|
||||
.AnyAsync(cancellation);
|
||||
}).WithMessage("@errors.forms.not_unique_alone");
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Check if this reference exists and is an entity which can be referenced (appId = shared for shareable entities or appId = current)
|
||||
/// </summary>
|
||||
public static IRuleBuilderOptions<T, string> Exists<T>(this IRuleBuilder<T, string> ruleBuilder, IZeroStore store) where T : ZeroEntity
|
||||
{
|
||||
return ruleBuilder.Exists<T, T>(store);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Check if this reference exists and is an entity which can be referenced (appId = shared for shareable entities or appId = current)
|
||||
/// </summary>
|
||||
public static IRuleBuilderOptions<T, string> Exists<T, TReference>(this IRuleBuilder<T, string> ruleBuilder, IZeroStore store) where T : ZeroEntity where TReference : ZeroEntity
|
||||
{
|
||||
return ruleBuilder.MustAsync(async (entity, id, context, cancellation) =>
|
||||
{
|
||||
if (id.IsNullOrWhiteSpace())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return await store.Session().Query<TReference>().AnyAsync(x => x.Id == id);
|
||||
}).WithMessage("@errors.forms.reference_notfound");
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
|
||||
public class ConfigureFlavorJsonOptions : IConfigureOptions<JsonOptions>
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
/// <summary>
|
||||
/// A flavor config holds information about a flavor implementation
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
public class FlavorOptions
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
/// <summary>
|
||||
/// A flavor provider is attached to an entity (which has ISupportsFlavors) and contains all flavors
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
public class FlavorProviderOptions<TEntity> where TEntity : class, ISupportsFlavors, new()
|
||||
{
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
internal class JsonFlavorVariantConverter<T> : JsonDiscriminatorConverter<T> where T : class, ISupportsFlavors, new()
|
||||
{
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
public class JsonFlavorVariantConverterFactory : JsonConverterFactory
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
/// <summary>
|
||||
/// Automatically generate ID with the specified length and insert it into this property on entity save
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Text.Json;
|
||||
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
public class IdGenerator
|
||||
{
|
||||
@@ -4,7 +4,7 @@ using Raven.Client.Documents.Indexes.Spatial;
|
||||
using Raven.Client.Documents.Operations.Attachments;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
|
||||
public abstract class ZeroJavascriptIndex : AbstractJavaScriptIndexCreationTask, IZeroIndexDefinition
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
public static class ZeroIndexExtensions
|
||||
{
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
using Raven.Client.Documents;
|
||||
using Raven.Client.Documents.Indexes;
|
||||
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
public class ZeroTreeHierarchyIndexResult : ZeroIdEntity, ISupportsDbConventions
|
||||
{
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace zero.Communication;
|
||||
namespace zero.Raven;
|
||||
|
||||
|
||||
public abstract partial class Interceptor<T> : Interceptor, IInterceptor<T> where T : ZeroIdEntity
|
||||
+6
-3
@@ -1,6 +1,6 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace zero.Communication;
|
||||
namespace zero.Raven;
|
||||
|
||||
public class InterceptorInstruction<T> where T : ZeroIdEntity, new()
|
||||
{
|
||||
@@ -17,6 +17,8 @@ public class InterceptorInstruction<T> where T : ZeroIdEntity, new()
|
||||
public Result<T> Result { get; private set; }
|
||||
|
||||
protected IZeroContext Context { get; private set; }
|
||||
|
||||
protected IZeroStore Store { get; private set; }
|
||||
|
||||
protected Lazy<IEnumerable<IInterceptor>> Interceptors { get; private set; }
|
||||
|
||||
@@ -29,9 +31,10 @@ public class InterceptorInstruction<T> where T : ZeroIdEntity, new()
|
||||
protected Func<IInterceptor, bool> InterceptorFilter { get; private set; } = x => true;
|
||||
|
||||
|
||||
internal InterceptorInstruction(IInterceptors interceptors, IZeroContext context, Lazy<IEnumerable<IInterceptor>> registrations, ILogger<IInterceptor> logger, InterceptorRunType runtype, T model, T previousModel = null)
|
||||
internal InterceptorInstruction(IInterceptors interceptors, IZeroStore store, IZeroContext context, Lazy<IEnumerable<IInterceptor>> registrations, ILogger<IInterceptor> logger, InterceptorRunType runtype, T model, T previousModel = null)
|
||||
{
|
||||
InterceptorHandler = interceptors;
|
||||
Store = store;
|
||||
Context = context;
|
||||
Guid = Guid.NewGuid();
|
||||
Logger = logger;
|
||||
@@ -65,7 +68,7 @@ public class InterceptorInstruction<T> where T : ZeroIdEntity, new()
|
||||
InterceptorParameters parameters = new()
|
||||
{
|
||||
Context = Context,
|
||||
Store = Context.Store,
|
||||
Store = Store,
|
||||
Properties = new(),
|
||||
Interceptors = InterceptorHandler,
|
||||
Operations = operations,
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace zero.Communication;
|
||||
namespace zero.Raven;
|
||||
|
||||
public class InterceptorParameters
|
||||
{
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace zero.Communication;
|
||||
namespace zero.Raven;
|
||||
|
||||
public class InterceptorResult<T>
|
||||
{
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace zero.Communication;
|
||||
namespace zero.Raven;
|
||||
|
||||
public enum InterceptorRunType
|
||||
{
|
||||
+8
-5
@@ -1,32 +1,35 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace zero.Communication;
|
||||
namespace zero.Raven;
|
||||
|
||||
public class Interceptors : IInterceptors
|
||||
{
|
||||
protected IZeroContext Context { get; set; }
|
||||
|
||||
protected IZeroStore Store { get; set; }
|
||||
|
||||
protected Lazy<IEnumerable<IInterceptor>> Registrations { get; set; }
|
||||
|
||||
protected ILogger<IInterceptor> Logger { get; set; }
|
||||
|
||||
|
||||
public Interceptors(IZeroContext context, Lazy<IEnumerable<IInterceptor>> registrations, ILogger<IInterceptor> logger)
|
||||
public Interceptors(IZeroContext context, IZeroStore store, Lazy<IEnumerable<IInterceptor>> registrations, ILogger<IInterceptor> logger)
|
||||
{
|
||||
Context = context;
|
||||
Store = store;
|
||||
Registrations = registrations;
|
||||
Logger = logger;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public InterceptorInstruction<T> ForCreate<T>(T model) where T : ZeroIdEntity, new() => new(this, Context, Registrations, Logger, InterceptorRunType.Create, model);
|
||||
public InterceptorInstruction<T> ForCreate<T>(T model) where T : ZeroIdEntity, new() => new(this, Store, Context, Registrations, Logger, InterceptorRunType.Create, model);
|
||||
|
||||
/// <inheritdoc />
|
||||
public InterceptorInstruction<T> ForUpdate<T>(T model, T previousModel = null) where T : ZeroIdEntity, new() => new(this, Context, Registrations, Logger, InterceptorRunType.Update, model, previousModel);
|
||||
public InterceptorInstruction<T> ForUpdate<T>(T model, T previousModel = null) where T : ZeroIdEntity, new() => new(this, Store, Context, Registrations, Logger, InterceptorRunType.Update, model, previousModel);
|
||||
|
||||
/// <inheritdoc />
|
||||
public InterceptorInstruction<T> ForDelete<T>(T model) where T : ZeroIdEntity, new() => new(this, Context, Registrations, Logger, InterceptorRunType.Delete, model);
|
||||
public InterceptorInstruction<T> ForDelete<T>(T model) where T : ZeroIdEntity, new() => new(this, Store, Context, Registrations, Logger, InterceptorRunType.Delete, model);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
public partial class RavenOperations : IRavenOperations
|
||||
{
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
public partial class RavenOperations : IRavenOperations
|
||||
{
|
||||
+1
-1
@@ -3,7 +3,7 @@ using Raven.Client.Documents.Indexes;
|
||||
using Raven.Client.Documents.Linq;
|
||||
using Raven.Client.Documents.Session;
|
||||
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
public partial class RavenOperations : IRavenOperations
|
||||
{
|
||||
+1
-1
@@ -3,7 +3,7 @@ using Raven.Client.Documents.Indexes;
|
||||
using Raven.Client.Documents.Linq;
|
||||
using Raven.Client.Documents.Session;
|
||||
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
public partial class RavenOperations : IRavenOperations
|
||||
{
|
||||
+3
-2
@@ -1,6 +1,7 @@
|
||||
using FluentValidation.Results;
|
||||
using Rv = Raven.Client;
|
||||
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
public partial class RavenOperations : IRavenOperations
|
||||
{
|
||||
@@ -24,7 +25,7 @@ public partial class RavenOperations : IRavenOperations
|
||||
// check if the Id for a model already exists
|
||||
if (!model.Id.IsNullOrEmpty())
|
||||
{
|
||||
using (IZeroDocumentSession session = Context.Store.Session(options: new Raven.Client.Documents.Session.SessionOptions() { Database = Context.Store.ResolvedDatabase, NoCaching = true }))
|
||||
using (IZeroDocumentSession session = Store.Session(options: new Rv.Documents.Session.SessionOptions() { Database = Store.ResolvedDatabase, NoCaching = true }))
|
||||
{
|
||||
previousModel = await session.LoadAsync<T>(model.Id);
|
||||
}
|
||||
+5
-2
@@ -4,12 +4,12 @@ using Raven.Client.Documents.Indexes;
|
||||
using Raven.Client.Documents.Linq;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
public partial class RavenOperations : IRavenOperations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public IZeroDocumentSession Session => Context.Store.Session();
|
||||
public IZeroDocumentSession Session => Store.Session();
|
||||
|
||||
protected record OperationOptions(bool IncludeInactive);
|
||||
|
||||
@@ -20,12 +20,15 @@ public partial class RavenOperations : IRavenOperations
|
||||
protected FlavorOptions Flavors { get; private set; }
|
||||
|
||||
protected IServiceProvider Services { get; private set; }
|
||||
|
||||
protected IZeroStore Store { get; private set; }
|
||||
|
||||
protected StoreInterceptorBlocker InterceptorBlocker { get; private set; }
|
||||
|
||||
|
||||
public RavenOperations(StoreContext context)
|
||||
{
|
||||
Store = context.Store;
|
||||
Context = context.Context;
|
||||
Interceptors = context.Interceptors;
|
||||
Services = context.Services;
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
using Raven.Client.Documents.Linq;
|
||||
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
public static class RavenOperationsExtensions
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
public class StoreContext
|
||||
{
|
||||
@@ -15,9 +15,9 @@ public class StoreContext
|
||||
public IMessageAggregator Messages { get; private set; }
|
||||
|
||||
|
||||
public StoreContext(IZeroContext context, IInterceptors interceptors, IServiceProvider serviceProvider, IMessageAggregator messages)
|
||||
public StoreContext(IZeroContext context, IZeroStore store, IInterceptors interceptors, IServiceProvider serviceProvider, IMessageAggregator messages)
|
||||
{
|
||||
Store = context.Store;
|
||||
Store = store;
|
||||
Options = context.Options;
|
||||
Context = context;
|
||||
Interceptors = interceptors;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
/// <summary>
|
||||
/// This attribute will allow the usage of custom collection names for Raven collections
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
public static partial class RavenConstants
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using Raven.Client.Documents.Indexes;
|
||||
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
public static class RavenIndexExtensions
|
||||
{
|
||||
@@ -1,7 +1,7 @@
|
||||
using Raven.Client.Documents;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
public class RavenOptions
|
||||
{
|
||||
+1
-1
@@ -4,7 +4,7 @@ using Raven.Client.Documents.Queries;
|
||||
using Raven.Client.Documents.Session;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
public static class RavenQueryableExtensions
|
||||
{
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
public class Safenames
|
||||
{
|
||||
+1
-1
@@ -3,7 +3,7 @@ using System.Net;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
/// <summary>
|
||||
/// Replicates the Rfc6238AuthenticationService from ASP.NET Core internals as it isn't part of the public API
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
[RavenCollection("Tokens")]
|
||||
public class SecurityToken : ISupportsDbConventions
|
||||
+1
-1
@@ -3,7 +3,7 @@ using Raven.Client.Documents.Session;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
public class ZeroTokenProvider : IZeroTokenProvider
|
||||
{
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
global using System;
|
||||
global using System.Collections;
|
||||
global using System.Collections.Generic;
|
||||
global using System.Linq;
|
||||
global using System.Threading;
|
||||
global using System.Threading.Tasks;
|
||||
|
||||
global using zero.Utils;
|
||||
global using zero.Configuration;
|
||||
global using zero.Extensions;
|
||||
global using zero.FileStorage;
|
||||
global using zero.Models;
|
||||
global using zero.Architecture;
|
||||
global using zero.Rendering;
|
||||
global using zero.Validation;
|
||||
global using zero.Localization;
|
||||
global using zero.Context;
|
||||
global using zero.Communication;
|
||||
@@ -0,0 +1,12 @@
|
||||
using zero.Raven;
|
||||
|
||||
namespace zero;
|
||||
|
||||
public static class ZeroBuilderExtensions
|
||||
{
|
||||
public static ZeroBuilder AddRavenDb(this ZeroBuilder builder)
|
||||
{
|
||||
builder.AddModule<ZeroRavenModule>();
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -2,8 +2,9 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Rv = Raven.Client;
|
||||
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
public class ZeroDocumentConventionsBuilder : IZeroDocumentConventionsBuilder
|
||||
{
|
||||
@@ -67,7 +68,7 @@ public class ZeroDocumentConventionsBuilder : IZeroDocumentConventionsBuilder
|
||||
};
|
||||
|
||||
// get inner type for revisions
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Raven.Client.Documents.Subscriptions.Revision<>))
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Rv.Documents.Subscriptions.Revision<>))
|
||||
{
|
||||
type = type.GetGenericArguments().FirstOrDefault();
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using Raven.Client.Documents;
|
||||
using Raven.Client.Documents.Session;
|
||||
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
public class ZeroDocumentSession : AsyncDocumentSession, IZeroDocumentSession
|
||||
{
|
||||
@@ -0,0 +1,16 @@
|
||||
using Rv = Raven.Client;
|
||||
|
||||
namespace zero.Raven;
|
||||
|
||||
public static class ZeroDocumentSessionExtensions
|
||||
{
|
||||
public static void SetCollection<T>(this IZeroDocumentSession session, T model, string collectionName)
|
||||
{
|
||||
session.Advanced.GetMetadataFor(model)[Rv.Constants.Documents.Metadata.Collection] = collectionName;
|
||||
}
|
||||
|
||||
public static void Expires<T>(this IZeroDocumentSession session, T model, TimeSpan expires)
|
||||
{
|
||||
session.Advanced.GetMetadataFor(model)[Rv.Constants.Documents.Metadata.Expires] = DateTime.UtcNow.AddSeconds(expires.TotalSeconds);
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ using Raven.Client.Documents.Operations;
|
||||
using Raven.Client.Documents.Queries;
|
||||
using Raven.Client.Documents.Session;
|
||||
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
public class ZeroDocumentStore : DocumentStore, IZeroDocumentStore
|
||||
{
|
||||
@@ -4,9 +4,9 @@ using Raven.Client.Documents;
|
||||
using Raven.Client.Documents.Indexes;
|
||||
using Raven.Client.Http;
|
||||
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
internal class ZeroPersistenceModule : ZeroModule
|
||||
internal class ZeroRavenModule : ZeroModule
|
||||
{
|
||||
public override void ConfigureServices(IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
@@ -16,6 +16,7 @@ internal class ZeroPersistenceModule : ZeroModule
|
||||
services.AddScoped<IZeroTokenProvider, ZeroTokenProvider>();
|
||||
services.AddScoped<StoreContext>();
|
||||
services.AddTransient<IRavenOperations, RavenOperations>();
|
||||
services.AddScoped<IInterceptors, Interceptors>();
|
||||
|
||||
services.AddOptions<FlavorOptions>();
|
||||
services.AddOptions<RavenOptions>().Bind(configuration.GetSection("Zero:Raven"));
|
||||
@@ -50,12 +51,10 @@ internal class ZeroPersistenceModule : ZeroModule
|
||||
IDocumentStore raven = store.Initialize();
|
||||
|
||||
// create all indexes
|
||||
if (options.Initialized)
|
||||
{
|
||||
var indexes = ravenOptions.Indexes.BuildAll(options, store);
|
||||
IndexCreation.CreateIndexes(indexes, store, database: ravenOptions.Database);
|
||||
}
|
||||
IEnumerable<IZeroIndexDefinition> indexes = ravenOptions.Indexes.BuildAll(options, store);
|
||||
IndexCreation.CreateIndexes(indexes, store, database: ravenOptions.Database);
|
||||
|
||||
|
||||
return (ZeroDocumentStore)raven;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using Raven.Client.Documents.Session;
|
||||
|
||||
namespace zero.Persistence;
|
||||
namespace zero.Raven;
|
||||
|
||||
public class ZeroStore : IZeroStore
|
||||
{
|
||||
@@ -0,0 +1,22 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<PackageId>zero.Raven</PackageId>
|
||||
<Version>1.0.0</Version>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
|
||||
<RootNamespace>zero.Raven</RootNamespace>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="RavenDB.Client" Version="5.4.5" />
|
||||
<PackageReference Include="FluentValidation" Version="11.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\zero\zero.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -17,6 +17,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "zero", "zero\zero.csproj",
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "legacy", "legacy", "{93A1CCEB-A323-445E-8116-4575C5939B46}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "zero.Raven", "zero.Raven\zero.Raven.csproj", "{DC79D7EA-FAA1-4701-9C36-8295CD1C45D0}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -43,6 +45,10 @@ Global
|
||||
{33CD6E46-CD81-42C3-9019-C0EAD557EE99}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{33CD6E46-CD81-42C3-9019-C0EAD557EE99}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{33CD6E46-CD81-42C3-9019-C0EAD557EE99}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DC79D7EA-FAA1-4701-9C36-8295CD1C45D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DC79D7EA-FAA1-4701-9C36-8295CD1C45D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DC79D7EA-FAA1-4701-9C36-8295CD1C45D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DC79D7EA-FAA1-4701-9C36-8295CD1C45D0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -7,7 +7,6 @@ internal class ZeroCommunicationModule : ZeroModule
|
||||
{
|
||||
public override void ConfigureServices(IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
services.AddScoped<IInterceptors, Interceptors>();
|
||||
services.AddScoped<IMessageAggregator, MessageAggregator>();
|
||||
services.AddTransient<IHandlerHolder, HandlerHolder>();
|
||||
services.AddTransient(typeof(Lazy<>), typeof(LazilyResolved<>));
|
||||
|
||||
@@ -6,9 +6,6 @@ namespace zero.Configuration;
|
||||
|
||||
public class ZeroOptions : IZeroOptions
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public bool Initialized => !string.IsNullOrEmpty(For<RavenOptions>()?.Database);
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Version { get; set; }
|
||||
|
||||
@@ -46,11 +43,6 @@ public interface IZeroOptions
|
||||
/// </summary>
|
||||
string Version { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether this zero instance is initialized (setup is completed)
|
||||
/// </summary>
|
||||
bool Initialized { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Expiration of a generated change token for an entity
|
||||
/// </summary>
|
||||
|
||||
@@ -9,10 +9,6 @@ public class ZeroContext : IZeroContext
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public IZeroOptions Options { get; protected set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IZeroStore Store { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IServiceProvider Services { get; private set; }
|
||||
|
||||
@@ -31,12 +27,11 @@ public class ZeroContext : IZeroContext
|
||||
|
||||
|
||||
public ZeroContext(IZeroOptions options, IHttpContextAccessor httpContextAccessor, ICultureResolver cultureResolver,
|
||||
ILogger<ZeroContext> logger, IZeroStore store, IHandlerHolder handler, IServiceProvider services)
|
||||
ILogger<ZeroContext> logger, IHandlerHolder handler, IServiceProvider services)
|
||||
{
|
||||
Options = options;
|
||||
CultureResolver = cultureResolver;
|
||||
Logger = logger;
|
||||
Store = store;
|
||||
Handler = handler;
|
||||
ValueCollection = new PrimitiveTypeCollection();
|
||||
HttpContextAccessor = httpContextAccessor;
|
||||
@@ -80,11 +75,6 @@ public interface IZeroContext
|
||||
/// </summary>
|
||||
IZeroOptions Options { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Document store
|
||||
/// </summary>
|
||||
IZeroStore Store { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Service container
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
using System.IO;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace zero.Localization;
|
||||
|
||||
public class FileLocalizer : Localizer
|
||||
{
|
||||
private List<Translation> _fileList;
|
||||
private IWebHostEnvironment _env;
|
||||
|
||||
|
||||
public FileLocalizer(IWebHostEnvironment env, IOptionsMonitor<LocalizationOptions> options) : base()
|
||||
{
|
||||
_env = env;
|
||||
LoadIntoCache(options.CurrentValue.FilePath);
|
||||
options.OnChange((opts, _) => LoadIntoCache(opts.FilePath));
|
||||
}
|
||||
|
||||
|
||||
protected void LoadIntoCache(string filePath)
|
||||
{
|
||||
string path = Path.Combine(_env.ContentRootPath, filePath);
|
||||
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
_fileList = new();
|
||||
}
|
||||
else
|
||||
{
|
||||
Dictionary<string, string> texts = JsonConvert.DeserializeObject<Dictionary<string, string>>(File.ReadAllText(path, Encoding.Latin1));
|
||||
_fileList = texts.Select(kvp => new Translation() { Key = kvp.Key, Value = kvp.Value }).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected override Translation LoadTranslation(string key)
|
||||
{
|
||||
//return new Translation()
|
||||
//{
|
||||
// Value = "{@" + key + "}"
|
||||
//};
|
||||
|
||||
return _fileList.FirstOrDefault(x => x.Key == key);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace zero.Localization;
|
||||
|
||||
public class LocalizationOptions
|
||||
{
|
||||
public string FilePath { get; set; }
|
||||
}
|
||||
@@ -3,17 +3,10 @@ using System.Reflection;
|
||||
|
||||
namespace zero.Localization;
|
||||
|
||||
public class Localizer : ILocalizer
|
||||
public abstract class Localizer : ILocalizer
|
||||
{
|
||||
protected ConcurrentDictionary<string, string> Cache { get; private set; } = new();
|
||||
|
||||
protected IRavenOperations Raven { get; private set; }
|
||||
|
||||
public Localizer(IRavenOperations raven)
|
||||
{
|
||||
Raven = raven;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Text(string key) => Text(key, null);
|
||||
@@ -76,10 +69,7 @@ public class Localizer : ILocalizer
|
||||
/// <summary>
|
||||
/// Get translation from database or any other source
|
||||
/// </summary>
|
||||
protected virtual Translation LoadTranslation(string key)
|
||||
{
|
||||
return Raven.Session.Synchronous.Query<Translation>().FirstOrDefault(x => x.Key == key);
|
||||
}
|
||||
protected abstract Translation LoadTranslation(string key);
|
||||
}
|
||||
|
||||
public interface ILocalizer
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
namespace zero.Localization;
|
||||
|
||||
[RavenCollection("Translations")]
|
||||
public class Translation : ZeroEntity, IAlwaysActive
|
||||
public class Translation
|
||||
{
|
||||
public Translation()
|
||||
{
|
||||
IsActive = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Key of the translation
|
||||
/// </summary>
|
||||
public string Key { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Value of the translation
|
||||
/// </summary>
|
||||
@@ -23,5 +22,5 @@ public class Translation : ZeroEntity, IAlwaysActive
|
||||
public enum TranslationDisplay
|
||||
{
|
||||
Text = 0,
|
||||
HTML = 1
|
||||
Html = 1
|
||||
}
|
||||
@@ -10,6 +10,11 @@ internal class ZeroLocalizationModule : ZeroModule
|
||||
{
|
||||
services.AddScoped<ICultureResolver, CultureResolver>();
|
||||
services.AddScoped<ICultureService, CultureService>();
|
||||
services.AddScoped<ILocalizer, Localizer>();
|
||||
services.AddScoped<ILocalizer, FileLocalizer>();
|
||||
|
||||
services.AddOptions<LocalizationOptions>().Bind(configuration.GetSection("Zero:Localization")).Configure(opts =>
|
||||
{
|
||||
opts.FilePath = "Config/texts.json";
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace zero.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Triggers custom conventions for database operations
|
||||
/// </summary>
|
||||
public interface ISupportsDbConventions { }
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace zero.Persistence;
|
||||
|
||||
/// <summary>
|
||||
/// Triggers custom Raven conventions for database operations
|
||||
/// </summary>
|
||||
public interface ISupportsDbConventions { }
|
||||
@@ -1,14 +0,0 @@
|
||||
namespace zero.Persistence;
|
||||
|
||||
public static class ZeroDocumentSessionExtensions
|
||||
{
|
||||
public static void SetCollection<T>(this IZeroDocumentSession session, T model, string collectionName)
|
||||
{
|
||||
session.Advanced.GetMetadataFor(model)[Raven.Client.Constants.Documents.Metadata.Collection] = collectionName;
|
||||
}
|
||||
|
||||
public static void Expires<T>(this IZeroDocumentSession session, T model, TimeSpan expires)
|
||||
{
|
||||
session.Advanced.GetMetadataFor(model)[Raven.Client.Constants.Documents.Metadata.Expires] = DateTime.UtcNow.AddSeconds(expires.TotalSeconds);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -6,7 +6,7 @@ global using System.Linq;
|
||||
global using System.Threading;
|
||||
global using System.Threading.Tasks;
|
||||
|
||||
global using zero.Persistence;
|
||||
//global using zero.Persistence;
|
||||
global using zero.Utils;
|
||||
global using zero.Configuration;
|
||||
global using zero.Extensions;
|
||||
|
||||
@@ -114,64 +114,4 @@ public static class ValidatorExtensions
|
||||
}
|
||||
}).WithMessage("@errors.forms.culture");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Check if this value is unique within a collection
|
||||
/// </summary>
|
||||
public static IRuleBuilderOptions<T, TProperty> Unique<T, TProperty>(this IRuleBuilder<T, TProperty> ruleBuilder, IZeroStore store) where T : ZeroEntity
|
||||
{
|
||||
return ruleBuilder.MustAsync(async (entity, value, context, cancellation) =>
|
||||
{
|
||||
bool any = await store.Session().Advanced.AsyncDocumentQuery<T>()
|
||||
.WhereNotEquals(nameof(ZeroIdEntity.Id), entity.Id)
|
||||
.WhereEquals(context.PropertyName.ToPascalCaseId(), value)
|
||||
.AnyAsync(cancellation);
|
||||
|
||||
return !any;
|
||||
}).WithMessage("@errors.forms.not_unique");
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Check if this value is at least set once to the expected value within a collection
|
||||
/// </summary>
|
||||
public static IRuleBuilderOptions<T, TProperty> ExpectAnyUnique<T, TProperty>(this IRuleBuilder<T, TProperty> ruleBuilder, IZeroStore store, TProperty expectedValue) where T : ZeroEntity
|
||||
{
|
||||
return ruleBuilder.MustAsync(async (entity, value, context, cancellation) =>
|
||||
{
|
||||
return await store.Session().Advanced.AsyncDocumentQuery<T>()
|
||||
.WhereNotEquals(nameof(ZeroIdEntity.Id), entity.Id)
|
||||
.WhereEquals(context.PropertyName.ToPascalCaseId(), expectedValue)
|
||||
.AnyAsync(cancellation);
|
||||
}).WithMessage("@errors.forms.not_unique_alone");
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Check if this reference exists and is an entity which can be referenced (appId = shared for shareable entities or appId = current)
|
||||
/// </summary>
|
||||
public static IRuleBuilderOptions<T, string> Exists<T>(this IRuleBuilder<T, string> ruleBuilder, IZeroStore store) where T : ZeroEntity
|
||||
{
|
||||
return ruleBuilder.Exists<T, T>(store);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Check if this reference exists and is an entity which can be referenced (appId = shared for shareable entities or appId = current)
|
||||
/// </summary>
|
||||
public static IRuleBuilderOptions<T, string> Exists<T, TReference>(this IRuleBuilder<T, string> ruleBuilder, IZeroStore store) where T : ZeroEntity where TReference : ZeroEntity
|
||||
{
|
||||
return ruleBuilder.MustAsync(async (entity, id, context, cancellation) =>
|
||||
{
|
||||
if (id.IsNullOrWhiteSpace())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return await store.Session().Query<TReference>().AnyAsync(x => x.Id == id);
|
||||
}).WithMessage("@errors.forms.reference_notfound");
|
||||
}
|
||||
}
|
||||
|
||||
+17
-1
@@ -47,7 +47,6 @@ public class ZeroBuilder
|
||||
//Modules.Add<ZeroMapperModule>();
|
||||
//Modules.Add<ZeroMediaModule>();
|
||||
//Modules.Add<ZeroPageModule>();
|
||||
Modules.Add<ZeroPersistenceModule>();
|
||||
Modules.Add<ZeroRenderingModule>();
|
||||
//Modules.Add<ZeroRoutingModule>();
|
||||
|
||||
@@ -66,4 +65,21 @@ public class ZeroBuilder
|
||||
Services.Configure(configureOptions);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public ZeroBuilder AddModule(IZeroModule module)
|
||||
{
|
||||
module.ConfigureServices(Services, _configuration);
|
||||
Modules.Add(module);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public ZeroBuilder AddModule<T>() where T : class, IZeroModule, new()
|
||||
{
|
||||
T module = new();
|
||||
module.ConfigureServices(Services, _configuration);
|
||||
Modules.Add(module);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user