Skip to content

Not possible to create database triggers with more than one statement in custom migrations #442

@alessandrojean

Description

@alessandrojean

Describe the bug
I'm trying to implement full-text search within a project by using SQLite's fts5, which seems to be supported by Cloudflare D1 SQL syntax as well (reference).

One of the ways to don't make the application code be responsible to insert, update and delete the data in the fts indexes tables is to use triggers, as exemplified in the SQLite docs:

-- Create a table. And an external content fts5 table to index it.
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
CREATE VIRTUAL TABLE fts_idx USING fts5(b, c, content='t1', content_rowid='a');

-- Triggers to keep the FTS index up to date.
CREATE TRIGGER t1_ai AFTER INSERT ON t1 BEGIN
  INSERT INTO fts_idx(rowid, b, c) VALUES (new.a, new.b, new.c);
END;
CREATE TRIGGER t1_ad AFTER DELETE ON t1 BEGIN
  INSERT INTO fts_idx(fts_idx, rowid, b, c) VALUES('delete', old.a, old.b, old.c);
END;
CREATE TRIGGER t1_au AFTER UPDATE ON t1 BEGIN
  INSERT INTO fts_idx(fts_idx, rowid, b, c) VALUES('delete', old.a, old.b, old.c);
  INSERT INTO fts_idx(rowid, b, c) VALUES (new.a, new.b, new.c);
END;

Using triggers makes the DB itself to be responsible to update the fts table, which makes it a better approach to don't depend on adding additional queries on each entity in the application that needs to be searchable.

The problem is the NuxtHub custom migration code seems to be breaking the migration file into multiple lines even inside the trigger code, which makes the migration to fail. I've taken a look into the Hub code, and it seems the culprit is the splitSqlQueries function. As the splitSqlQueries splits the migration statements, and it passes each splitted line to a prepared statement, it seems to not work as the prepared statement should include all of the trigger code instead, I assume.

In the end, the migration never gets applied and I always get a "Failed to apply query" error accusing incomplete commands on console.

Digging dipper, I copied the splitSqlQueries into a custom .js file (Gist) and have run it with the SQLite example given above, and it results as follows:

[
  "CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);",

  "CREATE VIRTUAL TABLE fts_idx USING fts5(b, c, content='t1', content_rowid='a');",

  "CREATE TRIGGER t1_ai AFTER INSERT ON t1 BEGIN\n  INSERT INTO fts_idx(rowid, b, c) VALUES (new.a, new.b, new.c);",

  "END;",

  "CREATE TRIGGER t1_ad AFTER DELETE ON t1 BEGIN\n  INSERT INTO fts_idx(fts_idx, rowid, b, c) VALUES('delete', old.a, old.b, old.c);",

  "END;",

  "CREATE TRIGGER t1_au AFTER UPDATE ON t1 BEGIN\n  INSERT INTO fts_idx(fts_idx, rowid, b, c) VALUES('delete', old.a, old.b, old.c);",

  "INSERT INTO fts_idx(rowid, b, c) VALUES (new.a, new.b, new.c);",

  "END;"
]

As it can be seen, the trigger is break within multiple separated statements to be executed. I've found #372, but even if the entire migration code is in one line, it still returns the same error.

Steps to reproduce
Steps to reproduce the behavior:

  1. Create a custom Drizzle migration with triggers that use multiple statements.
  2. Restart the project so the migrations can be applied.
  3. The migration fail to be applied.

Expected behavior
The migration should apply correctly.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions