using Raven.Client; using Raven.Client.Documents; using Raven.Client.Documents.BulkInsert; using Raven.Client.Documents.Operations; using Raven.Client.Documents.Queries; using Raven.Client.Documents.Session; using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using zero.Core.Options; namespace zero.Core.Database { public class ZeroStore : DocumentStore, IZeroStore { public ZeroStore(IZeroOptions options) : base() { Options = options; Database = null; } protected IZeroOptions Options { get; set; } protected Dictionary ScopedSessions { get; set; } = new(); /// public string ResolvedDatabase { get; set; } /// public IDocumentStore Raven => this; /// public IZeroDocumentSession Session(string database = null, ZeroSessionResolution resolution = ZeroSessionResolution.Reuse, SessionOptions options = null) { database ??= ResolvedDatabase; options ??= new SessionOptions() { Database = database }; if (resolution == ZeroSessionResolution.Create) { return OpenAsyncSession(options) as IZeroDocumentSession; } if (!ScopedSessions.TryGetValue(database, out IZeroDocumentSession session)) { session = OpenAsyncSession(options) as IZeroDocumentSession; ScopedSessions.TryAdd(database, session); } if (session.IsDisposed) { session = OpenAsyncSession(options) as IZeroDocumentSession; ScopedSessions.Remove(database); ScopedSessions.TryAdd(database, session); } return session; } /// public IZeroDocumentSession Session(bool global, string database = null, ZeroSessionResolution resolution = ZeroSessionResolution.Reuse, SessionOptions options = null) { return Session(global ? Options.Raven.Database : database, resolution, options); } /// public OperationExecutor GetOperationExecutor(string database = null) { return Operations.ForDatabase(database ?? ResolvedDatabase); } /// public IAsyncDocumentSession OpenCoreSession() { return OpenAsyncSession(Options.Raven.Database); } /// public override IAsyncDocumentSession OpenAsyncSession(string database) { return OpenAsyncSession(new SessionOptions() { Database = database }); } /// public override IAsyncDocumentSession OpenAsyncSession(SessionOptions options) { options.Database = options.Database ?? ResolvedDatabase; AssertInitialized(); EnsureNotClosed(); var sessionId = Guid.NewGuid(); var session = new ZeroDocumentSession(this, sessionId, options, Options.Raven.Database); RegisterEvents(session); AfterSessionCreated(session); session.OnSessionDisposing += (sender, args) => { session.IsDisposed = true; }; session.Advanced.DocumentStore.AggressivelyCacheFor(TimeSpan.FromHours(1), options.Database); return session; } /// public override IAsyncDocumentSession OpenAsyncSession() { return OpenAsyncSession(new SessionOptions() { Database = ResolvedDatabase }); } /// public override IDocumentSession OpenSession(SessionOptions options) { options.Database = options.Database ?? ResolvedDatabase; AssertInitialized(); EnsureNotClosed(); var sessionId = Guid.NewGuid(); var session = new DocumentSession(this, sessionId, options); RegisterEvents(session); AfterSessionCreated(session); session.Advanced.DocumentStore.AggressivelyCacheFor(TimeSpan.FromHours(1), options.Database); return session; } /// public override IDocumentSession OpenSession(string database) { return OpenSession(new SessionOptions() { Database = database }); } /// public override IDocumentSession OpenSession() { return OpenSession(new SessionOptions() { Database = ResolvedDatabase }); } /// public override BulkInsertOperation BulkInsert(string database = null, CancellationToken token = default) { return base.BulkInsert(database ?? ResolvedDatabase, token); } /// public async Task PurgeAsync(string database = null, string querySuffix = null, Parameters parameters = null) { var collectionName = Conventions.FindCollectionName(typeof(T)); var operationQuery = new DeleteByQueryOperation(new IndexQuery() { Query = $"from {collectionName} c {querySuffix ?? String.Empty}", QueryParameters = parameters }, new QueryOperationOptions { AllowStale = true }); Operation operation = await GetOperationExecutor(database ?? ResolvedDatabase).SendAsync(operationQuery); await operation.WaitForCompletionAsync(); } } public enum ZeroSessionResolution { Reuse = 0, Create = 1 } public interface IZeroStore : IDocumentStore { /// /// The database which has been resolved from the current application /// string ResolvedDatabase { get; set; } /// /// Get underlying raven document store /// IDocumentStore Raven { get; } /// /// Use a specific session /// IZeroDocumentSession Session(string database = null, ZeroSessionResolution resolution = ZeroSessionResolution.Reuse, SessionOptions options = null); /// /// Use a session for the core database /// IZeroDocumentSession Session(bool global, string database = null, ZeroSessionResolution resolution = ZeroSessionResolution.Reuse, SessionOptions options = null); /// /// Get operation executor /// OperationExecutor GetOperationExecutor(string database = null); /// /// Purges a collection /// Task PurgeAsync(string database = null, string querySuffix = null, Parameters parameters = null); /// /// Opens a session for the core database /// IAsyncDocumentSession OpenCoreSession(); } }