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
2 changes: 1 addition & 1 deletion Magic.IndexedDb/Extensions/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public static IServiceCollection AddMagicBlazorDB(this IServiceCollection servic
long jsMessageSizeBytes, bool isDebug)
{
services.AddScoped<IMagicIndexedDb>(sp =>
new MagicDbFactory(sp, sp.GetRequiredService<IJSRuntime>(), jsMessageSizeBytes));
new MagicDbFactory(sp.GetRequiredService<IJSRuntime>(), jsMessageSizeBytes));

if (isDebug)
{
Expand Down
143 changes: 65 additions & 78 deletions Magic.IndexedDb/Factories/MagicDbFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,44 +7,60 @@
using System.Collections.Concurrent;
using System.Reflection;
using Magic.IndexedDb.LinqTranslation.Interfaces;
using System.Diagnostics;
using System.Threading;

namespace Magic.IndexedDb.Factories
{
internal class MagicDbFactory : IMagicIndexedDb, IAsyncDisposable
{
internal MagicDbFactory(long jsMessageSizeBytes)
// null value indicates that the factory is disposed
Lazy<Task<IJSObjectReference>>? _jsModule;
Lazy<Task<IndexedDbManager>> _magicJsManager;
public MagicDbFactory(IJSRuntime jSRuntime, long jsMessageSizeBytes)
{
Cache.JsMessageSizeBytes = jsMessageSizeBytes;
}

Lazy<Task<IJSObjectReference>>? _jsRuntime;
readonly IServiceProvider _serviceProvider;
public static IndexedDbManager? _MagicJsManager { get; set; } = null;
private IJSObjectReference? _cachedJsModule; // Shared JS module instance
public MagicDbFactory(IServiceProvider serviceProvider, IJSRuntime jSRuntime, long jsMessageSizeBytes)
{
_serviceProvider = serviceProvider;
this._jsRuntime = new(() => jSRuntime.InvokeAsync<IJSObjectReference>(
this._jsModule = new(() => jSRuntime.InvokeAsync<IJSObjectReference>(
"import",
"./_content/Magic.IndexedDb/magicDbMethods.js").AsTask());
}
"./_content/Magic.IndexedDb/magicDbMethods.js").AsTask(),
isThreadSafe: true);

/// <summary>
/// Get or initialize the shared JavaScript module.
/// </summary>
private async Task<IJSObjectReference> GetJsModuleAsync()
{
if (_cachedJsModule is not null)
return _cachedJsModule;
this._magicJsManager = new(async () =>
{
var jsModule = await this._jsModule.Value;

var dbSchemas = SchemaHelper.GetAllSchemas();
// Create & Open the database (formerly in IndexedDbManager)
var manager = new IndexedDbManager(jsModule);

_cachedJsModule = await _jsRuntime.Value;
return _cachedJsModule;
var dbSets = SchemaHelper.GetAllIndexedDbSets();

if (dbSets != null)
{
foreach (var dbSet in dbSets)
{
await new MagicJsInvoke(jsModule).CallJsAsync(Cache.MagicDbJsImportPath,
IndexedDbFunctions.CREATE_LEGACY, default,
new TypedArgument<DbStore>(new DbStore()
{
Name = dbSet.DatabaseName,
Version = 1,
StoreSchemas = dbSchemas
}));
}
}
else
{
Console.WriteLine("No IndexedDbSet found and/or no found IMagicRepository.");
}
return manager;
},
isThreadSafe: true);
}

public async ValueTask DisposeAsync()
{
var js = _jsRuntime;
_jsRuntime = null;
var js = _jsModule;
_jsModule = null;

if (js is null || !js.IsValueCreated)
return;
Expand Down Expand Up @@ -79,58 +95,23 @@ public async ValueTask DisposeAsync()
}
}

/// <summary>
/// Ensure a database is opened and properly associated with the shared JS module.
/// </summary>
private async ValueTask<IndexedDbManager> GetOrCreateDatabaseAsync(CancellationToken cancellationToken = default)
{
if (_MagicJsManager != null)
return _MagicJsManager; // Return cached instance

var jsModule = await GetJsModuleAsync(); // Ensure shared JS module is ready

var dbSchemas = SchemaHelper.GetAllSchemas();
// Create & Open the database (formerly in IndexedDbManager)
var manager = new IndexedDbManager(jsModule);

var dbSets = SchemaHelper.GetAllIndexedDbSets();

if (dbSets != null)
{
foreach (var dbSet in dbSets)
{
await new MagicJsInvoke(jsModule).CallJsAsync(Cache.MagicDbJsImportPath,
IndexedDbFunctions.CREATE_LEGACY, cancellationToken,
new TypedArgument<DbStore>(new DbStore()
{
Name = dbSet.DatabaseName,
Version = 1,
StoreSchemas = dbSchemas
}));
}
}
else
{
Console.WriteLine("No IndexedDbSet found and/or no found IMagicRepository.");
}
_MagicJsManager = manager; // Cache the opened database
return _MagicJsManager;
}


/// <summary>
/// Get storage estimate using the shared JS module.
/// </summary>
public async Task<QuotaUsage> GetStorageEstimateAsync(CancellationToken cancellationToken = default)
{
var jsModule = await GetJsModuleAsync(); // Shared JS module reference
ObjectDisposedException.ThrowIf(this._jsModule is null, this);

var jsModule = await this._jsModule.Value;
var magicUtility = new MagicUtilities(jsModule);
return await magicUtility.GetStorageEstimateAsync();
}
[Obsolete("Not fully implemented yet until full migration protocol finished.")]
public async ValueTask<IMagicQuery<T>> Query<T>(IndexedDbSet indexedDbSet)
where T : class, IMagicTableBase, new()
where T : class, IMagicTableBase, new()
{
ObjectDisposedException.ThrowIf(this._jsModule is null, this);

// Get database name and schema name
string databaseName = indexedDbSet.DatabaseName;
string schemaName = SchemaHelper.GetTableName<T>();
Expand All @@ -140,9 +121,11 @@ public async ValueTask<IMagicQuery<T>> Query<T>(IndexedDbSet indexedDbSet)


public async ValueTask<IMagicQuery<T>> Query<T>(
Func<T, IndexedDbSet> dbSetSelector)
where T : class, IMagicTableBase, new()
Func<T, IndexedDbSet> dbSetSelector)
where T : class, IMagicTableBase, new()
{
ObjectDisposedException.ThrowIf(this._jsModule is null, this);

// Create an instance of T to access `DbSets`
var modelInstance = new T();

Expand All @@ -153,39 +136,43 @@ public async ValueTask<IMagicQuery<T>> Query<T>(
string databaseName = selectedDbSet.DatabaseName;
string schemaName = SchemaHelper.GetTableName<T>();

#pragma warning disable CS0618
return await QueryOverride<T>(databaseName, schemaName);
#pragma warning restore CS0618
}

/// <summary>
/// Query the database for a given type. Automatically opens the database if needed.
/// </summary>
public async ValueTask<IMagicQuery<T>> Query<T>()
where T : class, IMagicTableBase, new()
{
{
ObjectDisposedException.ThrowIf(this._jsModule is null, this);

string databaseName = SchemaHelper.GetDefaultDatabaseName<T>();
string schemaName = SchemaHelper.GetTableName<T>();
var dbManager = await GetOrCreateDatabaseAsync();
var dbManager = await this._magicJsManager.Value;
#pragma warning disable CS0618
return await QueryOverride<T>(databaseName, schemaName);
#pragma warning restore CS0618
}

[Obsolete("Not decided if this will be built in further or removed")]
public async ValueTask<IMagicQuery<T>> QueryOverride<T>(string databaseNameOverride, string schemaNameOverride)
where T: class, IMagicTableBase, new ()
{
var dbManager = await GetOrCreateDatabaseAsync(); // Ensure database is open
ObjectDisposedException.ThrowIf(this._jsModule is null, this);

var dbManager = await this._magicJsManager.Value;
return dbManager.Query<T>(databaseNameOverride, schemaNameOverride);
}

public async ValueTask<IMagicDatabaseScoped> Database(IndexedDbSet indexedDbSet)
{
var dbManager = await GetOrCreateDatabaseAsync(); // Ensure database is open
ObjectDisposedException.ThrowIf(this._jsModule is null, this);

var dbManager = await this._magicJsManager.Value;
return dbManager.Database(dbManager, indexedDbSet);
}

//public async ValueTask<IMagicDatabaseScoped> Database()
//{
// throw new Exception("Still working on it.");
//}

}
}
8 changes: 0 additions & 8 deletions TestServer/TestServer/Components/Pages/Home.razor
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,6 @@
{
if (firstRender)
{
try
{

// Targets the default database automatically if called without any parameters.
IMagicQuery<Person> personQuery = await _MagicDb.Query<Person>();
await personQuery.ClearTable();
Expand Down Expand Up @@ -758,11 +755,6 @@


StateHasChanged();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
15 changes: 9 additions & 6 deletions TestServer/TestServer/appsettings.Development.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
"Logging":
{
"LogLevel":
{
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"DetailedErrors": true
}