[PR #6240] [CLOSED] feat: unique where requirement, and other adapter improvements #6540

Closed
opened 2026-03-13 13:02:38 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/better-auth/better-auth/pull/6240
Author: @ping-maxwell
Created: 11/23/2025
Status: Closed

Base: canaryHead: feat/unique-where-requirement-for-adapter-factory


📝 Commits (10+)

  • 33d9a8d feat: unique where requirement for adapter factory
  • 187e1e4 Merge branch 'canary' into feat/unique-where-requirement-for-adapter-factory
  • d60ac5f fix: remove ne
  • ac01be1 fix: adapter unit tests
  • 9fa3212 fix: invalid adapter operations
  • 8da6665 fix: other adapter issues
  • a96f66b Merge branch 'canary' into feat/unique-where-requirement-for-adapter-factory
  • 20913fd chore: lint
  • a1aa31a fix
  • 0838204 Merge branch 'canary' into feat/unique-where-requirement-for-adapter-factory

📊 Changes

46 files changed (+1106 additions, -285 deletions)

View changed files

📝 packages/better-auth/src/adapters/adapter-factory/get-default-field-name.ts (+3 -1)
📝 packages/better-auth/src/adapters/adapter-factory/get-field-attributes.ts (+3 -1)
📝 packages/better-auth/src/adapters/adapter-factory/index.ts (+114 -27)
📝 packages/better-auth/src/adapters/adapter-factory/test/adapter-factory.test.ts (+601 -0)
📝 packages/better-auth/src/adapters/create-test-suite.ts (+1 -0)
📝 packages/better-auth/src/adapters/drizzle-adapter/test/drizzle.mysql.test.ts (+0 -0)
📝 packages/better-auth/src/adapters/drizzle-adapter/test/drizzle.pg.test.ts (+0 -0)
📝 packages/better-auth/src/adapters/drizzle-adapter/test/drizzle.sqlite.test.ts (+0 -0)
📝 packages/better-auth/src/adapters/kysely-adapter/kysely-adapter.ts (+4 -4)
📝 packages/better-auth/src/adapters/kysely-adapter/test/kysely.custom-schema-pg.test.ts (+0 -0)
📝 packages/better-auth/src/adapters/kysely-adapter/test/kysely.mssql.test.ts (+0 -0)
📝 packages/better-auth/src/adapters/kysely-adapter/test/kysely.mysql.test.ts (+0 -0)
📝 packages/better-auth/src/adapters/kysely-adapter/test/kysely.node-sqlite.test.ts (+41 -45)
📝 packages/better-auth/src/adapters/kysely-adapter/test/kysely.pg.test.ts (+0 -0)
📝 packages/better-auth/src/adapters/kysely-adapter/test/kysely.sqlite.test.ts (+0 -0)
📝 packages/better-auth/src/adapters/memory-adapter/memory-adapter.ts (+2 -1)
📝 packages/better-auth/src/adapters/memory-adapter/memory.test.ts (+0 -0)
📝 packages/better-auth/src/adapters/mongodb-adapter/mongo.test.ts (+0 -0)
📝 packages/better-auth/src/adapters/mongodb-adapter/mongodb-adapter.ts (+6 -6)
📝 packages/better-auth/src/adapters/prisma-adapter/test/generate-prisma-schema.ts (+1 -0)

...and 26 more files

📄 Description

Features / Improvements

  1. Unique Where Requirement - Ensures that where clauses for single-query operations meet the requirement to at least include 1 unique field in the where clause.
  2. Unit Test Improvements:
    • Kysely node-sqlite dialect was using the old better-auth adapter test system, it's now moved to use the new test suite version.
    • Currently some adapter test names start with adapter.<adapter_name>.<dialect>.test.ts this makes for a long test name. Using something like drizzle.sqlite.test.ts is enough, we do not need adapter.drizzle.sqlite.test.ts
  3. Type definition improvements, under the JoinConfig. We currently have the following: JoinConfig.on.from & JoinConfig.on.to, this is now changed to JoinConfig.on.field & JoinConfig.on.referencing for more accurate naming.

Unique Where Requirement fixes the following plugins:

(Technically speaking, everything here will fail for prisma users)

  • TwoFactor:
    • viewBackupCodes tries to find twoFactors by userId, but uid fk is not unique.
    • disableTwoFactor tries to delete a twoFactor by userId, but uid fk is not unique, must use deleteMany
  • Organization:
    • findMemberByEmail attempts to find a user by email, but email is not unique.
    • findMemberByOrgId tries to find an org by organizationId & userId, neither are unique.
    • findOrCreateTeamMember tries to find an org by teamId & userId, neither are unique.
    • checkMembership tries to find a member by userId & organizationId
    • findTeamMember tries to find by teamId & userId, neither of which are unique.
  • Device Authorization:
    • deviceCode should be unique
    • deviceVerify, deviceDeny & deviceApproves tries to find deviceCode but userCode is not unique
  • API Key:
    • key should be unique
  • username:
    • signInWithUsername tries to find 1 account but providerId and userId are not unique
  • oidc-provider:
    • authorize tries to find 1 oauthConsent via clientId & userId, but none are unique.
  • sso:
    • verifyDomain: tries to find verification via identifier but it's not unique
    • signInSSO: tries to get the ssoProvider but organizationId is not unique
    • registerSSOProvider: tries to check if a user is a member of an org but userId & orId is not uniuqe
    • callbackSSO finds member but not using unique keys
  • stripe:
    • onSubscriptionUpdated tries to find a subscription by stripeSubscriptionId but it's not unique
    • upgradeSubscription tries to find a subscription using referenceId but it's not unique.
  • swie:
    • verifySwieMessage tries to find a walletAddress using chainId or address which isn't unique
  • scim:
    • generateSCIMToken tries to find scimProvider from organizationId which is not unique
    • createSCIMUser tries to find existing accounts but accountId & providerId are not unique
    • findUserById tries to find existing accounts & members but userId & providerId are not unique

And Internal adapter which touches several core endpoints:

  • findAccount tries to find 1 account, but accountId is not unique
  • deleteVerificationByIdentifier tries to delete 1 identifier from verification model, but identifier is not unique.

Summary by cubic

Enforces a unique-field requirement for single-record queries in the adapter factory to prevent ambiguous matches. Applies to findOne, update, and delete, with schema and call-site updates; also refines join config naming.

  • New Features

    • Requires an equality (eq) on a unique field for single-record queries; operator defaults to eq and throws BetterAuthError when no unique-eq filter is provided.
    • Adds disableTransformWhere for advanced/testing.
    • Marks apiKey.key and deviceCode.deviceCode as unique.
    • Prisma schema generator disallows defaults on unique fields; createdAt gets a default only when not unique.
    • Renames JoinConfig.on.from/to to on.field/references.
  • Migration

    • For findOne, update, and delete, include id or another unique field with eq in where.
    • Use findMany with limit: 1 for non-unique lookups, and deleteMany/updateMany when the where clause isn’t unique.
    • In Prisma schemas, do not set default values on unique fields.

Written for commit dbe94bf59d. Summary will update automatically on new commits.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/better-auth/better-auth/pull/6240 **Author:** [@ping-maxwell](https://github.com/ping-maxwell) **Created:** 11/23/2025 **Status:** ❌ Closed **Base:** `canary` ← **Head:** `feat/unique-where-requirement-for-adapter-factory` --- ### 📝 Commits (10+) - [`33d9a8d`](https://github.com/better-auth/better-auth/commit/33d9a8d93e9f000fab3ae4551b2679659667d07f) feat: unique where requirement for adapter factory - [`187e1e4`](https://github.com/better-auth/better-auth/commit/187e1e4037b49f586a8fdd978396252186e334cf) Merge branch 'canary' into feat/unique-where-requirement-for-adapter-factory - [`d60ac5f`](https://github.com/better-auth/better-auth/commit/d60ac5fa3dda25a95c824b7c1ac3673776266452) fix: remove ne - [`ac01be1`](https://github.com/better-auth/better-auth/commit/ac01be1bb71d088cc231ae10732e8c8eea5f4938) fix: adapter unit tests - [`9fa3212`](https://github.com/better-auth/better-auth/commit/9fa3212b937abe68bc1275be85aaeec00e281e3a) fix: invalid adapter operations - [`8da6665`](https://github.com/better-auth/better-auth/commit/8da66653629926b25a078059ff4577bfe47b490a) fix: other adapter issues - [`a96f66b`](https://github.com/better-auth/better-auth/commit/a96f66b4b1adea7cecea106fbe0de80067f422f9) Merge branch 'canary' into feat/unique-where-requirement-for-adapter-factory - [`20913fd`](https://github.com/better-auth/better-auth/commit/20913fd76607e5abd43ce819fd8eaf42e02281f3) chore: lint - [`a1aa31a`](https://github.com/better-auth/better-auth/commit/a1aa31a29421fb3798ffe1157090ad5cfda62180) fix - [`0838204`](https://github.com/better-auth/better-auth/commit/08382043031ccd0bce40f8c3e8df3284d9dc1c26) Merge branch 'canary' into feat/unique-where-requirement-for-adapter-factory ### 📊 Changes **46 files changed** (+1106 additions, -285 deletions) <details> <summary>View changed files</summary> 📝 `packages/better-auth/src/adapters/adapter-factory/get-default-field-name.ts` (+3 -1) 📝 `packages/better-auth/src/adapters/adapter-factory/get-field-attributes.ts` (+3 -1) 📝 `packages/better-auth/src/adapters/adapter-factory/index.ts` (+114 -27) 📝 `packages/better-auth/src/adapters/adapter-factory/test/adapter-factory.test.ts` (+601 -0) 📝 `packages/better-auth/src/adapters/create-test-suite.ts` (+1 -0) 📝 `packages/better-auth/src/adapters/drizzle-adapter/test/drizzle.mysql.test.ts` (+0 -0) 📝 `packages/better-auth/src/adapters/drizzle-adapter/test/drizzle.pg.test.ts` (+0 -0) 📝 `packages/better-auth/src/adapters/drizzle-adapter/test/drizzle.sqlite.test.ts` (+0 -0) 📝 `packages/better-auth/src/adapters/kysely-adapter/kysely-adapter.ts` (+4 -4) 📝 `packages/better-auth/src/adapters/kysely-adapter/test/kysely.custom-schema-pg.test.ts` (+0 -0) 📝 `packages/better-auth/src/adapters/kysely-adapter/test/kysely.mssql.test.ts` (+0 -0) 📝 `packages/better-auth/src/adapters/kysely-adapter/test/kysely.mysql.test.ts` (+0 -0) 📝 `packages/better-auth/src/adapters/kysely-adapter/test/kysely.node-sqlite.test.ts` (+41 -45) 📝 `packages/better-auth/src/adapters/kysely-adapter/test/kysely.pg.test.ts` (+0 -0) 📝 `packages/better-auth/src/adapters/kysely-adapter/test/kysely.sqlite.test.ts` (+0 -0) 📝 `packages/better-auth/src/adapters/memory-adapter/memory-adapter.ts` (+2 -1) 📝 `packages/better-auth/src/adapters/memory-adapter/memory.test.ts` (+0 -0) 📝 `packages/better-auth/src/adapters/mongodb-adapter/mongo.test.ts` (+0 -0) 📝 `packages/better-auth/src/adapters/mongodb-adapter/mongodb-adapter.ts` (+6 -6) 📝 `packages/better-auth/src/adapters/prisma-adapter/test/generate-prisma-schema.ts` (+1 -0) _...and 26 more files_ </details> ### 📄 Description ## Features / Improvements 1. Unique Where Requirement - Ensures that where clauses for single-query operations meet the requirement to at least include 1 unique field in the where clause. 2. Unit Test Improvements: - Kysely `node-sqlite dialect` was using the old better-auth adapter test system, it's now moved to use the new test suite version. - Currently **some** adapter test names start with `adapter.<adapter_name>.<dialect>.test.ts` this makes for a long test name. Using something like `drizzle.sqlite.test.ts` is enough, we do not need `adapter.drizzle.sqlite.test.ts` 3. Type definition improvements, under the `JoinConfig`. We currently have the following: `JoinConfig.on.from` & `JoinConfig.on.to`, this is now changed to `JoinConfig.on.field` & `JoinConfig.on.referencing` for more accurate naming. ### Unique Where Requirement fixes the following plugins: (Technically speaking, everything here will fail for prisma users) - **TwoFactor**: - `viewBackupCodes` tries to find twoFactors by userId, but uid fk is not unique. - `disableTwoFactor` tries to delete a twoFactor by userId, but uid fk is not unique, must use deleteMany - **Organization**: - `findMemberByEmail` attempts to find a user by email, but `email` is not `unique`. - `findMemberByOrgId` tries to find an org by `organizationId` & `userId`, neither are `unique`. - `findOrCreateTeamMember` tries to find an org by `teamId` & `userId`, neither are `unique`. - `checkMembership` tries to find a member by `userId` & `organizationId` - `findTeamMember` tries to find by `teamId` & `userId`, neither of which are `unique`. - **Device Authorization**: - `deviceCode` should be `unique` - `deviceVerify`, `deviceDeny` & `deviceApproves` tries to find `deviceCode` but `userCode` is not unique - **API Key**: - `key` should be unique - **username**: - `signInWithUsername` tries to find 1 account but `providerId` and `userId` are not unique - **oidc-provider**: - `authorize` tries to find 1 `oauthConsent` via `clientId` & `userId`, but none are `unique`. - **sso**: - `verifyDomain`: tries to find verification via `identifier` but it's not unique - `signInSSO`: tries to get the `ssoProvider` but `organizationId` is not unique - `registerSSOProvider`: tries to check if a user is a member of an org but `userId` & `orId` is not uniuqe - `callbackSSO` finds member but not using unique keys - **stripe**: - `onSubscriptionUpdated` tries to find a subscription by `stripeSubscriptionId` but it's not unique - `upgradeSubscription` tries to find a subscription using `referenceId` but it's not unique. - **swie**: - `verifySwieMessage` tries to find a `walletAddress` using `chainId` or `address` which isn't unique - **scim**: - `generateSCIMToken` tries to find `scimProvider` from `organizationId` which is not unique - `createSCIMUser` tries to find existing accounts but `accountId` & `providerId` are not unique - `findUserById` tries to find existing accounts & members but `userId` & `providerId` are not unique And Internal adapter which touches several core endpoints: - `findAccount` tries to find 1 account, but `accountId` is not unique - `deleteVerificationByIdentifier` tries to delete 1 `identifier` from verification model, but `identifier` is not unique. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Enforces a unique-field requirement for single-record queries in the adapter factory to prevent ambiguous matches. Applies to findOne, update, and delete, with schema and call-site updates; also refines join config naming. - **New Features** - Requires an equality (eq) on a unique field for single-record queries; operator defaults to eq and throws BetterAuthError when no unique-eq filter is provided. - Adds disableTransformWhere for advanced/testing. - Marks apiKey.key and deviceCode.deviceCode as unique. - Prisma schema generator disallows defaults on unique fields; createdAt gets a default only when not unique. - Renames JoinConfig.on.from/to to on.field/references. - **Migration** - For findOne, update, and delete, include id or another unique field with eq in where. - Use findMany with limit: 1 for non-unique lookups, and deleteMany/updateMany when the where clause isn’t unique. - In Prisma schemas, do not set default values on unique fields. <sup>Written for commit dbe94bf59df5d976c538f2021eaf577cf750f298. Summary will update automatically on new commits.</sup> <!-- End of auto-generated description by cubic. --> --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-03-13 13:02:38 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#6540