From a46c3bf452d287b50b2e7dd5a24f5995c9fd26f6 Mon Sep 17 00:00:00 2001 From: vnugent Date: Mon, 9 Jan 2023 15:09:13 -0500 Subject: Restructure --- VNLib.Plugins.Extensions.Data/DbStore.cs | 507 ------------------------------- 1 file changed, 507 deletions(-) delete mode 100644 VNLib.Plugins.Extensions.Data/DbStore.cs (limited to 'VNLib.Plugins.Extensions.Data/DbStore.cs') diff --git a/VNLib.Plugins.Extensions.Data/DbStore.cs b/VNLib.Plugins.Extensions.Data/DbStore.cs deleted file mode 100644 index 8cf4e2e..0000000 --- a/VNLib.Plugins.Extensions.Data/DbStore.cs +++ /dev/null @@ -1,507 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Plugins.Extensions.Data -* File: DbStore.cs -* -* DbStore.cs is part of VNLib.Plugins.Extensions.Data which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Plugins.Extensions.Data is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published -* by the Free Software Foundation, either version 2 of the License, -* or (at your option) any later version. -* -* VNLib.Plugins.Extensions.Data is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with VNLib.Plugins.Extensions.Data. If not, see http://www.gnu.org/licenses/. -*/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -using Microsoft.EntityFrameworkCore; - -using VNLib.Utils; -using VNLib.Utils.Memory.Caching; -using VNLib.Plugins.Extensions.Data.Abstractions; - -namespace VNLib.Plugins.Extensions.Data -{ - /// - /// Implements basic data-store functionality with abstract query builders - /// - /// A implemented type - public abstract class DbStore : IDataStore, IPaginatedDataStore where T: class, IDbModel - { - /// - /// Gets a unique ID for a new record being added to the store - /// - public abstract string RecordIdBuilder { get; } - /// - /// Gets a new ready for use - /// - /// - public abstract TransactionalDbContext NewContext(); - - /// - /// An object rental for entity collections - /// - public ObjectRental> ListRental { get; } = ObjectRental.Create>(null, static ret => ret.Clear()); - - #region Add Or Update - /// - public virtual async Task AddOrUpdateAsync(T record) - { - //Open new db context - await using TransactionalDbContext ctx = NewContext(); - //Open transaction - await ctx.OpenTransactionAsync(); - IQueryable query; - if (string.IsNullOrWhiteSpace(record.Id)) - { - //Get the application - query = AddOrUpdateQueryBuilder(ctx, record); - } - else - { - //Get the application - query = (from et in ctx.Set() - where et.Id == record.Id - select et); - } - //Using single - T? entry = await query.SingleOrDefaultAsync(); - //Check if creted - if (entry == null) - { - //Create a new template id - record.Id = RecordIdBuilder; - //Set the created/lm times - record.Created = record.LastModified = DateTime.UtcNow; - //Add the new template to the ctx - ctx.Add(record); - } - else - { - OnRecordUpdate(record, entry); - } - //Save changes - ERRNO result = await ctx.SaveChangesAsync(); - if (result) - { - //commit transaction if update was successful - await ctx.CommitTransactionAsync(); - } - return result; - } - /// - public virtual async Task UpdateAsync(T record) - { - //Open new db context - await using TransactionalDbContext ctx = NewContext(); - //Open transaction - await ctx.OpenTransactionAsync(); - //Get the application - IQueryable query = UpdateQueryBuilder(ctx, record); - //Using single to make sure only one app is in the db (should never be an issue) - T? oldEntry = await query.SingleOrDefaultAsync(); - if (oldEntry == null) - { - return false; - } - //Update the template meta-data - OnRecordUpdate(record, oldEntry); - //Only publish update if changes happened - if (!ctx.ChangeTracker.HasChanges()) - { - //commit transaction if no changes need to be made - await ctx.CommitTransactionAsync(); - return true; - } - //Save changes - ERRNO result = await ctx.SaveChangesAsync(); - if (result) - { - //commit transaction if update was successful - await ctx.CommitTransactionAsync(); - } - return result; - } - /// - public virtual async Task CreateAsync(T record) - { - //Open new db context - await using TransactionalDbContext ctx = NewContext(); - //Open transaction - await ctx.OpenTransactionAsync(); - //Create a new template id - record.Id = RecordIdBuilder; - //Update the created/last modified time of the record - record.Created = record.LastModified = DateTime.UtcNow; - //Add the new template - ctx.Add(record); - //save changes - ERRNO result = await ctx.SaveChangesAsync(); - if (result) - { - //Commit transaction - await ctx.CommitTransactionAsync(); - } - return result; - } - - /// - /// Builds a query that attempts to get a single entry from the - /// store based on the specified record if it does not have a - /// valid property - /// - /// The active context to query - /// The record to search for - /// A query that yields a single record if it exists in the store - protected virtual IQueryable AddOrUpdateQueryBuilder(TransactionalDbContext context, T record) - { - //default to get single of the specific record - return GetSingleQueryBuilder(context, record); - } - /// - /// Builds a query that attempts to get a single entry from the - /// store to update based on the specified record - /// - /// The active context to query - /// The record to search for - /// A query that yields a single record to update if it exists in the store - protected virtual IQueryable UpdateQueryBuilder(TransactionalDbContext context, T record) - { - //default to get single of the specific record - return GetSingleQueryBuilder(context, record); - } - /// - /// Updates the current record (if found) to the new record before - /// storing the updates. - /// - /// The new record to capture data from - /// The current record to be updated - protected abstract void OnRecordUpdate(T newRecord, T currentRecord); - #endregion - - #region Delete - /// - public virtual async Task DeleteAsync(string key) - { - //Open new db context - await using TransactionalDbContext ctx = NewContext(); - //Open transaction - await ctx.OpenTransactionAsync(); - //Get the template by its id - IQueryable query = (from temp in ctx.Set() - where temp.Id == key - select temp); - T? record = await query.SingleOrDefaultAsync(); - if (record == null) - { - return false; - } - //Add the new application - ctx.Remove(record); - //Save changes - ERRNO result = await ctx.SaveChangesAsync(); - if (result) - { - //Commit transaction - await ctx.CommitTransactionAsync(); - } - return result; - } - /// - public virtual async Task DeleteAsync(T record) - { - //Open new db context - await using TransactionalDbContext ctx = NewContext(); - //Open transaction - await ctx.OpenTransactionAsync(); - //Get a query for a a single item - IQueryable query = GetSingleQueryBuilder(ctx, record); - //Get the entry - T? entry = await query.SingleOrDefaultAsync(); - if (entry == null) - { - return false; - } - //Add the new application - ctx.Remove(entry); - //Save changes - ERRNO result = await ctx.SaveChangesAsync(); - if (result) - { - //Commit transaction - await ctx.CommitTransactionAsync(); - } - return result; - } - /// - public virtual async Task DeleteAsync(params string[] specifiers) - { - //Open new db context - await using TransactionalDbContext ctx = NewContext(); - //Open transaction - await ctx.OpenTransactionAsync(); - //Get the template by its id - IQueryable query = DeleteQueryBuilder(ctx, specifiers); - T? entry = await query.SingleOrDefaultAsync(); - if (entry == null) - { - return false; - } - //Add the new application - ctx.Remove(entry); - //Save changes - ERRNO result = await ctx.SaveChangesAsync(); - if (result) - { - //Commit transaction - await ctx.CommitTransactionAsync(); - } - return result; - } - - /// - /// Builds a query that results in a single entry to delete from the - /// constraint arguments - /// - /// The active context - /// A variable length parameter array of query constraints - /// A query that yields a single record (or no record) to delete - protected virtual IQueryable DeleteQueryBuilder(TransactionalDbContext context, params string[] constraints) - { - //default use the get-single method, as the implementation is usually identical - return GetSingleQueryBuilder(context, constraints); - } - #endregion - - #region Get Collection - /// - public virtual async Task GetCollectionAsync(ICollection collection, string specifier, int limit) - { - int previous = collection.Count; - //Open new db context - await using TransactionalDbContext ctx = NewContext(); - //Open transaction - await ctx.OpenTransactionAsync(); - //Get the single template by its id - await GetCollectionQueryBuilder(ctx, specifier).Take(limit).Select(static e => e).ForEachAsync(collection.Add); - //close db and transaction - await ctx.CommitTransactionAsync(); - //Return the number of elements add to the collection - return collection.Count - previous; - } - /// - public virtual async Task GetCollectionAsync(ICollection collection, int limit, params string[] args) - { - int previous = collection.Count; - //Open new db context - await using TransactionalDbContext ctx = NewContext(); - //Open transaction - await ctx.OpenTransactionAsync(); - //Get the single template by its id - await GetCollectionQueryBuilder(ctx, args).Take(limit).Select(static e => e).ForEachAsync(collection.Add); - //close db and transaction - await ctx.CommitTransactionAsync(); - //Return the number of elements add to the collection - return collection.Count - previous; - } - - /// - /// Builds a query to get a count of records constrained by the specifier - /// - /// The active context to run the query on - /// The specifier constrain - /// A query that can be counted - protected virtual IQueryable GetCollectionQueryBuilder(TransactionalDbContext context, string specifier) - { - return GetCollectionQueryBuilder(context, new string[] { specifier }); - } - - /// - /// Builds a query to get a collection of records based on an variable length array of parameters - /// - /// The active context to run the query on - /// An arguments array to constrain the results of the query - /// A query that returns a collection of records from the store - protected abstract IQueryable GetCollectionQueryBuilder(TransactionalDbContext context, params string[] constraints); - - #endregion - - #region Get Count - /// - public virtual async Task GetCountAsync() - { - //Open db connection - await using TransactionalDbContext ctx = NewContext(); - //Open transaction - await ctx.OpenTransactionAsync(); - //Async get the number of records of the given entity type - long count = await ctx.Set().LongCountAsync(); - //close db and transaction - await ctx.CommitTransactionAsync(); - return count; - } - /// - public virtual async Task GetCountAsync(string specifier) - { - await using TransactionalDbContext ctx = NewContext(); - //Open transaction - await ctx.OpenTransactionAsync(); - //Async get the number of records of the given entity type - long count = await GetCountQueryBuilder(ctx, specifier).LongCountAsync(); - //close db and transaction - await ctx.CommitTransactionAsync(); - return count; - } - - /// - /// Builds a query to get a count of records constrained by the specifier - /// - /// The active context to run the query on - /// The specifier constrain - /// A query that can be counted - protected virtual IQueryable GetCountQueryBuilder(TransactionalDbContext context, string specifier) - { - //Default use the get collection and just call the count method - return GetCollectionQueryBuilder(context, specifier); - } - #endregion - - #region Get Single - /// - public virtual async Task GetSingleAsync(string key) - { - //Open db connection - await using TransactionalDbContext ctx = NewContext(); - //Open transaction - await ctx.OpenTransactionAsync(); - //Get the single template by its id - T? record = await (from entry in ctx.Set() - where entry.Id == key - select entry) - .SingleOrDefaultAsync(); - //close db and transaction - await ctx.CommitTransactionAsync(); - return record; - } - /// - public virtual async Task GetSingleAsync(T record) - { - //Open db connection - await using TransactionalDbContext ctx = NewContext(); - //Open transaction - await ctx.OpenTransactionAsync(); - //Get the single template by its id - T? entry = await GetSingleQueryBuilder(ctx, record).SingleOrDefaultAsync(); - //close db and transaction - await ctx.CommitTransactionAsync(); - return record; - } - /// - public virtual async Task GetSingleAsync(params string[] specifiers) - { - //Open db connection - await using TransactionalDbContext ctx = NewContext(); - //Open transaction - await ctx.OpenTransactionAsync(); - //Get the single template by its id - T? record = await GetSingleQueryBuilder(ctx, specifiers).SingleOrDefaultAsync(); - //close db and transaction - await ctx.CommitTransactionAsync(); - return record; - } - /// - /// Builds a query to get a single record from the variable length parameter arguments - /// - /// The context to execute query against - /// Arguments to constrain the results of the query to a single record - /// A query that yields a single record - protected abstract IQueryable GetSingleQueryBuilder(TransactionalDbContext context, params string[] constraints); - /// - /// - /// Builds a query to get a single record from the specified record. - /// - /// - /// Unless overridden, performs an ID based query for a single entry - /// - /// - /// The context to execute query against - /// A record to referrence the lookup - /// A query that yields a single record - protected virtual IQueryable GetSingleQueryBuilder(TransactionalDbContext context, T record) - { - return from entry in context.Set() - where entry.Id == record.Id - select entry; - } - #endregion - - #region Get Page - /// - public virtual async Task GetPageAsync(ICollection collection, int page, int limit) - { - //Store preivous count - int previous = collection.Count; - //Open db connection - await using TransactionalDbContext ctx = NewContext(); - //Open transaction - await ctx.OpenTransactionAsync(); - //Get a page offset and a limit for the - await ctx.Set() - .Skip(page * limit) - .Take(limit) - .Select(static p => p) - .ForEachAsync(collection.Add); - - //close db and transaction - await ctx.CommitTransactionAsync(); - //Return the number of records added - return collection.Count - previous; - } - /// - public virtual async Task GetPageAsync(ICollection collection, int page, int limit, params string[] constraints) - { - //Store preivous count - int previous = collection.Count; - //Open new db context - await using TransactionalDbContext ctx = NewContext(); - //Open transaction - await ctx.OpenTransactionAsync(); - //Get the single template by its id - await GetPageQueryBuilder(ctx, constraints) - .Skip(page * limit) - .Take(limit) - .Select(static e => e) - .ForEachAsync(collection.Add); - - //close db and transaction - await ctx.CommitTransactionAsync(); - //Return the number of records added - return collection.Count - previous; - } - /// - /// Builds a query to get a collection of records based on an variable length array of parameters - /// - /// The active context to run the query on - /// An arguments array to constrain the results of the query - /// A query that returns a paginated collection of records from the store - protected virtual IQueryable GetPageQueryBuilder(TransactionalDbContext context, params string[] constraints) - { - //Default to getting the entire collection and just selecting a single page - return GetCollectionQueryBuilder(context, constraints); - } - #endregion - } -} -- cgit