diff --git a/crates/core/src/crud_vtab.rs b/crates/core/src/crud_vtab.rs index 4c0f407..8c66f2b 100644 --- a/crates/core/src/crud_vtab.rs +++ b/crates/core/src/crud_vtab.rs @@ -239,7 +239,7 @@ impl SimpleCrudTransactionMode { prepare_lazy(&mut self.set_updated_rows, || { // language=SQLite db.prepare_v3( - "INSERT OR IGNORE INTO ps_updated_rows(row_type, row_id) VALUES(?, ?)", + "INSERT OR IGNORE INTO ps_updated_rows(row_type, row_id, bucket) VALUES(?, ?, 0)", 0, ) }) diff --git a/crates/core/src/fix_data.rs b/crates/core/src/fix_data.rs index 89243e3..9a95425 100644 --- a/crates/core/src/fix_data.rs +++ b/crates/core/src/fix_data.rs @@ -38,8 +38,8 @@ pub fn apply_v035_fix(db: *mut sqlite::sqlite3) -> Result { // language=SQLite let statement = db.prepare_v2(&format!( " -INSERT OR IGNORE INTO ps_updated_rows(row_type, row_id) -SELECT ?1, id FROM {} +INSERT OR IGNORE INTO ps_updated_rows(row_type, row_id, bucket) +SELECT ?1, id, 0 FROM {} WHERE NOT EXISTS ( SELECT 1 FROM ps_oplog WHERE row_type = ?1 AND row_id = {}.id diff --git a/crates/core/src/migrations.rs b/crates/core/src/migrations.rs index 95df220..2f3020c 100644 --- a/crates/core/src/migrations.rs +++ b/crates/core/src/migrations.rs @@ -13,7 +13,7 @@ use crate::fix_data::apply_v035_fix; use crate::schema::inspection::ExistingView; use crate::sync::BucketPriority; -pub const LATEST_VERSION: i32 = 12; +pub const LATEST_VERSION: i32 = 13; pub fn powersync_migrate( ctx: *mut sqlite::context, @@ -424,5 +424,29 @@ json_object('sql', 'DELETE FROM ps_migration WHERE id >= 12') local_db.exec_safe(stmt).into_db_result(local_db)?; } + if current_version < 13 && target_version >= 13 { + let stmt = "\ +ALTER TABLE ps_updated_rows RENAME TO ps_updated_rows_old; +CREATE TABLE ps_updated_rows( + row_type TEXT, + row_id TEXT, + bucket INTEGER NOT NULL, + PRIMARY KEY(bucket, row_type, row_id)) STRICT, WITHOUT ROWID; +INSERT INTO ps_updated_rows(row_type, row_id, bucket) + SELECT row_type, row_id, 0 FROM ps_updated_rows_old; +INSERT OR IGNORE INTO ps_updated_rows(row_type, row_id, bucket) + SELECT row_type, row_id, bucket FROM ps_oplog; +DROP TABLE ps_updated_rows_old; +INSERT INTO ps_migration(id, down_migrations) VALUES(13, json_array( +json_object('sql', 'ALTER TABLE ps_updated_rows RENAME TO ps_updated_rows_13'), +json_object('sql', 'CREATE TABLE ps_updated_rows(\n row_type TEXT,\n row_id TEXT,\n PRIMARY KEY(row_type, row_id)) STRICT, WITHOUT ROWID'), +json_object('sql', 'INSERT INTO ps_updated_rows(row_type, row_id)\n SELECT row_type, row_id FROM ps_updated_rows_13\n GROUP BY row_type, row_id'), +json_object('sql', 'DROP TABLE ps_updated_rows_13'), +json_object('sql', 'DELETE FROM ps_migration WHERE id >= 13') +)); +"; + local_db.exec_safe(stmt).into_db_result(local_db)?; + } + Ok(()) } diff --git a/crates/core/src/operations.rs b/crates/core/src/operations.rs index adbeef0..264d2ae 100644 --- a/crates/core/src/operations.rs +++ b/crates/core/src/operations.rs @@ -51,8 +51,8 @@ pub fn delete_bucket(db: *mut sqlite::sqlite3, name: &str) -> Result<(), ResultC // language=SQLite let updated_statement = db.prepare_v2( "\ -INSERT OR IGNORE INTO ps_updated_rows(row_type, row_id) -SELECT row_type, row_id +INSERT OR IGNORE INTO ps_updated_rows(row_type, row_id, bucket) +SELECT row_type, row_id, 0 FROM ps_oplog WHERE bucket = ?1", )?; diff --git a/crates/core/src/sync/operations.rs b/crates/core/src/sync/operations.rs index e3fa0d7..67440fa 100644 --- a/crates/core/src/sync/operations.rs +++ b/crates/core/src/sync/operations.rs @@ -52,8 +52,9 @@ INSERT INTO ps_oplog(bucket, op_id, key, row_type, row_id, data, hash) VALUES (? let updated_row_statement = db.prepare_v2( "\ -INSERT OR IGNORE INTO ps_updated_rows(row_type, row_id) VALUES(?1, ?2)", +INSERT OR IGNORE INTO ps_updated_rows(row_type, row_id, bucket) VALUES(?1, ?2, ?3)", )?; + updated_row_statement.bind_int64(3, bucket_id)?; let mut last_op: Option = None; let mut add_checksum = Checksum::zero(); @@ -150,6 +151,12 @@ INSERT OR IGNORE INTO ps_updated_rows(row_type, row_id) VALUES(?1, ?2)", insert_statement.bind_int(7, checksum.bitcast_i32())?; insert_statement.exec()?; + if let (Some(object_type), Some(object_id)) = (object_type, object_id) { + updated_row_statement.bind_text(1, object_type, sqlite::Destructor::STATIC)?; + updated_row_statement.bind_text(2, object_id, sqlite::Destructor::STATIC)?; + updated_row_statement.exec()?; + } + op_checksum += checksum; } else if op == OpType::MOVE { add_checksum += checksum; @@ -158,8 +165,8 @@ INSERT OR IGNORE INTO ps_updated_rows(row_type, row_id) VALUES(?1, ?2)", // language=SQLite let clear_statement1 = db .prepare_v2( - "INSERT OR IGNORE INTO ps_updated_rows(row_type, row_id) -SELECT row_type, row_id + "INSERT OR IGNORE INTO ps_updated_rows(row_type, row_id, bucket) +SELECT row_type, row_id, ?1 FROM ps_oplog WHERE bucket = ?1", ) diff --git a/crates/core/src/sync_local.rs b/crates/core/src/sync_local.rs index ea031cd..f2abcf0 100644 --- a/crates/core/src/sync_local.rs +++ b/crates/core/src/sync_local.rs @@ -299,10 +299,7 @@ impl<'a> SyncOperation<'a> { .prepare_v2( "\ WITH updated_rows AS ( - SELECT b.row_type, b.row_id FROM ps_buckets AS buckets - CROSS JOIN ps_oplog AS b ON b.bucket = buckets.id - AND (b.op_id > buckets.last_applied_op) - UNION ALL SELECT row_type, row_id FROM ps_updated_rows + SELECT row_type, row_id FROM ps_updated_rows ) SELECT @@ -325,7 +322,7 @@ SELECT .db .prepare_v2( "\ --- 1. Filter oplog by the ops added but not applied yet (oplog b). +-- 1. Filter updated rows by the buckets included in this partial checkpoint. -- We do not do any DISTINCT operation here, since that introduces a temp b-tree. -- We filter out duplicates using the GROUP BY below. WITH @@ -334,10 +331,8 @@ WITH OR name IN (SELECT value FROM json_each(json_extract(?1, '$.buckets'))) ), updated_rows AS ( - SELECT b.row_type, b.row_id FROM ps_buckets AS buckets - CROSS JOIN ps_oplog AS b ON b.bucket = buckets.id - AND (b.op_id > buckets.last_applied_op) - WHERE buckets.id IN (SELECT id FROM involved_buckets) + SELECT row_type, row_id FROM ps_updated_rows + WHERE bucket IN (SELECT id FROM involved_buckets) ) -- 2. Find *all* current ops over different buckets for those objects (oplog r). @@ -406,7 +401,22 @@ SELECT .into_db_result(self.db)?; BucketPriority::SENTINEL } - Some(partial) => partial.priority, + Some(partial) => { + let stmt = self + .db + .prepare_v2( + "DELETE FROM ps_updated_rows + WHERE bucket IN ( + SELECT id FROM ps_buckets + WHERE ?1 IS NULL + OR name IN (SELECT value FROM json_each(json_extract(?1, '$.buckets'))) + )", + ) + .into_db_result(self.db)?; + stmt.bind_text(1, partial.args, Destructor::STATIC)?; + stmt.exec()?; + partial.priority + } } .into(); diff --git a/dart/test/sync_local_performance_test.dart b/dart/test/sync_local_performance_test.dart index ec0f5ba..10a8543 100644 --- a/dart/test/sync_local_performance_test.dart +++ b/dart/test/sync_local_performance_test.dart @@ -82,6 +82,11 @@ SELECT FROM generate_bucket_rows; +INSERT OR IGNORE INTO ps_updated_rows (bucket, row_type, row_id) +SELECT b.bucket, b.row_type, b.row_id FROM ps_buckets AS buckets + CROSS JOIN ps_oplog AS b ON b.bucket = buckets.id + AND (b.op_id > buckets.last_applied_op); + COMMIT; '''); // Enable this to see stats for initial data generation @@ -120,6 +125,71 @@ COMMIT; // The tests below are for comparing different queries, not run as part of the // standard test suite. + test('sync_local new new query', () { + var timer = Stopwatch()..start(); + final q = ''' +-- 1. Filter by the ops added but not applied yet +WITH updated_rows AS ( + SELECT row_type, row_id FROM ps_updated_rows +) + +-- 2. Find *all* current ops over different buckets for those objects (oplog r). +SELECT + b.row_type, + b.row_id, + ( + -- 3. For each unique row, select the data from the latest oplog entry. + -- The max(r.op_id) clause is used to select the latest oplog entry. + -- The iif is to avoid the max(r.op_id) column ending up in the results. + SELECT iif(max(r.op_id), r.data, null) + FROM ps_oplog r + WHERE r.row_type = b.row_type + AND r.row_id = b.row_id + + ) as data + FROM updated_rows b + -- Group for (2) + GROUP BY b.row_type, b.row_id; +'''; + db.select(q); + print('${timer.elapsed.inMilliseconds}ms ${vfs.stats()}'); + }, skip: skip); + + test('sync_local new old query', () { + // Same as "new query", but ignoring the data in ps_updated_rows since it's unfair to that test. + var timer = Stopwatch()..start(); + final q = ''' +-- 1. Filter oplog by the ops added but not applied yet (oplog b). +-- We do not do any DISTINCT operation here, since that introduces a temp b-tree. +-- We filter out duplicates using the GROUP BY below. +WITH updated_rows AS ( + SELECT b.row_type, b.row_id FROM ps_buckets AS buckets + CROSS JOIN ps_oplog AS b ON b.bucket = buckets.id + AND (b.op_id > buckets.last_applied_op) +) + +-- 2. Find *all* current ops over different buckets for those objects (oplog r). +SELECT + b.row_type, + b.row_id, + ( + -- 3. For each unique row, select the data from the latest oplog entry. + -- The max(r.op_id) clause is used to select the latest oplog entry. + -- The iif is to avoid the max(r.op_id) column ending up in the results. + SELECT iif(max(r.op_id), r.data, null) + FROM ps_oplog r + WHERE r.row_type = b.row_type + AND r.row_id = b.row_id + + ) as data + FROM updated_rows b + -- Group for (2) + GROUP BY b.row_type, b.row_id; +'''; + db.select(q); + print('${timer.elapsed.inMilliseconds}ms ${vfs.stats()}'); + }, skip: skip); + test('sync_local new query', () { // This is the query we're using now. // This query only uses a single TEMP B-TREE for the GROUP BY operation, diff --git a/dart/test/utils/fix_035_fixtures.dart b/dart/test/utils/fix_035_fixtures.dart index 5f7b397..a02ff3a 100644 --- a/dart/test/utils/fix_035_fixtures.dart +++ b/dart/test/utils/fix_035_fixtures.dart @@ -25,9 +25,9 @@ const dataMigrated = ''' (1, 1, 'todos', 't1', '', '{}', 100), (1, 2, 'todos', 't2', '', '{}', 20), (2, 3, 'lists', 'l1', '', '{}', 3) -;INSERT INTO ps_updated_rows(row_type, row_id) VALUES - ('lists', 'l3'), - ('todos', 't3') +;INSERT INTO ps_updated_rows(row_type, row_id, bucket) VALUES + ('lists', 'l3', 0), + ('todos', 't3', 0) ;INSERT INTO ps_data__lists(id, data) VALUES ('l1', '{}'), ('l3', '{}') diff --git a/dart/test/utils/migration_fixtures.dart b/dart/test/utils/migration_fixtures.dart index 09d67be..db48fb9 100644 --- a/dart/test/utils/migration_fixtures.dart +++ b/dart/test/utils/migration_fixtures.dart @@ -1,5 +1,5 @@ /// The current database version -const databaseVersion = 12; +const databaseVersion = 13; /// This is the base database state that we expect at various schema versions. /// Generated by loading the specific library version, and exporting the schema. @@ -475,6 +475,69 @@ const expectedState = { ;INSERT INTO ps_migration(id, down_migrations) VALUES(10, '[{"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":"DELETE FROM ps_migration WHERE id >= 10"}]') ;INSERT INTO ps_migration(id, down_migrations) VALUES(11, '[{"sql":"DROP TABLE ps_stream_subscriptions"},{"sql":"DELETE FROM ps_migration WHERE id >= 11"}]') ;INSERT INTO ps_migration(id, down_migrations) VALUES(12, '[{"sql":"ALTER TABLE ps_buckets DROP COLUMN downloaded_size"},{"sql":"DELETE FROM ps_migration WHERE id >= 12"}]') +''', + 13: r''' +;CREATE TABLE ps_buckets( + id INTEGER PRIMARY KEY, + name TEXT NOT NULL, + last_applied_op INTEGER NOT NULL DEFAULT 0, + last_op INTEGER NOT NULL DEFAULT 0, + target_op INTEGER NOT NULL DEFAULT 0, + add_checksum INTEGER NOT NULL DEFAULT 0, + op_checksum INTEGER NOT NULL DEFAULT 0, + pending_delete INTEGER NOT NULL DEFAULT 0 +, count_at_last INTEGER NOT NULL DEFAULT 0, count_since_last INTEGER NOT NULL DEFAULT 0, downloaded_size INTEGER NOT NULL DEFAULT 0) STRICT +;CREATE TABLE ps_crud (id INTEGER PRIMARY KEY AUTOINCREMENT, data TEXT, tx_id INTEGER) +;CREATE TABLE ps_kv(key TEXT PRIMARY KEY NOT NULL, value BLOB) +;CREATE TABLE ps_migration(id INTEGER PRIMARY KEY, down_migrations TEXT) +;CREATE TABLE ps_oplog( + bucket INTEGER NOT NULL, + op_id INTEGER NOT NULL, + row_type TEXT, + row_id TEXT, + key TEXT, + data TEXT, + hash INTEGER NOT NULL) STRICT +;CREATE TABLE ps_stream_subscriptions ( + id INTEGER NOT NULL PRIMARY KEY, + stream_name TEXT NOT NULL, + active INTEGER NOT NULL DEFAULT FALSE, + is_default INTEGER NOT NULL DEFAULT FALSE, + local_priority INTEGER, + local_params TEXT NOT NULL DEFAULT 'null', + ttl INTEGER, + expires_at INTEGER, + last_synced_at INTEGER, + UNIQUE (stream_name, local_params) +) STRICT +;CREATE TABLE ps_sync_state ( + priority INTEGER NOT NULL PRIMARY KEY, + last_synced_at TEXT NOT NULL +) STRICT +;CREATE TABLE ps_tx(id INTEGER PRIMARY KEY NOT NULL, current_tx INTEGER, next_tx INTEGER) +;CREATE TABLE ps_untyped(type TEXT NOT NULL, id TEXT NOT NULL, data TEXT, PRIMARY KEY (type, id)) +;CREATE TABLE ps_updated_rows( + row_type TEXT, + row_id TEXT, + bucket INTEGER NOT NULL, + PRIMARY KEY(bucket, row_type, row_id)) STRICT, WITHOUT ROWID +;CREATE UNIQUE INDEX ps_buckets_name ON ps_buckets (name) +;CREATE INDEX ps_oplog_key ON ps_oplog (bucket, key) +;CREATE INDEX ps_oplog_opid ON ps_oplog (bucket, op_id) +;CREATE INDEX ps_oplog_row ON ps_oplog (row_type, row_id) +;INSERT INTO ps_migration(id, down_migrations) VALUES(1, null) +;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":[]}]') +;INSERT INTO ps_migration(id, down_migrations) VALUES(3, '[{"sql":"DELETE FROM ps_migration WHERE id >= 3"},{"sql":"DROP TABLE ps_kv"}]') +;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"}]') +;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"}]') +;INSERT INTO ps_migration(id, down_migrations) VALUES(6, '[{"sql":"DELETE FROM ps_migration WHERE id >= 6"}]') +;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"}]') +;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"}]') +;INSERT INTO ps_migration(id, down_migrations) VALUES(9, '[{"sql":"ALTER TABLE ps_buckets DROP COLUMN count_at_last"},{"sql":"ALTER TABLE ps_buckets DROP COLUMN count_since_last"},{"sql":"DELETE FROM ps_migration WHERE id >= 9"}]') +;INSERT INTO ps_migration(id, down_migrations) VALUES(10, '[{"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":"DELETE FROM ps_migration WHERE id >= 10"}]') +;INSERT INTO ps_migration(id, down_migrations) VALUES(11, '[{"sql":"DROP TABLE ps_stream_subscriptions"},{"sql":"DELETE FROM ps_migration WHERE id >= 11"}]') +;INSERT INTO ps_migration(id, down_migrations) VALUES(12, '[{"sql":"ALTER TABLE ps_buckets DROP COLUMN downloaded_size"},{"sql":"DELETE FROM ps_migration WHERE id >= 12"}]') +;INSERT INTO ps_migration(id, down_migrations) VALUES(13, '[{"sql":"ALTER TABLE ps_updated_rows RENAME TO ps_updated_rows_13"},{"sql":"CREATE TABLE ps_updated_rows(\n row_type TEXT,\n row_id TEXT,\n PRIMARY KEY(row_type, row_id)) STRICT, WITHOUT ROWID"},{"sql":"INSERT INTO ps_updated_rows(row_type, row_id)\n SELECT row_type, row_id FROM ps_updated_rows_13\n GROUP BY row_type, row_id"},{"sql":"DROP TABLE ps_updated_rows_13"},{"sql":"DELETE FROM ps_migration WHERE id >= 13"}]') ''', }; @@ -599,6 +662,20 @@ const data1 = { (2, 3, 'lists', 'l1', '', '{}', 3) ;INSERT INTO ps_updated_rows(row_type, row_id) VALUES ('lists', 'l2') +''', + 13: r''' +;INSERT INTO ps_buckets(id, name, last_applied_op, last_op, target_op, add_checksum, op_checksum, pending_delete, count_at_last, count_since_last, downloaded_size) VALUES + (1, 'b1', 0, 0, 0, 0, 120, 0, 0, 0, 0), + (2, 'b2', 0, 0, 0, 1005, 3, 0, 0, 0, 0) +;INSERT INTO ps_oplog(bucket, op_id, row_type, row_id, key, data, hash) VALUES + (1, 1, 'todos', 't1', '', '{}', 100), + (1, 2, 'todos', 't2', '', '{}', 20), + (2, 3, 'lists', 'l1', '', '{}', 3) +;INSERT INTO ps_updated_rows(row_type, row_id, bucket) VALUES + ('lists', 'l1', 2), + ('lists', 'l2', 0), + ('todos', 't1', 1), + ('todos', 't2', 1) ''' }; @@ -612,7 +689,10 @@ final dataDown1 = { ('b1', 0, 0, 0, 0, 0), ('b2', 0, 0, 0, 1005, 0) ;INSERT INTO ps_oplog(bucket, op_id, op, row_type, row_id, key, data, hash, superseded) VALUES + ('$local', 1, 4, 'lists', 'l1', null, null, 0, 0), ('$local', 1, 4, 'lists', 'l2', null, null, 0, 0), + ('$local', 1, 4, 'todos', 't1', null, null, 0, 0), + ('$local', 1, 4, 'todos', 't2', null, null, 0, 0), ('b1', 1, 3, 'todos', 't1', '', '{}', 100, 0), ('b1', 2, 3, 'todos', 't2', '', '{}', 20, 0), ('b2', 3, 3, 'lists', 'l1', '', '{}', 3, 0) @@ -623,7 +703,10 @@ final dataDown1 = { ('b1', 0, 0, 0, 0, 0), ('b2', 0, 0, 0, 1005, 0) ;INSERT INTO ps_oplog(bucket, op_id, op, row_type, row_id, key, data, hash, superseded) VALUES + ('$local', 1, 4, 'lists', 'l1', null, null, 0, 0), ('$local', 1, 4, 'lists', 'l2', null, null, 0, 0), + ('$local', 1, 4, 'todos', 't1', null, null, 0, 0), + ('$local', 1, 4, 'todos', 't2', null, null, 0, 0), ('b1', 1, 3, 'todos', 't1', '', '{}', 100, 0), ('b1', 2, 3, 'todos', 't2', '', '{}', 20, 0), ('b2', 3, 3, 'lists', 'l1', '', '{}', 3, 0) @@ -634,18 +717,126 @@ final dataDown1 = { ('b1', 0, 0, 0, 0, 0, 120, 0), ('b2', 0, 0, 0, 1005, 0, 3, 0) ;INSERT INTO ps_oplog(bucket, op_id, op, row_type, row_id, key, data, hash, superseded) VALUES + ('$local', 1, 4, 'lists', 'l1', null, null, 0, 0), ('$local', 1, 4, 'lists', 'l2', null, null, 0, 0), + ('$local', 1, 4, 'todos', 't1', null, null, 0, 0), + ('$local', 1, 4, 'todos', 't2', null, null, 0, 0), ('b1', 1, 3, 'todos', 't1', '', '{}', 100, 0), ('b1', 2, 3, 'todos', 't2', '', '{}', 20, 0), ('b2', 3, 3, 'lists', 'l1', '', '{}', 3, 0) ''', - 5: data1[5]!, - 6: data1[5]!, - 7: data1[5]!, - 8: data1[5]!, - 9: data1[9]!, - 10: data1[9]!, - 11: data1[10]!, + 5: r''' +;INSERT INTO ps_buckets(id, name, last_applied_op, last_op, target_op, add_checksum, op_checksum, pending_delete) VALUES + (1, 'b1', 0, 0, 0, 0, 120, 0), + (2, 'b2', 0, 0, 0, 1005, 3, 0) +;INSERT INTO ps_oplog(bucket, op_id, row_type, row_id, key, data, hash) VALUES + (1, 1, 'todos', 't1', '', '{}', 100), + (1, 2, 'todos', 't2', '', '{}', 20), + (2, 3, 'lists', 'l1', '', '{}', 3) +;INSERT INTO ps_updated_rows(row_type, row_id) VALUES + ('lists', 'l1'), + ('lists', 'l2'), + ('todos', 't1'), + ('todos', 't2') +''', + 6: r''' +;INSERT INTO ps_buckets(id, name, last_applied_op, last_op, target_op, add_checksum, op_checksum, pending_delete) VALUES + (1, 'b1', 0, 0, 0, 0, 120, 0), + (2, 'b2', 0, 0, 0, 1005, 3, 0) +;INSERT INTO ps_oplog(bucket, op_id, row_type, row_id, key, data, hash) VALUES + (1, 1, 'todos', 't1', '', '{}', 100), + (1, 2, 'todos', 't2', '', '{}', 20), + (2, 3, 'lists', 'l1', '', '{}', 3) +;INSERT INTO ps_updated_rows(row_type, row_id) VALUES + ('lists', 'l1'), + ('lists', 'l2'), + ('todos', 't1'), + ('todos', 't2') +''', + 7: r''' +;INSERT INTO ps_buckets(id, name, last_applied_op, last_op, target_op, add_checksum, op_checksum, pending_delete) VALUES + (1, 'b1', 0, 0, 0, 0, 120, 0), + (2, 'b2', 0, 0, 0, 1005, 3, 0) +;INSERT INTO ps_oplog(bucket, op_id, row_type, row_id, key, data, hash) VALUES + (1, 1, 'todos', 't1', '', '{}', 100), + (1, 2, 'todos', 't2', '', '{}', 20), + (2, 3, 'lists', 'l1', '', '{}', 3) +;INSERT INTO ps_updated_rows(row_type, row_id) VALUES + ('lists', 'l1'), + ('lists', 'l2'), + ('todos', 't1'), + ('todos', 't2') +''', + 8: r''' +;INSERT INTO ps_buckets(id, name, last_applied_op, last_op, target_op, add_checksum, op_checksum, pending_delete) VALUES + (1, 'b1', 0, 0, 0, 0, 120, 0), + (2, 'b2', 0, 0, 0, 1005, 3, 0) +;INSERT INTO ps_oplog(bucket, op_id, row_type, row_id, key, data, hash) VALUES + (1, 1, 'todos', 't1', '', '{}', 100), + (1, 2, 'todos', 't2', '', '{}', 20), + (2, 3, 'lists', 'l1', '', '{}', 3) +;INSERT INTO ps_updated_rows(row_type, row_id) VALUES + ('lists', 'l1'), + ('lists', 'l2'), + ('todos', 't1'), + ('todos', 't2') +''', + 9: r''' +;INSERT INTO ps_buckets(id, name, last_applied_op, last_op, target_op, add_checksum, op_checksum, pending_delete, count_at_last, count_since_last) VALUES + (1, 'b1', 0, 0, 0, 0, 120, 0, 0, 0), + (2, 'b2', 0, 0, 0, 1005, 3, 0, 0, 0) +;INSERT INTO ps_oplog(bucket, op_id, row_type, row_id, key, data, hash) VALUES + (1, 1, 'todos', 't1', '', '{}', 100), + (1, 2, 'todos', 't2', '', '{}', 20), + (2, 3, 'lists', 'l1', '', '{}', 3) +;INSERT INTO ps_updated_rows(row_type, row_id) VALUES + ('lists', 'l1'), + ('lists', 'l2'), + ('todos', 't1'), + ('todos', 't2') +''', + 10: r''' +;INSERT INTO ps_buckets(id, name, last_applied_op, last_op, target_op, add_checksum, op_checksum, pending_delete, count_at_last, count_since_last) VALUES + (1, 'b1', 0, 0, 0, 0, 120, 0, 0, 0), + (2, 'b2', 0, 0, 0, 1005, 3, 0, 0, 0) +;INSERT INTO ps_oplog(bucket, op_id, row_type, row_id, key, data, hash) VALUES + (1, 1, 'todos', 't1', '', '{}', 100), + (1, 2, 'todos', 't2', '', '{}', 20), + (2, 3, 'lists', 'l1', '', '{}', 3) +;INSERT INTO ps_updated_rows(row_type, row_id) VALUES + ('lists', 'l1'), + ('lists', 'l2'), + ('todos', 't1'), + ('todos', 't2') +''', + 11: r''' +;INSERT INTO ps_buckets(id, name, last_applied_op, last_op, target_op, add_checksum, op_checksum, pending_delete, count_at_last, count_since_last) VALUES + (1, 'b1', 0, 0, 0, 0, 120, 0, 0, 0), + (2, 'b2', 0, 0, 0, 1005, 3, 0, 0, 0) +;INSERT INTO ps_oplog(bucket, op_id, row_type, row_id, key, data, hash) VALUES + (1, 1, 'todos', 't1', '', '{}', 100), + (1, 2, 'todos', 't2', '', '{}', 20), + (2, 3, 'lists', 'l1', '', '{}', 3) +;INSERT INTO ps_updated_rows(row_type, row_id) VALUES + ('lists', 'l1'), + ('lists', 'l2'), + ('todos', 't1'), + ('todos', 't2') +''', + 12: r''' +;INSERT INTO ps_buckets(id, name, last_applied_op, last_op, target_op, add_checksum, op_checksum, pending_delete, count_at_last, count_since_last, downloaded_size) VALUES + (1, 'b1', 0, 0, 0, 0, 120, 0, 0, 0, 0), + (2, 'b2', 0, 0, 0, 1005, 3, 0, 0, 0, 0) +;INSERT INTO ps_oplog(bucket, op_id, row_type, row_id, key, data, hash) VALUES + (1, 1, 'todos', 't1', '', '{}', 100), + (1, 2, 'todos', 't2', '', '{}', 20), + (2, 3, 'lists', 'l1', '', '{}', 3) +;INSERT INTO ps_updated_rows(row_type, row_id) VALUES + ('lists', 'l1'), + ('lists', 'l2'), + ('todos', 't1'), + ('todos', 't2') +''', }; final finalData1 = data1[databaseVersion]!;