@venizia/ignis-docs 0.0.8-3 → 0.1.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/README.md +7 -7
- package/{wiki → content}/best-practices/api-usage-examples.md +15 -12
- package/{wiki → content}/best-practices/architectural-patterns.md +70 -78
- package/{wiki → content}/best-practices/architecture-decisions.md +91 -60
- package/{wiki → content}/best-practices/code-style-standards/advanced-patterns.md +56 -44
- package/{wiki → content}/best-practices/code-style-standards/constants-configuration.md +11 -11
- package/{wiki → content}/best-practices/code-style-standards/control-flow.md +5 -2
- package/{wiki → content}/best-practices/code-style-standards/documentation.md +13 -13
- package/{wiki → content}/best-practices/code-style-standards/function-patterns.md +9 -10
- package/{wiki → content}/best-practices/code-style-standards/index.md +1 -1
- package/{wiki → content}/best-practices/code-style-standards/naming-conventions.md +10 -8
- package/{wiki → content}/best-practices/code-style-standards/route-definitions.md +30 -12
- package/{wiki → content}/best-practices/code-style-standards/tooling.md +8 -5
- package/{wiki → content}/best-practices/code-style-standards/type-safety.md +13 -12
- package/{wiki → content}/best-practices/common-pitfalls.md +56 -37
- package/{wiki → content}/best-practices/contribution-workflow.md +13 -14
- package/{wiki → content}/best-practices/data-modeling.md +44 -20
- package/{wiki → content}/best-practices/deployment-strategies.md +28 -27
- package/{wiki → content}/best-practices/error-handling.md +48 -24
- package/{wiki → content}/best-practices/index.md +5 -5
- package/{wiki → content}/best-practices/performance-optimization.md +36 -28
- package/{wiki → content}/best-practices/security-guidelines.md +52 -23
- package/{wiki → content}/best-practices/testing-strategies.md +65 -51
- package/{wiki → content}/best-practices/troubleshooting-tips.md +24 -24
- package/{wiki/extensions/components/swagger.md → content/extensions/components/api-reference.md} +40 -31
- package/{wiki → content}/extensions/components/authentication/api.md +19 -19
- package/{wiki → content}/extensions/components/authentication/errors.md +7 -7
- package/{wiki → content}/extensions/components/authentication/index.md +10 -8
- package/{wiki → content}/extensions/components/authentication/usage.md +101 -6
- package/{wiki → content}/extensions/components/authorization/api.md +45 -25
- package/{wiki → content}/extensions/components/authorization/errors.md +6 -6
- package/{wiki → content}/extensions/components/authorization/index.md +11 -10
- package/{wiki → content}/extensions/components/authorization/usage.md +21 -21
- package/{wiki → content}/extensions/components/health-check.md +1 -1
- package/{wiki → content}/extensions/components/index.md +5 -5
- package/{wiki → content}/extensions/components/mail/errors.md +15 -15
- package/{wiki → content}/extensions/components/mail/index.md +1 -2
- package/{wiki → content}/extensions/components/mail/usage.md +1 -1
- package/{wiki → content}/extensions/components/request-tracker.md +1 -1
- package/{wiki → content}/extensions/components/socket-io/api.md +9 -9
- package/{wiki → content}/extensions/components/socket-io/errors.md +5 -5
- package/{wiki → content}/extensions/components/socket-io/index.md +8 -8
- package/{wiki → content}/extensions/components/socket-io/usage.md +1 -1
- package/{wiki → content}/extensions/components/static-asset/api.md +17 -4
- package/{wiki → content}/extensions/components/static-asset/errors.md +4 -4
- package/{wiki → content}/extensions/components/static-asset/index.md +26 -28
- package/{wiki → content}/extensions/components/static-asset/usage.md +13 -12
- package/{wiki → content}/extensions/components/template/index.md +2 -2
- package/{wiki → content}/extensions/components/template/setup-page.md +1 -1
- package/{wiki → content}/extensions/components/websocket/api.md +3 -3
- package/{wiki → content}/extensions/components/websocket/errors.md +5 -5
- package/{wiki → content}/extensions/components/websocket/index.md +5 -5
- package/{wiki → content}/extensions/components/websocket/usage.md +3 -3
- package/{wiki → content}/extensions/helpers/cron/index.md +2 -2
- package/{wiki → content}/extensions/helpers/crypto/index.md +1 -1
- package/{wiki → content}/extensions/helpers/env/index.md +27 -12
- package/content/extensions/helpers/error/index.md +283 -0
- package/{wiki → content}/extensions/helpers/index.md +2 -3
- package/{wiki → content}/extensions/helpers/inversion/index.md +15 -7
- package/{wiki → content}/extensions/helpers/kafka/examples.md +1 -1
- package/{wiki → content}/extensions/helpers/logger/index.md +32 -2
- package/{wiki → content}/extensions/helpers/network/index.md +6 -0
- package/{wiki → content}/extensions/helpers/queue/index.md +14 -17
- package/content/extensions/helpers/redis/index.md +713 -0
- package/{wiki → content}/extensions/helpers/socket-io/index.md +14 -10
- package/{wiki → content}/extensions/helpers/storage/api.md +44 -8
- package/{wiki → content}/extensions/helpers/storage/index.md +43 -7
- package/{wiki → content}/extensions/helpers/template/index.md +6 -3
- package/{wiki → content}/extensions/helpers/types/index.md +11 -8
- package/{wiki → content}/extensions/helpers/websocket/api.md +9 -9
- package/{wiki → content}/extensions/helpers/websocket/index.md +7 -7
- package/{wiki → content}/extensions/helpers/worker-thread/index.md +2 -2
- package/{wiki → content}/extensions/index.md +3 -4
- package/{wiki → content}/extensions/src-details/mcp-server.md +18 -24
- package/{wiki → content}/guides/core-concepts/application/bootstrapping.md +11 -14
- package/{wiki → content}/guides/core-concepts/application/index.md +3 -3
- package/{wiki → content}/guides/core-concepts/components.md +19 -10
- package/{wiki → content}/guides/core-concepts/dependency-injection.md +6 -3
- package/{wiki → content}/guides/core-concepts/grpc-controllers.md +6 -5
- package/{wiki → content}/guides/core-concepts/persistent/datasources.md +33 -27
- package/{wiki → content}/guides/core-concepts/persistent/index.md +16 -5
- package/{wiki → content}/guides/core-concepts/persistent/models.md +24 -20
- package/content/guides/core-concepts/persistent/postgres-drivers.md +167 -0
- package/{wiki → content}/guides/core-concepts/persistent/repositories.md +40 -23
- package/content/guides/core-concepts/persistent/search-meilisearch.md +183 -0
- package/content/guides/core-concepts/persistent/search-typesense.md +429 -0
- package/{wiki → content}/guides/core-concepts/persistent/transactions.md +61 -25
- package/{wiki → content}/guides/core-concepts/rest-controllers.md +12 -9
- package/content/guides/core-concepts/services.md +389 -0
- package/{wiki → content}/guides/get-started/5-minute-quickstart.md +19 -19
- package/{wiki → content}/guides/get-started/philosophy.md +36 -36
- package/{wiki → content}/guides/get-started/setup.md +3 -3
- package/{wiki → content}/guides/index.md +3 -3
- package/content/guides/migrations/redis-helpers-migration.md +177 -0
- package/{wiki → content}/guides/migrations/scoped-rbac-migration.md +17 -17
- package/content/guides/migrations/unified-connectors-migration.md +113 -0
- package/{wiki → content}/guides/reference/glossary.md +19 -12
- package/{wiki → content}/guides/reference/mcp-docs-server.md +22 -18
- package/{wiki → content}/guides/tutorials/building-a-crud-api.md +30 -33
- package/{wiki → content}/guides/tutorials/complete-installation.md +17 -17
- package/{wiki → content}/guides/tutorials/ecommerce-api.md +158 -119
- package/{wiki → content}/guides/tutorials/realtime-chat.md +176 -130
- package/content/guides/tutorials/testing.md +264 -0
- package/content/index.md +5 -0
- package/content/public/apple-touch-icon.png +0 -0
- package/content/public/og-image.png +0 -0
- package/content/public/site.webmanifest +11 -0
- package/{wiki → content}/references/base/application.md +4 -5
- package/{wiki → content}/references/base/bootstrapping.md +18 -5
- package/{wiki → content}/references/base/components.md +149 -120
- package/content/references/base/connectors.md +178 -0
- package/{wiki → content}/references/base/controllers.md +41 -30
- package/content/references/base/datasources.md +527 -0
- package/{wiki → content}/references/base/dependency-injection.md +34 -22
- package/{wiki → content}/references/base/filter-system/application-usage.md +17 -14
- package/{wiki → content}/references/base/filter-system/array-operators.md +7 -2
- package/{wiki → content}/references/base/filter-system/comparison-operators.md +3 -0
- package/{wiki → content}/references/base/filter-system/default-filter.md +89 -71
- package/{wiki → content}/references/base/filter-system/fields-order-pagination.md +22 -22
- package/{wiki → content}/references/base/filter-system/index.md +6 -3
- package/{wiki → content}/references/base/filter-system/json-filtering.md +20 -1
- package/{wiki → content}/references/base/filter-system/list-operators.md +1 -1
- package/{wiki → content}/references/base/filter-system/logical-operators.md +33 -1
- package/{wiki → content}/references/base/filter-system/null-operators.md +30 -1
- package/{wiki → content}/references/base/filter-system/quick-reference.md +23 -4
- package/{wiki → content}/references/base/filter-system/tips.md +5 -5
- package/{wiki → content}/references/base/filter-system/use-cases.md +12 -12
- package/{wiki → content}/references/base/grpc-controllers.md +13 -13
- package/{wiki → content}/references/base/index.md +24 -12
- package/{wiki/references/base/middleware.md → content/references/base/middlewares.md} +205 -24
- package/{wiki → content}/references/base/models.md +63 -49
- package/{wiki → content}/references/base/providers.md +136 -130
- package/{wiki → content}/references/base/repositories/advanced.md +59 -58
- package/{wiki → content}/references/base/repositories/index.md +115 -91
- package/content/references/base/repositories/mixins.md +99 -0
- package/{wiki → content}/references/base/repositories/relations.md +54 -64
- package/{wiki → content}/references/base/repositories/soft-deletable.md +31 -30
- package/content/references/base/services.md +404 -0
- package/{wiki → content}/references/configuration/environment-variables.md +46 -30
- package/{wiki → content}/references/configuration/index.md +6 -6
- package/{wiki → content}/references/index.md +17 -12
- package/{wiki → content}/references/quick-reference.md +65 -106
- package/content/references/utilities/crypto.md +98 -0
- package/{wiki → content}/references/utilities/index.md +3 -3
- package/{wiki → content}/references/utilities/jsx.md +6 -4
- package/content/references/utilities/module.md +90 -0
- package/{wiki → content}/references/utilities/parse.md +4 -14
- package/{wiki → content}/references/utilities/promise.md +9 -7
- package/{wiki → content}/references/utilities/schema.md +5 -3
- package/dist/mcp-server/common/guards.d.ts +8 -0
- package/dist/mcp-server/common/guards.d.ts.map +1 -0
- package/dist/mcp-server/common/guards.js +14 -0
- package/dist/mcp-server/common/guards.js.map +1 -0
- package/dist/mcp-server/common/index.d.ts +1 -0
- package/dist/mcp-server/common/index.d.ts.map +1 -1
- package/dist/mcp-server/common/index.js +1 -0
- package/dist/mcp-server/common/index.js.map +1 -1
- package/dist/mcp-server/common/paths.d.ts.map +1 -1
- package/dist/mcp-server/common/paths.js +2 -2
- 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 +4 -2
- package/dist/mcp-server/helpers/docs.helper.js.map +1 -1
- package/dist/mcp-server/helpers/github.helper.js +1 -1
- package/dist/mcp-server/index.js +7 -2
- package/dist/mcp-server/index.js.map +1 -1
- package/dist/mcp-server/tools/base.tool.d.ts +6 -2
- package/dist/mcp-server/tools/base.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/base.tool.js.map +1 -1
- package/dist/mcp-server/tools/docs/search-documents.tool.d.ts +1 -1
- package/dist/mcp-server/tools/github/list-project-files.tool.d.ts +1 -1
- package/dist/mcp-server/tools/github/search-code.tool.d.ts +1 -1
- package/dist/mcp-server/tools/github/search-code.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/github/search-code.tool.js +4 -1
- package/dist/mcp-server/tools/github/search-code.tool.js.map +1 -1
- package/dist/mcp-server/tools/github/verify-dependencies.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/github/verify-dependencies.tool.js +3 -1
- package/dist/mcp-server/tools/github/verify-dependencies.tool.js.map +1 -1
- package/package.json +12 -12
- package/wiki/extensions/helpers/error/index.md +0 -227
- package/wiki/extensions/helpers/redis/index.md +0 -488
- package/wiki/extensions/helpers/testing/index.md +0 -510
- package/wiki/guides/core-concepts/services.md +0 -119
- package/wiki/guides/tutorials/testing.md +0 -722
- package/wiki/index.md +0 -183
- package/wiki/references/base/datasources.md +0 -454
- package/wiki/references/base/middlewares.md +0 -590
- package/wiki/references/base/repositories/mixins.md +0 -335
- package/wiki/references/base/services.md +0 -201
- package/wiki/references/utilities/crypto.md +0 -56
- package/wiki/references/utilities/module.md +0 -42
- /package/{wiki → content}/extensions/components/mail/api.md +0 -0
- /package/{wiki → content}/extensions/components/template/api-page.md +0 -0
- /package/{wiki → content}/extensions/components/template/errors-page.md +0 -0
- /package/{wiki → content}/extensions/components/template/single-page.md +0 -0
- /package/{wiki → content}/extensions/components/template/usage-page.md +0 -0
- /package/{wiki → content}/extensions/helpers/kafka/admin.md +0 -0
- /package/{wiki → content}/extensions/helpers/kafka/consumer.md +0 -0
- /package/{wiki → content}/extensions/helpers/kafka/index.md +0 -0
- /package/{wiki → content}/extensions/helpers/kafka/producer.md +0 -0
- /package/{wiki → content}/extensions/helpers/kafka/schema-registry.md +0 -0
- /package/{wiki → content}/extensions/helpers/network/api.md +0 -0
- /package/{wiki → content}/extensions/helpers/socket-io/api.md +0 -0
- /package/{wiki → content}/extensions/helpers/template/single-page.md +0 -0
- /package/{wiki → content}/extensions/helpers/uid/index.md +0 -0
- /package/{wiki → content}/guides/core-concepts/components-guide.md +0 -0
- /package/{wiki → content}/public/logo.svg +0 -0
- /package/{wiki → content}/references/base/filter-system/pattern-matching.md +0 -0
- /package/{wiki → content}/references/base/filter-system/range-operators.md +0 -0
- /package/{wiki → content}/references/utilities/date.md +0 -0
- /package/{wiki → content}/references/utilities/performance.md +0 -0
- /package/{wiki → content}/references/utilities/request.md +0 -0
- /package/{wiki → content}/references/utilities/statuses.md +0 -0
|
@@ -9,7 +9,7 @@ Fetch related data using `include` for eager loading. This guide covers one-to-o
|
|
|
9
9
|
|
|
10
10
|
```typescript
|
|
11
11
|
// Fetch user with their posts
|
|
12
|
-
const user = await
|
|
12
|
+
const user = await userRepository.findOne({
|
|
13
13
|
filter: {
|
|
14
14
|
where: { id: '123' },
|
|
15
15
|
include: [{ relation: 'posts' }]
|
|
@@ -31,7 +31,7 @@ const user = await userRepo.findOne({
|
|
|
31
31
|
|
|
32
32
|
```typescript
|
|
33
33
|
// Fetch post with its author
|
|
34
|
-
const post = await
|
|
34
|
+
const post = await postRepository.findOne({
|
|
35
35
|
filter: {
|
|
36
36
|
where: { id: 'p1' },
|
|
37
37
|
include: [{ relation: 'author' }]
|
|
@@ -51,7 +51,7 @@ const post = await postRepo.findOne({
|
|
|
51
51
|
|
|
52
52
|
```typescript
|
|
53
53
|
// Fetch post with author AND comments
|
|
54
|
-
const post = await
|
|
54
|
+
const post = await postRepository.findOne({
|
|
55
55
|
filter: {
|
|
56
56
|
where: { id: 'p1' },
|
|
57
57
|
include: [
|
|
@@ -74,7 +74,7 @@ Apply filters, ordering, and limits to included relations using `scope`:
|
|
|
74
74
|
|
|
75
75
|
```typescript
|
|
76
76
|
// User with only published posts
|
|
77
|
-
const user = await
|
|
77
|
+
const user = await userRepository.findOne({
|
|
78
78
|
filter: {
|
|
79
79
|
where: { id: '123' },
|
|
80
80
|
include: [{
|
|
@@ -91,7 +91,7 @@ const user = await userRepo.findOne({
|
|
|
91
91
|
|
|
92
92
|
```typescript
|
|
93
93
|
// User with posts ordered by date
|
|
94
|
-
const user = await
|
|
94
|
+
const user = await userRepository.findOne({
|
|
95
95
|
filter: {
|
|
96
96
|
where: { id: '123' },
|
|
97
97
|
include: [{
|
|
@@ -108,7 +108,7 @@ const user = await userRepo.findOne({
|
|
|
108
108
|
|
|
109
109
|
```typescript
|
|
110
110
|
// User with their 5 most recent posts
|
|
111
|
-
const user = await
|
|
111
|
+
const user = await userRepository.findOne({
|
|
112
112
|
filter: {
|
|
113
113
|
where: { id: '123' },
|
|
114
114
|
include: [{
|
|
@@ -125,7 +125,7 @@ const user = await userRepo.findOne({
|
|
|
125
125
|
### Combined Scope Options
|
|
126
126
|
|
|
127
127
|
```typescript
|
|
128
|
-
const user = await
|
|
128
|
+
const user = await userRepository.findOne({
|
|
129
129
|
filter: {
|
|
130
130
|
where: { id: '123' },
|
|
131
131
|
include: [{
|
|
@@ -147,7 +147,7 @@ Each inclusion can independently bypass the related model's default filter:
|
|
|
147
147
|
|
|
148
148
|
```typescript
|
|
149
149
|
// Include soft-deleted posts that would normally be filtered out
|
|
150
|
-
const user = await
|
|
150
|
+
const user = await userRepository.findOne({
|
|
151
151
|
filter: {
|
|
152
152
|
where: { id: '123' },
|
|
153
153
|
include: [{
|
|
@@ -167,7 +167,7 @@ Include relations of relations (up to 2 levels recommended):
|
|
|
167
167
|
|
|
168
168
|
```typescript
|
|
169
169
|
// User -> Posts -> Comments
|
|
170
|
-
const user = await
|
|
170
|
+
const user = await userRepository.findOne({
|
|
171
171
|
filter: {
|
|
172
172
|
where: { id: '123' },
|
|
173
173
|
include: [{
|
|
@@ -200,7 +200,7 @@ const user = await userRepo.findOne({
|
|
|
200
200
|
|
|
201
201
|
```typescript
|
|
202
202
|
// Product -> SaleChannelProduct (junction) -> SaleChannel
|
|
203
|
-
const product = await
|
|
203
|
+
const product = await productRepository.findOne({
|
|
204
204
|
filter: {
|
|
205
205
|
where: { id: 'prod1' },
|
|
206
206
|
include: [{
|
|
@@ -236,7 +236,7 @@ const product = await productRepo.findOne({
|
|
|
236
236
|
|
|
237
237
|
## Defining Relations
|
|
238
238
|
|
|
239
|
-
Relations are
|
|
239
|
+
Relations are declared on the model as a static `relations` resolver returning an array of `TRelationConfig`. The framework translates them to Drizzle ORM relations internally during schema discovery.
|
|
240
240
|
|
|
241
241
|
### Relation Config Type
|
|
242
242
|
|
|
@@ -261,34 +261,32 @@ type TRelationConfig = {
|
|
|
261
261
|
|
|
262
262
|
```typescript
|
|
263
263
|
// src/models/user.model.ts
|
|
264
|
-
import {
|
|
264
|
+
import { model, RelationTypes } from '@venizia/ignis';
|
|
265
|
+
import { BasePostgresEntity, TRelationConfig } from '@venizia/ignis/postgres';
|
|
266
|
+
import { pgTable, text } from 'drizzle-orm/pg-core';
|
|
267
|
+
import { Post } from './post.model';
|
|
265
268
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
269
|
+
@model({ type: 'entity' })
|
|
270
|
+
export class User extends BasePostgresEntity<typeof User.schema> {
|
|
271
|
+
static override schema = pgTable('User', {
|
|
272
|
+
id: text('id').primaryKey(),
|
|
273
|
+
name: text('name').notNull(),
|
|
274
|
+
email: text('email').notNull(),
|
|
275
|
+
});
|
|
271
276
|
|
|
272
|
-
|
|
273
|
-
source: userTable,
|
|
274
|
-
relations: [
|
|
277
|
+
static override relations = (): TRelationConfig[] => [
|
|
275
278
|
{
|
|
276
|
-
type: 'many',
|
|
277
|
-
schema: postTable,
|
|
278
279
|
name: 'posts',
|
|
280
|
+
type: RelationTypes.MANY,
|
|
281
|
+
schema: Post.schema,
|
|
279
282
|
metadata: { relationName: 'posts' },
|
|
280
283
|
},
|
|
281
|
-
]
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
@model({ type: 'entity' })
|
|
285
|
-
export class User extends BaseEntity<typeof User.schema> {
|
|
286
|
-
static override schema = userTable;
|
|
287
|
-
static override relations = () => userRelationsConfig.definitions;
|
|
288
|
-
static override TABLE_NAME = 'User';
|
|
284
|
+
];
|
|
289
285
|
}
|
|
290
286
|
```
|
|
291
287
|
|
|
288
|
+
The resolver form (`() => [...]`) defers evaluation until all `@model` classes are registered, avoiding circular-import ordering issues between related models.
|
|
289
|
+
|
|
292
290
|
### Relation Types
|
|
293
291
|
|
|
294
292
|
| Type | Drizzle Function | Description | Example |
|
|
@@ -297,46 +295,38 @@ export class User extends BaseEntity<typeof User.schema> {
|
|
|
297
295
|
| `'many'` | `many()` | One-to-many | User has many Posts |
|
|
298
296
|
|
|
299
297
|
> [!NOTE]
|
|
300
|
-
> Unlike LoopBack 4's `hasMany`/`hasOne`/`belongsTo` terminology,
|
|
298
|
+
> Unlike LoopBack 4's `hasMany`/`hasOne`/`belongsTo` terminology, IGNIS uses Drizzle ORM's relation model which has only `one` and `many` types. A "belongsTo" relationship is expressed as `type: 'one'` with `fields` (local FK) and `references` (remote PK) in the metadata.
|
|
301
299
|
|
|
302
300
|
### Example: Post Model with Both Types
|
|
303
301
|
|
|
304
302
|
```typescript
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
303
|
+
@model({ type: 'entity' })
|
|
304
|
+
export class Post extends BasePostgresEntity<typeof Post.schema> {
|
|
305
|
+
static override schema = postTable;
|
|
306
|
+
|
|
307
|
+
static override relations = (): TRelationConfig[] => [
|
|
308
308
|
{
|
|
309
|
-
type: 'one',
|
|
310
|
-
schema: userTable,
|
|
311
309
|
name: 'author',
|
|
310
|
+
type: RelationTypes.ONE,
|
|
311
|
+
schema: User.schema,
|
|
312
312
|
metadata: {
|
|
313
|
-
fields: [
|
|
314
|
-
references: [
|
|
313
|
+
fields: [Post.schema.authorId],
|
|
314
|
+
references: [User.schema.id],
|
|
315
315
|
},
|
|
316
316
|
},
|
|
317
317
|
{
|
|
318
|
-
type: 'many',
|
|
319
|
-
schema: commentTable,
|
|
320
318
|
name: 'comments',
|
|
319
|
+
type: RelationTypes.MANY,
|
|
320
|
+
schema: Comment.schema,
|
|
321
321
|
metadata: { relationName: 'comments' },
|
|
322
322
|
},
|
|
323
|
-
]
|
|
324
|
-
}
|
|
323
|
+
];
|
|
324
|
+
}
|
|
325
325
|
```
|
|
326
326
|
|
|
327
|
-
###
|
|
328
|
-
|
|
329
|
-
`createRelations` returns an object with two properties:
|
|
330
|
-
|
|
331
|
-
```typescript
|
|
332
|
-
const result = createRelations({ source, relations });
|
|
333
|
-
|
|
334
|
-
result.definitions; // Record<string, TRelationConfig> - keyed by relation name
|
|
335
|
-
result.relations; // Drizzle relations() call result - pass to DataSource schema
|
|
336
|
-
```
|
|
327
|
+
### How Configs Become Drizzle Relations
|
|
337
328
|
|
|
338
|
-
|
|
339
|
-
- **`relations`**: The actual Drizzle ORM relations definition, needed for DataSource schema registration.
|
|
329
|
+
During schema discovery, `MetadataRegistry` resolves each model's `relations` array and passes it to the `createRelations` helper (`packages/core/src/connectors/postgres/repositories/operators/relation.ts`), which builds the actual Drizzle `relations()` definition registered on the DataSource schema. You do not call `createRelations` yourself in application code.
|
|
340
330
|
|
|
341
331
|
|
|
342
332
|
## Auto-Resolution
|
|
@@ -362,7 +352,7 @@ When building include queries, the `FilterBuilder.toInclude()` method automatica
|
|
|
362
352
|
|
|
363
353
|
```typescript
|
|
364
354
|
// User model has hiddenProperties: ['password']
|
|
365
|
-
const post = await
|
|
355
|
+
const post = await postRepository.findOne({
|
|
366
356
|
filter: {
|
|
367
357
|
include: [{ relation: 'author' }]
|
|
368
358
|
}
|
|
@@ -383,7 +373,7 @@ type UserWithPosts = User & {
|
|
|
383
373
|
};
|
|
384
374
|
|
|
385
375
|
// Use generic override
|
|
386
|
-
const user = await
|
|
376
|
+
const user = await userRepository.findOne<UserWithPosts>({
|
|
387
377
|
filter: {
|
|
388
378
|
where: { id: '123' },
|
|
389
379
|
include: [{ relation: 'posts' }]
|
|
@@ -405,7 +395,7 @@ type ProductWithChannels = Product & {
|
|
|
405
395
|
})[];
|
|
406
396
|
};
|
|
407
397
|
|
|
408
|
-
const product = await
|
|
398
|
+
const product = await productRepository.findOne<ProductWithChannels>({
|
|
409
399
|
filter: {
|
|
410
400
|
where: { id: 'prod1' },
|
|
411
401
|
include: [{
|
|
@@ -441,7 +431,7 @@ type TInclusion = {
|
|
|
441
431
|
|
|
442
432
|
```typescript
|
|
443
433
|
// Get users with post count
|
|
444
|
-
const users = await
|
|
434
|
+
const users = await userRepository.find({
|
|
445
435
|
filter: {
|
|
446
436
|
include: [{
|
|
447
437
|
relation: 'posts',
|
|
@@ -465,7 +455,7 @@ async function getUser(id: string, includePosts: boolean) {
|
|
|
465
455
|
? [{ relation: 'posts' }]
|
|
466
456
|
: [];
|
|
467
457
|
|
|
468
|
-
return
|
|
458
|
+
return userRepository.findOne({
|
|
469
459
|
filter: {
|
|
470
460
|
where: { id },
|
|
471
461
|
include
|
|
@@ -483,7 +473,7 @@ If you try to include a relation that doesn't exist:
|
|
|
483
473
|
|
|
484
474
|
```typescript
|
|
485
475
|
// Error: [FilterBuilder][toInclude] Relation NOT FOUND | relation: 'nonExistent'
|
|
486
|
-
await
|
|
476
|
+
await userRepository.find({
|
|
487
477
|
filter: {
|
|
488
478
|
include: [{ relation: 'nonExistent' }]
|
|
489
479
|
}
|
|
@@ -520,14 +510,14 @@ in connector.query | Available keys: [Post, Comment]
|
|
|
520
510
|
|
|
521
511
|
```typescript
|
|
522
512
|
// Instead of deep nesting, use separate queries
|
|
523
|
-
const user = await
|
|
524
|
-
const posts = await
|
|
513
|
+
const user = await userRepository.findById({ id: '123' });
|
|
514
|
+
const posts = await postRepository.find({
|
|
525
515
|
filter: {
|
|
526
516
|
where: { authorId: '123' },
|
|
527
517
|
limit: 10
|
|
528
518
|
}
|
|
529
519
|
});
|
|
530
|
-
const comments = await
|
|
520
|
+
const comments = await commentRepository.find({
|
|
531
521
|
filter: {
|
|
532
522
|
where: { postId: { inq: posts.map(p => p.id) } }
|
|
533
523
|
}
|
|
@@ -563,7 +553,7 @@ const comments = await commentRepo.find({
|
|
|
563
553
|
|
|
564
554
|
- **Related Topics:**
|
|
565
555
|
- [Advanced Features](./advanced) - Hidden properties, transactions
|
|
566
|
-
- [Repository Mixins](./mixins) -
|
|
556
|
+
- [Repository Mixins (Removed)](./mixins) - Where default-filter and fields-visibility behavior lives now
|
|
567
557
|
- [Filter System](/references/base/filter-system/) - Query operators
|
|
568
558
|
|
|
569
559
|
- **External Resources:**
|
|
@@ -8,7 +8,7 @@ difficulty: intermediate
|
|
|
8
8
|
|
|
9
9
|
A repository that overrides delete operations to set a `deletedAt` timestamp instead of physically removing records. Extends `DefaultCRUDRepository` with restore capabilities.
|
|
10
10
|
|
|
11
|
-
**File:** `packages/core/src/
|
|
11
|
+
**File:** `packages/core/src/connectors/postgres/repositories/core/soft-deletable.ts` (PostgreSQL connector - soft delete via `deletedAt` is a Drizzle/SQL-specific pattern, not part of the engine-neutral `AbstractRepository`)
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
## Setup
|
|
@@ -70,17 +70,17 @@ All delete methods set `deletedAt = new Date()` instead of removing the row. The
|
|
|
70
70
|
|
|
71
71
|
```typescript
|
|
72
72
|
// Soft delete - sets deletedAt timestamp
|
|
73
|
-
const result = await
|
|
73
|
+
const result = await repository.deleteById({ id: '123' });
|
|
74
74
|
// { count: 1, data: { id: '123', name: 'Electronics', deletedAt: '2026-03-06T...' } }
|
|
75
75
|
|
|
76
76
|
// Without returning data
|
|
77
|
-
const result = await
|
|
77
|
+
const result = await repository.deleteById({
|
|
78
78
|
id: '123',
|
|
79
79
|
options: { shouldReturn: false },
|
|
80
80
|
});
|
|
81
81
|
|
|
82
82
|
// Hard delete - physically removes the row
|
|
83
|
-
const result = await
|
|
83
|
+
const result = await repository.deleteById({
|
|
84
84
|
id: '123',
|
|
85
85
|
options: { shouldHardDelete: true },
|
|
86
86
|
});
|
|
@@ -90,13 +90,13 @@ const result = await repo.deleteById({
|
|
|
90
90
|
|
|
91
91
|
```typescript
|
|
92
92
|
// Soft delete all matching records
|
|
93
|
-
const result = await
|
|
93
|
+
const result = await repository.deleteAll({
|
|
94
94
|
where: { status: 'archived' },
|
|
95
95
|
options: { force: true },
|
|
96
96
|
});
|
|
97
97
|
|
|
98
98
|
// Hard delete all matching records
|
|
99
|
-
const result = await
|
|
99
|
+
const result = await repository.deleteAll({
|
|
100
100
|
where: { status: 'archived' },
|
|
101
101
|
options: { shouldHardDelete: true, force: true },
|
|
102
102
|
});
|
|
@@ -106,12 +106,12 @@ const result = await repo.deleteAll({
|
|
|
106
106
|
|
|
107
107
|
```typescript
|
|
108
108
|
// Soft delete by where condition (alias for deleteAll)
|
|
109
|
-
const result = await
|
|
109
|
+
const result = await repository.deleteBy({
|
|
110
110
|
where: { name: 'Obsolete' },
|
|
111
111
|
});
|
|
112
112
|
|
|
113
113
|
// Hard delete by where condition
|
|
114
|
-
const result = await
|
|
114
|
+
const result = await repository.deleteBy({
|
|
115
115
|
where: { name: 'Obsolete' },
|
|
116
116
|
options: { shouldHardDelete: true },
|
|
117
117
|
});
|
|
@@ -125,11 +125,11 @@ Restore methods set `deletedAt = null` and automatically use `shouldSkipDefaultF
|
|
|
125
125
|
### restoreById
|
|
126
126
|
|
|
127
127
|
```typescript
|
|
128
|
-
const result = await
|
|
128
|
+
const result = await repository.restoreById({ id: '123' });
|
|
129
129
|
// { count: 1, data: { id: '123', name: 'Electronics', deletedAt: null } }
|
|
130
130
|
|
|
131
131
|
// Without returning data
|
|
132
|
-
const result = await
|
|
132
|
+
const result = await repository.restoreById({
|
|
133
133
|
id: '123',
|
|
134
134
|
options: { shouldReturn: false },
|
|
135
135
|
});
|
|
@@ -139,13 +139,13 @@ const result = await repo.restoreById({
|
|
|
139
139
|
|
|
140
140
|
```typescript
|
|
141
141
|
// Restore all soft-deleted records (requires force for empty where)
|
|
142
|
-
const result = await
|
|
142
|
+
const result = await repository.restoreAll({
|
|
143
143
|
where: {},
|
|
144
144
|
options: { force: true },
|
|
145
145
|
});
|
|
146
146
|
|
|
147
147
|
// Restore matching records
|
|
148
|
-
const result = await
|
|
148
|
+
const result = await repository.restoreAll({
|
|
149
149
|
where: { name: 'Electronics' },
|
|
150
150
|
});
|
|
151
151
|
```
|
|
@@ -154,7 +154,7 @@ const result = await repo.restoreAll({
|
|
|
154
154
|
|
|
155
155
|
```typescript
|
|
156
156
|
// Alias for restoreAll
|
|
157
|
-
const result = await
|
|
157
|
+
const result = await repository.restoreBy({
|
|
158
158
|
where: { status: 'archived' },
|
|
159
159
|
});
|
|
160
160
|
```
|
|
@@ -168,10 +168,10 @@ const result = await repo.restoreBy({
|
|
|
168
168
|
|
|
169
169
|
```typescript
|
|
170
170
|
// Returns null if not found (default)
|
|
171
|
-
const category = await
|
|
171
|
+
const category = await repository.findById({ id: '123' });
|
|
172
172
|
|
|
173
173
|
// Throws 404 if not found
|
|
174
|
-
const category = await
|
|
174
|
+
const category = await repository.findById({
|
|
175
175
|
id: '123',
|
|
176
176
|
options: { isStrict: true },
|
|
177
177
|
});
|
|
@@ -226,8 +226,8 @@ All other read operations (`find`, `findOne`, `count`, `existsWith`) work as nor
|
|
|
226
226
|
```typescript
|
|
227
227
|
const tx = await this.dataSource.beginTransaction();
|
|
228
228
|
try {
|
|
229
|
-
await this.
|
|
230
|
-
await this.
|
|
229
|
+
await this.categoryRepository.deleteById({ id: '123', options: { transaction: tx } });
|
|
230
|
+
await this.auditRepository.create({
|
|
231
231
|
data: { action: 'soft_delete', entityId: '123' },
|
|
232
232
|
options: { transaction: tx },
|
|
233
233
|
});
|
|
@@ -259,11 +259,12 @@ If your schema does not have a `deletedAt` column, you will get a TypeScript com
|
|
|
259
259
|
## Class Hierarchy
|
|
260
260
|
|
|
261
261
|
```
|
|
262
|
-
AbstractRepository
|
|
263
|
-
->
|
|
264
|
-
->
|
|
265
|
-
->
|
|
266
|
-
->
|
|
262
|
+
AbstractRepository (engine-neutral, src/base)
|
|
263
|
+
-> PostgresBaseRepository (connectors/postgres)
|
|
264
|
+
-> ReadableRepository
|
|
265
|
+
-> PersistableRepository
|
|
266
|
+
-> DefaultCRUDRepository
|
|
267
|
+
-> SoftDeletableRepository <-- you are here
|
|
267
268
|
```
|
|
268
269
|
|
|
269
270
|
|
|
@@ -271,19 +272,19 @@ AbstractRepository
|
|
|
271
272
|
|
|
272
273
|
| Want to... | Code |
|
|
273
274
|
|------------|------|
|
|
274
|
-
| Soft delete by ID | `
|
|
275
|
-
| Hard delete by ID | `
|
|
276
|
-
| Soft delete by condition | `
|
|
277
|
-
| Restore by ID | `
|
|
278
|
-
| Restore by condition | `
|
|
279
|
-
| Find including deleted | `
|
|
280
|
-
| Strict findById (404) | `
|
|
275
|
+
| Soft delete by ID | `repository.deleteById({ id })` |
|
|
276
|
+
| Hard delete by ID | `repository.deleteById({ id, options: { shouldHardDelete: true } })` |
|
|
277
|
+
| Soft delete by condition | `repository.deleteAll({ where, options: { force: true } })` |
|
|
278
|
+
| Restore by ID | `repository.restoreById({ id })` |
|
|
279
|
+
| Restore by condition | `repository.restoreAll({ where })` |
|
|
280
|
+
| Find including deleted | `repository.find({ filter, options: { shouldSkipDefaultFilter: true } })` |
|
|
281
|
+
| Strict findById (404) | `repository.findById({ id, options: { isStrict: true } })` |
|
|
281
282
|
|
|
282
283
|
|
|
283
284
|
## Next Steps
|
|
284
285
|
|
|
285
286
|
- [Advanced Features](./advanced.md) - Transactions, hidden properties
|
|
286
|
-
- [Repository Mixins](./mixins.md) -
|
|
287
|
+
- [Repository Mixins (Removed)](./mixins.md) - Where default-filter and fields-visibility behavior lives now
|
|
287
288
|
- [Repository Overview](./index.md) - Repository basics
|
|
288
289
|
|
|
289
290
|
## See Also
|