drizzle-team / drizzle-orm

Headless TypeScript ORM with a head. Runs on Node, Bun and Deno. Lives on the Edge and yes, it's a JavaScript ORM too 😅
https://orm.drizzle.team
Apache License 2.0
24.43k stars 641 forks source link

Improper escaping of string containing quotes for `introspect` on SQLite (libsql) #3412

Open bradobro opened 6 months ago

bradobro commented 6 months ago

Summary: pulling schema from a local SQLite database creates schema statements that don't parse as TypeScript.

Example:

// generates field definitions including this:
{
    type: text("type").default("sql`("base")`").notNull(),
        //  unescaped double quotes:     ^        ^  break parsing.  
}

Environment:

Package Versions: "drizzle-kit": "^0.21.2" "drizzle-orm": "^0.30.10" "@libsql/client": "^0.6.0" "typescript": "^5.0.0"

Runtimes:

OS/Hardware:

Recreating Here's a SQL to create a table that will cause some offenders:

CREATE TABLE `_collections` (
                `id`         TEXT PRIMARY KEY NOT NULL,
                `system`     BOOLEAN DEFAULT FALSE NOT NULL,
                `type`       TEXT DEFAULT "base" NOT NULL,
                `created` TEXT DEFAULT "" NOT NULL,
                `updated` TEXT DEFAULT "" NOT NULL,
                `name`       TEXT UNIQUE NOT NULL,
                `schema`     JSON DEFAULT "[]" NOT NULL,
                `indexes`    JSON DEFAULT "[]" NOT NULL,
                `listRule`   TEXT DEFAULT NULL,
                `viewRule`   TEXT DEFAULT NULL,
                `createRule` TEXT DEFAULT NULL,
                `updateRule` TEXT DEFAULT NULL,
                `deleteRule` TEXT DEFAULT NULL,
                `options`    JSON DEFAULT "{}" NOT NULL
            );
bradobro commented 6 months ago

I suspect the real culprit is the software creating the table, that if it had used single quotes for the default strings drizzle-kit would have generated valid code.

But SQLite seems to allow--and preserve--this, which isn't likely to change quickly.

I wonder if there's a simple but robust workaround for this? Maybe generate code for strings with JSON.stringify(thestring);?

For example:

const desiredString = 'sql`("base")`';
const jsonString = JSON.stringify(desiredString);
console.log(desiredString, jsonVersion);
// output: sql`("base")` "sql`(\"base\")`"