Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 8d088f3

Browse files
committedMar 5, 2025
Fix duplicate entries in ps_sync_state
1 parent 56f37c8 commit 8d088f3

File tree

8 files changed

+220
-40
lines changed

8 files changed

+220
-40
lines changed
 

‎crates/core/src/migrations.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,5 +333,26 @@ json_object('sql', 'DELETE FROM ps_migration WHERE id >= 7')
333333
local_db.exec_safe(&stmt).into_db_result(local_db)?;
334334
}
335335

336+
if current_version < 8 && target_version >= 8 {
337+
let stmt = "\
338+
ALTER TABLE ps_sync_state RENAME TO ps_sync_state_old;
339+
CREATE TABLE ps_sync_state (
340+
priority INTEGER NOT NULL PRIMARY KEY,
341+
last_synced_at TEXT NOT NULL
342+
) STRICT;
343+
INSERT INTO ps_sync_state (priority, last_synced_at)
344+
SELECT priority, MAX(last_synced_at) FROM ps_sync_state_old GROUP BY priority;
345+
DROP TABLE ps_sync_state_old;
346+
INSERT INTO ps_migration(id, down_migrations) VALUES(8, json_array(
347+
json_object('sql', 'ALTER TABLE ps_sync_state RENAME TO ps_sync_state_new'),
348+
json_object('sql', 'CREATE TABLE ps_sync_state (\n priority INTEGER NOT NULL,\n last_synced_at TEXT NOT NULL\n) STRICT'),
349+
json_object('sql', 'INSERT INTO ps_sync_state SELECT * FROM ps_sync_state_new'),
350+
json_object('sql', 'DROP TABLE ps_sync_state_new'),
351+
json_object('sql', 'DELETE FROM ps_migration WHERE id >= 8')
352+
));
353+
";
354+
local_db.exec_safe(&stmt).into_db_result(local_db)?;
355+
}
356+
336357
Ok(())
337358
}

‎crates/core/src/view_admin.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ fn powersync_init_impl(
120120

121121
setup_internal_views(local_db)?;
122122

123-
powersync_migrate(ctx, 7)?;
123+
powersync_migrate(ctx, 8)?;
124124

125125
Ok(String::from(""))
126126
}

‎dart/pubspec.lock

Lines changed: 44 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,18 @@ packages:
55
dependency: transitive
66
description:
77
name: _fe_analyzer_shared
8-
sha256: "03f6da266a27a4538a69295ec142cb5717d7d4e5727b84658b63e1e1509bac9c"
8+
sha256: dc27559385e905ad30838356c5f5d574014ba39872d732111cd07ac0beff4c57
99
url: "https://pub.dev"
1010
source: hosted
11-
version: "79.0.0"
12-
_macros:
13-
dependency: transitive
14-
description: dart
15-
source: sdk
16-
version: "0.3.3"
11+
version: "80.0.0"
1712
analyzer:
1813
dependency: transitive
1914
description:
2015
name: analyzer
21-
sha256: c9040fc56483c22a5e04a9f6a251313118b1a3c42423770623128fa484115643
16+
sha256: "192d1c5b944e7e53b24b5586db760db934b177d4147c42fbca8c8c5f1eb8d11e"
2217
url: "https://pub.dev"
2318
source: hosted
24-
version: "7.2.0"
19+
version: "7.3.0"
2520
args:
2621
dependency: transitive
2722
description:
@@ -34,10 +29,10 @@ packages:
3429
dependency: transitive
3530
description:
3631
name: async
37-
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
32+
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
3833
url: "https://pub.dev"
3934
source: hosted
40-
version: "2.12.0"
35+
version: "2.13.0"
4136
boolean_selector:
4237
dependency: transitive
4338
description:
@@ -46,6 +41,14 @@ packages:
4641
url: "https://pub.dev"
4742
source: hosted
4843
version: "2.1.2"
44+
clock:
45+
dependency: transitive
46+
description:
47+
name: clock
48+
sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
49+
url: "https://pub.dev"
50+
source: hosted
51+
version: "1.1.2"
4952
collection:
5053
dependency: transitive
5154
description:
@@ -78,16 +81,24 @@ packages:
7881
url: "https://pub.dev"
7982
source: hosted
8083
version: "3.0.6"
84+
fake_async:
85+
dependency: "direct dev"
86+
description:
87+
name: fake_async
88+
sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
89+
url: "https://pub.dev"
90+
source: hosted
91+
version: "1.3.3"
8192
ffi:
8293
dependency: transitive
8394
description:
8495
name: ffi
85-
sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
96+
sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418"
8697
url: "https://pub.dev"
8798
source: hosted
88-
version: "2.1.3"
99+
version: "2.1.4"
89100
file:
90-
dependency: transitive
101+
dependency: "direct dev"
91102
description:
92103
name: file
93104
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
@@ -138,10 +149,10 @@ packages:
138149
dependency: transitive
139150
description:
140151
name: js
141-
sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf
152+
sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc"
142153
url: "https://pub.dev"
143154
source: hosted
144-
version: "0.7.1"
155+
version: "0.7.2"
145156
logging:
146157
dependency: transitive
147158
description:
@@ -150,14 +161,6 @@ packages:
150161
url: "https://pub.dev"
151162
source: hosted
152163
version: "1.3.0"
153-
macros:
154-
dependency: transitive
155-
description:
156-
name: macros
157-
sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656"
158-
url: "https://pub.dev"
159-
source: hosted
160-
version: "0.1.3-main.0"
161164
matcher:
162165
dependency: transitive
163166
description:
@@ -250,10 +253,10 @@ packages:
250253
dependency: transitive
251254
description:
252255
name: shelf_web_socket
253-
sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67
256+
sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925"
254257
url: "https://pub.dev"
255258
source: hosted
256-
version: "2.0.1"
259+
version: "3.0.0"
257260
source_map_stack_trace:
258261
dependency: transitive
259262
description:
@@ -282,10 +285,18 @@ packages:
282285
dependency: "direct main"
283286
description:
284287
name: sqlite3
285-
sha256: "35d3726fe18ab1463403a5cc8d97dbc81f2a0b08082e8173851363fcc97b6627"
288+
sha256: "32b632dda27d664f85520093ed6f735ae5c49b5b75345afb8b19411bc59bb53d"
286289
url: "https://pub.dev"
287290
source: hosted
288-
version: "2.7.2"
291+
version: "2.7.4"
292+
sqlite3_test:
293+
dependency: "direct dev"
294+
description:
295+
name: sqlite3_test
296+
sha256: "0b6f76541385cbe0cebf9454854f78dc9aa18b8cb512d8e597e63385e61d4f45"
297+
url: "https://pub.dev"
298+
source: hosted
299+
version: "0.1.1"
289300
stack_trace:
290301
dependency: transitive
291302
description:
@@ -322,10 +333,10 @@ packages:
322333
dependency: "direct dev"
323334
description:
324335
name: test
325-
sha256: "8391fbe68d520daf2314121764d38e37f934c02fd7301ad18307bd93bd6b725d"
336+
sha256: "301b213cd241ca982e9ba50266bd3f5bd1ea33f1455554c5abb85d1be0e2d87e"
326337
url: "https://pub.dev"
327338
source: hosted
328-
version: "1.25.14"
339+
version: "1.25.15"
329340
test_api:
330341
dependency: transitive
331342
description:
@@ -370,10 +381,10 @@ packages:
370381
dependency: transitive
371382
description:
372383
name: web
373-
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
384+
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
374385
url: "https://pub.dev"
375386
source: hosted
376-
version: "1.1.0"
387+
version: "1.1.1"
377388
web_socket:
378389
dependency: transitive
379390
description:
@@ -407,4 +418,4 @@ packages:
407418
source: hosted
408419
version: "3.1.3"
409420
sdks:
410-
dart: ">=3.5.0 <4.0.0"
421+
dart: ">=3.7.0 <4.0.0"

‎dart/pubspec.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,6 @@ dependencies:
88
sqlite3: ^2.4.5
99
dev_dependencies:
1010
test: ^1.25.0
11+
file: ^7.0.1
12+
sqlite3_test: ^0.1.1
13+
fake_async: ^1.3.3

‎dart/test/migration_test.dart

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,5 +246,34 @@ ${fixtures.schema5.trim()}
246246
end''';
247247
expect(schema, equals(expected));
248248
});
249+
250+
test('schema 7 -> 8 migrates last_synced_at data', () {
251+
db.execute(fixtures.expectedState[7]!);
252+
253+
for (var i = 0; i < 10; i++) {
254+
db.execute(
255+
'INSERT OR REPLACE INTO ps_sync_state (priority, last_synced_at) VALUES (?, ?);',
256+
[2147483647, '2025-03-05 14:58:${i.toString().padLeft(2, '0')}'],
257+
);
258+
259+
db.execute(
260+
'INSERT OR REPLACE INTO ps_sync_state (priority, last_synced_at) VALUES (?, ?);',
261+
[3, '2025-03-05 13:58:${i.toString().padLeft(2, '0')}'],
262+
);
263+
}
264+
265+
db.execute('SELECT powersync_test_migration(8);');
266+
267+
expect(db.select('SELECT * FROM ps_sync_state ORDER BY priority'), [
268+
{
269+
'priority': 3,
270+
'last_synced_at': '2025-03-05 13:58:09',
271+
},
272+
{
273+
'priority': 2147483647,
274+
'last_synced_at': '2025-03-05 14:58:09',
275+
}
276+
]);
277+
});
249278
});
250279
}

‎dart/test/sync_test.dart

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,28 @@
11
import 'dart:convert';
22

3+
import 'package:fake_async/fake_async.dart';
4+
import 'package:file/local.dart';
35
import 'package:sqlite3/common.dart';
6+
import 'package:sqlite3/sqlite3.dart';
7+
import 'package:sqlite3_test/sqlite3_test.dart';
48
import 'package:test/test.dart';
59

610
import 'utils/native_test_utils.dart';
711

812
void main() {
13+
final vfs = TestSqliteFileSystem(fs: const LocalFileSystem());
14+
15+
setUpAll(() {
16+
loadExtension();
17+
sqlite3.registerVirtualFileSystem(vfs, makeDefault: false);
18+
});
19+
tearDownAll(() => sqlite3.unregisterVirtualFileSystem(vfs));
20+
921
group('sync tests', () {
1022
late CommonDatabase db;
1123

1224
setUp(() async {
13-
db = openTestDatabase()
25+
db = openTestDatabase(vfs)
1426
..select('select powersync_init();')
1527
..select('select powersync_replace_schema(?)', [json.encode(_schema)]);
1628
});
@@ -187,6 +199,38 @@ void main() {
187199
}
188200
});
189201

202+
test('can sync multiple times', () {
203+
fakeAsync((controller) {
204+
for (var i = 0; i < 10; i++) {
205+
for (var prio in const [1, 2, 3, null]) {
206+
pushCheckpointComplete('1', null, [], priority: prio);
207+
208+
// Make sure there's only a single row in last_synced_at
209+
expect(
210+
db.select(
211+
"SELECT datetime(last_synced_at, 'localtime') AS last_synced_at FROM ps_sync_state WHERE priority = ?",
212+
[prio ?? 2147483647]),
213+
[
214+
{'last_synced_at': '2025-03-01 ${10 + i}:00:00'}
215+
],
216+
);
217+
218+
if (prio == null) {
219+
expect(
220+
db.select(
221+
"SELECT datetime(powersync_last_synced_at(), 'localtime') AS last_synced_at"),
222+
[
223+
{'last_synced_at': '2025-03-01 ${10 + i}:00:00'}
224+
],
225+
);
226+
}
227+
}
228+
229+
controller.elapse(const Duration(hours: 1));
230+
}
231+
}, initialTime: DateTime(2025, 3, 1, 10));
232+
});
233+
190234
test('clearing database clears sync status', () {
191235
pushSyncData('prio1', '1', 'row-0', 'PUT', {'col': 'hi'});
192236

‎dart/test/utils/migration_fixtures.dart

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/// The current database version
2-
const databaseVersion = 7;
2+
const databaseVersion = 8;
33

44
/// This is the base database state that we expect at various schema versions.
55
/// Generated by loading the specific library version, and exporting the schema.
@@ -216,6 +216,51 @@ const expectedState = <int, String>{
216216
;INSERT INTO ps_migration(id, down_migrations) VALUES(5, '[{"sql":"SELECT powersync_drop_view(view.name)\n FROM sqlite_master view\n WHERE view.type = ''view''\n AND view.sql GLOB ''*-- powersync-auto-generated''"},{"sql":"ALTER TABLE ps_buckets RENAME TO ps_buckets_5"},{"sql":"ALTER TABLE ps_oplog RENAME TO ps_oplog_5"},{"sql":"CREATE TABLE ps_buckets(\n name TEXT PRIMARY KEY,\n last_applied_op INTEGER NOT NULL DEFAULT 0,\n last_op INTEGER NOT NULL DEFAULT 0,\n target_op INTEGER NOT NULL DEFAULT 0,\n add_checksum INTEGER NOT NULL DEFAULT 0,\n pending_delete INTEGER NOT NULL DEFAULT 0\n, op_checksum INTEGER NOT NULL DEFAULT 0, remove_operations INTEGER NOT NULL DEFAULT 0)"},{"sql":"INSERT INTO ps_buckets(name, last_applied_op, last_op, target_op, add_checksum, op_checksum, pending_delete)\n SELECT name, last_applied_op, last_op, target_op, add_checksum, op_checksum, pending_delete FROM ps_buckets_5"},{"sql":"CREATE TABLE ps_oplog(\n bucket TEXT NOT NULL,\n op_id INTEGER NOT NULL,\n op INTEGER NOT NULL,\n row_type TEXT,\n row_id TEXT,\n key TEXT,\n data TEXT,\n hash INTEGER NOT NULL,\n superseded INTEGER NOT NULL)"},{"sql":"CREATE INDEX ps_oplog_by_row ON ps_oplog (row_type, row_id) WHERE superseded = 0"},{"sql":"CREATE INDEX ps_oplog_by_opid ON ps_oplog (bucket, op_id)"},{"sql":"CREATE INDEX ps_oplog_by_key ON ps_oplog (bucket, key) WHERE superseded = 0"},{"sql":"INSERT INTO ps_oplog(bucket, op_id, op, row_type, row_id, key, data, hash, superseded)\n SELECT ps_buckets_5.name, oplog.op_id, 3, oplog.row_type, oplog.row_id, oplog.key, oplog.data, oplog.hash, 0\n FROM ps_oplog_5 oplog\n JOIN ps_buckets_5\n ON ps_buckets_5.id = oplog.bucket"},{"sql":"DROP TABLE ps_oplog_5"},{"sql":"DROP TABLE ps_buckets_5"},{"sql":"INSERT INTO ps_oplog(bucket, op_id, op, row_type, row_id, hash, superseded)\n SELECT ''$local'', 1, 4, r.row_type, r.row_id, 0, 0\n FROM ps_updated_rows r"},{"sql":"INSERT OR REPLACE INTO ps_buckets(name, pending_delete, last_op, target_op) VALUES(''$local'', 1, 0, 9223372036854775807)"},{"sql":"DROP TABLE ps_updated_rows"},{"sql":"DELETE FROM ps_migration WHERE id >= 5"}]')
217217
;INSERT INTO ps_migration(id, down_migrations) VALUES(6, '[{"sql":"DELETE FROM ps_migration WHERE id >= 6"}]')
218218
;INSERT INTO ps_migration(id, down_migrations) VALUES(7, '[{"sql":"INSERT OR REPLACE INTO ps_kv(key, value) SELECT ''last_synced_at'', last_synced_at FROM ps_sync_state WHERE priority = 2147483647"},{"sql":"DROP TABLE ps_sync_state"},{"sql":"DELETE FROM ps_migration WHERE id >= 7"}]')
219+
''',
220+
8: r'''
221+
;CREATE TABLE ps_buckets(
222+
id INTEGER PRIMARY KEY,
223+
name TEXT NOT NULL,
224+
last_applied_op INTEGER NOT NULL DEFAULT 0,
225+
last_op INTEGER NOT NULL DEFAULT 0,
226+
target_op INTEGER NOT NULL DEFAULT 0,
227+
add_checksum INTEGER NOT NULL DEFAULT 0,
228+
op_checksum INTEGER NOT NULL DEFAULT 0,
229+
pending_delete INTEGER NOT NULL DEFAULT 0
230+
) STRICT
231+
;CREATE TABLE ps_crud (id INTEGER PRIMARY KEY AUTOINCREMENT, data TEXT, tx_id INTEGER)
232+
;CREATE TABLE ps_kv(key TEXT PRIMARY KEY NOT NULL, value BLOB)
233+
;CREATE TABLE ps_migration(id INTEGER PRIMARY KEY, down_migrations TEXT)
234+
;CREATE TABLE ps_oplog(
235+
bucket INTEGER NOT NULL,
236+
op_id INTEGER NOT NULL,
237+
row_type TEXT,
238+
row_id TEXT,
239+
key TEXT,
240+
data TEXT,
241+
hash INTEGER NOT NULL) STRICT
242+
;CREATE TABLE ps_sync_state (
243+
priority INTEGER NOT NULL PRIMARY KEY,
244+
last_synced_at TEXT NOT NULL
245+
) STRICT
246+
;CREATE TABLE ps_tx(id INTEGER PRIMARY KEY NOT NULL, current_tx INTEGER, next_tx INTEGER)
247+
;CREATE TABLE ps_untyped(type TEXT NOT NULL, id TEXT NOT NULL, data TEXT, PRIMARY KEY (type, id))
248+
;CREATE TABLE ps_updated_rows(
249+
row_type TEXT,
250+
row_id TEXT,
251+
PRIMARY KEY(row_type, row_id)) STRICT, WITHOUT ROWID
252+
;CREATE UNIQUE INDEX ps_buckets_name ON ps_buckets (name)
253+
;CREATE INDEX ps_oplog_key ON ps_oplog (bucket, key)
254+
;CREATE INDEX ps_oplog_opid ON ps_oplog (bucket, op_id)
255+
;CREATE INDEX ps_oplog_row ON ps_oplog (row_type, row_id)
256+
;INSERT INTO ps_migration(id, down_migrations) VALUES(1, null)
257+
;INSERT INTO ps_migration(id, down_migrations) VALUES(2, '[{"sql":"DELETE FROM ps_migration WHERE id >= 2","params":[]},{"sql":"DROP TABLE ps_tx","params":[]},{"sql":"ALTER TABLE ps_crud DROP COLUMN tx_id","params":[]}]')
258+
;INSERT INTO ps_migration(id, down_migrations) VALUES(3, '[{"sql":"DELETE FROM ps_migration WHERE id >= 3"},{"sql":"DROP TABLE ps_kv"}]')
259+
;INSERT INTO ps_migration(id, down_migrations) VALUES(4, '[{"sql":"DELETE FROM ps_migration WHERE id >= 4"},{"sql":"ALTER TABLE ps_buckets DROP COLUMN op_checksum"},{"sql":"ALTER TABLE ps_buckets DROP COLUMN remove_operations"}]')
260+
;INSERT INTO ps_migration(id, down_migrations) VALUES(5, '[{"sql":"SELECT powersync_drop_view(view.name)\n FROM sqlite_master view\n WHERE view.type = ''view''\n AND view.sql GLOB ''*-- powersync-auto-generated''"},{"sql":"ALTER TABLE ps_buckets RENAME TO ps_buckets_5"},{"sql":"ALTER TABLE ps_oplog RENAME TO ps_oplog_5"},{"sql":"CREATE TABLE ps_buckets(\n name TEXT PRIMARY KEY,\n last_applied_op INTEGER NOT NULL DEFAULT 0,\n last_op INTEGER NOT NULL DEFAULT 0,\n target_op INTEGER NOT NULL DEFAULT 0,\n add_checksum INTEGER NOT NULL DEFAULT 0,\n pending_delete INTEGER NOT NULL DEFAULT 0\n, op_checksum INTEGER NOT NULL DEFAULT 0, remove_operations INTEGER NOT NULL DEFAULT 0)"},{"sql":"INSERT INTO ps_buckets(name, last_applied_op, last_op, target_op, add_checksum, op_checksum, pending_delete)\n SELECT name, last_applied_op, last_op, target_op, add_checksum, op_checksum, pending_delete FROM ps_buckets_5"},{"sql":"CREATE TABLE ps_oplog(\n bucket TEXT NOT NULL,\n op_id INTEGER NOT NULL,\n op INTEGER NOT NULL,\n row_type TEXT,\n row_id TEXT,\n key TEXT,\n data TEXT,\n hash INTEGER NOT NULL,\n superseded INTEGER NOT NULL)"},{"sql":"CREATE INDEX ps_oplog_by_row ON ps_oplog (row_type, row_id) WHERE superseded = 0"},{"sql":"CREATE INDEX ps_oplog_by_opid ON ps_oplog (bucket, op_id)"},{"sql":"CREATE INDEX ps_oplog_by_key ON ps_oplog (bucket, key) WHERE superseded = 0"},{"sql":"INSERT INTO ps_oplog(bucket, op_id, op, row_type, row_id, key, data, hash, superseded)\n SELECT ps_buckets_5.name, oplog.op_id, 3, oplog.row_type, oplog.row_id, oplog.key, oplog.data, oplog.hash, 0\n FROM ps_oplog_5 oplog\n JOIN ps_buckets_5\n ON ps_buckets_5.id = oplog.bucket"},{"sql":"DROP TABLE ps_oplog_5"},{"sql":"DROP TABLE ps_buckets_5"},{"sql":"INSERT INTO ps_oplog(bucket, op_id, op, row_type, row_id, hash, superseded)\n SELECT ''$local'', 1, 4, r.row_type, r.row_id, 0, 0\n FROM ps_updated_rows r"},{"sql":"INSERT OR REPLACE INTO ps_buckets(name, pending_delete, last_op, target_op) VALUES(''$local'', 1, 0, 9223372036854775807)"},{"sql":"DROP TABLE ps_updated_rows"},{"sql":"DELETE FROM ps_migration WHERE id >= 5"}]')
261+
;INSERT INTO ps_migration(id, down_migrations) VALUES(6, '[{"sql":"DELETE FROM ps_migration WHERE id >= 6"}]')
262+
;INSERT INTO ps_migration(id, down_migrations) VALUES(7, '[{"sql":"INSERT OR REPLACE INTO ps_kv(key, value) SELECT ''last_synced_at'', last_synced_at FROM ps_sync_state WHERE priority = 2147483647"},{"sql":"DROP TABLE ps_sync_state"},{"sql":"DELETE FROM ps_migration WHERE id >= 7"}]')
263+
;INSERT INTO ps_migration(id, down_migrations) VALUES(8, '[{"sql":"ALTER TABLE ps_sync_state RENAME TO ps_sync_state_new"},{"sql":"CREATE TABLE ps_sync_state (\n priority INTEGER NOT NULL,\n last_synced_at TEXT NOT NULL\n) STRICT"},{"sql":"INSERT INTO ps_sync_state SELECT * FROM ps_sync_state_new"},{"sql":"DROP TABLE ps_sync_state_new"},{"sql":"DELETE FROM ps_migration WHERE id >= 8"}]')
219264
''',
220265
};
221266

@@ -285,6 +330,17 @@ const data1 = <int, String>{
285330
(2, 3, 'lists', 'l1', '', '{}', 3)
286331
;INSERT INTO ps_updated_rows(row_type, row_id) VALUES
287332
('lists', 'l2')
333+
''',
334+
8: r'''
335+
;INSERT INTO ps_buckets(id, name, last_applied_op, last_op, target_op, add_checksum, op_checksum, pending_delete) VALUES
336+
(1, 'b1', 0, 0, 0, 0, 120, 0),
337+
(2, 'b2', 0, 0, 0, 1005, 3, 0)
338+
;INSERT INTO ps_oplog(bucket, op_id, row_type, row_id, key, data, hash) VALUES
339+
(1, 1, 'todos', 't1', '', '{}', 100),
340+
(1, 2, 'todos', 't2', '', '{}', 20),
341+
(2, 3, 'lists', 'l1', '', '{}', 3)
342+
;INSERT INTO ps_updated_rows(row_type, row_id) VALUES
343+
('lists', 'l2')
288344
'''
289345
};
290346

@@ -326,7 +382,8 @@ final dataDown1 = <int, String>{
326382
('b2', 3, 3, 'lists', 'l1', '', '{}', 3, 0)
327383
''',
328384
5: data1[5]!,
329-
6: data1[5]!
385+
6: data1[5]!,
386+
7: data1[5]!,
330387
};
331388

332389
final finalData1 = data1[databaseVersion]!;

‎dart/test/utils/native_test_utils.dart

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,33 @@ import 'package:path/path.dart' as p;
88
const defaultSqlitePath = 'libsqlite3.so.0';
99

1010
const libPath = '../target/debug';
11+
var didLoadExtension = false;
1112

12-
CommonDatabase openTestDatabase() {
13+
void applyOpenOverride() {
1314
sqlite_open.open.overrideFor(sqlite_open.OperatingSystem.linux, () {
1415
return DynamicLibrary.open('libsqlite3.so.0');
1516
});
1617
sqlite_open.open.overrideFor(sqlite_open.OperatingSystem.macOS, () {
17-
return DynamicLibrary.open('libsqlite3.dylib');
18+
return DynamicLibrary.open('/opt/homebrew/opt/sqlite/lib/libsqlite3.dylib');
1819
});
20+
}
21+
22+
CommonDatabase openTestDatabase([VirtualFileSystem? vfs]) {
23+
applyOpenOverride();
24+
if (!didLoadExtension) {
25+
loadExtension();
26+
}
27+
28+
return sqlite3.open(':memory:', vfs: vfs?.name);
29+
}
30+
31+
void loadExtension() {
32+
applyOpenOverride();
33+
1934
var lib = DynamicLibrary.open(getLibraryForPlatform(path: libPath));
2035
var extension = SqliteExtension.inLibrary(lib, 'sqlite3_powersync_init');
2136
sqlite3.ensureExtensionLoaded(extension);
22-
return sqlite3.open(':memory:');
37+
didLoadExtension = true;
2338
}
2439

2540
String getLibraryForPlatform({String? path = "."}) {

0 commit comments

Comments
 (0)
Please sign in to comment.