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
21.52k stars 487 forks source link

[BUG]: [SQLITE] Push command show SQL to apply with no schema changes #2560

Open Haaxor1689 opened 6 days ago

Haaxor1689 commented 6 days ago

What version of drizzle-orm are you using?

0.31.2

What version of drizzle-kit are you using?

0.22.7

Describe the Bug

On previous drizzle version there was this bug with sqlite integer field in boolean mode did not handle default value correctly so I used 0 as never as a workaround. Now that it correctly handles false for a default value, drizzle-kit push wants to apply SQL commands to the database, (supposedly) successfully finishes and then running push shows the same SQL again.

Old schema on older drizzle version:

export const talentTrees = sqliteTable(
    'talentTree',
    {
        id: text('id', { length: 36 })
            .primaryKey()
            .$default(() => nanoid(10)),
        name: text('name', { length: 255 }).notNull(),
        public: integer('public', { mode: 'boolean' }).default(0 as never).notNull(),
        notes: text('notes'),
        class: integer('class').default(0).notNull(),
        icon: text('icon', { length: 255 })
            .default('inv_misc_questionmark')
            .notNull(),
        tree: text('tree', { mode: 'json' })
            .default('[]')
            .notNull()
            .$type<TalentTreeT>(),
        createdById: text('createdById', { length: 255 }).notNull(),
        createdAt: integer('createdAt', { mode: 'timestamp' }).notNull(),
        updatedAt: integer('updatedAt', { mode: 'timestamp' })
    },
    example => ({
        createdByIdIdx: index('trees_createdById_idx').on(example.createdById),
        nameIndex: index('trees_name_idx').on(example.name),
        publicIndex: index('trees_public_idx').on(example.public)
    })
);

New schema on current drizzle version:

export const talentTrees = sqliteTable(
    'talentTree',
    {
        id: text('id', { length: 36 })
            .primaryKey()
            .$default(() => nanoid(10)),
        name: text('name', { length: 255 }).notNull(),
        public: integer('public', { mode: 'boolean' }).default(false).notNull(),
        notes: text('notes'),
        class: integer('class').default(0).notNull(),
        icon: text('icon', { length: 255 })
            .default('inv_misc_questionmark')
            .notNull(),
        tree: text('tree', { mode: 'json' })
            .default('[]')
            .notNull()
            .$type<TalentTreeT>(),
        createdById: text('createdById', { length: 255 }).notNull(),
        createdAt: integer('createdAt', { mode: 'timestamp' }).notNull(),
        updatedAt: integer('updatedAt', { mode: 'timestamp' })
    },
    example => ({
        createdByIdIdx: index('trees_createdById_idx').on(example.createdById),
        nameIndex: index('trees_name_idx').on(example.name),
        publicIndex: index('trees_public_idx').on(example.public)
    })
);

SQL generated by push (seen with --verbose):

CREATE INDEX `trees_createdById_idx` ON `talent-builder_talentTree` (`createdById`);
CREATE INDEX `trees_name_idx` ON `talent-builder_talentTree` (`name`);
CREATE INDEX `trees_public_idx` ON `talent-builder_talentTree` (`public`);
ALTER TABLE `talent-builder_talentTree` RENAME TO `__old_push_talent-builder_talentTree`;
CREATE TABLE `talent-builder_talentTree` (
        `id` text(128) PRIMARY KEY NOT NULL,
        `name` text(256) DEFAULT 'New talent tree' NOT NULL,
        `public` integer DEFAULT 0 NOT NULL,
        `class` integer DEFAULT 0 NOT NULL,
        `icon` text(256) DEFAULT 'inv_misc_questionmark' NOT NULL,
        `tree` text DEFAULT '[]' NOT NULL,
        `createdById` text(255) NOT NULL,
        `createdAt` integer NOT NULL,
        `updatedAt` integer,
        `notes` text
);

INSERT INTO "talent-builder_talentTree" SELECT * FROM "__old_push_talent-builder_talentTree";
DROP TABLE `__old_push_talent-builder_talentTree`;

Expected behavior

It should not detect this as a change OR fix whatever it is detecting as a change and work again properly.

Environment & setup

No response

Haaxor1689 commented 6 days ago

Upon some further investigation on a fresh local DB, it all seems to work, just the production turso DB I'm connecting to does not want to get fixed by push.

Haaxor1689 commented 6 days ago

Also I was getting a warning about the table needing to be dropped because it's not null and missing a default value when I tried adding a new column although the column definition was orderIndex: integer('orderIndex').default(0).notNull()

Haaxor1689 commented 2 days ago

Update: I've found a workaround. With strict and verbose flags enabled, I was able to see the SQL that the drizzle-kit is trying to apply and then manually apply relevant queries myself directly.