@better-auth/prisma-adapter 1.5.0-beta.17 → 1.5.0-beta.19
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.
- package/README.md +17 -0
- package/package.json +22 -5
- package/.turbo/turbo-build.log +0 -16
- package/src/index.ts +0 -1
- package/src/prisma-adapter.test.ts +0 -14
- package/src/prisma-adapter.ts +0 -564
- package/tsconfig.json +0 -9
- package/tsdown.config.ts +0 -8
- package/vitest.config.ts +0 -8
package/README.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Better Auth Prisma Adapter
|
|
2
|
+
|
|
3
|
+
Prisma adapter for [Better Auth](https://www.better-auth.com).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @better-auth/prisma-adapter
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Documentation
|
|
12
|
+
|
|
13
|
+
For full documentation, visit [better-auth.com/docs/adapters/prisma](https://www.better-auth.com/docs/adapters/prisma).
|
|
14
|
+
|
|
15
|
+
## License
|
|
16
|
+
|
|
17
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,13 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-auth/prisma-adapter",
|
|
3
|
-
"version": "1.5.0-beta.
|
|
3
|
+
"version": "1.5.0-beta.19",
|
|
4
4
|
"description": "Prisma adapter for Better Auth",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"homepage": "https://www.better-auth.com/docs/adapters/prisma",
|
|
6
8
|
"repository": {
|
|
7
9
|
"type": "git",
|
|
8
10
|
"url": "git+https://github.com/better-auth/better-auth.git",
|
|
9
11
|
"directory": "packages/prisma-adapter"
|
|
10
12
|
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"auth",
|
|
15
|
+
"prisma",
|
|
16
|
+
"adapter",
|
|
17
|
+
"typescript",
|
|
18
|
+
"better-auth"
|
|
19
|
+
],
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist"
|
|
25
|
+
],
|
|
11
26
|
"main": "./dist/index.mjs",
|
|
12
27
|
"module": "./dist/index.mjs",
|
|
13
28
|
"types": "./dist/index.d.mts",
|
|
@@ -25,19 +40,21 @@
|
|
|
25
40
|
"@better-auth/utils": "^0.3.0",
|
|
26
41
|
"@prisma/client": "^5.0.0 || ^6.0.0 || ^7.0.0",
|
|
27
42
|
"prisma": "^5.0.0 || ^6.0.0 || ^7.0.0",
|
|
28
|
-
"@better-auth/core": "1.5.0-beta.
|
|
43
|
+
"@better-auth/core": "1.5.0-beta.19"
|
|
29
44
|
},
|
|
30
45
|
"devDependencies": {
|
|
31
46
|
"@better-auth/utils": "^0.3.1",
|
|
32
47
|
"prisma": "^5.0.0",
|
|
33
48
|
"tsdown": "^0.20.3",
|
|
34
49
|
"typescript": "^5.9.3",
|
|
35
|
-
"@better-auth/core": "1.5.0-beta.
|
|
50
|
+
"@better-auth/core": "1.5.0-beta.19"
|
|
36
51
|
},
|
|
37
52
|
"scripts": {
|
|
38
53
|
"build": "tsdown",
|
|
39
54
|
"dev": "tsdown --watch",
|
|
40
|
-
"
|
|
41
|
-
"
|
|
55
|
+
"lint:package": "publint run --strict",
|
|
56
|
+
"lint:types": "attw --profile esm-only --pack .",
|
|
57
|
+
"typecheck": "tsc --noEmit",
|
|
58
|
+
"test": "vitest"
|
|
42
59
|
}
|
|
43
60
|
}
|
package/.turbo/turbo-build.log
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
> @better-auth/prisma-adapter@1.5.0-beta.17 build /home/runner/work/better-auth/better-auth/packages/prisma-adapter
|
|
3
|
-
> tsdown
|
|
4
|
-
|
|
5
|
-
[34mℹ[39m tsdown [2mv0.20.3[22m powered by rolldown [2mv1.0.0-rc.3[22m
|
|
6
|
-
[34mℹ[39m config file: [4m/home/runner/work/better-auth/better-auth/packages/prisma-adapter/tsdown.config.ts[24m
|
|
7
|
-
[34mℹ[39m entry: [34msrc/index.ts[39m
|
|
8
|
-
[34mℹ[39m tsconfig: [34mtsconfig.json[39m
|
|
9
|
-
[34mℹ[39m Build start
|
|
10
|
-
[34mℹ[39m [2mdist/[22m[1mindex.mjs[22m [2m11.33 kB[22m [2m│ gzip: 2.65 kB[22m
|
|
11
|
-
[33m[PLUGIN_TIMINGS] Warning:[0m Your build spent significant time in plugin `rolldown-plugin-dts:generate`. See https://rolldown.rs/options/checks#plugintimings for more details.
|
|
12
|
-
[34mℹ[39m [2mdist/[22mindex.mjs.map [2m27.23 kB[22m [2m│ gzip: 6.47 kB[22m
|
|
13
|
-
|
|
14
|
-
[34mℹ[39m [2mdist/[22m[32m[1mindex.d.mts[22m[39m [2m 1.06 kB[22m [2m│ gzip: 0.51 kB[22m
|
|
15
|
-
[34mℹ[39m 3 files, total: 39.63 kB
|
|
16
|
-
[32m✔[39m Build complete in [32m8494ms[39m
|
package/src/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./prisma-adapter";
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi } from "vitest";
|
|
2
|
-
import { prismaAdapter } from "./prisma-adapter";
|
|
3
|
-
|
|
4
|
-
describe("prisma-adapter", () => {
|
|
5
|
-
it("should create prisma adapter", () => {
|
|
6
|
-
const prisma = {
|
|
7
|
-
$transaction: vi.fn(),
|
|
8
|
-
} as any;
|
|
9
|
-
const adapter = prismaAdapter(prisma, {
|
|
10
|
-
provider: "sqlite",
|
|
11
|
-
});
|
|
12
|
-
expect(adapter).toBeDefined();
|
|
13
|
-
});
|
|
14
|
-
});
|
package/src/prisma-adapter.ts
DELETED
|
@@ -1,564 +0,0 @@
|
|
|
1
|
-
import type { Awaitable, BetterAuthOptions } from "@better-auth/core";
|
|
2
|
-
import type {
|
|
3
|
-
AdapterFactoryCustomizeAdapterCreator,
|
|
4
|
-
AdapterFactoryOptions,
|
|
5
|
-
DBAdapter,
|
|
6
|
-
DBAdapterDebugLogOption,
|
|
7
|
-
JoinConfig,
|
|
8
|
-
Where,
|
|
9
|
-
} from "@better-auth/core/db/adapter";
|
|
10
|
-
import { createAdapterFactory } from "@better-auth/core/db/adapter";
|
|
11
|
-
import { BetterAuthError } from "@better-auth/core/error";
|
|
12
|
-
|
|
13
|
-
export interface PrismaConfig {
|
|
14
|
-
/**
|
|
15
|
-
* Database provider.
|
|
16
|
-
*/
|
|
17
|
-
provider:
|
|
18
|
-
| "sqlite"
|
|
19
|
-
| "cockroachdb"
|
|
20
|
-
| "mysql"
|
|
21
|
-
| "postgresql"
|
|
22
|
-
| "sqlserver"
|
|
23
|
-
| "mongodb";
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Enable debug logs for the adapter
|
|
27
|
-
*
|
|
28
|
-
* @default false
|
|
29
|
-
*/
|
|
30
|
-
debugLogs?: DBAdapterDebugLogOption | undefined;
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Use plural table names
|
|
34
|
-
*
|
|
35
|
-
* @default false
|
|
36
|
-
*/
|
|
37
|
-
usePlural?: boolean | undefined;
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Whether to execute multiple operations in a transaction.
|
|
41
|
-
*
|
|
42
|
-
* If the database doesn't support transactions,
|
|
43
|
-
* set this to `false` and operations will be executed sequentially.
|
|
44
|
-
* @default false
|
|
45
|
-
*/
|
|
46
|
-
transaction?: boolean | undefined;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
interface PrismaClient {}
|
|
50
|
-
|
|
51
|
-
type PrismaClientInternal = {
|
|
52
|
-
$transaction: (
|
|
53
|
-
callback: (db: PrismaClient) => Awaitable<any>,
|
|
54
|
-
) => Promise<any>;
|
|
55
|
-
} & {
|
|
56
|
-
[model: string]: {
|
|
57
|
-
create: (data: any) => Promise<any>;
|
|
58
|
-
findFirst: (data: any) => Promise<any>;
|
|
59
|
-
findMany: (data: any) => Promise<any>;
|
|
60
|
-
update: (data: any) => Promise<any>;
|
|
61
|
-
updateMany: (data: any) => Promise<any>;
|
|
62
|
-
delete: (data: any) => Promise<any>;
|
|
63
|
-
[key: string]: any;
|
|
64
|
-
};
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
export const prismaAdapter = (prisma: PrismaClient, config: PrismaConfig) => {
|
|
68
|
-
let lazyOptions: BetterAuthOptions | null = null;
|
|
69
|
-
const createCustomAdapter =
|
|
70
|
-
(prisma: PrismaClient): AdapterFactoryCustomizeAdapterCreator =>
|
|
71
|
-
({
|
|
72
|
-
getFieldName,
|
|
73
|
-
getModelName,
|
|
74
|
-
getFieldAttributes,
|
|
75
|
-
getDefaultModelName,
|
|
76
|
-
schema,
|
|
77
|
-
}) => {
|
|
78
|
-
const db = prisma as PrismaClientInternal;
|
|
79
|
-
|
|
80
|
-
const convertSelect = (
|
|
81
|
-
select: string[] | undefined,
|
|
82
|
-
model: string,
|
|
83
|
-
join?: JoinConfig | undefined,
|
|
84
|
-
) => {
|
|
85
|
-
if (!select && !join) return undefined;
|
|
86
|
-
|
|
87
|
-
const result: Record<string, Record<string, any> | boolean> = {};
|
|
88
|
-
|
|
89
|
-
if (select) {
|
|
90
|
-
for (const field of select) {
|
|
91
|
-
result[getFieldName({ model, field })] = true;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (join) {
|
|
96
|
-
// when joining that has a limit, we need to use Prisma's `select` syntax to append the limit to the field
|
|
97
|
-
// because of such, it also means we need to select all base-model fields as well
|
|
98
|
-
// should check if `select` is not provided, because then we should select all base-model fields
|
|
99
|
-
if (!select) {
|
|
100
|
-
const fields = schema[getDefaultModelName(model)]?.fields || {};
|
|
101
|
-
fields.id = { type: "string" }; // make sure there is at least an id field
|
|
102
|
-
for (const field of Object.keys(fields)) {
|
|
103
|
-
result[getFieldName({ model, field })] = true;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
for (const [joinModel, joinAttr] of Object.entries(join)) {
|
|
108
|
-
const key = getJoinKeyName(model, getModelName(joinModel), schema);
|
|
109
|
-
if (joinAttr.relation === "one-to-one") {
|
|
110
|
-
result[key] = true;
|
|
111
|
-
} else {
|
|
112
|
-
result[key] = { take: joinAttr.limit };
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
return result;
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Build the join key name based on whether the foreign field is unique or not.
|
|
122
|
-
* If unique, use singular. Otherwise, pluralize (add 's').
|
|
123
|
-
*/
|
|
124
|
-
const getJoinKeyName = (
|
|
125
|
-
baseModel: string,
|
|
126
|
-
joinedModel: string,
|
|
127
|
-
schema: any,
|
|
128
|
-
): string => {
|
|
129
|
-
try {
|
|
130
|
-
const defaultBaseModelName = getDefaultModelName(baseModel);
|
|
131
|
-
const defaultJoinedModelName = getDefaultModelName(joinedModel);
|
|
132
|
-
const key = getModelName(joinedModel).toLowerCase();
|
|
133
|
-
|
|
134
|
-
// First, check if the joined model has FKs to the base model (forward join)
|
|
135
|
-
let foreignKeys = Object.entries(
|
|
136
|
-
schema[defaultJoinedModelName]?.fields || {},
|
|
137
|
-
).filter(
|
|
138
|
-
([_field, fieldAttributes]: any) =>
|
|
139
|
-
fieldAttributes.references &&
|
|
140
|
-
getDefaultModelName(fieldAttributes.references.model) ===
|
|
141
|
-
defaultBaseModelName,
|
|
142
|
-
);
|
|
143
|
-
|
|
144
|
-
if (foreignKeys.length > 0) {
|
|
145
|
-
// Forward join: joined model has FK to base model
|
|
146
|
-
// This is typically a one-to-many relationship (plural)
|
|
147
|
-
// Unless the FK is unique, then it's one-to-one (singular)
|
|
148
|
-
const [_foreignKey, foreignKeyAttributes] = foreignKeys[0] as any;
|
|
149
|
-
// Only check if field is explicitly marked as unique
|
|
150
|
-
const isUnique = foreignKeyAttributes?.unique === true;
|
|
151
|
-
return isUnique || config.usePlural === true ? key : `${key}s`;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// Check backwards: does the base model have FKs to the joined model?
|
|
155
|
-
foreignKeys = Object.entries(
|
|
156
|
-
schema[defaultBaseModelName]?.fields || {},
|
|
157
|
-
).filter(
|
|
158
|
-
([_field, fieldAttributes]: any) =>
|
|
159
|
-
fieldAttributes.references &&
|
|
160
|
-
getDefaultModelName(fieldAttributes.references.model) ===
|
|
161
|
-
defaultJoinedModelName,
|
|
162
|
-
);
|
|
163
|
-
|
|
164
|
-
if (foreignKeys.length > 0) {
|
|
165
|
-
return key;
|
|
166
|
-
}
|
|
167
|
-
} catch {
|
|
168
|
-
// Fallback to pluralizing if we can't determine uniqueness
|
|
169
|
-
}
|
|
170
|
-
return `${getModelName(joinedModel).toLowerCase()}s`;
|
|
171
|
-
};
|
|
172
|
-
function operatorToPrismaOperator(operator: string) {
|
|
173
|
-
switch (operator) {
|
|
174
|
-
case "starts_with":
|
|
175
|
-
return "startsWith";
|
|
176
|
-
case "ends_with":
|
|
177
|
-
return "endsWith";
|
|
178
|
-
case "ne":
|
|
179
|
-
return "not";
|
|
180
|
-
case "not_in":
|
|
181
|
-
return "notIn";
|
|
182
|
-
default:
|
|
183
|
-
return operator;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
const convertWhereClause = ({
|
|
187
|
-
action,
|
|
188
|
-
model,
|
|
189
|
-
where,
|
|
190
|
-
}: {
|
|
191
|
-
model: string;
|
|
192
|
-
where?: Where[] | undefined;
|
|
193
|
-
action:
|
|
194
|
-
| "create"
|
|
195
|
-
| "update"
|
|
196
|
-
| "delete"
|
|
197
|
-
| "findOne"
|
|
198
|
-
| "findMany"
|
|
199
|
-
| "count"
|
|
200
|
-
| "updateMany"
|
|
201
|
-
| "deleteMany";
|
|
202
|
-
}) => {
|
|
203
|
-
if (!where || !where.length) return {};
|
|
204
|
-
const buildSingleCondition = (w: Where) => {
|
|
205
|
-
const fieldName = getFieldName({ model, field: w.field });
|
|
206
|
-
// Special handling for Prisma null semantics, for non-nullable fields this is a tautology. Skip condition.
|
|
207
|
-
if (w.operator === "ne" && w.value === null) {
|
|
208
|
-
const fieldAttributes = getFieldAttributes({
|
|
209
|
-
model,
|
|
210
|
-
field: w.field,
|
|
211
|
-
});
|
|
212
|
-
const isNullable = fieldAttributes?.required !== true;
|
|
213
|
-
return isNullable ? { [fieldName]: { not: null } } : {};
|
|
214
|
-
}
|
|
215
|
-
if (
|
|
216
|
-
(w.operator === "in" || w.operator === "not_in") &&
|
|
217
|
-
Array.isArray(w.value)
|
|
218
|
-
) {
|
|
219
|
-
const filtered = w.value.filter((v) => v != null);
|
|
220
|
-
if (filtered.length === 0) {
|
|
221
|
-
if (w.operator === "in") {
|
|
222
|
-
return {
|
|
223
|
-
AND: [
|
|
224
|
-
{ [fieldName]: { equals: "__never__" } },
|
|
225
|
-
{ [fieldName]: { not: "__never__" } },
|
|
226
|
-
],
|
|
227
|
-
};
|
|
228
|
-
} else {
|
|
229
|
-
return {};
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
const prismaOp = operatorToPrismaOperator(w.operator);
|
|
233
|
-
return { [fieldName]: { [prismaOp]: filtered } };
|
|
234
|
-
}
|
|
235
|
-
if (w.operator === "eq" || !w.operator) {
|
|
236
|
-
return { [fieldName]: w.value };
|
|
237
|
-
}
|
|
238
|
-
return {
|
|
239
|
-
[fieldName]: {
|
|
240
|
-
[operatorToPrismaOperator(w.operator)]: w.value,
|
|
241
|
-
},
|
|
242
|
-
};
|
|
243
|
-
};
|
|
244
|
-
|
|
245
|
-
// Special handling for update actions: extract AND conditions with eq operator to root level
|
|
246
|
-
// Prisma requires unique fields to be at root level, not nested in AND arrays
|
|
247
|
-
// Only simple equality conditions can be at root level; complex operators must stay in AND array
|
|
248
|
-
if (action === "update") {
|
|
249
|
-
const and = where.filter(
|
|
250
|
-
(w) => w.connector === "AND" || !w.connector,
|
|
251
|
-
);
|
|
252
|
-
const or = where.filter((w) => w.connector === "OR");
|
|
253
|
-
|
|
254
|
-
// Separate AND conditions into simple eq (can extract) and complex (must stay in AND)
|
|
255
|
-
const andSimple = and.filter(
|
|
256
|
-
(w) => w.operator === "eq" || !w.operator,
|
|
257
|
-
);
|
|
258
|
-
const andComplex = and.filter(
|
|
259
|
-
(w) => w.operator !== "eq" && w.operator !== undefined,
|
|
260
|
-
);
|
|
261
|
-
|
|
262
|
-
const andSimpleClause = andSimple.map((w) => buildSingleCondition(w));
|
|
263
|
-
const andComplexClause = andComplex.map((w) =>
|
|
264
|
-
buildSingleCondition(w),
|
|
265
|
-
);
|
|
266
|
-
const orClause = or.map((w) => buildSingleCondition(w));
|
|
267
|
-
|
|
268
|
-
// Extract simple equality AND conditions to root level
|
|
269
|
-
const result: Record<string, any> = {};
|
|
270
|
-
for (const clause of andSimpleClause) {
|
|
271
|
-
Object.assign(result, clause);
|
|
272
|
-
}
|
|
273
|
-
// Keep complex AND conditions in AND array
|
|
274
|
-
if (andComplexClause.length > 0) {
|
|
275
|
-
result.AND = andComplexClause;
|
|
276
|
-
}
|
|
277
|
-
if (orClause.length > 0) {
|
|
278
|
-
result.OR = orClause;
|
|
279
|
-
}
|
|
280
|
-
return result;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
// Special handling for delete actions: extract id to root level
|
|
284
|
-
if (action === "delete") {
|
|
285
|
-
const idCondition = where.find((w) => w.field === "id");
|
|
286
|
-
if (idCondition) {
|
|
287
|
-
const idFieldName = getFieldName({ model, field: "id" });
|
|
288
|
-
const idClause = buildSingleCondition(idCondition);
|
|
289
|
-
const remainingWhere = where.filter((w) => w.field !== "id");
|
|
290
|
-
|
|
291
|
-
if (remainingWhere.length === 0) {
|
|
292
|
-
return idClause;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
const and = remainingWhere.filter(
|
|
296
|
-
(w) => w.connector === "AND" || !w.connector,
|
|
297
|
-
);
|
|
298
|
-
const or = remainingWhere.filter((w) => w.connector === "OR");
|
|
299
|
-
const andClause = and.map((w) => buildSingleCondition(w));
|
|
300
|
-
const orClause = or.map((w) => buildSingleCondition(w));
|
|
301
|
-
|
|
302
|
-
// Extract id to root level, put other conditions in AND array
|
|
303
|
-
const result: Record<string, any> = {};
|
|
304
|
-
if (idFieldName in idClause) {
|
|
305
|
-
result[idFieldName] = (idClause as Record<string, any>)[
|
|
306
|
-
idFieldName
|
|
307
|
-
];
|
|
308
|
-
} else {
|
|
309
|
-
// Handle edge case where idClause might have special structure
|
|
310
|
-
Object.assign(result, idClause);
|
|
311
|
-
}
|
|
312
|
-
if (andClause.length > 0) {
|
|
313
|
-
result.AND = andClause;
|
|
314
|
-
}
|
|
315
|
-
if (orClause.length > 0) {
|
|
316
|
-
result.OR = orClause;
|
|
317
|
-
}
|
|
318
|
-
return result;
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
if (where.length === 1) {
|
|
323
|
-
const w = where[0]!;
|
|
324
|
-
if (!w) {
|
|
325
|
-
return;
|
|
326
|
-
}
|
|
327
|
-
return buildSingleCondition(w);
|
|
328
|
-
}
|
|
329
|
-
const and = where.filter((w) => w.connector === "AND" || !w.connector);
|
|
330
|
-
const or = where.filter((w) => w.connector === "OR");
|
|
331
|
-
const andClause = and.map((w) => buildSingleCondition(w));
|
|
332
|
-
const orClause = or.map((w) => buildSingleCondition(w));
|
|
333
|
-
|
|
334
|
-
return {
|
|
335
|
-
...(andClause.length ? { AND: andClause } : {}),
|
|
336
|
-
...(orClause.length ? { OR: orClause } : {}),
|
|
337
|
-
};
|
|
338
|
-
};
|
|
339
|
-
|
|
340
|
-
return {
|
|
341
|
-
async create({ model, data: values, select }) {
|
|
342
|
-
if (!db[model]) {
|
|
343
|
-
throw new BetterAuthError(
|
|
344
|
-
`Model ${model} does not exist in the database. If you haven't generated the Prisma client, you need to run 'npx prisma generate'`,
|
|
345
|
-
);
|
|
346
|
-
}
|
|
347
|
-
const result = await db[model]!.create({
|
|
348
|
-
data: values,
|
|
349
|
-
select: convertSelect(select, model),
|
|
350
|
-
});
|
|
351
|
-
return result;
|
|
352
|
-
},
|
|
353
|
-
async findOne({ model, where, select, join }) {
|
|
354
|
-
// this is just "JoinOption" type because we disabled join transformation in adapter config
|
|
355
|
-
const whereClause = convertWhereClause({
|
|
356
|
-
model,
|
|
357
|
-
where,
|
|
358
|
-
action: "findOne",
|
|
359
|
-
});
|
|
360
|
-
if (!db[model]) {
|
|
361
|
-
throw new BetterAuthError(
|
|
362
|
-
`Model ${model} does not exist in the database. If you haven't generated the Prisma client, you need to run 'npx prisma generate'`,
|
|
363
|
-
);
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
// transform join keys to use Prisma expected field names
|
|
367
|
-
const map = new Map<string, string>();
|
|
368
|
-
for (const joinModel of Object.keys(join ?? {})) {
|
|
369
|
-
const key = getJoinKeyName(model, joinModel, schema);
|
|
370
|
-
map.set(key, getModelName(joinModel));
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
const selects = convertSelect(select, model, join);
|
|
374
|
-
|
|
375
|
-
const result = await db[model]!.findFirst({
|
|
376
|
-
where: whereClause,
|
|
377
|
-
select: selects,
|
|
378
|
-
});
|
|
379
|
-
|
|
380
|
-
// transform the resulting `include` items to use better-auth expected field names
|
|
381
|
-
if (join && result) {
|
|
382
|
-
for (const [includeKey, originalKey] of map.entries()) {
|
|
383
|
-
if (includeKey === originalKey) continue;
|
|
384
|
-
if (includeKey in result) {
|
|
385
|
-
result[originalKey] = result[includeKey];
|
|
386
|
-
delete result[includeKey];
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
return result;
|
|
391
|
-
},
|
|
392
|
-
async findMany({ model, where, limit, select, offset, sortBy, join }) {
|
|
393
|
-
// this is just "JoinOption" type because we disabled join transformation in adapter config
|
|
394
|
-
const whereClause = convertWhereClause({
|
|
395
|
-
model,
|
|
396
|
-
where,
|
|
397
|
-
action: "findMany",
|
|
398
|
-
});
|
|
399
|
-
if (!db[model]) {
|
|
400
|
-
throw new BetterAuthError(
|
|
401
|
-
`Model ${model} does not exist in the database. If you haven't generated the Prisma client, you need to run 'npx prisma generate'`,
|
|
402
|
-
);
|
|
403
|
-
}
|
|
404
|
-
// transform join keys to use Prisma expected field names
|
|
405
|
-
const map = new Map<string, string>();
|
|
406
|
-
if (join) {
|
|
407
|
-
for (const [joinModel, _value] of Object.entries(join)) {
|
|
408
|
-
const key = getJoinKeyName(model, joinModel, schema);
|
|
409
|
-
map.set(key, getModelName(joinModel));
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
const selects = convertSelect(select, model, join);
|
|
414
|
-
|
|
415
|
-
const result = await db[model]!.findMany({
|
|
416
|
-
where: whereClause,
|
|
417
|
-
take: limit || 100,
|
|
418
|
-
skip: offset || 0,
|
|
419
|
-
...(sortBy?.field
|
|
420
|
-
? {
|
|
421
|
-
orderBy: {
|
|
422
|
-
[getFieldName({ model, field: sortBy.field })]:
|
|
423
|
-
sortBy.direction === "desc" ? "desc" : "asc",
|
|
424
|
-
},
|
|
425
|
-
}
|
|
426
|
-
: {}),
|
|
427
|
-
select: selects,
|
|
428
|
-
});
|
|
429
|
-
|
|
430
|
-
// transform the resulting join items to use better-auth expected field names
|
|
431
|
-
if (join && Array.isArray(result)) {
|
|
432
|
-
for (const item of result) {
|
|
433
|
-
for (const [includeKey, originalKey] of map.entries()) {
|
|
434
|
-
if (includeKey === originalKey) continue;
|
|
435
|
-
if (includeKey in item) {
|
|
436
|
-
item[originalKey] = item[includeKey];
|
|
437
|
-
delete item[includeKey];
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
return result;
|
|
444
|
-
},
|
|
445
|
-
async count({ model, where }) {
|
|
446
|
-
const whereClause = convertWhereClause({
|
|
447
|
-
model,
|
|
448
|
-
where,
|
|
449
|
-
action: "count",
|
|
450
|
-
});
|
|
451
|
-
if (!db[model]) {
|
|
452
|
-
throw new BetterAuthError(
|
|
453
|
-
`Model ${model} does not exist in the database. If you haven't generated the Prisma client, you need to run 'npx prisma generate'`,
|
|
454
|
-
);
|
|
455
|
-
}
|
|
456
|
-
return await db[model]!.count({
|
|
457
|
-
where: whereClause,
|
|
458
|
-
});
|
|
459
|
-
},
|
|
460
|
-
async update({ model, where, update }) {
|
|
461
|
-
if (!db[model]) {
|
|
462
|
-
throw new BetterAuthError(
|
|
463
|
-
`Model ${model} does not exist in the database. If you haven't generated the Prisma client, you need to run 'npx prisma generate'`,
|
|
464
|
-
);
|
|
465
|
-
}
|
|
466
|
-
const whereClause = convertWhereClause({
|
|
467
|
-
model,
|
|
468
|
-
where,
|
|
469
|
-
action: "update",
|
|
470
|
-
});
|
|
471
|
-
|
|
472
|
-
return await db[model]!.update({
|
|
473
|
-
where: whereClause,
|
|
474
|
-
data: update,
|
|
475
|
-
});
|
|
476
|
-
},
|
|
477
|
-
async updateMany({ model, where, update }) {
|
|
478
|
-
if (!db[model]) {
|
|
479
|
-
throw new BetterAuthError(
|
|
480
|
-
`Model ${model} does not exist in the database. If you haven't generated the Prisma client, you need to run 'npx prisma generate'`,
|
|
481
|
-
);
|
|
482
|
-
}
|
|
483
|
-
const whereClause = convertWhereClause({
|
|
484
|
-
model,
|
|
485
|
-
where,
|
|
486
|
-
action: "updateMany",
|
|
487
|
-
});
|
|
488
|
-
const result = await db[model]!.updateMany({
|
|
489
|
-
where: whereClause,
|
|
490
|
-
data: update,
|
|
491
|
-
});
|
|
492
|
-
return result ? (result.count as number) : 0;
|
|
493
|
-
},
|
|
494
|
-
async delete({ model, where }) {
|
|
495
|
-
if (!db[model]) {
|
|
496
|
-
throw new BetterAuthError(
|
|
497
|
-
`Model ${model} does not exist in the database. If you haven't generated the Prisma client, you need to run 'npx prisma generate'`,
|
|
498
|
-
);
|
|
499
|
-
}
|
|
500
|
-
const whereClause = convertWhereClause({
|
|
501
|
-
model,
|
|
502
|
-
where,
|
|
503
|
-
action: "delete",
|
|
504
|
-
});
|
|
505
|
-
try {
|
|
506
|
-
await db[model]!.delete({
|
|
507
|
-
where: whereClause,
|
|
508
|
-
});
|
|
509
|
-
} catch (e: any) {
|
|
510
|
-
// If the record doesn't exist, we don't want to throw an error
|
|
511
|
-
if (e?.meta?.cause === "Record to delete does not exist.") return;
|
|
512
|
-
if (e?.code === "P2025") return; // Prisma 7+
|
|
513
|
-
// otherwise if it's an unknown error, we want to just log it for debugging.
|
|
514
|
-
console.log(e);
|
|
515
|
-
}
|
|
516
|
-
},
|
|
517
|
-
async deleteMany({ model, where }) {
|
|
518
|
-
const whereClause = convertWhereClause({
|
|
519
|
-
model,
|
|
520
|
-
where,
|
|
521
|
-
action: "deleteMany",
|
|
522
|
-
});
|
|
523
|
-
const result = await db[model]!.deleteMany({
|
|
524
|
-
where: whereClause,
|
|
525
|
-
});
|
|
526
|
-
return result ? (result.count as number) : 0;
|
|
527
|
-
},
|
|
528
|
-
options: config,
|
|
529
|
-
};
|
|
530
|
-
};
|
|
531
|
-
|
|
532
|
-
let adapterOptions: AdapterFactoryOptions | null = null;
|
|
533
|
-
adapterOptions = {
|
|
534
|
-
config: {
|
|
535
|
-
adapterId: "prisma",
|
|
536
|
-
adapterName: "Prisma Adapter",
|
|
537
|
-
usePlural: config.usePlural ?? false,
|
|
538
|
-
debugLogs: config.debugLogs ?? false,
|
|
539
|
-
supportsUUIDs: config.provider === "postgresql" ? true : false,
|
|
540
|
-
supportsArrays:
|
|
541
|
-
config.provider === "postgresql" || config.provider === "mongodb"
|
|
542
|
-
? true
|
|
543
|
-
: false,
|
|
544
|
-
transaction:
|
|
545
|
-
(config.transaction ?? false)
|
|
546
|
-
? (cb) =>
|
|
547
|
-
(prisma as PrismaClientInternal).$transaction((tx) => {
|
|
548
|
-
const adapter = createAdapterFactory({
|
|
549
|
-
config: adapterOptions!.config,
|
|
550
|
-
adapter: createCustomAdapter(tx),
|
|
551
|
-
})(lazyOptions!);
|
|
552
|
-
return cb(adapter);
|
|
553
|
-
})
|
|
554
|
-
: false,
|
|
555
|
-
},
|
|
556
|
-
adapter: createCustomAdapter(prisma),
|
|
557
|
-
};
|
|
558
|
-
|
|
559
|
-
const adapter = createAdapterFactory(adapterOptions);
|
|
560
|
-
return (options: BetterAuthOptions): DBAdapter<BetterAuthOptions> => {
|
|
561
|
-
lazyOptions = options;
|
|
562
|
-
return adapter(options);
|
|
563
|
-
};
|
|
564
|
-
};
|
package/tsconfig.json
DELETED
package/tsdown.config.ts
DELETED