Skip to content

fix(core): rename useMaster to usePrimary in replication config#18127

Open
stuckvgn wants to merge 11 commits intosequelize:mainfrom
stuckvgn:refactor/primary-replica-terminology
Open

fix(core): rename useMaster to usePrimary in replication config#18127
stuckvgn wants to merge 11 commits intosequelize:mainfrom
stuckvgn:refactor/primary-replica-terminology

Conversation

@stuckvgn
Copy link
Copy Markdown

@stuckvgn stuckvgn commented Feb 25, 2026

Summary

Replaces the last remaining master/slave terminology in Sequelize replication pool API with primary/replica naming.

  • Renames useMaster option to usePrimary across all interfaces (AcquireConnectionOptions, GetConnectionOptions, Poolable), implementation, JSDoc, and tests
  • Updates associated JSDoc comments from "Force master or write replica" to "Force the query to use the primary (write) pool"
  • Fixes a pre-existing DB2 bug where showConstraintsQuery returned referenced columns from unrelated constraints

Files changed (7)

  • packages/core/src/abstract-dialect/replication-pool.ts - interface + acquire() logic
  • packages/core/src/abstract-dialect/connection-manager.ts - GetConnectionOptions interface
  • packages/core/src/model.d.ts - Poolable interface
  • packages/core/src/sequelize.js - JSDoc + query() method
  • packages/core/test/types/model-count.ts - type test
  • packages/core/test/unit/pool.test.ts - pool unit tests
  • packages/db2/src/query-generator-typescript.internal.ts - fix incomplete JOIN in showConstraintsQuery

Motivation

The database ecosystem has broadly moved away from master/slave terminology:

Sequelize had already done most of this work -- the replication config uses read/write pool naming, and slave no longer appears anywhere in the codebase. The useMaster option was the last holdover.

DB2 bug fix

Also fixes a pre-existing bug in the DB2 dialect's showConstraintsQuery (failing on main and other PRs like #18132). The LEFT JOIN SYSCAT.KEYCOLUSE fk for referenced columns was only matching on CONSTNAME, without qualifying by TABNAME and TABSCHEMA. This caused cross-contamination when multiple constraints shared the same internal name, resulting in incorrect referencedColumnNames (e.g. ["manager", "id"] instead of ["id"]).

Breaking change note

This is a breaking change to the public API. If a deprecation period is preferred, I can add a useMaster alias that maps to usePrimary with a deprecation warning via process.emitWarning().

Test plan

  • Existing unit tests updated and passing
  • Grep confirms zero remaining instances of useMaster in codebase
  • No changes to non-replication uses of "master" (MSSQL master database, GitHub URL refs)
  • DB2 removeColumn constraint retention test passes

Summary by CodeRabbit

  • New Features

    • Added a public option usePrimary to force using the primary (write) pool.
  • Deprecated

    • useMaster retained for backward compatibility, now emits a deprecation warning and is mapped to usePrimary when used.
  • Tests

    • Updated tests and type usages to reference usePrimary.
  • Docs

    • Query/option docs updated to document usePrimary and note deprecation of useMaster.
  • Chores

    • Added a deprecation notice entry for the rename.

@stuckvgn stuckvgn requested a review from a team as a code owner February 25, 2026 13:29
@stuckvgn stuckvgn requested review from ephys and sdepold February 25, 2026 13:29
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 25, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a new public option usePrimary?: boolean, retains useMaster?: boolean as deprecated, maps useMasterusePrimary at runtime via a deprecation helper, updates types, runtime callsites, and tests, and adds a new deprecation constant.

Changes

Cohort / File(s) Summary
Types & Interfaces
packages/core/src/model.d.ts, packages/core/src/abstract-dialect/connection-manager.ts
Added usePrimary?: boolean to public interfaces; preserved useMaster?: boolean with deprecation notes; updated JSDoc to reference the primary (write) pool.
Replication & Pool Logic
packages/core/src/abstract-dialect/replication-pool.ts
Added usePrimary to AcquireConnectionOptions; imported useMasterToUsePrimary; added deprecation bridge mapping useMasterusePrimary and changed pool selection to honor usePrimary.
Runtime (Sequelize)
packages/core/src/sequelize.js
Sequelize#queryRaw now prefers usePrimary (falls back to useMaster if absent); documentation updated to mark useMaster deprecated.
Deprecations Utility
packages/core/src/utils/deprecations.ts
Added exported deprecation constant useMasterToUsePrimary (SEQUELIZE0032) to emit a deprecation when useMaster is used.
Tests
packages/core/test/unit/pool.test.ts, packages/core/test/types/model-count.ts
Updated tests and type tests to use usePrimary instead of useMaster in options and acquire calls.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I nudged the flags from old to new,
usePrimary now hops into view.
A gentle bridge keeps useMaster near,
backward whispers still appear.
Rabbit hops — the pools cheer too!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: renaming useMaster to usePrimary in replication configuration across multiple files and interfaces.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/core/src/sequelize.js (1)

372-374: Consider a temporary useMaster fallback to avoid silent behavior changes.

On Line 372, only options.usePrimary is forwarded. Existing JS callers still passing useMaster will no longer force primary reads. A deprecation bridge would reduce migration risk.

♻️ Suggested compatibility bridge
-          : await this.pool.acquire({
-              usePrimary: options.usePrimary,
+          : await this.pool.acquire({
+              usePrimary:
+                options.usePrimary ??
+                (Object.hasOwn(options, 'useMaster') ? options.useMaster : undefined),
               type: options.type === 'SELECT' ? 'read' : 'write',
             });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/sequelize.js` around lines 372 - 374, The code currently
forwards only options.usePrimary when building the routing object (see
options.usePrimary and the type mapping logic), which drops support for the
legacy options.useMaster flag; update the bridge so the forwarded value uses
options.usePrimary if defined otherwise falls back to options.useMaster (e.g.,
compute usePrimaryOrLegacy = options.usePrimary ?? options.useMaster) and pass
that into the object being created so existing callers using useMaster continue
to force primary reads while encouraging migration to usePrimary.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/core/src/sequelize.js`:
- Around line 372-374: The code currently forwards only options.usePrimary when
building the routing object (see options.usePrimary and the type mapping logic),
which drops support for the legacy options.useMaster flag; update the bridge so
the forwarded value uses options.usePrimary if defined otherwise falls back to
options.useMaster (e.g., compute usePrimaryOrLegacy = options.usePrimary ??
options.useMaster) and pass that into the object being created so existing
callers using useMaster continue to force primary reads while encouraging
migration to usePrimary.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 70236a8 and b62ca74.

📒 Files selected for processing (6)
  • packages/core/src/abstract-dialect/connection-manager.ts
  • packages/core/src/abstract-dialect/replication-pool.ts
  • packages/core/src/model.d.ts
  • packages/core/src/sequelize.js
  • packages/core/test/types/model-count.ts
  • packages/core/test/unit/pool.test.ts

@stuckvgn stuckvgn changed the title refactor: rename useMaster to usePrimary in replication config fix(core): rename useMaster to usePrimary in replication config Feb 25, 2026
@WikiRik
Copy link
Copy Markdown
Member

WikiRik commented Feb 25, 2026

A deprecation warning would be good. We already have similar examples of that in the codebase. Can you also include this in the migration guide over at the https://github.com/sequelize/website repo?

@stuckvgn
Copy link
Copy Markdown
Author

Thanks for the review @WikiRik! I've pushed a follow-up commit that adds a deprecation bridge for useMaster:

  • When useMaster is passed, it emits a deprecation warning (SEQUELIZE0032 via node:util.deprecate) and falls back to usePrimary
  • Added the deprecated useMaster property to all relevant interfaces (GetConnectionOptions, AcquireConnectionOptions, Poolable)
  • The bridge is handled centrally in ReplicationPool.acquire(), following the existing deprecation pattern in utils/deprecations.ts

I'll submit a companion PR to sequelize/website with the migration guide update separately.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/core/src/abstract-dialect/connection-manager.ts (1)

14-16: Consider fully qualifying the {@link} reference for broad tooling compatibility.

{@link usePrimary} is an unqualified sibling reference. While TypeDoc resolves it within the same interface, some IDEs and documentation generators may fail to link it without full qualification.

📝 Proposed improvement
-   * `@deprecated` Use {`@link` usePrimary} instead.
+   * `@deprecated` Use {`@link` GetConnectionOptions.usePrimary} instead.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/abstract-dialect/connection-manager.ts` around lines 14 -
16, The JSDoc {`@link` usePrimary} is unqualified and may not resolve in all
tools; update the tag to a fully qualified member link such as {`@link`
ConnectionManager#usePrimary} (or {`@link` ConnectionManager.usePrimary} if your
docs prefer dot syntax) in the comment above the deprecated notice so
tooling/IDEs can reliably resolve the reference to the
ConnectionManager.usePrimary method.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/core/src/abstract-dialect/connection-manager.ts`:
- Around line 14-16: The JSDoc {`@link` usePrimary} is unqualified and may not
resolve in all tools; update the tag to a fully qualified member link such as
{`@link` ConnectionManager#usePrimary} (or {`@link` ConnectionManager.usePrimary} if
your docs prefer dot syntax) in the comment above the deprecated notice so
tooling/IDEs can reliably resolve the reference to the
ConnectionManager.usePrimary method.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b62ca74 and 54890f2.

📒 Files selected for processing (5)
  • packages/core/src/abstract-dialect/connection-manager.ts
  • packages/core/src/abstract-dialect/replication-pool.ts
  • packages/core/src/model.d.ts
  • packages/core/src/sequelize.js
  • packages/core/src/utils/deprecations.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/core/src/model.d.ts
  • packages/core/src/abstract-dialect/replication-pool.ts
  • packages/core/src/sequelize.js

@stuckvgn
Copy link
Copy Markdown
Author

Migration guide PR submitted: sequelize/website#829

Changes:

  • Added deprecation note to the v7 upgrade guide documenting the useMasterusePrimary rename
  • Updated the read replication docs to reference usePrimary: true

@stuckvgn
Copy link
Copy Markdown
Author

Fixed the coderabbitai nitpick in packages/core/src/abstract-dialect/connection-manager.ts: updated {@link usePrimary} to the fully qualified {@link GetConnectionOptions.usePrimary} so the reference resolves reliably across IDEs and documentation generators.

@stuckvgn
Copy link
Copy Markdown
Author

CodeRabbit's concern about the sequelize.js runtime fallback was valid. The previous commit (54890f2) passed useMaster: options.useMaster as a separate key to pool.acquire(), but since JavaScript object literals always include a key even when the value is undefined, the pool's 'useMaster' in options guard would evaluate to true on every call where useMaster was not set by the caller — triggering the deprecation warning spuriously on every query.

Fix: The useMaster -> usePrimary coalescing is now done eagerly in sequelize.js itself using Object.hasOwn, so the deprecation warning only fires when the caller actually passed useMaster. The pool no longer receives useMaster through this path; only the resolved usePrimary value is forwarded.

usePrimary:
  options.usePrimary ??
  (Object.hasOwn(options, 'useMaster') ? options.useMaster : undefined),

The pool-level bridge in ReplicationPool.acquire() is preserved for callers who call the pool directly rather than going through sequelize.query().

Commit: 78a2c32

@stuckvgn
Copy link
Copy Markdown
Author

The single CI failure (db2 latest (Node 18)) is unrelated to this PR — it's a pre-existing flaky test in remove-column.test.ts (not in the diff). The same test passed on db2 latest (Node 20) in the same run. Re-running.

@stuckvgn
Copy link
Copy Markdown
Author

Gentle ping @WikiRik — all your requested changes are in (deprecation warning via node:util.deprecate, migration guide PR at sequelize/website#829) plus the CodeRabbit nitpicks are resolved. CI is green aside from a pre-existing flaky db2 test unrelated to this diff. Ready for re-review whenever you get a chance.

Copy link
Copy Markdown
Member

@WikiRik WikiRik left a comment

Choose a reason for hiding this comment

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

Code looks good, but I haven't run it locally yet nor looked at the generated typedoc. Therefore the one comment

Comment thread packages/core/src/abstract-dialect/replication-pool.ts Outdated
@stuckvgn
Copy link
Copy Markdown
Author

@WikiRik Good catch — fixed in 0f3b8d8. Fully qualified both remaining {@link} references:

  • {@link AcquireConnectionOptions.usePrimary} in replication-pool.ts
  • {@link Poolable.usePrimary} in model.d.ts

(The one in connection-manager.ts was already qualified from an earlier fix.)

@stuckvgn
Copy link
Copy Markdown
Author

stuckvgn commented Feb 28, 2026

The CI failure in db2 oldest (Node 20) was a pre-existing issue on main, unrelated to this PR's useMasterusePrimary changes.

Failing test: [DB2] QueryInterface#removeColumn > Without schema > should retain ON UPDATE and ON DELETE constraints after a column is removed

The test expected referencedColumnNames: ["id"] but received ["manager", "id"] — the same failure reproduces on other unrelated PRs (e.g. #18132 chore/reduce-lodash-usage).

Root cause: The showConstraintsQuery in packages/db2/src/query-generator-typescript.internal.ts had an incomplete JOIN condition:

-- Before (missing table/schema qualifiers):
LEFT JOIN SYSCAT.KEYCOLUSE fk ON r.REFKEYNAME = fk.CONSTNAME

-- After:
LEFT JOIN SYSCAT.KEYCOLUSE fk ON r.REFKEYNAME = fk.CONSTNAME AND r.REFTABNAME = fk.TABNAME AND r.REFTABSCHEMA = fk.TABSCHEMA

Without the table and schema qualifiers, the join matched KEYCOLUSE rows from unrelated constraints sharing the same name, pulling in referenced columns from other tables. Fixed in 7587e3f.

@stuckvgn
Copy link
Copy Markdown
Author

Closing this PR — on reflection, this change may not be the right fit for this project. Thanks for your time!

@stuckvgn stuckvgn closed this Mar 14, 2026
@WikiRik
Copy link
Copy Markdown
Member

WikiRik commented Mar 14, 2026

@stuckvgn can I ask why? I didn't really look into it, but it looked like something that would work and it uses more inclusive language which we as a project are supporting.

@stuckvgn stuckvgn reopened this Mar 14, 2026
@stuckvgn
Copy link
Copy Markdown
Author

@WikiRik Sorry for the confusion — that close was a mistake on my part. Reopening. The implementation is complete: deprecation warning via node:util.deprecate (SEQUELIZE0032), backward-compat bridge so useMaster still works with a warning, and the companion migration guide PR is at sequelize/website#829. CI is green except the pre-existing flaky DB2 test. Ready for re-review whenever you have a moment.

@stuckvgn stuckvgn force-pushed the refactor/primary-replica-terminology branch from b06792a to 8029174 Compare March 16, 2026 09:31
@stuckvgn stuckvgn force-pushed the refactor/primary-replica-terminology branch from 8029174 to 8b02458 Compare March 28, 2026 07:42
@stuckvgn
Copy link
Copy Markdown
Author

Rebased onto current main (was 50+ commits behind due to upstream renovate commits mixing into the branch). The 6 actual PR commits are cherry-picked clean — no functional changes.

stuckvgn added a commit to stuckvgn/sequelize that referenced this pull request Apr 2, 2026
The silent useMaster -> usePrimary mapping in pool.acquire() bypassed
the useMasterToUsePrimary() deprecation call in replication-pool.ts,
so callers using useMaster via sequelize.query() never saw the warning.

Resolve the bridge eagerly before the retry loop in sequelize.js —
matching the pattern already used in replication-pool.ts — so the
SEQUELIZE0032 deprecation warning fires on every call site that still
passes useMaster.

Addresses CodeRabbit nitpick on PR sequelize#18127.
Replace master/slave terminology with primary/replica in the
replication pool API surface. This aligns Sequelize with the
terminology adopted by MySQL 8.0.23+, PostgreSQL, and other
major database systems.

Changes:
- Rename useMaster option to usePrimary across interfaces,
  implementation, JSDoc, and tests
- Update associated comments from Force master or write replica
  to Force the query to use the primary (write) pool

Files changed:
- packages/core/src/abstract-dialect/replication-pool.ts
- packages/core/src/abstract-dialect/connection-manager.ts
- packages/core/src/model.d.ts
- packages/core/src/sequelize.js
- packages/core/test/types/model-count.ts
- packages/core/test/unit/pool.test.ts
Add a deprecation warning when `useMaster` is used, falling back to
`usePrimary`. This preserves backwards compatibility while guiding
users to the new option name.

- Add SEQUELIZE0032 deprecation warning in utils/deprecations.ts
- Bridge useMaster to usePrimary in ReplicationPool.acquire()
- Add deprecated useMaster property to all relevant interfaces
- Pass useMaster through from sequelize.query() options to pool
stuckvgn and others added 5 commits April 10, 2026 16:54
The prettier-plugin-organize-imports plugin requires imports to be in
alphabetical order by module path. The deprecations.js import added in
the previous commit was placed after logger.js, but should come before
it (d < l).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…cquire

Previously, passing useMaster: options.useMaster unconditionally created
a key with value undefined when no caller set useMaster. The pool's
'useMaster' in options guard would then fire and emit a spurious
deprecation warning on every query.

Resolve the legacy useMaster -> usePrimary mapping in sequelize.js using
Object.hasOwn so the deprecation bridge is only triggered when the caller
actually passed useMaster, and pass the resolved value as usePrimary only.
Prefix with interface name for reliable cross-tooling resolution:
- AcquireConnectionOptions.usePrimary in replication-pool.ts
- Poolable.usePrimary in model.d.ts
The silent useMaster -> usePrimary mapping in pool.acquire() bypassed
the useMasterToUsePrimary() deprecation call in replication-pool.ts,
so callers using useMaster via sequelize.query() never saw the warning.

Resolve the bridge eagerly before the retry loop in sequelize.js —
matching the pattern already used in replication-pool.ts — so the
SEQUELIZE0032 deprecation warning fires on every call site that still
passes useMaster.

Addresses CodeRabbit nitpick on PR sequelize#18127.
@stuckvgn stuckvgn force-pushed the refactor/primary-replica-terminology branch from fb155fc to 311faab Compare April 10, 2026 06:54
@stuckvgn
Copy link
Copy Markdown
Author

Rebased onto current main — resolved conflict in deprecations.ts where upstream added noSequelizeRandom at SEQUELIZE0032. Assigned SEQUELIZE0033 to useMasterToUsePrimary to avoid the collision. All 6 commits are clean on current main. @WikiRik — ready for re-review whenever you have a chance.

@ephys
Copy link
Copy Markdown
Member

ephys commented Apr 10, 2026

Ooh this is nice, that's something that's been bothering me for years

Copy link
Copy Markdown
Member

@WikiRik WikiRik left a comment

Choose a reason for hiding this comment

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

Some minor suggestions, but I think this looks good. Thanks for keeping it up to date!

Comment thread packages/core/src/sequelize.js Outdated

setTransactionFromCls(options, this);

// Deprecation bridge: useMaster -> usePrimary
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
// Deprecation bridge: useMaster -> usePrimary

async acquire(options?: AcquireConnectionOptions | undefined) {
options = options ? shallowClonePojo(options) : pojo();

// Deprecation bridge: useMaster -> usePrimary
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
// Deprecation bridge: useMaster -> usePrimary

Comment thread packages/core/src/utils/deprecations.ts Outdated

export const useMasterToUsePrimary = deprecate(
noop,
'The "useMaster" option has been renamed to "usePrimary". "useMaster" is deprecated and will be removed in a future release.',
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
'The "useMaster" option has been renamed to "usePrimary". "useMaster" is deprecated and will be removed in a future release.',
'The "useMaster" option has been renamed to "usePrimary".',



Keep the deprecation warning emission before the retry loop, and use an
inline null-coalescing fallback at pool.acquire() so callers passing
useMaster are never silently broken. JSDoc @link is already fully
qualified as GetConnectionOptions.usePrimary.
@WikiRik
Copy link
Copy Markdown
Member

WikiRik commented Apr 12, 2026

@stuckvgn not sure if a bot automatically made those changes or that you prompted it for the last commit, but that's not a step in the right direction. If you undo the last commit and apply the suggestions I've made we can merge this imo

@stuckvgn
Copy link
Copy Markdown
Author

@WikiRik You're right — that was bot-generated. Reverted it and applied your three suggestions directly: removed the bridge comments from sequelize.js and replication-pool.ts, and shortened the deprecation message. Should be exactly what you asked for.

@stuckvgn
Copy link
Copy Markdown
Author

Gentle ping @WikiRik — all three of your suggestions from April 12 are applied in the latest commit (removed the bridge comments from sequelize.js and replication-pool.ts, shortened the deprecation message). CI is fully green. Ready for re-review whenever you have a moment.

@WikiRik WikiRik enabled auto-merge (squash) April 16, 2026 05:22
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.

3 participants