From 0b0fccd4a3f605945f80025ce7576431fbf26249 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Gonz=C3=A1lez?= Date: Wed, 4 Mar 2026 19:52:31 +0100 Subject: [PATCH] UUID for formulas --- TODO.md | 4 ++++ lib/corpus.dart | 19 +++++++++++++++---- lib/formula_models.dart | 31 ++++++++++++++++--------------- pubspec.lock | 2 +- pubspec.yaml | 3 +-- 5 files changed, 37 insertions(+), 22 deletions(-) diff --git a/TODO.md b/TODO.md index fbcac80..22088a1 100644 --- a/TODO.md +++ b/TODO.md @@ -53,5 +53,9 @@ - _prettyPrintSet(Set s, int indent) - _prettyPrintArray(dynamic[] a, int indent) - _prettyPrintRawString(String s, int indent): Use _prettyPrintRawString when the string contains newlines, $, backlash... +- [X] Add a field to Formula: UUID. + - A constructor without UUID will generate a new random UUID. A constructor with UUID will use the provided UUID. + - The field should be used in database and everywhere instead of the name. The name is not unique anymore, but the UUID is. + - This will be used to identify formulas, instead of the name. This way, we can have formulas with the same name but different UUIDs. The name is not unique anymore. Corpus will be a list of UUIDs, instead of a list of formulas. The corpus.getFormula() method will return the first formula with that name. - [ ] When _FormulaScreenState._evaluateFormula() detect an error, instead of show an SnackBar, show a ExpansionTile with "⚠️ There were an error. Show details..." with the details of the exception. The ExpansionTile will be invisible if there is no error. - [ ] Investigate https://pub.dev/packages/quantity diff --git a/lib/corpus.dart b/lib/corpus.dart index b2f7cf2..acdfdec 100644 --- a/lib/corpus.dart +++ b/lib/corpus.dart @@ -25,12 +25,13 @@ class Multimap extends DelegatingMap> { class Corpus{ final Multimap _tags = Multimap.create(); + // Map formulas by uuid final Map _allFormulas = {}; void loadFormulas(List formulas, {bool replaceOnDuplicates = true, bool checkUnits = true}) { for (final formula in formulas) { - if (!replaceOnDuplicates && _allFormulas.containsKey(formula.name)) { - throw ArgumentError("Duplicate formula:$formula"); + if (!replaceOnDuplicates && _allFormulas.containsKey(formula.uuid)) { + throw ArgumentError("Duplicate formula:${formula}"); } if( checkUnits ){ @@ -41,7 +42,7 @@ class Corpus{ } } - _allFormulas[formula.name] = formula; + _allFormulas[formula.uuid] = formula; for( final tag in formula.tags ){ _tags[tag]?.add(formula); } @@ -59,8 +60,18 @@ class Corpus{ return _allFormulas.values.toList(growable:false); } + /// Returns first formula with the given name (preserves old API semantics). Formula? getFormula(String name) { - return _allFormulas.get(name); + try { + return _allFormulas.values.firstWhere((f) => f.name == name); + } catch (e) { + return null; + } + } + + /// Returns formula by uuid + Formula? getFormulaByUuid(String uuid) { + return _allFormulas[uuid]; } final Multimap _baseToUnits = Multimap.create(); diff --git a/lib/formula_models.dart b/lib/formula_models.dart index 5f80397..1aaa6b9 100644 --- a/lib/formula_models.dart +++ b/lib/formula_models.dart @@ -1,6 +1,8 @@ import 'package:d4rt/d4rt.dart'; import 'package:collection/collection.dart'; import 'package:d4rt_formulas/d4rt_formulas.dart'; +import 'dart:math'; +import 'package:uuid/uuid.dart'; typedef Number = double; @@ -45,7 +47,7 @@ abstract class SetUtils { .replaceAll('\n', r'\\n') .replaceAll('\r', r'\\r') .replaceAll('\t', r'\\t') - .replaceAll('"', r'\\"'); + .replaceAll('"', r'\"'); } /// Parses corpus elements from an array string literal. @@ -95,7 +97,7 @@ abstract class SetUtils { // Check if the string needs raw string formatting (newlines, $, backslashes, quotes) final needsRawString = s.contains('\n') || s.contains(r'$') || - s.contains(r'\') || + s.contains(r'\\') || s.contains('"'); if (needsRawString) { @@ -160,7 +162,7 @@ abstract class SetUtils { /// Uses Dart's raw string syntax r"""...""" static String _prettyPrintRawString(String s, int indent) { // Escape triple quotes by replacing """ with ""\" - final escaped = s.replaceAll('"""', r'""\"'); + final escaped = s.replaceAll('"""', r'""\\"'); return 'r"""$escaped"""'; } } @@ -296,7 +298,10 @@ class VariableSpec extends FormulaElement{ } +String _generateUuidV4() => Uuid().v4(); + class Formula extends FormulaElement { + final String uuid; final String name; final String? description; final List input; @@ -306,6 +311,7 @@ class Formula extends FormulaElement { @override Map toMap() { + // UUID NOT INCLUDED ON PURPOSE return { 'name': name, if (description != null) 'description': description, @@ -317,13 +323,14 @@ class Formula extends FormulaElement { } Formula({ + String? uuid = null, required this.name, this.description, required this.input, required this.output, required this.d4rtCode, this.tags = const [], - }) { + }) : uuid = uuid ?? _generateUuidV4() { validate(); } @@ -337,25 +344,17 @@ class Formula extends FormulaElement { @override String toString() => - 'Formula(name: $name, description: $description, input: $input, output: $output, d4rtCode: $d4rtCode, tags: $tags)'; + 'Formula(uuid: $uuid, name: $name, description: $description, input: $input, output: $output, d4rtCode: $d4rtCode, tags: $tags)'; @override bool operator ==(Object other) => identical(this, other) || other is Formula && runtimeType == other.runtimeType && - name == other.name && - description == other.description && - output == other.output && - ListEquality().equals(input, other.input) && - d4rtCode == other.d4rtCode && - ListEquality().equals(tags, other.tags); + uuid == other.uuid; @override - int get hashCode => - Object.hash( - name, description, ListEquality().hash(input), output, d4rtCode, - ListEquality().hash(tags)); + int get hashCode => uuid.hashCode; List inputVarNames() => input.map((v) => v.name).toList(growable: false); @@ -405,6 +404,7 @@ class Formula extends FormulaElement { ); } + String? uuid = theSet['uuid'] as String?; String name = SetUtils.stringValue(theSet, "name"); String? description = theSet["description"] as String?; List tags = (theSet["tags"] as List? ?? []).map((t) => @@ -417,6 +417,7 @@ class Formula extends FormulaElement { String d4rtCode = SetUtils.stringValue(theSet, "d4rtCode"); return Formula( + uuid: uuid, name: name, description: description, tags: tags, diff --git a/pubspec.lock b/pubspec.lock index d7b2023..6971366 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -990,7 +990,7 @@ packages: source: hosted version: "3.1.5" uuid: - dependency: transitive + dependency: "direct main" description: name: uuid sha256: "1fef9e8e11e2991bb773070d4656b7bd5d850967a2456cfc83cf47925ba79489" diff --git a/pubspec.yaml b/pubspec.yaml index b5a09ea..8c8e51e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -41,8 +41,7 @@ dependencies: flutter_markdown_plus: flutter_markdown_plus_latex: flutter_code_editor: - - # Drift dependencies for database support + uuid: drift: sqlite3_flutter_libs: path_provider: