@nest-admin/nestjs 0.11.0
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/LICENSE +21 -0
- package/README.md +252 -0
- package/dist/admin-ui/assets/index-AyWOamlt.js +50 -0
- package/dist/admin-ui/assets/index-AyWOamlt.js.map +1 -0
- package/dist/admin-ui/assets/index-D4Eh84eD.css +2 -0
- package/dist/admin-ui/index.html +14 -0
- package/dist/chunk-7IXLRGGQ.js +356 -0
- package/dist/chunk-7IXLRGGQ.js.map +1 -0
- package/dist/drizzle.cjs +895 -0
- package/dist/drizzle.cjs.map +1 -0
- package/dist/drizzle.d.cts +335 -0
- package/dist/drizzle.d.ts +335 -0
- package/dist/drizzle.js +756 -0
- package/dist/drizzle.js.map +1 -0
- package/dist/index.cjs +3247 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1652 -0
- package/dist/index.d.ts +1652 -0
- package/dist/index.js +2901 -0
- package/dist/index.js.map +1 -0
- package/dist/prisma.cjs +1159 -0
- package/dist/prisma.cjs.map +1 -0
- package/dist/prisma.d.cts +585 -0
- package/dist/prisma.d.ts +585 -0
- package/dist/prisma.js +995 -0
- package/dist/prisma.js.map +1 -0
- package/package.json +130 -0
package/dist/drizzle.cjs
ADDED
|
@@ -0,0 +1,895 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc2) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc2 = __getOwnPropDesc(from, key)) || desc2.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
|
|
31
|
+
// src/drizzle.ts
|
|
32
|
+
var drizzle_exports = {};
|
|
33
|
+
__export(drizzle_exports, {
|
|
34
|
+
DEFAULT_PER_PAGE: () => DEFAULT_PER_PAGE,
|
|
35
|
+
DrizzleAdapter: () => DrizzleAdapter,
|
|
36
|
+
MAX_PER_PAGE: () => MAX_PER_PAGE
|
|
37
|
+
});
|
|
38
|
+
module.exports = __toCommonJS(drizzle_exports);
|
|
39
|
+
|
|
40
|
+
// ../core/dist/index.js
|
|
41
|
+
var BRAND = /* @__PURE__ */ Symbol.for("nest-admin.error");
|
|
42
|
+
var NestAdminError = class extends Error {
|
|
43
|
+
static {
|
|
44
|
+
__name(this, "NestAdminError");
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Which error this is.
|
|
48
|
+
*
|
|
49
|
+
* Subclasses override it with a literal. The base value covers anything that
|
|
50
|
+
* extends this class without declaring one - the Prisma schema errors, for
|
|
51
|
+
* instance - which the transport layer treats as internal.
|
|
52
|
+
*/
|
|
53
|
+
kind = "unknown";
|
|
54
|
+
constructor(message, options) {
|
|
55
|
+
super(message, options);
|
|
56
|
+
this.name = new.target.name;
|
|
57
|
+
Object.defineProperty(this, BRAND, {
|
|
58
|
+
value: true,
|
|
59
|
+
enumerable: false
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
function isNestAdminError(value) {
|
|
64
|
+
return typeof value === "object" && value !== null && value[BRAND] === true;
|
|
65
|
+
}
|
|
66
|
+
__name(isNestAdminError, "isNestAdminError");
|
|
67
|
+
var ModelNotFoundError = class extends NestAdminError {
|
|
68
|
+
static {
|
|
69
|
+
__name(this, "ModelNotFoundError");
|
|
70
|
+
}
|
|
71
|
+
constructor(model, availableModels = []) {
|
|
72
|
+
const known = availableModels.length > 0 ? ` Known models: ${availableModels.join(", ")}.` : "";
|
|
73
|
+
super(`Unknown model "${model}".${known}`);
|
|
74
|
+
this.model = model;
|
|
75
|
+
this.availableModels = availableModels;
|
|
76
|
+
}
|
|
77
|
+
model;
|
|
78
|
+
availableModels;
|
|
79
|
+
kind = "model-not-found";
|
|
80
|
+
};
|
|
81
|
+
var FieldNotFoundError = class extends NestAdminError {
|
|
82
|
+
static {
|
|
83
|
+
__name(this, "FieldNotFoundError");
|
|
84
|
+
}
|
|
85
|
+
constructor(model, field, reason) {
|
|
86
|
+
super(`Unknown field "${field}" on model "${model}".${reason ? ` ${reason}` : ""}`);
|
|
87
|
+
this.model = model;
|
|
88
|
+
this.field = field;
|
|
89
|
+
}
|
|
90
|
+
model;
|
|
91
|
+
field;
|
|
92
|
+
kind = "field-not-found";
|
|
93
|
+
};
|
|
94
|
+
var RecordNotFoundError = class extends NestAdminError {
|
|
95
|
+
static {
|
|
96
|
+
__name(this, "RecordNotFoundError");
|
|
97
|
+
}
|
|
98
|
+
constructor(model, id) {
|
|
99
|
+
super(`No ${model} record found for id ${JSON.stringify(id)}.`);
|
|
100
|
+
this.model = model;
|
|
101
|
+
this.id = id;
|
|
102
|
+
}
|
|
103
|
+
model;
|
|
104
|
+
id;
|
|
105
|
+
kind = "record-not-found";
|
|
106
|
+
};
|
|
107
|
+
var InvalidQueryError = class extends NestAdminError {
|
|
108
|
+
static {
|
|
109
|
+
__name(this, "InvalidQueryError");
|
|
110
|
+
}
|
|
111
|
+
kind = "invalid-query";
|
|
112
|
+
};
|
|
113
|
+
var ConstraintError = class extends NestAdminError {
|
|
114
|
+
static {
|
|
115
|
+
__name(this, "ConstraintError");
|
|
116
|
+
}
|
|
117
|
+
constructor(constraint, model, fields = []) {
|
|
118
|
+
super(describeConstraint(constraint, model, fields));
|
|
119
|
+
this.constraint = constraint;
|
|
120
|
+
this.model = model;
|
|
121
|
+
this.fields = fields;
|
|
122
|
+
}
|
|
123
|
+
constraint;
|
|
124
|
+
model;
|
|
125
|
+
fields;
|
|
126
|
+
kind = "constraint";
|
|
127
|
+
};
|
|
128
|
+
function describeConstraint(constraint, model, fields) {
|
|
129
|
+
const named = fields.length > 0 ? fields.join(", ") : void 0;
|
|
130
|
+
switch (constraint) {
|
|
131
|
+
case "unique":
|
|
132
|
+
return named ? `Another ${model} already has this ${named}.` : `Another ${model} already has one of these values.`;
|
|
133
|
+
case "foreign-key":
|
|
134
|
+
return named ? `The ${named} does not refer to an existing record, or the record it refers to is still in use.` : `A reference on this ${model} does not point at an existing record, or is still in use.`;
|
|
135
|
+
case "required":
|
|
136
|
+
return named ? `${named} is required.` : `A required value on this ${model} is missing.`;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
__name(describeConstraint, "describeConstraint");
|
|
140
|
+
var AdapterError = class extends NestAdminError {
|
|
141
|
+
static {
|
|
142
|
+
__name(this, "AdapterError");
|
|
143
|
+
}
|
|
144
|
+
kind = "adapter";
|
|
145
|
+
constructor(message, options) {
|
|
146
|
+
super(message, options);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
// ../drizzle/dist/index.js
|
|
151
|
+
var import_drizzle_orm = require("drizzle-orm");
|
|
152
|
+
var import_drizzle_orm2 = require("drizzle-orm");
|
|
153
|
+
var import_drizzle_orm3 = require("drizzle-orm");
|
|
154
|
+
var import_drizzle_orm4 = require("drizzle-orm");
|
|
155
|
+
function driverErrorOf(cause) {
|
|
156
|
+
if (typeof cause !== "object" || cause === null) return void 0;
|
|
157
|
+
const error = cause;
|
|
158
|
+
const inner = error.cause;
|
|
159
|
+
if (typeof error.code !== "string" && typeof inner === "object" && inner !== null) {
|
|
160
|
+
return inner;
|
|
161
|
+
}
|
|
162
|
+
return error;
|
|
163
|
+
}
|
|
164
|
+
__name(driverErrorOf, "driverErrorOf");
|
|
165
|
+
var SQLITE_KINDS = {
|
|
166
|
+
SQLITE_CONSTRAINT_UNIQUE: "unique",
|
|
167
|
+
SQLITE_CONSTRAINT_PRIMARYKEY: "unique",
|
|
168
|
+
SQLITE_CONSTRAINT_NOTNULL: "required",
|
|
169
|
+
SQLITE_CONSTRAINT_FOREIGNKEY: "foreign-key",
|
|
170
|
+
SQLITE_CONSTRAINT_TRIGGER: "foreign-key"
|
|
171
|
+
};
|
|
172
|
+
var CODE_KINDS = {
|
|
173
|
+
// Postgres
|
|
174
|
+
"23505": "unique",
|
|
175
|
+
"23503": "foreign-key",
|
|
176
|
+
"23502": "required",
|
|
177
|
+
// MySQL
|
|
178
|
+
ER_DUP_ENTRY: "unique",
|
|
179
|
+
ER_NO_REFERENCED_ROW_2: "foreign-key",
|
|
180
|
+
ER_ROW_IS_REFERENCED_2: "foreign-key",
|
|
181
|
+
ER_BAD_NULL_ERROR: "required"
|
|
182
|
+
};
|
|
183
|
+
function sqliteColumns(message) {
|
|
184
|
+
const listed = /constraint failed: (.+)$/i.exec(message)?.[1];
|
|
185
|
+
if (listed === void 0) return [];
|
|
186
|
+
return listed.split(",").map((entry) => entry.trim().split(".").at(-1) ?? "").filter((entry) => entry !== "");
|
|
187
|
+
}
|
|
188
|
+
__name(sqliteColumns, "sqliteColumns");
|
|
189
|
+
function postgresColumns(error) {
|
|
190
|
+
if (typeof error.column === "string" && error.column !== "") return [
|
|
191
|
+
error.column
|
|
192
|
+
];
|
|
193
|
+
if (typeof error.detail === "string") {
|
|
194
|
+
const key = /^Key \(([^)]+)\)=/.exec(error.detail)?.[1];
|
|
195
|
+
if (key !== void 0) return key.split(",").map((entry) => entry.trim());
|
|
196
|
+
}
|
|
197
|
+
if (typeof error.constraint === "string") {
|
|
198
|
+
const index = /^(.+?)_(.+)_(key|pkey|fkey)$/.exec(error.constraint);
|
|
199
|
+
if (index?.[2] !== void 0) return index[2].split("_");
|
|
200
|
+
}
|
|
201
|
+
return [];
|
|
202
|
+
}
|
|
203
|
+
__name(postgresColumns, "postgresColumns");
|
|
204
|
+
function toConstraintError(cause, model, toFieldNames) {
|
|
205
|
+
const error = driverErrorOf(cause);
|
|
206
|
+
if (error === void 0) return void 0;
|
|
207
|
+
const code = typeof error.code === "string" ? error.code : void 0;
|
|
208
|
+
const message = typeof error.message === "string" ? error.message : "";
|
|
209
|
+
if (code !== void 0 && code in SQLITE_KINDS) {
|
|
210
|
+
return new ConstraintError(SQLITE_KINDS[code], model, toFieldNames(sqliteColumns(message)));
|
|
211
|
+
}
|
|
212
|
+
if (code !== void 0 && code in CODE_KINDS) {
|
|
213
|
+
return new ConstraintError(CODE_KINDS[code], model, toFieldNames(postgresColumns(error)));
|
|
214
|
+
}
|
|
215
|
+
if (code === "SQLITE_CONSTRAINT" || code === void 0 && /constraint failed/i.test(message)) {
|
|
216
|
+
const kind = /UNIQUE/i.test(message) ? "unique" : /NOT NULL/i.test(message) ? "required" : "foreign-key";
|
|
217
|
+
return new ConstraintError(kind, model, toFieldNames(sqliteColumns(message)));
|
|
218
|
+
}
|
|
219
|
+
return void 0;
|
|
220
|
+
}
|
|
221
|
+
__name(toConstraintError, "toConstraintError");
|
|
222
|
+
var KINDS = {
|
|
223
|
+
string: "string",
|
|
224
|
+
number: "number",
|
|
225
|
+
boolean: "boolean",
|
|
226
|
+
date: "datetime",
|
|
227
|
+
json: "json",
|
|
228
|
+
bigint: "string",
|
|
229
|
+
buffer: "unknown",
|
|
230
|
+
array: "unknown",
|
|
231
|
+
custom: "unknown"
|
|
232
|
+
};
|
|
233
|
+
function kindOf(column) {
|
|
234
|
+
if (column.enumValues !== void 0 && column.enumValues.length > 0) return "enum";
|
|
235
|
+
return KINDS[column.dataType] ?? "unknown";
|
|
236
|
+
}
|
|
237
|
+
__name(kindOf, "kindOf");
|
|
238
|
+
function isGenerated(column) {
|
|
239
|
+
return column.autoIncrement === true || typeof column.defaultFn === "function" || typeof column.onUpdateFn === "function" || (0, import_drizzle_orm2.is)(column.default, import_drizzle_orm2.SQL);
|
|
240
|
+
}
|
|
241
|
+
__name(isGenerated, "isGenerated");
|
|
242
|
+
function literalDefault(column) {
|
|
243
|
+
if (!column.hasDefault || isGenerated(column)) return void 0;
|
|
244
|
+
return column.default;
|
|
245
|
+
}
|
|
246
|
+
__name(literalDefault, "literalDefault");
|
|
247
|
+
function toField(key, column, primaryKey) {
|
|
248
|
+
const isId = primaryKey.includes(key);
|
|
249
|
+
const defaultValue = literalDefault(column);
|
|
250
|
+
return {
|
|
251
|
+
name: key,
|
|
252
|
+
kind: kindOf(column),
|
|
253
|
+
isId,
|
|
254
|
+
isRequired: column.notNull,
|
|
255
|
+
// A primary key is unique whether or not anyone said so.
|
|
256
|
+
isUnique: column.isUnique || isId,
|
|
257
|
+
// Drizzle has no list columns outside Postgres arrays, which arrive as
|
|
258
|
+
// `dataType: 'array'` and are mapped to `unknown` above.
|
|
259
|
+
isList: false,
|
|
260
|
+
isGenerated: isGenerated(column),
|
|
261
|
+
...defaultValue !== void 0 ? {
|
|
262
|
+
defaultValue
|
|
263
|
+
} : {},
|
|
264
|
+
...column.enumValues !== void 0 && column.enumValues.length > 0 ? {
|
|
265
|
+
enumValues: [
|
|
266
|
+
...column.enumValues
|
|
267
|
+
]
|
|
268
|
+
} : {}
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
__name(toField, "toField");
|
|
272
|
+
function primaryKeyOf(entry, composite) {
|
|
273
|
+
const declared = composite.get(entry.model);
|
|
274
|
+
if (declared && declared.length > 0) return declared;
|
|
275
|
+
const inline = [];
|
|
276
|
+
for (const [key, column] of entry.columns) {
|
|
277
|
+
if (column.primary) inline.push(key);
|
|
278
|
+
}
|
|
279
|
+
return inline;
|
|
280
|
+
}
|
|
281
|
+
__name(primaryKeyOf, "primaryKeyOf");
|
|
282
|
+
function toModelMetadata(input) {
|
|
283
|
+
const { schema, compositeKeys } = input;
|
|
284
|
+
return schema.tables.map((entry) => {
|
|
285
|
+
const primaryKey = primaryKeyOf(entry, compositeKeys);
|
|
286
|
+
const columns = [];
|
|
287
|
+
for (const [key, column] of entry.columns) {
|
|
288
|
+
columns.push(toField(key, column, primaryKey));
|
|
289
|
+
}
|
|
290
|
+
const relations = schema.relations.filter((relation) => relation.model === entry.model).map((relation) => ({
|
|
291
|
+
name: relation.field,
|
|
292
|
+
kind: "relation",
|
|
293
|
+
isId: false,
|
|
294
|
+
// A to-one is required exactly when its foreign key is. A to-many never
|
|
295
|
+
// is: a parent with no children is a parent.
|
|
296
|
+
isRequired: relation.cardinality === "one" && relation.from !== void 0 ? entry.columns.get(relation.from)?.notNull ?? false : false,
|
|
297
|
+
isUnique: false,
|
|
298
|
+
isList: relation.cardinality === "many",
|
|
299
|
+
isGenerated: false,
|
|
300
|
+
relation: {
|
|
301
|
+
targetModel: relation.targetModel,
|
|
302
|
+
cardinality: relation.cardinality,
|
|
303
|
+
name: relation.name,
|
|
304
|
+
...relation.from !== void 0 ? {
|
|
305
|
+
from: relation.from
|
|
306
|
+
} : {},
|
|
307
|
+
...relation.to !== void 0 ? {
|
|
308
|
+
to: relation.to
|
|
309
|
+
} : {}
|
|
310
|
+
}
|
|
311
|
+
}));
|
|
312
|
+
return {
|
|
313
|
+
name: entry.model,
|
|
314
|
+
primaryKey,
|
|
315
|
+
fields: [
|
|
316
|
+
...columns,
|
|
317
|
+
...relations
|
|
318
|
+
]
|
|
319
|
+
};
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
__name(toModelMetadata, "toModelMetadata");
|
|
323
|
+
var DEFAULT_PER_PAGE = 25;
|
|
324
|
+
var MAX_PER_PAGE = 100;
|
|
325
|
+
var STRING_ONLY = /* @__PURE__ */ new Set([
|
|
326
|
+
"contains",
|
|
327
|
+
"startsWith",
|
|
328
|
+
"endsWith"
|
|
329
|
+
]);
|
|
330
|
+
var COMPARISON = /* @__PURE__ */ new Set([
|
|
331
|
+
"gt",
|
|
332
|
+
"gte",
|
|
333
|
+
"lt",
|
|
334
|
+
"lte"
|
|
335
|
+
]);
|
|
336
|
+
function queryable(model, fieldName, purpose) {
|
|
337
|
+
const field = model.fields.find((candidate) => candidate.name === fieldName);
|
|
338
|
+
if (!field) throw new FieldNotFoundError(model.name, fieldName);
|
|
339
|
+
if (field.kind === "relation") {
|
|
340
|
+
const owned = field.relation?.from;
|
|
341
|
+
if (owned !== void 0 && field.relation?.cardinality === "one") {
|
|
342
|
+
if (purpose === "filter") return queryable(model, owned, purpose);
|
|
343
|
+
throw new FieldNotFoundError(model.name, fieldName, `Sorting by a relation is not supported in this version. Sorting by "${owned}" would order by an opaque key rather than by anything readable.`);
|
|
344
|
+
}
|
|
345
|
+
throw new FieldNotFoundError(model.name, fieldName, "Relation fields cannot be filtered or sorted in this version.");
|
|
346
|
+
}
|
|
347
|
+
if (field.isList) {
|
|
348
|
+
throw new FieldNotFoundError(model.name, fieldName, "List fields cannot be filtered or sorted in this version.");
|
|
349
|
+
}
|
|
350
|
+
return field;
|
|
351
|
+
}
|
|
352
|
+
__name(queryable, "queryable");
|
|
353
|
+
function columnOf(entry, field) {
|
|
354
|
+
const column = entry.columns.get(field.name);
|
|
355
|
+
if (column === void 0) {
|
|
356
|
+
throw new FieldNotFoundError(entry.model, field.name);
|
|
357
|
+
}
|
|
358
|
+
return column;
|
|
359
|
+
}
|
|
360
|
+
__name(columnOf, "columnOf");
|
|
361
|
+
function escapeLike(term) {
|
|
362
|
+
return term.replace(/[\\%_]/g, (match) => `\\${match}`);
|
|
363
|
+
}
|
|
364
|
+
__name(escapeLike, "escapeLike");
|
|
365
|
+
function insensitiveLike(column, pattern) {
|
|
366
|
+
return import_drizzle_orm3.sql`lower(${column}) LIKE lower(${pattern}) ESCAPE '\\'`;
|
|
367
|
+
}
|
|
368
|
+
__name(insensitiveLike, "insensitiveLike");
|
|
369
|
+
function condition(model, entry, rule) {
|
|
370
|
+
const field = queryable(model, rule.field, "filter");
|
|
371
|
+
const column = columnOf(entry, field);
|
|
372
|
+
if (STRING_ONLY.has(rule.operator) && field.kind !== "string" && field.kind !== "enum") {
|
|
373
|
+
throw new InvalidQueryError(`Operator "${rule.operator}" requires a string field, but "${model.name}.${field.name}" is of kind "${field.kind}".`);
|
|
374
|
+
}
|
|
375
|
+
if (COMPARISON.has(rule.operator) && field.kind === "boolean") {
|
|
376
|
+
throw new InvalidQueryError(`Operator "${rule.operator}" cannot be applied to boolean field "${model.name}.${field.name}".`);
|
|
377
|
+
}
|
|
378
|
+
const value = coerce(field, rule.value, model.name);
|
|
379
|
+
switch (rule.operator) {
|
|
380
|
+
case "in": {
|
|
381
|
+
if (!Array.isArray(rule.value)) {
|
|
382
|
+
throw new InvalidQueryError(`Operator "in" requires an array value for "${model.name}.${field.name}".`);
|
|
383
|
+
}
|
|
384
|
+
return (0, import_drizzle_orm3.inArray)(column, rule.value.map((entryValue) => coerce(field, entryValue, model.name)));
|
|
385
|
+
}
|
|
386
|
+
case "eq":
|
|
387
|
+
return (0, import_drizzle_orm3.eq)(column, value);
|
|
388
|
+
case "ne":
|
|
389
|
+
return (0, import_drizzle_orm3.ne)(column, value);
|
|
390
|
+
case "gt":
|
|
391
|
+
return (0, import_drizzle_orm3.gt)(column, value);
|
|
392
|
+
case "gte":
|
|
393
|
+
return (0, import_drizzle_orm3.gte)(column, value);
|
|
394
|
+
case "lt":
|
|
395
|
+
return (0, import_drizzle_orm3.lt)(column, value);
|
|
396
|
+
case "lte":
|
|
397
|
+
return (0, import_drizzle_orm3.lte)(column, value);
|
|
398
|
+
case "contains":
|
|
399
|
+
return insensitiveLike(column, `%${escapeLike(String(rule.value))}%`);
|
|
400
|
+
case "startsWith":
|
|
401
|
+
return insensitiveLike(column, `${escapeLike(String(rule.value))}%`);
|
|
402
|
+
case "endsWith":
|
|
403
|
+
return insensitiveLike(column, `%${escapeLike(String(rule.value))}`);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
__name(condition, "condition");
|
|
407
|
+
function coerce(field, value, model) {
|
|
408
|
+
if (value === null || value === void 0) return value;
|
|
409
|
+
if (field.kind === "datetime" && !(value instanceof Date)) {
|
|
410
|
+
const parsed = new Date(String(value));
|
|
411
|
+
if (Number.isNaN(parsed.getTime())) {
|
|
412
|
+
throw new InvalidQueryError(`"${value}" is not a date, for "${model}.${field.name}".`);
|
|
413
|
+
}
|
|
414
|
+
return parsed;
|
|
415
|
+
}
|
|
416
|
+
return value;
|
|
417
|
+
}
|
|
418
|
+
__name(coerce, "coerce");
|
|
419
|
+
function searchCondition(model, entry, term) {
|
|
420
|
+
const foreignKeys = new Set(model.fields.map((field) => field.relation?.from).filter((name) => name !== void 0));
|
|
421
|
+
const searchable = model.fields.filter((field) => (field.kind === "string" || field.kind === "enum") && !field.isList && !field.isGenerated && !foreignKeys.has(field.name) && entry.columns.has(field.name));
|
|
422
|
+
if (searchable.length === 0) return void 0;
|
|
423
|
+
const pattern = `%${escapeLike(term)}%`;
|
|
424
|
+
return (0, import_drizzle_orm3.or)(...searchable.map((field) => insensitiveLike(columnOf(entry, field), pattern)));
|
|
425
|
+
}
|
|
426
|
+
__name(searchCondition, "searchCondition");
|
|
427
|
+
function buildWhere(model, entry, query) {
|
|
428
|
+
const conditions = [];
|
|
429
|
+
for (const rule of query.filters ?? []) {
|
|
430
|
+
conditions.push(condition(model, entry, rule));
|
|
431
|
+
}
|
|
432
|
+
const term = query.search?.trim();
|
|
433
|
+
if (term) {
|
|
434
|
+
const search = searchCondition(model, entry, term);
|
|
435
|
+
if (search) conditions.push(search);
|
|
436
|
+
}
|
|
437
|
+
if (conditions.length === 0) return void 0;
|
|
438
|
+
return conditions.length === 1 ? conditions[0] : (0, import_drizzle_orm3.and)(...conditions);
|
|
439
|
+
}
|
|
440
|
+
__name(buildWhere, "buildWhere");
|
|
441
|
+
function buildOrderBy(model, entry, rules) {
|
|
442
|
+
return (rules ?? []).map((rule) => {
|
|
443
|
+
const field = queryable(model, rule.field, "sort");
|
|
444
|
+
const column = columnOf(entry, field);
|
|
445
|
+
return rule.direction === "desc" ? (0, import_drizzle_orm3.desc)(column) : (0, import_drizzle_orm3.asc)(column);
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
__name(buildOrderBy, "buildOrderBy");
|
|
449
|
+
function resolvePagination(query) {
|
|
450
|
+
const rawPage = query.page ?? 1;
|
|
451
|
+
const rawPerPage = query.perPage ?? DEFAULT_PER_PAGE;
|
|
452
|
+
const page = Number.isFinite(rawPage) && rawPage >= 1 ? Math.floor(rawPage) : 1;
|
|
453
|
+
const perPage = Number.isFinite(rawPerPage) && rawPerPage >= 1 ? Math.min(Math.floor(rawPerPage), MAX_PER_PAGE) : DEFAULT_PER_PAGE;
|
|
454
|
+
return {
|
|
455
|
+
page,
|
|
456
|
+
perPage,
|
|
457
|
+
offset: (page - 1) * perPage,
|
|
458
|
+
limit: perPage
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
__name(resolvePagination, "resolvePagination");
|
|
462
|
+
function dialectOf(tables) {
|
|
463
|
+
for (const entry of tables) {
|
|
464
|
+
for (const column of entry.columns.values()) {
|
|
465
|
+
if (column.columnType.startsWith("SQLite")) return "sqlite";
|
|
466
|
+
if (column.columnType.startsWith("Pg")) return "pg";
|
|
467
|
+
if (column.columnType.startsWith("MySql")) return "mysql";
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
throw new AdapterError("Could not tell which SQL dialect this Drizzle schema uses. Pass a schema containing at least one table with at least one column.");
|
|
471
|
+
}
|
|
472
|
+
__name(dialectOf, "dialectOf");
|
|
473
|
+
var CORES = {
|
|
474
|
+
sqlite: "drizzle-orm/sqlite-core",
|
|
475
|
+
pg: "drizzle-orm/pg-core",
|
|
476
|
+
mysql: "drizzle-orm/mysql-core"
|
|
477
|
+
};
|
|
478
|
+
async function configReader(dialect) {
|
|
479
|
+
const core = await import(CORES[dialect]);
|
|
480
|
+
return core.getTableConfig;
|
|
481
|
+
}
|
|
482
|
+
__name(configReader, "configReader");
|
|
483
|
+
function keyOf(entry, column) {
|
|
484
|
+
for (const [key, candidate] of entry.columns) {
|
|
485
|
+
if (candidate.name === column.name) return key;
|
|
486
|
+
}
|
|
487
|
+
return void 0;
|
|
488
|
+
}
|
|
489
|
+
__name(keyOf, "keyOf");
|
|
490
|
+
function declaredRelations(schema, tables, nameOfFk) {
|
|
491
|
+
const byTable = new Map(tables.map((entry) => [
|
|
492
|
+
entry.table,
|
|
493
|
+
entry
|
|
494
|
+
]));
|
|
495
|
+
const found = [];
|
|
496
|
+
for (const value of Object.values(schema)) {
|
|
497
|
+
if (!(0, import_drizzle_orm4.is)(value, import_drizzle_orm4.Relations)) continue;
|
|
498
|
+
const owner = byTable.get(value.table);
|
|
499
|
+
if (owner === void 0) continue;
|
|
500
|
+
const built = value.config((0, import_drizzle_orm4.createTableRelationsHelpers)(value.table));
|
|
501
|
+
for (const [field, relation] of Object.entries(built)) {
|
|
502
|
+
const one = (0, import_drizzle_orm4.is)(relation, import_drizzle_orm4.One);
|
|
503
|
+
if (!one && !(0, import_drizzle_orm4.is)(relation, import_drizzle_orm4.Many)) continue;
|
|
504
|
+
const target = byTable.get(relation.referencedTable);
|
|
505
|
+
if (target === void 0) continue;
|
|
506
|
+
if (!one) {
|
|
507
|
+
found.push({
|
|
508
|
+
model: owner.model,
|
|
509
|
+
field,
|
|
510
|
+
targetModel: target.model,
|
|
511
|
+
cardinality: "many",
|
|
512
|
+
name: ""
|
|
513
|
+
});
|
|
514
|
+
continue;
|
|
515
|
+
}
|
|
516
|
+
const config = relation.config;
|
|
517
|
+
const fk = config?.fields?.[0];
|
|
518
|
+
const reference = relation.config?.references?.[0];
|
|
519
|
+
const fkKey = fk ? keyOf(owner, fk) : void 0;
|
|
520
|
+
const refKey = reference ? keyOf(target, reference) : void 0;
|
|
521
|
+
found.push({
|
|
522
|
+
model: owner.model,
|
|
523
|
+
field,
|
|
524
|
+
targetModel: target.model,
|
|
525
|
+
cardinality: "one",
|
|
526
|
+
name: fkKey ? nameOfFk(owner.model, fkKey) : "",
|
|
527
|
+
...fkKey !== void 0 ? {
|
|
528
|
+
from: fkKey
|
|
529
|
+
} : {},
|
|
530
|
+
...refKey !== void 0 ? {
|
|
531
|
+
to: refKey
|
|
532
|
+
} : {}
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
return found;
|
|
537
|
+
}
|
|
538
|
+
__name(declaredRelations, "declaredRelations");
|
|
539
|
+
async function readSchema(schema) {
|
|
540
|
+
const tables = [];
|
|
541
|
+
for (const [model, value] of Object.entries(schema)) {
|
|
542
|
+
if (!(0, import_drizzle_orm4.is)(value, import_drizzle_orm4.Table)) continue;
|
|
543
|
+
const columns = new Map(Object.entries((0, import_drizzle_orm4.getTableColumns)(value)));
|
|
544
|
+
tables.push({
|
|
545
|
+
model,
|
|
546
|
+
sqlName: (0, import_drizzle_orm4.getTableName)(value),
|
|
547
|
+
table: value,
|
|
548
|
+
columns
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
if (tables.length === 0) {
|
|
552
|
+
throw new AdapterError("This Drizzle schema exports no tables. Pass the schema module itself, for example `new DrizzleAdapter({ db, schema })` after `import * as schema from './schema.js'`.");
|
|
553
|
+
}
|
|
554
|
+
const dialect = dialectOf(tables);
|
|
555
|
+
const getTableConfig = await configReader(dialect);
|
|
556
|
+
const byTable = new Map(tables.map((entry) => [
|
|
557
|
+
entry.table,
|
|
558
|
+
entry
|
|
559
|
+
]));
|
|
560
|
+
const nameOfFk = /* @__PURE__ */ __name((child, fk) => `${child}.${fk}`, "nameOfFk");
|
|
561
|
+
const declared = declaredRelations(schema, tables, nameOfFk);
|
|
562
|
+
const declaredOn = new Set(declared.map((relation) => `${relation.model}.${relation.field}`));
|
|
563
|
+
const relations = [];
|
|
564
|
+
for (const child of tables) {
|
|
565
|
+
for (const foreign of getTableConfig(child.table).foreignKeys) {
|
|
566
|
+
const reference = foreign.reference();
|
|
567
|
+
const parent = byTable.get(reference.foreignTable);
|
|
568
|
+
const column = reference.columns[0];
|
|
569
|
+
const target = reference.foreignColumns[0];
|
|
570
|
+
if (parent === void 0 || column === void 0 || target === void 0) continue;
|
|
571
|
+
const fkKey = keyOf(child, column);
|
|
572
|
+
const refKey = keyOf(parent, target);
|
|
573
|
+
if (fkKey === void 0 || refKey === void 0) continue;
|
|
574
|
+
const name = nameOfFk(child.model, fkKey);
|
|
575
|
+
const declaredOne = declared.find((relation) => relation.cardinality === "one" && relation.name === name);
|
|
576
|
+
if (declaredOne === void 0) {
|
|
577
|
+
relations.push({
|
|
578
|
+
model: child.model,
|
|
579
|
+
// `authorId` describes a column; `author` describes the thing on the
|
|
580
|
+
// other end, which is what a person reading a record wants named.
|
|
581
|
+
field: relationFieldName(fkKey, child.columns),
|
|
582
|
+
targetModel: parent.model,
|
|
583
|
+
cardinality: "one",
|
|
584
|
+
name,
|
|
585
|
+
from: fkKey,
|
|
586
|
+
to: refKey
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
const declaredMany = declared.find((relation) => relation.cardinality === "many" && relation.model === parent.model && relation.targetModel === child.model && relation.name === "");
|
|
590
|
+
if (declaredMany === void 0) {
|
|
591
|
+
relations.push({
|
|
592
|
+
model: parent.model,
|
|
593
|
+
field: manyFieldName(child.model, parent, declaredOn),
|
|
594
|
+
targetModel: child.model,
|
|
595
|
+
cardinality: "many",
|
|
596
|
+
name
|
|
597
|
+
});
|
|
598
|
+
} else {
|
|
599
|
+
relations.push({
|
|
600
|
+
...declaredMany,
|
|
601
|
+
name
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
for (const relation of declared) {
|
|
607
|
+
if (relation.cardinality === "one" && relation.name !== "") relations.push(relation);
|
|
608
|
+
}
|
|
609
|
+
return {
|
|
610
|
+
dialect,
|
|
611
|
+
tables,
|
|
612
|
+
relations
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
__name(readSchema, "readSchema");
|
|
616
|
+
function relationFieldName(fkKey, columns) {
|
|
617
|
+
const stripped = /^(.+?)(Id|_id|ID)$/.exec(fkKey)?.[1];
|
|
618
|
+
if (stripped === void 0 || stripped === "") return `${fkKey}Ref`;
|
|
619
|
+
return columns.has(stripped) ? `${fkKey}Ref` : stripped;
|
|
620
|
+
}
|
|
621
|
+
__name(relationFieldName, "relationFieldName");
|
|
622
|
+
function manyFieldName(childModel, parent, declaredOn) {
|
|
623
|
+
const base = `${childModel.charAt(0).toLowerCase()}${childModel.slice(1)}`;
|
|
624
|
+
const plural = base.endsWith("s") ? base : `${base}s`;
|
|
625
|
+
const taken = parent.columns.has(plural) || declaredOn.has(`${parent.model}.${plural}`);
|
|
626
|
+
return taken ? `${plural}Related` : plural;
|
|
627
|
+
}
|
|
628
|
+
__name(manyFieldName, "manyFieldName");
|
|
629
|
+
var DrizzleAdapter = class {
|
|
630
|
+
static {
|
|
631
|
+
__name(this, "DrizzleAdapter");
|
|
632
|
+
}
|
|
633
|
+
name = "drizzle";
|
|
634
|
+
#db;
|
|
635
|
+
#schemaModule;
|
|
636
|
+
#schema;
|
|
637
|
+
#models;
|
|
638
|
+
constructor(options) {
|
|
639
|
+
if (options.db === null || options.db === void 0) {
|
|
640
|
+
throw new AdapterError("DrizzleAdapter requires a constructed Drizzle database. Pass one via `new DrizzleAdapter({ db, schema })`.");
|
|
641
|
+
}
|
|
642
|
+
if (options.schema === null || options.schema === void 0) {
|
|
643
|
+
throw new AdapterError("DrizzleAdapter requires the schema module. Import it with `import * as schema from './schema.js'` and pass it as `schema`.");
|
|
644
|
+
}
|
|
645
|
+
this.#db = options.db;
|
|
646
|
+
this.#schemaModule = options.schema;
|
|
647
|
+
}
|
|
648
|
+
async getModels() {
|
|
649
|
+
if (this.#models) return this.#models;
|
|
650
|
+
const schema = await readSchema(this.#schemaModule);
|
|
651
|
+
if (schema.dialect === "mysql") {
|
|
652
|
+
throw new AdapterError("The Drizzle adapter does not support MySQL yet, because MySQL has no RETURNING clause and writes could not report the stored row. SQLite and PostgreSQL are supported.");
|
|
653
|
+
}
|
|
654
|
+
this.#schema = schema;
|
|
655
|
+
this.#models = toModelMetadata({
|
|
656
|
+
schema,
|
|
657
|
+
compositeKeys: await this.#compositeKeys(schema)
|
|
658
|
+
});
|
|
659
|
+
return this.#models;
|
|
660
|
+
}
|
|
661
|
+
async list(model, query) {
|
|
662
|
+
const { metadata, entry } = await this.#require(model);
|
|
663
|
+
const where = buildWhere(metadata, entry, query);
|
|
664
|
+
const orderBy = buildOrderBy(metadata, entry, query.sort);
|
|
665
|
+
const { page, perPage, offset, limit } = resolvePagination(query);
|
|
666
|
+
return this.#run(model, async () => {
|
|
667
|
+
let rows = this.#db.select().from(entry.table).where(where);
|
|
668
|
+
if (orderBy.length > 0) rows = rows.orderBy(...orderBy);
|
|
669
|
+
const [data, totals] = await Promise.all([
|
|
670
|
+
rows.limit(limit).offset(offset),
|
|
671
|
+
this.#db.select({
|
|
672
|
+
value: (0, import_drizzle_orm.count)()
|
|
673
|
+
}).from(entry.table).where(where)
|
|
674
|
+
]);
|
|
675
|
+
const total = Number(totals[0]?.["value"] ?? 0);
|
|
676
|
+
return {
|
|
677
|
+
data,
|
|
678
|
+
total,
|
|
679
|
+
page,
|
|
680
|
+
perPage
|
|
681
|
+
};
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
async findOne(model, id) {
|
|
685
|
+
const { metadata, entry } = await this.#require(model);
|
|
686
|
+
const rows = await this.#run(model, () => this.#db.select().from(entry.table).where(this.#byId(metadata, entry, id)).limit(1));
|
|
687
|
+
return rows[0] ?? null;
|
|
688
|
+
}
|
|
689
|
+
async create(model, data) {
|
|
690
|
+
const { metadata, entry } = await this.#require(model);
|
|
691
|
+
const writable = this.#writable(metadata, entry, data);
|
|
692
|
+
const rows = await this.#run(model, () => this.#db.insert(entry.table).values(writable).returning());
|
|
693
|
+
const created = rows[0];
|
|
694
|
+
if (created === void 0) {
|
|
695
|
+
throw new AdapterError(`Creating a ${model} returned no row.`);
|
|
696
|
+
}
|
|
697
|
+
return created;
|
|
698
|
+
}
|
|
699
|
+
async update(model, id, data) {
|
|
700
|
+
const { metadata, entry } = await this.#require(model);
|
|
701
|
+
const writable = this.#writable(metadata, entry, data);
|
|
702
|
+
if (Object.keys(writable).length === 0) {
|
|
703
|
+
const existing = await this.findOne(model, id);
|
|
704
|
+
if (existing === null) throw new RecordNotFoundError(model, id);
|
|
705
|
+
return existing;
|
|
706
|
+
}
|
|
707
|
+
const rows = await this.#run(model, () => this.#db.update(entry.table).set(writable).where(this.#byId(metadata, entry, id)).returning());
|
|
708
|
+
const updated = rows[0];
|
|
709
|
+
if (updated === void 0) throw new RecordNotFoundError(model, id);
|
|
710
|
+
return updated;
|
|
711
|
+
}
|
|
712
|
+
async delete(model, id) {
|
|
713
|
+
const { metadata, entry } = await this.#require(model);
|
|
714
|
+
const rows = await this.#run(model, () => this.#db.delete(entry.table).where(this.#byId(metadata, entry, id)).returning());
|
|
715
|
+
if (rows.length === 0) throw new RecordNotFoundError(model, id);
|
|
716
|
+
}
|
|
717
|
+
async listRelated(model, id, relationField, query) {
|
|
718
|
+
const link = await this.#link(model, relationField);
|
|
719
|
+
const { metadata: targetMetadata, entry: target } = await this.#require(link.targetModel);
|
|
720
|
+
const parentValue = await this.#referencedValue(model, id, link.to);
|
|
721
|
+
const foreignKey = target.columns.get(link.from);
|
|
722
|
+
if (foreignKey === void 0) {
|
|
723
|
+
throw new FieldNotFoundError(link.targetModel, link.from);
|
|
724
|
+
}
|
|
725
|
+
const declared = buildWhere(targetMetadata, target, query);
|
|
726
|
+
const belongs = (0, import_drizzle_orm.eq)(foreignKey, parentValue);
|
|
727
|
+
const where = declared ? (0, import_drizzle_orm.and)(belongs, declared) : belongs;
|
|
728
|
+
const orderBy = buildOrderBy(targetMetadata, target, query.sort);
|
|
729
|
+
const { page, perPage, offset, limit } = resolvePagination(query);
|
|
730
|
+
return this.#run(link.targetModel, async () => {
|
|
731
|
+
let rows = this.#db.select().from(target.table).where(where);
|
|
732
|
+
if (orderBy.length > 0) rows = rows.orderBy(...orderBy);
|
|
733
|
+
const [data, totals] = await Promise.all([
|
|
734
|
+
rows.limit(limit).offset(offset),
|
|
735
|
+
this.#db.select({
|
|
736
|
+
value: (0, import_drizzle_orm.count)()
|
|
737
|
+
}).from(target.table).where(where)
|
|
738
|
+
]);
|
|
739
|
+
return {
|
|
740
|
+
data,
|
|
741
|
+
total: Number(totals[0]?.["value"] ?? 0),
|
|
742
|
+
page,
|
|
743
|
+
perPage
|
|
744
|
+
};
|
|
745
|
+
});
|
|
746
|
+
}
|
|
747
|
+
async attachRelated(model, id, relationField, targetId) {
|
|
748
|
+
const link = await this.#link(model, relationField);
|
|
749
|
+
const parentValue = await this.#referencedValue(model, id, link.to);
|
|
750
|
+
await this.#setForeignKey(link, targetId, parentValue);
|
|
751
|
+
}
|
|
752
|
+
async detachRelated(model, id, relationField, targetId) {
|
|
753
|
+
const link = await this.#link(model, relationField);
|
|
754
|
+
await this.#setForeignKey(link, targetId, null);
|
|
755
|
+
}
|
|
756
|
+
/* ---------------------------------------------------------------------- */
|
|
757
|
+
async #require(model) {
|
|
758
|
+
const models = await this.getModels();
|
|
759
|
+
const metadata = models.find((candidate) => candidate.name === model);
|
|
760
|
+
if (!metadata) throw new ModelNotFoundError(model);
|
|
761
|
+
const entry = this.#schema?.tables.find((candidate) => candidate.model === model);
|
|
762
|
+
if (!entry) throw new ModelNotFoundError(model);
|
|
763
|
+
return {
|
|
764
|
+
metadata,
|
|
765
|
+
entry
|
|
766
|
+
};
|
|
767
|
+
}
|
|
768
|
+
/**
|
|
769
|
+
* The two ends of a to-many, resolved to property names.
|
|
770
|
+
*
|
|
771
|
+
* `from` is the foreign key on the child, `to` the column on this model it
|
|
772
|
+
* points at. Only the `one` side carries them, so a `many` is resolved by
|
|
773
|
+
* finding its partner - which is why both sides are given the same relation
|
|
774
|
+
* name when the schema is read.
|
|
775
|
+
*/
|
|
776
|
+
async #link(model, relationField) {
|
|
777
|
+
const { metadata } = await this.#require(model);
|
|
778
|
+
const field = metadata.fields.find((candidate) => candidate.name === relationField);
|
|
779
|
+
if (!field?.relation) throw new FieldNotFoundError(model, relationField);
|
|
780
|
+
if (field.relation.cardinality !== "many") {
|
|
781
|
+
throw new FieldNotFoundError(model, relationField, "Only to-many relations can be listed or modified through this route.");
|
|
782
|
+
}
|
|
783
|
+
const models = await this.getModels();
|
|
784
|
+
const target = models.find((candidate) => candidate.name === field.relation?.targetModel);
|
|
785
|
+
const inverse = target?.fields.find((candidate) => candidate.relation?.cardinality === "one" && candidate.relation.name === field.relation?.name);
|
|
786
|
+
const from = inverse?.relation?.from;
|
|
787
|
+
const to = inverse?.relation?.to;
|
|
788
|
+
if (from === void 0 || to === void 0) {
|
|
789
|
+
throw new FieldNotFoundError(model, relationField, "This relation has no foreign key on the far side. A many-to-many in Drizzle is a join table, and is administered as its own resource.");
|
|
790
|
+
}
|
|
791
|
+
return {
|
|
792
|
+
targetModel: field.relation.targetModel,
|
|
793
|
+
from,
|
|
794
|
+
to
|
|
795
|
+
};
|
|
796
|
+
}
|
|
797
|
+
async #referencedValue(model, id, column) {
|
|
798
|
+
const record = await this.findOne(model, id);
|
|
799
|
+
if (record === null) throw new RecordNotFoundError(model, id);
|
|
800
|
+
return record[column];
|
|
801
|
+
}
|
|
802
|
+
async #setForeignKey(link, targetId, value) {
|
|
803
|
+
const { metadata, entry } = await this.#require(link.targetModel);
|
|
804
|
+
await this.#run(link.targetModel, () => this.#db.update(entry.table).set({
|
|
805
|
+
[link.from]: value
|
|
806
|
+
}).where(this.#byId(metadata, entry, targetId)).returning());
|
|
807
|
+
}
|
|
808
|
+
#byId(metadata, entry, id) {
|
|
809
|
+
const key = metadata.primaryKey[0];
|
|
810
|
+
if (key === void 0 || metadata.primaryKey.length > 1) {
|
|
811
|
+
throw new AdapterError(`${metadata.name} has ${metadata.primaryKey.length === 0 ? "no" : "a composite"} primary key. Records are addressed by a single key in this version.`);
|
|
812
|
+
}
|
|
813
|
+
const column = entry.columns.get(key);
|
|
814
|
+
if (column === void 0) throw new FieldNotFoundError(metadata.name, key);
|
|
815
|
+
const field = metadata.fields.find((candidate) => candidate.name === key);
|
|
816
|
+
const value = field?.kind === "number" ? Number(id) : id;
|
|
817
|
+
return (0, import_drizzle_orm.eq)(column, value);
|
|
818
|
+
}
|
|
819
|
+
/**
|
|
820
|
+
* The submitted data, restricted to columns that exist and may be written.
|
|
821
|
+
*
|
|
822
|
+
* Generated columns are dropped rather than refused: a form that round-trips
|
|
823
|
+
* a record would otherwise fail on the id it was shown. Unknown keys *are*
|
|
824
|
+
* refused, because silently ignoring a field is how a value appears to save
|
|
825
|
+
* and does not.
|
|
826
|
+
*/
|
|
827
|
+
#writable(metadata, entry, data) {
|
|
828
|
+
const writable = {};
|
|
829
|
+
for (const [key, value] of Object.entries(data)) {
|
|
830
|
+
const field = metadata.fields.find((candidate) => candidate.name === key);
|
|
831
|
+
if (!field || !entry.columns.has(key)) {
|
|
832
|
+
if (field?.kind === "relation") continue;
|
|
833
|
+
throw new FieldNotFoundError(metadata.name, key);
|
|
834
|
+
}
|
|
835
|
+
if (field.isGenerated && field.isId) continue;
|
|
836
|
+
writable[key] = field.kind === "datetime" && typeof value === "string" ? new Date(value) : value;
|
|
837
|
+
}
|
|
838
|
+
return writable;
|
|
839
|
+
}
|
|
840
|
+
/** Composite primary keys, which are only reachable through the dialect's config. */
|
|
841
|
+
async #compositeKeys(schema) {
|
|
842
|
+
const core = await (schema.dialect === "pg" ? import("drizzle-orm/pg-core") : import("drizzle-orm/sqlite-core"));
|
|
843
|
+
const keys = /* @__PURE__ */ new Map();
|
|
844
|
+
for (const entry of schema.tables) {
|
|
845
|
+
const declared = core.getTableConfig(entry.table).primaryKeys[0];
|
|
846
|
+
if (declared === void 0) continue;
|
|
847
|
+
const names = [];
|
|
848
|
+
for (const column of declared.columns) {
|
|
849
|
+
for (const [key, candidate] of entry.columns) {
|
|
850
|
+
if (candidate.name === column.name) names.push(key);
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
if (names.length > 0) keys.set(entry.model, names);
|
|
854
|
+
}
|
|
855
|
+
return keys;
|
|
856
|
+
}
|
|
857
|
+
/**
|
|
858
|
+
* Run a query, and translate whatever it throws.
|
|
859
|
+
*
|
|
860
|
+
* Core's own errors pass through: they were raised by this adapter and
|
|
861
|
+
* already say what is wrong. Everything else is the driver's, and becomes
|
|
862
|
+
* either a constraint the interface can put beside a field or an
|
|
863
|
+
* `AdapterError`, which the HTTP layer reports without its message.
|
|
864
|
+
*/
|
|
865
|
+
async #run(model, operation) {
|
|
866
|
+
try {
|
|
867
|
+
return await operation();
|
|
868
|
+
} catch (cause) {
|
|
869
|
+
if (isNestAdminError(cause)) throw cause;
|
|
870
|
+
const entry = this.#schema?.tables.find((candidate) => candidate.model === model);
|
|
871
|
+
const toFieldNames = /* @__PURE__ */ __name((sqlNames) => {
|
|
872
|
+
if (entry === void 0) return sqlNames;
|
|
873
|
+
const named = [];
|
|
874
|
+
for (const sqlName of sqlNames) {
|
|
875
|
+
for (const [key, column] of entry.columns) {
|
|
876
|
+
if (column.name === sqlName) named.push(key);
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
return named;
|
|
880
|
+
}, "toFieldNames");
|
|
881
|
+
const constraint = toConstraintError(cause, model, toFieldNames);
|
|
882
|
+
if (constraint) throw constraint;
|
|
883
|
+
throw new AdapterError(`The database refused a ${model} operation: ${cause instanceof Error ? cause.message : String(cause)}`, {
|
|
884
|
+
cause
|
|
885
|
+
});
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
};
|
|
889
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
890
|
+
0 && (module.exports = {
|
|
891
|
+
DEFAULT_PER_PAGE,
|
|
892
|
+
DrizzleAdapter,
|
|
893
|
+
MAX_PER_PAGE
|
|
894
|
+
});
|
|
895
|
+
//# sourceMappingURL=drizzle.cjs.map
|