Skip to content

fix(sqlite-kit): preserve NOT NULL on non-integer primary key columns - #6168

Open
webdevsamran wants to merge 1 commit into
drizzle-team:betafrom
webdevsamran:fix/sqlite-text-pk-notnull
Open

fix(sqlite-kit): preserve NOT NULL on non-integer primary key columns#6168
webdevsamran wants to merge 1 commit into
drizzle-team:betafrom
webdevsamran:fix/sqlite-text-pk-notnull

Conversation

@webdevsamran

Copy link
Copy Markdown

Summary

Fixes #6165.

On the v1 (beta) line, drizzle-kit generate drops NOT NULL from every primary-key column when serializing a Drizzle schema into the interim/snapshot representation:

  • drizzle-kit/src/dialects/sqlite/drizzle.ts: notNull: column.notNull && !primaryKey
  • drizzle-kit/src/cli/commands/up-sqlite.ts (v6→v7 upgrader): notNull: column.notNull && !column.primaryKey

Since SQLite only enforces non-NULL values on INTEGER PRIMARY KEY columns (rowid alias), NOT NULL is load-bearing for every other PK shape — text('id').primaryKey() produced:

CREATE TABLE `users` (
	`id` text PRIMARY KEY
);

which silently allows NULL ids — a regression from 0.31 behavior and a data-integrity hazard for anyone who doesn't hand-patch their migrations.

The DDL convertor (drizzle-kit/src/dialects/sqlite/convertor.ts) already implements the correct SQLite-specific rule: it omits NOT NULL only for single-column integer PKs (omitNotNull = isColumnPk && column.type.toLowerCase().startsWith('int')). The serializer stripping the flag upstream of it made that logic unreachable for PK columns. This change makes the serializer faithful (notNull: column.notNull) and lets the convertor keep deciding what to emit, which:

  • restores NOT NULL for TEXT/BLOB/REAL/INT PKs and any explicitly .notNull() PK column,
  • keeps omitting redundant NOT NULL for single-column integer().primaryKey() (the behavior requested in [FEATURE]: SQLite .primaryKey().notNull() #2611),
  • keeps upgraded (v6→v7) snapshots consistent with freshly generated ones.

Reproduction (before)

With drizzle-orm@1.0.0-rc.4 + drizzle-kit@1.0.0-rc.4:

// schema.ts
import { sqliteTable, text } from 'drizzle-orm/sqlite-core';
export const users = sqliteTable('users', { id: text('id').primaryKey() });

npx drizzle-kit generate`id` text PRIMARY KEY (no NOT NULL; verified: SQLite accepts INSERT INTO users VALUES (NULL)).

Testing

New regression tests in drizzle-kit/tests/sqlite/sqlite-pk-notnull.test.ts:

  • text PK keeps notNull: true in the serialized schema
  • generated SQL emits `id` text PRIMARY KEY NOT NULL for text PKs
  • generated SQL still emits `id` integer PRIMARY KEY without NOT NULL for single-column integer PKs
✓ tests/sqlite/sqlite-pk-notnull.test.ts (3 tests) 5ms

 Test Files  1 passed (1)
      Tests  3 passed (3)

Verified red→green: with the fix stashed, 2 of the 3 new tests fail; with the fix applied all pass. Full tests/sqlite/ suite comparison on this machine (Windows checkout lacks a better-sqlite3 prebuilt for Node 24, so DB-backed suites fail identically before and after the change): clean beta → 23 failed / 21 passed; with this change → 21 failed / 23 passed (+2 = the new regression tests; no previously passing test regressed).

oxlint clean on all changed files.

SQLite only enforces NOT NULL on INTEGER PRIMARY KEY columns; for every other PK shape (TEXT/BLOB/REAL, INT, composite) NULLs are allowed, so the flag is load-bearing. The v1 schema serializer and the v6->v7 snapshot upgrader stripped notNull from all primary key columns, so generated migrations emitted nullable text primary keys (regression from 0.31 behavior). The DDL convertor already omits NOT NULL for single-column integer PKs, so preserving the flag here keeps that behavior intact while restoring NOT NULL everywhere else.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0c9191c0d1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

type: column.getSQLType(),
default: defalutValue,
notNull: column.notNull && !primaryKey,
notNull: column.notNull,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Emit a migration for existing nullable primary keys

For projects whose existing v7 snapshot or database was produced by the buggy release, this changes the desired text-PK column from notNull: false to true, but ddlDiff unconditionally deletes every single-column primary-key notNull alteration in drizzle-kit/src/dialects/sqlite/diff.ts:259-260. Both generate and push therefore emit no table recreation, and generate records the new snapshot as non-null despite leaving the actual column nullable, so affected databases are never repaired. Restrict that suppression to actual INTEGER PRIMARY KEY rowid aliases so non-integer PKs receive a corrective migration.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant