@venizia/ignis-docs 0.0.7 → 0.0.8-1
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/dist/mcp-server/common/paths.d.ts +4 -2
- package/dist/mcp-server/common/paths.d.ts.map +1 -1
- package/dist/mcp-server/common/paths.js +8 -6
- package/dist/mcp-server/common/paths.js.map +1 -1
- package/dist/mcp-server/helpers/docs.helper.d.ts.map +1 -1
- package/dist/mcp-server/helpers/docs.helper.js +1 -1
- package/dist/mcp-server/helpers/docs.helper.js.map +1 -1
- package/dist/mcp-server/tools/base.tool.d.ts +1 -1
- package/dist/mcp-server/tools/docs/get-document-content.tool.d.ts +1 -1
- package/dist/mcp-server/tools/docs/get-document-content.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/docs/get-document-content.tool.js +7 -7
- package/dist/mcp-server/tools/docs/get-document-metadata.tool.js +3 -3
- package/dist/mcp-server/tools/docs/get-package-overview.tool.d.ts +1 -1
- package/dist/mcp-server/tools/docs/get-package-overview.tool.js +1 -1
- package/dist/mcp-server/tools/docs/search-documents.tool.d.ts +1 -1
- package/dist/mcp-server/tools/docs/search-documents.tool.js +1 -1
- package/dist/mcp-server/tools/docs/search-documents.tool.js.map +1 -1
- package/dist/mcp-server/tools/github/list-project-files.tool.d.ts +1 -1
- package/dist/mcp-server/tools/github/list-project-files.tool.js +1 -1
- package/dist/mcp-server/tools/github/list-project-files.tool.js.map +1 -1
- package/dist/mcp-server/tools/github/search-code.tool.d.ts +1 -1
- package/dist/mcp-server/tools/github/search-code.tool.js +1 -1
- package/dist/mcp-server/tools/github/search-code.tool.js.map +1 -1
- package/package.json +9 -9
- package/wiki/best-practices/api-usage-examples.md +9 -9
- package/wiki/best-practices/architectural-patterns.md +19 -3
- package/wiki/best-practices/architecture-decisions.md +6 -6
- package/wiki/best-practices/code-style-standards/advanced-patterns.md +1 -1
- package/wiki/best-practices/code-style-standards/control-flow.md +1 -1
- package/wiki/best-practices/code-style-standards/function-patterns.md +2 -2
- package/wiki/best-practices/code-style-standards/index.md +2 -2
- package/wiki/best-practices/code-style-standards/naming-conventions.md +1 -1
- package/wiki/best-practices/code-style-standards/route-definitions.md +4 -4
- package/wiki/best-practices/data-modeling.md +1 -1
- package/wiki/best-practices/deployment-strategies.md +1 -1
- package/wiki/best-practices/error-handling.md +2 -2
- package/wiki/best-practices/performance-optimization.md +3 -3
- package/wiki/best-practices/security-guidelines.md +2 -2
- package/wiki/best-practices/troubleshooting-tips.md +1 -1
- package/wiki/{references → extensions}/components/authentication/api.md +12 -20
- package/wiki/{references → extensions}/components/authentication/errors.md +1 -1
- package/wiki/{references → extensions}/components/authentication/index.md +5 -8
- package/wiki/{references → extensions}/components/authentication/usage.md +20 -36
- package/wiki/{references → extensions}/components/authorization/api.md +62 -13
- package/wiki/{references → extensions}/components/authorization/errors.md +12 -7
- package/wiki/{references → extensions}/components/authorization/index.md +93 -6
- package/wiki/{references → extensions}/components/authorization/usage.md +42 -4
- package/wiki/{references → extensions}/components/health-check.md +5 -4
- package/wiki/{references → extensions}/components/index.md +2 -0
- package/wiki/{references → extensions}/components/mail/index.md +1 -1
- package/wiki/{references → extensions}/components/request-tracker.md +1 -1
- package/wiki/{references → extensions}/components/socket-io/api.md +2 -2
- package/wiki/{references → extensions}/components/socket-io/errors.md +2 -0
- package/wiki/{references → extensions}/components/socket-io/index.md +24 -20
- package/wiki/{references → extensions}/components/socket-io/usage.md +2 -2
- package/wiki/{references → extensions}/components/static-asset/api.md +14 -15
- package/wiki/{references → extensions}/components/static-asset/errors.md +3 -1
- package/wiki/{references → extensions}/components/static-asset/index.md +158 -89
- package/wiki/{references → extensions}/components/static-asset/usage.md +8 -5
- package/wiki/{references → extensions}/components/swagger.md +3 -3
- package/wiki/{references → extensions}/components/template/index.md +4 -4
- package/wiki/{references → extensions}/components/template/setup-page.md +1 -1
- package/wiki/{references → extensions}/components/template/single-page.md +1 -1
- package/wiki/{references → extensions}/components/websocket/api.md +7 -6
- package/wiki/{references → extensions}/components/websocket/errors.md +17 -3
- package/wiki/{references → extensions}/components/websocket/index.md +17 -11
- package/wiki/{references → extensions}/components/websocket/usage.md +2 -2
- package/wiki/{references → extensions}/helpers/crypto/index.md +1 -1
- package/wiki/{references → extensions}/helpers/env/index.md +9 -5
- package/wiki/{references → extensions}/helpers/error/index.md +2 -7
- package/wiki/{references → extensions}/helpers/index.md +18 -6
- package/wiki/{references → extensions}/helpers/kafka/admin.md +13 -1
- package/wiki/{references → extensions}/helpers/kafka/consumer.md +32 -31
- package/wiki/{references → extensions}/helpers/kafka/examples.md +20 -20
- package/wiki/{references → extensions}/helpers/kafka/index.md +61 -54
- package/wiki/{references → extensions}/helpers/kafka/producer.md +21 -20
- package/wiki/{references → extensions}/helpers/kafka/schema-registry.md +25 -25
- package/wiki/{references → extensions}/helpers/logger/index.md +2 -2
- package/wiki/{references → extensions}/helpers/queue/index.md +400 -4
- package/wiki/{references → extensions}/helpers/storage/api.md +170 -10
- package/wiki/{references → extensions}/helpers/storage/index.md +44 -8
- package/wiki/{references → extensions}/helpers/template/index.md +1 -1
- package/wiki/{references → extensions}/helpers/testing/index.md +4 -4
- package/wiki/{references → extensions}/helpers/types/index.md +63 -16
- package/wiki/{references → extensions}/helpers/websocket/index.md +1 -1
- package/wiki/extensions/index.md +48 -0
- package/wiki/guides/core-concepts/application/bootstrapping.md +55 -37
- package/wiki/guides/core-concepts/application/index.md +95 -35
- package/wiki/guides/core-concepts/components-guide.md +23 -19
- package/wiki/guides/core-concepts/components.md +34 -10
- package/wiki/guides/core-concepts/dependency-injection.md +99 -34
- package/wiki/guides/core-concepts/grpc-controllers.md +295 -0
- package/wiki/guides/core-concepts/persistent/datasources.md +37 -19
- package/wiki/guides/core-concepts/persistent/index.md +6 -6
- package/wiki/guides/core-concepts/persistent/models.md +50 -6
- package/wiki/guides/core-concepts/persistent/repositories.md +83 -8
- package/wiki/guides/core-concepts/persistent/transactions.md +39 -8
- package/wiki/guides/core-concepts/{controllers.md → rest-controllers.md} +32 -35
- package/wiki/guides/core-concepts/services.md +19 -6
- package/wiki/guides/get-started/5-minute-quickstart.md +17 -17
- package/wiki/guides/get-started/philosophy.md +1 -1
- package/wiki/guides/index.md +2 -2
- package/wiki/guides/reference/glossary.md +7 -7
- package/wiki/guides/reference/mcp-docs-server.md +1 -1
- package/wiki/guides/tutorials/building-a-crud-api.md +45 -39
- package/wiki/guides/tutorials/complete-installation.md +74 -51
- package/wiki/guides/tutorials/ecommerce-api.md +39 -30
- package/wiki/guides/tutorials/realtime-chat.md +12 -13
- package/wiki/guides/tutorials/testing.md +2 -2
- package/wiki/index.md +4 -3
- package/wiki/references/base/application.md +341 -21
- package/wiki/references/base/bootstrapping.md +43 -13
- package/wiki/references/base/components.md +259 -8
- package/wiki/references/base/controllers.md +556 -253
- package/wiki/references/base/datasources.md +159 -79
- package/wiki/references/base/dependency-injection.md +299 -48
- package/wiki/references/base/filter-system/application-usage.md +18 -2
- package/wiki/references/base/filter-system/array-operators.md +14 -6
- package/wiki/references/base/filter-system/comparison-operators.md +9 -3
- package/wiki/references/base/filter-system/default-filter.md +28 -3
- package/wiki/references/base/filter-system/fields-order-pagination.md +17 -13
- package/wiki/references/base/filter-system/index.md +169 -11
- package/wiki/references/base/filter-system/json-filtering.md +51 -18
- package/wiki/references/base/filter-system/list-operators.md +4 -3
- package/wiki/references/base/filter-system/logical-operators.md +7 -2
- package/wiki/references/base/filter-system/null-operators.md +50 -0
- package/wiki/references/base/filter-system/quick-reference.md +82 -243
- package/wiki/references/base/filter-system/range-operators.md +7 -1
- package/wiki/references/base/filter-system/tips.md +34 -7
- package/wiki/references/base/filter-system/use-cases.md +6 -5
- package/wiki/references/base/grpc-controllers.md +984 -0
- package/wiki/references/base/index.md +32 -24
- package/wiki/references/base/middleware.md +347 -0
- package/wiki/references/base/models.md +390 -46
- package/wiki/references/base/providers.md +14 -14
- package/wiki/references/base/repositories/advanced.md +195 -69
- package/wiki/references/base/repositories/index.md +447 -12
- package/wiki/references/base/repositories/mixins.md +103 -98
- package/wiki/references/base/repositories/relations.md +129 -45
- package/wiki/references/base/repositories/soft-deletable.md +104 -23
- package/wiki/references/base/services.md +94 -14
- package/wiki/references/index.md +12 -10
- package/wiki/references/quick-reference.md +98 -65
- package/wiki/references/utilities/crypto.md +21 -4
- package/wiki/references/utilities/date.md +25 -7
- package/wiki/references/utilities/index.md +26 -24
- package/wiki/references/utilities/jsx.md +54 -54
- package/wiki/references/utilities/module.md +8 -6
- package/wiki/references/utilities/parse.md +16 -9
- package/wiki/references/utilities/performance.md +22 -7
- package/wiki/references/utilities/promise.md +19 -16
- package/wiki/references/utilities/request.md +48 -26
- package/wiki/references/utilities/schema.md +69 -6
- package/wiki/references/utilities/statuses.md +131 -140
- /package/wiki/{references → extensions}/components/mail/api.md +0 -0
- /package/wiki/{references → extensions}/components/mail/errors.md +0 -0
- /package/wiki/{references → extensions}/components/mail/usage.md +0 -0
- /package/wiki/{references → extensions}/components/template/api-page.md +0 -0
- /package/wiki/{references → extensions}/components/template/errors-page.md +0 -0
- /package/wiki/{references → extensions}/components/template/usage-page.md +0 -0
- /package/wiki/{references → extensions}/helpers/cron/index.md +0 -0
- /package/wiki/{references → extensions}/helpers/inversion/index.md +0 -0
- /package/wiki/{references → extensions}/helpers/network/api.md +0 -0
- /package/wiki/{references → extensions}/helpers/network/index.md +0 -0
- /package/wiki/{references → extensions}/helpers/redis/index.md +0 -0
- /package/wiki/{references → extensions}/helpers/socket-io/api.md +0 -0
- /package/wiki/{references → extensions}/helpers/socket-io/index.md +0 -0
- /package/wiki/{references → extensions}/helpers/template/single-page.md +0 -0
- /package/wiki/{references → extensions}/helpers/uid/index.md +0 -0
- /package/wiki/{references → extensions}/helpers/websocket/api.md +0 -0
- /package/wiki/{references → extensions}/helpers/worker-thread/index.md +0 -0
- /package/wiki/{references → extensions}/src-details/mcp-server.md +0 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
title: Providers Reference
|
|
3
3
|
description: Technical reference for the Provider pattern in IGNIS
|
|
4
4
|
difficulty: advanced
|
|
5
|
-
lastUpdated: 2026-
|
|
5
|
+
lastUpdated: 2026-03-15
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Providers Reference
|
|
@@ -461,38 +461,38 @@ export class MailQueueExecutorProvider extends BaseProvider<TGetMailQueueExecuto
|
|
|
461
461
|
|
|
462
462
|
### Example 3: Middleware Provider
|
|
463
463
|
|
|
464
|
-
Providers can also produce middleware:
|
|
464
|
+
Providers can also produce middleware. `RequestSpyMiddleware` is a real-world example that implements `IProvider<MiddlewareHandler>` directly (extending `BaseHelper`, not `BaseProvider`):
|
|
465
465
|
|
|
466
466
|
```typescript
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
// RequestSpyMiddleware is a provider that produces Hono middleware
|
|
470
|
-
@injectable()
|
|
467
|
+
// From packages/core/src/base/middlewares/request-spy.middleware.ts
|
|
471
468
|
export class RequestSpyMiddleware extends BaseHelper implements IProvider<MiddlewareHandler> {
|
|
472
469
|
static readonly REQUEST_ID_KEY = 'requestId';
|
|
473
470
|
|
|
474
471
|
constructor() {
|
|
475
|
-
super({ scope:
|
|
472
|
+
super({ scope: 'SpyMW' });
|
|
476
473
|
}
|
|
477
474
|
|
|
475
|
+
/** Returns a Hono middleware that logs request details and duration. */
|
|
478
476
|
value() {
|
|
479
477
|
return createMiddleware(async (context, next) => {
|
|
478
|
+
const t = performance.now();
|
|
480
479
|
const requestId = context.get(RequestSpyMiddleware.REQUEST_ID_KEY);
|
|
480
|
+
const method = context.req.method;
|
|
481
|
+
const path = context.req.path ?? '/';
|
|
481
482
|
|
|
482
|
-
this.logger.info('[
|
|
483
|
+
this.logger.info('[%s][=>] %s %s', requestId, method, path);
|
|
483
484
|
|
|
484
485
|
await next();
|
|
485
486
|
|
|
486
|
-
|
|
487
|
+
const duration = (performance.now() - t).toFixed(2);
|
|
488
|
+
this.logger.info('[%s][<=] %s %s | Took: %s (ms)', requestId, method, path, duration);
|
|
487
489
|
});
|
|
488
490
|
}
|
|
489
491
|
}
|
|
490
|
-
|
|
491
|
-
// Usage
|
|
492
|
-
const requestSpy = new RequestSpyMiddleware();
|
|
493
|
-
app.use(requestSpy.value());
|
|
494
492
|
```
|
|
495
493
|
|
|
494
|
+
Note that `RequestSpyMiddleware.value()` does not accept a `container` parameter -- the `IProvider<T>` interface defines `value(container: Container): T`, but implementations may ignore the parameter when they don't need container access. In practice, `RequestSpyMiddleware` is registered via `RequestTrackerComponent`, which binds it as a provider in the DI container and resolves it automatically.
|
|
495
|
+
|
|
496
496
|
|
|
497
497
|
## Common Patterns
|
|
498
498
|
|
|
@@ -708,7 +708,7 @@ export class ConfigProvider extends BaseProvider<Config> {
|
|
|
708
708
|
- **Related References:**
|
|
709
709
|
- [Services](./services.md) - Business logic layer
|
|
710
710
|
- [Dependency Injection](./dependency-injection.md) - DI container and injection
|
|
711
|
-
- [
|
|
711
|
+
- [Middleware](./middleware.md) - Built-in middlewares (includes `RequestSpyMiddleware` provider)
|
|
712
712
|
|
|
713
713
|
- **Guides:**
|
|
714
714
|
- [Dependency Injection Guide](/guides/core-concepts/dependency-injection.md)
|
|
@@ -101,6 +101,114 @@ async function transferFunds(fromId: string, toId: string, amount: number) {
|
|
|
101
101
|
```
|
|
102
102
|
|
|
103
103
|
|
|
104
|
+
## Row-Level Locking
|
|
105
|
+
|
|
106
|
+
Acquire pessimistic locks on selected rows within a transaction using PostgreSQL's `SELECT ... FOR UPDATE/SHARE` syntax.
|
|
107
|
+
|
|
108
|
+
### Basic Usage
|
|
109
|
+
|
|
110
|
+
Pass `lock` in options alongside a `transaction`:
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
const tx = await repo.beginTransaction();
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
// Lock the row — other transactions will wait
|
|
117
|
+
const item = await repo.findOne({
|
|
118
|
+
filter: { where: { id: '123' } },
|
|
119
|
+
options: {
|
|
120
|
+
transaction: tx,
|
|
121
|
+
lock: { strength: 'update' },
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Safe to modify — no concurrent changes possible
|
|
126
|
+
await repo.updateById({
|
|
127
|
+
id: '123',
|
|
128
|
+
data: { quantity: item.quantity - 1 },
|
|
129
|
+
options: { transaction: tx },
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
await tx.commit();
|
|
133
|
+
} catch (error) {
|
|
134
|
+
await tx.rollback();
|
|
135
|
+
throw error;
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Lock Strengths
|
|
140
|
+
|
|
141
|
+
Use the `LockStrengths` constant class or string literals:
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
import { LockStrengths } from '@venizia/ignis';
|
|
145
|
+
|
|
146
|
+
// Using constant
|
|
147
|
+
lock: { strength: LockStrengths.UPDATE }
|
|
148
|
+
|
|
149
|
+
// Using string literal
|
|
150
|
+
lock: { strength: 'update' }
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
| Strength | SQL | Use Case |
|
|
154
|
+
|----------|-----|----------|
|
|
155
|
+
| `update` | `FOR UPDATE` | Exclusive lock for writes |
|
|
156
|
+
| `no key update` | `FOR NO KEY UPDATE` | Exclusive lock, allows concurrent `FOR KEY SHARE` |
|
|
157
|
+
| `share` | `FOR SHARE` | Shared read lock, prevents writes |
|
|
158
|
+
| `key share` | `FOR KEY SHARE` | Weakest lock, only prevents key changes |
|
|
159
|
+
|
|
160
|
+
### Wait Behavior
|
|
161
|
+
|
|
162
|
+
Control what happens when rows are already locked:
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
// Skip locked rows (queue-style worker pattern)
|
|
166
|
+
const items = await repo.find({
|
|
167
|
+
filter: { where: { status: 'pending' }, limit: 10 },
|
|
168
|
+
options: {
|
|
169
|
+
transaction: tx,
|
|
170
|
+
lock: { strength: 'update', config: { skipLocked: true } },
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// Fail immediately instead of waiting
|
|
175
|
+
const item = await repo.findOne({
|
|
176
|
+
filter: { where: { id: '123' } },
|
|
177
|
+
options: {
|
|
178
|
+
transaction: tx,
|
|
179
|
+
lock: { strength: 'update', config: { noWait: true } },
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
| Config | SQL | Behavior |
|
|
185
|
+
|--------|-----|----------|
|
|
186
|
+
| *(none)* | `FOR UPDATE` | Wait until lock is released |
|
|
187
|
+
| `{ noWait: true }` | `FOR UPDATE NOWAIT` | Throw error immediately if locked |
|
|
188
|
+
| `{ skipLocked: true }` | `FOR UPDATE SKIP LOCKED` | Silently skip locked rows |
|
|
189
|
+
|
|
190
|
+
### Constraints
|
|
191
|
+
|
|
192
|
+
> [!WARNING]
|
|
193
|
+
> Row-level locking requires a **transaction** and is **incompatible with `include`/`fields`** in the filter (these use the Drizzle Query API which does not support `.for()`).
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
// Error — no transaction
|
|
197
|
+
await repo.findOne({
|
|
198
|
+
filter: { where: { id: '123' } },
|
|
199
|
+
options: { lock: { strength: 'update' } },
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// Error — include uses Query API
|
|
203
|
+
await repo.findOne({
|
|
204
|
+
filter: { where: { id: '123' }, include: [{ relation: 'posts' }] },
|
|
205
|
+
options: { transaction: tx, lock: { strength: 'update' } },
|
|
206
|
+
});
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
**Supported methods:** `find`, `findOne`, `findById`
|
|
210
|
+
|
|
211
|
+
|
|
104
212
|
## Hidden Properties
|
|
105
213
|
|
|
106
214
|
Automatically exclude sensitive fields from query results.
|
|
@@ -207,7 +315,7 @@ const usersWithPosts = await repo.find({
|
|
|
207
315
|
|
|
208
316
|
| Filter Options | API Used | Performance |
|
|
209
317
|
|----------------|----------|-------------|
|
|
210
|
-
| `where`, `limit`, `order`, `offset` only | Core API | ~15-20% faster |
|
|
318
|
+
| `where`, `limit`, `order`, `offset`/`skip` only | Core API | ~15-20% faster |
|
|
211
319
|
| Has `include` (relations) | Query API | Standard |
|
|
212
320
|
| Has `fields` selection | Query API | Standard |
|
|
213
321
|
|
|
@@ -216,7 +324,7 @@ const usersWithPosts = await repo.find({
|
|
|
216
324
|
Prevent memory exhaustion on large tables:
|
|
217
325
|
|
|
218
326
|
```typescript
|
|
219
|
-
//
|
|
327
|
+
// Good - bounded result set
|
|
220
328
|
await repo.find({
|
|
221
329
|
filter: {
|
|
222
330
|
where: { status: 'active' },
|
|
@@ -230,42 +338,39 @@ await repo.find({
|
|
|
230
338
|
});
|
|
231
339
|
```
|
|
232
340
|
|
|
233
|
-
|
|
341
|
+
> [!NOTE]
|
|
342
|
+
> The default limit is `10` when using the `FilterSchema` Zod validation (via `LimitSchema`). However, when calling repository methods directly without schema validation, no default limit is applied.
|
|
343
|
+
|
|
344
|
+
### Pagination with Data Range
|
|
345
|
+
|
|
346
|
+
Use `shouldQueryRange` to get both data and total count in a single call:
|
|
234
347
|
|
|
235
348
|
```typescript
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
return {
|
|
250
|
-
data: users,
|
|
251
|
-
pagination: {
|
|
252
|
-
page,
|
|
253
|
-
pageSize,
|
|
254
|
-
total,
|
|
255
|
-
totalPages: Math.ceil(total / pageSize)
|
|
256
|
-
}
|
|
257
|
-
};
|
|
258
|
-
}
|
|
349
|
+
const result = await userRepo.find({
|
|
350
|
+
filter: {
|
|
351
|
+
where: { status: 'active' },
|
|
352
|
+
limit: 20,
|
|
353
|
+
skip: 40,
|
|
354
|
+
order: ['createdAt DESC']
|
|
355
|
+
},
|
|
356
|
+
options: { shouldQueryRange: true }
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
// Result type: { data: User[], range: { start: number, end: number, total: number } }
|
|
360
|
+
// range follows HTTP Content-Range standard (inclusive end index)
|
|
361
|
+
// Example: { data: [...20 users], range: { start: 40, end: 59, total: 150 } }
|
|
259
362
|
```
|
|
260
363
|
|
|
364
|
+
This runs `find` and `count` in parallel via `Promise.all` for optimal performance.
|
|
365
|
+
|
|
261
366
|
### WeakMap Cache
|
|
262
367
|
|
|
263
368
|
The filter builder caches table column metadata, avoiding repeated reflection:
|
|
264
369
|
|
|
265
370
|
```typescript
|
|
266
371
|
// Internal optimization - automatic
|
|
267
|
-
// First query: getTableColumns(schema)
|
|
268
|
-
// Subsequent queries: retrieved from WeakMap
|
|
372
|
+
// First query: getTableColumns(schema) -> cached in WeakMap
|
|
373
|
+
// Subsequent queries: retrieved from WeakMap cache
|
|
269
374
|
```
|
|
270
375
|
|
|
271
376
|
|
|
@@ -281,8 +386,7 @@ const result1 = await repo.create({
|
|
|
281
386
|
data: { name: 'John' },
|
|
282
387
|
options: { shouldReturn: false }
|
|
283
388
|
});
|
|
284
|
-
// Type: Promise<{ count: number; data: null }>
|
|
285
|
-
console.log(result1.data); // null
|
|
389
|
+
// Type: Promise<{ count: number; data: undefined | null }>
|
|
286
390
|
|
|
287
391
|
// shouldReturn: true (default) - TypeScript knows data is the entity
|
|
288
392
|
const result2 = await repo.create({
|
|
@@ -327,7 +431,7 @@ if (user) {
|
|
|
327
431
|
**Supported Methods:**
|
|
328
432
|
- `find<R>()`, `findOne<R>()`, `findById<R>()`
|
|
329
433
|
- `create<R>()`, `createAll<R>()`
|
|
330
|
-
- `updateById<R>()`, `updateAll<R>()`
|
|
434
|
+
- `updateById<R>()`, `updateAll<R>()`, `updateBy<R>()`
|
|
331
435
|
- `deleteById<R>()`, `deleteAll<R>()`, `deleteBy<R>()`
|
|
332
436
|
|
|
333
437
|
|
|
@@ -355,7 +459,7 @@ await repo.updateById({
|
|
|
355
459
|
});
|
|
356
460
|
```
|
|
357
461
|
|
|
358
|
-
**Available on:** `create`, `createAll`, `updateById`, `updateAll`, `deleteById`, `deleteAll`, `deleteBy`
|
|
462
|
+
**Available on:** `create`, `createAll`, `updateById`, `updateAll`, `updateBy`, `deleteById`, `deleteAll`, `deleteBy` (all write operations that go through `_create`, `_update`, or `_delete` internal methods)
|
|
359
463
|
|
|
360
464
|
### Query Interface Validation
|
|
361
465
|
|
|
@@ -377,10 +481,10 @@ The repository validates schema registration on startup:
|
|
|
377
481
|
Prevents accidental mass updates/deletes:
|
|
378
482
|
|
|
379
483
|
```typescript
|
|
380
|
-
//
|
|
484
|
+
// Throws error - empty where without force
|
|
381
485
|
await repo.deleteAll({ where: {} });
|
|
382
486
|
|
|
383
|
-
//
|
|
487
|
+
// Explicit force flag - logs warning, proceeds
|
|
384
488
|
await repo.deleteAll({
|
|
385
489
|
where: {},
|
|
386
490
|
options: { force: true }
|
|
@@ -393,29 +497,16 @@ await repo.deleteAll({
|
|
|
393
497
|
| Empty `where` | Throws error | Logs warning, proceeds |
|
|
394
498
|
| Valid `where` | Executes normally | Executes normally |
|
|
395
499
|
|
|
396
|
-
|
|
500
|
+
> [!NOTE]
|
|
501
|
+
> This protection applies to `updateAll`, `updateBy`, `deleteAll`, and `deleteBy`. The `updateById` and `deleteById` methods always have a non-empty where (`{ id }`) so they are not affected.
|
|
397
502
|
|
|
398
|
-
|
|
503
|
+
### Transaction Safety
|
|
399
504
|
|
|
400
|
-
|
|
401
|
-
// ❌ Error: First parameter must extend AbstractDataSource
|
|
402
|
-
@repository({ model: User, dataSource: PostgresDataSource })
|
|
403
|
-
export class UserRepository extends DefaultCRUDRepository<typeof User.schema> {
|
|
404
|
-
constructor(dataSource: any) { // 'any' not allowed!
|
|
405
|
-
super(dataSource);
|
|
406
|
-
}
|
|
407
|
-
}
|
|
505
|
+
The `resolveConnector` method validates transaction state before use:
|
|
408
506
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
constructor(
|
|
413
|
-
@inject({ key: 'datasources.PostgresDataSource' })
|
|
414
|
-
dataSource: PostgresDataSource,
|
|
415
|
-
) {
|
|
416
|
-
super(dataSource);
|
|
417
|
-
}
|
|
418
|
-
}
|
|
507
|
+
```typescript
|
|
508
|
+
// If a transaction has already been committed or rolled back:
|
|
509
|
+
// Error: [UserRepository][resolveConnector] Transaction is no longer active
|
|
419
510
|
```
|
|
420
511
|
|
|
421
512
|
|
|
@@ -444,12 +535,13 @@ const results = await connector
|
|
|
444
535
|
|
|
445
536
|
## Repository Class Hierarchy
|
|
446
537
|
|
|
447
|
-
| Class | Description |
|
|
448
|
-
|
|
449
|
-
| `AbstractRepository` |
|
|
450
|
-
| `ReadableRepository` | Read-only operations (find
|
|
451
|
-
| `PersistableRepository` | Adds write operations (create
|
|
452
|
-
| `DefaultCRUDRepository` |
|
|
538
|
+
| Class | Scope | Description |
|
|
539
|
+
|-------|-------|-------------|
|
|
540
|
+
| `AbstractRepository` | N/A | Abstract base class, defines all method signatures, combines `FieldsVisibilityMixin` + `DefaultFilterMixin` |
|
|
541
|
+
| `ReadableRepository` | `READ_ONLY` | Read-only operations (`find`, `findOne`, `findById`, `count`, `existsWith`). Write operations throw errors. |
|
|
542
|
+
| `PersistableRepository` | `READ_WRITE` | Adds write operations (`create`, `update`, `delete`) with `UpdateBuilder` |
|
|
543
|
+
| `DefaultCRUDRepository` | `READ_WRITE` | Extends `PersistableRepository` with no additional logic - **recommended default** |
|
|
544
|
+
| `SoftDeletableRepository` | `READ_WRITE` | Extends `DefaultCRUDRepository` with soft delete + restore operations |
|
|
453
545
|
|
|
454
546
|
### Creating a Read-Only Repository
|
|
455
547
|
|
|
@@ -461,6 +553,15 @@ export class AuditLogRepository extends ReadableRepository<typeof AuditLog.schem
|
|
|
461
553
|
}
|
|
462
554
|
```
|
|
463
555
|
|
|
556
|
+
### Alias Methods
|
|
557
|
+
|
|
558
|
+
`AbstractRepository` provides two alias methods for convenience:
|
|
559
|
+
|
|
560
|
+
- `updateBy(opts)` - Alias for `updateAll(opts)`. Delegates directly.
|
|
561
|
+
- `deleteBy(opts)` - Alias for `deleteAll(opts)`. Delegates directly.
|
|
562
|
+
|
|
563
|
+
Both accept the same parameters (`where`, `data`/`options`) and support `shouldReturn` and `force` options.
|
|
564
|
+
|
|
464
565
|
|
|
465
566
|
## Default Filter Bypass
|
|
466
567
|
|
|
@@ -515,7 +616,7 @@ await tx.commit();
|
|
|
515
616
|
|
|
516
617
|
## Nested JSON Updates
|
|
517
618
|
|
|
518
|
-
Repositories support updating specific fields within `json` or `jsonb` columns without overwriting the entire object. This is achieved using **JSON Path Notation** in the update data
|
|
619
|
+
Repositories support updating specific fields within `json` or `jsonb` columns without overwriting the entire object. This is achieved using **JSON Path Notation** in the update data via the `UpdateBuilder`.
|
|
519
620
|
|
|
520
621
|
### Basic Usage
|
|
521
622
|
|
|
@@ -540,9 +641,10 @@ await repo.updateById({
|
|
|
540
641
|
|
|
541
642
|
- **Deep Nesting:** Update properties at any depth (e.g., `settings.display.font.size`).
|
|
542
643
|
- **Array Access:** Update array elements by index (e.g., `tags[0]`).
|
|
543
|
-
- **Auto-Creation:** Creates missing intermediate keys automatically.
|
|
544
|
-
- **Type Safety:** Validates that the target column is a JSON type.
|
|
545
|
-
- **Multiple Updates:**
|
|
644
|
+
- **Auto-Creation:** Creates missing intermediate keys automatically (`jsonb_set` with `create_missing = true`).
|
|
645
|
+
- **Type Safety:** Validates that the target column is a JSON/JSONB type.
|
|
646
|
+
- **Multiple Updates:** Multiple updates to the same column are chained as nested `jsonb_set` calls.
|
|
647
|
+
- **Mixed Updates:** Combine regular column updates with JSON path updates in a single call.
|
|
546
648
|
|
|
547
649
|
### Examples
|
|
548
650
|
|
|
@@ -580,7 +682,7 @@ await repo.updateById({
|
|
|
580
682
|
data: {
|
|
581
683
|
status: 'active', // Regular column
|
|
582
684
|
'metadata.lastLogin': now, // JSON path
|
|
583
|
-
'preferences.lang': 'en'
|
|
685
|
+
'preferences.lang': 'en' // Another JSON path
|
|
584
686
|
}
|
|
585
687
|
});
|
|
586
688
|
```
|
|
@@ -588,14 +690,34 @@ await repo.updateById({
|
|
|
588
690
|
### Security & Validation
|
|
589
691
|
|
|
590
692
|
The framework validates JSON paths to prevent SQL injection:
|
|
591
|
-
- **Allowed Characters:**
|
|
592
|
-
- **Validation:**
|
|
593
|
-
- **Values:** Values are
|
|
693
|
+
- **Allowed Characters:** Path components must match `/^[a-zA-Z_][a-zA-Z0-9_-]*$|^\d+$/` (identifiers, kebab-case, or array indices).
|
|
694
|
+
- **Column Type Validation:** Only `json` and `jsonb` columns are allowed. Other column types throw an error.
|
|
695
|
+
- **Values:** Values are serialized to JSONB literals with proper escaping.
|
|
594
696
|
|
|
595
697
|
> [!NOTE]
|
|
596
698
|
> This feature uses PostgreSQL's `jsonb_set` function. It is only available for columns defined as `json` or `jsonb`.
|
|
597
699
|
|
|
598
700
|
|
|
701
|
+
## ExtraOptions Reference
|
|
702
|
+
|
|
703
|
+
All repository operations accept an `options` parameter with these fields:
|
|
704
|
+
|
|
705
|
+
| Option | Type | Default | Description |
|
|
706
|
+
|--------|------|---------|-------------|
|
|
707
|
+
| `transaction` | `ITransaction` | - | Transaction context for the operation |
|
|
708
|
+
| `log` | `{ use: boolean; level?: TLogLevel }` | - | Enable operation logging |
|
|
709
|
+
| `shouldSkipDefaultFilter` | `boolean` | `false` | Bypass the default filter from model settings |
|
|
710
|
+
| `lock` | `TLockOptions` | - | Row-level locking (requires transaction, Core API only) |
|
|
711
|
+
|
|
712
|
+
Write operations additionally support:
|
|
713
|
+
|
|
714
|
+
| Option | Type | Default | Description |
|
|
715
|
+
|--------|------|---------|-------------|
|
|
716
|
+
| `shouldReturn` | `boolean` | `true` | Return the created/updated/deleted data |
|
|
717
|
+
| `force` | `boolean` | `false` | Allow empty `where` condition on bulk operations |
|
|
718
|
+
| `shouldQueryRange` | `boolean` | `false` | Return `{ data, range }` with total count (find only) |
|
|
719
|
+
|
|
720
|
+
|
|
599
721
|
## Quick Reference
|
|
600
722
|
|
|
601
723
|
| Feature | Code |
|
|
@@ -605,9 +727,12 @@ The framework validates JSON paths to prevent SQL injection:
|
|
|
605
727
|
| Commit | `await tx.commit()` |
|
|
606
728
|
| Rollback | `await tx.rollback()` |
|
|
607
729
|
| Bypass default filter | `options: { shouldSkipDefaultFilter: true }` |
|
|
730
|
+
| Lock rows for update | `options: { transaction: tx, lock: { strength: 'update' } }` |
|
|
731
|
+
| Lock + skip locked | `options: { transaction: tx, lock: { strength: 'update', config: { skipLocked: true } } }` |
|
|
608
732
|
| Enable logging | `options: { log: { use: true, level: 'debug' } }` |
|
|
609
733
|
| Force delete all | `options: { force: true }` |
|
|
610
734
|
| Skip returning data | `options: { shouldReturn: false }` |
|
|
735
|
+
| Get data + count | `options: { shouldQueryRange: true }` |
|
|
611
736
|
| Access connector | `repo.getConnector()` |
|
|
612
737
|
|
|
613
738
|
|
|
@@ -618,6 +743,7 @@ The framework validates JSON paths to prevent SQL injection:
|
|
|
618
743
|
- [Default Filter](../filter-system/default-filter.md) - Automatic filter configuration
|
|
619
744
|
- [Repository Mixins](./mixins.md) - Composable features
|
|
620
745
|
- [Relations & Includes](./relations.md) - Eager loading
|
|
746
|
+
- [Soft-Deletable Repository](./soft-deletable.md) - Soft delete operations
|
|
621
747
|
- [JSON Path Filtering](../filter-system/json-filtering) - JSONB queries
|
|
622
748
|
- [Array Operators](../filter-system/array-operators) - PostgreSQL arrays
|
|
623
749
|
|
|
@@ -629,7 +755,7 @@ The framework validates JSON paths to prevent SQL injection:
|
|
|
629
755
|
- [DataSources](/guides/core-concepts/persistent/datasources) - Database connections
|
|
630
756
|
|
|
631
757
|
- **Related Topics:**
|
|
632
|
-
- [Repository Mixins](./mixins) -
|
|
758
|
+
- [Repository Mixins](./mixins) - Composable mixin features
|
|
633
759
|
- [Relations & Includes](./relations) - Loading related data
|
|
634
760
|
- [Filter System](/references/base/filter-system/) - Query operators
|
|
635
761
|
|