express-model-binding 1.0.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 +208 -0
- package/dist/BaseAdapter-BjvLQijd.d.mts +214 -0
- package/dist/BaseAdapter-BjvLQijd.d.ts +214 -0
- package/dist/adapters/KnexAdapter.d.mts +44 -0
- package/dist/adapters/KnexAdapter.d.ts +44 -0
- package/dist/adapters/KnexAdapter.js +257 -0
- package/dist/adapters/KnexAdapter.js.map +1 -0
- package/dist/adapters/KnexAdapter.mjs +229 -0
- package/dist/adapters/KnexAdapter.mjs.map +1 -0
- package/dist/adapters/MongooseAdapter.d.mts +30 -0
- package/dist/adapters/MongooseAdapter.d.ts +30 -0
- package/dist/adapters/MongooseAdapter.js +245 -0
- package/dist/adapters/MongooseAdapter.js.map +1 -0
- package/dist/adapters/MongooseAdapter.mjs +225 -0
- package/dist/adapters/MongooseAdapter.mjs.map +1 -0
- package/dist/adapters/PrismaAdapter.d.mts +42 -0
- package/dist/adapters/PrismaAdapter.d.ts +42 -0
- package/dist/adapters/PrismaAdapter.js +247 -0
- package/dist/adapters/PrismaAdapter.js.map +1 -0
- package/dist/adapters/PrismaAdapter.mjs +220 -0
- package/dist/adapters/PrismaAdapter.mjs.map +1 -0
- package/dist/adapters/SequelizeAdapter.d.mts +27 -0
- package/dist/adapters/SequelizeAdapter.d.ts +27 -0
- package/dist/adapters/SequelizeAdapter.js +280 -0
- package/dist/adapters/SequelizeAdapter.js.map +1 -0
- package/dist/adapters/SequelizeAdapter.mjs +260 -0
- package/dist/adapters/SequelizeAdapter.mjs.map +1 -0
- package/dist/adapters/TypeORMAdapter.d.mts +26 -0
- package/dist/adapters/TypeORMAdapter.d.ts +26 -0
- package/dist/adapters/TypeORMAdapter.js +294 -0
- package/dist/adapters/TypeORMAdapter.js.map +1 -0
- package/dist/adapters/TypeORMAdapter.mjs +267 -0
- package/dist/adapters/TypeORMAdapter.mjs.map +1 -0
- package/dist/index.d.mts +411 -0
- package/dist/index.d.ts +411 -0
- package/dist/index.js +1514 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1450 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +148 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/adapters/SequelizeAdapter.ts
|
|
21
|
+
var SequelizeAdapter_exports = {};
|
|
22
|
+
__export(SequelizeAdapter_exports, {
|
|
23
|
+
SequelizeAdapter: () => SequelizeAdapter
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(SequelizeAdapter_exports);
|
|
26
|
+
|
|
27
|
+
// src/errors/index.ts
|
|
28
|
+
var BindingError = class extends Error {
|
|
29
|
+
constructor(message, originalError) {
|
|
30
|
+
super(message);
|
|
31
|
+
this.name = "BindingError";
|
|
32
|
+
this.originalError = originalError;
|
|
33
|
+
Error.captureStackTrace(this, this.constructor);
|
|
34
|
+
}
|
|
35
|
+
toJSON() {
|
|
36
|
+
return {
|
|
37
|
+
name: this.name,
|
|
38
|
+
message: this.message,
|
|
39
|
+
originalError: this.originalError?.message
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
var InvalidModelError = class extends Error {
|
|
44
|
+
constructor(message, model) {
|
|
45
|
+
super(message);
|
|
46
|
+
this.name = "InvalidModelError";
|
|
47
|
+
this.model = model;
|
|
48
|
+
Error.captureStackTrace(this, this.constructor);
|
|
49
|
+
}
|
|
50
|
+
toJSON() {
|
|
51
|
+
return {
|
|
52
|
+
name: this.name,
|
|
53
|
+
message: this.message,
|
|
54
|
+
model: typeof this.model === "string" ? this.model : String(this.model)
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// src/core/BaseAdapter.ts
|
|
60
|
+
var BaseAdapter = class {
|
|
61
|
+
transformValue(_model, _key, value) {
|
|
62
|
+
if (/^\d+$/.test(value)) {
|
|
63
|
+
const num = parseInt(value, 10);
|
|
64
|
+
if (!isNaN(num) && Number.isSafeInteger(num)) {
|
|
65
|
+
return num;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
70
|
+
supportsSoftDeletes(_model) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
getModelMetadata(model) {
|
|
74
|
+
return {
|
|
75
|
+
name: this.getModelName(model),
|
|
76
|
+
primaryKey: this.getPrimaryKeyName(model),
|
|
77
|
+
softDeletes: this.supportsSoftDeletes(model),
|
|
78
|
+
adapter: this.name
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
validateModel(model) {
|
|
82
|
+
if (!this.isValidModel(model)) {
|
|
83
|
+
throw new InvalidModelError(`Invalid model for ${this.name} adapter`, model);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
getModelName(model) {
|
|
87
|
+
if (typeof model === "string") {
|
|
88
|
+
return model;
|
|
89
|
+
}
|
|
90
|
+
if (model && typeof model === "object") {
|
|
91
|
+
const obj = model;
|
|
92
|
+
if (typeof obj.name === "string") return obj.name;
|
|
93
|
+
if (typeof obj.modelName === "string") return obj.modelName;
|
|
94
|
+
if (typeof obj.tableName === "string") return obj.tableName;
|
|
95
|
+
}
|
|
96
|
+
if (model && typeof model === "function") {
|
|
97
|
+
return model.name || "Unknown";
|
|
98
|
+
}
|
|
99
|
+
return "Unknown";
|
|
100
|
+
}
|
|
101
|
+
applySoftDeleteFilter(queryBuilder, _options) {
|
|
102
|
+
return queryBuilder;
|
|
103
|
+
}
|
|
104
|
+
applyIncludes(queryBuilder, _includes) {
|
|
105
|
+
return queryBuilder;
|
|
106
|
+
}
|
|
107
|
+
applySelect(queryBuilder, _select) {
|
|
108
|
+
return queryBuilder;
|
|
109
|
+
}
|
|
110
|
+
applyWhereConditions(queryBuilder, _where) {
|
|
111
|
+
return queryBuilder;
|
|
112
|
+
}
|
|
113
|
+
applyCustomQuery(queryBuilder, queryFn) {
|
|
114
|
+
if (queryFn) {
|
|
115
|
+
return queryFn(queryBuilder);
|
|
116
|
+
}
|
|
117
|
+
return queryBuilder;
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
// src/utils/validators.ts
|
|
122
|
+
var UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
123
|
+
function isUUID(value) {
|
|
124
|
+
return UUID_REGEX.test(value);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// src/adapters/SequelizeAdapter.ts
|
|
128
|
+
function isSequelizeModel(model) {
|
|
129
|
+
if (!model || typeof model !== "function") {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
const m = model;
|
|
133
|
+
return typeof m.findOne === "function" && typeof m.findAll === "function" && typeof m.rawAttributes === "object";
|
|
134
|
+
}
|
|
135
|
+
var SequelizeAdapter = class extends BaseAdapter {
|
|
136
|
+
constructor(sequelize) {
|
|
137
|
+
super();
|
|
138
|
+
this.sequelize = sequelize;
|
|
139
|
+
this.name = "sequelize";
|
|
140
|
+
}
|
|
141
|
+
getSequelize() {
|
|
142
|
+
return this.sequelize;
|
|
143
|
+
}
|
|
144
|
+
async findByKey(model, key, value, options = {}) {
|
|
145
|
+
this.validateModel(model);
|
|
146
|
+
try {
|
|
147
|
+
const transformedValue = this.transformValue(model, key, value);
|
|
148
|
+
const findOptions = {
|
|
149
|
+
where: { [key]: transformedValue }
|
|
150
|
+
};
|
|
151
|
+
if (options.select && options.select.length > 0) {
|
|
152
|
+
findOptions.attributes = options.select;
|
|
153
|
+
}
|
|
154
|
+
if (options.include) {
|
|
155
|
+
findOptions.include = this.buildIncludes(options.include);
|
|
156
|
+
}
|
|
157
|
+
if (options.where) {
|
|
158
|
+
findOptions.where = {
|
|
159
|
+
...findOptions.where,
|
|
160
|
+
...options.where
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
const isParanoid = model.options?.paranoid;
|
|
164
|
+
if (isParanoid) {
|
|
165
|
+
if (options.withTrashed) {
|
|
166
|
+
findOptions.paranoid = false;
|
|
167
|
+
} else if (options.onlyTrashed) {
|
|
168
|
+
findOptions.paranoid = false;
|
|
169
|
+
const { Op: SeqOp } = require("sequelize");
|
|
170
|
+
const whereClause = findOptions.where;
|
|
171
|
+
whereClause.deletedAt = { [SeqOp.ne]: null };
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (options.lock === "forUpdate") {
|
|
175
|
+
findOptions.lock = true;
|
|
176
|
+
} else if (options.lock === "forShare") {
|
|
177
|
+
const { Transaction: SeqTransaction } = require("sequelize");
|
|
178
|
+
findOptions.lock = SeqTransaction.LOCK.SHARE;
|
|
179
|
+
}
|
|
180
|
+
let result = await model.findOne(findOptions);
|
|
181
|
+
if (options.query && !result) {
|
|
182
|
+
result = await this.findWithCustomQuery(model, key, transformedValue, options);
|
|
183
|
+
}
|
|
184
|
+
return result;
|
|
185
|
+
} catch (error) {
|
|
186
|
+
throw new BindingError(
|
|
187
|
+
`Failed to fetch ${model.name}: ${error.message}`,
|
|
188
|
+
error
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
getPrimaryKeyName(model) {
|
|
193
|
+
return model.primaryKeyAttribute || "id";
|
|
194
|
+
}
|
|
195
|
+
isValidModel(model) {
|
|
196
|
+
return isSequelizeModel(model);
|
|
197
|
+
}
|
|
198
|
+
transformValue(model, key, value) {
|
|
199
|
+
const attributes = model.rawAttributes;
|
|
200
|
+
const attribute = attributes?.[key];
|
|
201
|
+
if (!attribute) {
|
|
202
|
+
if (isUUID(value)) {
|
|
203
|
+
return value;
|
|
204
|
+
}
|
|
205
|
+
const num = parseInt(value, 10);
|
|
206
|
+
if (!isNaN(num) && num.toString() === value) {
|
|
207
|
+
return num;
|
|
208
|
+
}
|
|
209
|
+
return value;
|
|
210
|
+
}
|
|
211
|
+
const attrType = attribute.type;
|
|
212
|
+
const type = attrType?.constructor?.name || String(attrType);
|
|
213
|
+
switch (type) {
|
|
214
|
+
case "INTEGER":
|
|
215
|
+
case "BIGINT":
|
|
216
|
+
case "SMALLINT": {
|
|
217
|
+
const intNum = parseInt(value, 10);
|
|
218
|
+
return isNaN(intNum) ? value : intNum;
|
|
219
|
+
}
|
|
220
|
+
case "FLOAT":
|
|
221
|
+
case "DOUBLE":
|
|
222
|
+
case "DECIMAL": {
|
|
223
|
+
const floatNum = parseFloat(value);
|
|
224
|
+
return isNaN(floatNum) ? value : floatNum;
|
|
225
|
+
}
|
|
226
|
+
case "BOOLEAN":
|
|
227
|
+
return value === "true" || value === "1";
|
|
228
|
+
case "UUID":
|
|
229
|
+
return value;
|
|
230
|
+
default:
|
|
231
|
+
return value;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
supportsSoftDeletes(model) {
|
|
235
|
+
return !!model.options?.paranoid;
|
|
236
|
+
}
|
|
237
|
+
getModelMetadata(model) {
|
|
238
|
+
const tableName = model.tableName || model.name;
|
|
239
|
+
const associations = Object.keys(model.associations || {});
|
|
240
|
+
return {
|
|
241
|
+
name: model.name,
|
|
242
|
+
primaryKey: this.getPrimaryKeyName(model),
|
|
243
|
+
tableName,
|
|
244
|
+
softDeletes: this.supportsSoftDeletes(model),
|
|
245
|
+
relations: associations,
|
|
246
|
+
adapter: this.name
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
buildIncludes(includes) {
|
|
250
|
+
if (Array.isArray(includes)) {
|
|
251
|
+
return includes.map((relation) => ({ association: relation }));
|
|
252
|
+
}
|
|
253
|
+
return Object.entries(includes).map(([relation, opts]) => {
|
|
254
|
+
if (typeof opts === "boolean" && opts) {
|
|
255
|
+
return { association: relation };
|
|
256
|
+
}
|
|
257
|
+
if (typeof opts === "object" && opts !== null) {
|
|
258
|
+
return {
|
|
259
|
+
association: relation,
|
|
260
|
+
...opts
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
return { association: relation };
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
async findWithCustomQuery(model, key, value, options) {
|
|
267
|
+
const findOptions = {
|
|
268
|
+
where: { [key]: value }
|
|
269
|
+
};
|
|
270
|
+
if (options.query) {
|
|
271
|
+
options.query(findOptions);
|
|
272
|
+
}
|
|
273
|
+
return await model.findOne(findOptions);
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
277
|
+
0 && (module.exports = {
|
|
278
|
+
SequelizeAdapter
|
|
279
|
+
});
|
|
280
|
+
//# sourceMappingURL=SequelizeAdapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/adapters/SequelizeAdapter.ts","../../src/errors/index.ts","../../src/core/BaseAdapter.ts","../../src/utils/validators.ts"],"sourcesContent":["import type {\n Sequelize,\n Model,\n ModelStatic,\n FindOptions,\n Includeable,\n Transaction,\n} from 'sequelize';\nimport { BaseAdapter } from '../core/BaseAdapter';\nimport { QueryOptions, ModelMetadata, QueryModifier } from '../core/types';\nimport { BindingError } from '../errors';\nimport { isUUID } from '../utils/validators';\n\n/**\n * Sequelize model static type\n */\ntype SequelizeModelStatic = ModelStatic<Model>;\n\n/**\n * Type guard for Sequelize model\n */\nfunction isSequelizeModel(model: unknown): model is SequelizeModelStatic {\n if (!model || typeof model !== 'function') {\n return false;\n }\n const m = model as unknown as Record<string, unknown>;\n return (\n typeof m.findOne === 'function' &&\n typeof m.findAll === 'function' &&\n typeof m.rawAttributes === 'object'\n );\n}\n\n/**\n * Adapter for Sequelize ORM supporting PostgreSQL, MySQL, SQLite, MSSQL\n */\nexport class SequelizeAdapter extends BaseAdapter<SequelizeModelStatic, Model, FindOptions> {\n readonly name = 'sequelize';\n\n constructor(private sequelize: Sequelize) {\n super();\n }\n\n getSequelize(): Sequelize {\n return this.sequelize;\n }\n\n async findByKey(\n model: SequelizeModelStatic,\n key: string,\n value: unknown,\n options: QueryOptions = {}\n ): Promise<Model | null> {\n this.validateModel(model);\n\n try {\n const transformedValue = this.transformValue(model, key, value as string);\n\n const findOptions: FindOptions = {\n where: { [key]: transformedValue },\n };\n\n if (options.select && options.select.length > 0) {\n findOptions.attributes = options.select;\n }\n\n if (options.include) {\n findOptions.include = this.buildIncludes(options.include);\n }\n\n if (options.where) {\n findOptions.where = {\n ...findOptions.where,\n ...options.where,\n };\n }\n\n const isParanoid = model.options?.paranoid;\n if (isParanoid) {\n if (options.withTrashed) {\n findOptions.paranoid = false;\n } else if (options.onlyTrashed) {\n findOptions.paranoid = false;\n // Sequelize Op must be loaded synchronously for query construction\n // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires\n const { Op: SeqOp } = require('sequelize');\n const whereClause = findOptions.where as Record<string, unknown>;\n whereClause.deletedAt = { [SeqOp.ne]: null };\n }\n }\n\n if (options.lock === 'forUpdate') {\n findOptions.lock = true;\n } else if (options.lock === 'forShare') {\n // Sequelize Transaction must be loaded synchronously for lock types\n // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires\n const { Transaction: SeqTransaction } = require('sequelize') as {\n Transaction: typeof Transaction;\n };\n findOptions.lock = SeqTransaction.LOCK.SHARE;\n }\n\n let result = await model.findOne(findOptions);\n\n if (options.query && !result) {\n result = await this.findWithCustomQuery(model, key, transformedValue, options);\n }\n\n return result;\n } catch (error) {\n throw new BindingError(\n `Failed to fetch ${model.name}: ${(error as Error).message}`,\n error as Error\n );\n }\n }\n\n getPrimaryKeyName(model: SequelizeModelStatic): string {\n return model.primaryKeyAttribute || 'id';\n }\n\n isValidModel(model: unknown): model is SequelizeModelStatic {\n return isSequelizeModel(model);\n }\n\n transformValue(model: SequelizeModelStatic, key: string, value: string): unknown {\n const attributes = model.rawAttributes;\n const attribute = attributes?.[key];\n\n if (!attribute) {\n if (isUUID(value)) {\n return value;\n }\n const num = parseInt(value, 10);\n if (!isNaN(num) && num.toString() === value) {\n return num;\n }\n return value;\n }\n\n const attrType = attribute.type;\n const type = attrType?.constructor?.name || String(attrType);\n\n switch (type) {\n case 'INTEGER':\n case 'BIGINT':\n case 'SMALLINT': {\n const intNum = parseInt(value, 10);\n return isNaN(intNum) ? value : intNum;\n }\n\n case 'FLOAT':\n case 'DOUBLE':\n case 'DECIMAL': {\n const floatNum = parseFloat(value);\n return isNaN(floatNum) ? value : floatNum;\n }\n\n case 'BOOLEAN':\n return value === 'true' || value === '1';\n\n case 'UUID':\n return value;\n\n default:\n return value;\n }\n }\n\n supportsSoftDeletes(model: SequelizeModelStatic): boolean {\n return !!model.options?.paranoid;\n }\n\n getModelMetadata(model: SequelizeModelStatic): ModelMetadata {\n const tableName = model.tableName || model.name;\n const associations = Object.keys(model.associations || {});\n\n return {\n name: model.name,\n primaryKey: this.getPrimaryKeyName(model),\n tableName: tableName,\n softDeletes: this.supportsSoftDeletes(model),\n relations: associations,\n adapter: this.name,\n };\n }\n\n private buildIncludes(includes: string[] | Record<string, unknown>): Includeable[] {\n if (Array.isArray(includes)) {\n return includes.map(relation => ({ association: relation }));\n }\n\n return Object.entries(includes).map(([relation, opts]) => {\n if (typeof opts === 'boolean' && opts) {\n return { association: relation };\n }\n\n if (typeof opts === 'object' && opts !== null) {\n return {\n association: relation,\n ...opts,\n };\n }\n\n return { association: relation };\n });\n }\n\n private async findWithCustomQuery(\n model: SequelizeModelStatic,\n key: string,\n value: unknown,\n options: QueryOptions\n ): Promise<Model | null> {\n const findOptions: FindOptions = {\n where: { [key]: value },\n };\n\n if (options.query) {\n (options.query as QueryModifier<FindOptions>)(findOptions);\n }\n\n return await model.findOne(findOptions);\n }\n}\n","/**\n * Base error class for model binding errors\n */\nexport class BindingError extends Error {\n public readonly originalError?: Error;\n\n constructor(message: string, originalError?: Error) {\n super(message);\n this.name = 'BindingError';\n this.originalError = originalError;\n Error.captureStackTrace(this, this.constructor);\n }\n\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n message: this.message,\n originalError: this.originalError?.message,\n };\n }\n}\n\n/**\n * Error thrown when a model is not found (404)\n */\nexport class ModelNotFoundError extends Error {\n public readonly statusCode = 404;\n public readonly paramName: string;\n public readonly paramValue: string;\n public readonly modelName: string;\n\n constructor(paramName: string, paramValue: string, modelName: string, customMessage?: string) {\n super(customMessage || `${modelName} not found with ${paramName} = ${paramValue}`);\n this.name = 'ModelNotFoundError';\n this.paramName = paramName;\n this.paramValue = paramValue;\n this.modelName = modelName;\n Error.captureStackTrace(this, this.constructor);\n }\n\n toJSON(): Record<string, unknown> {\n return {\n error: 'Not Found',\n message: this.message,\n statusCode: this.statusCode,\n param: this.paramName,\n value: this.paramValue,\n model: this.modelName,\n };\n }\n}\n\n/**\n * Error thrown when no adapter is configured\n */\nexport class AdapterNotSetError extends Error {\n constructor(\n message: string = 'No adapter set. Call ModelBinder.setAdapter() before using model binding.'\n ) {\n super(message);\n this.name = 'AdapterNotSetError';\n Error.captureStackTrace(this, this.constructor);\n }\n\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n message: this.message,\n };\n }\n}\n\n/**\n * Error thrown when a model is invalid for an adapter\n */\nexport class InvalidModelError extends Error {\n public readonly model: unknown;\n\n constructor(message: string, model: unknown) {\n super(message);\n this.name = 'InvalidModelError';\n this.model = model;\n Error.captureStackTrace(this, this.constructor);\n }\n\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n message: this.message,\n model: typeof this.model === 'string' ? this.model : String(this.model),\n };\n }\n}\n\n/**\n * Error thrown when validation fails\n */\nexport class ValidationError extends Error {\n public readonly statusCode: number;\n public readonly details?: unknown;\n\n constructor(message: string, statusCode: number = 400, details?: unknown) {\n super(message);\n this.name = 'ValidationError';\n this.statusCode = statusCode;\n this.details = details;\n Error.captureStackTrace(this, this.constructor);\n }\n\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n message: this.message,\n statusCode: this.statusCode,\n details: this.details,\n };\n }\n}\n","import { IORMAdapter, QueryOptions, ModelMetadata, QueryModifier } from './types';\nimport { InvalidModelError } from '../errors';\n\n/**\n * Abstract base class providing common adapter functionality.\n * Extend this class to implement ORM-specific adapters.\n *\n * @typeParam TModel - Model type accepted by this adapter\n * @typeParam TResult - Result type returned by queries\n * @typeParam TQueryBuilder - ORM-specific query builder type\n */\nexport abstract class BaseAdapter<\n TModel = unknown,\n TResult = unknown,\n TQueryBuilder = unknown,\n> implements IORMAdapter<TModel, TResult> {\n abstract readonly name: string;\n\n abstract findByKey(\n model: TModel,\n key: string,\n value: unknown,\n options?: QueryOptions\n ): Promise<TResult | null>;\n\n abstract getPrimaryKeyName(model: TModel): string;\n\n abstract isValidModel(model: unknown): model is TModel;\n\n transformValue(_model: TModel, _key: string, value: string): unknown {\n if (/^\\d+$/.test(value)) {\n const num = parseInt(value, 10);\n if (!isNaN(num) && Number.isSafeInteger(num)) {\n return num;\n }\n }\n return value;\n }\n\n supportsSoftDeletes(_model: TModel): boolean {\n return false;\n }\n\n getModelMetadata(model: TModel): ModelMetadata {\n return {\n name: this.getModelName(model),\n primaryKey: this.getPrimaryKeyName(model),\n softDeletes: this.supportsSoftDeletes(model),\n adapter: this.name,\n };\n }\n\n protected validateModel(model: unknown): asserts model is TModel {\n if (!this.isValidModel(model)) {\n throw new InvalidModelError(`Invalid model for ${this.name} adapter`, model);\n }\n }\n\n protected getModelName(model: TModel): string {\n if (typeof model === 'string') {\n return model;\n }\n if (model && typeof model === 'object') {\n const obj = model as Record<string, unknown>;\n if (typeof obj.name === 'string') return obj.name;\n if (typeof obj.modelName === 'string') return obj.modelName;\n if (typeof obj.tableName === 'string') return obj.tableName;\n }\n if (model && typeof model === 'function') {\n return (model as { name: string }).name || 'Unknown';\n }\n return 'Unknown';\n }\n\n protected applySoftDeleteFilter(\n queryBuilder: TQueryBuilder,\n _options?: QueryOptions\n ): TQueryBuilder {\n return queryBuilder;\n }\n\n protected applyIncludes(\n queryBuilder: TQueryBuilder,\n _includes?: string[] | Record<string, unknown>\n ): TQueryBuilder {\n return queryBuilder;\n }\n\n protected applySelect(queryBuilder: TQueryBuilder, _select?: string[]): TQueryBuilder {\n return queryBuilder;\n }\n\n protected applyWhereConditions(\n queryBuilder: TQueryBuilder,\n _where?: Record<string, unknown>\n ): TQueryBuilder {\n return queryBuilder;\n }\n\n protected applyCustomQuery(\n queryBuilder: TQueryBuilder,\n queryFn?: QueryModifier<TQueryBuilder>\n ): TQueryBuilder {\n if (queryFn) {\n return queryFn(queryBuilder) as TQueryBuilder;\n }\n return queryBuilder;\n }\n}\n","/**\n * UUID regex pattern\n */\nconst UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/**\n * MongoDB ObjectId regex pattern (24 hex characters)\n */\nconst OBJECT_ID_REGEX = /^[0-9a-f]{24}$/i;\n\n/**\n * Check if a value is a valid UUID\n */\nexport function isUUID(value: string): boolean {\n return UUID_REGEX.test(value);\n}\n\n/**\n * Check if a value is a valid MongoDB ObjectId\n */\nexport function isObjectId(value: string): boolean {\n return OBJECT_ID_REGEX.test(value);\n}\n\n/**\n * Check if a value is a numeric string\n */\nexport function isNumeric(value: string): boolean {\n return /^-?\\d+$/.test(value);\n}\n\n/**\n * Check if a value is a valid positive integer\n */\nexport function isPositiveInteger(value: string): boolean {\n return /^\\d+$/.test(value) && parseInt(value, 10) > 0;\n}\n\n/**\n * Check if a value is a valid slug (lowercase alphanumeric with hyphens)\n */\nexport function isSlug(value: string): boolean {\n return /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(value);\n}\n\n/**\n * Check if a value is a valid email\n */\nexport function isEmail(value: string): boolean {\n return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value);\n}\n\n/**\n * Validate that a value is not empty\n */\nexport function isNotEmpty(value: unknown): boolean {\n if (value === null || value === undefined) {\n return false;\n }\n if (typeof value === 'string') {\n return value.trim().length > 0;\n }\n return true;\n}\n\n/**\n * Validate that a value is a non-empty string\n */\nexport function isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0;\n}\n\n/**\n * Validate that a value is a plain object\n */\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * Validate that a value is a function\n */\n// eslint-disable-next-line @typescript-eslint/ban-types\nexport function isFunction(value: unknown): value is Function {\n return typeof value === 'function';\n}\n\n/**\n * Validate route parameter name\n */\nexport function isValidParamName(value: string): boolean {\n return /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(value);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
// src/errors/index.ts
|
|
9
|
+
var BindingError = class extends Error {
|
|
10
|
+
constructor(message, originalError) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = "BindingError";
|
|
13
|
+
this.originalError = originalError;
|
|
14
|
+
Error.captureStackTrace(this, this.constructor);
|
|
15
|
+
}
|
|
16
|
+
toJSON() {
|
|
17
|
+
return {
|
|
18
|
+
name: this.name,
|
|
19
|
+
message: this.message,
|
|
20
|
+
originalError: this.originalError?.message
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
var InvalidModelError = class extends Error {
|
|
25
|
+
constructor(message, model) {
|
|
26
|
+
super(message);
|
|
27
|
+
this.name = "InvalidModelError";
|
|
28
|
+
this.model = model;
|
|
29
|
+
Error.captureStackTrace(this, this.constructor);
|
|
30
|
+
}
|
|
31
|
+
toJSON() {
|
|
32
|
+
return {
|
|
33
|
+
name: this.name,
|
|
34
|
+
message: this.message,
|
|
35
|
+
model: typeof this.model === "string" ? this.model : String(this.model)
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// src/core/BaseAdapter.ts
|
|
41
|
+
var BaseAdapter = class {
|
|
42
|
+
transformValue(_model, _key, value) {
|
|
43
|
+
if (/^\d+$/.test(value)) {
|
|
44
|
+
const num = parseInt(value, 10);
|
|
45
|
+
if (!isNaN(num) && Number.isSafeInteger(num)) {
|
|
46
|
+
return num;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
supportsSoftDeletes(_model) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
getModelMetadata(model) {
|
|
55
|
+
return {
|
|
56
|
+
name: this.getModelName(model),
|
|
57
|
+
primaryKey: this.getPrimaryKeyName(model),
|
|
58
|
+
softDeletes: this.supportsSoftDeletes(model),
|
|
59
|
+
adapter: this.name
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
validateModel(model) {
|
|
63
|
+
if (!this.isValidModel(model)) {
|
|
64
|
+
throw new InvalidModelError(`Invalid model for ${this.name} adapter`, model);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
getModelName(model) {
|
|
68
|
+
if (typeof model === "string") {
|
|
69
|
+
return model;
|
|
70
|
+
}
|
|
71
|
+
if (model && typeof model === "object") {
|
|
72
|
+
const obj = model;
|
|
73
|
+
if (typeof obj.name === "string") return obj.name;
|
|
74
|
+
if (typeof obj.modelName === "string") return obj.modelName;
|
|
75
|
+
if (typeof obj.tableName === "string") return obj.tableName;
|
|
76
|
+
}
|
|
77
|
+
if (model && typeof model === "function") {
|
|
78
|
+
return model.name || "Unknown";
|
|
79
|
+
}
|
|
80
|
+
return "Unknown";
|
|
81
|
+
}
|
|
82
|
+
applySoftDeleteFilter(queryBuilder, _options) {
|
|
83
|
+
return queryBuilder;
|
|
84
|
+
}
|
|
85
|
+
applyIncludes(queryBuilder, _includes) {
|
|
86
|
+
return queryBuilder;
|
|
87
|
+
}
|
|
88
|
+
applySelect(queryBuilder, _select) {
|
|
89
|
+
return queryBuilder;
|
|
90
|
+
}
|
|
91
|
+
applyWhereConditions(queryBuilder, _where) {
|
|
92
|
+
return queryBuilder;
|
|
93
|
+
}
|
|
94
|
+
applyCustomQuery(queryBuilder, queryFn) {
|
|
95
|
+
if (queryFn) {
|
|
96
|
+
return queryFn(queryBuilder);
|
|
97
|
+
}
|
|
98
|
+
return queryBuilder;
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// src/utils/validators.ts
|
|
103
|
+
var UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
104
|
+
function isUUID(value) {
|
|
105
|
+
return UUID_REGEX.test(value);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// src/adapters/SequelizeAdapter.ts
|
|
109
|
+
function isSequelizeModel(model) {
|
|
110
|
+
if (!model || typeof model !== "function") {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
const m = model;
|
|
114
|
+
return typeof m.findOne === "function" && typeof m.findAll === "function" && typeof m.rawAttributes === "object";
|
|
115
|
+
}
|
|
116
|
+
var SequelizeAdapter = class extends BaseAdapter {
|
|
117
|
+
constructor(sequelize) {
|
|
118
|
+
super();
|
|
119
|
+
this.sequelize = sequelize;
|
|
120
|
+
this.name = "sequelize";
|
|
121
|
+
}
|
|
122
|
+
getSequelize() {
|
|
123
|
+
return this.sequelize;
|
|
124
|
+
}
|
|
125
|
+
async findByKey(model, key, value, options = {}) {
|
|
126
|
+
this.validateModel(model);
|
|
127
|
+
try {
|
|
128
|
+
const transformedValue = this.transformValue(model, key, value);
|
|
129
|
+
const findOptions = {
|
|
130
|
+
where: { [key]: transformedValue }
|
|
131
|
+
};
|
|
132
|
+
if (options.select && options.select.length > 0) {
|
|
133
|
+
findOptions.attributes = options.select;
|
|
134
|
+
}
|
|
135
|
+
if (options.include) {
|
|
136
|
+
findOptions.include = this.buildIncludes(options.include);
|
|
137
|
+
}
|
|
138
|
+
if (options.where) {
|
|
139
|
+
findOptions.where = {
|
|
140
|
+
...findOptions.where,
|
|
141
|
+
...options.where
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
const isParanoid = model.options?.paranoid;
|
|
145
|
+
if (isParanoid) {
|
|
146
|
+
if (options.withTrashed) {
|
|
147
|
+
findOptions.paranoid = false;
|
|
148
|
+
} else if (options.onlyTrashed) {
|
|
149
|
+
findOptions.paranoid = false;
|
|
150
|
+
const { Op: SeqOp } = __require("sequelize");
|
|
151
|
+
const whereClause = findOptions.where;
|
|
152
|
+
whereClause.deletedAt = { [SeqOp.ne]: null };
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (options.lock === "forUpdate") {
|
|
156
|
+
findOptions.lock = true;
|
|
157
|
+
} else if (options.lock === "forShare") {
|
|
158
|
+
const { Transaction: SeqTransaction } = __require("sequelize");
|
|
159
|
+
findOptions.lock = SeqTransaction.LOCK.SHARE;
|
|
160
|
+
}
|
|
161
|
+
let result = await model.findOne(findOptions);
|
|
162
|
+
if (options.query && !result) {
|
|
163
|
+
result = await this.findWithCustomQuery(model, key, transformedValue, options);
|
|
164
|
+
}
|
|
165
|
+
return result;
|
|
166
|
+
} catch (error) {
|
|
167
|
+
throw new BindingError(
|
|
168
|
+
`Failed to fetch ${model.name}: ${error.message}`,
|
|
169
|
+
error
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
getPrimaryKeyName(model) {
|
|
174
|
+
return model.primaryKeyAttribute || "id";
|
|
175
|
+
}
|
|
176
|
+
isValidModel(model) {
|
|
177
|
+
return isSequelizeModel(model);
|
|
178
|
+
}
|
|
179
|
+
transformValue(model, key, value) {
|
|
180
|
+
const attributes = model.rawAttributes;
|
|
181
|
+
const attribute = attributes?.[key];
|
|
182
|
+
if (!attribute) {
|
|
183
|
+
if (isUUID(value)) {
|
|
184
|
+
return value;
|
|
185
|
+
}
|
|
186
|
+
const num = parseInt(value, 10);
|
|
187
|
+
if (!isNaN(num) && num.toString() === value) {
|
|
188
|
+
return num;
|
|
189
|
+
}
|
|
190
|
+
return value;
|
|
191
|
+
}
|
|
192
|
+
const attrType = attribute.type;
|
|
193
|
+
const type = attrType?.constructor?.name || String(attrType);
|
|
194
|
+
switch (type) {
|
|
195
|
+
case "INTEGER":
|
|
196
|
+
case "BIGINT":
|
|
197
|
+
case "SMALLINT": {
|
|
198
|
+
const intNum = parseInt(value, 10);
|
|
199
|
+
return isNaN(intNum) ? value : intNum;
|
|
200
|
+
}
|
|
201
|
+
case "FLOAT":
|
|
202
|
+
case "DOUBLE":
|
|
203
|
+
case "DECIMAL": {
|
|
204
|
+
const floatNum = parseFloat(value);
|
|
205
|
+
return isNaN(floatNum) ? value : floatNum;
|
|
206
|
+
}
|
|
207
|
+
case "BOOLEAN":
|
|
208
|
+
return value === "true" || value === "1";
|
|
209
|
+
case "UUID":
|
|
210
|
+
return value;
|
|
211
|
+
default:
|
|
212
|
+
return value;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
supportsSoftDeletes(model) {
|
|
216
|
+
return !!model.options?.paranoid;
|
|
217
|
+
}
|
|
218
|
+
getModelMetadata(model) {
|
|
219
|
+
const tableName = model.tableName || model.name;
|
|
220
|
+
const associations = Object.keys(model.associations || {});
|
|
221
|
+
return {
|
|
222
|
+
name: model.name,
|
|
223
|
+
primaryKey: this.getPrimaryKeyName(model),
|
|
224
|
+
tableName,
|
|
225
|
+
softDeletes: this.supportsSoftDeletes(model),
|
|
226
|
+
relations: associations,
|
|
227
|
+
adapter: this.name
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
buildIncludes(includes) {
|
|
231
|
+
if (Array.isArray(includes)) {
|
|
232
|
+
return includes.map((relation) => ({ association: relation }));
|
|
233
|
+
}
|
|
234
|
+
return Object.entries(includes).map(([relation, opts]) => {
|
|
235
|
+
if (typeof opts === "boolean" && opts) {
|
|
236
|
+
return { association: relation };
|
|
237
|
+
}
|
|
238
|
+
if (typeof opts === "object" && opts !== null) {
|
|
239
|
+
return {
|
|
240
|
+
association: relation,
|
|
241
|
+
...opts
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
return { association: relation };
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
async findWithCustomQuery(model, key, value, options) {
|
|
248
|
+
const findOptions = {
|
|
249
|
+
where: { [key]: value }
|
|
250
|
+
};
|
|
251
|
+
if (options.query) {
|
|
252
|
+
options.query(findOptions);
|
|
253
|
+
}
|
|
254
|
+
return await model.findOne(findOptions);
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
export {
|
|
258
|
+
SequelizeAdapter
|
|
259
|
+
};
|
|
260
|
+
//# sourceMappingURL=SequelizeAdapter.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/errors/index.ts","../../src/core/BaseAdapter.ts","../../src/utils/validators.ts","../../src/adapters/SequelizeAdapter.ts"],"sourcesContent":["/**\n * Base error class for model binding errors\n */\nexport class BindingError extends Error {\n public readonly originalError?: Error;\n\n constructor(message: string, originalError?: Error) {\n super(message);\n this.name = 'BindingError';\n this.originalError = originalError;\n Error.captureStackTrace(this, this.constructor);\n }\n\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n message: this.message,\n originalError: this.originalError?.message,\n };\n }\n}\n\n/**\n * Error thrown when a model is not found (404)\n */\nexport class ModelNotFoundError extends Error {\n public readonly statusCode = 404;\n public readonly paramName: string;\n public readonly paramValue: string;\n public readonly modelName: string;\n\n constructor(paramName: string, paramValue: string, modelName: string, customMessage?: string) {\n super(customMessage || `${modelName} not found with ${paramName} = ${paramValue}`);\n this.name = 'ModelNotFoundError';\n this.paramName = paramName;\n this.paramValue = paramValue;\n this.modelName = modelName;\n Error.captureStackTrace(this, this.constructor);\n }\n\n toJSON(): Record<string, unknown> {\n return {\n error: 'Not Found',\n message: this.message,\n statusCode: this.statusCode,\n param: this.paramName,\n value: this.paramValue,\n model: this.modelName,\n };\n }\n}\n\n/**\n * Error thrown when no adapter is configured\n */\nexport class AdapterNotSetError extends Error {\n constructor(\n message: string = 'No adapter set. Call ModelBinder.setAdapter() before using model binding.'\n ) {\n super(message);\n this.name = 'AdapterNotSetError';\n Error.captureStackTrace(this, this.constructor);\n }\n\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n message: this.message,\n };\n }\n}\n\n/**\n * Error thrown when a model is invalid for an adapter\n */\nexport class InvalidModelError extends Error {\n public readonly model: unknown;\n\n constructor(message: string, model: unknown) {\n super(message);\n this.name = 'InvalidModelError';\n this.model = model;\n Error.captureStackTrace(this, this.constructor);\n }\n\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n message: this.message,\n model: typeof this.model === 'string' ? this.model : String(this.model),\n };\n }\n}\n\n/**\n * Error thrown when validation fails\n */\nexport class ValidationError extends Error {\n public readonly statusCode: number;\n public readonly details?: unknown;\n\n constructor(message: string, statusCode: number = 400, details?: unknown) {\n super(message);\n this.name = 'ValidationError';\n this.statusCode = statusCode;\n this.details = details;\n Error.captureStackTrace(this, this.constructor);\n }\n\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n message: this.message,\n statusCode: this.statusCode,\n details: this.details,\n };\n }\n}\n","import { IORMAdapter, QueryOptions, ModelMetadata, QueryModifier } from './types';\nimport { InvalidModelError } from '../errors';\n\n/**\n * Abstract base class providing common adapter functionality.\n * Extend this class to implement ORM-specific adapters.\n *\n * @typeParam TModel - Model type accepted by this adapter\n * @typeParam TResult - Result type returned by queries\n * @typeParam TQueryBuilder - ORM-specific query builder type\n */\nexport abstract class BaseAdapter<\n TModel = unknown,\n TResult = unknown,\n TQueryBuilder = unknown,\n> implements IORMAdapter<TModel, TResult> {\n abstract readonly name: string;\n\n abstract findByKey(\n model: TModel,\n key: string,\n value: unknown,\n options?: QueryOptions\n ): Promise<TResult | null>;\n\n abstract getPrimaryKeyName(model: TModel): string;\n\n abstract isValidModel(model: unknown): model is TModel;\n\n transformValue(_model: TModel, _key: string, value: string): unknown {\n if (/^\\d+$/.test(value)) {\n const num = parseInt(value, 10);\n if (!isNaN(num) && Number.isSafeInteger(num)) {\n return num;\n }\n }\n return value;\n }\n\n supportsSoftDeletes(_model: TModel): boolean {\n return false;\n }\n\n getModelMetadata(model: TModel): ModelMetadata {\n return {\n name: this.getModelName(model),\n primaryKey: this.getPrimaryKeyName(model),\n softDeletes: this.supportsSoftDeletes(model),\n adapter: this.name,\n };\n }\n\n protected validateModel(model: unknown): asserts model is TModel {\n if (!this.isValidModel(model)) {\n throw new InvalidModelError(`Invalid model for ${this.name} adapter`, model);\n }\n }\n\n protected getModelName(model: TModel): string {\n if (typeof model === 'string') {\n return model;\n }\n if (model && typeof model === 'object') {\n const obj = model as Record<string, unknown>;\n if (typeof obj.name === 'string') return obj.name;\n if (typeof obj.modelName === 'string') return obj.modelName;\n if (typeof obj.tableName === 'string') return obj.tableName;\n }\n if (model && typeof model === 'function') {\n return (model as { name: string }).name || 'Unknown';\n }\n return 'Unknown';\n }\n\n protected applySoftDeleteFilter(\n queryBuilder: TQueryBuilder,\n _options?: QueryOptions\n ): TQueryBuilder {\n return queryBuilder;\n }\n\n protected applyIncludes(\n queryBuilder: TQueryBuilder,\n _includes?: string[] | Record<string, unknown>\n ): TQueryBuilder {\n return queryBuilder;\n }\n\n protected applySelect(queryBuilder: TQueryBuilder, _select?: string[]): TQueryBuilder {\n return queryBuilder;\n }\n\n protected applyWhereConditions(\n queryBuilder: TQueryBuilder,\n _where?: Record<string, unknown>\n ): TQueryBuilder {\n return queryBuilder;\n }\n\n protected applyCustomQuery(\n queryBuilder: TQueryBuilder,\n queryFn?: QueryModifier<TQueryBuilder>\n ): TQueryBuilder {\n if (queryFn) {\n return queryFn(queryBuilder) as TQueryBuilder;\n }\n return queryBuilder;\n }\n}\n","/**\n * UUID regex pattern\n */\nconst UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/**\n * MongoDB ObjectId regex pattern (24 hex characters)\n */\nconst OBJECT_ID_REGEX = /^[0-9a-f]{24}$/i;\n\n/**\n * Check if a value is a valid UUID\n */\nexport function isUUID(value: string): boolean {\n return UUID_REGEX.test(value);\n}\n\n/**\n * Check if a value is a valid MongoDB ObjectId\n */\nexport function isObjectId(value: string): boolean {\n return OBJECT_ID_REGEX.test(value);\n}\n\n/**\n * Check if a value is a numeric string\n */\nexport function isNumeric(value: string): boolean {\n return /^-?\\d+$/.test(value);\n}\n\n/**\n * Check if a value is a valid positive integer\n */\nexport function isPositiveInteger(value: string): boolean {\n return /^\\d+$/.test(value) && parseInt(value, 10) > 0;\n}\n\n/**\n * Check if a value is a valid slug (lowercase alphanumeric with hyphens)\n */\nexport function isSlug(value: string): boolean {\n return /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(value);\n}\n\n/**\n * Check if a value is a valid email\n */\nexport function isEmail(value: string): boolean {\n return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value);\n}\n\n/**\n * Validate that a value is not empty\n */\nexport function isNotEmpty(value: unknown): boolean {\n if (value === null || value === undefined) {\n return false;\n }\n if (typeof value === 'string') {\n return value.trim().length > 0;\n }\n return true;\n}\n\n/**\n * Validate that a value is a non-empty string\n */\nexport function isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0;\n}\n\n/**\n * Validate that a value is a plain object\n */\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * Validate that a value is a function\n */\n// eslint-disable-next-line @typescript-eslint/ban-types\nexport function isFunction(value: unknown): value is Function {\n return typeof value === 'function';\n}\n\n/**\n * Validate route parameter name\n */\nexport function isValidParamName(value: string): boolean {\n return /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(value);\n}\n","import type {\n Sequelize,\n Model,\n ModelStatic,\n FindOptions,\n Includeable,\n Transaction,\n} from 'sequelize';\nimport { BaseAdapter } from '../core/BaseAdapter';\nimport { QueryOptions, ModelMetadata, QueryModifier } from '../core/types';\nimport { BindingError } from '../errors';\nimport { isUUID } from '../utils/validators';\n\n/**\n * Sequelize model static type\n */\ntype SequelizeModelStatic = ModelStatic<Model>;\n\n/**\n * Type guard for Sequelize model\n */\nfunction isSequelizeModel(model: unknown): model is SequelizeModelStatic {\n if (!model || typeof model !== 'function') {\n return false;\n }\n const m = model as unknown as Record<string, unknown>;\n return (\n typeof m.findOne === 'function' &&\n typeof m.findAll === 'function' &&\n typeof m.rawAttributes === 'object'\n );\n}\n\n/**\n * Adapter for Sequelize ORM supporting PostgreSQL, MySQL, SQLite, MSSQL\n */\nexport class SequelizeAdapter extends BaseAdapter<SequelizeModelStatic, Model, FindOptions> {\n readonly name = 'sequelize';\n\n constructor(private sequelize: Sequelize) {\n super();\n }\n\n getSequelize(): Sequelize {\n return this.sequelize;\n }\n\n async findByKey(\n model: SequelizeModelStatic,\n key: string,\n value: unknown,\n options: QueryOptions = {}\n ): Promise<Model | null> {\n this.validateModel(model);\n\n try {\n const transformedValue = this.transformValue(model, key, value as string);\n\n const findOptions: FindOptions = {\n where: { [key]: transformedValue },\n };\n\n if (options.select && options.select.length > 0) {\n findOptions.attributes = options.select;\n }\n\n if (options.include) {\n findOptions.include = this.buildIncludes(options.include);\n }\n\n if (options.where) {\n findOptions.where = {\n ...findOptions.where,\n ...options.where,\n };\n }\n\n const isParanoid = model.options?.paranoid;\n if (isParanoid) {\n if (options.withTrashed) {\n findOptions.paranoid = false;\n } else if (options.onlyTrashed) {\n findOptions.paranoid = false;\n // Sequelize Op must be loaded synchronously for query construction\n // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires\n const { Op: SeqOp } = require('sequelize');\n const whereClause = findOptions.where as Record<string, unknown>;\n whereClause.deletedAt = { [SeqOp.ne]: null };\n }\n }\n\n if (options.lock === 'forUpdate') {\n findOptions.lock = true;\n } else if (options.lock === 'forShare') {\n // Sequelize Transaction must be loaded synchronously for lock types\n // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires\n const { Transaction: SeqTransaction } = require('sequelize') as {\n Transaction: typeof Transaction;\n };\n findOptions.lock = SeqTransaction.LOCK.SHARE;\n }\n\n let result = await model.findOne(findOptions);\n\n if (options.query && !result) {\n result = await this.findWithCustomQuery(model, key, transformedValue, options);\n }\n\n return result;\n } catch (error) {\n throw new BindingError(\n `Failed to fetch ${model.name}: ${(error as Error).message}`,\n error as Error\n );\n }\n }\n\n getPrimaryKeyName(model: SequelizeModelStatic): string {\n return model.primaryKeyAttribute || 'id';\n }\n\n isValidModel(model: unknown): model is SequelizeModelStatic {\n return isSequelizeModel(model);\n }\n\n transformValue(model: SequelizeModelStatic, key: string, value: string): unknown {\n const attributes = model.rawAttributes;\n const attribute = attributes?.[key];\n\n if (!attribute) {\n if (isUUID(value)) {\n return value;\n }\n const num = parseInt(value, 10);\n if (!isNaN(num) && num.toString() === value) {\n return num;\n }\n return value;\n }\n\n const attrType = attribute.type;\n const type = attrType?.constructor?.name || String(attrType);\n\n switch (type) {\n case 'INTEGER':\n case 'BIGINT':\n case 'SMALLINT': {\n const intNum = parseInt(value, 10);\n return isNaN(intNum) ? value : intNum;\n }\n\n case 'FLOAT':\n case 'DOUBLE':\n case 'DECIMAL': {\n const floatNum = parseFloat(value);\n return isNaN(floatNum) ? value : floatNum;\n }\n\n case 'BOOLEAN':\n return value === 'true' || value === '1';\n\n case 'UUID':\n return value;\n\n default:\n return value;\n }\n }\n\n supportsSoftDeletes(model: SequelizeModelStatic): boolean {\n return !!model.options?.paranoid;\n }\n\n getModelMetadata(model: SequelizeModelStatic): ModelMetadata {\n const tableName = model.tableName || model.name;\n const associations = Object.keys(model.associations || {});\n\n return {\n name: model.name,\n primaryKey: this.getPrimaryKeyName(model),\n tableName: tableName,\n softDeletes: this.supportsSoftDeletes(model),\n relations: associations,\n adapter: this.name,\n };\n }\n\n private buildIncludes(includes: string[] | Record<string, unknown>): Includeable[] {\n if (Array.isArray(includes)) {\n return includes.map(relation => ({ association: relation }));\n }\n\n return Object.entries(includes).map(([relation, opts]) => {\n if (typeof opts === 'boolean' && opts) {\n return { association: relation };\n }\n\n if (typeof opts === 'object' && opts !== null) {\n return {\n association: relation,\n ...opts,\n };\n }\n\n return { association: relation };\n });\n }\n\n private async findWithCustomQuery(\n model: SequelizeModelStatic,\n key: string,\n value: unknown,\n options: QueryOptions\n ): Promise<Model | null> {\n const findOptions: FindOptions = {\n where: { [key]: value },\n };\n\n if (options.query) {\n (options.query as QueryModifier<FindOptions>)(findOptions);\n }\n\n return await model.findOne(findOptions);\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { EntityTarget, ObjectLiteral, SelectQueryBuilder, DataSource } from 'typeorm';
|
|
2
|
+
import { b as BaseAdapter, Q as QueryOptions, d as ModelMetadata } from '../BaseAdapter-BjvLQijd.mjs';
|
|
3
|
+
import 'express';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* TypeORM entity type alias for better readability
|
|
7
|
+
*/
|
|
8
|
+
type TypeORMEntity = EntityTarget<ObjectLiteral>;
|
|
9
|
+
/**
|
|
10
|
+
* Adapter for TypeORM supporting SQL and NoSQL databases
|
|
11
|
+
*/
|
|
12
|
+
declare class TypeORMAdapter extends BaseAdapter<TypeORMEntity, ObjectLiteral, SelectQueryBuilder<ObjectLiteral>> {
|
|
13
|
+
private dataSource;
|
|
14
|
+
readonly name = "typeorm";
|
|
15
|
+
constructor(dataSource: DataSource);
|
|
16
|
+
getDataSource(): DataSource;
|
|
17
|
+
findByKey(entity: TypeORMEntity, key: string, value: unknown, options?: QueryOptions): Promise<ObjectLiteral | null>;
|
|
18
|
+
getPrimaryKeyName(entity: TypeORMEntity): string;
|
|
19
|
+
isValidModel(model: unknown): model is TypeORMEntity;
|
|
20
|
+
transformValue(entity: TypeORMEntity, key: string, value: string): unknown;
|
|
21
|
+
supportsSoftDeletes(entity: TypeORMEntity): boolean;
|
|
22
|
+
getModelMetadata(entity: TypeORMEntity): ModelMetadata;
|
|
23
|
+
private findWithQueryBuilder;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export { TypeORMAdapter, type TypeORMEntity };
|