@venizia/ignis-docs 0.0.3 → 0.0.4-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/README.md +1 -1
- package/package.json +4 -2
- package/wiki/best-practices/api-usage-examples.md +591 -0
- package/wiki/best-practices/architectural-patterns.md +415 -0
- package/wiki/best-practices/architecture-decisions.md +488 -0
- package/wiki/{get-started/best-practices → best-practices}/code-style-standards.md +406 -17
- package/wiki/{get-started/best-practices → best-practices}/common-pitfalls.md +109 -4
- package/wiki/{get-started/best-practices → best-practices}/contribution-workflow.md +34 -7
- package/wiki/best-practices/data-modeling.md +376 -0
- package/wiki/best-practices/deployment-strategies.md +698 -0
- package/wiki/best-practices/index.md +27 -0
- package/wiki/best-practices/performance-optimization.md +196 -0
- package/wiki/best-practices/security-guidelines.md +218 -0
- package/wiki/{get-started/best-practices → best-practices}/troubleshooting-tips.md +97 -1
- package/wiki/changelogs/2025-12-16-initial-architecture.md +1 -1
- package/wiki/changelogs/2025-12-16-model-repo-datasource-refactor.md +1 -1
- package/wiki/changelogs/2025-12-17-refactor.md +1 -1
- package/wiki/changelogs/2025-12-18-performance-optimizations.md +5 -5
- package/wiki/changelogs/2025-12-18-repository-validation-security.md +13 -7
- package/wiki/changelogs/2025-12-26-nested-relations-and-generics.md +2 -2
- package/wiki/changelogs/2025-12-29-dynamic-binding-registration.md +104 -0
- package/wiki/changelogs/2025-12-29-snowflake-uid-helper.md +100 -0
- package/wiki/changelogs/2025-12-30-repository-enhancements.md +214 -0
- package/wiki/changelogs/2025-12-31-json-path-filtering-array-operators.md +214 -0
- package/wiki/changelogs/2025-12-31-string-id-custom-generator.md +137 -0
- package/wiki/changelogs/2026-01-02-default-filter-and-repository-mixins.md +418 -0
- package/wiki/changelogs/index.md +6 -0
- package/wiki/changelogs/planned-schema-migrator.md +0 -8
- package/wiki/{get-started/core-concepts → guides/core-concepts/application}/bootstrapping.md +18 -5
- package/wiki/{get-started/core-concepts/application.md → guides/core-concepts/application/index.md} +47 -104
- package/wiki/guides/core-concepts/components-guide.md +509 -0
- package/wiki/{get-started → guides}/core-concepts/components.md +24 -17
- package/wiki/{get-started → guides}/core-concepts/controllers.md +30 -13
- package/wiki/{get-started → guides}/core-concepts/dependency-injection.md +97 -0
- package/wiki/guides/core-concepts/persistent/datasources.md +179 -0
- package/wiki/guides/core-concepts/persistent/index.md +119 -0
- package/wiki/guides/core-concepts/persistent/models.md +241 -0
- package/wiki/guides/core-concepts/persistent/repositories.md +219 -0
- package/wiki/guides/core-concepts/persistent/transactions.md +170 -0
- package/wiki/{get-started → guides}/core-concepts/services.md +26 -3
- package/wiki/{get-started → guides/get-started}/5-minute-quickstart.md +59 -14
- package/wiki/guides/get-started/philosophy.md +682 -0
- package/wiki/guides/get-started/setup.md +157 -0
- package/wiki/guides/index.md +89 -0
- package/wiki/guides/reference/glossary.md +243 -0
- package/wiki/{get-started → guides/reference}/mcp-docs-server.md +0 -10
- package/wiki/{get-started → guides/tutorials}/building-a-crud-api.md +134 -132
- package/wiki/{get-started/quickstart.md → guides/tutorials/complete-installation.md} +107 -71
- package/wiki/guides/tutorials/ecommerce-api.md +1399 -0
- package/wiki/guides/tutorials/realtime-chat.md +1261 -0
- package/wiki/guides/tutorials/testing.md +723 -0
- package/wiki/index.md +176 -37
- package/wiki/references/base/application.md +27 -0
- package/wiki/references/base/bootstrapping.md +31 -26
- package/wiki/references/base/components.md +24 -7
- package/wiki/references/base/controllers.md +50 -20
- package/wiki/references/base/datasources.md +30 -0
- package/wiki/references/base/dependency-injection.md +39 -3
- package/wiki/references/base/filter-system/application-usage.md +224 -0
- package/wiki/references/base/filter-system/array-operators.md +132 -0
- package/wiki/references/base/filter-system/comparison-operators.md +109 -0
- package/wiki/references/base/filter-system/default-filter.md +428 -0
- package/wiki/references/base/filter-system/fields-order-pagination.md +155 -0
- package/wiki/references/base/filter-system/index.md +127 -0
- package/wiki/references/base/filter-system/json-filtering.md +197 -0
- package/wiki/references/base/filter-system/list-operators.md +71 -0
- package/wiki/references/base/filter-system/logical-operators.md +156 -0
- package/wiki/references/base/filter-system/null-operators.md +58 -0
- package/wiki/references/base/filter-system/pattern-matching.md +108 -0
- package/wiki/references/base/filter-system/quick-reference.md +431 -0
- package/wiki/references/base/filter-system/range-operators.md +63 -0
- package/wiki/references/base/filter-system/tips.md +190 -0
- package/wiki/references/base/filter-system/use-cases.md +452 -0
- package/wiki/references/base/index.md +90 -0
- package/wiki/references/base/middlewares.md +604 -0
- package/wiki/references/base/models.md +215 -23
- package/wiki/references/base/providers.md +731 -0
- package/wiki/references/base/repositories/advanced.md +555 -0
- package/wiki/references/base/repositories/index.md +228 -0
- package/wiki/references/base/repositories/mixins.md +331 -0
- package/wiki/references/base/repositories/relations.md +486 -0
- package/wiki/references/base/repositories.md +40 -635
- package/wiki/references/base/services.md +28 -4
- package/wiki/references/components/authentication.md +22 -2
- package/wiki/references/components/health-check.md +12 -0
- package/wiki/references/components/index.md +23 -0
- package/wiki/references/components/mail.md +687 -0
- package/wiki/references/components/request-tracker.md +16 -0
- package/wiki/references/components/socket-io.md +18 -0
- package/wiki/references/components/static-asset.md +14 -26
- package/wiki/references/components/swagger.md +17 -0
- package/wiki/references/configuration/environment-variables.md +427 -0
- package/wiki/references/configuration/index.md +73 -0
- package/wiki/references/helpers/cron.md +14 -0
- package/wiki/references/helpers/crypto.md +15 -0
- package/wiki/references/helpers/env.md +16 -0
- package/wiki/references/helpers/error.md +17 -0
- package/wiki/references/helpers/index.md +14 -0
- package/wiki/references/helpers/inversion.md +24 -4
- package/wiki/references/helpers/logger.md +19 -0
- package/wiki/references/helpers/network.md +11 -0
- package/wiki/references/helpers/queue.md +19 -0
- package/wiki/references/helpers/redis.md +21 -0
- package/wiki/references/helpers/socket-io.md +24 -5
- package/wiki/references/helpers/storage.md +18 -10
- package/wiki/references/helpers/testing.md +18 -0
- package/wiki/references/helpers/types.md +16 -0
- package/wiki/references/helpers/uid.md +167 -0
- package/wiki/references/helpers/worker-thread.md +16 -0
- package/wiki/references/index.md +177 -0
- package/wiki/references/quick-reference.md +634 -0
- package/wiki/references/src-details/boot.md +3 -3
- package/wiki/references/src-details/dev-configs.md +0 -4
- package/wiki/references/src-details/docs.md +2 -2
- package/wiki/references/src-details/index.md +86 -0
- package/wiki/references/src-details/inversion.md +1 -6
- package/wiki/references/src-details/mcp-server.md +3 -15
- package/wiki/references/utilities/index.md +86 -10
- package/wiki/references/utilities/jsx.md +577 -0
- package/wiki/references/utilities/request.md +0 -2
- package/wiki/references/utilities/statuses.md +740 -0
- package/wiki/get-started/best-practices/api-usage-examples.md +0 -266
- package/wiki/get-started/best-practices/architectural-patterns.md +0 -170
- package/wiki/get-started/best-practices/data-modeling.md +0 -177
- package/wiki/get-started/best-practices/deployment-strategies.md +0 -121
- package/wiki/get-started/best-practices/performance-optimization.md +0 -97
- package/wiki/get-started/best-practices/security-guidelines.md +0 -99
- package/wiki/get-started/core-concepts/persistent.md +0 -539
- package/wiki/get-started/index.md +0 -65
- package/wiki/get-started/philosophy.md +0 -296
- package/wiki/get-started/prerequisites.md +0 -113
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: String ID with Custom Generator
|
|
3
|
+
description: Text column with customizable ID generator for maximum database compatibility
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Changelog - 2025-12-31
|
|
7
|
+
|
|
8
|
+
## String ID with Custom Generator
|
|
9
|
+
|
|
10
|
+
This release changes the string ID implementation from PostgreSQL `uuid` type to `text` column with a customizable ID generator for maximum database compatibility.
|
|
11
|
+
|
|
12
|
+
## Overview
|
|
13
|
+
|
|
14
|
+
- **Text Column**: String IDs now use `text` column type instead of PostgreSQL `uuid`
|
|
15
|
+
- **Custom Generator**: Optional `generator` function to use any ID format (UUID, nanoid, cuid, etc.)
|
|
16
|
+
- **Default UUID**: Uses `crypto.randomUUID()` by default for backwards compatibility
|
|
17
|
+
- **Consistent Naming**: Renamed `visibleColumns` to `visibleProperties` for consistency with `hiddenProperties`
|
|
18
|
+
- **Removed 'uuid' Option**: Principal enricher now only supports `'number' | 'string'`
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
## String ID Changes
|
|
22
|
+
|
|
23
|
+
### Before
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
// Used PostgreSQL uuid type
|
|
27
|
+
uuid('id').defaultRandom().primaryKey()
|
|
28
|
+
// Column type: uuid
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### After
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
// Uses text column with $defaultFn
|
|
35
|
+
text('id').primaryKey().$defaultFn(() => crypto.randomUUID())
|
|
36
|
+
// Column type: text
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Custom Generator Option
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
import { nanoid } from 'nanoid';
|
|
43
|
+
|
|
44
|
+
generateIdColumnDefs({
|
|
45
|
+
id: {
|
|
46
|
+
dataType: 'string',
|
|
47
|
+
generator: () => nanoid(), // Custom generator
|
|
48
|
+
},
|
|
49
|
+
})
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Type Definition
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
type TIdEnricherOptions = {
|
|
56
|
+
id?: { columnName?: string } & (
|
|
57
|
+
| { dataType: 'string'; generator?: () => string } // NEW: optional generator
|
|
58
|
+
| { dataType: 'number'; sequenceOptions?: PgSequenceOptions }
|
|
59
|
+
| { dataType: 'big-number'; numberMode: 'number' | 'bigint'; sequenceOptions?: PgSequenceOptions }
|
|
60
|
+
);
|
|
61
|
+
};
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
## Naming Consistency
|
|
66
|
+
|
|
67
|
+
Renamed internal properties for consistency:
|
|
68
|
+
|
|
69
|
+
| Before | After |
|
|
70
|
+
|--------|-------|
|
|
71
|
+
| `_visibleColumns` | `_visibleProperties` |
|
|
72
|
+
| `getVisibleColumns()` | `getVisibleProperties()` |
|
|
73
|
+
| `visibleColumns` getter/setter | `visibleProps` getter/setter |
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
## Principal Enricher Simplification
|
|
77
|
+
|
|
78
|
+
Removed 'uuid' option since it's now identical to 'string':
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
// Before
|
|
82
|
+
type IdType = 'number' | 'string' | 'uuid';
|
|
83
|
+
|
|
84
|
+
// After
|
|
85
|
+
type IdType = 'number' | 'string';
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
## Files Changed
|
|
90
|
+
|
|
91
|
+
### Core Package (`packages/core`)
|
|
92
|
+
|
|
93
|
+
| File | Changes |
|
|
94
|
+
|------|---------|
|
|
95
|
+
| `src/base/models/enrichers/id.enricher.ts` | Text column with custom generator, type aliases |
|
|
96
|
+
| `src/base/models/enrichers/principal.enricher.ts` | Removed 'uuid' option, uses text for string IDs |
|
|
97
|
+
| `src/base/repositories/core/base.ts` | Renamed visibleColumns to visibleProperties |
|
|
98
|
+
| `src/base/repositories/core/readable.ts` | Updated to use getVisibleProperties() |
|
|
99
|
+
| `src/base/repositories/core/persistable.ts` | Updated to use getVisibleProperties() |
|
|
100
|
+
| `src/components/static-asset/models/base.model.ts` | uuid() to text() |
|
|
101
|
+
| `src/components/auth/models/entities/*.ts` | uuid() to text() for all auth models |
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
## Migration Guide
|
|
105
|
+
|
|
106
|
+
### No Breaking Changes for Most Users
|
|
107
|
+
|
|
108
|
+
If you're using `generateIdColumnDefs({ id: { dataType: 'string' } })`, your code continues to work. The only difference is the underlying column type changes from `uuid` to `text`.
|
|
109
|
+
|
|
110
|
+
### Database Migration
|
|
111
|
+
|
|
112
|
+
If you have existing `uuid` columns and want to migrate to `text`:
|
|
113
|
+
|
|
114
|
+
```sql
|
|
115
|
+
-- Option 1: Alter column type (data preserved)
|
|
116
|
+
ALTER TABLE "your_table" ALTER COLUMN "id" TYPE TEXT;
|
|
117
|
+
|
|
118
|
+
-- Option 2: Keep uuid type (still works with text-based code)
|
|
119
|
+
-- No migration needed - uuid values are compatible with text operations
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Custom ID Generator
|
|
123
|
+
|
|
124
|
+
To use a custom generator:
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
import { nanoid } from 'nanoid';
|
|
128
|
+
// or
|
|
129
|
+
import { createId } from '@paralleldrive/cuid2';
|
|
130
|
+
|
|
131
|
+
generateIdColumnDefs({
|
|
132
|
+
id: {
|
|
133
|
+
dataType: 'string',
|
|
134
|
+
generator: () => nanoid(), // or createId
|
|
135
|
+
},
|
|
136
|
+
})
|
|
137
|
+
```
|
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Default Filter & Repository Mixins
|
|
3
|
+
description: Added default filter support for models and refactored repository architecture with composable mixins
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Changelog - 2026-01-02
|
|
7
|
+
|
|
8
|
+
## Default Filter & Repository Mixins
|
|
9
|
+
|
|
10
|
+
This release introduces **Default Filter** - a powerful feature that automatically applies predefined filter conditions to all repository queries. Additionally, the repository architecture has been refactored to use composable mixins for better code organization and reusability.
|
|
11
|
+
|
|
12
|
+
## Overview
|
|
13
|
+
|
|
14
|
+
- **Default Filter**: Configure automatic filter conditions at the model level (e.g., soft delete, tenant isolation)
|
|
15
|
+
- **Skip Default Filter**: Bypass default filters with `shouldSkipDefaultFilter: true` for admin/maintenance operations
|
|
16
|
+
- **Repository Mixins**: Extracted `DefaultFilterMixin` and `FieldsVisibilityMixin` for composable repository features
|
|
17
|
+
- **FilterBuilder Enhancement**: Renamed `DrizzleFilterBuilder` to `FilterBuilder`, added `mergeFilter` method
|
|
18
|
+
- **IExtraOptions Interface**: New interface replacing `TTransactionOption` with `shouldSkipDefaultFilter` support
|
|
19
|
+
|
|
20
|
+
## New Features
|
|
21
|
+
|
|
22
|
+
### Default Filter
|
|
23
|
+
|
|
24
|
+
**Files:**
|
|
25
|
+
- `packages/core/src/base/repositories/mixins/default-filter.ts`
|
|
26
|
+
- `packages/core/src/base/repositories/operators/filter.ts`
|
|
27
|
+
|
|
28
|
+
**Problem:** Applications often need to apply the same filter conditions to every query - soft delete (`isDeleted: false`), tenant isolation (`tenantId: 'xxx'`), or active record patterns. Without a centralized solution, developers must manually add these conditions to every repository call.
|
|
29
|
+
|
|
30
|
+
**Solution:** Configure a `defaultFilter` in your model settings. The repository automatically merges this filter with user-provided filters for all read, update, and delete operations.
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
// Model configuration with default filter
|
|
34
|
+
@model({
|
|
35
|
+
type: 'entity',
|
|
36
|
+
settings: {
|
|
37
|
+
// Automatically applied to all queries
|
|
38
|
+
defaultFilter: {
|
|
39
|
+
where: { isDeleted: false },
|
|
40
|
+
limit: 100, // Prevent unbounded queries
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
})
|
|
44
|
+
export class User extends BaseEntity<typeof User.schema> {
|
|
45
|
+
static override schema = userTable;
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Automatic Application:**
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
// User query - default filter automatically merged
|
|
53
|
+
await userRepo.find({
|
|
54
|
+
filter: { where: { status: 'active' } }
|
|
55
|
+
});
|
|
56
|
+
// Actual query: WHERE isDeleted = false AND status = 'active' LIMIT 100
|
|
57
|
+
|
|
58
|
+
// Default filter also applies to count, update, delete
|
|
59
|
+
await userRepo.count({ where: { role: 'admin' } });
|
|
60
|
+
// Actual query: WHERE isDeleted = false AND role = 'admin'
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Filter Merge Strategy:**
|
|
64
|
+
|
|
65
|
+
| Property | Strategy |
|
|
66
|
+
|----------|----------|
|
|
67
|
+
| `where` | Deep merge (user overrides matching keys) |
|
|
68
|
+
| `limit` | User replaces default (if provided) |
|
|
69
|
+
| `offset`/`skip` | User replaces default (if provided) |
|
|
70
|
+
| `order` | User replaces default (if provided) |
|
|
71
|
+
| `fields` | User replaces default (if provided) |
|
|
72
|
+
| `include` | User replaces default (if provided) |
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
// Default: { where: { isDeleted: false, status: 'pending' }, limit: 100 }
|
|
76
|
+
// User: { where: { status: 'active' }, limit: 10 }
|
|
77
|
+
// Result: { where: { isDeleted: false, status: 'active' }, limit: 10 }
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Skip Default Filter
|
|
81
|
+
|
|
82
|
+
**Problem:** Admin users or maintenance scripts sometimes need to query all records, including soft-deleted ones or records from all tenants.
|
|
83
|
+
|
|
84
|
+
**Solution:** Pass `shouldSkipDefaultFilter: true` in the options to bypass the default filter:
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
// Normal query - default filter applies
|
|
88
|
+
await repo.find({ filter: { where: { role: 'admin' } } });
|
|
89
|
+
// WHERE isDeleted = false AND role = 'admin'
|
|
90
|
+
|
|
91
|
+
// Admin query - bypass default filter
|
|
92
|
+
await repo.find({
|
|
93
|
+
filter: { where: { role: 'admin' } },
|
|
94
|
+
options: { shouldSkipDefaultFilter: true }
|
|
95
|
+
});
|
|
96
|
+
// WHERE role = 'admin' (includes deleted records)
|
|
97
|
+
|
|
98
|
+
// Works with all operations
|
|
99
|
+
await repo.count({ where: {}, options: { shouldSkipDefaultFilter: true } });
|
|
100
|
+
await repo.updateAll({
|
|
101
|
+
where: { status: 'archived' },
|
|
102
|
+
data: { isDeleted: true },
|
|
103
|
+
options: { shouldSkipDefaultFilter: true }
|
|
104
|
+
});
|
|
105
|
+
await repo.deleteAll({
|
|
106
|
+
where: { createdAt: { lt: '2020-01-01' } },
|
|
107
|
+
options: { shouldSkipDefaultFilter: true, force: true }
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Benefits:**
|
|
112
|
+
- Automatic soft-delete filtering without manual `where` additions
|
|
113
|
+
- Multi-tenant isolation at the data layer
|
|
114
|
+
- Consistent query behavior across the application
|
|
115
|
+
- Easy bypass for admin/maintenance operations
|
|
116
|
+
|
|
117
|
+
### Repository Mixins
|
|
118
|
+
|
|
119
|
+
**Files:**
|
|
120
|
+
- `packages/core/src/base/repositories/mixins/default-filter.ts`
|
|
121
|
+
- `packages/core/src/base/repositories/mixins/fields-visibility.ts`
|
|
122
|
+
- `packages/core/src/base/repositories/mixins/index.ts`
|
|
123
|
+
|
|
124
|
+
**Problem:** Repository base classes were becoming monolithic with multiple concerns (hidden properties, default filters, transaction handling) mixed together.
|
|
125
|
+
|
|
126
|
+
**Solution:** Extract cross-cutting concerns into composable mixins:
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
// DefaultFilterMixin - Provides default filter functionality
|
|
130
|
+
export const DefaultFilterMixin = <T extends TMixinTarget<object>>(baseClass: T) => {
|
|
131
|
+
abstract class Mixed extends baseClass {
|
|
132
|
+
getDefaultFilter(): TFilter | undefined;
|
|
133
|
+
hasDefaultFilter(): boolean;
|
|
134
|
+
applyDefaultFilter(opts: { userFilter?: TFilter; shouldSkipDefaultFilter?: boolean }): TFilter;
|
|
135
|
+
}
|
|
136
|
+
return Mixed;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
// FieldsVisibilityMixin - Provides hidden properties functionality
|
|
140
|
+
export const FieldsVisibilityMixin = <T extends TMixinTarget<object>>(baseClass: T) => {
|
|
141
|
+
abstract class Mixed extends baseClass {
|
|
142
|
+
get hiddenProperties(): Set<string>;
|
|
143
|
+
get visibleProperties(): Record<string, any> | undefined;
|
|
144
|
+
getHiddenProperties(): Set<string>;
|
|
145
|
+
hasHiddenProperties(): boolean;
|
|
146
|
+
getVisibleProperties(): Record<string, any> | undefined;
|
|
147
|
+
}
|
|
148
|
+
return Mixed;
|
|
149
|
+
};
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**Usage in AbstractRepository:**
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
export abstract class AbstractRepository<...>
|
|
156
|
+
extends DefaultFilterMixin(FieldsVisibilityMixin(BaseHelper))
|
|
157
|
+
implements IPersistableRepository<...>
|
|
158
|
+
{
|
|
159
|
+
// Mixins provide getDefaultFilter, applyDefaultFilter,
|
|
160
|
+
// getHiddenProperties, getVisibleProperties, etc.
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
**Benefits:**
|
|
165
|
+
- Separation of concerns
|
|
166
|
+
- Reusable logic across different repository types
|
|
167
|
+
- Easier testing of individual features
|
|
168
|
+
- Clear dependency chain
|
|
169
|
+
|
|
170
|
+
### IExtraOptions Interface
|
|
171
|
+
|
|
172
|
+
**File:** `packages/core/src/base/repositories/common/types.ts`
|
|
173
|
+
|
|
174
|
+
**Problem:** The `TTransactionOption` type only supported `transaction` option. With the new default filter feature, we need additional options.
|
|
175
|
+
|
|
176
|
+
**Solution:** Introduced `IExtraOptions` interface that extends beyond transactions:
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
// New interface
|
|
180
|
+
export interface IExtraOptions extends IWithTransaction {
|
|
181
|
+
/**
|
|
182
|
+
* If true, bypass the default filter configured in model settings.
|
|
183
|
+
* Use this when you need to query all records regardless of default filter constraints.
|
|
184
|
+
*/
|
|
185
|
+
shouldSkipDefaultFilter?: boolean;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Base transaction interface
|
|
189
|
+
export interface IWithTransaction {
|
|
190
|
+
transaction?: ITransaction;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Deprecated alias for backward compatibility
|
|
194
|
+
/** @deprecated Use IExtraOptions instead */
|
|
195
|
+
export type TTransactionOption = IExtraOptions;
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### FilterBuilder Enhancements
|
|
199
|
+
|
|
200
|
+
**File:** `packages/core/src/base/repositories/operators/filter.ts`
|
|
201
|
+
|
|
202
|
+
**Changes:**
|
|
203
|
+
- Renamed `DrizzleFilterBuilder` to `FilterBuilder`
|
|
204
|
+
- Added `mergeFilter` method for combining default and user filters
|
|
205
|
+
- Added `resolveHiddenProperties` and `resolveRelations` methods
|
|
206
|
+
- Simplified `build` method signature (relations resolved internally)
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
// New mergeFilter method
|
|
210
|
+
const filterBuilder = new FilterBuilder();
|
|
211
|
+
|
|
212
|
+
const result = filterBuilder.mergeFilter({
|
|
213
|
+
defaultFilter: { where: { isDeleted: false }, limit: 100 },
|
|
214
|
+
userFilter: { where: { status: 'active' }, limit: 10 }
|
|
215
|
+
});
|
|
216
|
+
// Result: { where: { isDeleted: false, status: 'active' }, limit: 10 }
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**Internal Changes:**
|
|
220
|
+
- Relations now resolved internally via `resolveRelations` method
|
|
221
|
+
- Hidden properties resolved via `resolveHiddenProperties` method
|
|
222
|
+
- Simplified API for `build` method (no need to pass resolvers)
|
|
223
|
+
|
|
224
|
+
## Files Changed
|
|
225
|
+
|
|
226
|
+
### Core Package (`packages/core`)
|
|
227
|
+
|
|
228
|
+
| File | Changes |
|
|
229
|
+
|------|---------|
|
|
230
|
+
| `src/base/repositories/mixins/default-filter.ts` | **NEW** - DefaultFilterMixin implementation |
|
|
231
|
+
| `src/base/repositories/mixins/fields-visibility.ts` | **NEW** - FieldsVisibilityMixin implementation |
|
|
232
|
+
| `src/base/repositories/mixins/index.ts` | **NEW** - Barrel export for mixins |
|
|
233
|
+
| `src/base/repositories/common/types.ts` | Added `IExtraOptions`, `IWithTransaction` interfaces |
|
|
234
|
+
| `src/base/repositories/core/base.ts` | Refactored to use mixins, updated method signatures |
|
|
235
|
+
| `src/base/repositories/core/readable.ts` | Added `applyDefaultFilter` calls to read operations |
|
|
236
|
+
| `src/base/repositories/core/persistable.ts` | Added `applyDefaultFilter` calls to update/delete |
|
|
237
|
+
| `src/base/repositories/core/default-crud.ts` | Updated type parameters |
|
|
238
|
+
| `src/base/repositories/operators/filter.ts` | Renamed to `FilterBuilder`, added `mergeFilter` |
|
|
239
|
+
| `src/helpers/inversion/common/types.ts` | Added `defaultFilter` to model settings type |
|
|
240
|
+
|
|
241
|
+
### Tests (`packages/core/src/__tests__`)
|
|
242
|
+
|
|
243
|
+
| File | Changes |
|
|
244
|
+
|------|---------|
|
|
245
|
+
| `default-filter/default-filter.test.ts` | **NEW** - Comprehensive test suite (150+ test cases) |
|
|
246
|
+
|
|
247
|
+
### Examples (`examples/vert`)
|
|
248
|
+
|
|
249
|
+
| File | Changes |
|
|
250
|
+
|------|---------|
|
|
251
|
+
| `src/services/tests/default-filter-test.service.ts` | **NEW** - Integration test service |
|
|
252
|
+
| `src/services/tests/TEST_CASES.md` | **NEW** - Test case documentation |
|
|
253
|
+
|
|
254
|
+
## Breaking Changes
|
|
255
|
+
|
|
256
|
+
### DrizzleFilterBuilder Renamed to FilterBuilder
|
|
257
|
+
|
|
258
|
+
**Before:**
|
|
259
|
+
```typescript
|
|
260
|
+
import { DrizzleFilterBuilder } from '@venizia/ignis';
|
|
261
|
+
const builder = new DrizzleFilterBuilder();
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
**After:**
|
|
265
|
+
```typescript
|
|
266
|
+
import { FilterBuilder } from '@venizia/ignis';
|
|
267
|
+
const builder = new FilterBuilder();
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### FilterBuilder.build() Signature Changed
|
|
271
|
+
|
|
272
|
+
**Before:**
|
|
273
|
+
```typescript
|
|
274
|
+
filterBuilder.build({
|
|
275
|
+
tableName: 'users',
|
|
276
|
+
schema: userSchema,
|
|
277
|
+
relations: { posts: { ... } },
|
|
278
|
+
filter: myFilter,
|
|
279
|
+
relationResolver: (schema) => { ... },
|
|
280
|
+
hiddenPropertiesResolver: (relationName) => { ... },
|
|
281
|
+
});
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
**After:**
|
|
285
|
+
```typescript
|
|
286
|
+
// Relations and hidden properties resolved internally
|
|
287
|
+
filterBuilder.build({
|
|
288
|
+
tableName: 'users',
|
|
289
|
+
schema: userSchema,
|
|
290
|
+
filter: myFilter,
|
|
291
|
+
});
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### TTransactionOption Deprecated
|
|
295
|
+
|
|
296
|
+
**Before:**
|
|
297
|
+
```typescript
|
|
298
|
+
import { TTransactionOption } from '@venizia/ignis';
|
|
299
|
+
|
|
300
|
+
class MyRepo extends AbstractRepository<Schema, Data, Persist, TTransactionOption> {}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
**After:**
|
|
304
|
+
```typescript
|
|
305
|
+
import { IExtraOptions } from '@venizia/ignis';
|
|
306
|
+
|
|
307
|
+
class MyRepo extends AbstractRepository<Schema, Data, Persist, IExtraOptions> {}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
## Migration Guide
|
|
311
|
+
|
|
312
|
+
### Step 1: Update FilterBuilder Usage
|
|
313
|
+
|
|
314
|
+
If you're using `DrizzleFilterBuilder` directly (rare), rename to `FilterBuilder`:
|
|
315
|
+
|
|
316
|
+
```typescript
|
|
317
|
+
// Before
|
|
318
|
+
import { DrizzleFilterBuilder } from '@venizia/ignis';
|
|
319
|
+
|
|
320
|
+
// After
|
|
321
|
+
import { FilterBuilder } from '@venizia/ignis';
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### Step 2: Update Custom Repository Generic Types
|
|
325
|
+
|
|
326
|
+
If you have custom repositories with explicit generic types:
|
|
327
|
+
|
|
328
|
+
```typescript
|
|
329
|
+
// Before
|
|
330
|
+
class MyRepo extends PersistableRepository<Schema, Data, Persist, TTransactionOption> {}
|
|
331
|
+
|
|
332
|
+
// After
|
|
333
|
+
class MyRepo extends PersistableRepository<Schema, Data, Persist, IExtraOptions> {}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### Step 3: Add Default Filters to Models (Optional)
|
|
337
|
+
|
|
338
|
+
To enable automatic filtering, add `defaultFilter` to your model settings:
|
|
339
|
+
|
|
340
|
+
```typescript
|
|
341
|
+
@model({
|
|
342
|
+
type: 'entity',
|
|
343
|
+
settings: {
|
|
344
|
+
defaultFilter: {
|
|
345
|
+
where: { isDeleted: false },
|
|
346
|
+
},
|
|
347
|
+
},
|
|
348
|
+
})
|
|
349
|
+
export class User extends BaseEntity<typeof User.schema> {
|
|
350
|
+
static override schema = userTable;
|
|
351
|
+
}
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
## Common Use Cases
|
|
355
|
+
|
|
356
|
+
### Soft Delete Pattern
|
|
357
|
+
|
|
358
|
+
```typescript
|
|
359
|
+
@model({
|
|
360
|
+
type: 'entity',
|
|
361
|
+
settings: {
|
|
362
|
+
defaultFilter: {
|
|
363
|
+
where: { deletedAt: null }, // or { isDeleted: false }
|
|
364
|
+
},
|
|
365
|
+
},
|
|
366
|
+
})
|
|
367
|
+
export class Post extends BaseEntity<typeof Post.schema> {}
|
|
368
|
+
|
|
369
|
+
// All queries automatically exclude deleted posts
|
|
370
|
+
await postRepo.find({ filter: { where: { published: true } } });
|
|
371
|
+
// WHERE deletedAt IS NULL AND published = true
|
|
372
|
+
|
|
373
|
+
// Restore deleted post (bypass default filter)
|
|
374
|
+
await postRepo.updateById({
|
|
375
|
+
id: postId,
|
|
376
|
+
data: { deletedAt: null },
|
|
377
|
+
options: { shouldSkipDefaultFilter: true }
|
|
378
|
+
});
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
### Multi-Tenant Isolation
|
|
382
|
+
|
|
383
|
+
```typescript
|
|
384
|
+
// Note: tenantId would be injected per-request in real applications
|
|
385
|
+
@model({
|
|
386
|
+
type: 'entity',
|
|
387
|
+
settings: {
|
|
388
|
+
defaultFilter: {
|
|
389
|
+
where: { tenantId: 'current-tenant-id' },
|
|
390
|
+
},
|
|
391
|
+
},
|
|
392
|
+
})
|
|
393
|
+
export class Document extends BaseEntity<typeof Document.schema> {}
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
### Active Records Only
|
|
397
|
+
|
|
398
|
+
```typescript
|
|
399
|
+
@model({
|
|
400
|
+
type: 'entity',
|
|
401
|
+
settings: {
|
|
402
|
+
defaultFilter: {
|
|
403
|
+
where: {
|
|
404
|
+
isActive: true,
|
|
405
|
+
expiresAt: { gt: new Date().toISOString() },
|
|
406
|
+
},
|
|
407
|
+
limit: 50, // Prevent unbounded queries
|
|
408
|
+
},
|
|
409
|
+
},
|
|
410
|
+
})
|
|
411
|
+
export class Subscription extends BaseEntity<typeof Subscription.schema> {}
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
## Documentation
|
|
415
|
+
|
|
416
|
+
- [Default Filter Guide](/references/base/filter-system/default-filter) - Full documentation
|
|
417
|
+
- [Repository Mixins](/references/base/repositories/mixins) - Mixin architecture
|
|
418
|
+
- [Advanced Repository Features](/references/base/repositories/advanced) - Updated with shouldSkipDefaultFilter
|
package/wiki/changelogs/index.md
CHANGED
|
@@ -17,6 +17,12 @@ This section tracks the history of significant changes, refactors, and updates t
|
|
|
17
17
|
|
|
18
18
|
| Date | Title | Type |
|
|
19
19
|
|------|-------|------|
|
|
20
|
+
| 2026-01-02 | [Default Filter & Repository Mixins](./2026-01-02-default-filter-and-repository-mixins) | New Feature |
|
|
21
|
+
| 2025-12-31 | [JSON Path Filtering & Array Operators](./2025-12-31-json-path-filtering-array-operators) | New Feature |
|
|
22
|
+
| 2025-12-31 | [String ID with Custom Generator](./2025-12-31-string-id-custom-generator) | Enhancement |
|
|
23
|
+
| 2025-12-30 | [Repository Enhancements](./2025-12-30-repository-enhancements) | Enhancement |
|
|
24
|
+
| 2025-12-29 | [Snowflake UID Helper](./2025-12-29-snowflake-uid-helper) | New Feature |
|
|
25
|
+
| 2025-12-29 | [Dynamic Binding Registration Fix](./2025-12-29-dynamic-binding-registration) | Bug Fix |
|
|
20
26
|
| 2025-12-26 | [Transaction Support](./2025-12-26-transaction-support) | Enhancement |
|
|
21
27
|
| 2025-12-26 | [Nested Relations & Generic Types](./2025-12-26-nested-relations-and-generics) | Enhancement |
|
|
22
28
|
| 2025-12-18 | [Performance Optimizations](./2025-12-18-performance-optimizations) | Enhancement |
|
|
@@ -40,7 +40,6 @@ await migrator.automigrate(); // Drops and recreates all tables
|
|
|
40
40
|
| `autoupdate()` | Compares DB ↔ Model, applies ALTER statements | **No** |
|
|
41
41
|
| `automigrate()` | Drops and recreates tables | **Yes** |
|
|
42
42
|
|
|
43
|
-
---
|
|
44
43
|
|
|
45
44
|
## Implementation Steps
|
|
46
45
|
|
|
@@ -409,7 +408,6 @@ export abstract class BaseDataSource<...> {
|
|
|
409
408
|
}
|
|
410
409
|
```
|
|
411
410
|
|
|
412
|
-
---
|
|
413
411
|
|
|
414
412
|
## Files to Create
|
|
415
413
|
|
|
@@ -428,7 +426,6 @@ export abstract class BaseDataSource<...> {
|
|
|
428
426
|
| `packages/core/src/base/datasources/base.ts` | Add `getMigrator()`, `autoupdate()`, `automigrate()` |
|
|
429
427
|
| `packages/core/src/base/datasources/index.ts` | Export new classes |
|
|
430
428
|
|
|
431
|
-
---
|
|
432
429
|
|
|
433
430
|
## Drizzle to PostgreSQL Type Mapping
|
|
434
431
|
|
|
@@ -449,7 +446,6 @@ export abstract class BaseDataSource<...> {
|
|
|
449
446
|
| `real()` | `real` | 32-bit float |
|
|
450
447
|
| `doublePrecision()` | `double precision` | 64-bit float |
|
|
451
448
|
|
|
452
|
-
---
|
|
453
449
|
|
|
454
450
|
## Change Detection Matrix
|
|
455
451
|
|
|
@@ -466,7 +462,6 @@ export abstract class BaseDataSource<...> {
|
|
|
466
462
|
| New index | Index not in DB | `CREATE INDEX` |
|
|
467
463
|
| Removed index | Index not in model | `DROP INDEX` |
|
|
468
464
|
|
|
469
|
-
---
|
|
470
465
|
|
|
471
466
|
## Usage Examples
|
|
472
467
|
|
|
@@ -515,7 +510,6 @@ if (process.env.NODE_ENV === 'development') {
|
|
|
515
510
|
}
|
|
516
511
|
```
|
|
517
512
|
|
|
518
|
-
---
|
|
519
513
|
|
|
520
514
|
## Safety Considerations
|
|
521
515
|
|
|
@@ -536,7 +530,6 @@ if (process.env.NODE_ENV === 'development') {
|
|
|
536
530
|
| `ALTER TYPE` | May fail if incompatible | Checks compatibility first |
|
|
537
531
|
| `automigrate()` | Drops all tables | Requires `force: true` |
|
|
538
532
|
|
|
539
|
-
---
|
|
540
533
|
|
|
541
534
|
## Future Enhancements
|
|
542
535
|
|
|
@@ -546,7 +539,6 @@ if (process.env.NODE_ENV === 'development') {
|
|
|
546
539
|
4. **Multi-Schema Support** - Support for PostgreSQL schemas beyond `public`
|
|
547
540
|
5. **MySQL/SQLite Support** - Extend beyond PostgreSQL
|
|
548
541
|
|
|
549
|
-
---
|
|
550
542
|
|
|
551
543
|
## Comparison with Alternatives
|
|
552
544
|
|
package/wiki/{get-started/core-concepts → guides/core-concepts/application}/bootstrapping.md
RENAMED
|
@@ -558,9 +558,22 @@ npx glob "your-pattern/**/*.controller.js"
|
|
|
558
558
|
- Skip subdirectories if you have nested structure
|
|
559
559
|
- Ignore boot errors (they indicate misconfiguration)
|
|
560
560
|
|
|
561
|
-
##
|
|
561
|
+
## See Also
|
|
562
562
|
|
|
563
|
-
-
|
|
564
|
-
- [Application
|
|
565
|
-
- [
|
|
566
|
-
- [
|
|
563
|
+
- **Related Concepts:**
|
|
564
|
+
- [Application Overview](./index) - Main application class
|
|
565
|
+
- [Controllers](/guides/core-concepts/controllers) - Auto-discovered controllers
|
|
566
|
+
- [Services](/guides/core-concepts/services) - Auto-discovered services
|
|
567
|
+
- [Repositories](/guides/core-concepts/persistent/repositories) - Auto-discovered repositories
|
|
568
|
+
|
|
569
|
+
- **References:**
|
|
570
|
+
- [Bootstrapping API](/references/base/bootstrapping) - Complete API reference
|
|
571
|
+
- [Boot Package](/references/src-details/boot) - Boot system internals
|
|
572
|
+
- [Dependency Injection](/references/base/dependency-injection) - DI container
|
|
573
|
+
|
|
574
|
+
- **Tutorials:**
|
|
575
|
+
- [Complete Installation](/guides/tutorials/complete-installation) - Project structure
|
|
576
|
+
- [Building a CRUD API](/guides/tutorials/building-a-crud-api) - Bootstrapping in action
|
|
577
|
+
|
|
578
|
+
- **Best Practices:**
|
|
579
|
+
- [Architectural Patterns](/best-practices/architectural-patterns) - Project organization patterns
|