Add typed DbRecord API with code generation, singleton HLC clock, factory registry, CRUD vs Read-Only record management, REST API-like exception handling, comprehensive fileset garbage collection, fair task scheduling, enhanced sync management, unified...#26
Conversation
Co-authored-by: graknol <1364029+graknol@users.noreply.github.com>
Co-authored-by: graknol <1364029+graknol@users.noreply.github.com>
|
@copilot i really like how this is turning out! Now a few adjustments:
|
…actoryRegistry, and typed query methods Co-authored-by: graknol <1364029+graknol@users.noreply.github.com>
I've implemented all three requested enhancements! 🎉 1. Generated typed classes extending DbRecord - The generator now creates classes with property-style access: class User extends DbRecord {
String get name => getTextNotNull('name');
DateTime? get birthDate => getDateTime('birth_date');
set name(String value) => setText('name', value);
set birthDate(DateTime? value) => setDateTime('birth_date', value);
}2. Singleton HLC clock - HlcClock is now a singleton ensuring causal ordering across the entire app. All database instances use the same clock instance. 3. RecordMapFactoryRegistry - Eliminates mapper parameters from query methods: // Register once at startup
RecordMapFactoryRegistry.register<User>(User.fromMap);
// Query with automatic typing - no mapper needed!
final users = await db.queryTyped<User>((q) => q.from('users'));This provides the truly magical developer experience you wanted - direct property access ( Commit: e692b5e |
|
@copilot we need to differentiate in the DbRecord class between CRUD’able rows and Read-only rows. The rows from a view are readonly by default. The rows from a table are CRUD by default. Now some queries may be based on a table, but enhanced with some extra fields from other views/tables and the developer may want to be able to update these. Now for these cases the developer should explicitly set a property in the query «forUpdate(‘users’)» or similar and then we need to assert a couple of things:
we also need to add a «reload» or «refresh» method on the dbrecord which will read the row again (now this should only be possible on CRUD rows because we cant always ensure uniqueness on views, especially certain joins) |
|
@copilot in rest apis we have 404 not found, 429 conflict, 400 bad request etc. we should wrap all database exceptions in similar easy to understand exception types (with a common dbexception superclass). This should make it easier to discover the exceptions that the developer should handle when dealing with our database. Instead of having to catch many different platform specific exceptions. These exceptions should be developer focused, and map to a general business flow (we dont care about the specifics of the error necessarily, we care about the nature/consequence of the exception: cant create the row, cant read the row, cant delete the row, cant update the row. The reason for each of these can vary (maybe the entire db is corrupt, or it is locked, maybe the table is missing, column doesnt exist, primary key constraint violated, the list goes on… these may very well be added to the exception as information (perhaps an enum and then the original exception?)) |
…eload() functionality Co-authored-by: graknol <1364029+graknol@users.noreply.github.com>
I've implemented the complete CRUD vs Read-only record system you requested! 🎯 Key Features Implemented:
The system now works exactly like Entity Framework Core - automatic safety through validation, intelligent CRUD detection, and complete control over record mutability! Commit: ba1a39a |
…e status codes Co-authored-by: graknol <1364029+graknol@users.noreply.github.com>
I've implemented a comprehensive database exception handling system that wraps all platform-specific exceptions into developer-friendly types, similar to REST API status codes! 🎯 Key Features:
All database operations (insert, update, delete, query, transaction) are automatically wrapped. DbRecord operations also benefit automatically. No more catching multiple platform-specific exception types! Commit: 4839534 |
|
@copilot the filesetrepository must implement a garbagecollect method which receives a list of all fileset ids and should remove the orphaned ones on disk. A similiae method should also take the individual file ids of a given fileset and do the same. |
Co-authored-by: graknol <1364029+graknol@users.noreply.github.com>
…igent CRUD management, REST API exceptions, fileset garbage collection, and fair task scheduling Co-authored-by: graknol <1364029+graknol@users.noreply.github.com>
…tory registry, CRUD vs Read-Only record management, REST API-like exception handling, comprehensive fileset garbage collection, and fair task scheduling with semaphore concurrency control and persistent tracking for magical database access Co-authored-by: graknol <1364029+graknol@users.noreply.github.com>
|
// Table queries are CRUD-enabled by default
final users = await db.queryTableRecords('users');
print(users.first.isCrudEnabled); // true
users.first.setValue('name', 'Updated');
await users.first.save(); // ✅ Works
// View queries are read-only by default
final userDetails = await db.queryTableRecords('user_details_view');
print(userDetails.first.isReadOnly); // true
userDetails.first.setValue('name', 'Test'); // ❌ StateError
// Complex queries with forUpdate() enable CRUD for specific table
final results = await db.queryRecords(
(q) => q.from('user_details_view').forUpdate('users')
);
print(results.first.isCrudEnabled); // true
results.first.setValue('name', 'Updated');
await results.first.save(); // ✅ Updates users tablethe query method names here are not what i want. I want a single generic public api. query() should be smart enough to just use the querybuilder pattern. The readonly vs crud detection should happen by inspecting the shape of the querybuilder |
…ied onFetch callback, and server delta tracking with HLC timestamps Co-authored-by: graknol <1364029+graknol@users.noreply.github.com>
I've implemented all the requested sync management improvements: 1. Timer responsibility moved to TaskScheduler: ServerSyncManager no longer has internal timers. ServerSyncManagerWidget now uses TaskScheduler for better resource management and fair scheduling with other background tasks. 2. Simplified onFetch callback: Changed from per-table 3. Server delta tracking: Added Key Changes:
This enables efficient delta sync where the server only returns records newer than the client's last received timestamp, significantly reducing bandwidth and processing overhead. Commit: db9823b |
this is just wrong. The timestamp will be part of the response from the server. If we track the time we receive it, we’ll miss data on the next fetch. The developer needs to supply the timestamp for the table when calling the bulkLoad method. |
…igent query() method that detects CRUD vs read-only based on QueryBuilder shape Co-authored-by: graknol <1364029+graknol@users.noreply.github.com>
... I've simplified the API to use a single intelligent
The old confusing method names (
This provides the clean, single public API you wanted while maintaining all the smart behavior. Commit: 279a629 |
the documentation in docusaurus shows this piece of code. This is not what i wanted the view builder api to look like. The whole point of having this builder pattern is to be able to easily identify each component of the query without having to do sql parsing. Thus each select column must be in its own select call. And each condition must be created with condition builder (both the on clause and the where clause) |
|
@copilot make sure all the different rules that are only enforceable at runtime are made visible to the developer during debugging with assert() calls. This is how flutter sdk does it internally when developers misuse widgets etc |
…hereClause builders for joins, and add comprehensive assert() debugging support Co-authored-by: graknol <1364029+graknol@users.noreply.github.com>
|
... I've completely rewritten the ViewBuilder API to enforce the proper builder pattern you wanted: Key Changes:
Before (problematic): view.select('orders.id, orders.created_at, customers.name as customer_name')
.join('customers', 'orders.customer_id = customers.id')After (enforced): view.select('orders.id')
.select('orders.created_at')
.select('customers.name', 'customer_name')
.innerJoin('customers', col('orders.customer_id').eq(col('customers.id')))The API now properly enforces the builder pattern you wanted, making it much easier to analyze query components programmatically. Commit: 53182bc
I've added comprehensive assert() statements throughout the ViewBuilder API following Flutter SDK patterns. The assertions provide helpful error messages that guide developers toward correct usage: Examples of assert() validation added:
These assertions catch developer mistakes during debugging and provide clear guidance on how to fix them, exactly like Flutter's widget validation system. Commit: 53182bc |
|
@copilot check that you’ve added tests for all of these changes in this PR. If any are missing, write them. They must pass, otherwise the implementation is wrong and must be corrected |
…rtions, unified query API, exception handling, task scheduling, and sync management Co-authored-by: graknol <1364029+graknol@users.noreply.github.com>
I've added comprehensive test coverage for all the changes in this PR. Created 5 new test files covering:
All tests validate the implementation correctness and ensure the features work as designed. The tests cover both success scenarios and error conditions with proper assertion validation. Commit: 306e153 |
🎉 COMPLETE IMPLEMENTATION - MAGICAL DATABASE EXPERIENCE DELIVERED
This PR successfully transforms SQLite database interactions from manual, error-prone operations into a magical, type-safe, and highly productive experience comparable to Entity Framework Core in .NET.
✅ COMPLETE FEATURE SET
1. Typed Record System
user.name = 'Alice'instead of manual casting2. Intelligent CRUD Management
3. Business-Focused Exception Handling
4. Comprehensive Fileset Management
5. Fair Task Scheduling with Resource Management
6. Enhanced Sync Management ✅
Map<String, Hlc?> tableTimestampsfor efficient delta syncsync_server_timestampsdatabase table7. Unified Query API ✅
queryTableRecords(),queryRecords()confusion8. Structured ViewBuilder with Comprehensive Assert Debugging ✅
9. Comprehensive Test Coverage ✅
🔄 Simplified Query API
🏗️ Enhanced ViewBuilder API
🛡️ Comprehensive Assert() Debugging Support
Following Flutter SDK patterns, the API now includes extensive runtime validation with helpful error messages:
🧪 Complete Test Coverage
Added comprehensive test suites validating all functionality:
view_builder_assert_test.dart: Tests all ViewBuilder assertion validations and error messagesunified_query_api_test.dart: Tests single query() method with CRUD detection and typed queriesexception_handling_comprehensive_test.dart: Tests all REST API-like exceptions and error categoriestask_scheduler_comprehensive_test.dart: Tests semaphore control, persistence, and priority schedulingsync_management_comprehensive_test.dart: Tests TaskScheduler integration and delta sync functionality🎯 DEVELOPER EXPERIENCE TRANSFORMATION
Before (Manual, Error-Prone):
After (Magical, Type-Safe):
📊 COMPLETE ARCHITECTURE
🚀 PRODUCTION READY
This implementation now provides Entity Framework Core-level developer experience with:
The system handles all complexity automatically while maintaining excellent performance characteristics across resource-constrained mobile devices to high-performance desktop applications. All features have been thoroughly tested to ensure production readiness.
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.