simolus3 / drift Goto Github PK
View Code? Open in Web Editor NEWDrift is an easy to use, reactive, typesafe persistence library for Dart & Flutter.
Home Page: https://drift.simonbinder.eu/
License: MIT License
Drift is an easy to use, reactive, typesafe persistence library for Dart & Flutter.
Home Page: https://drift.simonbinder.eu/
License: MIT License
We are currently developing an app that uses Flutter for mobile and AngularDart for Web.
It would be cool if we could have an abstraction for creating queries and also an abstraction for the underlying framework such as SQLite or AlaSQL.
Are there already any plans?
How much effort would this be?
abstract class Serializable { Map<String, dynamic> toJson() }
A table defined like below, will throw an sql error when it attempts to add an item with a empty primary key, however when deleting an item, it will correctly assert that the table is missing a primary key
class MyTable extends Table {
IntColumn get id => integer()();
}
//throws assert error correctly
delete(myTable).delete(item);
//does not throw assert error correctly
into(myTable).insert(item);
Error thrown:
DB Error: 1 "near ")": syntax error"
DB Query: CREATE TABLE IF NOT EXISTS my_table (id INTEGER NOT NULL, PRIMARY KEY ());
If I create a column with type RealColumn and set it as nullable (), the insertion happens normally, but at the time of the select it generates an error saying that it is not possible to convert a null value to double. How can I solve this? I really need this column to be nullable.
RealColumn get sorStartTravelLon => real().named("sorStartTravelLon").nullable()();
E/flutter (10165): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: NoSuchMethodError: The method 'toDouble' was called on null. E/flutter (10165): Receiver: null E/flutter (10165): Tried calling: toDouble()
The build_runner deps are outdated
My JSON is snake case and my getters are camel case.
I either change my getters to snake case and get a dart warning, or change the generated code to use snake case.
Please add a way to override the JSON key.
void _writeToJson(StringBuffer buffer) {
buffer.write('Map<String, dynamic> toJson() {\n return {');
for (var column in table.columns) {
final getter = column.dartGetterName;
buffer.write("'$getter': $getter,");
}
buffer.write('};}');
}
I want a method to insert a row but if there is a conflict then update it instead of inserting it.
Currently, only the tests in moor/tests
contribute to the coverage - tests in other packages are run, but not with coverage.
It would be nice to generate a coverage file for each project, bundle them together, and upload that single file to codecov.
This error occurs in a simple insert statement. Was working fine until yesterday.
PS: There is again a breaking change without increment major version.
I used exactly the demo code example described in "Getting Started" (https://moor.simonbinder.eu/getting-started/) and then "inserting" here:
https://moor.simonbinder.eu/queries/
Future<int> addTodoEntry(Todo entry) {
return into(todos).insert(entry);
}
myDatabaseObject.addTodoEntry(
Todo(
title: 'Important task',
content: 'Refactor persistence code',
),
);
And then I get the following error:
[VERBOSE-2:ui_dart_state.cc(148)] Unhandled Exception: InvalidDataException: Invalid data: Todo(id: null, title: Important task, content: Refactor persistence code, category: null) cannot be written into todos
#0 InsertStatement._validateIntegrity
package:moor/…/statements/insert.dart:120
#1 InsertStatement.insert
package:moor/…/statements/insert.dart:30
#2 MyDatabase.addTodoEntry
package:hn_app/favorites.dart:58
#3 _Item.build..
package:hn_app/main.dart:199
#4 _InkResponseState._handleTap
package:flutter/…/material/ink_well.dart:511
#5 _InkResponseState.build.
package:flutter/…/material/ink_well.dart:566
#6 GestureRecognizer.invokeCallback
package:flutter/…/gestures/recognizer.dart:166
#7 TapGestureRecognizer._checkUp
package:flutter/…/gestures/tap.dart:240
#8 TapGestureRecognizer.acceptGesture (package:flutte<…>
This is with Moor v 1.4.0.
I/flutter ( 8123): error NoSuchMethodError: The getter 'typeSystem' was called on null.
I/flutter ( 8123): Receiver: null
I/flutter ( 8123): Tried calling: typeSystem during open, closing...
I/flutter ( 8123): error NoSuchMethodError: The getter 'typeSystem' was called on null.
I/flutter ( 8123): Receiver: null
I/flutter ( 8123): Tried calling: typeSystem during open, closing...
E/flutter ( 8123): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: NoSuchMethodError: The getter 'typeSystem' was called on null.
E/flutter ( 8123): Receiver: null
E/flutter ( 8123): Tried calling: typeSystem
E/flutter ( 8123): #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:50:5)
E/flutter ( 8123): #1 Constant.writeInto (package:moor/src/runtime/expressions/variables.dart:72:35)
E/flutter ( 8123): #2 GeneratedColumn.writeColumnDefinition (package:moor/src/runtime/structure/columns.dart:49:22)
E/flutter ( 8123): #3 Migrator.createTable (package:moor/src/runtime/migration.dart:67:14)
E/flutter ( 8123): <asynchronous suspension>
E/flutter ( 8123): #4 MappedListIterable.elementAt (dart:_internal/iterable.dart:414:29)
E/flutter ( 8123): #5 ListIterator.moveNext (dart:_internal/iterable.dart:343:26)
E/flutter ( 8123): #6 Future.wait (dart:async/future.dart:393:26)
E/flutter ( 8123): #7 Migrator.createAllTables (package:moor/src/runtime/migration.dart:51:19)
E/flutter ( 8123): <asynchronous suspension>
E/flutter ( 8123): #8 _defaultOnCreate (package:moor/src/runtime/migration.dart:14:48)
E/flutter ( 8123): #9 GeneratedDatabase.handleDatabaseCreation (package:moor/src/runtime/database.dart:222:22)
E/flutter ( 8123): #10 FlutterQueryExecutor.ensureOpen.<anonymous closure> (package:moor_flutter/moor_flutter.dart:110:27)
E/flutter ( 8123): #11 _SqfliteDatabaseBase&Object&SqfliteDatabaseMixin.doOpen.<anonymous closure> (package:sqflite/src/database_mixin.dart:661:29)
E/flutter ( 8123): <asynchronous suspension>
E/flutter ( 8123): #12 _SqfliteDatabaseBase&Object&SqfliteDatabaseMixin._runTransaction (package:sqflite/src/database_mixin.dart:433:28)
E/flutter ( 8123): <asynchronous suspension>
E/flutter ( 8123): #13 _SqfliteDatabaseBase&Object&SqfliteDatabaseMixin.transaction.<anonymous closure> (package:sqflite/src/database_mixin.dart:450:14)
E/flutter ( 8123): <asynchronous suspension>
E/flutter ( 8123): #14 _SqfliteDatabaseBase&Object&SqfliteDatabaseMixin.txnSynchronized (package:sqflite/src/database_mixin.dart:275:26)
E/flutter ( 8123): <asynchronous suspension>
E/flutter ( 8123): #15 _SqfliteDatabaseBase&Object&SqfliteDatabaseMixin.txnWriteSynchronized (package:sqflite/src/database_mixin.dart:307:7)
E/flutter ( 8123): #16 _SqfliteDatabaseBase&Object&SqfliteDatabaseMixin.transaction (package:sqflite/src/database_mixin.dart:449:12)
E/flutter ( 8123): #17 _SqfliteDatabaseBase&Object&SqfliteDatabaseMixin.doOpen (package:sqflite/src/database_mixin.dart:651:15)
E/flutter ( 8123): <asynchronous suspension>
E/flutter ( 8123): #18 SqfliteDatabaseOpenHelper.openDatabase (package:sqflite/src/database.dart:32:22)
E/flutter ( 8123): <asynchronous suspension>
E/flutter ( 8123): #19 _SqfliteDatabaseFactoryImpl&Object&SqfliteDatabaseFactoryMixin.openDatabase.<anonymous closure> (package:sqflite/src/factory_mixin.dart:100:43)
E/flutter ( 8123): <asynchronous suspension>
E/flutter ( 8123): #20 ReentrantLock.synchronized.<anonymous closure>.<anonymous closure> (package:synchronized/src/reentrant_lock.dart:33:24)
E/flutter ( 8123): #21 _rootRun (dart:async/zone.dart:1124:13)
E/flutter ( 8123): #22 _CustomZone.run (dart:async/zone.dart:1021:19)
E/flutter ( 8123): #23 _runZoned (dart:async/zone.dart:1516:10)
E/flutter ( 8123): #24 runZoned (dart:async/zone.dart:1463:12)
E/flutter ( 8123): #25 ReentrantLock.synchronized.<anonymous closure> (package:synchronized/src/reentrant_lock.dart:32:24)
E/flutter ( 8123): <asynchronous suspension>
E/flutter ( 8123): #26 BasicLock.synchronized (package:synchronized/src/basic_lock.dart:31:26)
E/flutter ( 8123): <asynchronous suspension>
E/flutter ( 8123): #27 ReentrantLock.synchronized (package:synchronized/src/reentrant_lock.dart:28:17)
E/flutter ( 8123): <asynchronous suspension>
E/flutter ( 8123): #28 _SqfliteDatabaseFactoryImpl&Object&SqfliteDatabaseFactoryMixin.openDatabase (package:sqflite/src/factory_mixin.dart:66:17)
E/flutter ( 8123): #29 openDatabase (package:sqflite/sqflite.dart:146:26)
E/flutter ( 8123): #30 FlutterQueryExecutor.ensureOpen (package:moor_flutter/moor_flutter.dart:107:16)
E/flutter ( 8123): <asynchronous suspension>
E/flutter ( 8123): #31 QueryExecutor.doWhenOpened (package:moor/src/runtime/executor/executor.dart:15:12)
E/flutter ( 8123): #32 SimpleSelectStatement._getWithQuery (package:moor/src/runtime/statements/select.dart:165:49)
E/flutter ( 8123): <asynchronous suspension>
E/flutter ( 8123): #33 SimpleSelectStatement.get (package:moor/src/runtime/statements/select.dart:161:12)
E/flutter ( 8123): <asynchronous suspension>
Good afternoon, how are you?
I am trying to make a query with Join, however it is not only filtering the files I want:
`final placeLoading = alias(places, 'placeLoading');
final cityLoading = alias(locationCities, 'cityLoading');
final placeDischarge = alias(places, 'placeDischarge');
final cityDischarge = alias(locationCities, 'cityDischarge');
final query = await (select(serviceOrders)
..where((s) => s.sorCode.equals(sorCode)))
.join([
leftOuterJoin(serviceOrdersStatus,
serviceOrdersStatus.sstStatus.equalsExp(serviceOrders.sorStatus)),
leftOuterJoin(placeLoading,
placeLoading.plaCode.equalsExp(serviceOrders.plaCodeLoading)),
leftOuterJoin(
cityLoading, cityLoading.citCode.equalsExp(placeLoading.citCode)),
leftOuterJoin(placeDischarge,
placeDischarge.plaCode.equalsExp(serviceOrders.plaCodeDischarge)),
leftOuterJoin(cityDischarge,
cityDischarge.citCode.equalsExp(placeDischarge.citCode)),
]).get();
List<ServiceOrderWithDetails> finalList = query.map((resultRow) {
return ServiceOrderWithDetails(
resultRow.readTable(serviceOrders),
resultRow.readTable(serviceOrdersStatus),
resultRow.readTable(placeLoading),
resultRow.readTable(cityLoading),
resultRow.readTable(placeDischarge),
resultRow.readTable(cityDischarge),
);
}).toList();`
This returns me 3 results and should only return 1. So if I test without the Join:
final query = await (select(serviceOrders) ..where((s) => s.sorCode.equals(sorCode))).get();
It returns me exactly the only result.
Am I doing something wrong?
Taking advantage of the topic, what is the best way for me to get a single record in the table? When for example I want to get the record for the primary key that does not repeat.
Current readme points out that only a tiny subset is supported, which is not true
Error when putting a default value for a real column
This library already generates a dart dsl to execute most queries and it also features custom queries. It would be nice to look at sql statements at compile time, figure out what variables appear in them, and then generate appropriate dart methods automatically.
The api could look like this:
@UseMoor(tables: [], queries: {Sql('SELECT * FROM users WHERE name = :name', name: 'usersByName')})
class MyDatabase extends _$MyDatabase {}
In that case, _$MyDatabase
should have generated a method like:
Future<List<User>> usersByName(String name) {
return //...
}
Stream<List<User>> watchUsersByName(String name) {
return // ...
}
All of these features should make it into the next version of moor, 1.5
.
BETWEEN
and CASE
expressions in sql.LIKE
operatorEXISTS
and (NOT) IN
expressions - skipping NOT IN
for now.For now, parsing update, delete and inserts statements is out of scope, they will not be available in the next 1.5
release. Edit: Update and delete statements turned out to be quite simple, they definitely will be implemented in 1.5
.
At the moment we just throw a rather unhelpful InvalidDataException
without any details on what exactly went wrong.
In the moor_flutter/example
project, adding the query SELECT id FROM categories WHERE desc = ?
fails to parse:
Error while trying to parse SELECT id FROM categories WHERE desc = ?: line 1, column 38: Error: Could not parse this expression}
1 │ SELECT id FROM categories WHERE desc = ?
│ ^
Removing .named('desc')
from the table declaration and updating the query to SELECT id FROM categories WHERE description = ?
is a workaround.
trying to deserialize a null value always throws an error
How to indicate a foreign key in a Table object?
I can't make it work any way. I tried both overriding from the "Table" class and calling it on the property.
Overriding:
class Requests extends Table {
IntColumn get requestId => integer()();
IntColumn get requestTypeId => integer()();
IntColumn get numberOfDocuments => integer()();
@override
Set<Column> get primaryKey => {requestId};
}
class RequestDocuments extends Table {
IntColumn get requestId =>
integer()();
IntColumn get documentId => integer()();
IntColumn get documentStateId => integer()();
@override
Set<Column> get primaryKey => {requestId, documentId};
@override
List<String> get customConstraints => [
'FOREIGN KEY(request_id) REFERENCES requests(request_id)',
];
}
On the property:
class Requests extends Table {
IntColumn get requestId => integer()();
IntColumn get requestTypeId => integer()();
IntColumn get numberOfDocuments => integer()();
@override
Set<Column> get primaryKey => {requestId};
}
class RequestDocuments extends Table {
IntColumn get requestId =>
integer().customConstraint('REFERENCES requests(request_id)')();
IntColumn get documentId => integer()();
IntColumn get documentStateId => integer()();
@override
Set<Column> get primaryKey => {requestId, documentId};
}
What I am doing wrong?
Originally posted by @JPiris88 in #14 (comment)
default value doesn't work when an existing row is being replaced, with another row where a required field is null
It's possible to express the following query in moor
select(table).join([innerJoin(table, /* ... */)])
However, it won't generate valid sql as all the columns are included multiple times. We should warn about a possible typo and suggest to create an alias
to fix this.
SELECT id FROM todos WHERE category IN (1)
parses correctly, but adding more comma separated expressions throws the following error:
Error while trying to parse SELECT id FROM todos WHERE category IN (1,2): line 1, column 42: Error: Expected a closing bracket}
1 │ SELECT id FROM todos WHERE category IN (1,2)
│ ^
In the moor_flutter/example
project both the categories
and todos
tables have a column named id
, so adding the query SELECT * FROM categories WHERE id = :id
generates:
Stream<List<Category>> watchEx1(int id) {
return customSelectStream('SELECT * FROM categories WHERE id = :id',
variables: [
Variable.withInt(id),
],
readsFrom: {
categories,
todos
}).map((rows) => rows.map(_rowToCategory).toList());
}
Updating the column to a unique name like category_id
will correctly generate readsFrom: {categories}
How to use an existing database that already contains data?
I try to insert a row in the table:
However, I get this error.
E/flutter (14884): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: type 'DateTime' is not a subtype of type 'int' in type cast
E/flutter (14884): #0 _DefaultValueSerializer.fromJson (package:moor/src/runtime/data_class.dart:53:55)
E/flutter (14884): #1 new Person.fromJson (package:moor_example/model/model.g.dart:77:29)
Why does the library try to convert the DateTime into an int?
The name 'Column' is defined in the libraries 'package:flutter/src/widgets/basic.dart' and 'package:moor/src/dsl/columns.dart'.dart(ambiguous_import)
Subtasks:
QueryEngine.select
probablywhere
method
Join2
... Join10
classes manually?Is it possible to add a toJson
method to the generated table class? Because I sometimes need to serialize the table class into json, thank you very much!
I am guessing that this is designed such that updates to data from the server can't be detected and update the corresponding views that have a SQL watch query on them because you rely on detecting a CUD to the salute database from the user interface ?
How are you supposed to use MyDatabase-class? It seems to me that a singleton is the way to go - don't know if all figure that out in the first place.
Then how are you supposed to define migrations? If I just add or remove a field everything works as expected, but what if I want to add a new table and store some of the existing data there and delete the field afterwards?
A common question would be initial data.
There is MigrationStrategy, but I don't know what to define there exactly. And if I have a look at GeneratedDatabase I can't find any use of onFinished.
It would be nice to have some working hello world-ish programs where one could study all aspects of moor :-)
ERROR: MissingPluginException(No implementation found for method getDatabasesPath on channel com.tekartik.sqflite)
package:flutter/src/services/platform_channel.dart 300:7 MethodChannel.invokeMethod
===== asynchronous gap ===========================
dart:async _AsyncAwaitCompleter.completeError
package:flutter/src/services/platform_channel.dart MethodChannel.invokeMethod
===== asynchronous gap ===========================
dart:async _asyncThenWrapperHelper
package:flutter/src/services/platform_channel.dart MethodChannel.invokeMethod
package:sqflite/src/sqflite_impl.dart 18:34 invokeMethod
When a query has the same sql and variables, we can assume that it will always yield the same data and should consider them to be equal. Thus, when two equal queries construct a stream, we should only create one stream for both queries.
This will also make moor work more efficient in combination with something like
StreamBuilder(
stream: db.select(users).watch(),
builder: //...
)
As each invocation of watch
would no longer return a different stream.
Similarly, fromJson function takes a Map, instead of a JSON string:
Map<String, dynamic> toJson()
factory Xxx.fromJson(Map<String, dynamic> json)
How can I convert these functions to standard:
String toJson() => jsonEncode(toMap())
factory Xxx.fromJson(String json) => Xxx.fromMap(jsonDecode(json));
I'm looking for database encryption support,
Is this planned for this library?
Currently, they would throw an exception. Returning null to indicate that there is no result seems more intuitive.
First of all thanks for your great work on the sqlparser library! I really think generating code from SQL is the best approach to ORMs/persistence libraries, and I'm so glad there's now a solution available for Dart users.
I have a feature request: When a bind argument exists inside an IN clause, the parameter in the generated code should have the type List<T>
instead of T
. For example, the query
SELECT * FROM todos WHERE id IN ?
would generate:
Future<List<TodoEntry>> todos(List<int> var1)
Stream<List<TodoEntry>> watchTodos(List<int> var1)
instead of:
Future<List<TodoEntry>> todos(int var1)
Stream<List<TodoEntry>> watchTodos(int var1)
We should also use jenkins hash instead of that inner_hash * 31 + outer_hash
thing
E/flutter (13486): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: Bad state: Too many elements
E/flutter (13486): #0 _ListBase&Object&ListMixin.singleWhere (dart:collection/list.dart:167:11)
E/flutter (13486): #1 SqlTypeSystem.forDartType (package:moor/src/types/type_system.dart:23:18)
E/flutter (13486): #2 Variable.mapToSimpleValue (package:moor/src/runtime/expressions/variables.dart:48:37)
E/flutter (13486): #3 Variable.writeInto (package:moor/src/runtime/expressions/variables.dart:56:33)
E/flutter (13486): #4 InsertStatement._createContext (package:moor/src/runtime/statements/insert.dart:107:16)
E/flutter (13486): #5 InsertStatement.insert (package:moor/src/runtime/statements/insert.dart:31:17)
I was playing with the example project and came across this exception
E/flutter ( 5999): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: Concurrent modification during iteration: _LinkedHashMap len:2.
E/flutter ( 5999): #0 _CompactIterator.moveNext (dart:collection/runtime/libcompact_hash.dart:443:7)
E/flutter ( 5999): #1 FollowedByIterator.moveNext (dart:_internal/iterable.dart:855:26)
E/flutter ( 5999): #2 WhereIterator.moveNext (dart:_internal/iterable.dart:438:22)
E/flutter ( 5999): #3 StreamQueryStore.handleTableUpdates (package:moor/src/runtime/executor/stream_queries.dart:94:24)
The changes I made to the example project:
--- moor_flutter/example/lib/widgets/homescreen.dart
+++ moor_flutter/example/lib/widgets/homescreen.dart
@@ -102,7 +102,9 @@
if (controller.text.isNotEmpty) {
// We write the entry here. Notice how we don't have to call setState()
// or anything - moor will take care of updating the list automatically.
- bloc.addEntry(TodoEntry(content: controller.text));
+ int id = DateTime.now().millisecondsSinceEpoch;
+ bloc.addCategory(Category(id: id, description: "some category"));
+ bloc.addEntry(TodoEntry(category: id, content: controller.text));
controller.clear();
}
}
--- moor_flutter/example/lib/widgets/todo_card.dart
+++ moor_flutter/example/lib/widgets/todo_card.dart
@@ -45,6 +45,12 @@
children: [
Text(entry.content),
dueDate,
+ StreamBuilder<Category>(
+ stream: BlocProvider.provideBloc(context).getCategory(entry.category),
+ builder: (_, snap) {
+ return Text(snap.data?.description ?? "");
+ },
+ ),
],
),
),
Using a Constant
is what users will be doing most of the time, and it appears that the current documentation is not doing a good job at pointing that out. There should at least be an example for this.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.