aboutsummaryrefslogtreecommitdiff
path: root/VNLib.Plugins.Extensions.Data
diff options
context:
space:
mode:
authorLibravatar vnugent <public@vaughnnugent.com>2023-01-09 15:09:13 -0500
committerLibravatar vnugent <public@vaughnnugent.com>2023-01-09 15:09:13 -0500
commita46c3bf452d287b50b2e7dd5a24f5995c9fd26f6 (patch)
tree3a978b2dd2887b5c0e25f595516594a647d8e880 /VNLib.Plugins.Extensions.Data
parent189c6714057bf45553847eaeb9ce97eb7272eb8c (diff)
Restructure
Diffstat (limited to 'VNLib.Plugins.Extensions.Data')
-rw-r--r--VNLib.Plugins.Extensions.Data/Abstractions/IBulkDataStore.cs65
-rw-r--r--VNLib.Plugins.Extensions.Data/Abstractions/IDataStore.cs123
-rw-r--r--VNLib.Plugins.Extensions.Data/Abstractions/IPaginatedDataStore.cs56
-rw-r--r--VNLib.Plugins.Extensions.Data/Abstractions/IUserEntity.cs39
-rw-r--r--VNLib.Plugins.Extensions.Data/DbModelBase.cs48
-rw-r--r--VNLib.Plugins.Extensions.Data/DbStore.cs507
-rw-r--r--VNLib.Plugins.Extensions.Data/Extensions.cs81
-rw-r--r--VNLib.Plugins.Extensions.Data/IDbModel.cs52
-rw-r--r--VNLib.Plugins.Extensions.Data/ProtectedDbStore.cs70
-rw-r--r--VNLib.Plugins.Extensions.Data/ProtectedEntityExtensions.cs86
-rw-r--r--VNLib.Plugins.Extensions.Data/SQL/DbExtensions.cs521
-rw-r--r--VNLib.Plugins.Extensions.Data/SQL/EnumerableTable.cs118
-rw-r--r--VNLib.Plugins.Extensions.Data/SQL/SqlColumnNameAttribute.cs54
-rw-r--r--VNLib.Plugins.Extensions.Data/SQL/SqlTableNameAttribute.cs40
-rw-r--r--VNLib.Plugins.Extensions.Data/SQL/SqlVariable.cs58
-rw-r--r--VNLib.Plugins.Extensions.Data/SQL/TableManager.cs66
-rw-r--r--VNLib.Plugins.Extensions.Data/Storage/Blob.cs244
-rw-r--r--VNLib.Plugins.Extensions.Data/Storage/BlobExtensions.cs67
-rw-r--r--VNLib.Plugins.Extensions.Data/Storage/BlobStore.cs162
-rw-r--r--VNLib.Plugins.Extensions.Data/Storage/LWDecriptorCreationException.cs45
-rw-r--r--VNLib.Plugins.Extensions.Data/Storage/LWStorageContext.cs48
-rw-r--r--VNLib.Plugins.Extensions.Data/Storage/LWStorageDescriptor.cs230
-rw-r--r--VNLib.Plugins.Extensions.Data/Storage/LWStorageEntry.cs44
-rw-r--r--VNLib.Plugins.Extensions.Data/Storage/LWStorageManager.cs347
-rw-r--r--VNLib.Plugins.Extensions.Data/Storage/LWStorageRemoveFailedException.cs44
-rw-r--r--VNLib.Plugins.Extensions.Data/Storage/LWStorageUpdateFailedException.cs43
-rw-r--r--VNLib.Plugins.Extensions.Data/Storage/UndefinedBlobStateException.cs45
-rw-r--r--VNLib.Plugins.Extensions.Data/TransactionalDbContext.cs99
-rw-r--r--VNLib.Plugins.Extensions.Data/VNLib.Plugins.Extensions.Data.csproj54
-rw-r--r--VNLib.Plugins.Extensions.Data/VNLib.Plugins.Extensions.Data.xml476
30 files changed, 0 insertions, 3932 deletions
diff --git a/VNLib.Plugins.Extensions.Data/Abstractions/IBulkDataStore.cs b/VNLib.Plugins.Extensions.Data/Abstractions/IBulkDataStore.cs
deleted file mode 100644
index b644ec3..0000000
--- a/VNLib.Plugins.Extensions.Data/Abstractions/IBulkDataStore.cs
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Plugins.Extensions.Data
-* File: IBulkDataStore.cs
-*
-* IBulkDataStore.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.Collections.Generic;
-using System.Threading.Tasks;
-
-using VNLib.Utils;
-
-namespace VNLib.Plugins.Extensions.Data.Abstractions
-{
- /// <summary>
- /// An abstraction that defines a Data-Store that supports
- /// bulk data operations
- /// </summary>
- /// <typeparam name="T">The data-model type</typeparam>
- public interface IBulkDataStore<T>
- {
- /// <summary>
- /// Deletes a collection of records from the store
- /// </summary>
- /// <param name="records">A collection of records to delete</param>
- ///<returns>A task the resolves the number of entires removed from the store</returns>
- Task<ERRNO> DeleteBulkAsync(ICollection<T> records);
- /// <summary>
- /// Updates a collection of records
- /// </summary>
- /// <param name="records">The collection of records to update</param>
- /// <returns>A task the resolves an error code (should evaluate to false on failure, and true on success)</returns>
- Task<ERRNO> UpdateBulkAsync(ICollection<T> records);
- /// <summary>
- /// Creates a bulk collection of records as entries in the store
- /// </summary>
- /// <param name="records">The collection of records to add</param>
- /// <returns>A task the resolves an error code (should evaluate to false on failure, and true on success)</returns>
- Task<ERRNO> CreateBulkAsync(ICollection<T> records);
- /// <summary>
- /// Creates or updates individual records from a bulk collection of records
- /// </summary>
- /// <param name="records">The collection of records to add</param>
- /// <returns>A task the resolves an error code (should evaluate to false on failure, and true on success)</returns>
- Task<ERRNO> AddOrUpdateBulkAsync(ICollection<T> records);
- }
-
-}
diff --git a/VNLib.Plugins.Extensions.Data/Abstractions/IDataStore.cs b/VNLib.Plugins.Extensions.Data/Abstractions/IDataStore.cs
deleted file mode 100644
index 4ab62bf..0000000
--- a/VNLib.Plugins.Extensions.Data/Abstractions/IDataStore.cs
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Plugins.Extensions.Data
-* File: IDataStore.cs
-*
-* IDataStore.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.Threading.Tasks;
-using System.Collections.Generic;
-
-using VNLib.Utils;
-
-namespace VNLib.Plugins.Extensions.Data.Abstractions
-{
- /// <summary>
- /// An abstraction that defines a Data-Store and common
- /// operations that retrieve or manipulate records of data
- /// </summary>
- /// <typeparam name="T">The data-model type</typeparam>
- public interface IDataStore<T>
- {
- /// <summary>
- /// Gets the total number of records in the current store
- /// </summary>
- /// <returns>A task that resolves the number of records in the store</returns>
- Task<long> GetCountAsync();
- /// <summary>
- /// Gets the number of records that belong to the specified constraint
- /// </summary>
- /// <param name="specifier">A specifier to constrain the reults</param>
- /// <returns>The number of records that belong to the specifier</returns>
- Task<long> GetCountAsync(string specifier);
- /// <summary>
- /// Gets a record from its key
- /// </summary>
- /// <param name="key">The key identifying the unique record</param>
- /// <returns>A promise that resolves the record identified by the specified key</returns>
- Task<T?> GetSingleAsync(string key);
- /// <summary>
- /// Gets a record from its key
- /// </summary>
- /// <param name="specifiers">A variable length specifier arguemnt array for retreiving a single application</param>
- /// <returns></returns>
- Task<T?> GetSingleAsync(params string[] specifiers);
- /// <summary>
- /// Gets a record from the store with a partial model, intended to complete the model
- /// </summary>
- /// <param name="record">The partial model used to query the store</param>
- /// <returns>A task the resolves the completed data-model</returns>
- Task<T?> GetSingleAsync(T record);
- /// <summary>
- /// Fills a collection with enires retireved from the store using the specifer
- /// </summary>
- /// <param name="collection">The collection to add entires to</param>
- /// <param name="specifier">A specifier argument to constrain results</param>
- /// <param name="limit">The maximum number of elements to retrieve</param>
- /// <returns>A Task the resolves to the number of items added to the collection</returns>
- Task<ERRNO> GetCollectionAsync(ICollection<T> collection, string specifier, int limit);
- /// <summary>
- /// Fills a collection with enires retireved from the store using a variable length specifier
- /// parameter
- /// </summary>
- /// <param name="collection">The collection to add entires to</param>
- /// <param name="limit">The maximum number of elements to retrieve</param>
- /// <param name="args"></param>
- /// <returns>A Task the resolves to the number of items added to the collection</returns>
- Task<ERRNO> GetCollectionAsync(ICollection<T> collection, int limit, params string[] args);
- /// <summary>
- /// Updates an entry in the store with the specified record
- /// </summary>
- /// <param name="record">The record to update</param>
- /// <returns>A task the resolves an error code (should evaluate to false on failure, and true on success)</returns>
- Task<ERRNO> UpdateAsync(T record);
- /// <summary>
- /// Creates a new entry in the store representing the specified record
- /// </summary>
- /// <param name="record">The record to add to the store</param>
- /// <returns>A task the resolves an error code (should evaluate to false on failure, and true on success)</returns>
- Task<ERRNO> CreateAsync(T record);
- /// <summary>
- /// Deletes one or more entrires from the store matching the specified record
- /// </summary>
- /// <param name="record">The record to remove from the store</param>
- /// <returns>A task the resolves the number of records removed(should evaluate to false on failure, and deleted count on success)</returns>
- Task<ERRNO> DeleteAsync(T record);
- /// <summary>
- /// Deletes one or more entires from the store matching the specified unique key
- /// </summary>
- /// <param name="key">The unique key that identifies the record</param>
- /// <returns>A task the resolves the number of records removed(should evaluate to false on failure, and deleted count on success)</returns>
- Task<ERRNO> DeleteAsync(string key);
- /// <summary>
- /// Deletes one or more entires from the store matching the supplied specifiers
- /// </summary>
- /// <param name="specifiers">A variable length array of specifiers used to delete one or more entires</param>
- /// <returns>A task the resolves the number of records removed(should evaluate to false on failure, and deleted count on success)</returns>
- Task<ERRNO> DeleteAsync(params string[] specifiers);
- /// <summary>
- /// Updates an entry in the store if it exists, or creates a new entry if one does not already exist
- /// </summary>
- /// <param name="record">The record to add to the store</param>
- /// <returns>A task the resolves the result of the operation</returns>
- Task<ERRNO> AddOrUpdateAsync(T record);
- }
-}
diff --git a/VNLib.Plugins.Extensions.Data/Abstractions/IPaginatedDataStore.cs b/VNLib.Plugins.Extensions.Data/Abstractions/IPaginatedDataStore.cs
deleted file mode 100644
index 4a9cb89..0000000
--- a/VNLib.Plugins.Extensions.Data/Abstractions/IPaginatedDataStore.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Plugins.Extensions.Data
-* File: IPaginatedDataStore.cs
-*
-* IPaginatedDataStore.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.Collections.Generic;
-using System.Threading.Tasks;
-
-namespace VNLib.Plugins.Extensions.Data.Abstractions
-{
- /// <summary>
- /// Defines a Data-Store that can retirieve and manipulate paginated
- /// data
- /// </summary>
- /// <typeparam name="T">The data-model type</typeparam>
- public interface IPaginatedDataStore<T>
- {
- /// <summary>
- /// Gets a collection of records using a pagination style query, and adds the records to the collecion
- /// </summary>
- /// <param name="collection">The collection to add records to</param>
- /// <param name="page">Pagination page to get records from</param>
- /// <param name="limit">The maximum number of items to retrieve from the store</param>
- /// <returns>A task that resolves the number of items added to the collection</returns>
- Task<int> GetPageAsync(ICollection<T> collection, int page, int limit);
- /// <summary>
- /// Gets a collection of records using a pagination style query with constraint arguments, and adds the records to the collecion
- /// </summary>
- /// <param name="collection">The collection to add records to</param>
- /// <param name="page">Pagination page to get records from</param>
- /// <param name="limit">The maximum number of items to retrieve from the store</param>
- /// <param name="constraints">A params array of strings to constrain the result set from the db</param>
- /// <returns>A task that resolves the number of items added to the collection</returns>
- Task<int> GetPageAsync(ICollection<T> collection, int page, int limit, params string[] constraints);
- }
-
-}
diff --git a/VNLib.Plugins.Extensions.Data/Abstractions/IUserEntity.cs b/VNLib.Plugins.Extensions.Data/Abstractions/IUserEntity.cs
deleted file mode 100644
index aaca7c0..0000000
--- a/VNLib.Plugins.Extensions.Data/Abstractions/IUserEntity.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Plugins.Extensions.Data
-* File: IUserEntity.cs
-*
-* IUserEntity.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;
-
-namespace VNLib.Plugins.Extensions.Data.Abstractions
-{
- /// <summary>
- /// Defines an entity base that has an owner, identified by its user-id
- /// </summary>
- public interface IUserEntity
- {
- /// <summary>
- /// The user-id of the owner of the entity
- /// </summary>
- string? UserId { get; set; }
- }
-}
diff --git a/VNLib.Plugins.Extensions.Data/DbModelBase.cs b/VNLib.Plugins.Extensions.Data/DbModelBase.cs
deleted file mode 100644
index b48231b..0000000
--- a/VNLib.Plugins.Extensions.Data/DbModelBase.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Plugins.Extensions.Data
-* File: DbModelBase.cs
-*
-* DbModelBase.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.ComponentModel.DataAnnotations;
-using System.Text.Json.Serialization;
-
-namespace VNLib.Plugins.Extensions.Data
-{
- /// <summary>
- /// Provides a base for DBSet Records with a timestamp/version
- /// a unique ID key, and create/modified timestamps
- /// </summary>
- public abstract class DbModelBase : IDbModel
- {
- ///<inheritdoc/>
- public abstract string Id { get; set; }
- ///<inheritdoc/>
- [Timestamp]
- [JsonIgnore]
- public virtual byte[]? Version { get; set; }
- ///<inheritdoc/>
- public abstract DateTime Created { get; set; }
- ///<inheritdoc/>
- public abstract DateTime LastModified { get; set; }
- }
-}
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
-{
- /// <summary>
- /// Implements basic data-store functionality with abstract query builders
- /// </summary>
- /// <typeparam name="T">A <see cref="DbModelBase"/> implemented type</typeparam>
- public abstract class DbStore<T> : IDataStore<T>, IPaginatedDataStore<T> where T: class, IDbModel
- {
- /// <summary>
- /// Gets a unique ID for a new record being added to the store
- /// </summary>
- public abstract string RecordIdBuilder { get; }
- /// <summary>
- /// Gets a new <see cref="TransactionalDbContext"/> ready for use
- /// </summary>
- /// <returns></returns>
- public abstract TransactionalDbContext NewContext();
-
- /// <summary>
- /// An object rental for entity collections
- /// </summary>
- public ObjectRental<List<T>> ListRental { get; } = ObjectRental.Create<List<T>>(null, static ret => ret.Clear());
-
- #region Add Or Update
- ///<inheritdoc/>
- public virtual async Task<ERRNO> AddOrUpdateAsync(T record)
- {
- //Open new db context
- await using TransactionalDbContext ctx = NewContext();
- //Open transaction
- await ctx.OpenTransactionAsync();
- IQueryable<T> query;
- if (string.IsNullOrWhiteSpace(record.Id))
- {
- //Get the application
- query = AddOrUpdateQueryBuilder(ctx, record);
- }
- else
- {
- //Get the application
- query = (from et in ctx.Set<T>()
- 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;
- }
- ///<inheritdoc/>
- public virtual async Task<ERRNO> UpdateAsync(T record)
- {
- //Open new db context
- await using TransactionalDbContext ctx = NewContext();
- //Open transaction
- await ctx.OpenTransactionAsync();
- //Get the application
- IQueryable<T> 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;
- }
- ///<inheritdoc/>
- public virtual async Task<ERRNO> 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;
- }
-
- /// <summary>
- /// 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 <see cref="DbModelBase.Id"/> property
- /// </summary>
- /// <param name="context">The active context to query</param>
- /// <param name="record">The record to search for</param>
- /// <returns>A query that yields a single record if it exists in the store</returns>
- protected virtual IQueryable<T> AddOrUpdateQueryBuilder(TransactionalDbContext context, T record)
- {
- //default to get single of the specific record
- return GetSingleQueryBuilder(context, record);
- }
- /// <summary>
- /// Builds a query that attempts to get a single entry from the
- /// store to update based on the specified record
- /// </summary>
- /// <param name="context">The active context to query</param>
- /// <param name="record">The record to search for</param>
- /// <returns>A query that yields a single record to update if it exists in the store</returns>
- protected virtual IQueryable<T> UpdateQueryBuilder(TransactionalDbContext context, T record)
- {
- //default to get single of the specific record
- return GetSingleQueryBuilder(context, record);
- }
- /// <summary>
- /// Updates the current record (if found) to the new record before
- /// storing the updates.
- /// </summary>
- /// <param name="newRecord">The new record to capture data from</param>
- /// <param name="currentRecord">The current record to be updated</param>
- protected abstract void OnRecordUpdate(T newRecord, T currentRecord);
- #endregion
-
- #region Delete
- ///<inheritdoc/>
- public virtual async Task<ERRNO> DeleteAsync(string key)
- {
- //Open new db context
- await using TransactionalDbContext ctx = NewContext();
- //Open transaction
- await ctx.OpenTransactionAsync();
- //Get the template by its id
- IQueryable<T> query = (from temp in ctx.Set<T>()
- 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;
- }
- ///<inheritdoc/>
- public virtual async Task<ERRNO> 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<T> 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;
- }
- ///<inheritdoc/>
- public virtual async Task<ERRNO> 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<T> 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;
- }
-
- /// <summary>
- /// Builds a query that results in a single entry to delete from the
- /// constraint arguments
- /// </summary>
- /// <param name="context">The active context</param>
- /// <param name="constraints">A variable length parameter array of query constraints</param>
- /// <returns>A query that yields a single record (or no record) to delete</returns>
- protected virtual IQueryable<T> 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
- ///<inheritdoc/>
- public virtual async Task<ERRNO> GetCollectionAsync(ICollection<T> 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;
- }
- ///<inheritdoc/>
- public virtual async Task<ERRNO> GetCollectionAsync(ICollection<T> 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;
- }
-
- /// <summary>
- /// Builds a query to get a count of records constrained by the specifier
- /// </summary>
- /// <param name="context">The active context to run the query on</param>
- /// <param name="specifier">The specifier constrain</param>
- /// <returns>A query that can be counted</returns>
- protected virtual IQueryable<T> GetCollectionQueryBuilder(TransactionalDbContext context, string specifier)
- {
- return GetCollectionQueryBuilder(context, new string[] { specifier });
- }
-
- /// <summary>
- /// Builds a query to get a collection of records based on an variable length array of parameters
- /// </summary>
- /// <param name="context">The active context to run the query on</param>
- /// <param name="constraints">An arguments array to constrain the results of the query</param>
- /// <returns>A query that returns a collection of records from the store</returns>
- protected abstract IQueryable<T> GetCollectionQueryBuilder(TransactionalDbContext context, params string[] constraints);
-
- #endregion
-
- #region Get Count
- ///<inheritdoc/>
- public virtual async Task<long> 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<T>().LongCountAsync();
- //close db and transaction
- await ctx.CommitTransactionAsync();
- return count;
- }
- ///<inheritdoc/>
- public virtual async Task<long> 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;
- }
-
- /// <summary>
- /// Builds a query to get a count of records constrained by the specifier
- /// </summary>
- /// <param name="context">The active context to run the query on</param>
- /// <param name="specifier">The specifier constrain</param>
- /// <returns>A query that can be counted</returns>
- protected virtual IQueryable<T> GetCountQueryBuilder(TransactionalDbContext context, string specifier)
- {
- //Default use the get collection and just call the count method
- return GetCollectionQueryBuilder(context, specifier);
- }
- #endregion
-
- #region Get Single
- ///<inheritdoc/>
- public virtual async Task<T?> 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<T>()
- where entry.Id == key
- select entry)
- .SingleOrDefaultAsync();
- //close db and transaction
- await ctx.CommitTransactionAsync();
- return record;
- }
- ///<inheritdoc/>
- public virtual async Task<T?> 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;
- }
- ///<inheritdoc/>
- public virtual async Task<T?> 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;
- }
- /// <summary>
- /// Builds a query to get a single record from the variable length parameter arguments
- /// </summary>
- /// <param name="context">The context to execute query against</param>
- /// <param name="constraints">Arguments to constrain the results of the query to a single record</param>
- /// <returns>A query that yields a single record</returns>
- protected abstract IQueryable<T> GetSingleQueryBuilder(TransactionalDbContext context, params string[] constraints);
- /// <summary>
- /// <para>
- /// Builds a query to get a single record from the specified record.
- /// </para>
- /// <para>
- /// Unless overridden, performs an ID based query for a single entry
- /// </para>
- /// </summary>
- /// <param name="context">The context to execute query against</param>
- /// <param name="record">A record to referrence the lookup</param>
- /// <returns>A query that yields a single record</returns>
- protected virtual IQueryable<T> GetSingleQueryBuilder(TransactionalDbContext context, T record)
- {
- return from entry in context.Set<T>()
- where entry.Id == record.Id
- select entry;
- }
- #endregion
-
- #region Get Page
- ///<inheritdoc/>
- public virtual async Task<int> GetPageAsync(ICollection<T> 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<T>()
- .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;
- }
- ///<inheritdoc/>
- public virtual async Task<int> GetPageAsync(ICollection<T> 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;
- }
- /// <summary>
- /// Builds a query to get a collection of records based on an variable length array of parameters
- /// </summary>
- /// <param name="context">The active context to run the query on</param>
- /// <param name="constraints">An arguments array to constrain the results of the query</param>
- /// <returns>A query that returns a paginated collection of records from the store</returns>
- protected virtual IQueryable<T> GetPageQueryBuilder(TransactionalDbContext context, params string[] constraints)
- {
- //Default to getting the entire collection and just selecting a single page
- return GetCollectionQueryBuilder(context, constraints);
- }
- #endregion
- }
-}
diff --git a/VNLib.Plugins.Extensions.Data/Extensions.cs b/VNLib.Plugins.Extensions.Data/Extensions.cs
deleted file mode 100644
index 1e0c8de..0000000
--- a/VNLib.Plugins.Extensions.Data/Extensions.cs
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Plugins.Extensions.Data
-* File: Extensions.cs
-*
-* Extensions.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.Linq;
-using System.Threading.Tasks;
-using System.Collections.Generic;
-
-using Microsoft.EntityFrameworkCore;
-
-using VNLib.Utils;
-using VNLib.Plugins.Extensions.Data.Abstractions;
-
-namespace VNLib.Plugins.Extensions.Data
-{
- public static class Extensions
- {
-
- public static int GetPageOrDefault(this IReadOnlyDictionary<string, string> queryArgs, int @default, int minClamp = 0, int maxClamp = int.MaxValue)
- {
- return queryArgs.TryGetValue("page", out string? pageStr) && int.TryParse(pageStr, out int page) ? Math.Clamp(page, minClamp, maxClamp) : @default;
- }
-
- public static int GetLimitOrDefault(this IReadOnlyDictionary<string, string> queryArgs, int @default, int minClamp = 0, int maxClamp = int.MaxValue)
- {
- return queryArgs.TryGetValue("limit", out string? limitStr) && int.TryParse(limitStr, out int limit) ? Math.Clamp(limit, minClamp, maxClamp) : @default;
- }
-
- public static async Task<ERRNO> AddBulkAsync<TEntity>(this DbStore<TEntity> store, IEnumerable<TEntity> records, string userId, bool overwriteTime = true)
- where TEntity : class, IDbModel, IUserEntity
- {
- //Open context and transaction
- await using TransactionalDbContext database = store.NewContext();
- await database.OpenTransactionAsync();
- //Get the entity set
- DbSet<TEntity> set = database.Set<TEntity>();
- //Generate random ids for the feeds and set user-id
- foreach (TEntity entity in records)
- {
- entity.Id = store.RecordIdBuilder;
- //Explicitly assign the user-id
- entity.UserId = userId;
- //If the entity has the default created time, update it, otherwise leave it as is
- if (overwriteTime || entity.Created == default)
- {
- entity.Created = DateTime.UtcNow;
- }
- //Update last-modified time
- entity.LastModified = DateTime.UtcNow;
- }
- //Add feeds to database
- set.AddRange(records);
- //Commit changes
- ERRNO count = await database.SaveChangesAsync();
- //Commit transaction and exit
- await database.CommitTransactionAsync();
- return count;
- }
- }
-}
diff --git a/VNLib.Plugins.Extensions.Data/IDbModel.cs b/VNLib.Plugins.Extensions.Data/IDbModel.cs
deleted file mode 100644
index 8dbc2e4..0000000
--- a/VNLib.Plugins.Extensions.Data/IDbModel.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Plugins.Extensions.Data
-* File: IDbModel.cs
-*
-* IDbModel.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;
-
-namespace VNLib.Plugins.Extensions.Data
-{
- /// <summary>
- /// Represents a basic data model for an EFCore entity
- /// for support in data-stores
- /// </summary>
- public interface IDbModel
- {
- /// <summary>
- /// A unique id for the entity
- /// </summary>
- string Id { get; set; }
- /// <summary>
- /// The <see cref="DateTime"/> the entity was created in the store
- /// </summary>
- DateTime Created { get; set; }
- /// <summary>
- /// The <see cref="DateTime"/> the entity was last modified in the store
- /// </summary>
- DateTime LastModified { get; set; }
- /// <summary>
- /// Entity concurrency token
- /// </summary>
- byte[]? Version { get; set; }
- }
-} \ No newline at end of file
diff --git a/VNLib.Plugins.Extensions.Data/ProtectedDbStore.cs b/VNLib.Plugins.Extensions.Data/ProtectedDbStore.cs
deleted file mode 100644
index 654d52c..0000000
--- a/VNLib.Plugins.Extensions.Data/ProtectedDbStore.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Plugins.Extensions.Data
-* File: ProtectedDbStore.cs
-*
-* ProtectedDbStore.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.Linq;
-
-using VNLib.Plugins.Extensions.Data.Abstractions;
-
-namespace VNLib.Plugins.Extensions.Data
-{
-#nullable enable
- /// <summary>
- /// A data store that provides unique identities and protections based on an entity that has an owner <see cref="IUserEntity"/>
- /// </summary>
- public abstract class ProtectedDbStore<TEntity> : DbStore<TEntity> where TEntity : class, IDbModel, IUserEntity
- {
- ///<inheritdoc/>
- protected override IQueryable<TEntity> GetCollectionQueryBuilder(TransactionalDbContext context, params string[] constraints)
- {
- string userId = constraints[0];
- //Query items for the user and its id
- return from item in context.Set<TEntity>()
- where item.UserId == userId
- orderby item.Created descending
- select item;
- }
-
- /// <summary>
- /// Gets a single item contrained by a given user-id and item id
- /// </summary>
- /// <param name="context"></param>
- /// <param name="constraints"></param>
- /// <returns></returns>
- protected override IQueryable<TEntity> GetSingleQueryBuilder(TransactionalDbContext context, params string[] constraints)
- {
- string key = constraints[0];
- string userId = constraints[1];
- //Query items for the user and its id
- return from item in context.Set<TEntity>()
- where item.Id == key && item.UserId == userId
- select item;
- }
- ///<inheritdoc/>
- protected override IQueryable<TEntity> GetSingleQueryBuilder(TransactionalDbContext context, TEntity record)
- {
- return this.GetSingleQueryBuilder(context, record.Id, record.UserId);
- }
- }
-}
diff --git a/VNLib.Plugins.Extensions.Data/ProtectedEntityExtensions.cs b/VNLib.Plugins.Extensions.Data/ProtectedEntityExtensions.cs
deleted file mode 100644
index 7c4f4a3..0000000
--- a/VNLib.Plugins.Extensions.Data/ProtectedEntityExtensions.cs
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Plugins.Extensions.Data
-* File: ProtectedEntityExtensions.cs
-*
-* ProtectedEntityExtensions.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.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-using VNLib.Utils;
-using VNLib.Plugins.Extensions.Data.Abstractions;
-
-namespace VNLib.Plugins.Extensions.Data
-{
- public static class ProtectedEntityExtensions
- {
- /// <summary>
- /// Updates the specified record within the store
- /// </summary>
- /// <param name="store"></param>
- /// <param name="record">The record to update</param>
- /// <param name="userId">The userid of the record owner</param>
- /// <returns>A task that evaluates to the number of records modified</returns>
- public static Task<ERRNO> UpdateAsync<TEntity>(this IDataStore<TEntity> store, TEntity record, string userId) where TEntity : class, IDbModel, IUserEntity
- {
- record.UserId = userId;
- return store.UpdateAsync(record);
- }
-
- /// <summary>
- /// Updates the specified record within the store
- /// </summary>
- /// <param name="store"></param>
- /// <param name="record">The record to update</param>
- /// <param name="userId">The userid of the record owner</param>
- /// <returns>A task that evaluates to the number of records modified</returns>
- public static Task<ERRNO> CreateAsync<TEntity>(this IDataStore<TEntity> store, TEntity record, string userId) where TEntity : class, IDbModel, IUserEntity
- {
- record.UserId = userId;
- return store.CreateAsync(record);
- }
-
- /// <summary>
- /// Gets a single entity from its ID and user-id
- /// </summary>
- /// <param name="store"></param>
- /// <param name="key">The unique id of the entity</param>
- /// <param name="userId">The user's id that owns the resource</param>
- /// <returns>A task that resolves the entity or null if not found</returns>
- public static Task<TEntity?> GetSingleAsync<TEntity>(this IDataStore<TEntity> store, string key, string userId) where TEntity : class, IDbModel, IUserEntity
- {
- return store.GetSingleAsync(key, userId);
- }
-
- /// <summary>
- /// Deletes a single entiry by its ID only if it belongs to the speicifed user
- /// </summary>
- /// <param name="store"></param>
- /// <param name="key">The unique id of the entity</param>
- /// <param name="userId">The user's id that owns the resource</param>
- /// <returns>A task the resolves the number of eneities deleted (should evaluate to true or false)</returns>
- public static Task<ERRNO> DeleteAsync<TEntity>(this IDataStore<TEntity> store, string key, string userId) where TEntity : class, IDbModel, IUserEntity
- {
- return store.DeleteAsync(key, userId);
- }
- }
-}
diff --git a/VNLib.Plugins.Extensions.Data/SQL/DbExtensions.cs b/VNLib.Plugins.Extensions.Data/SQL/DbExtensions.cs
deleted file mode 100644
index 1f9164e..0000000
--- a/VNLib.Plugins.Extensions.Data/SQL/DbExtensions.cs
+++ /dev/null
@@ -1,521 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Plugins.Extensions.Data
-* File: DbExtensions.cs
-*
-* DbExtensions.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.Data;
-using System.Reflection;
-using System.Data.Common;
-using System.Threading.Tasks;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-
-using VNLib.Utils;
-using VNLib.Utils.Memory.Caching;
-
-namespace VNLib.Plugins.Extensions.Data.SQL
-{
- /// <summary>
- /// Provides basic extension methods for ADO.NET abstract classes
- /// for rapid development
- /// </summary>
- public static class DbExtensions
- {
- /*
- * Object rental for propery dictionaries used for custom result objects
- */
- private static ObjectRental<Dictionary<string, PropertyInfo>> DictStore { get; } = ObjectRental.Create<Dictionary<string, PropertyInfo>>(null, static dict => dict.Clear(), 20);
-
-
- /// <summary>
- /// Creates a new <see cref="DbParameter"/> configured for <see cref="ParameterDirection.Input"/> with the specified value
- /// and adds it to the command.
- /// </summary>
- /// <param name="cmd"></param>
- /// <param name="name">The parameter name</param>
- /// <param name="value">The value of the parameter</param>
- /// <param name="type">The <see cref="DbType"/> of the column</param>
- /// <param name="nullable">Are null types allowed in the value parameter</param>
- /// <returns>The created parameter</returns>
- public static DbParameter AddParameter<T>(this DbCommand cmd, string @name, T @value, DbType @type, bool @nullable = false)
- {
- //Create the new parameter from command
- DbParameter param = cmd.CreateParameter();
- //Set parameter variables
- param.ParameterName = name;
- param.Value = value;
- param.DbType = type;
- //Force non null mapping
- param.SourceColumnNullMapping = nullable;
- //Specify input parameter
- param.Direction = ParameterDirection.Input;
- //Add param to list
- cmd.Parameters.Add(param);
- return param;
- }
- /// <summary>
- /// Creates a new <see cref="DbParameter"/> configured for <see cref="ParameterDirection.Input"/> with the specified value
- /// and adds it to the command.
- /// </summary>
- /// <param name="cmd"></param>
- /// <param name="name">The parameter name</param>
- /// <param name="value">The value of the parameter</param>
- /// <param name="type">The <see cref="DbType"/> of the column</param>
- /// <param name="size">Size of the data value</param>
- /// <param name="nullable">Are null types allowed in the value parameter</param>
- /// <returns>The created parameter</returns>
- public static DbParameter AddParameter<T>(this DbCommand cmd, string @name, T @value, DbType @type, int @size, bool @nullable = false)
- {
- DbParameter param = AddParameter(cmd, name, value, type, nullable);
- //Set size parameter
- param.Size = size;
- return param;
- }
- /// <summary>
- /// Creates a new <see cref="DbParameter"/> configured for <see cref="ParameterDirection.Output"/> with the specified value
- /// and adds it to the command.
- /// </summary>
- /// <param name="cmd"></param>
- /// <param name="name">The parameter name</param>
- /// <param name="value">The value of the parameter</param>
- /// <param name="type">The <see cref="DbType"/> of the column</param>
- /// <param name="nullable">Are null types allowed in the value parameter</param>
- /// <returns>The created parameter</returns>
- public static DbParameter AddOutParameter<T>(this DbCommand cmd, string @name, T @value, DbType @type, bool @nullable = false)
- {
- //Create the new parameter from command
- DbParameter param = AddParameter(cmd, name, value, type, nullable);
- //Specify output parameter
- param.Direction = ParameterDirection.Output;
- return param;
- }
- /// <summary>
- /// Creates a new <see cref="DbParameter"/> configured for <see cref="ParameterDirection.Output"/> with the specified value
- /// and adds it to the command.
- /// </summary>
- /// <param name="cmd"></param>
- /// <param name="name">The parameter name</param>
- /// <param name="value">The value of the parameter</param>
- /// <param name="type">The <see cref="DbType"/> of the column</param>
- /// <param name="size">Size of the data value</param>
- /// <param name="nullable">Are null types allowed in the value parameter</param>
- /// <returns>The created parameter</returns>
- public static DbParameter AddOutParameter<T>(this DbCommand cmd, string @name, T @value, DbType @type, int @size, bool @nullable = false)
- {
- DbParameter param = AddOutParameter(cmd, name, value, type, nullable);
- //Set size parameter
- param.Size = size;
- return param;
- }
-
- /// <summary>
- /// Creates a new <see cref="DbCommand"/> for <see cref="CommandType.Text"/> with the specified command
- /// </summary>
- /// <param name="db"></param>
- /// <param name="cmdText">The command to run against the connection</param>
- /// <returns>The initalized <see cref="DbCommand"/></returns>
- public static DbCommand CreateTextCommand(this DbConnection db, string cmdText)
- {
- //Create the new command
- DbCommand cmd = db.CreateCommand();
- cmd.CommandText = cmdText;
- cmd.CommandType = CommandType.Text; //Specify text command
- return cmd;
- }
- /// <summary>
- /// Creates a new <see cref="DbCommand"/> for <see cref="CommandType.StoredProcedure"/> with the specified procedure name
- /// </summary>
- /// <param name="db"></param>
- /// <param name="procedureName">The name of the stored proecedure to execute</param>
- /// <returns>The initalized <see cref="DbCommand"/></returns>
- public static DbCommand CreateProcedureCommand(this DbConnection db, string procedureName)
- {
- //Create the new command
- DbCommand cmd = db.CreateCommand();
- cmd.CommandText = procedureName;
- cmd.CommandType = CommandType.StoredProcedure; //Specify stored procedure
- return cmd;
- }
-
- /// <summary>
- /// Creates a new <see cref="DbCommand"/> for <see cref="CommandType.Text"/> with the specified command
- /// on a given transaction
- /// </summary>
- /// <param name="db"></param>
- /// <param name="cmdText">The command to run against the connection</param>
- /// <param name="transaction">The transaction to execute on</param>
- /// <returns>The initalized <see cref="DbCommand"/></returns>
- public static DbCommand CreateTextCommand(this DbConnection db, string cmdText, DbTransaction transaction)
- {
- return CreateCommand(db, transaction, CommandType.Text, cmdText);
- }
- /// <summary>
- /// Shortcut to create a command on a transaction with the specifed command type and command
- /// </summary>
- /// <param name="db"></param>
- /// <param name="transaction">The transaction to complete the operation on</param>
- /// <param name="type">The command type</param>
- /// <param name="command">The command to execute</param>
- /// <returns>The intialized db command</returns>
- public static DbCommand CreateCommand(this DbConnection db, DbTransaction transaction, CommandType type, string command)
- {
- //Create the new command
- DbCommand cmd = db.CreateCommand();
- cmd.Transaction = transaction;
- cmd.CommandText = command;
- cmd.CommandType = type;
- return cmd;
- }
- /// <summary>
- /// Creates a new <see cref="DbCommand"/> for <see cref="CommandType.StoredProcedure"/> with the specified procedure name
- /// </summary>
- /// <param name="db"></param>
- /// <param name="procedureName">The name of the stored proecedure to execute</param>
- /// <param name="transaction">The transaction to execute on</param>
- /// <returns>The initalized <see cref="DbCommand"/></returns>
- public static DbCommand CreateProcedureCommand(this DbConnection db, string procedureName, DbTransaction transaction)
- {
- return CreateCommand(db, transaction, CommandType.StoredProcedure, procedureName);
- }
-
- /// <summary>
- /// Reads all available rows from the reader, adapts columns to public properties with <see cref="SqlColumnName"/>
- /// attributes, and adds them to the collection
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="reader"></param>
- /// <param name="container">The container to write created objects to</param>
- /// <returns>The number of objects created and written to the collection</returns>
- public static int GetAllObjects<T>(this DbDataReader reader, ICollection<T> container) where T : new()
- {
- //make sure its worth collecting object meta
- if (!reader.HasRows)
- {
- return 0;
- }
- Type objectType = typeof(T);
- //Rent a dict of properties that have the column attribute set so we can load the proper results
- Dictionary<string, PropertyInfo> avialbleProps = DictStore.Rent();
- //Itterate through public properties
- foreach (PropertyInfo prop in objectType.GetProperties())
- {
- //try to get the column name attribute of the propery
- SqlColumnNameAttribute? colAtt = prop.GetCustomAttribute<SqlColumnNameAttribute>(true);
- //Attribute is valid and coumn name is not empty
- if (!string.IsNullOrWhiteSpace(colAtt?.ColumnName))
- {
- //Store the property for later
- avialbleProps[colAtt.ColumnName] = prop;
- }
- }
- //Get the column schema
- ReadOnlyCollection<DbColumn> columns = reader.GetColumnSchema();
- int count = 0;
- //Read
- while (reader.Read())
- {
- //Create the new object
- T ret = new();
- //Iterate through columns
- foreach (DbColumn col in columns)
- {
- //Get the propery if its specified by its column-name attribute
- if (avialbleProps.TryGetValue(col.ColumnName, out PropertyInfo? prop))
- {
- //make sure the column has a value
- if (col.ColumnOrdinal.HasValue)
- {
- //Get the object
- object val = reader.GetValue(col.ColumnOrdinal.Value);
- //Set check if the row is DB null, if so set it, otherwise set the value
- prop.SetValue(ret, Convert.IsDBNull(val) ? null : val);
- }
- }
- }
- //Add the object to the collection
- container.Add(ret);
- //Increment count
- count++;
- }
- //return dict (if an error occurs, just let the dict go and create a new one next time, no stress setting up a try/finally block)
- DictStore.Return(avialbleProps);
- return count;
- }
- /// <summary>
- /// Reads all available rows from the reader, adapts columns to public properties with <see cref="SqlColumnName"/>
- /// attributes, and adds them to the collection
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="reader"></param>
- /// <param name="container">The container to write created objects to</param>
- /// <returns>The number of objects created and written to the collection</returns>
- public static async ValueTask<int> GetAllObjectsAsync<T>(this DbDataReader reader, ICollection<T> container) where T : new()
- {
- //make sure its worth collecting object meta
- if (!reader.HasRows)
- {
- return 0;
- }
- Type objectType = typeof(T);
- //Rent a dict of properties that have the column attribute set so we can load the proper results
- Dictionary<string, PropertyInfo> avialbleProps = DictStore.Rent();
- //Itterate through public properties
- foreach (PropertyInfo prop in objectType.GetProperties())
- {
- //try to get the column name attribute of the propery
- SqlColumnNameAttribute? colAtt = prop.GetCustomAttribute<SqlColumnNameAttribute>(true);
- //Attribute is valid and coumn name is not empty
- if (!string.IsNullOrWhiteSpace(colAtt?.ColumnName))
- {
- //Store the property for later
- avialbleProps[colAtt.ColumnName] = prop;
- }
- }
- //Get the column schema
- ReadOnlyCollection<DbColumn> columns = await reader.GetColumnSchemaAsync();
- int count = 0;
- //Read
- while (await reader.ReadAsync())
- {
- //Create the new object
- T ret = new();
- //Iterate through columns
- foreach (DbColumn col in columns)
- {
- //Get the propery if its specified by its column-name attribute
- if (avialbleProps.TryGetValue(col.ColumnName, out PropertyInfo? prop))
- {
- //make sure the column has a value
- if (col.ColumnOrdinal.HasValue)
- {
- //Get the object
- object val = reader.GetValue(col.ColumnOrdinal.Value);
- //Set check if the row is DB null, if so set it, otherwise set the value
- prop.SetValue(ret, Convert.IsDBNull(val) ? null : val);
- }
- }
- }
- //Add the object to the collection
- container.Add(ret);
- //Increment count
- count++;
- }
- //return dict (if an error occurs, just let the dict go and create a new one next time, no stress setting up a try/finally block)
- DictStore.Return(avialbleProps);
- return count;
- }
- /// <summary>
- /// Reads the first available row from the reader, adapts columns to public properties with <see cref="SqlColumnName"/>
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="reader"></param>
- /// <returns>The created object, or default if no rows are available</returns>
- public static T? GetFirstObject<T>(this DbDataReader reader) where T : new()
- {
- //make sure its worth collecting object meta
- if (!reader.HasRows)
- {
- return default;
- }
- //Get the object type
- Type objectType = typeof(T);
- //Get the column schema
- ReadOnlyCollection<DbColumn> columns = reader.GetColumnSchema();
- //Read
- if (reader.Read())
- {
- //Rent a dict of properties that have the column attribute set so we can load the proper results
- Dictionary<string, PropertyInfo> availbleProps = DictStore.Rent();
- //Itterate through public properties
- foreach (PropertyInfo prop in objectType.GetProperties())
- {
- //try to get the column name attribute of the propery
- SqlColumnNameAttribute? colAtt = prop.GetCustomAttribute<SqlColumnNameAttribute>(true);
- //Attribute is valid and coumn name is not empty
- if (colAtt != null && !string.IsNullOrWhiteSpace(colAtt.ColumnName))
- {
- //Store the property for later
- availbleProps[colAtt.ColumnName] = prop;
- }
- }
- //Create the new object
- T ret = new();
- //Iterate through columns
- foreach (DbColumn col in columns)
- {
- //Get the propery if its specified by its column-name attribute
- if (availbleProps.TryGetValue(col.ColumnName, out PropertyInfo? prop) && col.ColumnOrdinal.HasValue)
- {
- //Get the object
- object val = reader.GetValue(col.ColumnOrdinal.Value);
- //Set check if the row is DB null, if so set it, otherwise set the value
- prop.SetValue(ret, Convert.IsDBNull(val) ? null : val);
- }
- }
- //Return dict, no stress if error occurs, the goal is lower overhead
- DictStore.Return(availbleProps);
- //Return the new object
- return ret;
- }
- return default;
- }
- /// <summary>
- /// Reads the first available row from the reader, adapts columns to public properties with <see cref="SqlColumnName"/>
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="reader"></param>
- /// <returns>The created object, or default if no rows are available</returns>
- public static async Task<T?> GetFirstObjectAsync<T>(this DbDataReader reader) where T : new()
- {
- //Read
- if (await reader.ReadAsync())
- {
- //Get the object type
- Type objectType = typeof(T);
- //Get the column schema
- ReadOnlyCollection<DbColumn> columns = await reader.GetColumnSchemaAsync();
- //Rent a dict of properties that have the column attribute set so we can load the proper results
- Dictionary<string, PropertyInfo> availbleProps = DictStore.Rent();
- //Itterate through public properties
- foreach (PropertyInfo prop in objectType.GetProperties())
- {
- //try to get the column name attribute of the propery
- SqlColumnNameAttribute? colAtt = prop.GetCustomAttribute<SqlColumnNameAttribute>(true);
- //Attribute is valid and coumn name is not empty
- if (colAtt != null && !string.IsNullOrWhiteSpace(colAtt.ColumnName))
- {
- //Store the property for later
- availbleProps[colAtt.ColumnName] = prop;
- }
- }
- //Create the new object
- T ret = new();
- //Iterate through columns
- foreach (DbColumn col in columns)
- {
- //Get the propery if its specified by its column-name attribute
- if (availbleProps.TryGetValue(col.ColumnName, out PropertyInfo? prop) && col.ColumnOrdinal.HasValue)
- {
- //Get the object
- object val = reader.GetValue(col.ColumnOrdinal.Value);
- //Set check if the row is DB null, if so set it, otherwise set the value
- prop.SetValue(ret, Convert.IsDBNull(val) ? null : val);
- }
- }
- //Return dict, no stress if error occurs, the goal is lower overhead
- DictStore.Return(availbleProps);
- //Return the new object
- return ret;
- }
- return default;
- }
- /// <summary>
- /// Executes a nonquery operation with the specified command using the object properties set with the
- /// <see cref="SqlVariableAttribute"/> attributes
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="cmd"></param>
- /// <param name="obj">The object containing the <see cref="SqlVariableAttribute"/> properties to write to command variables</param>
- /// <returns>The number of rows affected</returns>
- /// <exception cref="TypeLoadException"></exception>
- /// <exception cref="ArgumentException"></exception>
- /// <exception cref="NotSupportedException"></exception>
- /// <exception cref="ArgumentNullException"></exception>
- /// <exception cref="AmbiguousMatchException"></exception>
- /// <exception cref="TargetInvocationException"></exception>
- public static ERRNO ExecuteNonQuery<T>(this DbCommand cmd, T obj) where T : notnull
- {
- if (obj == null)
- {
- throw new ArgumentNullException(nameof(obj));
- }
- //Get the objec type
- Type objtype = typeof(T);
- //Itterate through public properties
- foreach (PropertyInfo prop in objtype.GetProperties())
- {
- //try to get the variable attribute of the propery
- SqlVariableAttribute varprops = prop.GetCustomAttribute<SqlVariableAttribute>(true);
- //This property is an sql variable, so lets add it
- if (varprops == null)
- {
- continue;
- }
- //If the command type is text, then make sure the variable is actually in the command, if not, ignore it
- if (cmd.CommandType != CommandType.Text || cmd.CommandText.Contains(varprops.VariableName))
- {
- //Add the parameter to the command list
- cmd.AddParameter(varprops.VariableName, prop.GetValue(obj), varprops.DataType, varprops.Size, varprops.IsNullable).Direction = varprops.Direction;
- }
- }
- //Prepare the sql statement
- cmd.Prepare();
- //Exect the query and return the results
- return cmd.ExecuteNonQuery();
- }
- /// <summary>
- /// Executes a nonquery operation with the specified command using the object properties set with the
- /// <see cref="SqlVariable"/> attributes
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="cmd"></param>
- /// <param name="obj">The object containing the <see cref="SqlVariable"/> properties to write to command variables</param>
- /// <returns>The number of rows affected</returns>
- /// <exception cref="TypeLoadException"></exception>
- /// <exception cref="ArgumentException"></exception>
- /// <exception cref="NotSupportedException"></exception>
- /// <exception cref="ArgumentNullException"></exception>
- /// <exception cref="AmbiguousMatchException"></exception>
- /// <exception cref="TargetInvocationException"></exception>
- public static async Task<ERRNO> ExecuteNonQueryAsync<T>(this DbCommand cmd, T obj) where T : notnull
- {
- if (obj == null)
- {
- throw new ArgumentNullException(nameof(obj));
- }
- //Get the objec type
- Type objtype = typeof(T);
- //Itterate through public properties
- foreach (PropertyInfo prop in objtype.GetProperties())
- {
- //try to get the variable attribute of the propery
- SqlVariableAttribute? varprops = prop.GetCustomAttribute<SqlVariableAttribute>(true);
- //This property is an sql variable, so lets add it
- if (varprops == null)
- {
- continue;
- }
- //If the command type is text, then make sure the variable is actually in the command, if not, ignore it
- if (cmd.CommandType != CommandType.Text || cmd.CommandText.Contains(varprops.VariableName))
- {
- //Add the parameter to the command list
- cmd.AddParameter(varprops.VariableName, prop.GetValue(obj), varprops.DataType, varprops.Size, varprops.IsNullable).Direction = varprops.Direction;
- }
- }
- //Prepare the sql statement
- await cmd.PrepareAsync();
- //Exect the query and return the results
- return await cmd.ExecuteNonQueryAsync();
- }
- }
-} \ No newline at end of file
diff --git a/VNLib.Plugins.Extensions.Data/SQL/EnumerableTable.cs b/VNLib.Plugins.Extensions.Data/SQL/EnumerableTable.cs
deleted file mode 100644
index 23cd889..0000000
--- a/VNLib.Plugins.Extensions.Data/SQL/EnumerableTable.cs
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Plugins.Extensions.Data
-* File: EnumerableTable.cs
-*
-* EnumerableTable.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.Data;
-using System.Threading;
-using System.Data.Common;
-using System.Threading.Tasks;
-using System.Collections.Generic;
-
-namespace VNLib.Plugins.Extensions.Data.SQL
-{
- /// <summary>
- /// A base class for client side async enumerable SQL queries
- /// </summary>
- /// <typeparam name="T">The entity type</typeparam>
- public abstract class EnumerableTable<T> : TableManager, IAsyncEnumerable<T>
- {
- const string DEFAULT_ENUM_STATMENT = "SELECT *\r\nFROM @table\r\n;";
-
- public EnumerableTable(Func<DbConnection> factory, string tableName) : base(factory, tableName)
- {
- //Build the default select all statment
- Enumerate = DEFAULT_ENUM_STATMENT.Replace("@table", tableName);
- }
- public EnumerableTable(Func<DbConnection> factory) : base(factory)
- { }
-
- /// <summary>
- /// The command that will be run against the database to return rows for enumeration
- /// </summary>
- protected string Enumerate { get; set; }
-
- /// <summary>
- /// The isolation level to use when creating the transaction during enumerations
- /// </summary>
- protected IsolationLevel TransactionIsolationLevel { get; set; } = IsolationLevel.ReadUncommitted;
-
- IAsyncEnumerator<T> IAsyncEnumerable<T>.GetAsyncEnumerator(CancellationToken cancellationToken)
- {
- return GetAsyncEnumerator(cancellationToken: cancellationToken);
- }
-
- /// <summary>
- /// Transforms a row from the <paramref name="reader"/> into the item type
- /// to be returned when yielded.
- /// </summary>
- /// <param name="reader">The reader to get the item data from</param>
- /// <param name="cancellationToken">A token to cancel the operation</param>
- /// <returns>A task that returns the transformed item</returns>
- /// <remarks>The <paramref name="reader"/> position is set before this method is invoked</remarks>
- protected abstract Task<T> GetItemAsync(DbDataReader reader, CancellationToken cancellationToken);
- /// <summary>
- /// Invoked when an item is no longer in the enumerator scope, in the enumeration process.
- /// </summary>
- /// <param name="item">The item to cleanup</param>
- /// <param name="cancellationToken">A token to cancel the operation</param>
- /// <returns>A ValueTask that represents the cleanup process</returns>
- protected abstract ValueTask CleanupItemAsync(T item, CancellationToken cancellationToken);
-
- /// <summary>
- /// Gets an <see cref="IAsyncEnumerator{T}"/> to enumerate items within the backing store.
- /// </summary>
- /// <param name="closeItems">Cleanup items after each item is enumerated and the enumeration scope has
- /// returned to the enumerator</param>
- /// <param name="cancellationToken">A token to cancel the enumeration</param>
- /// <returns>A <see cref="IAsyncEnumerator{T}"/> to enumerate records within the store</returns>
- public virtual async IAsyncEnumerator<T> GetAsyncEnumerator(bool closeItems = true, CancellationToken cancellationToken = default)
- {
- await using DbConnection db = GetConnection();
- await db.OpenAsync(cancellationToken);
- await using DbTransaction transaction = await db.BeginTransactionAsync(cancellationToken);
- //Start the enumeration command
- await using DbCommand cmd = db.CreateTextCommand(Enumerate, transaction);
- await cmd.PrepareAsync(cancellationToken);
- await using DbDataReader reader = await cmd.ExecuteReaderAsync(cancellationToken);
- //loop through results and transform each element
- while (reader.Read())
- {
- //get the item
- T item = await GetItemAsync(reader, cancellationToken);
- try
- {
- yield return item;
- }
- finally
- {
- if (closeItems)
- {
- //Cleanup the item
- await CleanupItemAsync(item, cancellationToken);
- }
- }
- }
- }
- }
-} \ No newline at end of file
diff --git a/VNLib.Plugins.Extensions.Data/SQL/SqlColumnNameAttribute.cs b/VNLib.Plugins.Extensions.Data/SQL/SqlColumnNameAttribute.cs
deleted file mode 100644
index c18dab9..0000000
--- a/VNLib.Plugins.Extensions.Data/SQL/SqlColumnNameAttribute.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Plugins.Extensions.Data
-* File: SqlColumnNameAttribute.cs
-*
-* SqlColumnNameAttribute.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;
-
-namespace VNLib.Plugins.Extensions.Data.SQL
-{
- /// <summary>
- /// Property attribute that specifies the property represents an SQL column in the database
- /// </summary>
- [AttributeUsage(AttributeTargets.Property)]
- public sealed class SqlColumnNameAttribute : Attribute
- {
- public bool Nullable { get; }
- public bool Unique { get; }
- public bool PrimaryKey { get; }
- public string ColumnName { get; }
- /// <summary>
- /// Specifies the property is an SQL column name
- /// </summary>
- /// <param name="columnName">Name of the SQL column</param>
- /// <param name="primaryKey"></param>
- /// <param name="nullable"></param>
- /// <param name="unique"></param>
- public SqlColumnNameAttribute(string columnName, bool primaryKey = false, bool nullable = true, bool unique = false)
- {
- this.ColumnName = columnName;
- this.PrimaryKey = primaryKey;
- this.Nullable = nullable;
- this.Unique = unique;
- }
- }
-} \ No newline at end of file
diff --git a/VNLib.Plugins.Extensions.Data/SQL/SqlTableNameAttribute.cs b/VNLib.Plugins.Extensions.Data/SQL/SqlTableNameAttribute.cs
deleted file mode 100644
index 9c870ea..0000000
--- a/VNLib.Plugins.Extensions.Data/SQL/SqlTableNameAttribute.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Plugins.Extensions.Data
-* File: SqlColumnName.cs
-*
-* SqlColumnName.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;
-
-namespace VNLib.Plugins.Extensions.Data.SQL
-{
-
- /// <summary>
- /// Allows a type to declare itself as a <see cref="System.Data.DataTable"/> with the specified name
- /// </summary>
- [AttributeUsage(AttributeTargets.Class, AllowMultiple =false, Inherited = true)]
- public sealed class SqlTableNameAttribute : Attribute
- {
- public string TableName { get; }
-
- public SqlTableNameAttribute(string tableName) => TableName = tableName;
- }
-} \ No newline at end of file
diff --git a/VNLib.Plugins.Extensions.Data/SQL/SqlVariable.cs b/VNLib.Plugins.Extensions.Data/SQL/SqlVariable.cs
deleted file mode 100644
index b18d27b..0000000
--- a/VNLib.Plugins.Extensions.Data/SQL/SqlVariable.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Plugins.Extensions.Data
-* File: SqlVariable.cs
-*
-* SqlVariable.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.Data;
-
-namespace VNLib.Plugins.Extensions.Data.SQL
-{
- /// <summary>
- /// Property attribute that specifies the property is to be used for a given command variable
- /// </summary>
- [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
- public sealed class SqlVariableAttribute : Attribute
- {
- public string VariableName { get; }
- public DbType DataType { get; }
- public ParameterDirection Direction { get; }
- public int Size { get; }
- public bool IsNullable { get; }
- /// <summary>
- /// Specifies the property to be used as an SQL variable
- /// </summary>
- /// <param name="variableName">Sql statement variable this property will substitute</param>
- /// <param name="dataType">The sql data the property will represent</param>
- /// <param name="direction">Data direction during execution</param>
- /// <param name="size">Column size</param>
- /// <param name="isNullable">Is this property allowed to be null</param>
- public SqlVariableAttribute(string variableName, DbType dataType, ParameterDirection direction, int size, bool isNullable)
- {
- this.VariableName = variableName;
- this.DataType = dataType;
- this.Direction = direction;
- this.Size = size;
- this.IsNullable = isNullable;
- }
- }
-}
diff --git a/VNLib.Plugins.Extensions.Data/SQL/TableManager.cs b/VNLib.Plugins.Extensions.Data/SQL/TableManager.cs
deleted file mode 100644
index a7f7873..0000000
--- a/VNLib.Plugins.Extensions.Data/SQL/TableManager.cs
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Plugins.Extensions.Data
-* File: TableManager.cs
-*
-* TableManager.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.Data.Common;
-
-namespace VNLib.Plugins.Extensions.Data.SQL
-{
- /// <summary>
- /// A class that contains basic structures for interacting with an SQL driven database
- /// </summary>
- public abstract class TableManager
- {
- private readonly Func<DbConnection> Factory;
- protected string Insert { get; set; }
- protected string Select { get; set; }
- protected string Update { get; set; }
- protected string Delete { get; set; }
-
- /// <summary>
- /// The name of the table specified during initialized
- /// </summary>
- protected string TableName { get; }
-
- protected TableManager(Func<DbConnection> factory, string tableName)
- {
- this.Factory = factory ?? throw new ArgumentNullException(nameof(factory));
- this.TableName = !string.IsNullOrWhiteSpace(tableName) ? tableName : throw new ArgumentNullException(nameof(tableName));
- }
-
- protected TableManager(Func<DbConnection> factory)
- {
- this.Factory = factory ?? throw new ArgumentNullException(nameof(factory));
- this.TableName = "";
- }
- /// <summary>
- /// Opens a new <see cref="DbConnection"/> by invoking the factory callback method
- /// </summary>
- /// <returns>The open connection</returns>
- protected DbConnection GetConnection()
- {
- return Factory();
- }
- }
-}
diff --git a/VNLib.Plugins.Extensions.Data/Storage/Blob.cs b/VNLib.Plugins.Extensions.Data/Storage/Blob.cs
deleted file mode 100644
index ab18eeb..0000000
--- a/VNLib.Plugins.Extensions.Data/Storage/Blob.cs
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Plugins.Extensions.Data
-* File: Blob.cs
-*
-* Blob.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.IO;
-using System.Threading.Tasks;
-using System.Runtime.Versioning;
-
-using VNLib.Utils;
-using VNLib.Utils.IO;
-using VNLib.Utils.Async;
-
-namespace VNLib.Plugins.Extensions.Data.Storage
-{
- /// <summary>
- /// Represents a stream of arbitrary binary data
- /// </summary>
- public class Blob : BackingStream<FileStream>, IObjectStorage, IAsyncExclusiveResource
- {
- protected readonly LWStorageDescriptor Descriptor;
-
- /// <summary>
- /// The current blob's unique ID
- /// </summary>
- public string BlobId => Descriptor.DescriptorID;
- /// <summary>
- /// A value indicating if the <see cref="Blob"/> has been modified
- /// </summary>
- public bool Modified { get; protected set; }
- /// <summary>
- /// A valid indicating if the blob was flagged for deletiong
- /// </summary>
- public bool Deleted { get; protected set; }
-
- /// <summary>
- /// The name of the file (does not change the actual file system name)
- /// </summary>
- public string Name
- {
- get => Descriptor.GetName();
- set => Descriptor.SetName(value);
- }
- /// <summary>
- /// The UTC time the <see cref="Blob"/> was last modified
- /// </summary>
- public DateTimeOffset LastWriteTimeUtc => Descriptor.LastModified;
- /// <summary>
- /// The UTC time the <see cref="Blob"/> was created
- /// </summary>
- public DateTimeOffset CreationTimeUtc => Descriptor.Created;
-
- internal Blob(LWStorageDescriptor descriptor, in FileStream file)
- {
- this.Descriptor = descriptor;
- base.BaseStream = file;
- }
-
- /// <summary>
- /// Prevents other processes from reading from or writing to the <see cref="Blob"/>
- /// </summary>
- /// <param name="position">The begining position of the range to lock</param>
- /// <param name="length">The range to be locked</param>
- /// <exception cref="IOException"></exception>
- /// <exception cref="ObjectDisposedException"></exception>
- /// <exception cref="ArgumentOutOfRangeException"></exception>
- [UnsupportedOSPlatform("ios")]
- [UnsupportedOSPlatform("macos")]
- [UnsupportedOSPlatform("tvos")]
- public void Lock(long position, long length) => BaseStream.Lock(position, length);
- /// <summary>
- /// Prevents other processes from reading from or writing to the <see cref="Blob"/>
- /// </summary>
- /// <exception cref="IOException"></exception>
- /// <exception cref="ObjectDisposedException"></exception>
- /// <exception cref="ArgumentOutOfRangeException"></exception>
- [UnsupportedOSPlatform("ios")]
- [UnsupportedOSPlatform("macos")]
- [UnsupportedOSPlatform("tvos")]
- public void Lock() => BaseStream.Lock(0, BaseStream.Length);
- /// <summary>
- /// Allows access by other processes to all or part of the <see cref="Blob"/> that was previously locked
- /// </summary>
- /// <param name="position">The begining position of the range to unlock</param>
- /// <param name="length">The range to be unlocked</param>
- /// <exception cref="ArgumentOutOfRangeException"></exception>
- [UnsupportedOSPlatform("ios")]
- [UnsupportedOSPlatform("macos")]
- [UnsupportedOSPlatform("tvos")]
- public void Unlock(long position, long length) => BaseStream.Unlock(position, length);
- /// <summary>
- /// Allows access by other processes to the entire <see cref="Blob"/>
- /// </summary>
- /// <exception cref="ArgumentOutOfRangeException"></exception>
- [UnsupportedOSPlatform("ios")]
- [UnsupportedOSPlatform("macos")]
- [UnsupportedOSPlatform("tvos")]
- public void Unlock() => BaseStream.Unlock(0, BaseStream.Length);
- ///<inheritdoc/>
- public override void SetLength(long value)
- {
- base.SetLength(value);
- //Set modified flag
- Modified |= true;
- }
-
- /*
- * Capture on-write calls to set the modified flag
- */
- ///<inheritdoc/>
- protected override void OnWrite(int count) => Modified |= true;
-
- T IObjectStorage.GetObject<T>(string key) => ((IObjectStorage)Descriptor).GetObject<T>(key);
- void IObjectStorage.SetObject<T>(string key, T obj) => ((IObjectStorage)Descriptor).SetObject(key, obj);
-
- public string this[string index]
- {
- get => Descriptor[index];
- set => Descriptor[index] = value;
- }
-
-
- /// <summary>
- /// Marks the file for deletion and will be deleted when the <see cref="Blob"/> is disposed
- /// </summary>
- public void Delete()
- {
- //Set deleted flag
- Deleted |= true;
- Descriptor.Delete();
- }
- ///<inheritdoc/>
- public bool IsReleased => Descriptor.IsReleased;
-
-
- /// <summary>
- /// <para>
- /// If the <see cref="Blob"/> was opened with writing enabled,
- /// and file was modified, changes are flushed to the backing store
- /// and the stream is set to readonly.
- /// </para>
- /// <para>
- /// If calls to this method succeed the stream is placed into a read-only mode
- /// which will cause any calls to Write to throw a <see cref="NotSupportedException"/>
- /// </para>
- /// </summary>
- /// <returns>A <see cref="ValueTask"/> that may be awaited until the operation completes</returns>
- /// <remarks>
- /// This method may be called to avoid flushing changes to the backing store
- /// when the <see cref="Blob"/> is disposed (i.e. lifetime is manged outside of the desired scope)
- /// </remarks>
- /// <exception cref="IOException"></exception>
- /// <exception cref="ObjectDisposedException"></exception>
- /// <exception cref="InvalidOperationException"></exception>
- public async ValueTask FlushChangesAndSetReadonlyAsync()
- {
- if (Deleted)
- {
- throw new InvalidOperationException("The blob has been deleted and must be closed!");
- }
- if (Modified)
- {
- //flush the base stream
- await BaseStream.FlushAsync();
- //Update the file length in the store
- Descriptor.SetLength(BaseStream.Length);
- }
- //flush changes, this will cause the dispose method to complete synchronously when closing
- await Descriptor.WritePendingChangesAsync();
- //Clear modified flag
- Modified = false;
- //Set to readonly mode
- base.ForceReadOnly = true;
- }
-
-
- /*
- * Override the dispose async to manually dispose the
- * base stream and avoid the syncrhonous (OnClose)
- * method and allow awaiting the descriptor release
- */
- ///<inheritdoc/>
- public override async ValueTask DisposeAsync()
- {
- await ReleaseAsync();
- GC.SuppressFinalize(this);
- }
- ///<inheritdoc/>
- public async ValueTask ReleaseAsync()
- {
- try
- {
- //Check for deleted
- if (Deleted)
- {
- //Dispose the base stream explicitly
- await BaseStream.DisposeAsync();
- //Try to delete the file
- File.Delete(BaseStream.Name);
- }
- //Check to see if the file was modified
- else if (Modified)
- {
- //Set the file size in bytes
- Descriptor.SetLength(BaseStream.Length);
- }
- }
- catch
- {
- //Set the error flag
- Descriptor.IsError(true);
- //propagate the exception
- throw;
- }
- finally
- {
- //Dispose the stream
- await BaseStream.DisposeAsync();
- //Release the descriptor
- await Descriptor.ReleaseAsync();
- }
- }
- }
-} \ No newline at end of file
diff --git a/VNLib.Plugins.Extensions.Data/Storage/BlobExtensions.cs b/VNLib.Plugins.Extensions.Data/Storage/BlobExtensions.cs
deleted file mode 100644
index 468a66d..0000000
--- a/VNLib.Plugins.Extensions.Data/Storage/BlobExtensions.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Plugins.Extensions.Data
-* File: BlobExtensions.cs
-*
-* BlobExtensions.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 VNLib.Utils;
-
-namespace VNLib.Plugins.Extensions.Data.Storage
-{
- public static class BlobExtensions
- {
- public const string USER_ID_ENTRY = "__.uid";
- public const string VERSION_ENTRY = "__.vers";
-
- private const string FILE_SIZE = "__.size";
- private const string FILE_NAME = "__.name";
- private const string ERROR_FLAG = "__.err";
-
- public static string GetUserId(this Blob blob) => blob[USER_ID_ENTRY];
- /// <summary>
- /// Gets the <see cref="Version"/> stored in the current <see cref="Blob"/>
- /// </summary>
- /// <returns>The sored version if previously set, thows otherwise</returns>
- /// <exception cref="FormatException"></exception>
- public static Version GetVersion(this Blob blob) => Version.Parse(blob[VERSION_ENTRY]);
- /// <summary>
- /// Sets a <see cref="Version"/> for the current <see cref="Blob"/>
- /// </summary>
- /// <param name="blob"></param>
- /// <param name="version">The <see cref="Version"/> of the <see cref="Blob"/></param>
- public static void SetVersion(this Blob blob, Version version) => blob[VERSION_ENTRY] = version.ToString();
-
- /// <summary>
- /// Gets a value indicating if the last operation left the <see cref="Blob"/> in an undefined state
- /// </summary>
- /// <returns>True if the <see cref="Blob"/> state is undefined, false otherwise</returns>
- public static bool IsError(this Blob blob) => bool.TrueString.Equals(blob[ERROR_FLAG]);
- internal static void IsError(this LWStorageDescriptor blob, bool value) => blob[ERROR_FLAG] = value ? bool.TrueString : null;
-
- internal static long GetLength(this LWStorageDescriptor blob) => (blob as IObjectStorage).GetObject<long>(FILE_SIZE);
- internal static void SetLength(this LWStorageDescriptor blob, long length) => (blob as IObjectStorage).SetObject(FILE_SIZE, length);
-
- internal static string GetName(this LWStorageDescriptor blob) => blob[FILE_NAME];
- internal static string SetName(this LWStorageDescriptor blob, string filename) => blob[FILE_NAME] = filename;
- }
-} \ No newline at end of file
diff --git a/VNLib.Plugins.Extensions.Data/Storage/BlobStore.cs b/VNLib.Plugins.Extensions.Data/Storage/BlobStore.cs
deleted file mode 100644
index 6897516..0000000
--- a/VNLib.Plugins.Extensions.Data/Storage/BlobStore.cs
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Plugins.Extensions.Data
-* File: BlobStore.cs
-*
-* BlobStore.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.IO;
-using System.Security.Cryptography;
-using System.Threading.Tasks;
-
-using VNLib.Utils.Extensions;
-
-namespace VNLib.Plugins.Extensions.Data.Storage
-{
-
- /// <summary>
- /// Stores <see cref="Blob"/>s to the local file system backed with a single table <see cref="LWStorageManager"/>
- /// that tracks changes
- /// </summary>
- public class BlobStore
- {
- /// <summary>
- /// The root directory all blob files are stored
- /// </summary>
- public DirectoryInfo RootDir { get; }
- /// <summary>
- /// The backing store for blob meta-data
- /// </summary>
- protected LWStorageManager BlobTable { get; }
- /// <summary>
- /// Creates a new <see cref="BlobStore"/> that accesses files
- /// within the specified root directory.
- /// </summary>
- /// <param name="rootDir">The root directory containing the blob file contents</param>
- /// <param name="blobStoreMan">The db backing store</param>
- public BlobStore(DirectoryInfo rootDir, LWStorageManager blobStoreMan)
- {
- RootDir = rootDir;
- BlobTable = blobStoreMan;
- }
-
- private string GetPath(string fileId) => Path.Combine(RootDir.FullName, fileId);
-
- /*
- * Creates a repeatable unique identifier for the file
- * name and allows for lookups
- */
- internal static string CreateFileHash(string fileName)
- {
- throw new NotImplementedException();
- //return ManagedHash.ComputeBase64Hash(fileName, HashAlg.SHA1);
- }
-
- /// <summary>
- /// Opens an existing <see cref="Blob"/> from the current store
- /// </summary>
- /// <param name="fileId">The id of the file being requested</param>
- /// <param name="access">Access level of the file</param>
- /// <param name="share">The sharing option of the underlying file</param>
- /// <param name="bufferSize">The size of the file buffer</param>
- /// <returns>If found, the requested <see cref="Blob"/>, null otherwise. Throws exceptions if the file is opened in a non-sharable state</returns>
- /// <exception cref="IOException"></exception>
- /// <exception cref="NotSupportedException"></exception>
- /// <exception cref="ArgumentNullException"></exception>
- /// <exception cref="UnauthorizedAccessException"></exception>
- /// <exception cref="UndefinedBlobStateException"></exception>
- public virtual async Task<Blob> OpenBlobAsync(string fileId, FileAccess access, FileShare share, int bufferSize = 4096)
- {
- //Get the file's data descriptor
- LWStorageDescriptor fileDescriptor = await BlobTable.GetDescriptorFromIDAsync(fileId);
- //return null if not found
- if (fileDescriptor == null)
- {
- return null;
- }
- try
- {
- string fsSafeName = GetPath(fileDescriptor.DescriptorID);
- //try to open the file
- FileStream file = new(fsSafeName, FileMode.Open, access, share, bufferSize, FileOptions.Asynchronous);
- //Create the new blob
- return new Blob(fileDescriptor, file);
- }
- catch (FileNotFoundException)
- {
- //If the file was not found but the descriptor was, delete the descriptor from the db
- fileDescriptor.Delete();
- //Flush changes
- await fileDescriptor.ReleaseAsync();
- //return null since this is a desync issue and the file technically does not exist
- return null;
- }
- catch
- {
- //Release the descriptor and pass the exception
- await fileDescriptor.ReleaseAsync();
- throw;
- }
- }
-
- /// <summary>
- /// Creates a new <see cref="Blob"/> for the specified file sharing permissions
- /// </summary>
- /// <param name="name">The name of the original file</param>
- /// <param name="share">The blob sharing permissions</param>
- /// <param name="bufferSize"></param>
- /// <returns>The newly created <see cref="Blob"/></returns>
- /// <exception cref="IoExtensions"></exception>
- /// <exception cref="NotSupportedException"></exception>
- /// <exception cref="ArgumentNullException"></exception>
- /// <exception cref="UnauthorizedAccessException"></exception>
- public virtual async Task<Blob> CreateBlobAsync(string name, FileShare share = FileShare.None, int bufferSize = 4096)
- {
- //hash the file name to create a unique id for the file name
- LWStorageDescriptor newFile = await BlobTable.CreateDescriptorAsync(CreateFileHash(name));
- //if the descriptor was not created, return null
- if (newFile == null)
- {
- return null;
- }
- try
- {
- string fsSafeName = GetPath(newFile.DescriptorID);
- //Open/create the new file
- FileStream file = new(fsSafeName, FileMode.OpenOrCreate, FileAccess.ReadWrite, share, bufferSize, FileOptions.Asynchronous);
- //If the file already exists, make sure its zero'd
- file.SetLength(0);
- //Save the original name of the file
- newFile.SetName(name);
- //Create and return the new blob
- return new Blob(newFile, file);
- }
- catch
- {
- //If an exception occurs, remove the descritor from the db
- newFile.Delete();
- await newFile.ReleaseAsync();
- //Pass exception
- throw;
- }
- }
- }
-} \ No newline at end of file
diff --git a/VNLib.Plugins.Extensions.Data/Storage/LWDecriptorCreationException.cs b/VNLib.Plugins.Extensions.Data/Storage/LWDecriptorCreationException.cs
deleted file mode 100644
index db0dbbb..0000000
--- a/VNLib.Plugins.Extensions.Data/Storage/LWDecriptorCreationException.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Plugins.Extensions.Data
-* File: LWDecriptorCreationException.cs
-*
-* LWDecriptorCreationException.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;
-
-namespace VNLib.Plugins.Extensions.Data.Storage
-{
- /// <summary>
- /// Raised when an operation to create a new <see cref="LWStorageDescriptor"/>
- /// fails
- /// </summary>
- public class LWDescriptorCreationException : Exception
- {
- ///<inheritdoc/>
- public LWDescriptorCreationException()
- {}
- ///<inheritdoc/>
- public LWDescriptorCreationException(string? message) : base(message)
- {}
- ///<inheritdoc/>
- public LWDescriptorCreationException(string? message, Exception? innerException) : base(message, innerException)
- {}
- }
-} \ No newline at end of file
diff --git a/VNLib.Plugins.Extensions.Data/Storage/LWStorageContext.cs b/VNLib.Plugins.Extensions.Data/Storage/LWStorageContext.cs
deleted file mode 100644
index d7f6e29..0000000
--- a/VNLib.Plugins.Extensions.Data/Storage/LWStorageContext.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Plugins.Extensions.Data
-* File: LWStorageContext.cs
-*
-* LWStorageContext.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 Microsoft.EntityFrameworkCore;
-
-namespace VNLib.Plugins.Extensions.Data.Storage
-{
-#nullable disable
- internal sealed class LWStorageContext : TransactionalDbContext
- {
- private readonly string TableName;
- public DbSet<LWStorageEntry> Descriptors { get; set; }
-
- public LWStorageContext(DbContextOptions options, string tableName)
- :base(options)
- {
- TableName = tableName;
- }
-
- protected override void OnModelCreating(ModelBuilder modelBuilder)
- {
- //Set table name
- modelBuilder.Entity<LWStorageEntry>()
- .ToTable(TableName);
- }
- }
-} \ No newline at end of file
diff --git a/VNLib.Plugins.Extensions.Data/Storage/LWStorageDescriptor.cs b/VNLib.Plugins.Extensions.Data/Storage/LWStorageDescriptor.cs
deleted file mode 100644
index 72665f3..0000000
--- a/VNLib.Plugins.Extensions.Data/Storage/LWStorageDescriptor.cs
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Plugins.Extensions.Data
-* File: LWStorageDescriptor.cs
-*
-* LWStorageDescriptor.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.IO;
-using System.Text.Json;
-using System.Collections;
-using System.IO.Compression;
-using System.Threading.Tasks;
-using System.Collections.Generic;
-using System.Text.Json.Serialization;
-
-using VNLib.Utils;
-using VNLib.Utils.Async;
-using VNLib.Utils.Extensions;
-using VNLib.Utils.Memory;
-
-namespace VNLib.Plugins.Extensions.Data.Storage
-{
- /// <summary>
- /// Represents an open storage object, that when released or disposed, will flush its changes to the underlying table
- /// for which this descriptor represents
- /// </summary>
- public sealed class LWStorageDescriptor : AsyncUpdatableResource, IObjectStorage, IEnumerable<KeyValuePair<string, string>>, IIndexable<string, string>
- {
-
- private static readonly JsonSerializerOptions SerializerOptions = new()
- {
- DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
- NumberHandling = JsonNumberHandling.Strict,
- ReadCommentHandling = JsonCommentHandling.Disallow,
- WriteIndented = false,
- DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
- IgnoreReadOnlyFields = true,
- DefaultBufferSize = Environment.SystemPageSize,
- };
-
-
- internal LWStorageEntry Entry { get; }
-
- private readonly Lazy<Dictionary<string, string>> StringStorage;
-
- /// <summary>
- /// The currnt descriptor's identifier string within its backing table. Usually the primary key.
- /// </summary>
- public string DescriptorID => Entry.Id;
- /// <summary>
- /// The identifier of the user for which this descriptor belongs to
- /// </summary>
- public string UserID => Entry.UserId!;
- /// <summary>
- /// The <see cref="DateTime"/> when the descriptor was created
- /// </summary>
- public DateTimeOffset Created => Entry.Created;
- /// <summary>
- /// The last time this descriptor was updated
- /// </summary>
- public DateTimeOffset LastModified => Entry.LastModified;
-
- ///<inheritdoc/>
- protected override AsyncUpdateCallback UpdateCb { get; }
- ///<inheritdoc/>
- protected override AsyncDeleteCallback DeleteCb { get; }
- ///<inheritdoc/>
- protected override JsonSerializerOptions JSO => SerializerOptions;
-
- internal LWStorageDescriptor(LWStorageManager manager, LWStorageEntry entry)
- {
- Entry = entry;
- UpdateCb = manager.UpdateDescriptorAsync;
- DeleteCb = manager.RemoveDescriptorAsync;
- StringStorage = new(OnStringStoreLoad);
- }
-
- internal Dictionary<string, string> OnStringStoreLoad()
- {
- if(Entry.Data == null || Entry.Data.Length == 0)
- {
- return new(StringComparer.OrdinalIgnoreCase);
- }
- else
- {
- //Calc and alloc decode buffer
- int bufferSize = (int)(Entry.Data.Length * 1.75);
- using UnsafeMemoryHandle<byte> decodeBuffer = Memory.UnsafeAlloc<byte>(bufferSize);
-
- //Decode and deserialize the data
- return BrotliDecoder.TryDecompress(Entry.Data, decodeBuffer, out int written)
- ? JsonSerializer.Deserialize<Dictionary<string, string>>(Entry.Data, SerializerOptions) ?? new(StringComparer.OrdinalIgnoreCase)
- : throw new InvalidDataException("Failed to decompress data");
- }
- }
-
- /// <inheritdoc/>
- /// <exception cref="JsonException"></exception>
- /// <exception cref="NotSupportedException"></exception>
- /// <exception cref="ArgumentNullException"></exception>
- /// <exception cref="ObjectDisposedException"></exception>
- public T? GetObject<T>(string key)
- {
- Check();
- //De-serialize and return object
- return StringStorage.Value.TryGetValue(key, out string? val) ? val.AsJsonObject<T>(SerializerOptions) : default;
- }
-
- /// <inheritdoc/>
- /// <exception cref="NotSupportedException"></exception>
- /// <exception cref="ObjectDisposedException"></exception>
- public void SetObject<T>(string key, T obj)
- {
- //Remove the object from storage if its null
- if (obj == null)
- {
- SetStringValue(key, null);
- }
- else
- {
- //Serialize the object to a string
- string value = obj.ToJsonString(SerializerOptions)!;
- //Attempt to store string in storage
- SetStringValue(key, value);
- }
- }
-
-
- /// <summary>
- /// Gets a string value from string storage matching a given key
- /// </summary>
- /// <param name="key">Key for storage</param>
- /// <returns>Value associaetd with key if exists, <see cref="string.Empty"/> otherwise</returns>
- /// <exception cref="ArgumentNullException">If key is null</exception>
- /// <exception cref="ObjectDisposedException"></exception>
- public string GetStringValue(string key)
- {
- Check();
- return StringStorage.Value.TryGetValue(key, out string? val) ? val : string.Empty;
- }
-
- /// <summary>
- /// Creates, overwrites, or removes a string value identified by key.
- /// </summary>
- /// <param name="key">Entry key</param>
- /// <param name="value">String to store or overwrite, set to null or string.Empty to remove a property</param>
- /// <exception cref="ObjectDisposedException"></exception>
- /// <exception cref="ArgumentNullException">If key is null</exception>
- public void SetStringValue(string key, string? value)
- {
- if (string.IsNullOrEmpty(key))
- {
- throw new ArgumentNullException(nameof(key));
- }
- Check();
- //If the value is null, see if the the properties are null
- if (string.IsNullOrWhiteSpace(value))
- {
- //If the value is null and properies exist, remove the entry
- StringStorage.Value.Remove(key);
- Modified |= true;
- }
- else
- {
- //Set the value
- StringStorage.Value[key] = value;
- //Set modified flag
- Modified |= true;
- }
- }
-
- /// <summary>
- /// Gets or sets a string value from string storage matching a given key
- /// </summary>
- /// <param name="key">Key for storage</param>
- /// <returns>Value associaetd with key if exists, <seealso cref="string.Empty "/> otherwise</returns>
- /// <exception cref="ObjectDisposedException"></exception>
- /// <exception cref="ArgumentNullException">If key is null</exception>
- public string this[string key]
- {
- get => GetStringValue(key);
- set => SetStringValue(key, value);
- }
-
- /// <summary>
- /// Flushes all pending changes to the backing store asynchronously
- /// </summary>
- /// <exception cref="ObjectDisposedException"></exception>
- public ValueTask WritePendingChangesAsync()
- {
- Check();
- return Modified ? (new(FlushPendingChangesAsync())) : ValueTask.CompletedTask;
- }
-
- ///<inheritdoc/>
- public override async ValueTask ReleaseAsync()
- {
- await base.ReleaseAsync();
- //Cleanup dict on exit
- if (StringStorage.IsValueCreated)
- {
- StringStorage.Value.Clear();
- }
- }
-
- ///<inheritdoc/>
- public IEnumerator<KeyValuePair<string, string>> GetEnumerator() => StringStorage.Value.GetEnumerator();
- IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
- ///<inheritdoc/>
- protected override object GetResource() => StringStorage.Value;
- }
-} \ No newline at end of file
diff --git a/VNLib.Plugins.Extensions.Data/Storage/LWStorageEntry.cs b/VNLib.Plugins.Extensions.Data/Storage/LWStorageEntry.cs
deleted file mode 100644
index 5c5da61..0000000
--- a/VNLib.Plugins.Extensions.Data/Storage/LWStorageEntry.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Plugins.Extensions.Data
-* File: LwStorageEntry.cs
-*
-* LwStorageEntry.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 VNLib.Plugins.Extensions.Data.Abstractions;
-
-namespace VNLib.Plugins.Extensions.Data.Storage
-{
-
- internal sealed class LWStorageEntry : DbModelBase, IUserEntity
- {
- public override string Id { get; set; }
-
- public override DateTime Created { get; set; }
-
- public override DateTime LastModified { get; set; }
-
- public string? UserId { get; set; }
-
- public byte[]? Data { get; set; }
- }
-} \ No newline at end of file
diff --git a/VNLib.Plugins.Extensions.Data/Storage/LWStorageManager.cs b/VNLib.Plugins.Extensions.Data/Storage/LWStorageManager.cs
deleted file mode 100644
index 027fa90..0000000
--- a/VNLib.Plugins.Extensions.Data/Storage/LWStorageManager.cs
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Plugins.Extensions.Data
-* File: LWStorageManager.cs
-*
-* LWStorageManager.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.IO;
-using System.Data;
-using System.Linq;
-using System.Threading;
-using System.IO.Compression;
-using System.Threading.Tasks;
-
-using Microsoft.EntityFrameworkCore;
-
-using VNLib.Utils;
-using VNLib.Utils.IO;
-using VNLib.Utils.Memory;
-
-namespace VNLib.Plugins.Extensions.Data.Storage
-{
-
- /// <summary>
- /// Provides single table database object storage services
- /// </summary>
- public sealed class LWStorageManager
- {
- /// <summary>
- /// The generator function that is invoked when a new <see cref="LWStorageDescriptor"/> is to
- /// be created without an explicit id
- /// </summary>
- public Func<string> NewDescriptorIdGenerator { get; init; } = static () => Guid.NewGuid().ToString("N");
-
- private readonly DbContextOptions DbOptions;
- private readonly string TableName;
-
- private LWStorageContext GetContext() => new(DbOptions, TableName);
-
- /// <summary>
- /// Creates a new <see cref="LWStorageManager"/> with
- /// </summary>
- /// <param name="options">The db context options to create database connections with</param>
- /// <param name="tableName">The name of the table to operate on</param>
- /// <exception cref="ArgumentNullException"></exception>
- public LWStorageManager(DbContextOptions options, string tableName)
- {
- DbOptions = options ?? throw new ArgumentNullException(nameof(options));
- TableName = tableName ?? throw new ArgumentNullException(nameof(tableName));
- }
-
- /// <summary>
- /// Creates a new <see cref="LWStorageDescriptor"/> fror a given user
- /// </summary>
- /// <param name="userId">Id of user</param>
- /// <param name="descriptorIdOverride">An override to specify the new descriptor's id</param>
- /// <param name="cancellation">A token to cancel the operation</param>
- /// <returns>A new <see cref="LWStorageDescriptor"/> if successfully created, null otherwise</returns>
- /// <exception cref="ArgumentNullException"></exception>
- /// <exception cref="LWDescriptorCreationException"></exception>
- public async Task<LWStorageDescriptor> CreateDescriptorAsync(string userId, string? descriptorIdOverride = null, CancellationToken cancellation = default)
- {
- if (string.IsNullOrWhiteSpace(userId))
- {
- throw new ArgumentNullException(nameof(userId));
- }
-
- //If no override id was specified, generate a new one
- descriptorIdOverride ??= NewDescriptorIdGenerator();
-
- DateTime createdOrModifedTime = DateTime.UtcNow;
-
- await using LWStorageContext ctx = GetContext();
- await ctx.OpenTransactionAsync(cancellation);
-
- //Make sure the descriptor doesnt exist only by its descriptor id
- if (await ctx.Descriptors.AnyAsync(d => d.Id == descriptorIdOverride, cancellation))
- {
- throw new LWDescriptorCreationException($"A descriptor with id {descriptorIdOverride} already exists");
- }
-
- //Cache time
- DateTime now = DateTime.UtcNow;
-
- //Create the new descriptor
- LWStorageEntry entry = new()
- {
- Created = now,
- LastModified = now,
- Id = descriptorIdOverride,
- UserId = userId,
- };
-
- //Add and save changes
- ctx.Descriptors.Add(entry);
-
- ERRNO result = await ctx.SaveChangesAsync(cancellation);
-
- if (!result)
- {
- //Rollback and raise exception
- await ctx.RollbackTransctionAsync(cancellation);
- throw new LWDescriptorCreationException("Failed to create descriptor, because changes could not be saved");
- }
- else
- {
- //Commit transaction and return the new descriptor
- await ctx.CommitTransactionAsync(cancellation);
- return new LWStorageDescriptor(this, entry);
- }
- }
-
- /// <summary>
- /// Attempts to retrieve <see cref="LWStorageDescriptor"/> for a given user-id. The caller is responsible for
- /// consitancy state of the descriptor
- /// </summary>
- /// <param name="userid">User's id</param>
- /// <param name="cancellation">A token to cancel the operation</param>
- /// <returns>The descriptor belonging to the user, or null if not found or error occurs</returns>
- /// <exception cref="ArgumentNullException"></exception>
- public async Task<LWStorageDescriptor?> GetDescriptorFromUIDAsync(string userid, CancellationToken cancellation = default)
- {
- //Allow null/empty entrys to just return null
- if (string.IsNullOrWhiteSpace(userid))
- {
- throw new ArgumentNullException(nameof(userid));
- }
-
- //Init db
- await using LWStorageContext db = GetContext();
- //Begin transaction
- await db.OpenTransactionAsync(cancellation);
- //Get entry
- LWStorageEntry? entry = await (from s in db.Descriptors
- where s.UserId == userid
- select s)
- .SingleOrDefaultAsync(cancellation);
-
- //Close transactions and return
- if (entry == null)
- {
- await db.RollbackTransctionAsync(cancellation);
- return null;
- }
- else
- {
- await db.CommitTransactionAsync(cancellation);
- return new (this, entry);
- }
- }
-
- /// <summary>
- /// Attempts to retrieve the <see cref="LWStorageDescriptor"/> for the given descriptor id. The caller is responsible for
- /// consitancy state of the descriptor
- /// </summary>
- /// <param name="descriptorId">Unique identifier for the descriptor</param>
- /// <param name="cancellation">A token to cancel the opreeaiton</param>
- /// <returns>The descriptor belonging to the user, or null if not found or error occurs</returns>
- /// <exception cref="ArgumentNullException"></exception>
- public async Task<LWStorageDescriptor?> GetDescriptorFromIDAsync(string descriptorId, CancellationToken cancellation = default)
- {
- //Allow null/empty entrys to just return null
- if (string.IsNullOrWhiteSpace(descriptorId))
- {
- throw new ArgumentNullException(nameof(descriptorId));
- }
-
- //Init db
- await using LWStorageContext db = GetContext();
- //Begin transaction
- await db.OpenTransactionAsync(cancellation);
- //Get entry
- LWStorageEntry? entry = await (from s in db.Descriptors
- where s.Id == descriptorId
- select s)
- .SingleOrDefaultAsync(cancellation);
-
- //Close transactions and return
- if (entry == null)
- {
- await db.RollbackTransctionAsync(cancellation);
- return null;
- }
- else
- {
- await db.CommitTransactionAsync(cancellation);
- return new (this, entry);
- }
- }
-
- /// <summary>
- /// Cleanup entries before the specified <see cref="TimeSpan"/>. Entires are store in UTC time
- /// </summary>
- /// <param name="compareTime">Time before <see cref="DateTime.UtcNow"/> to compare against</param>
- /// <param name="cancellation">A token to cancel the operation</param>
- /// <returns>The number of entires cleaned</returns>S
- public Task<ERRNO> CleanupTableAsync(TimeSpan compareTime, CancellationToken cancellation = default) => CleanupTableAsync(DateTime.UtcNow.Subtract(compareTime), cancellation);
-
- /// <summary>
- /// Cleanup entries before the specified <see cref="DateTime"/>. Entires are store in UTC time
- /// </summary>
- /// <param name="compareTime">UTC time to compare entires against</param>
- /// <param name="cancellation">A token to cancel the operation</param>
- /// <returns>The number of entires cleaned</returns>
- public async Task<ERRNO> CleanupTableAsync(DateTime compareTime, CancellationToken cancellation = default)
- {
- //Init db
- await using LWStorageContext db = GetContext();
- //Begin transaction
- await db.OpenTransactionAsync(cancellation);
-
- //Get all expired entires
- LWStorageEntry[] expired = await (from s in db.Descriptors
- where s.Created < compareTime
- select s)
- .ToArrayAsync(cancellation);
-
- //Delete
- db.Descriptors.RemoveRange(expired);
-
- //Save changes
- ERRNO count = await db.SaveChangesAsync(cancellation);
-
- //Commit transaction
- await db.CommitTransactionAsync(cancellation);
-
- return count;
- }
-
- /// <summary>
- /// Updates a descriptor's data field
- /// </summary>
- /// <param name="descriptorObj">Descriptor to update</param>
- /// <param name="data">Data string to store to descriptor record</param>
- /// <exception cref="LWStorageUpdateFailedException"></exception>
- internal async Task UpdateDescriptorAsync(object descriptorObj, Stream data)
- {
- LWStorageEntry entry = (descriptorObj as LWStorageDescriptor)!.Entry;
- ERRNO result = 0;
- try
- {
- await using LWStorageContext ctx = GetContext();
- await ctx.OpenTransactionAsync(CancellationToken.None);
-
- //Begin tracking
- ctx.Descriptors.Attach(entry);
-
- //Convert stream to vnstream
- VnMemoryStream vms = (VnMemoryStream)data;
- using (IMemoryHandle<byte> encBuffer = Memory.SafeAlloc<byte>((int)vms.Length))
- {
- //try to compress
- if(!BrotliEncoder.TryCompress(vms.AsSpan(), encBuffer.Span, out int compressed))
- {
- throw new InvalidDataException("Failed to compress the descriptor data");
- }
- //Set the data
- entry.Data = encBuffer.Span.ToArray();
- }
- //Update modified time
- entry.LastModified = DateTime.UtcNow;
-
- //Save changes
- result = await ctx.SaveChangesAsync(CancellationToken.None);
-
- //Commit or rollback
- if (result)
- {
- await ctx.CommitTransactionAsync(CancellationToken.None);
- }
- else
- {
- await ctx.RollbackTransctionAsync(CancellationToken.None);
- }
- }
- catch (Exception ex)
- {
- throw new LWStorageUpdateFailedException("", ex);
- }
- //If the result is 0 then the update failed
- if (!result)
- {
- throw new LWStorageUpdateFailedException($"Descriptor {entry.Id} failed to update");
- }
- }
-
- /// <summary>
- /// Function to remove the specified descriptor
- /// </summary>
- /// <param name="descriptorObj">The active descriptor to remove from the database</param>
- /// <exception cref="LWStorageRemoveFailedException"></exception>
- internal async Task RemoveDescriptorAsync(object descriptorObj)
- {
- LWStorageEntry descriptor = (descriptorObj as LWStorageDescriptor)!.Entry;
- ERRNO result;
- try
- {
- //Init db
- await using LWStorageContext db = GetContext();
- //Begin transaction
- await db.OpenTransactionAsync();
-
- //Delete the user from the database
- db.Descriptors.Remove(descriptor);
-
- //Save changes and commit if successful
- result = await db.SaveChangesAsync();
-
- if (result)
- {
- await db.CommitTransactionAsync();
- }
- else
- {
- await db.RollbackTransctionAsync();
- }
- }
- catch (Exception ex)
- {
- throw new LWStorageRemoveFailedException("", ex);
- }
- if (!result)
- {
- throw new LWStorageRemoveFailedException("Failed to delete the user account because of a database failure, the user may already be deleted");
- }
- }
-
- }
-} \ No newline at end of file
diff --git a/VNLib.Plugins.Extensions.Data/Storage/LWStorageRemoveFailedException.cs b/VNLib.Plugins.Extensions.Data/Storage/LWStorageRemoveFailedException.cs
deleted file mode 100644
index 806912c..0000000
--- a/VNLib.Plugins.Extensions.Data/Storage/LWStorageRemoveFailedException.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Plugins.Extensions.Data
-* File: LWStorageRemoveFailedException.cs
-*
-* LWStorageRemoveFailedException.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 VNLib.Utils.Resources;
-
-namespace VNLib.Plugins.Extensions.Data.Storage
-{
- /// <summary>
- /// The exception raised when an open <see cref="LWStorageDescriptor"/> removal operation fails. The
- /// <see cref="Exception.InnerException"/> property may contain any nested exceptions that caused the removal to fail.
- /// </summary>
- public class LWStorageRemoveFailedException : ResourceDeleteFailedException
- {
- internal LWStorageRemoveFailedException(string error, Exception inner) : base(error, inner) { }
-
- public LWStorageRemoveFailedException()
- {}
-
- public LWStorageRemoveFailedException(string message) : base(message)
- {}
- }
-} \ No newline at end of file
diff --git a/VNLib.Plugins.Extensions.Data/Storage/LWStorageUpdateFailedException.cs b/VNLib.Plugins.Extensions.Data/Storage/LWStorageUpdateFailedException.cs
deleted file mode 100644
index fe555bf..0000000
--- a/VNLib.Plugins.Extensions.Data/Storage/LWStorageUpdateFailedException.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Plugins.Extensions.Data
-* File: LWStorageUpdateFailedException.cs
-*
-* LWStorageUpdateFailedException.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 VNLib.Utils.Resources;
-
-namespace VNLib.Plugins.Extensions.Data.Storage
-{
- /// <summary>
- /// The exception raised when an open <see cref="LWStorageDescriptor"/> update operation fails. The
- /// <see cref="Exception.InnerException"/> property may contain any nested exceptions that caused the update to fail.
- /// </summary>
- public class LWStorageUpdateFailedException : ResourceUpdateFailedException
- {
- internal LWStorageUpdateFailedException(string error, Exception inner) : base(error, inner) { }
-
- public LWStorageUpdateFailedException()
- {}
- public LWStorageUpdateFailedException(string message) : base(message)
- {}
- }
-} \ No newline at end of file
diff --git a/VNLib.Plugins.Extensions.Data/Storage/UndefinedBlobStateException.cs b/VNLib.Plugins.Extensions.Data/Storage/UndefinedBlobStateException.cs
deleted file mode 100644
index e845372..0000000
--- a/VNLib.Plugins.Extensions.Data/Storage/UndefinedBlobStateException.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Plugins.Extensions.Data
-* File: UndefinedBlobStateException.cs
-*
-* UndefinedBlobStateException.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.Runtime.Serialization;
-
-namespace VNLib.Plugins.Extensions.Data.Storage
-{
- /// <summary>
- /// Raised to signal that the requested <see cref="Blob"/> was left in an undefined state
- /// when previously accessed
- /// </summary>
- public class UndefinedBlobStateException : Exception
- {
- public UndefinedBlobStateException()
- {}
- public UndefinedBlobStateException(string message) : base(message)
- {}
- public UndefinedBlobStateException(string message, Exception innerException) : base(message, innerException)
- {}
- protected UndefinedBlobStateException(SerializationInfo info, StreamingContext context) : base(info, context)
- {}
- }
-} \ No newline at end of file
diff --git a/VNLib.Plugins.Extensions.Data/TransactionalDbContext.cs b/VNLib.Plugins.Extensions.Data/TransactionalDbContext.cs
deleted file mode 100644
index 6b835c5..0000000
--- a/VNLib.Plugins.Extensions.Data/TransactionalDbContext.cs
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Plugins.Extensions.Data
-* File: TransactionalDbContext.cs
-*
-* TransactionalDbContext.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.Threading;
-using System.Threading.Tasks;
-
-using Microsoft.EntityFrameworkCore;
-using Microsoft.EntityFrameworkCore.Storage;
-
-namespace VNLib.Plugins.Extensions.Data
-{
- public abstract class TransactionalDbContext : DbContext, IAsyncDisposable
- {
- /// <summary>
- /// <inheritdoc/>
- /// </summary>
- protected TransactionalDbContext()
- {}
- /// <summary>
- /// <inheritdoc/>
- /// </summary>
- protected TransactionalDbContext(DbContextOptions options) : base(options)
- {}
-
- /// <summary>
- /// The transaction that was opened on the current context
- /// </summary>
- public IDbContextTransaction? Transaction { get; set; }
-
-
-#pragma warning disable CA1816 // Dispose methods should call SuppressFinalize, ignore because base.Dispose() is called
- ///<inheritdoc/>
- public sealed override void Dispose()
- {
- //dispose the transaction
- Transaction?.Dispose();
- base.Dispose();
- }
-
- ///<inheritdoc/>
- public override async ValueTask DisposeAsync()
- {
- //If transaction has been created, dispose the transaction
- if (Transaction != null)
- {
- await Transaction.DisposeAsync();
- }
- await base.DisposeAsync();
- }
-#pragma warning restore CA1816 // Dispose methods should call SuppressFinalize
-
- /// <summary>
- /// Opens a single transaction on the current context. If a transaction is already open,
- /// it is disposed and a new transaction is begun.
- /// </summary>
- public async Task OpenTransactionAsync(CancellationToken cancellationToken = default)
- {
- //open a new transaction on the current database
- this.Transaction = await base.Database.BeginTransactionAsync(cancellationToken);
- }
- /// <summary>
- /// Invokes the <see cref="IDbContextTransaction.Commit"/> on the current context
- /// </summary>
- public Task CommitTransactionAsync(CancellationToken token = default)
- {
- return Transaction != null ? Transaction.CommitAsync(token) : Task.CompletedTask;
- }
- /// <summary>
- /// Invokes the <see cref="IDbContextTransaction.Rollback"/> on the current context
- /// </summary>
- public Task RollbackTransctionAsync(CancellationToken token = default)
- {
- return Transaction != null ? Transaction.RollbackAsync(token) : Task.CompletedTask;
- }
-
- }
-} \ No newline at end of file
diff --git a/VNLib.Plugins.Extensions.Data/VNLib.Plugins.Extensions.Data.csproj b/VNLib.Plugins.Extensions.Data/VNLib.Plugins.Extensions.Data.csproj
deleted file mode 100644
index b229e64..0000000
--- a/VNLib.Plugins.Extensions.Data/VNLib.Plugins.Extensions.Data.csproj
+++ /dev/null
@@ -1,54 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-
- <PropertyGroup>
- <TargetFramework>net6.0</TargetFramework>
- <RootNamespace>VNLib.Plugins.Extensions.Data</RootNamespace>
-
- </PropertyGroup>
-
- <!-- Resolve nuget dll files and store them in the output dir -->
- <PropertyGroup>
- <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
- <AssemblyName>VNLib.Plugins.Extensions.Data</AssemblyName>
- <Authors>Vaughn Nugent</Authors>
- <Description>Data extensions for VNLib Plugins</Description>
- <Copyright>Copyright © 2022 Vaughn Nugent</Copyright>
- <PackageProjectUrl>https://www.vaughnnugent.com/resources</PackageProjectUrl>
- <Version>1.0.1.1</Version>
- <Nullable>enable</Nullable>
- <SignAssembly>True</SignAssembly>
- <AssemblyOriginatorKeyFile>\\vaughnnugent.com\Internal\Folder Redirection\vman\Documents\Programming\Software\StrongNameingKey.snk</AssemblyOriginatorKeyFile>
- </PropertyGroup>
-
- <PropertyGroup>
- <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
- <GenerateDocumentationFile>True</GenerateDocumentationFile>
- <AnalysisLevel>latest-all</AnalysisLevel>
- </PropertyGroup>
-
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
- <Deterministic>False</Deterministic>
- </PropertyGroup>
-
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
- <Deterministic>False</Deterministic>
- </PropertyGroup>
-
- <ItemGroup>
- <PackageReference Include="ErrorProne.NET.CoreAnalyzers" Version="0.1.2">
- <PrivateAssets>all</PrivateAssets>
- <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
- </PackageReference>
- <PackageReference Include="ErrorProne.NET.Structs" Version="0.1.2">
- <PrivateAssets>all</PrivateAssets>
- <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
- </PackageReference>
- <PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.11" />
- <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.11" />
- </ItemGroup>
-
- <ItemGroup>
- <ProjectReference Include="..\..\..\VNLib\Utils\src\VNLib.Utils.csproj" />
- </ItemGroup>
-
-</Project>
diff --git a/VNLib.Plugins.Extensions.Data/VNLib.Plugins.Extensions.Data.xml b/VNLib.Plugins.Extensions.Data/VNLib.Plugins.Extensions.Data.xml
deleted file mode 100644
index 2f7736e..0000000
--- a/VNLib.Plugins.Extensions.Data/VNLib.Plugins.Extensions.Data.xml
+++ /dev/null
@@ -1,476 +0,0 @@
-<?xml version="1.0"?>
-<!--
-Copyright (c) 2022 Vaughn Nugent
--->
-<doc>
- <assembly>
- <name>VNLib.Plugins.Extensions.Data</name>
- </assembly>
- <members>
- <member name="T:VNLib.Plugins.Extensions.Data.Abstractions.IBulkDataStore`1">
- <summary>
- An abstraction that defines a Data-Store that supports
- bulk data operations
- </summary>
- <typeparam name="T">The data-model type</typeparam>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.Abstractions.IBulkDataStore`1.DeleteBulkAsync(System.Collections.Generic.ICollection{`0})">
- <summary>
- Deletes a collection of records from the store
- </summary>
- <param name="records">A collection of records to delete</param>
- <returns>A task the resolves the number of entires removed from the store</returns>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.Abstractions.IBulkDataStore`1.UpdateBulkAsync(System.Collections.Generic.ICollection{`0})">
- <summary>
- Updates a collection of records
- </summary>
- <param name="records">The collection of records to update</param>
- <returns>A task the resolves an error code (should evaluate to false on failure, and true on success)</returns>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.Abstractions.IBulkDataStore`1.CreateBulkAsync(System.Collections.Generic.ICollection{`0})">
- <summary>
- Creates a bulk collection of records as entries in the store
- </summary>
- <param name="records">The collection of records to add</param>
- <returns>A task the resolves an error code (should evaluate to false on failure, and true on success)</returns>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.Abstractions.IBulkDataStore`1.AddOrUpdateBulkAsync(System.Collections.Generic.ICollection{`0})">
- <summary>
- Creates or updates individual records from a bulk collection of records
- </summary>
- <param name="records">The collection of records to add</param>
- <returns>A task the resolves an error code (should evaluate to false on failure, and true on success)</returns>
- </member>
- <member name="T:VNLib.Plugins.Extensions.Data.Abstractions.IDataStore`1">
- <summary>
- An abstraction that defines a Data-Store and common
- operations that retrieve or manipulate records of data
- </summary>
- <typeparam name="T">The data-model type</typeparam>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.Abstractions.IDataStore`1.GetCountAsync">
- <summary>
- Gets the total number of records in the current store
- </summary>
- <returns>A task that resolves the number of records in the store</returns>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.Abstractions.IDataStore`1.GetCountAsync(System.String)">
- <summary>
- Gets the number of records that belong to the specified constraint
- </summary>
- <param name="specifier">A specifier to constrain the reults</param>
- <returns>The number of records that belong to the specifier</returns>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.Abstractions.IDataStore`1.GetSingleAsync(System.String)">
- <summary>
- Gets a record from its key
- </summary>
- <param name="key">The key identifying the unique record</param>
- <returns>A promise that resolves the record identified by the specified key</returns>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.Abstractions.IDataStore`1.GetSingleAsync(System.String[])">
- <summary>
- Gets a record from its key
- </summary>
- <param name="specifiers">A variable length specifier arguemnt array for retreiving a single application</param>
- <returns></returns>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.Abstractions.IDataStore`1.GetSingleAsync(`0)">
- <summary>
- Gets a record from the store with a partial model, intended to complete the model
- </summary>
- <param name="record">The partial model used to query the store</param>
- <returns>A task the resolves the completed data-model</returns>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.Abstractions.IDataStore`1.GetCollectionAsync(System.Collections.Generic.ICollection{`0},System.String,System.Int32)">
- <summary>
- Fills a collection with enires retireved from the store using the specifer
- </summary>
- <param name="collection">The collection to add entires to</param>
- <param name="specifier">A specifier argument to constrain results</param>
- <param name="limit">The maximum number of elements to retrieve</param>
- <returns>A Task the resolves to the number of items added to the collection</returns>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.Abstractions.IDataStore`1.GetCollectionAsync(System.Collections.Generic.ICollection{`0},System.Int32,System.String[])">
- <summary>
- Fills a collection with enires retireved from the store using a variable length specifier
- parameter
- </summary>
- <param name="collection">The collection to add entires to</param>
- <param name="limit">The maximum number of elements to retrieve</param>
- <param name="args"></param>
- <returns>A Task the resolves to the number of items added to the collection</returns>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.Abstractions.IDataStore`1.UpdateAsync(`0)">
- <summary>
- Updates an entry in the store with the specified record
- </summary>
- <param name="record">The record to update</param>
- <returns>A task the resolves an error code (should evaluate to false on failure, and true on success)</returns>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.Abstractions.IDataStore`1.CreateAsync(`0)">
- <summary>
- Creates a new entry in the store representing the specified record
- </summary>
- <param name="record">The record to add to the store</param>
- <returns>A task the resolves an error code (should evaluate to false on failure, and true on success)</returns>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.Abstractions.IDataStore`1.DeleteAsync(`0)">
- <summary>
- Deletes one or more entrires from the store matching the specified record
- </summary>
- <param name="record">The record to remove from the store</param>
- <returns>A task the resolves the number of records removed(should evaluate to false on failure, and deleted count on success)</returns>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.Abstractions.IDataStore`1.DeleteAsync(System.String)">
- <summary>
- Deletes one or more entires from the store matching the specified unique key
- </summary>
- <param name="key">The unique key that identifies the record</param>
- <returns>A task the resolves the number of records removed(should evaluate to false on failure, and deleted count on success)</returns>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.Abstractions.IDataStore`1.DeleteAsync(System.String[])">
- <summary>
- Deletes one or more entires from the store matching the supplied specifiers
- </summary>
- <param name="specifiers">A variable length array of specifiers used to delete one or more entires</param>
- <returns>A task the resolves the number of records removed(should evaluate to false on failure, and deleted count on success)</returns>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.Abstractions.IDataStore`1.AddOrUpdateAsync(`0)">
- <summary>
- Updates an entry in the store if it exists, or creates a new entry if one does not already exist
- </summary>
- <param name="record">The record to add to the store</param>
- <returns>A task the resolves the result of the operation</returns>
- </member>
- <member name="T:VNLib.Plugins.Extensions.Data.Abstractions.IPaginatedDataStore`1">
- <summary>
- Defines a Data-Store that can retirieve and manipulate paginated
- data
- </summary>
- <typeparam name="T">The data-model type</typeparam>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.Abstractions.IPaginatedDataStore`1.GetPageAsync(System.Collections.Generic.ICollection{`0},System.Int32,System.Int32)">
- <summary>
- Gets a collection of records using a pagination style query, and adds the records to the collecion
- </summary>
- <param name="collection">The collection to add records to</param>
- <param name="page">Pagination page to get records from</param>
- <param name="limit">The maximum number of items to retrieve from the store</param>
- <returns>A task that resolves the number of items added to the collection</returns>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.Abstractions.IPaginatedDataStore`1.GetPageAsync(System.Collections.Generic.ICollection{`0},System.Int32,System.Int32,System.String[])">
- <summary>
- Gets a collection of records using a pagination style query with constraint arguments, and adds the records to the collecion
- </summary>
- <param name="collection">The collection to add records to</param>
- <param name="page">Pagination page to get records from</param>
- <param name="limit">The maximum number of items to retrieve from the store</param>
- <param name="constraints">A params array of strings to constrain the result set from the db</param>
- <returns>A task that resolves the number of items added to the collection</returns>
- </member>
- <member name="T:VNLib.Plugins.Extensions.Data.Abstractions.IUserEntity">
- <summary>
- Defines an entity base that has an owner, identified by its user-id
- </summary>
- </member>
- <member name="P:VNLib.Plugins.Extensions.Data.Abstractions.IUserEntity.UserId">
- <summary>
- The user-id of the owner of the entity
- </summary>
- </member>
- <member name="T:VNLib.Plugins.Extensions.Data.DbModelBase">
- <summary>
- Provides a base for DBSet Records with a timestamp/version
- a unique ID key, and create/modified timestamps
- </summary>
- </member>
- <member name="P:VNLib.Plugins.Extensions.Data.DbModelBase.Id">
- <inheritdoc/>
- </member>
- <member name="P:VNLib.Plugins.Extensions.Data.DbModelBase.Version">
- <inheritdoc/>
- </member>
- <member name="P:VNLib.Plugins.Extensions.Data.DbModelBase.Created">
- <inheritdoc/>
- </member>
- <member name="P:VNLib.Plugins.Extensions.Data.DbModelBase.LastModified">
- <inheritdoc/>
- </member>
- <member name="T:VNLib.Plugins.Extensions.Data.DbStore`1">
- <summary>
- Implements basic data-store functionality with abstract query builders
- </summary>
- <typeparam name="T">A <see cref="T:VNLib.Plugins.Extensions.Data.DbModelBase"/> implemented type</typeparam>
- </member>
- <member name="P:VNLib.Plugins.Extensions.Data.DbStore`1.RecordIdBuilder">
- <summary>
- Gets a unique ID for a new record being added to the store
- </summary>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.DbStore`1.NewContext">
- <summary>
- Gets a new <see cref="T:VNLib.Plugins.Extensions.Data.TransactionalDbContext"/> ready for use
- </summary>
- <returns></returns>
- </member>
- <member name="P:VNLib.Plugins.Extensions.Data.DbStore`1.ListRental">
- <summary>
- An object rental for entity collections
- </summary>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.DbStore`1.AddOrUpdateAsync(`0)">
- <inheritdoc/>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.DbStore`1.UpdateAsync(`0)">
- <inheritdoc/>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.DbStore`1.CreateAsync(`0)">
- <inheritdoc/>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.DbStore`1.AddOrUpdateQueryBuilder(VNLib.Plugins.Extensions.Data.TransactionalDbContext,`0)">
- <summary>
- 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 <see cref="P:VNLib.Plugins.Extensions.Data.DbModelBase.Id"/> property
- </summary>
- <param name="context">The active context to query</param>
- <param name="record">The record to search for</param>
- <returns>A query that yields a single record if it exists in the store</returns>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.DbStore`1.UpdateQueryBuilder(VNLib.Plugins.Extensions.Data.TransactionalDbContext,`0)">
- <summary>
- Builds a query that attempts to get a single entry from the
- store to update based on the specified record
- </summary>
- <param name="context">The active context to query</param>
- <param name="record">The record to search for</param>
- <returns>A query that yields a single record to update if it exists in the store</returns>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.DbStore`1.OnRecordUpdate(`0,`0)">
- <summary>
- Updates the current record (if found) to the new record before
- storing the updates.
- </summary>
- <param name="newRecord">The new record to capture data from</param>
- <param name="currentRecord">The current record to be updated</param>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.DbStore`1.DeleteAsync(System.String)">
- <inheritdoc/>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.DbStore`1.DeleteAsync(`0)">
- <inheritdoc/>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.DbStore`1.DeleteAsync(System.String[])">
- <inheritdoc/>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.DbStore`1.DeleteQueryBuilder(VNLib.Plugins.Extensions.Data.TransactionalDbContext,System.String[])">
- <summary>
- Builds a query that results in a single entry to delete from the
- constraint arguments
- </summary>
- <param name="context">The active context</param>
- <param name="constraints">A variable length parameter array of query constraints</param>
- <returns>A query that yields a single record (or no record) to delete</returns>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.DbStore`1.GetCollectionAsync(System.Collections.Generic.ICollection{`0},System.String,System.Int32)">
- <inheritdoc/>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.DbStore`1.GetCollectionAsync(System.Collections.Generic.ICollection{`0},System.Int32,System.String[])">
- <inheritdoc/>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.DbStore`1.GetCollectionQueryBuilder(VNLib.Plugins.Extensions.Data.TransactionalDbContext,System.String)">
- <summary>
- Builds a query to get a count of records constrained by the specifier
- </summary>
- <param name="context">The active context to run the query on</param>
- <param name="specifier">The specifier constrain</param>
- <returns>A query that can be counted</returns>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.DbStore`1.GetCollectionQueryBuilder(VNLib.Plugins.Extensions.Data.TransactionalDbContext,System.String[])">
- <summary>
- Builds a query to get a collection of records based on an variable length array of parameters
- </summary>
- <param name="context">The active context to run the query on</param>
- <param name="constraints">An arguments array to constrain the results of the query</param>
- <returns>A query that returns a collection of records from the store</returns>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.DbStore`1.GetCountAsync">
- <inheritdoc/>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.DbStore`1.GetCountAsync(System.String)">
- <inheritdoc/>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.DbStore`1.GetCountQueryBuilder(VNLib.Plugins.Extensions.Data.TransactionalDbContext,System.String)">
- <summary>
- Builds a query to get a count of records constrained by the specifier
- </summary>
- <param name="context">The active context to run the query on</param>
- <param name="specifier">The specifier constrain</param>
- <returns>A query that can be counted</returns>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.DbStore`1.GetSingleAsync(System.String)">
- <inheritdoc/>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.DbStore`1.GetSingleAsync(`0)">
- <inheritdoc/>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.DbStore`1.GetSingleAsync(System.String[])">
- <inheritdoc/>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.DbStore`1.GetSingleQueryBuilder(VNLib.Plugins.Extensions.Data.TransactionalDbContext,System.String[])">
- <summary>
- Builds a query to get a single record from the variable length parameter arguments
- </summary>
- <param name="context">The context to execute query against</param>
- <param name="constraints">Arguments to constrain the results of the query to a single record</param>
- <returns>A query that yields a single record</returns>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.DbStore`1.GetSingleQueryBuilder(VNLib.Plugins.Extensions.Data.TransactionalDbContext,`0)">
- <summary>
- <para>
- Builds a query to get a single record from the specified record.
- </para>
- <para>
- Unless overridden, performs an ID based query for a single entry
- </para>
- </summary>
- <param name="context">The context to execute query against</param>
- <param name="record">A record to referrence the lookup</param>
- <returns>A query that yields a single record</returns>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.DbStore`1.GetPageAsync(System.Collections.Generic.ICollection{`0},System.Int32,System.Int32)">
- <inheritdoc/>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.DbStore`1.GetPageAsync(System.Collections.Generic.ICollection{`0},System.Int32,System.Int32,System.String[])">
- <inheritdoc/>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.DbStore`1.GetPageQueryBuilder(VNLib.Plugins.Extensions.Data.TransactionalDbContext,System.String[])">
- <summary>
- Builds a query to get a collection of records based on an variable length array of parameters
- </summary>
- <param name="context">The active context to run the query on</param>
- <param name="constraints">An arguments array to constrain the results of the query</param>
- <returns>A query that returns a paginated collection of records from the store</returns>
- </member>
- <member name="T:VNLib.Plugins.Extensions.Data.IDbModel">
- <summary>
- Represents a basic data model for an EFCore entity
- for support in data-stores
- </summary>
- </member>
- <member name="P:VNLib.Plugins.Extensions.Data.IDbModel.Id">
- <summary>
- A unique id for the entity
- </summary>
- </member>
- <member name="P:VNLib.Plugins.Extensions.Data.IDbModel.Created">
- <summary>
- The <see cref="T:System.DateTimeOffset"/> the entity was created in the store
- </summary>
- </member>
- <member name="P:VNLib.Plugins.Extensions.Data.IDbModel.LastModified">
- <summary>
- The <see cref="T:System.DateTimeOffset"/> the entity was last modified in the store
- </summary>
- </member>
- <member name="P:VNLib.Plugins.Extensions.Data.IDbModel.Version">
- <summary>
- Entity concurrency token
- </summary>
- </member>
- <member name="T:VNLib.Plugins.Extensions.Data.ProtectedDbStore`1">
- <summary>
- A data store that provides unique identities and protections based on an entity that has an owner <see cref="T:VNLib.Plugins.Extensions.Data.Abstractions.IUserEntity"/>
- </summary>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.ProtectedDbStore`1.GetCollectionQueryBuilder(VNLib.Plugins.Extensions.Data.TransactionalDbContext,System.String[])">
- <inheritdoc/>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.ProtectedDbStore`1.GetSingleQueryBuilder(VNLib.Plugins.Extensions.Data.TransactionalDbContext,System.String[])">
- <summary>
- Gets a single item contrained by a given user-id and item id
- </summary>
- <param name="context"></param>
- <param name="constraints"></param>
- <returns></returns>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.ProtectedDbStore`1.GetSingleQueryBuilder(VNLib.Plugins.Extensions.Data.TransactionalDbContext,`0)">
- <inheritdoc/>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.ProtectedEntityExtensions.UpdateAsync``1(VNLib.Plugins.Extensions.Data.Abstractions.IDataStore{``0},``0,System.String)">
- <summary>
- Updates the specified record within the store
- </summary>
- <param name="store"></param>
- <param name="record">The record to update</param>
- <param name="userId">The userid of the record owner</param>
- <returns>A task that evaluates to the number of records modified</returns>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.ProtectedEntityExtensions.CreateAsync``1(VNLib.Plugins.Extensions.Data.Abstractions.IDataStore{``0},``0,System.String)">
- <summary>
- Updates the specified record within the store
- </summary>
- <param name="store"></param>
- <param name="record">The record to update</param>
- <param name="userId">The userid of the record owner</param>
- <returns>A task that evaluates to the number of records modified</returns>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.ProtectedEntityExtensions.GetSingleAsync``1(VNLib.Plugins.Extensions.Data.Abstractions.IDataStore{``0},System.String,System.String)">
- <summary>
- Gets a single entity from its ID and user-id
- </summary>
- <param name="store"></param>
- <param name="key">The unique id of the entity</param>
- <param name="userId">The user's id that owns the resource</param>
- <returns>A task that resolves the entity or null if not found</returns>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.ProtectedEntityExtensions.DeleteAsync``1(VNLib.Plugins.Extensions.Data.Abstractions.IDataStore{``0},System.String,System.String)">
- <summary>
- Deletes a single entiry by its ID only if it belongs to the speicifed user
- </summary>
- <param name="store"></param>
- <param name="key">The unique id of the entity</param>
- <param name="userId">The user's id that owns the resource</param>
- <returns>A task the resolves the number of eneities deleted (should evaluate to true or false)</returns>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.TransactionalDbContext.#ctor">
- <summary>
- <inheritdoc/>
- </summary>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.TransactionalDbContext.#ctor(Microsoft.EntityFrameworkCore.DbContextOptions)">
- <summary>
- <inheritdoc/>
- </summary>
- </member>
- <member name="P:VNLib.Plugins.Extensions.Data.TransactionalDbContext.Transaction">
- <summary>
- The transaction that was opened on the current context
- </summary>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.TransactionalDbContext.Dispose">
- <inheritdoc/>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.TransactionalDbContext.OpenTransactionAsync(System.Threading.CancellationToken)">
- <summary>
- Opens a single transaction on the current context. If a transaction is already open,
- it is disposed and a new transaction is begun.
- </summary>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.TransactionalDbContext.CommitTransactionAsync(System.Threading.CancellationToken)">
- <summary>
- Invokes the <see cref="M:Microsoft.EntityFrameworkCore.Storage.IDbContextTransaction.Commit"/> on the current context
- </summary>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.TransactionalDbContext.RollbackTransctionAsync(System.Threading.CancellationToken)">
- <summary>
- Invokes the <see cref="M:Microsoft.EntityFrameworkCore.Storage.IDbContextTransaction.Rollback"/> on the current context
- </summary>
- </member>
- <member name="M:VNLib.Plugins.Extensions.Data.TransactionalDbContext.DisposeAsync">
- <inheritdoc/>
- </member>
- </members>
-</doc>