Breaking changes for the upcoming version

1. Removes transaction parameter in callbacks, custom queries
2. Removes MigrationStrategy.onFinished
This commit is contained in:
Simon Binder 2019-09-13 21:04:15 +02:00
parent 3097bb0591
commit c8ae99b52e
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
14 changed files with 86 additions and 125 deletions

View File

@ -98,7 +98,7 @@ class Database extends _$Database {
await m.createTable(friendships);
}
},
beforeOpen: (_, details) async {
beforeOpen: (details) async {
if (details.wasCreated) {
await into(users)
.insertAll([People.dash, People.duke, People.gopher]);
@ -108,7 +108,7 @@ class Database extends _$Database {
}
Future<void> deleteUser(User user, {bool fail = false}) {
return transaction((_) async {
return transaction(() async {
final id = user.id;
await (delete(friendships)
..where((f) => or(f.firstUser.equals(id), f.secondUser.equals(id))))

View File

@ -9,7 +9,7 @@ void transactionTests(TestExecutor executor) {
final db = Database(executor.createExecutor());
// ignore: invalid_use_of_protected_member, invalid_use_of_visible_for_testing_member
await db.transaction((_) async {
await db.transaction(() async {
final florianId = await db.writeUser(People.florian);
final dash = await db.getUserById(People.dashId);
@ -32,7 +32,7 @@ void transactionTests(TestExecutor executor) {
try {
// ignore: invalid_use_of_protected_member, invalid_use_of_visible_for_testing_member
await db.transaction((_) async {
await db.transaction(() async {
final florianId = await db.writeUser(People.florian);
final dash = await db.getUserById(People.dashId);

View File

@ -1,3 +1,36 @@
## 2.0.0
This is the first major update after the initial release and moor and we have a lot to cover.
... Finally, we also removed a variety of deprecated features. See the breaking changes
section to learn what components are affected and what alternatives are available.
TODO: Properly describe these additions when they're finalized:
- Queries and imports in `.moor` files
- Analyzer plugin for Dart Code
- `ffi` libraries
### Breaking changes
- __THIS LIKELY AFFECTS YOUR APP:__ Removed the `transaction` parameter for callbacks
in transactions and `beforeOpen` callbacks. So, instead of writing
```dart
transaction((t) async {
await t.update(table)...;
});
```
simply write
```dart
transaction(() async {
await update(table)...;
});
```
Similarly, instead of using `onOpen: (db, details) async {...}`, use
`onOpen: (details) async {...}`. You don't have to worry about calling methods on
your database instead of a transaction objects. They will be delegated automatically.
On a similar note, we also removed the `operateOn` parameter from compiled queries.
- Removed `MigrationStrategy.onFinished`. Use `beforeOpen` instead.
## 1.7.2
- Fixed a race condition that caused the database to be opened multiple times on slower devices.
This problem was introduced in `1.7.0` and was causing problems during migrations.

View File

@ -59,10 +59,9 @@ class Database extends _$Database {
@override
MigrationStrategy get migration {
return MigrationStrategy(
beforeOpen: (engine, details) async {
beforeOpen: (details) async {
// populate data
await engine
.into(categories)
await into(categories)
.insert(const CategoriesCompanion(description: Value('Sweets')));
},
);

View File

@ -847,19 +847,15 @@ abstract class _$Database extends GeneratedDatabase {
);
}
Selectable<TotalWeightResult> _totalWeightQuery(
{@Deprecated('No longer needed with Moor 1.6 - see the changelog for details')
QueryEngine operateOn}) {
Selectable<TotalWeightResult> _totalWeightQuery() {
return (operateOn ?? this).customSelectQuery(
' SELECT r.title, SUM(ir.amount) AS total_weight\n FROM recipes r\n INNER JOIN recipe_ingredients ir ON ir.recipe = r.id\n GROUP BY r.id\n ',
variables: [],
readsFrom: {recipes, ingredientInRecipes}).map(_rowToTotalWeightResult);
}
Future<List<TotalWeightResult>> _totalWeight(
{@Deprecated('No longer needed with Moor 1.6 - see the changelog for details')
QueryEngine operateOn}) {
return _totalWeightQuery(operateOn: operateOn).get();
Future<List<TotalWeightResult>> _totalWeight() {
return _totalWeightQuery().get();
}
Stream<List<TotalWeightResult>> _watchTotalWeight() {

View File

@ -28,7 +28,7 @@ class Database extends _$Database {
MigrationStrategy get migration {
return MigrationStrategy(
onCreate: (m) async => await m.createAllTables(),
beforeOpen: (engine, details) async {
beforeOpen: (details) async {
if (details.wasCreated) {
// populate default data
await createTodoEntry(

View File

@ -280,10 +280,10 @@ mixin QueryEngine on DatabaseConnectionUser {
/// inside a transaction returns the parent transaction.
@protected
@visibleForTesting
Future transaction(Future Function(QueryEngine transaction) action) async {
Future transaction(Future Function() action) async {
final resolved = _resolvedEngine;
if (resolved is Transaction) {
return action(resolved);
return action();
}
final executor = resolved.executor;
@ -294,7 +294,7 @@ mixin QueryEngine on DatabaseConnectionUser {
return _runEngineZoned(transaction, () async {
var success = false;
try {
await action(transaction);
await action();
success = true;
} catch (e) {
await transactionExecutor.rollback();
@ -376,13 +376,11 @@ abstract class GeneratedDatabase extends DatabaseConnectionUser
Future<void> beforeOpenCallback(
QueryExecutor executor, OpeningDetails details) async {
final migration = _resolvedMigration;
if (migration.onFinished != null) {
await migration.onFinished();
}
if (migration.beforeOpen != null) {
final engine = BeforeOpenEngine(this, executor);
await _runEngineZoned(engine, () {
return migration.beforeOpen(engine, details);
return migration.beforeOpen(details);
});
}
}

View File

@ -16,8 +16,7 @@ typedef Future<void> OnMigrationFinished();
/// Signature of a function that's called before a database is marked opened by
/// moor, but after migrations took place. This is a suitable callback to to
/// populate initial data or issue `PRAGMA` statements that you want to use.
typedef OnBeforeOpen = Future<void> Function(
QueryEngine db, OpeningDetails details);
typedef OnBeforeOpen = Future<void> Function(OpeningDetails details);
Future<void> _defaultOnCreate(Migrator m) => m.createAllTables();
Future<void> _defaultOnUpdate(Migrator m, int from, int to) async =>
@ -33,14 +32,6 @@ class MigrationStrategy {
/// happened at a lower [GeneratedDatabase.schemaVersion].
final OnUpgrade onUpgrade;
/// Executes after the database is ready and all migrations ran, but before
/// any other queries will be executed, making this method suitable to
/// populate data.
@Deprecated(
'This callback is broken and only exists for backwards compatibility. '
'Use beforeOpen instead')
final OnMigrationFinished onFinished;
/// Executes after the database is ready to be used (ie. it has been opened
/// and all migrations ran), but before any other queries will be sent. This
/// makes it a suitable place to populate data after the database has been
@ -51,8 +42,6 @@ class MigrationStrategy {
this.onCreate = _defaultOnCreate,
this.onUpgrade = _defaultOnUpdate,
this.beforeOpen,
@Deprecated('This callback is broken. Use beforeOpen instead')
this.onFinished,
});
}

View File

@ -819,10 +819,7 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
);
}
Selectable<ConfigData> readConfig(
String var1,
{@Deprecated('No longer needed with Moor 1.6 - see the changelog for details')
QueryEngine operateOn}) {
Selectable<ConfigData> readConfig(String var1) {
return (operateOn ?? this).customSelectQuery(
'readConfig: SELECT * FROM config WHERE config_key = ?;',
variables: [
@ -833,11 +830,7 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
}).map(_rowToConfigData);
}
Future<int> writeConfig(
String key,
String value,
{@Deprecated('No longer needed with Moor 1.6 - see the changelog for details')
QueryEngine operateOn}) {
Future<int> writeConfig(String key, String value) {
return (operateOn ?? this).customInsert(
'REPLACE INTO config VALUES (:key, :value)',
variables: [

View File

@ -1312,9 +1312,7 @@ abstract class _$TodoDb extends GeneratedDatabase {
);
}
Selectable<AllTodosWithCategoryResult> allTodosWithCategoryQuery(
{@Deprecated('No longer needed with Moor 1.6 - see the changelog for details')
QueryEngine operateOn}) {
Selectable<AllTodosWithCategoryResult> allTodosWithCategoryQuery() {
return (operateOn ?? this).customSelectQuery(
'SELECT t.*, c.id as catId, c."desc" as catDesc FROM todos t INNER JOIN categories c ON c.id = t.category',
variables: [],
@ -1324,20 +1322,15 @@ abstract class _$TodoDb extends GeneratedDatabase {
}).map(_rowToAllTodosWithCategoryResult);
}
Future<List<AllTodosWithCategoryResult>> allTodosWithCategory(
{@Deprecated('No longer needed with Moor 1.6 - see the changelog for details')
QueryEngine operateOn}) {
return allTodosWithCategoryQuery(operateOn: operateOn).get();
Future<List<AllTodosWithCategoryResult>> allTodosWithCategory() {
return allTodosWithCategoryQuery().get();
}
Stream<List<AllTodosWithCategoryResult>> watchAllTodosWithCategory() {
return allTodosWithCategoryQuery().watch();
}
Future<int> deleteTodoById(
int var1,
{@Deprecated('No longer needed with Moor 1.6 - see the changelog for details')
QueryEngine operateOn}) {
Future<int> deleteTodoById(int var1) {
return (operateOn ?? this).customUpdate(
'DELETE FROM todos WHERE id = ?',
variables: [
@ -1357,12 +1350,7 @@ abstract class _$TodoDb extends GeneratedDatabase {
);
}
Selectable<TodoEntry> withInQuery(
String var1,
String var2,
List<int> var3,
{@Deprecated('No longer needed with Moor 1.6 - see the changelog for details')
QueryEngine operateOn}) {
Selectable<TodoEntry> withInQuery(String var1, String var2, List<int> var3) {
var $highestIndex = 3;
final expandedvar3 = $expandVar($highestIndex, var3.length);
$highestIndex += var3.length;
@ -1378,13 +1366,8 @@ abstract class _$TodoDb extends GeneratedDatabase {
}).map(_rowToTodoEntry);
}
Future<List<TodoEntry>> withIn(
String var1,
String var2,
List<int> var3,
{@Deprecated('No longer needed with Moor 1.6 - see the changelog for details')
QueryEngine operateOn}) {
return withInQuery(var1, var2, var3, operateOn: operateOn).get();
Future<List<TodoEntry>> withIn(String var1, String var2, List<int> var3) {
return withInQuery(var1, var2, var3).get();
}
Stream<List<TodoEntry>> watchWithIn(
@ -1392,10 +1375,7 @@ abstract class _$TodoDb extends GeneratedDatabase {
return withInQuery(var1, var2, var3).watch();
}
Selectable<TodoEntry> searchQuery(
int id,
{@Deprecated('No longer needed with Moor 1.6 - see the changelog for details')
QueryEngine operateOn}) {
Selectable<TodoEntry> searchQuery(int id) {
return (operateOn ?? this).customSelectQuery(
'SELECT * FROM todos WHERE CASE WHEN -1 = :id THEN 1 ELSE id = :id END',
variables: [
@ -1406,11 +1386,8 @@ abstract class _$TodoDb extends GeneratedDatabase {
}).map(_rowToTodoEntry);
}
Future<List<TodoEntry>> search(
int id,
{@Deprecated('No longer needed with Moor 1.6 - see the changelog for details')
QueryEngine operateOn}) {
return searchQuery(id, operateOn: operateOn).get();
Future<List<TodoEntry>> search(int id) {
return searchQuery(id).get();
}
Stream<List<TodoEntry>> watchSearch(int id) {
@ -1424,19 +1401,15 @@ abstract class _$TodoDb extends GeneratedDatabase {
);
}
Selectable<FindCustomResult> findCustomQuery(
{@Deprecated('No longer needed with Moor 1.6 - see the changelog for details')
QueryEngine operateOn}) {
Selectable<FindCustomResult> findCustomQuery() {
return (operateOn ?? this).customSelectQuery(
'SELECT custom FROM table_without_p_k WHERE some_float < 10',
variables: [],
readsFrom: {tableWithoutPK}).map(_rowToFindCustomResult);
}
Future<List<FindCustomResult>> findCustom(
{@Deprecated('No longer needed with Moor 1.6 - see the changelog for details')
QueryEngine operateOn}) {
return findCustomQuery(operateOn: operateOn).get();
Future<List<FindCustomResult>> findCustom() {
return findCustomQuery().get();
}
Stream<List<FindCustomResult>> watchFindCustom() {
@ -1498,10 +1471,7 @@ mixin _$SomeDaoMixin on DatabaseAccessor<TodoDb> {
);
}
Selectable<TodoEntry> todosForUserQuery(
int user,
{@Deprecated('No longer needed with Moor 1.6 - see the changelog for details')
QueryEngine operateOn}) {
Selectable<TodoEntry> todosForUserQuery(int user) {
return (operateOn ?? this).customSelectQuery(
'SELECT t.* FROM todos t INNER JOIN shared_todos st ON st.todo = t.id INNER JOIN users u ON u.id = st.user WHERE u.id = :user',
variables: [
@ -1514,11 +1484,8 @@ mixin _$SomeDaoMixin on DatabaseAccessor<TodoDb> {
}).map(_rowToTodoEntry);
}
Future<List<TodoEntry>> todosForUser(
int user,
{@Deprecated('No longer needed with Moor 1.6 - see the changelog for details')
QueryEngine operateOn}) {
return todosForUserQuery(user, operateOn: operateOn).get();
Future<List<TodoEntry>> todosForUser(int user) {
return todosForUserQuery(user).get();
}
Stream<List<TodoEntry>> watchTodosForUser(int user) {

View File

@ -15,8 +15,9 @@ class _FakeDb extends GeneratedDatabase {
onUpgrade: (m, from, to) async {
await m.issueCustomQuery('updated from $from to $to');
},
beforeOpen: (db, details) async {
await db.customSelect(
beforeOpen: (details) async {
// this fake select query is verified via mocks
await customSelect(
'opened: ${details.versionBefore} to ${details.versionNow}');
},
);

View File

@ -33,16 +33,16 @@ void main() {
test("transactions don't allow creating streams", () {
expect(() async {
await db.transaction((t) async {
t.select(db.users).watch();
await db.transaction(() async {
db.select(db.users).watch();
});
}, throwsStateError);
});
test('nested transactions use the outer transaction', () async {
await db.transaction((t) async {
await t.transaction((t2) async {
expect(t2, equals(t));
await db.transaction(() async {
await db.transaction(() async {
// todo how can we test that these are really equal?
});
// the outer callback has not completed yet, so shouldn't send
@ -55,7 +55,7 @@ void main() {
test('code in callback uses transaction', () async {
// notice how we call .select on the database, but it should be called on
// transaction executor.
await db.transaction((_) async {
await db.transaction(() async {
await db.select(db.users).get();
});
@ -65,7 +65,7 @@ void main() {
test('transactions rollback after errors', () async {
final exception = Exception('oh no');
final future = db.transaction((_) async {
final future = db.transaction(() async {
throw exception;
});
@ -79,8 +79,8 @@ void main() {
when(executor.transactions.runUpdate(any, any))
.thenAnswer((_) => Future.value(2));
await db.transaction((t) async {
await t
await db.transaction(() async {
await db
.update(db.users)
.write(const UsersCompanion(name: Value('Updated name')));
@ -95,7 +95,7 @@ void main() {
});
test('the database is opened before starting a transaction', () async {
await db.transaction((t) async {
await db.transaction(() async {
verify(executor.doWhenOpened(any));
});
});

View File

@ -63,7 +63,7 @@ class Database extends _$Database {
await m.addColumn(todos, todos.targetDate);
}
},
beforeOpen: (db, details) async {
beforeOpen: (details) async {
if (details.wasCreated) {
// create default categories and entries
final workId = await into(categories)
@ -154,7 +154,7 @@ class Database extends _$Database {
}
Future deleteCategory(Category category) {
return transaction((t) async {
return transaction(() async {
await _resetCategory(category.id);
await delete(categories).delete(category);
});

View File

@ -9,9 +9,6 @@ import 'package:moor_generator/src/writer/writer.dart';
import 'package:recase/recase.dart';
import 'package:sqlparser/sqlparser.dart';
const queryEngineWarningDesc =
'No longer needed with Moor 1.6 - see the changelog for details';
const highestAssignedIndexVar = '\$highestIndex';
/// Writes the handling code for a query. The code emitted will be a method that
@ -157,9 +154,9 @@ class QueryWriter {
}
_buffer.write('Stream<List<${_select.resultClassName}>> $methodName(');
_writeParameters(dontOverrideEngine: true);
_writeParameters();
_buffer..write(') {\n')..write('return ${_nameOfCreationMethod()}(');
_writeUseParameters(dontUseEngine: true);
_writeUseParameters();
_buffer.write(').watch();\n}\n');
}
@ -187,7 +184,7 @@ class QueryWriter {
_buffer..write(',);\n}\n');
}
void _writeParameters({bool dontOverrideEngine = false}) {
void _writeParameters() {
final paramList = query.variables.map((v) {
var dartType = dartTypeNames[v.type];
if (v.isArray) {
@ -197,25 +194,13 @@ class QueryWriter {
}).join(', ');
_buffer.write(paramList);
// write named optional parameter to configure the query engine used to
// execute the statement,
if (!dontOverrideEngine) {
if (query.variables.isNotEmpty) _buffer.write(', ');
_buffer.write('{@Deprecated(${asDartLiteral(queryEngineWarningDesc)}) '
'QueryEngine operateOn}');
}
}
/// Writes code that uses the parameters as declared by [_writeParameters],
/// assuming that for each parameter, a variable with the same name exists
/// in the current scope.
void _writeUseParameters({bool dontUseEngine = false}) {
void _writeUseParameters() {
_buffer.write(query.variables.map((v) => v.dartParameterName).join(', '));
if (!dontUseEngine) {
if (query.variables.isNotEmpty) _buffer.write(', ');
_buffer.write('operateOn: operateOn');
}
}
// Some notes on parameters and generating query code: