Skip to content

feat(postgres,cocroach): added replica identity#5868

Open
letstri wants to merge 2 commits into
drizzle-team:rc4from
letstri:rc4
Open

feat(postgres,cocroach): added replica identity#5868
letstri wants to merge 2 commits into
drizzle-team:rc4from
letstri:rc4

Conversation

@letstri

@letstri letstri commented Jun 10, 2026

Copy link
Copy Markdown

Summary

Adds a chained .replicaIdentity(...) table method to pgTable and cockroachTable, mirroring the existing .enableRLS() / .withRLS() ergonomics. It maps to Postgres ALTER TABLE ... REPLICA IDENTITY { DEFAULT | FULL | NOTHING | USING INDEX <name> } and is wired end-to-end through drizzle-kit (schema → DDL, snapshot, diff/migrate, push, introspect/pull, and codegen) for both the postgres and cockroach dialects.

// drizzle-orm
export const users = pgTable('users', {
  id: integer().primaryKey(),
}).replicaIdentity('full'); // 'default' | 'full' | 'nothing'

export const posts = pgTable('posts', {
  id: integer().primaryKey(),
  email: text().notNull(),
}, (t) => [uniqueIndex('posts_email_idx').on(t.email)])
  .replicaIdentity({ usingIndex: 'posts_email_idx' });

Type: 'default' | 'full' | 'nothing' | { usingIndex: string }. Omitting the call (or 'default') keeps the database default. The value is exposed on getTableConfig(table).replicaIdentity.

What changed

drizzle-orm (pg-core + cockroach-core)

  • New ReplicaIdentity symbol and PgReplicaIdentity / CockroachReplicaIdentity types.
  • Chained .replicaIdentity() builder on the table instance (alongside enableRLS), plus the corresponding field on PgTableWithColumns / CockroachTableWithColumns.
  • getTableConfig() now returns replicaIdentity.

drizzle-kit (postgres + cockroach dialects)

  • DDL tables entity gains replicaIdentity modeled as a nullable { type: 'full' | 'nothing' | 'index'; index: string | null }, where nullDEFAULT (so existing snapshots/entities deserialize without churn).
  • Schema → DDL mapping (drizzle.ts), snapshot serialization, and legacy snapshot upgrade (versions.ts).
  • New alter_replica_identity JSON statement + convertor emitting ALTER TABLE ... REPLICA IDENTITY ..., registered in the convertor list and commutativity rules.
  • Diffing emits the statement for created tables (non-default identity) and for changed tables. The USING INDEX form is intentionally ordered after index creation so the referenced index exists.
  • DB introspection reads pg_class.relreplident plus the pg_index.indisreplident index name (introspect.ts, aws-introspect.ts, duckdb-introspect.ts).
  • Pull codegen appends .replicaIdentity(...) (typescript.ts).

Why the nullable single-field model

REPLICA IDENTITY has four forms but only USING INDEX carries extra data. Storing it as one nullable object (null = DEFAULT) keeps DEFAULT and 'default' from being two distinct states, lets the diff engine detect changes field-by-field, and avoids touching every existing table-entity construction site beyond adding the field where isRlsEnabled already lives.

Test plan

New tests assert SQL generation and a real round-trip:

  • drizzle-kit/tests/postgres/pg-tables.test.ts — 5 tests run against in-process PGlite (real Postgres): create-with-full, default → full, full → nothing, full → default (reset), and USING INDEX (verifies the ALTER is emitted after the CREATE UNIQUE INDEX). Each pairs diff() (statement gen) with push() (executes against PGlite).
  • drizzle-kit/tests/cockroach/replica-identity.test.ts — 4 DB-free diff() tests for the Cockroach dialect.
  • integration-tests/tests/pg/utils.test.tsgetTableConfig().replicaIdentity for all four forms.
  • Updated existing introspection expectations in pull.test.ts and the table-entity literals in commutativity.test.ts / hints-probe-skip.test.ts / studio-postgres.ts to carry the new field (same pattern as isRlsEnabled).

Empirical results on the affected suites:

Suite Result
drizzle-kit/tests/postgres/pg-tables.test.ts (replica identity, PGlite) 5 passed
drizzle-kit/tests/postgres/pull.test.ts (introspection round-trip) 72 passed | 3 skipped
drizzle-kit/tests/cockroach/replica-identity.test.ts (DB-free) 4 passed
integration-tests/tests/pg/utils.test.ts -t replicaIdentity 1 passed
Full drizzle-kit postgres suite 734 passed | 7 skipped (2 failures are pre-existing PostGIS tests needing POSTGIS_URL)

Compliance

  • drizzle-kit tsc -p tsconfig.typetest.json: clean (0 errors).
  • drizzle-orm test:types (type-tests): clean (0 errors).
  • oxlint on all changed drizzle-orm and drizzle-kit sources: 0 warnings, 0 errors.
  • dprint fmt applied to all changed files.

Note on CockroachDB

REPLICA IDENTITY is a Postgres logical-replication feature. The Cockroach dialect mirrors the Postgres implementation per request (the ORM API and kit codegen are symmetric), but the generated ALTER TABLE ... REPLICA IDENTITY may be rejected at runtime depending on CockroachDB version — the Cockroach tests cover only the SQL-generation path, not execution against a live CockroachDB.

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