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.
Files changed (41) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +208 -0
  3. package/dist/BaseAdapter-BjvLQijd.d.mts +214 -0
  4. package/dist/BaseAdapter-BjvLQijd.d.ts +214 -0
  5. package/dist/adapters/KnexAdapter.d.mts +44 -0
  6. package/dist/adapters/KnexAdapter.d.ts +44 -0
  7. package/dist/adapters/KnexAdapter.js +257 -0
  8. package/dist/adapters/KnexAdapter.js.map +1 -0
  9. package/dist/adapters/KnexAdapter.mjs +229 -0
  10. package/dist/adapters/KnexAdapter.mjs.map +1 -0
  11. package/dist/adapters/MongooseAdapter.d.mts +30 -0
  12. package/dist/adapters/MongooseAdapter.d.ts +30 -0
  13. package/dist/adapters/MongooseAdapter.js +245 -0
  14. package/dist/adapters/MongooseAdapter.js.map +1 -0
  15. package/dist/adapters/MongooseAdapter.mjs +225 -0
  16. package/dist/adapters/MongooseAdapter.mjs.map +1 -0
  17. package/dist/adapters/PrismaAdapter.d.mts +42 -0
  18. package/dist/adapters/PrismaAdapter.d.ts +42 -0
  19. package/dist/adapters/PrismaAdapter.js +247 -0
  20. package/dist/adapters/PrismaAdapter.js.map +1 -0
  21. package/dist/adapters/PrismaAdapter.mjs +220 -0
  22. package/dist/adapters/PrismaAdapter.mjs.map +1 -0
  23. package/dist/adapters/SequelizeAdapter.d.mts +27 -0
  24. package/dist/adapters/SequelizeAdapter.d.ts +27 -0
  25. package/dist/adapters/SequelizeAdapter.js +280 -0
  26. package/dist/adapters/SequelizeAdapter.js.map +1 -0
  27. package/dist/adapters/SequelizeAdapter.mjs +260 -0
  28. package/dist/adapters/SequelizeAdapter.mjs.map +1 -0
  29. package/dist/adapters/TypeORMAdapter.d.mts +26 -0
  30. package/dist/adapters/TypeORMAdapter.d.ts +26 -0
  31. package/dist/adapters/TypeORMAdapter.js +294 -0
  32. package/dist/adapters/TypeORMAdapter.js.map +1 -0
  33. package/dist/adapters/TypeORMAdapter.mjs +267 -0
  34. package/dist/adapters/TypeORMAdapter.mjs.map +1 -0
  35. package/dist/index.d.mts +411 -0
  36. package/dist/index.d.ts +411 -0
  37. package/dist/index.js +1514 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/index.mjs +1450 -0
  40. package/dist/index.mjs.map +1 -0
  41. package/package.json +148 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Sepehr Mohseni
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,208 @@
1
+ # express-model-binding
2
+
3
+ [![npm version](https://badge.fury.io/js/express-model-binding.svg)](https://www.npmjs.com/package/express-model-binding)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.x-blue.svg)](http://www.typescriptlang.org/)
6
+
7
+ Route model binding for Express.js. If you've used Laravel, you know how useful this pattern is—automatically resolve route parameters to database models.
8
+
9
+ Works with Knex, Mongoose, TypeORM, Sequelize, and Prisma.
10
+
11
+ ## Why?
12
+
13
+ Instead of this:
14
+
15
+ ```typescript
16
+ app.get('/users/:id', async (req, res) => {
17
+ const user = await db('users').where('id', req.params.id).first();
18
+ if (!user) return res.status(404).json({ error: 'User not found' });
19
+ res.json(user);
20
+ });
21
+ ```
22
+
23
+ Write this:
24
+
25
+ ```typescript
26
+ app.get('/users/:user', bindModel('user', 'users'), (req, res) => {
27
+ res.json(req.user);
28
+ });
29
+ ```
30
+
31
+ ## Install
32
+
33
+ ```bash
34
+ npm install express-model-binding
35
+ ```
36
+
37
+ Then install your ORM:
38
+
39
+ ```bash
40
+ npm install knex pg # Knex + Postgres
41
+ npm install mongoose # MongoDB
42
+ npm install typeorm # TypeORM
43
+ npm install sequelize # Sequelize
44
+ npm install @prisma/client # Prisma
45
+ ```
46
+
47
+ ## Setup
48
+
49
+ ```typescript
50
+ import express from 'express';
51
+ import Knex from 'knex';
52
+ import { ModelBinder, KnexAdapter, bindModel } from 'express-model-binding';
53
+
54
+ const app = express();
55
+ const knex = Knex({ client: 'pg', connection: process.env.DATABASE_URL });
56
+
57
+ // Configure once at startup
58
+ ModelBinder.setAdapter(new KnexAdapter(knex));
59
+
60
+ // Use in routes
61
+ app.get('/users/:user', bindModel('user', 'users'), (req, res) => {
62
+ res.json(req.user);
63
+ });
64
+ ```
65
+
66
+ ## Adapters
67
+
68
+ **Knex**
69
+ ```typescript
70
+ import { KnexAdapter } from 'express-model-binding';
71
+ ModelBinder.setAdapter(new KnexAdapter(knex));
72
+ app.get('/users/:user', bindModel('user', 'users'), handler);
73
+ ```
74
+
75
+ **Mongoose**
76
+ ```typescript
77
+ import { MongooseAdapter } from 'express-model-binding';
78
+ ModelBinder.setAdapter(new MongooseAdapter());
79
+ app.get('/users/:user', bindModel('user', User), handler);
80
+ ```
81
+
82
+ **TypeORM**
83
+ ```typescript
84
+ import { TypeORMAdapter } from 'express-model-binding';
85
+ ModelBinder.setAdapter(new TypeORMAdapter(dataSource));
86
+ app.get('/users/:user', bindModel('user', User), handler);
87
+ ```
88
+
89
+ **Sequelize**
90
+ ```typescript
91
+ import { SequelizeAdapter } from 'express-model-binding';
92
+ ModelBinder.setAdapter(new SequelizeAdapter(sequelize));
93
+ app.get('/users/:user', bindModel('user', User), handler);
94
+ ```
95
+
96
+ **Prisma**
97
+ ```typescript
98
+ import { PrismaAdapter } from 'express-model-binding';
99
+ ModelBinder.setAdapter(new PrismaAdapter(prisma));
100
+ app.get('/users/:user', bindModel('user', 'user'), handler);
101
+ ```
102
+
103
+ ## Middleware
104
+
105
+ **bindModel** — Basic binding
106
+ ```typescript
107
+ app.get('/users/:user', bindModel('user', 'users'), handler);
108
+ ```
109
+
110
+ **bindModels** — Multiple models
111
+ ```typescript
112
+ app.get('/users/:user/posts/:post', bindModels({
113
+ user: { model: 'users' },
114
+ post: { model: 'posts' },
115
+ }), handler);
116
+ ```
117
+
118
+ **bindOptional** — Don't throw if missing
119
+ ```typescript
120
+ app.get('/users/:user', bindOptional('user', 'users'), handler);
121
+ ```
122
+
123
+ **bindByKey** — Bind by slug, email, etc.
124
+ ```typescript
125
+ app.get('/posts/:slug', bindByKey('slug', 'posts', 'slug'), handler);
126
+ ```
127
+
128
+ **bindAs** — Custom request property name
129
+ ```typescript
130
+ app.get('/profile/:id', bindAs('id', 'users', 'profile'), handler);
131
+ ```
132
+
133
+ **bindCached** — With caching
134
+ ```typescript
135
+ app.get('/users/:user', bindCached('user', 'users', 60000), handler);
136
+ ```
137
+
138
+ **bindWithRelations** — Eager load relations
139
+ ```typescript
140
+ app.get('/users/:user', bindWithRelations('user', 'users', ['posts']), handler);
141
+ ```
142
+
143
+ ## Options
144
+
145
+ ```typescript
146
+ bindModel('user', 'users', {
147
+ key: 'slug', // Field to query (default: primary key)
148
+ optional: true, // Don't throw 404 if not found
149
+ select: ['id', 'name'], // Select specific fields
150
+ include: ['posts'], // Load relations
151
+ where: { active: true }, // Extra conditions
152
+ withTrashed: true, // Include soft-deleted
153
+ cache: true, // Enable caching
154
+ cacheTTL: 30000, // Cache duration (ms)
155
+ errorMessage: 'Not found',
156
+ });
157
+ ```
158
+
159
+ ## Error Handling
160
+
161
+ ```typescript
162
+ import { ModelNotFoundError } from 'express-model-binding';
163
+
164
+ app.use((err, req, res, next) => {
165
+ if (err instanceof ModelNotFoundError) {
166
+ return res.status(404).json({ error: err.message });
167
+ }
168
+ next(err);
169
+ });
170
+ ```
171
+
172
+ ## Utilities
173
+
174
+ **Transformers** — Convert parameter values
175
+ ```typescript
176
+ import { toNumber, toLowerCase } from 'express-model-binding';
177
+ bindModel('user', 'users', { transformValue: toNumber });
178
+ ```
179
+
180
+ **Validators** — Check format before querying
181
+ ```typescript
182
+ import { isUUID, isObjectId } from 'express-model-binding';
183
+ ```
184
+
185
+ ## Debugging
186
+
187
+ ```typescript
188
+ ModelBinder.setDebug(true);
189
+ ```
190
+
191
+ ## API
192
+
193
+ ```typescript
194
+ ModelBinder.setAdapter(adapter) // Set ORM adapter
195
+ ModelBinder.getAdapter() // Get current adapter
196
+ ModelBinder.clearCache() // Clear binding cache
197
+ ModelBinder.reset() // Reset all state
198
+ ```
199
+
200
+ ## License
201
+
202
+ MIT © [Sepehr Mohseni](https://github.com/sepehr-mohseni)
203
+
204
+ ## Links
205
+
206
+ - [npm](https://www.npmjs.com/package/express-model-binding)
207
+ - [GitHub](https://github.com/sepehr-mohseni/express-model-binding)
208
+ - [Issues](https://github.com/sepehr-mohseni/express-model-binding/issues)
@@ -0,0 +1,214 @@
1
+ import { Request, Response, NextFunction, RequestHandler } from 'express';
2
+
3
+ /**
4
+ * Generic query builder type - adapters can narrow this to their specific type
5
+ */
6
+ type QueryBuilder<T = unknown> = T;
7
+ /**
8
+ * Query modifier function type
9
+ */
10
+ type QueryModifier<T = unknown> = (queryBuilder: QueryBuilder<T>) => QueryBuilder<T>;
11
+ /**
12
+ * Base adapter interface that all ORM adapters must implement
13
+ */
14
+ interface IORMAdapter<TModel = unknown, TResult = unknown> {
15
+ readonly name: string;
16
+ findByKey(model: TModel, key: string, value: unknown, options?: QueryOptions): Promise<TResult | null>;
17
+ getPrimaryKeyName(model: TModel): string;
18
+ isValidModel(model: unknown): model is TModel;
19
+ transformValue(model: TModel, key: string, value: string): unknown;
20
+ supportsSoftDeletes(model: TModel): boolean;
21
+ getModelMetadata?(model: TModel): ModelMetadata;
22
+ }
23
+ /**
24
+ * Query options for model lookups
25
+ */
26
+ interface QueryOptions {
27
+ /**
28
+ * Relations to eager load
29
+ */
30
+ include?: string[] | Record<string, unknown>;
31
+ /**
32
+ * Additional WHERE conditions
33
+ */
34
+ where?: Record<string, unknown>;
35
+ /**
36
+ * Custom query modifier - receives ORM-specific query builder
37
+ */
38
+ query?: QueryModifier;
39
+ /**
40
+ * Fields to select
41
+ */
42
+ select?: string[];
43
+ /**
44
+ * Include soft-deleted records
45
+ */
46
+ withTrashed?: boolean;
47
+ /**
48
+ * Only return soft-deleted records
49
+ */
50
+ onlyTrashed?: boolean;
51
+ /**
52
+ * Enable result caching
53
+ */
54
+ cache?: boolean | number;
55
+ /**
56
+ * Row locking for transactions
57
+ */
58
+ lock?: 'forUpdate' | 'forShare';
59
+ }
60
+ /**
61
+ * Binding middleware options
62
+ */
63
+ interface BindOptions extends QueryOptions {
64
+ /**
65
+ * Field to search by (defaults to primary key)
66
+ */
67
+ key?: string;
68
+ /**
69
+ * Custom error when model not found
70
+ */
71
+ onNotFound?: Error | ((paramName: string, paramValue: string) => Error);
72
+ /**
73
+ * Transform parameter value before querying
74
+ */
75
+ transformValue?: (value: string) => unknown;
76
+ /**
77
+ * Property name for attaching model to request
78
+ */
79
+ as?: string;
80
+ /**
81
+ * Don't throw if model not found
82
+ */
83
+ optional?: boolean;
84
+ /**
85
+ * Custom 404 message
86
+ */
87
+ errorMessage?: string;
88
+ /**
89
+ * Validate loaded model
90
+ */
91
+ validate?: (model: unknown, req: Request) => void | Promise<void>;
92
+ /**
93
+ * Enable caching
94
+ */
95
+ cache?: boolean;
96
+ /**
97
+ * Cache TTL in milliseconds
98
+ */
99
+ cacheTTL?: number;
100
+ }
101
+ /**
102
+ * Multi-model binding configuration
103
+ */
104
+ interface ModelBindingsConfig {
105
+ [paramName: string]: {
106
+ model: unknown;
107
+ options?: BindOptions;
108
+ };
109
+ }
110
+ /**
111
+ * Binding operation context
112
+ */
113
+ interface BindingContext {
114
+ req: Request;
115
+ res: Response;
116
+ paramName: string;
117
+ paramValue: string;
118
+ model: unknown;
119
+ options: BindOptions;
120
+ adapter: IORMAdapter;
121
+ startTime: number;
122
+ }
123
+ /**
124
+ * Binding operation result
125
+ */
126
+ interface BindingResult {
127
+ success: boolean;
128
+ model?: unknown;
129
+ error?: Error;
130
+ duration: number;
131
+ fromCache?: boolean;
132
+ }
133
+ /**
134
+ * Model metadata for debugging
135
+ */
136
+ interface ModelMetadata {
137
+ name: string;
138
+ primaryKey: string;
139
+ tableName?: string;
140
+ relations?: string[];
141
+ softDeletes: boolean;
142
+ adapter?: string;
143
+ [key: string]: unknown;
144
+ }
145
+ /**
146
+ * Cache entry structure
147
+ */
148
+ interface CacheEntry<T = unknown> {
149
+ value: T;
150
+ timestamp: number;
151
+ ttl: number;
152
+ }
153
+ /**
154
+ * Global configuration options
155
+ */
156
+ interface ModelBindingGlobalConfig {
157
+ adapter?: IORMAdapter;
158
+ cache?: {
159
+ enabled: boolean;
160
+ ttl: number;
161
+ maxSize?: number;
162
+ };
163
+ debug?: boolean;
164
+ logger?: (message: string, context?: unknown) => void;
165
+ onError?: (error: Error, context: BindingContext) => void;
166
+ }
167
+ /**
168
+ * Express request with bound models
169
+ */
170
+ interface TypedRequest<P = Record<string, string>, ResBody = unknown, ReqBody = unknown, ReqQuery = unknown, Models extends Record<string, unknown> = Record<string, unknown>> extends Request<P, ResBody, ReqBody, ReqQuery> {
171
+ [K: string]: unknown;
172
+ models?: Models;
173
+ }
174
+ /**
175
+ * Extract model type from binding config
176
+ */
177
+ type ExtractModelType<T> = T extends {
178
+ model: infer M;
179
+ } ? M : never;
180
+ /**
181
+ * Typed request handler
182
+ */
183
+ type TypedRequestHandler<Models extends Record<string, unknown> = Record<string, unknown>, P = Record<string, string>, ResBody = unknown, ReqBody = unknown, ReqQuery = unknown> = (req: TypedRequest<P, ResBody, ReqBody, ReqQuery, Models>, res: Response<ResBody>, next: NextFunction) => void | Promise<void>;
184
+ /**
185
+ * Middleware function type
186
+ */
187
+ type MiddlewareFunction = RequestHandler;
188
+
189
+ /**
190
+ * Abstract base class providing common adapter functionality.
191
+ * Extend this class to implement ORM-specific adapters.
192
+ *
193
+ * @typeParam TModel - Model type accepted by this adapter
194
+ * @typeParam TResult - Result type returned by queries
195
+ * @typeParam TQueryBuilder - ORM-specific query builder type
196
+ */
197
+ declare abstract class BaseAdapter<TModel = unknown, TResult = unknown, TQueryBuilder = unknown> implements IORMAdapter<TModel, TResult> {
198
+ abstract readonly name: string;
199
+ abstract findByKey(model: TModel, key: string, value: unknown, options?: QueryOptions): Promise<TResult | null>;
200
+ abstract getPrimaryKeyName(model: TModel): string;
201
+ abstract isValidModel(model: unknown): model is TModel;
202
+ transformValue(_model: TModel, _key: string, value: string): unknown;
203
+ supportsSoftDeletes(_model: TModel): boolean;
204
+ getModelMetadata(model: TModel): ModelMetadata;
205
+ protected validateModel(model: unknown): asserts model is TModel;
206
+ protected getModelName(model: TModel): string;
207
+ protected applySoftDeleteFilter(queryBuilder: TQueryBuilder, _options?: QueryOptions): TQueryBuilder;
208
+ protected applyIncludes(queryBuilder: TQueryBuilder, _includes?: string[] | Record<string, unknown>): TQueryBuilder;
209
+ protected applySelect(queryBuilder: TQueryBuilder, _select?: string[]): TQueryBuilder;
210
+ protected applyWhereConditions(queryBuilder: TQueryBuilder, _where?: Record<string, unknown>): TQueryBuilder;
211
+ protected applyCustomQuery(queryBuilder: TQueryBuilder, queryFn?: QueryModifier<TQueryBuilder>): TQueryBuilder;
212
+ }
213
+
214
+ export { type BindOptions as B, type CacheEntry as C, type ExtractModelType as E, type IORMAdapter as I, type ModelBindingsConfig as M, type QueryOptions as Q, type TypedRequest as T, type BindingResult as a, BaseAdapter as b, type BindingContext as c, type ModelMetadata as d, type ModelBindingGlobalConfig as e, type TypedRequestHandler as f, type MiddlewareFunction as g };
@@ -0,0 +1,214 @@
1
+ import { Request, Response, NextFunction, RequestHandler } from 'express';
2
+
3
+ /**
4
+ * Generic query builder type - adapters can narrow this to their specific type
5
+ */
6
+ type QueryBuilder<T = unknown> = T;
7
+ /**
8
+ * Query modifier function type
9
+ */
10
+ type QueryModifier<T = unknown> = (queryBuilder: QueryBuilder<T>) => QueryBuilder<T>;
11
+ /**
12
+ * Base adapter interface that all ORM adapters must implement
13
+ */
14
+ interface IORMAdapter<TModel = unknown, TResult = unknown> {
15
+ readonly name: string;
16
+ findByKey(model: TModel, key: string, value: unknown, options?: QueryOptions): Promise<TResult | null>;
17
+ getPrimaryKeyName(model: TModel): string;
18
+ isValidModel(model: unknown): model is TModel;
19
+ transformValue(model: TModel, key: string, value: string): unknown;
20
+ supportsSoftDeletes(model: TModel): boolean;
21
+ getModelMetadata?(model: TModel): ModelMetadata;
22
+ }
23
+ /**
24
+ * Query options for model lookups
25
+ */
26
+ interface QueryOptions {
27
+ /**
28
+ * Relations to eager load
29
+ */
30
+ include?: string[] | Record<string, unknown>;
31
+ /**
32
+ * Additional WHERE conditions
33
+ */
34
+ where?: Record<string, unknown>;
35
+ /**
36
+ * Custom query modifier - receives ORM-specific query builder
37
+ */
38
+ query?: QueryModifier;
39
+ /**
40
+ * Fields to select
41
+ */
42
+ select?: string[];
43
+ /**
44
+ * Include soft-deleted records
45
+ */
46
+ withTrashed?: boolean;
47
+ /**
48
+ * Only return soft-deleted records
49
+ */
50
+ onlyTrashed?: boolean;
51
+ /**
52
+ * Enable result caching
53
+ */
54
+ cache?: boolean | number;
55
+ /**
56
+ * Row locking for transactions
57
+ */
58
+ lock?: 'forUpdate' | 'forShare';
59
+ }
60
+ /**
61
+ * Binding middleware options
62
+ */
63
+ interface BindOptions extends QueryOptions {
64
+ /**
65
+ * Field to search by (defaults to primary key)
66
+ */
67
+ key?: string;
68
+ /**
69
+ * Custom error when model not found
70
+ */
71
+ onNotFound?: Error | ((paramName: string, paramValue: string) => Error);
72
+ /**
73
+ * Transform parameter value before querying
74
+ */
75
+ transformValue?: (value: string) => unknown;
76
+ /**
77
+ * Property name for attaching model to request
78
+ */
79
+ as?: string;
80
+ /**
81
+ * Don't throw if model not found
82
+ */
83
+ optional?: boolean;
84
+ /**
85
+ * Custom 404 message
86
+ */
87
+ errorMessage?: string;
88
+ /**
89
+ * Validate loaded model
90
+ */
91
+ validate?: (model: unknown, req: Request) => void | Promise<void>;
92
+ /**
93
+ * Enable caching
94
+ */
95
+ cache?: boolean;
96
+ /**
97
+ * Cache TTL in milliseconds
98
+ */
99
+ cacheTTL?: number;
100
+ }
101
+ /**
102
+ * Multi-model binding configuration
103
+ */
104
+ interface ModelBindingsConfig {
105
+ [paramName: string]: {
106
+ model: unknown;
107
+ options?: BindOptions;
108
+ };
109
+ }
110
+ /**
111
+ * Binding operation context
112
+ */
113
+ interface BindingContext {
114
+ req: Request;
115
+ res: Response;
116
+ paramName: string;
117
+ paramValue: string;
118
+ model: unknown;
119
+ options: BindOptions;
120
+ adapter: IORMAdapter;
121
+ startTime: number;
122
+ }
123
+ /**
124
+ * Binding operation result
125
+ */
126
+ interface BindingResult {
127
+ success: boolean;
128
+ model?: unknown;
129
+ error?: Error;
130
+ duration: number;
131
+ fromCache?: boolean;
132
+ }
133
+ /**
134
+ * Model metadata for debugging
135
+ */
136
+ interface ModelMetadata {
137
+ name: string;
138
+ primaryKey: string;
139
+ tableName?: string;
140
+ relations?: string[];
141
+ softDeletes: boolean;
142
+ adapter?: string;
143
+ [key: string]: unknown;
144
+ }
145
+ /**
146
+ * Cache entry structure
147
+ */
148
+ interface CacheEntry<T = unknown> {
149
+ value: T;
150
+ timestamp: number;
151
+ ttl: number;
152
+ }
153
+ /**
154
+ * Global configuration options
155
+ */
156
+ interface ModelBindingGlobalConfig {
157
+ adapter?: IORMAdapter;
158
+ cache?: {
159
+ enabled: boolean;
160
+ ttl: number;
161
+ maxSize?: number;
162
+ };
163
+ debug?: boolean;
164
+ logger?: (message: string, context?: unknown) => void;
165
+ onError?: (error: Error, context: BindingContext) => void;
166
+ }
167
+ /**
168
+ * Express request with bound models
169
+ */
170
+ interface TypedRequest<P = Record<string, string>, ResBody = unknown, ReqBody = unknown, ReqQuery = unknown, Models extends Record<string, unknown> = Record<string, unknown>> extends Request<P, ResBody, ReqBody, ReqQuery> {
171
+ [K: string]: unknown;
172
+ models?: Models;
173
+ }
174
+ /**
175
+ * Extract model type from binding config
176
+ */
177
+ type ExtractModelType<T> = T extends {
178
+ model: infer M;
179
+ } ? M : never;
180
+ /**
181
+ * Typed request handler
182
+ */
183
+ type TypedRequestHandler<Models extends Record<string, unknown> = Record<string, unknown>, P = Record<string, string>, ResBody = unknown, ReqBody = unknown, ReqQuery = unknown> = (req: TypedRequest<P, ResBody, ReqBody, ReqQuery, Models>, res: Response<ResBody>, next: NextFunction) => void | Promise<void>;
184
+ /**
185
+ * Middleware function type
186
+ */
187
+ type MiddlewareFunction = RequestHandler;
188
+
189
+ /**
190
+ * Abstract base class providing common adapter functionality.
191
+ * Extend this class to implement ORM-specific adapters.
192
+ *
193
+ * @typeParam TModel - Model type accepted by this adapter
194
+ * @typeParam TResult - Result type returned by queries
195
+ * @typeParam TQueryBuilder - ORM-specific query builder type
196
+ */
197
+ declare abstract class BaseAdapter<TModel = unknown, TResult = unknown, TQueryBuilder = unknown> implements IORMAdapter<TModel, TResult> {
198
+ abstract readonly name: string;
199
+ abstract findByKey(model: TModel, key: string, value: unknown, options?: QueryOptions): Promise<TResult | null>;
200
+ abstract getPrimaryKeyName(model: TModel): string;
201
+ abstract isValidModel(model: unknown): model is TModel;
202
+ transformValue(_model: TModel, _key: string, value: string): unknown;
203
+ supportsSoftDeletes(_model: TModel): boolean;
204
+ getModelMetadata(model: TModel): ModelMetadata;
205
+ protected validateModel(model: unknown): asserts model is TModel;
206
+ protected getModelName(model: TModel): string;
207
+ protected applySoftDeleteFilter(queryBuilder: TQueryBuilder, _options?: QueryOptions): TQueryBuilder;
208
+ protected applyIncludes(queryBuilder: TQueryBuilder, _includes?: string[] | Record<string, unknown>): TQueryBuilder;
209
+ protected applySelect(queryBuilder: TQueryBuilder, _select?: string[]): TQueryBuilder;
210
+ protected applyWhereConditions(queryBuilder: TQueryBuilder, _where?: Record<string, unknown>): TQueryBuilder;
211
+ protected applyCustomQuery(queryBuilder: TQueryBuilder, queryFn?: QueryModifier<TQueryBuilder>): TQueryBuilder;
212
+ }
213
+
214
+ export { type BindOptions as B, type CacheEntry as C, type ExtractModelType as E, type IORMAdapter as I, type ModelBindingsConfig as M, type QueryOptions as Q, type TypedRequest as T, type BindingResult as a, BaseAdapter as b, type BindingContext as c, type ModelMetadata as d, type ModelBindingGlobalConfig as e, type TypedRequestHandler as f, type MiddlewareFunction as g };
@@ -0,0 +1,44 @@
1
+ import { Knex } from 'knex';
2
+ import { b as BaseAdapter, Q as QueryOptions, d as ModelMetadata } from '../BaseAdapter-BjvLQijd.mjs';
3
+ import 'express';
4
+
5
+ /**
6
+ * Model definition for Knex tables with soft delete support
7
+ */
8
+ interface KnexModel {
9
+ tableName: string;
10
+ primaryKey?: string;
11
+ softDeleteColumn?: string;
12
+ }
13
+ /**
14
+ * Union type for Knex model inputs
15
+ */
16
+ type KnexModelInput = string | KnexModel;
17
+ /**
18
+ * Adapter for Knex query builder supporting PostgreSQL, MySQL, SQLite, MSSQL, Oracle
19
+ */
20
+ declare class KnexAdapter extends BaseAdapter<KnexModelInput, Record<string, unknown>, Knex.QueryBuilder> {
21
+ private knex;
22
+ readonly name = "knex";
23
+ constructor(knex: Knex);
24
+ getKnex(): Knex;
25
+ findByKey(model: KnexModelInput, key: string, value: unknown, options?: QueryOptions): Promise<Record<string, unknown> | null>;
26
+ getPrimaryKeyName(model: KnexModelInput): string;
27
+ isValidModel(model: unknown): model is KnexModelInput;
28
+ transformValue(model: KnexModelInput, key: string, value: string): unknown;
29
+ supportsSoftDeletes(model: KnexModelInput): boolean;
30
+ getModelMetadata(model: KnexModelInput): ModelMetadata;
31
+ private getTableName;
32
+ private getSoftDeleteColumn;
33
+ protected applyWhereConditions(query: Knex.QueryBuilder, where: Record<string, unknown>): Knex.QueryBuilder;
34
+ }
35
+ /**
36
+ * Create a Knex model definition
37
+ */
38
+ declare function defineKnexModel(config: {
39
+ tableName: string;
40
+ primaryKey?: string;
41
+ softDeleteColumn?: string;
42
+ }): KnexModel;
43
+
44
+ export { KnexAdapter, type KnexModel, type KnexModelInput, defineKnexModel };