Skip to content

chore: add Drizzle schema and generated migrations for default and per-server databases#7395

Open
diegolmello wants to merge 4 commits into
feat/native-1272-sqlcipher-migrationfrom
feat/native-1275-drizzle-schema
Open

chore: add Drizzle schema and generated migrations for default and per-server databases#7395
diegolmello wants to merge 4 commits into
feat/native-1272-sqlcipher-migrationfrom
feat/native-1275-drizzle-schema

Conversation

@diegolmello

@diegolmello diegolmello commented Jun 13, 2026

Copy link
Copy Markdown
Member

Proposed changes

First code step of the WatermelonDB → expo-sqlite + Drizzle migration: adds the Drizzle ORM schema definitions and generated SQL migrations for both databases, plus the drizzle-kit tooling configs. No runtime behavior changes — nothing imports these modules yet.

  • Schemas (app/lib/database/driver/schema/):
    • app.ts — the 13 per-server tables (messages, subscriptions, rooms, threads, thread_messages, custom_emojis, frequently_used_emojis, uploads, settings, roles, permissions, slash_commands, users) with exact WatermelonDB table/column name parity.
    • servers.ts — the 3 default-database tables (servers, users, servers_history).
    • index.ts — typed exports and table registries for both database kinds.
  • Generated migrations (app/lib/database/driver/migrations/): drizzle-kit output (SQL + snapshots + journal + migrations.js for the expo driver), one folder per database.
  • Configs: drizzle.app.config.ts / drizzle.servers.config.ts (dialect sqlite, driver expo).
  • Dependencies: drizzle-orm 0.45.2 (runtime), drizzle-kit 0.31.10 (dev).

Schema decisions (from the migration PRD):

  • Sync bookkeeping columns (_status, _changed) are dropped — the new layer does not use WatermelonDB's sync protocol.
  • All columns are nullable except the id text primary keys, matching WatermelonDB's actual SQLite DDL (it emits no NOT NULL constraints on data columns), so the wipe-and-restore migration can re-insert any legacy row without constraint failures.
  • JSON-shaped columns stay as text for now; typed accessors come with the data-access facade work.

Issue(s)

https://rocketchat.atlassian.net/browse/NATIVE-1275

How to test or reproduce

  • TZ=UTC pnpm test app/lib/database/driver — schema tests assert table/column parity against the WatermelonDB schema and pin the generated SQL shapes of representative queries.
  • pnpm exec tsc --noEmit -p . — type-checks the schema exports.
  • Regenerating migrations with pnpm exec drizzle-kit generate --config drizzle.app.config.ts (and the servers config) produces no diff.

Screenshots

N/A — no UI changes.

Types of changes

  • Bugfix (non-breaking change which fixes an issue)
  • Improvement (non-breaking change which improves a current function)
  • New feature (non-breaking change which adds functionality)
  • Documentation update (if none of the other choices apply)

Checklist

  • I have read the CONTRIBUTING doc
  • I have signed the CLA
  • Lint and unit tests pass locally with my changes
  • I have added tests that prove my fix is effective or that my feature works (if applicable)
  • I have added necessary documentation (if applicable)
  • Any dependent changes have been merged and published in downstream modules

Further comments

Part of the WatermelonDB replacement track. The driver adapter (connection lifecycle, SQLCipher keying, live-query hooks) follows in a separate PR built on top of this one.

Summary by CodeRabbit

  • Chores
    • Initialized database infrastructure using SQLite and Drizzle ORM to support persistent storage of chat messages, user profiles, server configurations, rooms, threads, subscriptions, and related application data.
    • Implemented database migration system for managing schema updates and ensuring data consistency across application versions.
    • Added required development tools and dependencies for database operations.

@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: dff5e924-00bb-40c6-b81b-9ce3333383e1

📥 Commits

Reviewing files that changed from the base of the PR and between b23efd3 and 56d87d8.

📒 Files selected for processing (8)
  • app/lib/database/driver/migrations/app/0000_wise_mockingbird.sql
  • app/lib/database/driver/migrations/app/meta/0000_snapshot.json
  • app/lib/database/driver/migrations/app/meta/_journal.json
  • app/lib/database/driver/migrations/app/migrations.js
  • app/lib/database/driver/migrations/servers/0000_puzzling_colleen_wing.sql
  • app/lib/database/driver/migrations/servers/meta/0000_snapshot.json
  • app/lib/database/driver/migrations/servers/meta/_journal.json
  • app/lib/database/driver/migrations/servers/migrations.js
✅ Files skipped from review due to trivial changes (2)
  • app/lib/database/driver/migrations/servers/meta/_journal.json
  • app/lib/database/driver/migrations/servers/meta/0000_snapshot.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/lib/database/driver/migrations/app/meta/0000_snapshot.json
📜 Recent review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: ESLint and Test / run-eslint-and-test
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,ts,jsx,tsx}: Use descriptive names for functions, variables, and classes that clearly convey their purpose
Write comments that explain the 'why' behind code decisions, not the 'what'
Keep functions small and focused on a single responsibility
Use const by default, let when reassignment is needed, and avoid var
Prefer async/await over .then() chains for handling asynchronous operations
Use explicit error handling with try/catch blocks for async operations
Avoid deeply nested code; refactor complex logic into helper functions

Files:

  • app/lib/database/driver/migrations/servers/migrations.js
  • app/lib/database/driver/migrations/app/migrations.js
**/*.{js,jsx,ts,tsx,json}

📄 CodeRabbit inference engine (CLAUDE.md)

Use Prettier formatting with tabs, single quotes, 130 character line width, no trailing commas, and avoid arrow function parentheses

Files:

  • app/lib/database/driver/migrations/servers/migrations.js
  • app/lib/database/driver/migrations/app/meta/_journal.json
  • app/lib/database/driver/migrations/app/migrations.js
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Enforce ESLint rules from @rocket.chat/eslint-config with React, React Native, TypeScript, and Jest plugins

Files:

  • app/lib/database/driver/migrations/servers/migrations.js
  • app/lib/database/driver/migrations/app/migrations.js
🔇 Additional comments (5)
app/lib/database/driver/migrations/app/meta/_journal.json (1)

8-9: LGTM!

app/lib/database/driver/migrations/app/migrations.js (1)

4-10: LGTM!

app/lib/database/driver/migrations/servers/0000_puzzling_colleen_wing.sql (1)

3-5: LGTM!

app/lib/database/driver/migrations/servers/migrations.js (1)

4-10: LGTM!

app/lib/database/driver/migrations/app/0000_wise_mockingbird.sql (1)

5-6: Migrations and schemas are already aligned; external PR context needed to validate design decision claim.

The 0000_wise_mockingbird.sql and app.ts schema definitions are consistent—both mark extension and _updated_at as NOT NULL. However, the claim about a conflicting design decision ("all columns nullable except id") cannot be verified from the codebase. No design documentation, ADR, or schema guide exists supporting this constraint. The actual pattern is selective: metadata columns (_updated_at, ts), foreign keys (rid, team_id), and specific flags are NOT NULL; optional content is nullable. This appears intentional, not problematic. To validate the concern, confirm whether the referenced PR context actually specifies "all columns nullable" or if that was a mischaracterization.

			> Likely an incorrect or invalid review comment.

Walkthrough

Introduces Drizzle ORM as the database layer for two separate SQLite databases (app and servers). Adds TypeScript schema definitions for 16 tables total, generates initial SQL migrations and Drizzle Kit snapshots for both databases, wires Expo migration entry points, exports row type aliases via a central schema index, and validates query shapes with a Jest test suite.

Changes

Drizzle ORM Database Infrastructure

Layer / File(s) Summary
Tooling, Configuration, and Dependencies
package.json, drizzle.app.config.ts, drizzle.servers.config.ts, .eslintignore, .prettierignore
Adds drizzle-orm and drizzle-kit to package.json. Configures Drizzle Kit for both app and servers SQLite databases using the Expo driver. Excludes the migrations directory from ESLint and Prettier.
App Database Schema Definitions (13 Tables)
app/lib/database/driver/schema/app.ts
Defines 13 SQLite table schemas for app-scoped data: subscriptions (indexed on t, name, rid, team_id), rooms, shared messageColumns, messages, threads, threadMessages, customEmojis, frequentlyUsedEmojis, uploads, settings, roles, permissions, slashCommands, and usersApp—all with per-table indexes.
Servers Database Schema Definitions (3 Tables)
app/lib/database/driver/schema/servers.ts
Defines 3 SQLite table schemas for server-scoped data: usersServersTable, serversTable, and serversHistoryTable (with a url index).
Central Schema Export and Type Aliases
app/lib/database/driver/schema/index.ts
Re-exports all 16 table definitions and declares T...Row type aliases derived from InferSelectModel for every table.
App Initial Migration (0000), Snapshot, and Entry Point
app/lib/database/driver/migrations/app/0000_wise_mockingbird.sql, app/lib/database/driver/migrations/app/meta/*, app/lib/database/driver/migrations/app/migrations.js
SQL DDL creates all 13 app tables with columns and indexes. Snapshot JSON and journal JSON record schema state and migration version. migrations.js entry point wires journal and m0000 for Expo runtime execution.
Servers Initial Migration (0000), Snapshot, and Entry Point
app/lib/database/driver/migrations/servers/0000_puzzling_colleen_wing.sql, app/lib/database/driver/migrations/servers/meta/*, app/lib/database/driver/migrations/servers/migrations.js
SQL DDL creates all 3 servers tables with columns and indexes. Snapshot JSON and journal JSON record schema state and migration version. migrations.js entry point wires journal and m0000 for Expo runtime execution.
Query Shape Validation Tests
app/lib/database/driver/schema/__tests__/queryShapes.test.ts
Jest test suite validates Drizzle SQL query generation for subscriptions, messages, threads, custom emojis, users, and permissions tables, asserting SQL clause fragments and parameter bindings.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: adding Drizzle ORM schema definitions and generated migrations for both app and server databases. It is concise, specific, and directly reflects the changeset content.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • NATIVE-1275: Request failed with status code 401

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@diegolmello diegolmello left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Structural review (NATIVE-1275). Schema is column-complete vs the WatermelonDB source and the generated migrations are clean drizzle-kit output (no hand-edits). Two findings worth acting on before merge are inline below.

Minor notes, not blocking: the two near-identical drizzle.app.config.ts / drizzle.servers.config.ts exist only because drizzle-kit takes one schema target per config — a one-line comment saying so would stop a future "dedupe" that breaks generation. The mixed indentation in migrations/*/migrations.js is drizzle-kit's own Expo-template output (both files are prettier-ignored), so it's not actionable.

Comment thread app/lib/database/driver/schema/app.ts
Comment thread app/lib/database/driver/schema/app.ts Outdated
Comment thread app/lib/database/driver/schema/index.ts

@diegolmello diegolmello left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Review: Drizzle schema + generated migrations

Schema-only foundation; nothing imports it yet. Quality is high — I diffed all 16 tables (13 per-server + 3 servers-db) column-by-column against the WatermelonDB schemas in app/lib/database/schema/ and found full parity: no missing tables, no missing columns, correct SQLite affinities (incl. real() for the WMDB number/boolean cases), and every WMDB index reproduced. The deliberate choices (universal nullability, keeping verbatim SQLite column names) are clearly motivated.

Findings are all minor / process-level, no inline anchors needed:

🟡 [medium] No db:generate npm script for either config — the test instructions tell reviewers to run pnpm exec drizzle-kit generate --config drizzle.app.config.ts (and the servers variant) by hand. A "db:generate:app" / "db:generate:servers" pair makes the regenerate→diff loop repeatable for the next PR author.

🟡 [medium] The servers schema (serversTable, usersServersTable, serversHistoryTable) has zero query-shape test coverage — queryShapes.test.ts imports only from ./app. Add at least one serversTable and one usersServersTable lookup so a future divergence is caught.

🟢 [low] Generated files (*.sql, _journal.json, migrations.js, 0000_snapshot.json) have no trailing newline and are in .eslintignore/.prettierignore, so the hook won't fix them — expect noisy diffs on every regeneration unless normalised.

🟢 [low] All *_at/ts/ls timestamp columns are real() (correct WMDB parity — they store integer epoch-ms in a REAL-affinity column). Worth a one-line schema comment so accessor authors don't expect a Date.

Open question for the wipe-and-restore migration (not this PR): WMDB non-optional string columns default to '' on insert, never NULL, but the Drizzle schema makes them all nullable; and users_count was a WMDB string historically, now read as a number. When legacy rows are copied, watch for '' → NULL and '' → NaN/0 drift where downstream code does === '' checks.

Reviewed by an automated pass; treat comments as suggestions, not blockers.

@diegolmello diegolmello changed the base branch from develop to feat/native-1272-sqlcipher-migration June 19, 2026 15:11
…unused Insert types

- Extract shared messageColumns object spread into messagesTable, threadsTable,
  and threadMessagesTable; table-specific fields (tmid/tmsg/blocks/tshow/md/comment
  for messages; tmid/draft_message for threads; subscription_id for thread_messages)
  added per-table. messages.alias and messages.parse_urls override the shared
  nullable default to notNull.
- Add .notNull() to all columns whose WMDB counterpart lacks isOptional, across
  subscriptions, rooms, messages, threads, thread_messages, custom_emojis,
  frequently_used_emojis, uploads, permissions, users (app), and servers_history.
- Remove 16 TXxxInsert aliases (InferInsertModel-based) from index.ts; none are
  consumed in this or any stacked branch.
- Regenerate Drizzle migrations (drizzle-kit generate) for both app and servers
  schemas; new SQL files and snapshots committed.

Claude-Session: https://claude.ai/code/session_01TE9VsFTeXsXc8ssqeR8MJ7
…into 0000

Replace the two-migration sequence (0000 nullable + 0001 ALTER) with a single
0000 baseline that already carries all NOT NULL columns. Nothing has shipped,
so there are no existing databases to migrate from the old 0000.

App:   0000_wise_mockingbird.sql
Servers: 0000_puzzling_colleen_wing.sql

Claude-Session: https://claude.ai/code/session_01TE9VsFTeXsXc8ssqeR8MJ7
@github-actions

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

iOS Build Available

Rocket.Chat 4.74.0.109171

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant