From 7b4b8d4defc7fa3676a8f811e11c3ba10a4b2103 Mon Sep 17 00:00:00 2001 From: Stefanos Mousafeiris Date: Thu, 13 Jun 2024 16:43:28 +0300 Subject: [PATCH] feat(backend): Remove `WITHOUT ROWID` from SQLite migrations (#1349) ### Motivation Issue that prompted this was unusually slow inserts when loading large amounts of data into SQLite (using wa-sqlite and IndexedDB). ### Investigation After some investigation, we found that the `WITHOUT ROWID` table specification we add to all SQLite tables makes SQLite store data as a B-Tree rather than a B*-Tree, which causes significant slowdowns for large rows (significant w.r.t to the page size), and also causes the incremental blob I/O mechanism to not work. See https://www.sqlite.org/withoutrowid.html With disabled FKs downstream, simply moving from `WITHOUT ROWID` to ordinary tables with rowids the initial sync in Linearlite for 5k issues (and 25k comments) was reduced from 30 sec to 6-7sec This explanation also matches my observations that cutting down the bodies of the comments/issues to a few characters seemed to significantly speed everything up, as it would make the rows smaller and easily fit within pages and thus the inefficiency of accessing long blobs that comes with regular B-trees doesn't come up I've further confirmed that it's unrelated to WASM boundaries etc by creating a temporary table, inserting data there, and then copying it to the actual table with `INSERT ... SELECT ...` so the data transfer is all done within WASM and SQLite and it's still slow - which makes sense with the above. I've also removed all triggers to ensure that it's not a non-disabled trigger that's causing the slowdown. Additionally, in the Linearlite experiments, moving to having rowids results in a smaller storage footprint despite having to store an additional column of rowids and an index (21mb vs 26mb), and looking at how wa-sqlite stores stuff in IndexedDB, since each entry is a 4kb page, when using `WITHOUT ROWID` a lot of pages are mostly empty (since blobs are not stored sequentially as they are in B*-trees) so it ends up with ~6k pages whereas with rowids it ends up with ~4k pages and sampling the pages I don't seem to find empty blocks of data. ### Requirements If using ordinary tables in SQLite, there are 3 things to consider: 1. It is not necessary to specify a primary key 2. Primary keys are not also checked for being `NOT NULL` by default 3. The oplog needs to ignore the added `rowid` column from using ordinary tables and replication should work seamlessly For (1), the migration proxy will reject any schema that does not specify a primary key as electrification requires it, so even if technically an SQLite schema without a primary key is valid it will not be accepted by the migrations proxy. For (2), the SQLite migrations are generated by translating PG schemas, and that translation will always enforce that primary keys are also `NOT NULL`, so the resulting SQLite migration will always have both a `PRIMARY KEY` constraint along with a `NOT NULL` constraint. For (3), the oplog triggers only capture the actual columns of the specified table and do not include the `rowid`, so the replication is unaffected by this change, at least from what I could tell and test. ### Consequences This update means that any new SQLite migrations generated will not have different table definitions (without `WITHOUT ROWID` in them), but that isn't too much of an issue. I've checked that replication works fine between clients using `WITHOUT ROWID` in their tables and ones without, and clients are ephemeral either way so I wouldn't mark this as a breaking change. That being said, for users to see the performance benefits of this change they _will_ need to regenerate their migrations/clients. ### Notes For the full performance benefit measured, the foreign key checks also need to be disabled when applying transactions in the client, which currently can be done with an optional config key but is not enabled by default. I think we need to consider enabling it by default before releasing a patch. --- .changeset/khaki-needles-dream.md | 5 + .../test/client/notifications.test.ts | 2 +- clients/typescript/test/migrators/builder.ts | 18 +-- .../20230613112725_814/migration.sql | 2 +- .../20230613112735_992/migration.sql | 2 +- .../typescript/test/satellite/client.test.ts | 4 +- .../migration.sql | 6 +- .../satellite.sql | 6 +- .../test/support/migrations/manifest.json | 6 +- .../test/support/migrations/migrations.js | 10 +- .../lib/electric/postgres/dialect/sqlite.ex | 2 +- .../electric/test/electric/plug_test.exs | 14 +- .../electric/postgres/dialect/sqlite_test.exs | 24 +-- .../electric/postgres/replication_test.exs | 6 +- .../src/generated/client/migrations.ts | 146 +++++++++--------- 15 files changed, 125 insertions(+), 128 deletions(-) create mode 100644 .changeset/khaki-needles-dream.md diff --git a/.changeset/khaki-needles-dream.md b/.changeset/khaki-needles-dream.md new file mode 100644 index 00000000..48be6380 --- /dev/null +++ b/.changeset/khaki-needles-dream.md @@ -0,0 +1,5 @@ +--- +"@core/electric": patch +--- + +Remove `WITHOUT ROWID` specification on SQLite migrations for improved performance. diff --git a/clients/typescript/test/client/notifications.test.ts b/clients/typescript/test/client/notifications.test.ts index 0286ce6d..c08e3045 100644 --- a/clients/typescript/test/client/notifications.test.ts +++ b/clients/typescript/test/client/notifications.test.ts @@ -33,7 +33,7 @@ async function runAndCheckNotifications(f: () => Promise) { async function cleanDB() { await adapter.run({ sql: 'DROP TABLE IF EXISTS Items' }) await adapter.run({ - sql: 'CREATE TABLE IF NOT EXISTS Items (value TEXT PRIMARY KEY NOT NULL, nbr INTEGER) WITHOUT ROWID;', + sql: 'CREATE TABLE IF NOT EXISTS Items (value TEXT PRIMARY KEY NOT NULL, nbr INTEGER);', }) } diff --git a/clients/typescript/test/migrators/builder.ts b/clients/typescript/test/migrators/builder.ts index 80e601d8..fd86bd55 100644 --- a/clients/typescript/test/migrators/builder.ts +++ b/clients/typescript/test/migrators/builder.ts @@ -31,11 +31,7 @@ export const makeMigrationMetaData = (builder: QueryBuilder) => { stmts: [ SatOpMigrate_Stmt.fromPartial({ type: SatOpMigrate_Type.CREATE_TABLE, - sql: `CREATE TABLE "${ - builder.defaultNamespace - }"."stars" (\n "id" TEXT NOT NULL PRIMARY KEY,\n "avatar_url" TEXT NOT NULL,\n "name" TEXT,\n "starred_at" TEXT NOT NULL,\n "username" TEXT NOT NULL\n)${builder.sqliteOnly( - ' WITHOUT ROWID' - )};\n`, + sql: `CREATE TABLE "${builder.defaultNamespace}"."stars" (\n "id" TEXT NOT NULL PRIMARY KEY,\n "avatar_url" TEXT NOT NULL,\n "name" TEXT,\n "starred_at" TEXT NOT NULL,\n "username" TEXT NOT NULL\n);\n`, }), ], table: SatOpMigrate_Table.fromPartial({ @@ -118,11 +114,7 @@ export const builderTests = (test: TestFn) => { t.is(migration.version, migrationMetaData.version) t.is( migration.statements[0], - `CREATE TABLE "${ - builder.defaultNamespace - }"."stars" (\n "id" TEXT NOT NULL PRIMARY KEY,\n "avatar_url" TEXT NOT NULL,\n "name" TEXT,\n "starred_at" TEXT NOT NULL,\n "username" TEXT NOT NULL\n)${builder.sqliteOnly( - ' WITHOUT ROWID' - )};\n` + `CREATE TABLE "${builder.defaultNamespace}"."stars" (\n "id" TEXT NOT NULL PRIMARY KEY,\n "avatar_url" TEXT NOT NULL,\n "name" TEXT,\n "starred_at" TEXT NOT NULL,\n "username" TEXT NOT NULL\n);\n` ) if (builder.dialect === 'SQLite') { @@ -176,7 +168,7 @@ export const builderTests = (test: TestFn) => { stmts: [ SatOpMigrate_Stmt.fromPartial({ type: 0, - sql: `CREATE TABLE "${builder.defaultNamespace}"."tenants" (\n "id" TEXT NOT NULL,\n "name" TEXT NOT NULL,\n CONSTRAINT "tenants_pkey" PRIMARY KEY ("id")\n) WITHOUT ROWID;\n`, + sql: `CREATE TABLE "${builder.defaultNamespace}"."tenants" (\n "id" TEXT NOT NULL,\n "name" TEXT NOT NULL,\n CONSTRAINT "tenants_pkey" PRIMARY KEY ("id")\n);\n`, }), ], table: SatOpMigrate_Table.fromPartial({ @@ -214,7 +206,7 @@ export const builderTests = (test: TestFn) => { stmts: [ SatOpMigrate_Stmt.fromPartial({ type: 0, - sql: `CREATE TABLE "${builder.defaultNamespace}"."users" (\n "id" TEXT NOT NULL,\n "name" TEXT NOT NULL,\n "email" TEXT NOT NULL,\n "password_hash" TEXT NOT NULL,\n CONSTRAINT "users_pkey" PRIMARY KEY ("id")\n) WITHOUT ROWID;\n`, + sql: `CREATE TABLE "${builder.defaultNamespace}"."users" (\n "id" TEXT NOT NULL,\n "name" TEXT NOT NULL,\n "email" TEXT NOT NULL,\n "password_hash" TEXT NOT NULL,\n CONSTRAINT "users_pkey" PRIMARY KEY ("id")\n);\n`, }), ], table: SatOpMigrate_Table.fromPartial({ @@ -268,7 +260,7 @@ export const builderTests = (test: TestFn) => { stmts: [ SatOpMigrate_Stmt.fromPartial({ type: 0, - sql: `CREATE TABLE "${builder.defaultNamespace}"."tenant_users" (\n "tenant_id" TEXT NOT NULL,\n "user_id" TEXT NOT NULL,\n CONSTRAINT "tenant_users_tenant_id_fkey" FOREIGN KEY ("tenant_id") REFERENCES "tenants" ("id") ON DELETE CASCADE,\n CONSTRAINT "tenant_users_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE,\n CONSTRAINT "tenant_users_pkey" PRIMARY KEY ("tenant_id", "user_id")\n) WITHOUT ROWID;\n`, + sql: `CREATE TABLE "${builder.defaultNamespace}"."tenant_users" (\n "tenant_id" TEXT NOT NULL,\n "user_id" TEXT NOT NULL,\n CONSTRAINT "tenant_users_tenant_id_fkey" FOREIGN KEY ("tenant_id") REFERENCES "tenants" ("id") ON DELETE CASCADE,\n CONSTRAINT "tenant_users_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE,\n CONSTRAINT "tenant_users_pkey" PRIMARY KEY ("tenant_id", "user_id")\n);\n`, }), ], table: SatOpMigrate_Table.fromPartial({ diff --git a/clients/typescript/test/migrators/support/migrations/20230613112725_814/migration.sql b/clients/typescript/test/migrators/support/migrations/20230613112725_814/migration.sql index 1f31a60b..2ada10d2 100644 --- a/clients/typescript/test/migrators/support/migrations/20230613112725_814/migration.sql +++ b/clients/typescript/test/migrators/support/migrations/20230613112725_814/migration.sql @@ -5,4 +5,4 @@ CREATE TABLE "stars" ( "starred_at" TEXT NOT NULL, "username" TEXT NOT NULL, CONSTRAINT "stars_pkey" PRIMARY KEY ("id") -) WITHOUT ROWID; +); diff --git a/clients/typescript/test/migrators/support/migrations/20230613112735_992/migration.sql b/clients/typescript/test/migrators/support/migrations/20230613112735_992/migration.sql index b3504478..b6159cbd 100644 --- a/clients/typescript/test/migrators/support/migrations/20230613112735_992/migration.sql +++ b/clients/typescript/test/migrators/support/migrations/20230613112735_992/migration.sql @@ -3,4 +3,4 @@ CREATE TABLE "beers" ( "star_id" TEXT, CONSTRAINT "beers_star_id_fkey" FOREIGN KEY ("star_id") REFERENCES "stars" ("id"), CONSTRAINT "beers_pkey" PRIMARY KEY ("id") -) WITHOUT ROWID; +); diff --git a/clients/typescript/test/satellite/client.test.ts b/clients/typescript/test/satellite/client.test.ts index b28f4861..953b56b2 100644 --- a/clients/typescript/test/satellite/client.test.ts +++ b/clients/typescript/test/satellite/client.test.ts @@ -438,7 +438,7 @@ test.serial('migration transaction contains all information', async (t) => { stmts: [ Proto.SatOpMigrate_Stmt.create({ type: Proto.SatOpMigrate_Type.CREATE_TABLE, - sql: 'CREATE TABLE "foo" (\n "value" TEXT NOT NULL,\n CONSTRAINT "foo_pkey" PRIMARY KEY ("value")\n) WITHOUT ROWID;\n', + sql: 'CREATE TABLE "foo" (\n "value" TEXT NOT NULL,\n CONSTRAINT "foo_pkey" PRIMARY KEY ("value")\n);\n', }), ], table: Proto.SatOpMigrate_Table.create({ @@ -485,7 +485,7 @@ test.serial('migration transaction contains all information', async (t) => { { migrationType: Proto.SatOpMigrate_Type.CREATE_TABLE, table: migrate.table, - sql: 'CREATE TABLE "foo" (\n "value" TEXT NOT NULL,\n CONSTRAINT "foo_pkey" PRIMARY KEY ("value")\n) WITHOUT ROWID;\n', + sql: 'CREATE TABLE "foo" (\n "value" TEXT NOT NULL,\n CONSTRAINT "foo_pkey" PRIMARY KEY ("value")\n);\n', }, ], origin: begin.origin, diff --git a/clients/typescript/test/support/migrations/20230123_170646_833_test_schema/migration.sql b/clients/typescript/test/support/migrations/20230123_170646_833_test_schema/migration.sql index bec802b7..a2864f78 100644 --- a/clients/typescript/test/support/migrations/20230123_170646_833_test_schema/migration.sql +++ b/clients/typescript/test/support/migrations/20230123_170646_833_test_schema/migration.sql @@ -10,16 +10,16 @@ Write your SQLite migration below. */ CREATE TABLE IF NOT EXISTS items ( value TEXT PRIMARY KEY NOT NULL -) WITHOUT ROWID; +); CREATE TABLE IF NOT EXISTS parent ( id INTEGER PRIMARY KEY NOT NULL, value TEXT, other INTEGER DEFAULT 0 -) WITHOUT ROWID; +); CREATE TABLE IF NOT EXISTS child ( id INTEGER PRIMARY KEY NOT NULL, parent INTEGER NOT NULL, FOREIGN KEY(parent) REFERENCES parent(id) -) WITHOUT ROWID; +); diff --git a/clients/typescript/test/support/migrations/20230123_170646_833_test_schema/satellite.sql b/clients/typescript/test/support/migrations/20230123_170646_833_test_schema/satellite.sql index 3f5218b4..85043383 100644 --- a/clients/typescript/test/support/migrations/20230123_170646_833_test_schema/satellite.sql +++ b/clients/typescript/test/support/migrations/20230123_170646_833_test_schema/satellite.sql @@ -1,18 +1,18 @@ CREATE TABLE IF NOT EXISTS items ( value TEXT PRIMARY KEY NOT NULL -) WITHOUT ROWID; +); CREATE TABLE IF NOT EXISTS parent ( id INTEGER PRIMARY KEY NOT NULL, value TEXT, other INTEGER DEFAULT 0 -) WITHOUT ROWID; +); CREATE TABLE IF NOT EXISTS child ( id INTEGER PRIMARY KEY NOT NULL, parent INTEGER NOT NULL, FOREIGN KEY(parent) REFERENCES parent(id) -) WITHOUT ROWID; +); /*--------------------------------------------- Below are templated triggers added by Satellite diff --git a/clients/typescript/test/support/migrations/manifest.json b/clients/typescript/test/support/migrations/manifest.json index aac266f1..7c4ab9ae 100644 --- a/clients/typescript/test/support/migrations/manifest.json +++ b/clients/typescript/test/support/migrations/manifest.json @@ -17,9 +17,9 @@ "name": "20230123_170646_833_test_schema", "postgres_body": "\nCREATE TABLE public.parent (\n id bigint PRIMARY KEY,\n value text,\n other bigint DEFAULT 0);\nALTER TABLE public.parent REPLICA IDENTITY FULL;\n\nCREATE TABLE public.items (\n value text PRIMARY KEY);\nALTER TABLE public.items REPLICA IDENTITY FULL;\n\nCREATE TABLE public.child (\n id bigint PRIMARY KEY,\n parent bigint NOT NULL,\n FOREIGN KEY(parent) REFERENCES parent(id) MATCH SIMPLE);\nALTER TABLE public.child REPLICA IDENTITY FULL;\n", "satellite_body": [ - "CREATE TABLE IF NOT EXISTS items (\n value TEXT PRIMARY KEY NOT NULL\n) WITHOUT ROWID;", - "CREATE TABLE IF NOT EXISTS parent (\n id INTEGER PRIMARY KEY NOT NULL,\n value TEXT,\n other INTEGER DEFAULT 0\n) WITHOUT ROWID;", - "CREATE TABLE IF NOT EXISTS child (\n id INTEGER PRIMARY KEY NOT NULL,\n parent INTEGER NOT NULL,\n FOREIGN KEY(parent) REFERENCES parent(id)\n) WITHOUT ROWID;", + "CREATE TABLE IF NOT EXISTS items (\n value TEXT PRIMARY KEY NOT NULL\n);", + "CREATE TABLE IF NOT EXISTS parent (\n id INTEGER PRIMARY KEY NOT NULL,\n value TEXT,\n other INTEGER DEFAULT 0\n);", + "CREATE TABLE IF NOT EXISTS child (\n id INTEGER PRIMARY KEY NOT NULL,\n parent INTEGER NOT NULL,\n FOREIGN KEY(parent) REFERENCES parent(id)\n);", "DROP TABLE IF EXISTS _electric_trigger_settings;", "CREATE TABLE _electric_trigger_settings(tablename TEXT PRIMARY KEY, flag INTEGER);", "INSERT INTO _electric_trigger_settings(tablename,flag) VALUES ('main.child', 1);", diff --git a/clients/typescript/test/support/migrations/migrations.js b/clients/typescript/test/support/migrations/migrations.js index 85736ce4..ea3d1f49 100644 --- a/clients/typescript/test/support/migrations/migrations.js +++ b/clients/typescript/test/support/migrations/migrations.js @@ -16,11 +16,11 @@ export default [ }, { statements: [ - 'CREATE TABLE IF NOT EXISTS items (\n value TEXT PRIMARY KEY NOT NULL\n) WITHOUT ROWID;', - 'CREATE TABLE IF NOT EXISTS bigIntTable (\n value INT8 PRIMARY KEY NOT NULL\n) WITHOUT ROWID;', - 'CREATE TABLE IF NOT EXISTS blobTable (\n value BLOB PRIMARY KEY NOT NULL\n) WITHOUT ROWID;', - 'CREATE TABLE IF NOT EXISTS parent (\n id INTEGER PRIMARY KEY NOT NULL,\n value TEXT,\n other INTEGER DEFAULT 0\n) WITHOUT ROWID;', - 'CREATE TABLE IF NOT EXISTS child (\n id INTEGER PRIMARY KEY NOT NULL,\n parent INTEGER NOT NULL,\n FOREIGN KEY(parent) REFERENCES parent(id)\n) WITHOUT ROWID;', + 'CREATE TABLE IF NOT EXISTS items (\n value TEXT PRIMARY KEY NOT NULL\n);', + 'CREATE TABLE IF NOT EXISTS bigIntTable (\n value INT8 PRIMARY KEY NOT NULL\n);', + 'CREATE TABLE IF NOT EXISTS blobTable (\n value BLOB PRIMARY KEY NOT NULL\n);', + 'CREATE TABLE IF NOT EXISTS parent (\n id INTEGER PRIMARY KEY NOT NULL,\n value TEXT,\n other INTEGER DEFAULT 0\n);', + 'CREATE TABLE IF NOT EXISTS child (\n id INTEGER PRIMARY KEY NOT NULL,\n parent INTEGER NOT NULL,\n FOREIGN KEY(parent) REFERENCES parent(id)\n);', 'DROP TABLE IF EXISTS _electric_trigger_settings;', 'CREATE TABLE _electric_trigger_settings(namespace TEXT, tablename TEXT, flag INTEGER, PRIMARY KEY (namespace, tablename));', "INSERT INTO _electric_trigger_settings(namespace,tablename,flag) VALUES ('main', 'child', 1);", diff --git a/components/electric/lib/electric/postgres/dialect/sqlite.ex b/components/electric/lib/electric/postgres/dialect/sqlite.ex index 7541a7d9..da11baca 100644 --- a/components/electric/lib/electric/postgres/dialect/sqlite.ex +++ b/components/electric/lib/electric/postgres/dialect/sqlite.ex @@ -77,7 +77,7 @@ defmodule Electric.Postgres.Dialect.SQLite do "(" ]), stmt(defn, join, pretty), - ") WITHOUT ROWID;", + ");", "" ], if(pretty, do: "\n", else: "") diff --git a/components/electric/test/electric/plug_test.exs b/components/electric/test/electric/plug_test.exs index 58a4d747..023ad453 100644 --- a/components/electric/test/electric/plug_test.exs +++ b/components/electric/test/electric/plug_test.exs @@ -71,16 +71,16 @@ defmodule Electric.PlugTest do assert [ {~c"0001/migration.sql", - "CREATE TABLE \"a\" (\n \"id\" TEXT NOT NULL,\n \"value\" TEXT NOT NULL,\n CONSTRAINT \"a_pkey\" PRIMARY KEY (\"id\")\n) WITHOUT ROWID;\n\nCREATE INDEX \"a_idx\" ON \"a\" (\"value\" ASC);\n\nCREATE TABLE \"b\" (\n \"id\" TEXT NOT NULL,\n \"value\" TEXT NOT NULL,\n CONSTRAINT \"b_pkey\" PRIMARY KEY (\"id\")\n) WITHOUT ROWID;"}, + "CREATE TABLE \"a\" (\n \"id\" TEXT NOT NULL,\n \"value\" TEXT NOT NULL,\n CONSTRAINT \"a_pkey\" PRIMARY KEY (\"id\")\n);\n\nCREATE INDEX \"a_idx\" ON \"a\" (\"value\" ASC);\n\nCREATE TABLE \"b\" (\n \"id\" TEXT NOT NULL,\n \"value\" TEXT NOT NULL,\n CONSTRAINT \"b_pkey\" PRIMARY KEY (\"id\")\n);"}, {~c"0001/metadata.json", metadata_json_0001}, {~c"0002/migration.sql", - "CREATE TABLE \"c\" (\n \"id\" TEXT NOT NULL,\n \"value\" TEXT NOT NULL,\n CONSTRAINT \"c_pkey\" PRIMARY KEY (\"id\")\n) WITHOUT ROWID;"}, + "CREATE TABLE \"c\" (\n \"id\" TEXT NOT NULL,\n \"value\" TEXT NOT NULL,\n CONSTRAINT \"c_pkey\" PRIMARY KEY (\"id\")\n);"}, {~c"0002/metadata.json", metadata_json_0002}, {~c"0003/migration.sql", - "CREATE TABLE \"d\" (\n \"id\" TEXT NOT NULL,\n \"value\" TEXT NOT NULL,\n CONSTRAINT \"d_pkey\" PRIMARY KEY (\"id\")\n) WITHOUT ROWID;\n\nALTER TABLE \"d\" ADD COLUMN \"is_valid\" INTEGER;"}, + "CREATE TABLE \"d\" (\n \"id\" TEXT NOT NULL,\n \"value\" TEXT NOT NULL,\n CONSTRAINT \"d_pkey\" PRIMARY KEY (\"id\")\n);\n\nALTER TABLE \"d\" ADD COLUMN \"is_valid\" INTEGER;"}, {~c"0003/metadata.json", metadata_json_0003}, {~c"0004/migration.sql", - "CREATE TABLE \"e\" (\n \"id\" TEXT NOT NULL,\n \"value\" TEXT NOT NULL,\n CONSTRAINT \"e_pkey\" PRIMARY KEY (\"id\")\n) WITHOUT ROWID;"}, + "CREATE TABLE \"e\" (\n \"id\" TEXT NOT NULL,\n \"value\" TEXT NOT NULL,\n CONSTRAINT \"e_pkey\" PRIMARY KEY (\"id\")\n);"}, {~c"0004/metadata.json", metadata_json_0004} ] = file_list @@ -98,7 +98,7 @@ defmodule Electric.PlugTest do %SatOpMigrate.Stmt{ type: :CREATE_TABLE, sql: - "CREATE TABLE \"a\" (\n \"id\" TEXT NOT NULL,\n \"value\" TEXT NOT NULL,\n CONSTRAINT \"a_pkey\" PRIMARY KEY (\"id\")\n) WITHOUT ROWID;\n" + "CREATE TABLE \"a\" (\n \"id\" TEXT NOT NULL,\n \"value\" TEXT NOT NULL,\n CONSTRAINT \"a_pkey\" PRIMARY KEY (\"id\")\n);\n" }, %SatOpMigrate.Stmt{ type: :CREATE_INDEX, @@ -226,10 +226,10 @@ defmodule Electric.PlugTest do assert [ {~c"0003/migration.sql", - "CREATE TABLE \"d\" (\n \"id\" TEXT NOT NULL,\n \"value\" TEXT NOT NULL,\n CONSTRAINT \"d_pkey\" PRIMARY KEY (\"id\")\n) WITHOUT ROWID;\n\nALTER TABLE \"d\" ADD COLUMN \"is_valid\" INTEGER;"}, + "CREATE TABLE \"d\" (\n \"id\" TEXT NOT NULL,\n \"value\" TEXT NOT NULL,\n CONSTRAINT \"d_pkey\" PRIMARY KEY (\"id\")\n);\n\nALTER TABLE \"d\" ADD COLUMN \"is_valid\" INTEGER;"}, {~c"0003/metadata.json", metadata_json_0003}, {~c"0004/migration.sql", - "CREATE TABLE \"e\" (\n \"id\" TEXT NOT NULL,\n \"value\" TEXT NOT NULL,\n CONSTRAINT \"e_pkey\" PRIMARY KEY (\"id\")\n) WITHOUT ROWID;"}, + "CREATE TABLE \"e\" (\n \"id\" TEXT NOT NULL,\n \"value\" TEXT NOT NULL,\n CONSTRAINT \"e_pkey\" PRIMARY KEY (\"id\")\n);"}, {~c"0004/metadata.json", metadata_json_0004} ] = file_list diff --git a/components/electric/test/electric/postgres/dialect/sqlite_test.exs b/components/electric/test/electric/postgres/dialect/sqlite_test.exs index 93893f81..fbdf9808 100644 --- a/components/electric/test/electric/postgres/dialect/sqlite_test.exs +++ b/components/electric/test/electric/postgres/dialect/sqlite_test.exs @@ -122,7 +122,7 @@ defmodule Electric.Postgres.Dialect.SqliteTest do "i6" INTEGER, "i7" REAL, CONSTRAINT "i_pkey" PRIMARY KEY ("id") - ) WITHOUT ROWID; + ); """ end @@ -154,7 +154,7 @@ defmodule Electric.Postgres.Dialect.SqliteTest do ~s["i6" INTEGER,], ~s["i7" REAL,], ~s[CONSTRAINT "i_pkey" PRIMARY KEY ("id")], - ~s[) WITHOUT ROWID;] + ~s[);] ]) end @@ -169,7 +169,7 @@ defmodule Electric.Postgres.Dialect.SqliteTest do CREATE TABLE IF NOT EXISTS "i" ( "id" INTEGER NOT NULL, CONSTRAINT "i_pkey" PRIMARY KEY ("id") - ) WITHOUT ROWID; + ); """ end @@ -186,7 +186,7 @@ defmodule Electric.Postgres.Dialect.SqliteTest do CREATE TABLE "i" ( "id" INTEGER NOT NULL, CONSTRAINT "i_pkey" PRIMARY KEY ("id") - ) WITHOUT ROWID; + ); """ end @@ -205,7 +205,7 @@ defmodule Electric.Postgres.Dialect.SqliteTest do "id" INTEGER NOT NULL, "name" TEXT(256) NOT NULL, CONSTRAINT "i_pkey" PRIMARY KEY ("id") - ) WITHOUT ROWID; + ); """ end @@ -230,7 +230,7 @@ defmodule Electric.Postgres.Dialect.SqliteTest do CONSTRAINT "i_j_id_fkey" FOREIGN KEY ("j_id") REFERENCES "j" ("id") ON DELETE CASCADE ON UPDATE SET DEFAULT, CONSTRAINT "i_j_id2_fkey" FOREIGN KEY ("j_id2") REFERENCES "j" ("id"), CONSTRAINT "i_pkey" PRIMARY KEY ("id") - ) WITHOUT ROWID; + ); """ end @@ -258,7 +258,7 @@ defmodule Electric.Postgres.Dialect.SqliteTest do CONSTRAINT "starts" CHECK ((substring("c3", 1, 3) == 'his')), CONSTRAINT "percent" CHECK ((("c2" >= 0) AND ("c2" <= 100))), CONSTRAINT "i_pkey" PRIMARY KEY ("id") - ) WITHOUT ROWID; + ); """ end @@ -278,7 +278,7 @@ defmodule Electric.Postgres.Dialect.SqliteTest do "c1" INTEGER, CONSTRAINT "i_pkey" PRIMARY KEY ("id"), CONSTRAINT "i_c1_key" UNIQUE ("c1") - ) WITHOUT ROWID; + ); """ end @@ -301,7 +301,7 @@ defmodule Electric.Postgres.Dialect.SqliteTest do "c2" INTEGER, CONSTRAINT "i_pkey" PRIMARY KEY ("id"), CONSTRAINT "i_c1_c2_key" UNIQUE ("c1", "c2") - ) WITHOUT ROWID; + ); """ end @@ -336,7 +336,7 @@ defmodule Electric.Postgres.Dialect.SqliteTest do "c8" INTEGER DEFAULT (CAST('13' AS INTEGER)), "c9" TEXT DEFAULT current_timestamp, CONSTRAINT "i_pkey" PRIMARY KEY ("id") - ) WITHOUT ROWID; + ); """ end @@ -364,7 +364,7 @@ defmodule Electric.Postgres.Dialect.SqliteTest do "vv1" TEXT GENERATED ALWAYS AS ("v1" || "v2") STORED, "vv2" TEXT GENERATED ALWAYS AS (coalesce(upper("v1"), '') || coalesce(ltrim("v2", 'x'), '') || coalesce("v3", '')) STORED, CONSTRAINT "i_pkey" PRIMARY KEY ("id") - ) WITHOUT ROWID; + ); """ end end @@ -465,7 +465,7 @@ defmodule Electric.Postgres.Dialect.SqliteTest do "id" INTEGER NOT NULL, "k" INTEGER DEFAULT '0' NOT NULL, CONSTRAINT "i_pkey" PRIMARY KEY ("id") - ) WITHOUT ROWID; + ); """ end end diff --git a/components/electric/test/electric/postgres/replication_test.exs b/components/electric/test/electric/postgres/replication_test.exs index 4924d39c..cf3ff8d6 100644 --- a/components/electric/test/electric/postgres/replication_test.exs +++ b/components/electric/test/electric/postgres/replication_test.exs @@ -136,7 +136,7 @@ defmodule Electric.Postgres.ReplicationTest do %SatOpMigrate.Stmt{ type: :CREATE_TABLE, sql: - "CREATE TABLE \"fish\" (\n \"id\" INTEGER NOT NULL,\n CONSTRAINT \"fish_pkey\" PRIMARY KEY (\"id\")\n) WITHOUT ROWID;\n" + "CREATE TABLE \"fish\" (\n \"id\" INTEGER NOT NULL,\n CONSTRAINT \"fish_pkey\" PRIMARY KEY (\"id\")\n);\n" } ] @@ -175,7 +175,7 @@ defmodule Electric.Postgres.ReplicationTest do %SatOpMigrate.Stmt{ type: :CREATE_TABLE, sql: - "CREATE TABLE \"front\" (\n \"id\" INTEGER NOT NULL,\n \"frog_id\" INTEGER NOT NULL,\n CONSTRAINT \"front_frog_id_fkey\" FOREIGN KEY (\"frog_id\") REFERENCES \"fish\" (\"id\"),\n CONSTRAINT \"front_pkey\" PRIMARY KEY (\"id\")\n) WITHOUT ROWID;\n" + "CREATE TABLE \"front\" (\n \"id\" INTEGER NOT NULL,\n \"frog_id\" INTEGER NOT NULL,\n CONSTRAINT \"front_frog_id_fkey\" FOREIGN KEY (\"frog_id\") REFERENCES \"fish\" (\"id\"),\n CONSTRAINT \"front_pkey\" PRIMARY KEY (\"id\")\n);\n" } ] @@ -345,7 +345,7 @@ defmodule Electric.Postgres.ReplicationTest do %SatOpMigrate.Stmt{ type: :CREATE_TABLE, sql: - "CREATE TABLE \"wall\" (\n \"id\" INTEGER NOT NULL,\n \"finish\" TEXT,\n CONSTRAINT \"wall_pkey\" PRIMARY KEY (\"id\")\n) WITHOUT ROWID;\n" + "CREATE TABLE \"wall\" (\n \"id\" INTEGER NOT NULL,\n \"finish\" TEXT,\n CONSTRAINT \"wall_pkey\" PRIMARY KEY (\"id\")\n);\n" } ] diff --git a/e2e/satellite_client/src/generated/client/migrations.ts b/e2e/satellite_client/src/generated/client/migrations.ts index 0d620a53..2d46e233 100644 --- a/e2e/satellite_client/src/generated/client/migrations.ts +++ b/e2e/satellite_client/src/generated/client/migrations.ts @@ -1,121 +1,121 @@ export default [ { - "statements": [ - "CREATE TABLE \"items\" (\n \"id\" TEXT NOT NULL,\n \"content\" TEXT NOT NULL,\n \"content_text_null\" TEXT,\n \"content_text_null_default\" TEXT,\n \"intvalue_null\" INTEGER,\n \"intvalue_null_default\" INTEGER,\n CONSTRAINT \"items_pkey\" PRIMARY KEY (\"id\")\n) WITHOUT ROWID;\n", - "CREATE TABLE \"other_items\" (\n \"id\" TEXT NOT NULL,\n \"content\" TEXT NOT NULL,\n \"item_id\" TEXT,\n CONSTRAINT \"other_items_item_id_fkey\" FOREIGN KEY (\"item_id\") REFERENCES \"items\" (\"id\"),\n CONSTRAINT \"other_items_pkey\" PRIMARY KEY (\"id\")\n) WITHOUT ROWID;\n", - "CREATE TABLE \"timestamps\" (\n \"id\" TEXT NOT NULL,\n \"created_at\" TEXT NOT NULL,\n \"updated_at\" TEXT NOT NULL,\n CONSTRAINT \"timestamps_pkey\" PRIMARY KEY (\"id\")\n) WITHOUT ROWID;\n", - "CREATE TABLE \"datetimes\" (\n \"id\" TEXT NOT NULL,\n \"d\" TEXT NOT NULL,\n \"t\" TEXT NOT NULL,\n CONSTRAINT \"datetimes_pkey\" PRIMARY KEY (\"id\")\n) WITHOUT ROWID;\n", - "CREATE TABLE \"bools\" (\n \"id\" TEXT NOT NULL,\n \"b\" INTEGER,\n CONSTRAINT \"bools_pkey\" PRIMARY KEY (\"id\")\n) WITHOUT ROWID;\n", - "CREATE TABLE \"uuids\" (\n \"id\" TEXT NOT NULL,\n CONSTRAINT \"uuids_pkey\" PRIMARY KEY (\"id\")\n) WITHOUT ROWID;\n", - "CREATE TABLE \"ints\" (\n \"id\" TEXT NOT NULL,\n \"i2\" INTEGER,\n \"i4\" INTEGER,\n \"i8\" INTEGER,\n CONSTRAINT \"ints_pkey\" PRIMARY KEY (\"id\")\n) WITHOUT ROWID;\n", - "CREATE TABLE \"floats\" (\n \"id\" TEXT NOT NULL,\n \"f4\" REAL,\n \"f8\" REAL,\n CONSTRAINT \"floats_pkey\" PRIMARY KEY (\"id\")\n) WITHOUT ROWID;\n", - "CREATE TABLE \"jsons\" (\n \"id\" TEXT NOT NULL,\n \"jsb\" TEXT_JSON,\n CONSTRAINT \"jsons_pkey\" PRIMARY KEY (\"id\")\n) WITHOUT ROWID;\n", - "CREATE TABLE \"enums\" (\n \"id\" TEXT NOT NULL,\n \"c\" TEXT,\n CONSTRAINT \"enums_pkey\" PRIMARY KEY (\"id\")\n) WITHOUT ROWID;\n", - "CREATE TABLE \"blobs\" (\n \"id\" TEXT NOT NULL,\n \"blob\" BLOB,\n CONSTRAINT \"blobs_pkey\" PRIMARY KEY (\"id\")\n) WITHOUT ROWID;\n", + statements: [ + 'CREATE TABLE "items" (\n "id" TEXT NOT NULL,\n "content" TEXT NOT NULL,\n "content_text_null" TEXT,\n "content_text_null_default" TEXT,\n "intvalue_null" INTEGER,\n "intvalue_null_default" INTEGER,\n CONSTRAINT "items_pkey" PRIMARY KEY ("id")\n);\n', + 'CREATE TABLE "other_items" (\n "id" TEXT NOT NULL,\n "content" TEXT NOT NULL,\n "item_id" TEXT,\n CONSTRAINT "other_items_item_id_fkey" FOREIGN KEY ("item_id") REFERENCES "items" ("id"),\n CONSTRAINT "other_items_pkey" PRIMARY KEY ("id")\n);\n', + 'CREATE TABLE "timestamps" (\n "id" TEXT NOT NULL,\n "created_at" TEXT NOT NULL,\n "updated_at" TEXT NOT NULL,\n CONSTRAINT "timestamps_pkey" PRIMARY KEY ("id")\n);\n', + 'CREATE TABLE "datetimes" (\n "id" TEXT NOT NULL,\n "d" TEXT NOT NULL,\n "t" TEXT NOT NULL,\n CONSTRAINT "datetimes_pkey" PRIMARY KEY ("id")\n);\n', + 'CREATE TABLE "bools" (\n "id" TEXT NOT NULL,\n "b" INTEGER,\n CONSTRAINT "bools_pkey" PRIMARY KEY ("id")\n);\n', + 'CREATE TABLE "uuids" (\n "id" TEXT NOT NULL,\n CONSTRAINT "uuids_pkey" PRIMARY KEY ("id")\n);\n', + 'CREATE TABLE "ints" (\n "id" TEXT NOT NULL,\n "i2" INTEGER,\n "i4" INTEGER,\n "i8" INTEGER,\n CONSTRAINT "ints_pkey" PRIMARY KEY ("id")\n);\n', + 'CREATE TABLE "floats" (\n "id" TEXT NOT NULL,\n "f4" REAL,\n "f8" REAL,\n CONSTRAINT "floats_pkey" PRIMARY KEY ("id")\n);\n', + 'CREATE TABLE "jsons" (\n "id" TEXT NOT NULL,\n "jsb" TEXT_JSON,\n CONSTRAINT "jsons_pkey" PRIMARY KEY ("id")\n);\n', + 'CREATE TABLE "enums" (\n "id" TEXT NOT NULL,\n "c" TEXT,\n CONSTRAINT "enums_pkey" PRIMARY KEY ("id")\n);\n', + 'CREATE TABLE "blobs" (\n "id" TEXT NOT NULL,\n "blob" BLOB,\n CONSTRAINT "blobs_pkey" PRIMARY KEY ("id")\n);\n', "INSERT OR IGNORE INTO _electric_trigger_settings (namespace, tablename, flag) VALUES ('main', 'items', 1);", - "DROP TRIGGER IF EXISTS update_ensure_main_items_primarykey;", - "CREATE TRIGGER update_ensure_main_items_primarykey\n BEFORE UPDATE ON \"main\".\"items\"\nBEGIN\n SELECT\n CASE\n WHEN old.\"id\" != new.\"id\" THEN\n \t\tRAISE (ABORT, 'cannot change the value of column id as it belongs to the primary key')\n END;\nEND;", - "DROP TRIGGER IF EXISTS insert_main_items_into_oplog;", + 'DROP TRIGGER IF EXISTS update_ensure_main_items_primarykey;', + 'CREATE TRIGGER update_ensure_main_items_primarykey\n BEFORE UPDATE ON "main"."items"\nBEGIN\n SELECT\n CASE\n WHEN old."id" != new."id" THEN\n \t\tRAISE (ABORT, \'cannot change the value of column id as it belongs to the primary key\')\n END;\nEND;', + 'DROP TRIGGER IF EXISTS insert_main_items_into_oplog;', "CREATE TRIGGER insert_main_items_into_oplog\n AFTER INSERT ON \"main\".\"items\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'items')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'items', 'INSERT', json_patch('{}', json_object('id', new.\"id\")), json_object('content', new.\"content\", 'content_text_null', new.\"content_text_null\", 'content_text_null_default', new.\"content_text_null_default\", 'id', new.\"id\", 'intvalue_null', new.\"intvalue_null\", 'intvalue_null_default', new.\"intvalue_null_default\"), NULL, NULL);\nEND;", - "DROP TRIGGER IF EXISTS update_main_items_into_oplog;", + 'DROP TRIGGER IF EXISTS update_main_items_into_oplog;', "CREATE TRIGGER update_main_items_into_oplog\n AFTER UPDATE ON \"main\".\"items\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'items')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'items', 'UPDATE', json_patch('{}', json_object('id', new.\"id\")), json_object('content', new.\"content\", 'content_text_null', new.\"content_text_null\", 'content_text_null_default', new.\"content_text_null_default\", 'id', new.\"id\", 'intvalue_null', new.\"intvalue_null\", 'intvalue_null_default', new.\"intvalue_null_default\"), json_object('content', old.\"content\", 'content_text_null', old.\"content_text_null\", 'content_text_null_default', old.\"content_text_null_default\", 'id', old.\"id\", 'intvalue_null', old.\"intvalue_null\", 'intvalue_null_default', old.\"intvalue_null_default\"), NULL);\nEND;", - "DROP TRIGGER IF EXISTS delete_main_items_into_oplog;", + 'DROP TRIGGER IF EXISTS delete_main_items_into_oplog;', "CREATE TRIGGER delete_main_items_into_oplog\n AFTER DELETE ON \"main\".\"items\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'items')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'items', 'DELETE', json_patch('{}', json_object('id', old.\"id\")), NULL, json_object('content', old.\"content\", 'content_text_null', old.\"content_text_null\", 'content_text_null_default', old.\"content_text_null_default\", 'id', old.\"id\", 'intvalue_null', old.\"intvalue_null\", 'intvalue_null_default', old.\"intvalue_null_default\"), NULL);\nEND;", "INSERT OR IGNORE INTO _electric_trigger_settings (namespace, tablename, flag) VALUES ('main', 'other_items', 1);", - "DROP TRIGGER IF EXISTS update_ensure_main_other_items_primarykey;", - "CREATE TRIGGER update_ensure_main_other_items_primarykey\n BEFORE UPDATE ON \"main\".\"other_items\"\nBEGIN\n SELECT\n CASE\n WHEN old.\"id\" != new.\"id\" THEN\n \t\tRAISE (ABORT, 'cannot change the value of column id as it belongs to the primary key')\n END;\nEND;", - "DROP TRIGGER IF EXISTS insert_main_other_items_into_oplog;", + 'DROP TRIGGER IF EXISTS update_ensure_main_other_items_primarykey;', + 'CREATE TRIGGER update_ensure_main_other_items_primarykey\n BEFORE UPDATE ON "main"."other_items"\nBEGIN\n SELECT\n CASE\n WHEN old."id" != new."id" THEN\n \t\tRAISE (ABORT, \'cannot change the value of column id as it belongs to the primary key\')\n END;\nEND;', + 'DROP TRIGGER IF EXISTS insert_main_other_items_into_oplog;', "CREATE TRIGGER insert_main_other_items_into_oplog\n AFTER INSERT ON \"main\".\"other_items\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'other_items')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'other_items', 'INSERT', json_patch('{}', json_object('id', new.\"id\")), json_object('content', new.\"content\", 'id', new.\"id\", 'item_id', new.\"item_id\"), NULL, NULL);\nEND;", - "DROP TRIGGER IF EXISTS update_main_other_items_into_oplog;", + 'DROP TRIGGER IF EXISTS update_main_other_items_into_oplog;', "CREATE TRIGGER update_main_other_items_into_oplog\n AFTER UPDATE ON \"main\".\"other_items\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'other_items')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'other_items', 'UPDATE', json_patch('{}', json_object('id', new.\"id\")), json_object('content', new.\"content\", 'id', new.\"id\", 'item_id', new.\"item_id\"), json_object('content', old.\"content\", 'id', old.\"id\", 'item_id', old.\"item_id\"), NULL);\nEND;", - "DROP TRIGGER IF EXISTS delete_main_other_items_into_oplog;", + 'DROP TRIGGER IF EXISTS delete_main_other_items_into_oplog;', "CREATE TRIGGER delete_main_other_items_into_oplog\n AFTER DELETE ON \"main\".\"other_items\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'other_items')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'other_items', 'DELETE', json_patch('{}', json_object('id', old.\"id\")), NULL, json_object('content', old.\"content\", 'id', old.\"id\", 'item_id', old.\"item_id\"), NULL);\nEND;", - "DROP TRIGGER IF EXISTS compensation_insert_main_other_items_item_id_into_oplog;", + 'DROP TRIGGER IF EXISTS compensation_insert_main_other_items_item_id_into_oplog;', "CREATE TRIGGER compensation_insert_main_other_items_item_id_into_oplog\n AFTER INSERT ON \"main\".\"other_items\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'other_items') AND\n 1 = (SELECT value from _electric_meta WHERE key = 'compensations')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n SELECT 'main', 'items', 'COMPENSATION', json_patch('{}', json_object('id', \"id\")), json_object('id', \"id\"), NULL, NULL\n FROM \"main\".\"items\" WHERE \"id\" = new.\"item_id\";\nEND;", - "DROP TRIGGER IF EXISTS compensation_update_main_other_items_item_id_into_oplog;", + 'DROP TRIGGER IF EXISTS compensation_update_main_other_items_item_id_into_oplog;', "CREATE TRIGGER compensation_update_main_other_items_item_id_into_oplog\n AFTER UPDATE ON \"main\".\"other_items\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'other_items') AND\n 1 = (SELECT value from _electric_meta WHERE key = 'compensations')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n SELECT 'main', 'items', 'COMPENSATION', json_patch('{}', json_object('id', \"id\")), json_object('id', \"id\"), NULL, NULL\n FROM \"main\".\"items\" WHERE \"id\" = new.\"item_id\";\nEND;", "INSERT OR IGNORE INTO _electric_trigger_settings (namespace, tablename, flag) VALUES ('main', 'timestamps', 1);", - "DROP TRIGGER IF EXISTS update_ensure_main_timestamps_primarykey;", - "CREATE TRIGGER update_ensure_main_timestamps_primarykey\n BEFORE UPDATE ON \"main\".\"timestamps\"\nBEGIN\n SELECT\n CASE\n WHEN old.\"id\" != new.\"id\" THEN\n \t\tRAISE (ABORT, 'cannot change the value of column id as it belongs to the primary key')\n END;\nEND;", - "DROP TRIGGER IF EXISTS insert_main_timestamps_into_oplog;", + 'DROP TRIGGER IF EXISTS update_ensure_main_timestamps_primarykey;', + 'CREATE TRIGGER update_ensure_main_timestamps_primarykey\n BEFORE UPDATE ON "main"."timestamps"\nBEGIN\n SELECT\n CASE\n WHEN old."id" != new."id" THEN\n \t\tRAISE (ABORT, \'cannot change the value of column id as it belongs to the primary key\')\n END;\nEND;', + 'DROP TRIGGER IF EXISTS insert_main_timestamps_into_oplog;', "CREATE TRIGGER insert_main_timestamps_into_oplog\n AFTER INSERT ON \"main\".\"timestamps\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'timestamps')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'timestamps', 'INSERT', json_patch('{}', json_object('id', new.\"id\")), json_object('created_at', new.\"created_at\", 'id', new.\"id\", 'updated_at', new.\"updated_at\"), NULL, NULL);\nEND;", - "DROP TRIGGER IF EXISTS update_main_timestamps_into_oplog;", + 'DROP TRIGGER IF EXISTS update_main_timestamps_into_oplog;', "CREATE TRIGGER update_main_timestamps_into_oplog\n AFTER UPDATE ON \"main\".\"timestamps\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'timestamps')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'timestamps', 'UPDATE', json_patch('{}', json_object('id', new.\"id\")), json_object('created_at', new.\"created_at\", 'id', new.\"id\", 'updated_at', new.\"updated_at\"), json_object('created_at', old.\"created_at\", 'id', old.\"id\", 'updated_at', old.\"updated_at\"), NULL);\nEND;", - "DROP TRIGGER IF EXISTS delete_main_timestamps_into_oplog;", + 'DROP TRIGGER IF EXISTS delete_main_timestamps_into_oplog;', "CREATE TRIGGER delete_main_timestamps_into_oplog\n AFTER DELETE ON \"main\".\"timestamps\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'timestamps')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'timestamps', 'DELETE', json_patch('{}', json_object('id', old.\"id\")), NULL, json_object('created_at', old.\"created_at\", 'id', old.\"id\", 'updated_at', old.\"updated_at\"), NULL);\nEND;", "INSERT OR IGNORE INTO _electric_trigger_settings (namespace, tablename, flag) VALUES ('main', 'datetimes', 1);", - "DROP TRIGGER IF EXISTS update_ensure_main_datetimes_primarykey;", - "CREATE TRIGGER update_ensure_main_datetimes_primarykey\n BEFORE UPDATE ON \"main\".\"datetimes\"\nBEGIN\n SELECT\n CASE\n WHEN old.\"id\" != new.\"id\" THEN\n \t\tRAISE (ABORT, 'cannot change the value of column id as it belongs to the primary key')\n END;\nEND;", - "DROP TRIGGER IF EXISTS insert_main_datetimes_into_oplog;", + 'DROP TRIGGER IF EXISTS update_ensure_main_datetimes_primarykey;', + 'CREATE TRIGGER update_ensure_main_datetimes_primarykey\n BEFORE UPDATE ON "main"."datetimes"\nBEGIN\n SELECT\n CASE\n WHEN old."id" != new."id" THEN\n \t\tRAISE (ABORT, \'cannot change the value of column id as it belongs to the primary key\')\n END;\nEND;', + 'DROP TRIGGER IF EXISTS insert_main_datetimes_into_oplog;', "CREATE TRIGGER insert_main_datetimes_into_oplog\n AFTER INSERT ON \"main\".\"datetimes\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'datetimes')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'datetimes', 'INSERT', json_patch('{}', json_object('id', new.\"id\")), json_object('d', new.\"d\", 'id', new.\"id\", 't', new.\"t\"), NULL, NULL);\nEND;", - "DROP TRIGGER IF EXISTS update_main_datetimes_into_oplog;", + 'DROP TRIGGER IF EXISTS update_main_datetimes_into_oplog;', "CREATE TRIGGER update_main_datetimes_into_oplog\n AFTER UPDATE ON \"main\".\"datetimes\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'datetimes')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'datetimes', 'UPDATE', json_patch('{}', json_object('id', new.\"id\")), json_object('d', new.\"d\", 'id', new.\"id\", 't', new.\"t\"), json_object('d', old.\"d\", 'id', old.\"id\", 't', old.\"t\"), NULL);\nEND;", - "DROP TRIGGER IF EXISTS delete_main_datetimes_into_oplog;", + 'DROP TRIGGER IF EXISTS delete_main_datetimes_into_oplog;', "CREATE TRIGGER delete_main_datetimes_into_oplog\n AFTER DELETE ON \"main\".\"datetimes\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'datetimes')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'datetimes', 'DELETE', json_patch('{}', json_object('id', old.\"id\")), NULL, json_object('d', old.\"d\", 'id', old.\"id\", 't', old.\"t\"), NULL);\nEND;", "INSERT OR IGNORE INTO _electric_trigger_settings (namespace, tablename, flag) VALUES ('main', 'bools', 1);", - "DROP TRIGGER IF EXISTS update_ensure_main_bools_primarykey;", - "CREATE TRIGGER update_ensure_main_bools_primarykey\n BEFORE UPDATE ON \"main\".\"bools\"\nBEGIN\n SELECT\n CASE\n WHEN old.\"id\" != new.\"id\" THEN\n \t\tRAISE (ABORT, 'cannot change the value of column id as it belongs to the primary key')\n END;\nEND;", - "DROP TRIGGER IF EXISTS insert_main_bools_into_oplog;", + 'DROP TRIGGER IF EXISTS update_ensure_main_bools_primarykey;', + 'CREATE TRIGGER update_ensure_main_bools_primarykey\n BEFORE UPDATE ON "main"."bools"\nBEGIN\n SELECT\n CASE\n WHEN old."id" != new."id" THEN\n \t\tRAISE (ABORT, \'cannot change the value of column id as it belongs to the primary key\')\n END;\nEND;', + 'DROP TRIGGER IF EXISTS insert_main_bools_into_oplog;', "CREATE TRIGGER insert_main_bools_into_oplog\n AFTER INSERT ON \"main\".\"bools\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'bools')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'bools', 'INSERT', json_patch('{}', json_object('id', new.\"id\")), json_object('b', new.\"b\", 'id', new.\"id\"), NULL, NULL);\nEND;", - "DROP TRIGGER IF EXISTS update_main_bools_into_oplog;", + 'DROP TRIGGER IF EXISTS update_main_bools_into_oplog;', "CREATE TRIGGER update_main_bools_into_oplog\n AFTER UPDATE ON \"main\".\"bools\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'bools')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'bools', 'UPDATE', json_patch('{}', json_object('id', new.\"id\")), json_object('b', new.\"b\", 'id', new.\"id\"), json_object('b', old.\"b\", 'id', old.\"id\"), NULL);\nEND;", - "DROP TRIGGER IF EXISTS delete_main_bools_into_oplog;", + 'DROP TRIGGER IF EXISTS delete_main_bools_into_oplog;', "CREATE TRIGGER delete_main_bools_into_oplog\n AFTER DELETE ON \"main\".\"bools\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'bools')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'bools', 'DELETE', json_patch('{}', json_object('id', old.\"id\")), NULL, json_object('b', old.\"b\", 'id', old.\"id\"), NULL);\nEND;", "INSERT OR IGNORE INTO _electric_trigger_settings (namespace, tablename, flag) VALUES ('main', 'uuids', 1);", - "DROP TRIGGER IF EXISTS update_ensure_main_uuids_primarykey;", - "CREATE TRIGGER update_ensure_main_uuids_primarykey\n BEFORE UPDATE ON \"main\".\"uuids\"\nBEGIN\n SELECT\n CASE\n WHEN old.\"id\" != new.\"id\" THEN\n \t\tRAISE (ABORT, 'cannot change the value of column id as it belongs to the primary key')\n END;\nEND;", - "DROP TRIGGER IF EXISTS insert_main_uuids_into_oplog;", + 'DROP TRIGGER IF EXISTS update_ensure_main_uuids_primarykey;', + 'CREATE TRIGGER update_ensure_main_uuids_primarykey\n BEFORE UPDATE ON "main"."uuids"\nBEGIN\n SELECT\n CASE\n WHEN old."id" != new."id" THEN\n \t\tRAISE (ABORT, \'cannot change the value of column id as it belongs to the primary key\')\n END;\nEND;', + 'DROP TRIGGER IF EXISTS insert_main_uuids_into_oplog;', "CREATE TRIGGER insert_main_uuids_into_oplog\n AFTER INSERT ON \"main\".\"uuids\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'uuids')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'uuids', 'INSERT', json_patch('{}', json_object('id', new.\"id\")), json_object('id', new.\"id\"), NULL, NULL);\nEND;", - "DROP TRIGGER IF EXISTS update_main_uuids_into_oplog;", + 'DROP TRIGGER IF EXISTS update_main_uuids_into_oplog;', "CREATE TRIGGER update_main_uuids_into_oplog\n AFTER UPDATE ON \"main\".\"uuids\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'uuids')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'uuids', 'UPDATE', json_patch('{}', json_object('id', new.\"id\")), json_object('id', new.\"id\"), json_object('id', old.\"id\"), NULL);\nEND;", - "DROP TRIGGER IF EXISTS delete_main_uuids_into_oplog;", + 'DROP TRIGGER IF EXISTS delete_main_uuids_into_oplog;', "CREATE TRIGGER delete_main_uuids_into_oplog\n AFTER DELETE ON \"main\".\"uuids\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'uuids')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'uuids', 'DELETE', json_patch('{}', json_object('id', old.\"id\")), NULL, json_object('id', old.\"id\"), NULL);\nEND;", "INSERT OR IGNORE INTO _electric_trigger_settings (namespace, tablename, flag) VALUES ('main', 'ints', 1);", - "DROP TRIGGER IF EXISTS update_ensure_main_ints_primarykey;", - "CREATE TRIGGER update_ensure_main_ints_primarykey\n BEFORE UPDATE ON \"main\".\"ints\"\nBEGIN\n SELECT\n CASE\n WHEN old.\"id\" != new.\"id\" THEN\n \t\tRAISE (ABORT, 'cannot change the value of column id as it belongs to the primary key')\n END;\nEND;", - "DROP TRIGGER IF EXISTS insert_main_ints_into_oplog;", + 'DROP TRIGGER IF EXISTS update_ensure_main_ints_primarykey;', + 'CREATE TRIGGER update_ensure_main_ints_primarykey\n BEFORE UPDATE ON "main"."ints"\nBEGIN\n SELECT\n CASE\n WHEN old."id" != new."id" THEN\n \t\tRAISE (ABORT, \'cannot change the value of column id as it belongs to the primary key\')\n END;\nEND;', + 'DROP TRIGGER IF EXISTS insert_main_ints_into_oplog;', "CREATE TRIGGER insert_main_ints_into_oplog\n AFTER INSERT ON \"main\".\"ints\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'ints')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'ints', 'INSERT', json_patch('{}', json_object('id', new.\"id\")), json_object('i2', new.\"i2\", 'i4', new.\"i4\", 'i8', cast(new.\"i8\" as TEXT), 'id', new.\"id\"), NULL, NULL);\nEND;", - "DROP TRIGGER IF EXISTS update_main_ints_into_oplog;", + 'DROP TRIGGER IF EXISTS update_main_ints_into_oplog;', "CREATE TRIGGER update_main_ints_into_oplog\n AFTER UPDATE ON \"main\".\"ints\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'ints')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'ints', 'UPDATE', json_patch('{}', json_object('id', new.\"id\")), json_object('i2', new.\"i2\", 'i4', new.\"i4\", 'i8', cast(new.\"i8\" as TEXT), 'id', new.\"id\"), json_object('i2', old.\"i2\", 'i4', old.\"i4\", 'i8', cast(old.\"i8\" as TEXT), 'id', old.\"id\"), NULL);\nEND;", - "DROP TRIGGER IF EXISTS delete_main_ints_into_oplog;", + 'DROP TRIGGER IF EXISTS delete_main_ints_into_oplog;', "CREATE TRIGGER delete_main_ints_into_oplog\n AFTER DELETE ON \"main\".\"ints\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'ints')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'ints', 'DELETE', json_patch('{}', json_object('id', old.\"id\")), NULL, json_object('i2', old.\"i2\", 'i4', old.\"i4\", 'i8', cast(old.\"i8\" as TEXT), 'id', old.\"id\"), NULL);\nEND;", "INSERT OR IGNORE INTO _electric_trigger_settings (namespace, tablename, flag) VALUES ('main', 'floats', 1);", - "DROP TRIGGER IF EXISTS update_ensure_main_floats_primarykey;", - "CREATE TRIGGER update_ensure_main_floats_primarykey\n BEFORE UPDATE ON \"main\".\"floats\"\nBEGIN\n SELECT\n CASE\n WHEN old.\"id\" != new.\"id\" THEN\n \t\tRAISE (ABORT, 'cannot change the value of column id as it belongs to the primary key')\n END;\nEND;", - "DROP TRIGGER IF EXISTS insert_main_floats_into_oplog;", + 'DROP TRIGGER IF EXISTS update_ensure_main_floats_primarykey;', + 'CREATE TRIGGER update_ensure_main_floats_primarykey\n BEFORE UPDATE ON "main"."floats"\nBEGIN\n SELECT\n CASE\n WHEN old."id" != new."id" THEN\n \t\tRAISE (ABORT, \'cannot change the value of column id as it belongs to the primary key\')\n END;\nEND;', + 'DROP TRIGGER IF EXISTS insert_main_floats_into_oplog;', "CREATE TRIGGER insert_main_floats_into_oplog\n AFTER INSERT ON \"main\".\"floats\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'floats')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'floats', 'INSERT', json_patch('{}', json_object('id', new.\"id\")), json_object('f4', cast(new.\"f4\" as TEXT), 'f8', cast(new.\"f8\" as TEXT), 'id', new.\"id\"), NULL, NULL);\nEND;", - "DROP TRIGGER IF EXISTS update_main_floats_into_oplog;", + 'DROP TRIGGER IF EXISTS update_main_floats_into_oplog;', "CREATE TRIGGER update_main_floats_into_oplog\n AFTER UPDATE ON \"main\".\"floats\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'floats')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'floats', 'UPDATE', json_patch('{}', json_object('id', new.\"id\")), json_object('f4', cast(new.\"f4\" as TEXT), 'f8', cast(new.\"f8\" as TEXT), 'id', new.\"id\"), json_object('f4', cast(old.\"f4\" as TEXT), 'f8', cast(old.\"f8\" as TEXT), 'id', old.\"id\"), NULL);\nEND;", - "DROP TRIGGER IF EXISTS delete_main_floats_into_oplog;", + 'DROP TRIGGER IF EXISTS delete_main_floats_into_oplog;', "CREATE TRIGGER delete_main_floats_into_oplog\n AFTER DELETE ON \"main\".\"floats\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'floats')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'floats', 'DELETE', json_patch('{}', json_object('id', old.\"id\")), NULL, json_object('f4', cast(old.\"f4\" as TEXT), 'f8', cast(old.\"f8\" as TEXT), 'id', old.\"id\"), NULL);\nEND;", "INSERT OR IGNORE INTO _electric_trigger_settings (namespace, tablename, flag) VALUES ('main', 'jsons', 1);", - "DROP TRIGGER IF EXISTS update_ensure_main_jsons_primarykey;", - "CREATE TRIGGER update_ensure_main_jsons_primarykey\n BEFORE UPDATE ON \"main\".\"jsons\"\nBEGIN\n SELECT\n CASE\n WHEN old.\"id\" != new.\"id\" THEN\n \t\tRAISE (ABORT, 'cannot change the value of column id as it belongs to the primary key')\n END;\nEND;", - "DROP TRIGGER IF EXISTS insert_main_jsons_into_oplog;", + 'DROP TRIGGER IF EXISTS update_ensure_main_jsons_primarykey;', + 'CREATE TRIGGER update_ensure_main_jsons_primarykey\n BEFORE UPDATE ON "main"."jsons"\nBEGIN\n SELECT\n CASE\n WHEN old."id" != new."id" THEN\n \t\tRAISE (ABORT, \'cannot change the value of column id as it belongs to the primary key\')\n END;\nEND;', + 'DROP TRIGGER IF EXISTS insert_main_jsons_into_oplog;', "CREATE TRIGGER insert_main_jsons_into_oplog\n AFTER INSERT ON \"main\".\"jsons\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'jsons')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'jsons', 'INSERT', json_patch('{}', json_object('id', new.\"id\")), json_object('id', new.\"id\", 'jsb', new.\"jsb\"), NULL, NULL);\nEND;", - "DROP TRIGGER IF EXISTS update_main_jsons_into_oplog;", + 'DROP TRIGGER IF EXISTS update_main_jsons_into_oplog;', "CREATE TRIGGER update_main_jsons_into_oplog\n AFTER UPDATE ON \"main\".\"jsons\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'jsons')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'jsons', 'UPDATE', json_patch('{}', json_object('id', new.\"id\")), json_object('id', new.\"id\", 'jsb', new.\"jsb\"), json_object('id', old.\"id\", 'jsb', old.\"jsb\"), NULL);\nEND;", - "DROP TRIGGER IF EXISTS delete_main_jsons_into_oplog;", + 'DROP TRIGGER IF EXISTS delete_main_jsons_into_oplog;', "CREATE TRIGGER delete_main_jsons_into_oplog\n AFTER DELETE ON \"main\".\"jsons\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'jsons')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'jsons', 'DELETE', json_patch('{}', json_object('id', old.\"id\")), NULL, json_object('id', old.\"id\", 'jsb', old.\"jsb\"), NULL);\nEND;", "INSERT OR IGNORE INTO _electric_trigger_settings (namespace, tablename, flag) VALUES ('main', 'enums', 1);", - "DROP TRIGGER IF EXISTS update_ensure_main_enums_primarykey;", - "CREATE TRIGGER update_ensure_main_enums_primarykey\n BEFORE UPDATE ON \"main\".\"enums\"\nBEGIN\n SELECT\n CASE\n WHEN old.\"id\" != new.\"id\" THEN\n \t\tRAISE (ABORT, 'cannot change the value of column id as it belongs to the primary key')\n END;\nEND;", - "DROP TRIGGER IF EXISTS insert_main_enums_into_oplog;", + 'DROP TRIGGER IF EXISTS update_ensure_main_enums_primarykey;', + 'CREATE TRIGGER update_ensure_main_enums_primarykey\n BEFORE UPDATE ON "main"."enums"\nBEGIN\n SELECT\n CASE\n WHEN old."id" != new."id" THEN\n \t\tRAISE (ABORT, \'cannot change the value of column id as it belongs to the primary key\')\n END;\nEND;', + 'DROP TRIGGER IF EXISTS insert_main_enums_into_oplog;', "CREATE TRIGGER insert_main_enums_into_oplog\n AFTER INSERT ON \"main\".\"enums\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'enums')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'enums', 'INSERT', json_patch('{}', json_object('id', new.\"id\")), json_object('c', new.\"c\", 'id', new.\"id\"), NULL, NULL);\nEND;", - "DROP TRIGGER IF EXISTS update_main_enums_into_oplog;", + 'DROP TRIGGER IF EXISTS update_main_enums_into_oplog;', "CREATE TRIGGER update_main_enums_into_oplog\n AFTER UPDATE ON \"main\".\"enums\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'enums')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'enums', 'UPDATE', json_patch('{}', json_object('id', new.\"id\")), json_object('c', new.\"c\", 'id', new.\"id\"), json_object('c', old.\"c\", 'id', old.\"id\"), NULL);\nEND;", - "DROP TRIGGER IF EXISTS delete_main_enums_into_oplog;", + 'DROP TRIGGER IF EXISTS delete_main_enums_into_oplog;', "CREATE TRIGGER delete_main_enums_into_oplog\n AFTER DELETE ON \"main\".\"enums\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'enums')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'enums', 'DELETE', json_patch('{}', json_object('id', old.\"id\")), NULL, json_object('c', old.\"c\", 'id', old.\"id\"), NULL);\nEND;", "INSERT OR IGNORE INTO _electric_trigger_settings (namespace, tablename, flag) VALUES ('main', 'blobs', 1);", - "DROP TRIGGER IF EXISTS update_ensure_main_blobs_primarykey;", - "CREATE TRIGGER update_ensure_main_blobs_primarykey\n BEFORE UPDATE ON \"main\".\"blobs\"\nBEGIN\n SELECT\n CASE\n WHEN old.\"id\" != new.\"id\" THEN\n \t\tRAISE (ABORT, 'cannot change the value of column id as it belongs to the primary key')\n END;\nEND;", - "DROP TRIGGER IF EXISTS insert_main_blobs_into_oplog;", + 'DROP TRIGGER IF EXISTS update_ensure_main_blobs_primarykey;', + 'CREATE TRIGGER update_ensure_main_blobs_primarykey\n BEFORE UPDATE ON "main"."blobs"\nBEGIN\n SELECT\n CASE\n WHEN old."id" != new."id" THEN\n \t\tRAISE (ABORT, \'cannot change the value of column id as it belongs to the primary key\')\n END;\nEND;', + 'DROP TRIGGER IF EXISTS insert_main_blobs_into_oplog;', "CREATE TRIGGER insert_main_blobs_into_oplog\n AFTER INSERT ON \"main\".\"blobs\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'blobs')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'blobs', 'INSERT', json_patch('{}', json_object('id', new.\"id\")), json_object('blob', CASE WHEN new.\"blob\" IS NOT NULL THEN hex(new.\"blob\") ELSE NULL END, 'id', new.\"id\"), NULL, NULL);\nEND;", - "DROP TRIGGER IF EXISTS update_main_blobs_into_oplog;", + 'DROP TRIGGER IF EXISTS update_main_blobs_into_oplog;', "CREATE TRIGGER update_main_blobs_into_oplog\n AFTER UPDATE ON \"main\".\"blobs\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'blobs')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'blobs', 'UPDATE', json_patch('{}', json_object('id', new.\"id\")), json_object('blob', CASE WHEN new.\"blob\" IS NOT NULL THEN hex(new.\"blob\") ELSE NULL END, 'id', new.\"id\"), json_object('blob', CASE WHEN old.\"blob\" IS NOT NULL THEN hex(old.\"blob\") ELSE NULL END, 'id', old.\"id\"), NULL);\nEND;", - "DROP TRIGGER IF EXISTS delete_main_blobs_into_oplog;", - "CREATE TRIGGER delete_main_blobs_into_oplog\n AFTER DELETE ON \"main\".\"blobs\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'blobs')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'blobs', 'DELETE', json_patch('{}', json_object('id', old.\"id\")), NULL, json_object('blob', CASE WHEN old.\"blob\" IS NOT NULL THEN hex(old.\"blob\") ELSE NULL END, 'id', old.\"id\"), NULL);\nEND;" + 'DROP TRIGGER IF EXISTS delete_main_blobs_into_oplog;', + "CREATE TRIGGER delete_main_blobs_into_oplog\n AFTER DELETE ON \"main\".\"blobs\"\n WHEN 1 = (SELECT flag from _electric_trigger_settings WHERE namespace = 'main' AND tablename = 'blobs')\nBEGIN\n INSERT INTO _electric_oplog (namespace, tablename, optype, primaryKey, newRow, oldRow, timestamp)\n VALUES ('main', 'blobs', 'DELETE', json_patch('{}', json_object('id', old.\"id\")), NULL, json_object('blob', CASE WHEN old.\"blob\" IS NOT NULL THEN hex(old.\"blob\") ELSE NULL END, 'id', old.\"id\"), NULL);\nEND;", ], - "version": "1" - } -] \ No newline at end of file + version: '1', + }, +]