Skip to content

New Schema Refactor (Dev Migrations Required) #60

Closed
@magiccodingman

Description

@magiccodingman

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!

Metadata

Metadata

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions