diff --git a/packages/drift_sqlite_async/CHANGELOG.md b/packages/drift_sqlite_async/CHANGELOG.md index 6bef517..109e9e1 100644 --- a/packages/drift_sqlite_async/CHANGELOG.md +++ b/packages/drift_sqlite_async/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.3.1 + +- Batch consecutive `runBatched` statements that share a statement index into a single `executeBatch` call instead of running one write per argument set. + ## 0.3.0 - Support versions 3.x of the `sqlite3` package. diff --git a/packages/drift_sqlite_async/lib/src/executor.dart b/packages/drift_sqlite_async/lib/src/executor.dart index 711c886..206c4a6 100644 --- a/packages/drift_sqlite_async/lib/src/executor.dart +++ b/packages/drift_sqlite_async/lib/src/executor.dart @@ -74,11 +74,19 @@ class _SqliteAsyncQueryDelegate extends QueryDelegate { @override Future runBatched(BatchedStatements statements) async { return writeLock((tx) async { - // sqlite_async's batch functionality doesn't have enough flexibility to support - // this with prepared statements yet. - for (final arg in statements.arguments) { - await tx.execute( - statements.statements[arg.statementIndex], arg.arguments); + final args = statements.arguments; + var i = 0; + // The statements must be run in order, so we can't group all arguments by + // their statement index up front. Instead we batch runs of consecutive + // arguments that share a statement index, preserving execution order. + while (i < args.length) { + final stmtIndex = args[i].statementIndex; + final paramSets = >[]; + while (i < args.length && args[i].statementIndex == stmtIndex) { + paramSets.add(args[i].arguments); + i++; + } + await tx.executeBatch(statements.statements[stmtIndex], paramSets); } }); } diff --git a/packages/drift_sqlite_async/pubspec.yaml b/packages/drift_sqlite_async/pubspec.yaml index fe0b890..b2237af 100644 --- a/packages/drift_sqlite_async/pubspec.yaml +++ b/packages/drift_sqlite_async/pubspec.yaml @@ -1,5 +1,5 @@ name: drift_sqlite_async -version: 0.3.0 +version: 0.3.1 homepage: https://github.com/powersync-ja/sqlite_async.dart repository: https://github.com/powersync-ja/sqlite_async.dart description: Use Drift with a sqlite_async database, allowing both to be used in the same application. diff --git a/packages/drift_sqlite_async/test/db_test.dart b/packages/drift_sqlite_async/test/db_test.dart index f5b269a..3d50840 100644 --- a/packages/drift_sqlite_async/test/db_test.dart +++ b/packages/drift_sqlite_async/test/db_test.dart @@ -147,5 +147,32 @@ void main() { final items = await dbu.todoItems.all().get(); expect(items.map((e) => e.description).toSet(), {'root', 'tx0', 'tx1'}); }); + + test('batch insert', () async { + await dbu.batch((batch) { + batch.insertAll(dbu.todoItems, [ + for (var i = 0; i < 10; i++) + TodoItemsCompanion.insert(description: 'desc $i'), + ]); + }); + + final items = await dbu.todoItems.all().get(); + expect(items.map((e) => e.description), + [for (var i = 0; i < 10; i++) 'desc $i']); + }); + + test('batch preserves statement order', () async { + await dbu.batch((batch) { + batch.insert(dbu.todoItems, + TodoItemsCompanion.insert(id: Value(1), description: 'a')); + batch.update(dbu.todoItems, TodoItemsCompanion(description: Value('b')), + where: (t) => t.id.equals(1)); + batch.insert(dbu.todoItems, + TodoItemsCompanion.insert(id: Value(2), description: 'c')); + }); + + final items = await dbu.todoItems.all().get(); + expect(items.map((e) => (e.id, e.description)), [(1, 'b'), (2, 'c')]); + }); }); }