@@ -1021,35 +1021,65 @@ END;
10211021 });
10221022
10231023 group ('raw tables' , () {
1024- syncTest ('smoke test' , (_) {
1025- db.execute (
1026- 'CREATE TABLE users (id TEXT NOT NULL PRIMARY KEY, name TEXT NOT NULL) STRICT;' );
1027-
1028- invokeControl (
1029- 'start' ,
1030- json.encode ({
1031- 'schema' : {
1032- 'raw_tables' : [
1033- {
1034- 'name' : 'users' ,
1035- 'put' : {
1036- 'sql' :
1037- 'INSERT OR REPLACE INTO users (id, name) VALUES (?, ?);' ,
1038- 'params' : [
1039- 'Id' ,
1040- {'Column' : 'name' }
1041- ],
1042- },
1043- 'delete' : {
1044- 'sql' : 'DELETE FROM users WHERE id = ?' ,
1045- 'params' : ['Id' ],
1046- },
1047- }
1024+ const schema = {
1025+ 'raw_tables' : [
1026+ {
1027+ 'name' : 'users' ,
1028+ 'put' : {
1029+ 'sql' : 'INSERT OR REPLACE INTO users (id, name) VALUES (?, ?);' ,
1030+ 'params' : [
1031+ 'Id' ,
1032+ {'Column' : 'name' }
10481033 ],
1049- 'tables' : [],
10501034 },
1051- }),
1052- );
1035+ 'delete' : {
1036+ 'sql' : 'DELETE FROM users WHERE id = ?' ,
1037+ 'params' : ['Id' ],
1038+ },
1039+ }
1040+ ],
1041+ 'tables' : [],
1042+ };
1043+
1044+ void setupRawTables () {
1045+ db.execute ('''
1046+ CREATE TABLE users (id TEXT NOT NULL PRIMARY KEY, name TEXT NOT NULL) STRICT;
1047+
1048+ CREATE TRIGGER users_insert
1049+ AFTER INSERT ON users
1050+ FOR EACH ROW
1051+ BEGIN
1052+ INSERT INTO powersync_crud (op, id, type, data) VALUES ('PUT', NEW.id, 'users', json_object(
1053+ 'name', NEW.name
1054+ ));
1055+ END;
1056+
1057+ CREATE TRIGGER users_update
1058+ AFTER UPDATE ON users
1059+ FOR EACH ROW
1060+ BEGIN
1061+ SELECT CASE
1062+ WHEN (OLD.id != NEW.id)
1063+ THEN RAISE (FAIL, 'Cannot update id')
1064+ END;
1065+
1066+ INSERT INTO powersync_crud (op, id, type, data) VALUES ('PATCH', NEW.id, 'users', json_object(
1067+ 'name', NEW.name
1068+ ));
1069+ END;
1070+
1071+ CREATE TRIGGER users_delete
1072+ AFTER DELETE ON users
1073+ FOR EACH ROW
1074+ BEGIN
1075+ INSERT INTO powersync_crud (op, id, type) VALUES ('DELETE', OLD.id, 'users');
1076+ END;
1077+ ''' );
1078+ }
1079+
1080+ syncTest ('smoke test' , (_) {
1081+ setupRawTables ();
1082+ invokeControl ('start' , json.encode ({'schema' : schema}));
10531083
10541084 // Insert
10551085 pushCheckpoint (buckets: [bucketDescription ('a' )]);
@@ -1083,34 +1113,71 @@ END;
10831113 expect (db.select ('SELECT * FROM users' ), isEmpty);
10841114 });
10851115
1086- test ("crud vtab is no-op during sync" , () {
1087- db. execute (
1088- 'CREATE TABLE users (id TEXT NOT NULL PRIMARY KEY, name TEXT NOT NULL) STRICT;' );
1116+ test ('reports errors from underlying statements' , () {
1117+ setupRawTables ();
1118+ invokeControl ( 'start' , json. encode ({ 'schema' : schema}) );
10891119
1090- invokeControl (
1091- 'start' ,
1092- json.encode ({
1093- 'schema' : {
1094- 'raw_tables' : [
1095- {
1096- 'name' : 'users' ,
1097- 'put' : {
1098- 'sql' : "INSERT INTO powersync_crud_(data) VALUES (?);" ,
1099- 'params' : [
1100- {'Column' : 'name' }
1101- ],
1102- },
1103- 'delete' : {
1104- 'sql' : 'DELETE FROM users WHERE id = ?' ,
1105- 'params' : ['Id' ],
1106- },
1107- }
1108- ],
1109- 'tables' : [],
1110- },
1111- }),
1120+ pushCheckpoint (buckets: [bucketDescription ('a' )]);
1121+ pushSyncData (
1122+ 'a' ,
1123+ '1' ,
1124+ 'my_user' ,
1125+ 'PUT' ,
1126+ {},
1127+ objectType: 'users' ,
11121128 );
11131129
1130+ expect (
1131+ pushCheckpointComplete,
1132+ throwsA (
1133+ isSqliteException (
1134+ 1299 ,
1135+ 'powersync_control: replacing into users, id = my_user, data = {}: '
1136+ 'internal SQLite call returned CONSTRAINT_NOTNULL: '
1137+ 'NOT NULL constraint failed: users.name' ,
1138+ ),
1139+ ),
1140+ );
1141+ });
1142+
1143+ test ('crud vtab' , () {
1144+ // This is mostly a test for the triggers, validating the suggestions we
1145+ // give on https://docs.powersync.com/usage/use-case-examples/raw-tables#capture-local-writes-with-triggers
1146+ setupRawTables ();
1147+
1148+ db.execute ('''
1149+ BEGIN;
1150+ INSERT INTO users (id, name) VALUES ('test-id', 'test user');
1151+ UPDATE users SET name = name || '2';
1152+ DELETE FROM users;
1153+ END;
1154+ ''' );
1155+
1156+ expect (db.select ('SELECT * FROM ps_crud' ), [
1157+ {
1158+ 'id' : 1 ,
1159+ 'data' :
1160+ '{"op":"PUT","id":"test-id","type":"users","data":{"name":"test user"}}' ,
1161+ 'tx_id' : 1
1162+ },
1163+ {
1164+ 'id' : 2 ,
1165+ 'data' :
1166+ '{"op":"PATCH","id":"test-id","type":"users","data":{"name":"test user2"}}' ,
1167+ 'tx_id' : 1
1168+ },
1169+ {
1170+ 'id' : 3 ,
1171+ 'data' : '{"op":"DELETE","id":"test-id","type":"users"}' ,
1172+ 'tx_id' : 1
1173+ },
1174+ ]);
1175+ });
1176+
1177+ test ("crud vtab is no-op during sync" , () {
1178+ setupRawTables ();
1179+ invokeControl ('start' , json.encode ({'schema' : schema}));
1180+
11141181 // Insert
11151182 pushCheckpoint (buckets: [bucketDescription ('a' )]);
11161183 pushSyncData (
0 commit comments