@better-auth/drizzle-adapter 1.7.0-rc.0 → 1.7.0-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,22 +2,42 @@ import { initGetFieldName, initGetModelName } from "@better-auth/core/db/adapter
2
2
  import { existsSync } from "node:fs";
3
3
  import path from "node:path";
4
4
  import { getAuthTables } from "@better-auth/core/db";
5
+ import { getDatabaseFieldIndexName, getDatabaseIndexStringLength, resolveDatabaseSchemaIndexes } from "@better-auth/core/db/internal";
5
6
  //#region src/relations-v2/generate-drizzle-schema.ts
6
7
  function convertToSnakeCase(str, camelCase) {
7
8
  if (camelCase) return str;
8
9
  return str.replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2").replace(/([a-z\d])([A-Z])/g, "$1_$2").toLowerCase();
9
10
  }
11
+ /**
12
+ * Convert a schema namespace into a valid JavaScript identifier so it can be
13
+ * used as the `const <name>Schema = pgSchema(...)` variable name.
14
+ * e.g. "my-auth" -> "myAuth", "123schema" -> "_123schema".
15
+ */
16
+ function toValidIdentifier(str) {
17
+ let result = str.replace(/[^a-zA-Z0-9]+([a-zA-Z0-9])/g, (_, char) => char.toUpperCase()).replace(/[^a-zA-Z0-9]/g, "").replace(/^[0-9]/, "_$&");
18
+ if (result.length > 0 && /[A-Z]/.test(result[0])) result = result[0].toLowerCase() + result.slice(1);
19
+ return result || "schema";
20
+ }
10
21
  const generateDrizzleSchema = async ({ options, file, provider, adapterConfig, camelCase, tables: propsTables }) => {
11
22
  const tables = propsTables ?? getAuthTables(options);
12
23
  const filePath = file || "./auth-schema.ts";
13
24
  const databaseType = provider;
25
+ const schemaName = adapterConfig?.schemaName;
14
26
  if (!databaseType) throw new Error(`Database provider type is undefined during Drizzle schema generation. Please define a \`provider\` in the Drizzle adapter config. Read more at https://better-auth.com/docs/adapters/drizzle`);
15
27
  const fileExist = existsSync(filePath);
16
28
  let code = generateImport({
17
29
  databaseType,
18
30
  tables,
19
- options
31
+ options,
32
+ schemaName
20
33
  });
34
+ let schemaVarName;
35
+ if (databaseType === "pg" && schemaName) {
36
+ schemaVarName = `${toValidIdentifier(schemaName)}Schema`;
37
+ if (schemaVarName === "pgSchema") schemaVarName = "pgCustomSchema";
38
+ code += `\nconst ${schemaVarName} = pgSchema(${JSON.stringify(schemaName)});\n`;
39
+ }
40
+ const tableFunction = databaseType === "pg" && schemaName && schemaVarName ? `${schemaVarName}.table` : `${databaseType}Table`;
21
41
  const getModelName = initGetModelName({
22
42
  schema: tables,
23
43
  usePlural: adapterConfig?.usePlural
@@ -30,11 +50,18 @@ const generateDrizzleSchema = async ({ options, file, provider, adapterConfig, c
30
50
  schema: tables,
31
51
  usePlural: adapterConfig?.usePlural
32
52
  });
53
+ const resolvedIndexesByTable = resolveDatabaseSchemaIndexes(Object.keys(tables).filter((tableKey) => !tables[tableKey].disableMigrations).map((tableKey) => ({
54
+ fields: tables[tableKey].fields,
55
+ indexes: tables[tableKey].indexes,
56
+ tableName: getModelName(tableKey)
57
+ })));
33
58
  for (const tableKey in tables) {
34
59
  const table = tables[tableKey];
60
+ if (table.disableMigrations) continue;
35
61
  const modelName = getModelName(tableKey);
36
62
  const fields = table.fields;
37
- function getType(name, field) {
63
+ const resolvedTableIndexes = resolvedIndexesByTable.get(modelName) ?? [];
64
+ function getType(name, field, tableIndexStringLength) {
38
65
  if (!databaseType) throw new Error(`Database provider type is undefined during Drizzle schema generation. Please define a \`provider\` in the Drizzle adapter config. Read more at https://better-auth.com/docs/adapters/drizzle`);
39
66
  name = convertToSnakeCase(name, camelCase);
40
67
  if (field.references?.field === "id") {
@@ -60,7 +87,7 @@ const generateDrizzleSchema = async ({ options, file, provider, adapterConfig, c
60
87
  string: {
61
88
  sqlite: `text('${name}')`,
62
89
  pg: `text('${name}')`,
63
- mysql: field.unique ? `varchar('${name}', { length: 255 })` : field.references ? `varchar('${name}', { length: 36 })` : field.sortable ? `varchar('${name}', { length: 255 })` : field.index ? `varchar('${name}', { length: 255 })` : `text('${name}')`
90
+ mysql: tableIndexStringLength ? `varchar('${name}', { length: ${tableIndexStringLength} })` : field.unique ? `varchar('${name}', { length: 255 })` : field.references ? `varchar('${name}', { length: 36 })` : field.sortable ? `varchar('${name}', { length: 255 })` : field.index ? `varchar('${name}', { length: 255 })` : `text('${name}')`
64
91
  },
65
92
  boolean: {
66
93
  sqlite: `integer('${name}', { mode: 'boolean' })`,
@@ -109,25 +136,35 @@ const generateDrizzleSchema = async ({ options, file, provider, adapterConfig, c
109
136
  const assignIndexes = (indexes) => {
110
137
  if (!indexes.length) return "";
111
138
  const code = [`, (table) => [`];
112
- for (const index of indexes) code.push(` ${index.type}("${index.name}").on(table.${index.on}),`);
139
+ for (const index of indexes) code.push(` ${index.type}(${JSON.stringify(index.name)}).on(${index.on.map((fieldName) => `table.${fieldName}`).join(", ")}),`);
113
140
  code.push(`]`);
114
141
  return code.join("\n");
115
142
  };
116
- const schema = `export const ${modelName} = ${databaseType}Table("${convertToSnakeCase(modelName, camelCase)}", {
143
+ for (const tableIndex of resolvedTableIndexes) indexes.push({
144
+ type: tableIndex.unique ? "uniqueIndex" : "index",
145
+ name: tableIndex.name,
146
+ on: tableIndex.columns
147
+ });
148
+ const schema = `export const ${modelName} = ${tableFunction}("${convertToSnakeCase(modelName, camelCase)}", {
117
149
  id: ${id},
118
150
  ${Object.keys(fields).map((field) => {
119
151
  const attr = fields[field];
120
152
  const fieldName = attr.fieldName || field;
121
- let type = getType(fieldName, attr);
153
+ let type = getType(fieldName, attr, databaseType === "mysql" ? getDatabaseIndexStringLength({
154
+ columnName: fieldName,
155
+ dialect: "mysql",
156
+ fields,
157
+ indexes: resolvedTableIndexes
158
+ }) : void 0);
122
159
  if (attr.index && !attr.unique) indexes.push({
123
160
  type: "index",
124
- name: `${modelName}_${fieldName}_idx`,
125
- on: fieldName
161
+ name: getDatabaseFieldIndexName(modelName, fieldName, false),
162
+ on: [fieldName]
126
163
  });
127
164
  else if (attr.index && attr.unique) indexes.push({
128
165
  type: "uniqueIndex",
129
- name: `${modelName}_${fieldName}_uidx`,
130
- on: fieldName
166
+ name: getDatabaseFieldIndexName(modelName, fieldName, true),
167
+ on: [fieldName]
131
168
  });
132
169
  if (attr.defaultValue !== null && typeof attr.defaultValue !== "undefined") if (typeof attr.defaultValue === "function") {
133
170
  if (attr.type === "date" && attr.defaultValue.toString().includes("new Date()")) if (databaseType === "sqlite") type += `.default(sql\`(cast(unixepoch('subsecond') * 1000 as integer))\`)`;
@@ -151,6 +188,7 @@ const generateDrizzleSchema = async ({ options, file, provider, adapterConfig, c
151
188
  }
152
189
  const schemaObjectKeys = [];
153
190
  for (const tableKey in tables) {
191
+ if (tables[tableKey].disableMigrations) continue;
154
192
  const modelName = getModelName(tableKey);
155
193
  schemaObjectKeys.push(modelName);
156
194
  }
@@ -158,11 +196,13 @@ const generateDrizzleSchema = async ({ options, file, provider, adapterConfig, c
158
196
  const relationsMap = /* @__PURE__ */ new Map();
159
197
  for (const tableKey in tables) {
160
198
  const table = tables[tableKey];
199
+ if (table.disableMigrations) continue;
161
200
  const modelName = getModelName(tableKey);
162
201
  const modelRelations = [];
163
202
  const foreignFields = Object.entries(table.fields).filter(([_, field]) => field.references);
164
203
  for (const [fieldName, field] of foreignFields) {
165
204
  const referencedModel = field.references.model;
205
+ if (tables[referencedModel]?.disableMigrations) continue;
166
206
  const targetModelName = getModelName(referencedModel);
167
207
  const fromField = getFieldName({
168
208
  model: tableKey,
@@ -184,7 +224,7 @@ const generateDrizzleSchema = async ({ options, file, provider, adapterConfig, c
184
224
  sourceModel: modelName
185
225
  });
186
226
  }
187
- const otherModels = Object.entries(tables).filter(([modelName]) => modelName !== tableKey);
227
+ const otherModels = Object.entries(tables).filter(([modelName, otherTable]) => modelName !== tableKey && !otherTable.disableMigrations);
188
228
  for (const [otherTableKey, otherTable] of otherModels) {
189
229
  const foreignKeysPointingHere = Object.entries(otherTable.fields).filter(([_, field]) => field.references?.model === tableKey || field.references?.model === modelName);
190
230
  if (foreignKeysPointingHere.length === 0) continue;
@@ -269,9 +309,11 @@ const generateDrizzleSchema = async ({ options, file, provider, adapterConfig, c
269
309
  append: false
270
310
  };
271
311
  };
272
- function generateImport({ databaseType, tables, options }) {
312
+ function generateImport({ databaseType, tables, options, schemaName }) {
273
313
  const rootImports = ["defineRelationsPart"];
274
314
  const coreImports = [];
315
+ if (databaseType === "pg" && schemaName) coreImports.push("pgSchema");
316
+ if (!(databaseType === "pg" && schemaName)) coreImports.push(`${databaseType}Table`);
275
317
  let hasBigint = false;
276
318
  let hasJson = false;
277
319
  for (const table of Object.values(tables)) {
@@ -283,7 +325,6 @@ function generateImport({ databaseType, tables, options }) {
283
325
  }
284
326
  const useNumberId = options.advanced?.database?.generateId === "serial";
285
327
  const useUUIDs = options.advanced?.database?.generateId === "uuid";
286
- coreImports.push(`${databaseType}Table`);
287
328
  coreImports.push(databaseType === "mysql" ? "varchar, text" : databaseType === "pg" ? "text" : "text");
288
329
  coreImports.push(hasBigint ? databaseType !== "sqlite" ? "bigint" : "" : "");
289
330
  coreImports.push(databaseType !== "sqlite" ? "timestamp, boolean" : "");
@@ -301,8 +342,8 @@ function generateImport({ databaseType, tables, options }) {
301
342
  if (databaseType === "mysql") coreImports.push("json");
302
343
  }
303
344
  if (databaseType === "sqlite" && Object.values(tables).some((table) => Object.values(table.fields).some((field) => field.type === "date" && field.defaultValue && typeof field.defaultValue === "function" && field.defaultValue.toString().includes("new Date()")))) rootImports.push("sql");
304
- const hasIndexes = Object.values(tables).some((table) => Object.values(table.fields).some((field) => field.index && !field.unique));
305
- const hasUniqueIndexes = Object.values(tables).some((table) => Object.values(table.fields).some((field) => field.unique && field.index));
345
+ const hasIndexes = Object.values(tables).some((table) => Object.values(table.fields).some((field) => field.index && !field.unique) || (table.indexes?.some((index) => !index.unique) ?? false));
346
+ const hasUniqueIndexes = Object.values(tables).some((table) => Object.values(table.fields).some((field) => field.unique && field.index) || (table.indexes?.some((index) => index.unique) ?? false));
306
347
  if (hasIndexes) coreImports.push("index");
307
348
  if (hasUniqueIndexes) coreImports.push("uniqueIndex");
308
349
  return `${rootImports.length > 0 ? `import { ${rootImports.join(", ")} } from "drizzle-orm";\n` : ""}import { ${coreImports.map((x) => x.trim()).filter((x) => x !== "").join(", ")} } from "drizzle-orm/${databaseType}-core";\n`;
package/dist/index.d.mts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { DBAdapter, DBAdapterDebugLogOption } from "@better-auth/core/db/adapter";
2
2
  import { BetterAuthOptions } from "@better-auth/core";
3
-
4
3
  //#region src/drizzle-adapter.d.ts
5
4
  interface DB {
6
5
  [key: string]: any;
@@ -41,6 +40,22 @@ interface DrizzleAdapterConfig {
41
40
  * @default false
42
41
  */
43
42
  transaction?: boolean | undefined;
43
+ /**
44
+ * Database schema namespace, used during the Better Auth CLI to generate the schema.
45
+ *
46
+ * Only applies to PostgreSQL. It will generate something like this:
47
+ *
48
+ * ```ts
49
+ * const authSchema = pgSchema("auth");
50
+ *
51
+ * export const user = authSchema.table("user", {...});
52
+ * export const session = authSchema.table("session", {...});
53
+ * ```
54
+ *
55
+ * @example "auth"
56
+ * @default undefined
57
+ */
58
+ schemaName?: string | undefined;
44
59
  }
45
60
  declare const drizzleAdapter: (db: DB, config: DrizzleAdapterConfig) => (options: BetterAuthOptions) => DBAdapter<BetterAuthOptions>;
46
61
  //#endregion
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { a as insensitiveNe, i as insensitiveInArray, n as insensitiveEq, o as insensitiveNotInArray, r as insensitiveIlike } from "./query-builders-D2eE7gbx.mjs";
1
+ import { a as insensitiveNe, i as insensitiveInArray, n as insensitiveEq, o as insensitiveNotInArray, r as insensitiveIlike } from "./query-builders-Btx2OekF.mjs";
2
2
  import { createAdapterFactory } from "@better-auth/core/db/adapter";
3
3
  import { logger } from "@better-auth/core/env";
4
4
  import { BetterAuthError } from "@better-auth/core/error";
@@ -7,15 +7,19 @@ import { and, asc, count, desc, eq, gt, gte, inArray, isNotNull, isNull, like, l
7
7
  /**
8
8
  * Derive the number of affected rows from a Drizzle write result.
9
9
  *
10
- * Drizzle's drivers report affected rows under different shapes: postgres-js
11
- * exposes `rowCount`, mysql2 reports `affectedRows`/`rowsAffected` (sometimes as
12
- * the first element of a result-header array), and better-sqlite3 uses
13
- * `changes`. This normalizes those so write methods that depend on affected
14
- * rows honor the adapter contract instead of leaking the raw driver result.
10
+ * Drizzle returns the raw per-driver result for a non-returning write, so the
11
+ * count lives under a different field per driver: node-postgres / neon expose
12
+ * `rowCount`, postgres-js / bun-sql carry `count` on an Array subclass, mysql2
13
+ * reports `affectedRows` (in a result-header array), planetscale and other
14
+ * serverless drivers use `rowsAffected`, better-sqlite3 uses `changes`, and
15
+ * Cloudflare D1 nests the count under `meta.changes`. This normalizes them so
16
+ * write methods that depend on affected rows honor the adapter contract instead
17
+ * of leaking the raw driver result.
15
18
  */
16
19
  function getAffectedRowCount(result, operation, context) {
17
20
  let count = 0;
18
21
  if (result && typeof result === "object" && "rowCount" in result) count = result.rowCount;
22
+ else if (result && typeof result === "object" && typeof result.count === "number") count = result.count;
19
23
  else if (Array.isArray(result)) count = result.length > 0 && hasDriverRowCount(result[0]) ? readDriverRowCount(result[0]) : result.length;
20
24
  else if (hasDriverRowCount(result)) count = readDriverRowCount(result);
21
25
  if (typeof count !== "number" || !Number.isFinite(count)) {
@@ -27,12 +31,19 @@ function getAffectedRowCount(result, operation, context) {
27
31
  }
28
32
  return count;
29
33
  }
30
- function hasDriverRowCount(result) {
31
- return !!result && typeof result === "object" && ("affectedRows" in result || "rowsAffected" in result || "changes" in result);
32
- }
33
34
  function readDriverRowCount(result) {
34
- const r = result;
35
- return r.affectedRows ?? r.rowsAffected ?? r.changes;
35
+ if (!result || typeof result !== "object") return void 0;
36
+ const driverResult = result;
37
+ if ("affectedRows" in driverResult) return driverResult.affectedRows;
38
+ if ("rowsAffected" in driverResult) return driverResult.rowsAffected;
39
+ if ("changes" in driverResult) return driverResult.changes;
40
+ if ("meta" in driverResult) {
41
+ const meta = driverResult.meta;
42
+ if (meta && typeof meta === "object" && "changes" in meta) return meta.changes;
43
+ }
44
+ }
45
+ function hasDriverRowCount(result) {
46
+ return readDriverRowCount(result) !== void 0;
36
47
  }
37
48
  const drizzleAdapter = (db, config) => {
38
49
  let lazyOptions = null;
@@ -267,6 +278,7 @@ const drizzleAdapter = (db, config) => {
267
278
  * corresponds to the same table object
268
279
  */
269
280
  function getQueryModel(model) {
281
+ if (!db.query) return null;
270
282
  if (db.query[model]) return model;
271
283
  if (config.usePlural) {
272
284
  const plural = `${model}s`;
@@ -287,12 +299,13 @@ const drizzleAdapter = (db, config) => {
287
299
  async create({ model, data: values }) {
288
300
  const schemaModel = getSchema(model);
289
301
  checkMissingFields(schemaModel, model, values);
290
- return await withReturning(model, db.insert(schemaModel).values(values), values);
302
+ const builder = db.insert(schemaModel).values(values);
303
+ return await withReturning(model, builder, values);
291
304
  },
292
305
  async findOne({ model, where, select, join }) {
293
306
  const schemaModel = getSchema(model);
294
307
  const clause = convertWhereClause(where, model);
295
- if (options.experimental?.joins) {
308
+ if (join) {
296
309
  const queryModel = getQueryModel(model);
297
310
  if (!db.query || !queryModel) {
298
311
  logger.error(`[# Drizzle Adapter]: The model "${model}" was not found in the query object. Please update your Drizzle schema to include relations or re-generate using "npx auth@latest generate".`);
@@ -300,16 +313,14 @@ const drizzleAdapter = (db, config) => {
300
313
  } else {
301
314
  let includes;
302
315
  const pluralJoinResults = [];
303
- if (join) {
304
- includes = {};
305
- const joinEntries = Object.entries(join);
306
- for (const [model, joinAttr] of joinEntries) {
307
- const limit = joinAttr.limit ?? options.advanced?.database?.defaultFindManyLimit ?? 100;
308
- const isUnique = joinAttr.relation === "one-to-one";
309
- const pluralSuffix = isUnique || config.usePlural ? "" : "s";
310
- includes[`${model}${pluralSuffix}`] = isUnique ? true : { limit };
311
- if (!isUnique) pluralJoinResults.push(`${model}${pluralSuffix}`);
312
- }
316
+ includes = {};
317
+ const joinEntries = Object.entries(join);
318
+ for (const [model, joinAttr] of joinEntries) {
319
+ const limit = joinAttr.limit ?? options.advanced?.database?.defaultFindManyLimit ?? 100;
320
+ const isUnique = joinAttr.relation === "one-to-one";
321
+ const pluralSuffix = isUnique || config.usePlural ? "" : "s";
322
+ includes[`${model}${pluralSuffix}`] = isUnique ? true : { limit };
323
+ if (!isUnique) pluralJoinResults.push(`${model}${pluralSuffix}`);
313
324
  }
314
325
  const res = await db.query[queryModel].findFirst({
315
326
  where: clause[0],
@@ -347,24 +358,22 @@ const drizzleAdapter = (db, config) => {
347
358
  const schemaModel = getSchema(model);
348
359
  const clause = where ? convertWhereClause(where, model) : [];
349
360
  const sortFn = sortBy?.direction === "desc" ? desc : asc;
350
- if (options.experimental?.joins) {
361
+ if (join) {
351
362
  const queryModel = getQueryModel(model);
352
- if (!queryModel) {
363
+ if (!db.query || !queryModel) {
353
364
  logger.error(`[# Drizzle Adapter]: The model "${model}" was not found in the query object. Please update your Drizzle schema to include relations or re-generate using "npx auth@latest generate".`);
354
365
  logger.info("Falling back to regular query");
355
366
  } else {
356
367
  let includes;
357
368
  const pluralJoinResults = [];
358
- if (join) {
359
- includes = {};
360
- const joinEntries = Object.entries(join);
361
- for (const [model, joinAttr] of joinEntries) {
362
- const isUnique = joinAttr.relation === "one-to-one";
363
- const limit = joinAttr.limit ?? options.advanced?.database?.defaultFindManyLimit ?? 100;
364
- const pluralSuffix = isUnique || config.usePlural ? "" : "s";
365
- includes[`${model}${pluralSuffix}`] = isUnique ? true : { limit };
366
- if (!isUnique) pluralJoinResults.push(`${model}${pluralSuffix}`);
367
- }
369
+ includes = {};
370
+ const joinEntries = Object.entries(join);
371
+ for (const [model, joinAttr] of joinEntries) {
372
+ const isUnique = joinAttr.relation === "one-to-one";
373
+ const limit = joinAttr.limit ?? options.advanced?.database?.defaultFindManyLimit ?? 100;
374
+ const pluralSuffix = isUnique || config.usePlural ? "" : "s";
375
+ includes[`${model}${pluralSuffix}`] = isUnique ? true : { limit };
376
+ if (!isUnique) pluralJoinResults.push(`${model}${pluralSuffix}`);
368
377
  }
369
378
  let orderBy = void 0;
370
379
  if (sortBy?.field) orderBy = [sortFn(schemaModel[getFieldName({
@@ -422,7 +431,8 @@ const drizzleAdapter = (db, config) => {
422
431
  async update({ model, where, update: values }) {
423
432
  const schemaModel = getSchema(model);
424
433
  const clause = convertWhereClause(where, model);
425
- return await withReturning(model, db.update(schemaModel).set(values).where(...clause), values, where);
434
+ const builder = db.update(schemaModel).set(values).where(...clause);
435
+ return await withReturning(model, builder, values, where);
426
436
  },
427
437
  async updateMany({ model, where, update: values }) {
428
438
  const schemaModel = getSchema(model);
@@ -1,6 +1,5 @@
1
1
  import { DBAdapter, DBAdapterDebugLogOption } from "@better-auth/core/db/adapter";
2
2
  import { BetterAuthOptions } from "@better-auth/core";
3
-
4
3
  //#region src/relations-v2/index.d.ts
5
4
  interface DB {
6
5
  [key: string]: any;
@@ -41,6 +40,22 @@ interface DrizzleAdapterConfig {
41
40
  * @default false
42
41
  */
43
42
  transaction?: boolean | undefined;
43
+ /**
44
+ * Database schema namespace, used during the Better Auth CLI to generate the schema.
45
+ *
46
+ * Only applies to PostgreSQL. It will generate something like this:
47
+ *
48
+ * ```ts
49
+ * const authSchema = pgSchema("auth");
50
+ *
51
+ * export const user = authSchema.table("user", {...});
52
+ * export const session = authSchema.table("session", {...});
53
+ * ```
54
+ *
55
+ * @example "auth"
56
+ * @default undefined
57
+ */
58
+ schemaName?: string | undefined;
44
59
  }
45
60
  declare const drizzleAdapter: (db: DB, config: DrizzleAdapterConfig) => (options: BetterAuthOptions) => DBAdapter<BetterAuthOptions>;
46
61
  //#endregion
@@ -1,4 +1,4 @@
1
- import { a as insensitiveNe, i as insensitiveInArray, n as insensitiveEq, o as insensitiveNotInArray, t as escapedLike } from "../query-builders-D2eE7gbx.mjs";
1
+ import { a as insensitiveNe, i as insensitiveInArray, n as insensitiveEq, o as insensitiveNotInArray, t as escapedLike } from "../query-builders-Btx2OekF.mjs";
2
2
  import { createAdapterFactory } from "@better-auth/core/db/adapter";
3
3
  import { logger } from "@better-auth/core/env";
4
4
  import { BetterAuthError } from "@better-auth/core/error";
@@ -278,12 +278,13 @@ const drizzleAdapter = (db, config) => {
278
278
  async create({ model, data: values }) {
279
279
  const schemaModel = getSchema(model);
280
280
  checkMissingFields(schemaModel, model, values);
281
- return await withReturning(model, db.insert(schemaModel).values(values), values);
281
+ const builder = db.insert(schemaModel).values(values);
282
+ return await withReturning(model, builder, values);
282
283
  },
283
284
  async findOne({ model, where, select, join }) {
284
285
  const schemaModel = getSchema(model);
285
286
  const clause = convertWhereClause(where, model);
286
- if (options.experimental?.joins) {
287
+ if (join) {
287
288
  const queryModel = getQueryModel(model);
288
289
  if (!db.query || !queryModel) {
289
290
  logger.error(`[# Drizzle Adapter]: The model "${model}" was not found in the query object. Please update your Drizzle schema to include relations or re-generate using "npx @better-auth/cli@latest generate".`);
@@ -291,19 +292,17 @@ const drizzleAdapter = (db, config) => {
291
292
  } else {
292
293
  let includes;
293
294
  const pluralJoinResults = [];
294
- if (join) {
295
- includes = {};
296
- const joinEntries = Object.entries(join);
297
- for (const [model, joinAttr] of joinEntries) {
298
- const limit = joinAttr.limit ?? options.advanced?.database?.defaultFindManyLimit ?? 100;
299
- const isUnique = joinAttr.relation === "one-to-one";
300
- const relationKey = getJoinRelationKey(model, isUnique);
301
- includes[relationKey] = isUnique ? true : { limit };
302
- if (!isUnique) pluralJoinResults.push({
303
- key: relationKey,
304
- target: model
305
- });
306
- }
295
+ includes = {};
296
+ const joinEntries = Object.entries(join);
297
+ for (const [model, joinAttr] of joinEntries) {
298
+ const limit = joinAttr.limit ?? options.advanced?.database?.defaultFindManyLimit ?? 100;
299
+ const isUnique = joinAttr.relation === "one-to-one";
300
+ const relationKey = getJoinRelationKey(model, isUnique);
301
+ includes[relationKey] = isUnique ? true : { limit };
302
+ if (!isUnique) pluralJoinResults.push({
303
+ key: relationKey,
304
+ target: model
305
+ });
307
306
  }
308
307
  const clause = convertNewWhereClause(where, model);
309
308
  const res = await db.query[queryModel].findFirst({
@@ -342,7 +341,7 @@ const drizzleAdapter = (db, config) => {
342
341
  const schemaModel = getSchema(model);
343
342
  const clause = where ? convertWhereClause(where, model) : [];
344
343
  const sortFn = sortBy?.direction === "desc" ? desc : asc;
345
- if (options.experimental?.joins) {
344
+ if (join) {
346
345
  const queryModel = getQueryModel(model);
347
346
  if (!db.query || !queryModel) {
348
347
  logger.error(`[# Drizzle Adapter]: The model "${model}" was not found in the query object. Please update your Drizzle schema to include relations or re-generate using "npx @better-auth/cli@latest generate".`);
@@ -350,19 +349,17 @@ const drizzleAdapter = (db, config) => {
350
349
  } else {
351
350
  let includes;
352
351
  const pluralJoinResults = [];
353
- if (join) {
354
- includes = {};
355
- const joinEntries = Object.entries(join);
356
- for (const [model, joinAttr] of joinEntries) {
357
- const isUnique = joinAttr.relation === "one-to-one";
358
- const limit = joinAttr.limit ?? options.advanced?.database?.defaultFindManyLimit ?? 100;
359
- const relationKey = getJoinRelationKey(model, isUnique);
360
- includes[relationKey] = isUnique ? true : { limit };
361
- if (!isUnique) pluralJoinResults.push({
362
- key: relationKey,
363
- target: model
364
- });
365
- }
352
+ includes = {};
353
+ const joinEntries = Object.entries(join);
354
+ for (const [model, joinAttr] of joinEntries) {
355
+ const isUnique = joinAttr.relation === "one-to-one";
356
+ const limit = joinAttr.limit ?? options.advanced?.database?.defaultFindManyLimit ?? 100;
357
+ const relationKey = getJoinRelationKey(model, isUnique);
358
+ includes[relationKey] = isUnique ? true : { limit };
359
+ if (!isUnique) pluralJoinResults.push({
360
+ key: relationKey,
361
+ target: model
362
+ });
366
363
  }
367
364
  let orderBy = void 0;
368
365
  if (sortBy?.field) orderBy = { [getFieldName({
@@ -419,7 +416,8 @@ const drizzleAdapter = (db, config) => {
419
416
  async update({ model, where, update: values }) {
420
417
  const schemaModel = getSchema(model);
421
418
  const clause = convertWhereClause(where, model);
422
- return await withReturning(model, db.update(schemaModel).set(values).where(...clause), values, where);
419
+ const builder = db.update(schemaModel).set(values).where(...clause);
420
+ return await withReturning(model, builder, values, where);
423
421
  },
424
422
  async updateMany({ model, where, update: values }) {
425
423
  const schemaModel = getSchema(model);
@@ -509,7 +507,7 @@ const drizzleAdapter = (db, config) => {
509
507
  return (await db.update(schemaModel).set(assignments).where(inArray(idColumn, targetIds)).returning())[0] ?? null;
510
508
  },
511
509
  async createSchema(props) {
512
- const { generateDrizzleSchema } = await import("../generate-drizzle-schema-BdVT4xKv.mjs");
510
+ const { generateDrizzleSchema } = await import("../generate-drizzle-schema-D5cxh_0D.mjs");
513
511
  return await generateDrizzleSchema({
514
512
  adapterConfig: config,
515
513
  options,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@better-auth/drizzle-adapter",
3
- "version": "1.7.0-rc.0",
3
+ "version": "1.7.0-rc.2",
4
4
  "bugs": {
5
5
  "url": "https://github.com/better-auth/better-auth/issues"
6
6
  },
@@ -45,7 +45,7 @@
45
45
  "peerDependencies": {
46
46
  "@better-auth/utils": "0.4.2",
47
47
  "drizzle-orm": "^0.45.2 || >=1.0.0-rc.1 <2.0.0",
48
- "@better-auth/core": "^1.7.0-rc.0"
48
+ "@better-auth/core": "^1.7.0-rc.2"
49
49
  },
50
50
  "peerDependenciesMeta": {
51
51
  "drizzle-orm": {
@@ -55,9 +55,9 @@
55
55
  "devDependencies": {
56
56
  "@better-auth/utils": "0.4.2",
57
57
  "drizzle-orm": "^0.45.2",
58
- "tsdown": "0.21.1",
59
- "typescript": "^5.9.3",
60
- "@better-auth/core": "1.7.0-rc.0"
58
+ "tsdown": "0.22.7",
59
+ "typescript": "^6.0.3",
60
+ "@better-auth/core": "1.7.0-rc.2"
61
61
  },
62
62
  "scripts": {
63
63
  "build": "tsdown",
@@ -65,6 +65,7 @@
65
65
  "lint:package": "publint run --strict --pack false",
66
66
  "lint:types": "attw --profile esm-only --pack .",
67
67
  "typecheck": "tsc --noEmit",
68
- "test": "vitest"
68
+ "test": "vitest",
69
+ "coverage": "vitest run --coverage --coverage.provider=istanbul"
69
70
  }
70
71
  }