Try to read formulas from database, it is not working

This commit is contained in:
Your Name 2026-02-13 08:53:04 +01:00
parent c63a215212
commit 74b226591e
9 changed files with 178 additions and 35 deletions

11
TODO.md
View file

@ -1,6 +1,6 @@
# Conventions
[ ] Means not done
[R] Means done, but needs a human review
[R] Means done by an ai agent, but needs a human review
[X] Means done
@ -23,10 +23,11 @@
- [X] In linux, the sqlite database file will be located following rules at https://specifications.freedesktop.org/basedir/latest/
- [X] In Windows, the sqlite database file will be in %appdata%/Roaming
- [X] In Macos, the sqlite database file will be in ~/Library/Application Support
- [ ] Initialize database at startup
- [ ] If the database is empty, sugest to use a default corpus
- [ ] If the user choose to use the default corpus, populate de database with the default corpus (load defaultcorpus, and the use toStringLiteral)
- [ ] From now on, the corpus will be loaded from database instead of assets
- [X] Initialize database at startup
- [X] Try first to load a corpus from database
- [X] If the database is empty, sugest to use a default corpus
- [X] If the user choose to use the default corpus, populate de database with the default corpus (load defaultcorpus, and then use toStringLiteral). If not, start with an empty list of formulas.
- [X] From now on, the corpus will be loaded from database instead of assets
- [ ] Create method List<UnitSpec> Corpus.withDependencies(Formula formula). It will return the list of units of the formula, and related units from the corpus.
- [ ] Add a Share button to the formula list. It will export the array string literal of the formula with the units from Corpus.withDependencies().
- [ ] Replace flutter-markdown with flutter-markdown-plus

View file

@ -205,4 +205,11 @@ class Corpus{
loadFormulas(formulas);
}
/// Loads corpus from database elements
static Future<Corpus> fromDatabaseElements(List<FormulaElement> elements) async {
final corpus = Corpus();
corpus.loadFormulaElements(elements);
return corpus;
}
}

View file

@ -0,0 +1,7 @@
import 'package:d4rt_formulas/formula_models.dart' as models;
// Interface for corpus database operations
abstract class CorpusDatabaseInterface {
Future<List<models.FormulaElement>> loadCorpusElements();
Future<void> saveCorpusElements(List<models.FormulaElement> elements);
}

View file

@ -1,15 +1,37 @@
import 'package:get_it/get_it.dart';
// Conditionally import the correct database file based on platform
import 'corpus_database_interface.dart';
import 'formulas_database.dart'
if (dart.library.html) 'formulas_database_web.dart';
import 'package:d4rt_formulas/formula_models.dart' as models;
GetIt locator = GetIt.instance;
// Extension to add corpus loading/saving functionality to FormulasDatabase
extension CorpusDatabaseExtension on FormulasDatabase {
// Method to load corpus elements from database
Future<List<models.FormulaElement>> loadCorpusElements() async {
final elements = await getAllFormulaElements();
final List<models.FormulaElement> parsedElements = [];
void setupLocator() {
locator.registerSingleton<FormulasDatabase>(FormulasDatabase());
}
for (final element in elements) {
try {
final parsed = models.parseCorpusElements('[${element.elementText}]');
parsedElements.addAll(parsed);
} catch (e) {
print('Error parsing database element: $e');
// Skip invalid elements but continue processing others
continue;
}
}
FormulasDatabase getDatabase() {
return locator<FormulasDatabase>();
return parsedElements;
}
// Method to save corpus elements to database
Future<void> saveCorpusElements(List<models.FormulaElement> elements) async {
// Clear existing elements first
await delete(formulaElements).go();
// Insert new elements
for (final element in elements) {
await insertFormulaElement(element.toStringLiteral());
}
}
}

View file

@ -44,6 +44,9 @@ class FormulasDatabase extends _$FormulasDatabase {
Future<void> deleteFormulaElement(int id) {
return (delete(formulaElements)..where((tbl) => tbl.id.equals(id))).go();
}
// Additional helper methods for direct access to the table
SimpleSelectStatement get allFormulaElements => select(formulaElements);
}
LazyDatabase _openConnection() {

View file

@ -41,6 +41,9 @@ class FormulasDatabase extends _$FormulasDatabase {
Future<void> deleteFormulaElement(int id) {
return (delete(formulaElements)..where((tbl) => tbl.id.equals(id))).go();
}
// Additional helper methods for direct access to the table
SimpleSelectStatement get allFormulaElements => select(formulaElements);
}
LazyDatabase _openConnection() {

View file

@ -1,16 +1,19 @@
import 'package:flutter/material.dart';
import 'database/database_service.dart';
import 'package:drift/drift.dart' as drift;
import 'service_locator.dart';
import 'ai/formula_list.dart';
import 'corpus.dart';
import 'defaults/default_corpus.dart';
import 'formula_models.dart' as models;
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Setup service locator and initialize the database
setupLocator();
runApp(const MyApp());
}
@ -20,26 +23,103 @@ class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: FutureBuilder<Corpus>(
future: createDefaultCorpus(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasError) {
return Center(child: Text('Error loading units: ${snapshot.error}'));
}
return Scaffold(
appBar: AppBar(title: const Text('Formulas')),
body: FormulaList(
corpus: snapshot.data!,
formulas: snapshot.data!.getFormulas(),
),
);
}
return const Center(child: CircularProgressIndicator());
},
),
home: CorpusLoader(),
);
}
}
class CorpusLoader extends StatefulWidget {
@override
_CorpusLoaderState createState() => _CorpusLoaderState();
}
class _CorpusLoaderState extends State<CorpusLoader> {
late Future<Corpus> _corpusFuture;
@override
void initState() {
super.initState();
_corpusFuture = loadCorpusFromDatabaseOrAssets();
}
@override
Widget build(BuildContext context) {
return FutureBuilder<Corpus>(
future: _corpusFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasError) {
return Center(child: Text('Error loading corpus: ${snapshot.error}'));
}
// If the corpus is empty (user chose not to load default), we could handle that here
// For now, just display the formula list
return Scaffold(
appBar: AppBar(title: const Text('Formulas')),
body: FormulaList(
corpus: snapshot.data!,
formulas: snapshot.data!.getFormulas(),
),
);
}
return const Center(child: CircularProgressIndicator());
},
);
}
}
/// Attempts to load corpus from database first, falls back to default corpus if database is empty
Future<Corpus> loadCorpusFromDatabaseOrAssets() async {
final database = getDatabase();
try {
// Try to load from database first
final dbElements = await database.loadCorpusElements();
if (dbElements.isEmpty) {
// Database is empty, load default corpus and save to database
final defaultCorpus = await createDefaultCorpus();
// Convert corpus to elements and save to database
final elements = <models.FormulaElement>[];
elements.addAll(defaultCorpus.allUnits().cast<models.FormulaElement>());
elements.addAll(defaultCorpus.getFormulas().cast<models.FormulaElement>());
await database.saveCorpusElements(elements);
return defaultCorpus;
} else {
// Load corpus from database elements
return await Corpus.fromDatabaseElements(dbElements);
}
} catch (e) {
// If there's an error loading from database, fall back to default corpus
print('Error loading corpus from database: $e');
return await createDefaultCorpus();
}
}
/// Shows a dialog to ask user if they want to use the default corpus
Future<bool> showUseDefaultCorpusDialog(BuildContext context) async {
return await showDialog<bool>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Empty Database'),
content: const Text('The database is empty. Would you like to load the default corpus?'),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.of(context).pop(false), // Don't use default corpus
child: const Text('No'),
),
TextButton(
onPressed: () => Navigator.of(context).pop(true), // Use default corpus
child: const Text('Yes'),
),
],
);
},
) ?? false; // Default to false if dialog is dismissed
}

19
lib/service_locator.dart Normal file
View file

@ -0,0 +1,19 @@
import 'package:get_it/get_it.dart';
import 'database/formulas_database.dart'
if (dart.library.html) 'database/formulas_database_web.dart';
GetIt locator = GetIt.instance;
void setupLocator() {
locator.registerSingleton<FormulasDatabase>(getDatabase());
}
FormulasDatabase getDatabase() {
// Check if already registered to avoid recreating
if (locator.isRegistered<FormulasDatabase>()) {
return locator.get<FormulasDatabase>();
}
// Create new instance based on platform
return FormulasDatabase();
}

View file

@ -1,5 +1,6 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:d4rt_formulas/database/database_service.dart';
import 'package:d4rt_formulas/service_locator.dart';
void main() {
setUp(() {
@ -10,4 +11,4 @@ void main() {
final database = getDatabase();
expect(database, isNotNull);
});
}
}