Description
Overview
This proposal introduces a significant refactor to the Magic.IndexDB library, focusing on simplifying database schema management, improving ease of use, and removing unnecessary manual setup. The primary change involves eliminating the need for explicit database initialization by leveraging attribute-based metadata, thus reducing developer overhead and improving usability.
Current System
Currently, Magic.IndexDB requires developers to explicitly register and manage database connections using the MagicDbFactory
. The following methods are used to open and interact with databases:
ValueTask<IndexedDbManager> OpenAsync(DbStore dbStore, bool force = false, CancellationToken cancellationToken = default);
IndexedDbManager Get(string dbName);
ValueTask<IndexedDbManager> GetRegisteredAsync(string dbName, CancellationToken cancellationToken = default);
Developers then use the IndexedDbManager
to query and manipulate records. Example usage:
var manager = await _MagicDb.GetRegisteredAsync("client");
// Get all records
allPeople = (await manager.GetAllAsync<Person>()).ToList();
// Where statement with filtering
var WhereExample = (await manager.Where<Person>(x => x.Name.StartsWith("c", StringComparison.OrdinalIgnoreCase)
|| x.Name.StartsWith("l", StringComparison.OrdinalIgnoreCase)
|| x.Name.StartsWith("j", StringComparison.OrdinalIgnoreCase) && x._Age > 35
|| x.Name.Contains("bo", StringComparison.OrdinalIgnoreCase))
.OrderBy(x => x._Id)
.Skip(1)
.ToListAsync());
This approach requires developers to explicitly open databases and associate models with the correct database manager. However, this information is already available in model attributes:
[MagicTable("Person", "client")]
public class Person
Where the MagicTable
attribute includes:
public MagicTableAttribute(string schemaName, string databaseName)
Since the system already knows which database a model belongs to, requiring manual database initialization is redundant and adds unnecessary complexity.
Proposed Changes
1. Automatic Database Initialization on First Use
Instead of requiring explicit database registration, databases will automatically open when a model is accessed. This eliminates the need for developers to manually manage database connections.
- Before: Developers must manually register and open databases.
- After: Databases open automatically when accessed, based on model attributes.
2. Removing Explicit Database Manager Assignment
Currently, multiple managers must be instantiated for different databases, and developers must remember which manager corresponds to which models. This proposal eliminates that requirement, as the system can infer database assignments from attributes.
3. Simplified Database Closing Mechanism
While databases will open automatically, developers should retain control over closing them. This proposal introduces new methods:
// Close a specific database
IndexedDBManager.CloseDatabase("client");
// Close all open databases
IndexedDBManager.CloseAllDatabases();
// Close databases based on model types
IndexedDBManager.CloseDatabases(typeof(Person), typeof(Order));
This provides a streamlined approach to resource management while removing unnecessary manual steps.
4. Refactoring Startup Configuration
Currently, database registration in Program.cs
looks like this:
builder.Services.AddBlazorDB(options =>
{
options.Name = DbNames.Client;
options.Version = 1;
options.StoreSchemas = SchemaHelper.GetAllSchemas(DbNames.Client);
});
The proposed refactor eliminates options.Name
and options.StoreSchemas
, as this information is redundant given the attribute-based schema system. The new approach would be:
builder.Services.AddBlazorDB({
options.Version = 1;
});
The system will infer database names and schemas at runtime.
5. Removing DbStore.StoreSchemas
Previously, DbStore
required explicit schema definitions:
public class DbStore
{
public string Name { get; set; }
public int Version { get; set; }
public List<StoreSchema> StoreSchemas { get; set; }
}
This proposal removes StoreSchemas
entirely, as Magic.IndexDB can determine schema details automatically.
6. Introducing Dynamic Runtime Table & Database Creation
To allow for dynamic, runtime-created tables and databases, a special runtime model will be introduced. This model will allow developers to:
- Define properties dynamically at runtime.
- Set primary keys and indexes dynamically.
- Maintain strongly typed structures even for dynamically created tables.
This ensures that even runtime-created databases maintain the benefits of strong typing and schema validation.
Summary of Benefits
Feature | Current System | Proposed System |
---|---|---|
Database Opening | Manual registration | Automatic on first use |
Database Manager Association | Must track and assign manually | Fully inferred from attributes |
Database Closing | Not easily managed | Explicit close methods provided |
Startup Configuration | Requires explicit schemas | Completely inferred |
Schema Definitions | Must be manually provided | Automatically determined |
Dynamic Tables | Not well supported | Fully supported with structured runtime models |
Migration Guide
Changes to Database Initialization
Before:
var manager = await _MagicDb.GetRegisteredAsync("client");
var people = await manager.GetAllAsync<Person>();
After:
var people = await MagicDb.GetAllAsync<Person>();
Changes to Closing Databases
Before:
var manager = await _MagicDb.GetRegisteredAsync("client");
manager.Close();
After:
var manager = await _MagicDb.GetRegisteredAsync();
manager.CloseDatabase("client");
Changes to Startup Configuration
Before:
builder.Services.AddBlazorDB(options =>
{
options.Name = "client";
options.Version = 1;
options.StoreSchemas = SchemaHelper.GetAllSchemas("client");
});
After:
builder.Services.AddBlazorDB({
options.Version = 1;
});
Conclusion
This refactor simplifies database usage, eliminates redundant setup, and improves developer experience by making database management seamless. While a migration is required, it is a one-time change that provides long-term benefits by reducing boilerplate and enforcing best practices.
Feedback from the community is encouraged before implementation!