Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Magic.IndexedDb/Extensions/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ public static class ServiceCollectionExtensions
{
public static IServiceCollection AddBlazorDB(this IServiceCollection services, Action<DbStore> options)
{
services.TryAddScoped<IMagicDbFactory, MagicDbFactory>();

var dbStore = new DbStore();
options(dbStore);

services.AddTransient<DbStore>((_) => dbStore);
services.TryAddSingleton<IMagicDbFactory, MagicDbFactory>();
_ = services.AddSingleton(dbStore);

return services;
}
Expand Down
24 changes: 20 additions & 4 deletions Magic.IndexedDb/Factories/MagicDbFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,32 @@

namespace Magic.IndexedDb.Factories
{
public class MagicDbFactory : IMagicDbFactory
public class MagicDbFactory : IMagicDbFactory, IAsyncDisposable
{
readonly IJSRuntime _jsRuntime;
readonly Task<IJSObjectReference> _jsRuntime;
readonly IServiceProvider _serviceProvider;
readonly IDictionary<string, IndexedDbManager> _databases = new Dictionary<string, IndexedDbManager>();

public MagicDbFactory(IServiceProvider serviceProvider, IJSRuntime jSRuntime)
{
_serviceProvider = serviceProvider;
_jsRuntime = jSRuntime;
this._jsRuntime = jSRuntime.InvokeAsync<IJSObjectReference>(
"import",
"./_content/Magic.IndexedDb/magicDB.js").AsTask();
}
public async ValueTask DisposeAsync()
{
var js = await _jsRuntime;
try
{
var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10));
await js.InvokeVoidAsync(IndexedDbFunctions.CLOSE_ALL, timeout.Token);
}
catch
{
// do nothing here
}
await js.DisposeAsync();
}

public async ValueTask<IndexedDbManager> OpenAsync(
Expand All @@ -23,7 +39,7 @@ public async ValueTask<IndexedDbManager> OpenAsync(
if (force || !_databases.ContainsKey(dbStore.Name))
{
var db = await IndexedDbManager.CreateAndOpenAsync(
dbStore, _jsRuntime, cancellationToken);
dbStore, await _jsRuntime, cancellationToken);
_databases[dbStore.Name] = db;
}
return _databases[dbStore.Name];
Expand Down
38 changes: 9 additions & 29 deletions Magic.IndexedDb/IndexDbManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Linq.Expressions;
using System.Reflection;
using System.Text.Json;
using System.Threading;
using Magic.IndexedDb.Factories;
using Magic.IndexedDb.Helpers;
using Magic.IndexedDb.Models;
Expand All @@ -17,46 +16,29 @@ namespace Magic.IndexedDb
/// <summary>
/// Provides functionality for accessing IndexedDB from Blazor application
/// </summary>
public sealed class IndexedDbManager : IAsyncDisposable
public sealed class IndexedDbManager
{
internal static async ValueTask<IndexedDbManager> CreateAndOpenAsync(
DbStore dbStore, IJSRuntime jsRuntime,
DbStore dbStore, IJSObjectReference jsRuntime,
CancellationToken cancellationToken = default)
{
var result = new IndexedDbManager(dbStore, jsRuntime);
try
{
await result.CallJsAsync(IndexedDbFunctions.CREATE_DB, cancellationToken, [dbStore]);
return result;
}
catch
{
await result.DisposeAsync();
throw;
}
await result.CallJsAsync(IndexedDbFunctions.CREATE_DB, cancellationToken, [dbStore]);
return result;
}


readonly DbStore _dbStore;
readonly Task<IJSObjectReference> _jsModule;

public async ValueTask DisposeAsync()
{
var module = await _jsModule;
await module.DisposeAsync();
}
readonly IJSObjectReference _jsModule;

/// <summary>
/// Ctor
/// </summary>
/// <param name="dbStore"></param>
/// <param name="jsRuntime"></param>
private IndexedDbManager(DbStore dbStore, IJSRuntime jsRuntime)
private IndexedDbManager(DbStore dbStore, IJSObjectReference jsRuntime)
{
this._dbStore = dbStore;
this._jsModule = jsRuntime.InvokeAsync<IJSObjectReference>(
"import",
"./_content/Magic.IndexedDb/magicDB.js").AsTask();
this._jsModule = jsRuntime;
}

// TODO: make it readonly
Expand Down Expand Up @@ -806,14 +788,12 @@ public Task ClearTableAsync<T>(CancellationToken cancellationToken = default) wh

internal async Task CallJsAsync(string functionName, CancellationToken token, object[] args)
{
var mod = await this._jsModule;
await mod.InvokeVoidAsync(functionName, token, args);
await this._jsModule.InvokeVoidAsync(functionName, token, args);
}

internal async Task<T> CallJsAsync<T>(string functionName, CancellationToken token, object[] args)
{
var mod = await this._jsModule;
return await mod.InvokeAsync<T>(functionName, token, args);
return await this._jsModule.InvokeAsync<T>(functionName, token, args);
}
}
}
1 change: 1 addition & 0 deletions Magic.IndexedDb/IndexedDbFunctions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ namespace Magic.IndexedDb
internal struct IndexedDbFunctions
{
public const string CREATE_DB = "createDb";
public const string CLOSE_ALL = "closeAll";
public const string DELETE_DB = "deleteDb";
public const string ADD_ITEM = "addItem";
public const string BULKADD_ITEM = "bulkAddItem";
Expand Down
8 changes: 8 additions & 0 deletions Magic.IndexedDb/wwwroot/magicDB.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ export function createDb(dbStore)
db.open();
}

export function closeAll()
{
const dbs = databases;
databases = [];
for (db of dbs)
db.db.close();
}

export async function deleteDb(dbName)
{
const db = await getDb(dbName);
Expand Down
31 changes: 10 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,16 @@ This open source library provides an IndexedDb wrapper for C# and Blazor WebAsse
This code is still very young. I will be making updates for this code as I come across it. I will try my best to not depreciate or break syntax already in use. But please take note of any version updates before you use my code if you're updating it in the future. As I will not guarentee right now that I won't break your stuff if you download this version and then come back in a year and get the latest version.

## Future Planned Features
[X] Updating soon to NET 8

[] Reset Primary Key starting Id

[] Compound Key Indexing

[] Easy table syncing functionality with API

[X] Allow Any and/or All Linq statements inside the WHERE query

[] Handling of Nested OR conditions in where query

[] API like response protocal from JS. This will allow better debugging and make it easier to expand the code. I left the original weak reference system build by nwestfall, but I will be removing that code for a system I believe is easier to tame and more appropriate for the project goals.

[] Superior & easy version handling and table altering. Current form handles changes easily but it'd take some work to do serious data migrations. I want data migrations to be built in c#, translated to clients, and automatically handled with extreme ease. I have some really interesting protocals I've brainstormed and would like to experiment with.

[] Deferred execution of table joins. I want c# join abilities to properly join tables together.

[] Superior reflections. The current version of reflections is fine, but I've not spent much time optimizing. I need to convert more into hash sets, dictionaries, and more. This wrapper is meant to be a very expandable version that will engulf indexedDb with a great deal of capabilities. Fine tuning and perfecting the protocal I'm working on will allow some very cool features in the future.

[] **Long Term** - NET 8 provides AOT features that I think could be extremely abusive in a good way for this project. I believe with future NET 8 possibilites and AOT, I can move IndexedDB into being a multi thread monster and various other performance improvements. Obviously I'd make this optional. But I believe there's some very interesting possibilities I'd like to experiment with in the future.
- [ ] Reset Primary Key starting Id
- [ ] Compound Key Indexing
- [ ] Easy table syncing functionality with API
- [X] Allow Any and/or All Linq statements inside the WHERE query
- [ ] Handling of Nested OR conditions in where query
- [ ] API like response protocal from JS. This will allow better debugging and make it easier to expand the code. I left the original weak reference system build by nwestfall, but I will be removing that code for a system I believe is easier to tame and more appropriate for the project goals.
- [ ] Superior & easy version handling and table altering. Current form handles changes easily but it'd take some work to do serious data migrations. I want data migrations to be built in c#, translated to clients, and automatically handled with extreme ease. I have some really interesting protocals I've brainstormed and would like to experiment with.
- [ ] Deferred execution of table joins. I want c# join abilities to properly join tables together.
- [ ] Superior reflections. The current version of reflections is fine, but I've not spent much time optimizing. I need to convert more into hash sets, dictionaries, and more. This wrapper is meant to be a very expandable version that will engulf indexedDb with a great deal of capabilities. Fine tuning and perfecting the protocal I'm working on will allow some very cool features in the future.
- [ ] **Long Term** - NET 8 provides AOT features that I think could be extremely abusive in a good way for this project. I believe with future NET 8 possibilites and AOT, I can move IndexedDB into being a multi thread monster and various other performance improvements. Obviously I'd make this optional. But I believe there's some very interesting possibilities I'd like to experiment with in the future.

## Table of Contents

Expand Down