Skip to content

Commit fdca32e

Browse files
committed
Verify schema invalidation
1 parent 30a29b6 commit fdca32e

File tree

2 files changed

+85
-17
lines changed

2 files changed

+85
-17
lines changed

crates/core/src/schema/raw_table.rs

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -125,29 +125,24 @@ impl InferredSchemaCache {
125125
schema_version: usize,
126126
tbl: &RawTable,
127127
) -> Result<Rc<PendingStatement>, PowerSyncError> {
128-
let mut entries = self.entries.borrow_mut();
129-
let mut entry = entries.entry(tbl.name.clone());
130-
let entry = match entry {
131-
Entry::Vacant(entry) => entry.insert(SchemaCacheEntry::infer(db, schema_version, tbl)?),
132-
Entry::Occupied(ref mut entry) => {
133-
let value = entry.get_mut();
134-
if value.schema_version != schema_version {
135-
// Values are outdated, refresh.
136-
*value = SchemaCacheEntry::infer(db, schema_version, tbl)?;
137-
}
138-
139-
value
140-
}
141-
};
142-
143-
Ok(entry.put())
128+
self.with_entry(db, schema_version, tbl, SchemaCacheEntry::put)
144129
}
145130

146131
pub fn infer_delete_statement(
147132
&self,
148133
db: *mut sqlite::sqlite3,
149134
schema_version: usize,
150135
tbl: &RawTable,
136+
) -> Result<Rc<PendingStatement>, PowerSyncError> {
137+
self.with_entry(db, schema_version, tbl, SchemaCacheEntry::delete)
138+
}
139+
140+
fn with_entry(
141+
&self,
142+
db: *mut sqlite::sqlite3,
143+
schema_version: usize,
144+
tbl: &RawTable,
145+
f: fn(&mut SchemaCacheEntry) -> Rc<PendingStatement>,
151146
) -> Result<Rc<PendingStatement>, PowerSyncError> {
152147
let mut entries = self.entries.borrow_mut();
153148
let mut entry = entries.entry(tbl.name.clone());
@@ -164,7 +159,7 @@ impl InferredSchemaCache {
164159
}
165160
};
166161

167-
Ok(entry.delete())
162+
Ok(f(entry))
168163
}
169164
}
170165

dart/test/sync_test.dart

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1171,6 +1171,79 @@ CREATE TRIGGER users_delete
11711171
});
11721172

11731173
syncTest('inferred schema smoke test', (_) {
1174+
db.execute(
1175+
'CREATE TABLE local_users (id TEXT NOT NULL PRIMARY KEY, name TEXT NOT NULL, local TEXT) STRICT;');
1176+
final table = {
1177+
'name': 'users',
1178+
'table_name': 'local_users',
1179+
'local_only_columns': ['local'],
1180+
// This also tests that the trigger preventing updates and deletes on
1181+
// insert-only tables is inert during sync_local.
1182+
'insert_only': true,
1183+
};
1184+
1185+
invokeControl(
1186+
'start',
1187+
json.encode({
1188+
'schema': {
1189+
'raw_tables': [table],
1190+
'tables': [],
1191+
}
1192+
}));
1193+
1194+
// Insert
1195+
pushCheckpoint(buckets: [bucketDescription('a')]);
1196+
pushSyncData(
1197+
'a',
1198+
'1',
1199+
'my_user',
1200+
'PUT',
1201+
{
1202+
'name': 'First user',
1203+
'local': 'ignored because the column is local-only'
1204+
},
1205+
objectType: 'users',
1206+
);
1207+
pushCheckpointComplete();
1208+
1209+
var users = db.select('SELECT * FROM local_users;');
1210+
expect(users, [
1211+
{
1212+
'id': 'my_user',
1213+
'name': 'First user',
1214+
'local': null,
1215+
}
1216+
]);
1217+
1218+
// Now, alter the underlying table to add a new column
1219+
db.execute('ALTER TABLE local_users ADD COLUMN email TEXT');
1220+
pushCheckpoint(buckets: [bucketDescription('a')]);
1221+
pushSyncData(
1222+
'a',
1223+
'2',
1224+
'my_user',
1225+
'PUT',
1226+
{
1227+
'name': 'First user',
1228+
'email': 'email@example.org',
1229+
'local': 'still ignored'
1230+
},
1231+
objectType: 'users',
1232+
);
1233+
pushCheckpointComplete();
1234+
1235+
users = db.select('SELECT * FROM local_users;');
1236+
expect(users, [
1237+
{
1238+
'id': 'my_user',
1239+
'name': 'First user',
1240+
'email': 'email@example.org',
1241+
'local': null,
1242+
}
1243+
]);
1244+
});
1245+
1246+
test('inferred schema with changes', () {
11741247
db.execute(
11751248
'CREATE TABLE local_users (id TEXT NOT NULL PRIMARY KEY, name TEXT NOT NULL) STRICT;');
11761249
final table = {

0 commit comments

Comments
 (0)