@venizia/ignis-docs 0.0.1-8 → 0.0.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/LICENSE.md +1 -0
- package/package.json +2 -2
- package/wiki/changelogs/2025-12-16-initial-architecture.md +145 -0
- package/wiki/changelogs/2025-12-16-model-repo-datasource-refactor.md +300 -0
- package/wiki/changelogs/2025-12-17-refactor.md +90 -0
- package/wiki/changelogs/2025-12-18-performance-optimizations.md +130 -0
- package/wiki/changelogs/2025-12-18-repository-validation-security.md +249 -0
- package/wiki/changelogs/index.md +33 -0
- package/wiki/changelogs/planned-transaction-support.md +216 -0
- package/wiki/changelogs/template.md +123 -0
- package/wiki/get-started/5-minute-quickstart.md +1 -1
- package/wiki/get-started/best-practices/api-usage-examples.md +12 -10
- package/wiki/get-started/best-practices/architectural-patterns.md +2 -2
- package/wiki/get-started/best-practices/common-pitfalls.md +7 -5
- package/wiki/get-started/best-practices/contribution-workflow.md +2 -0
- package/wiki/get-started/best-practices/data-modeling.md +91 -40
- package/wiki/get-started/best-practices/security-guidelines.md +3 -1
- package/wiki/get-started/building-a-crud-api.md +63 -78
- package/wiki/get-started/core-concepts/application.md +72 -3
- package/wiki/get-started/core-concepts/bootstrapping.md +566 -0
- package/wiki/get-started/core-concepts/components.md +4 -2
- package/wiki/get-started/core-concepts/controllers.md +14 -14
- package/wiki/get-started/core-concepts/persistent.md +383 -431
- package/wiki/get-started/core-concepts/services.md +21 -27
- package/wiki/get-started/quickstart.md +1 -1
- package/wiki/references/base/bootstrapping.md +789 -0
- package/wiki/references/base/components.md +1 -1
- package/wiki/references/base/controllers.md +40 -16
- package/wiki/references/base/datasources.md +195 -33
- package/wiki/references/base/dependency-injection.md +98 -5
- package/wiki/references/base/models.md +398 -28
- package/wiki/references/base/repositories.md +475 -22
- package/wiki/references/base/services.md +2 -2
- package/wiki/references/components/authentication.md +228 -10
- package/wiki/references/components/health-check.md +1 -1
- package/wiki/references/components/index.md +1 -1
- package/wiki/references/components/swagger.md +1 -1
- package/wiki/references/helpers/error.md +2 -2
- package/wiki/references/helpers/inversion.md +8 -3
- package/wiki/references/src-details/boot.md +379 -0
- package/wiki/references/src-details/core.md +8 -7
- package/wiki/references/src-details/inversion.md +4 -4
- package/wiki/references/utilities/request.md +16 -7
package/LICENSE.md
CHANGED
|
@@ -33,6 +33,7 @@ This monorepo contains the following packages, all licensed under MIT:
|
|
|
33
33
|
| Package | Description |
|
|
34
34
|
|---------|-------------|
|
|
35
35
|
| `@venizia/ignis` | Core framework - controllers, services, decorators |
|
|
36
|
+
| `@venizia/ignis-boot` | Application bootstrapping & artifact auto-discovery |
|
|
36
37
|
| `@venizia/ignis-helpers` | Utility helpers - logging, cron, Redis, queues, storage |
|
|
37
38
|
| `@venizia/ignis-inversion` | Dependency Injection & IoC container |
|
|
38
39
|
| `@venizia/dev-configs` | Shared ESLint, Prettier, TypeScript configurations |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@venizia/ignis-docs",
|
|
3
|
-
"version": "0.0.1
|
|
3
|
+
"version": "0.0.1",
|
|
4
4
|
"description": "Documentation and MCP Server for Ignis Framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ignis",
|
|
@@ -111,7 +111,7 @@
|
|
|
111
111
|
"@braintree/sanitize-url": "^7.1.1",
|
|
112
112
|
"@types/bun": "^1.3.4",
|
|
113
113
|
"@types/glob": "^8.1.0",
|
|
114
|
-
"@venizia/dev-configs": "^0.0.
|
|
114
|
+
"@venizia/dev-configs": "^0.0.2",
|
|
115
115
|
"eslint": "^9.36.0",
|
|
116
116
|
"glob": "^10.4.2",
|
|
117
117
|
"prettier": "^3.6.2",
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Initial Architecture
|
|
3
|
+
description: Documentation of the original Ignis architecture before the Model-Repository-DataSource refactor
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Changelog - 2025-12-16
|
|
7
|
+
|
|
8
|
+
## Initial Architecture (Pre-Refactor)
|
|
9
|
+
|
|
10
|
+
This documents the original architecture of the Ignis framework before the Model-Repository-DataSource refactor. This version required manual schema registration and explicit constructor parameters.
|
|
11
|
+
|
|
12
|
+
## Overview
|
|
13
|
+
|
|
14
|
+
- **Model Definition**: Three separate declarations (table, relations, class) for each model.
|
|
15
|
+
- **DataSource Definition**: Required manual schema registration.
|
|
16
|
+
- **Repository Definition**: Required explicit constructor injection.
|
|
17
|
+
|
|
18
|
+
## Architecture Pattern
|
|
19
|
+
|
|
20
|
+
### Model Definition
|
|
21
|
+
|
|
22
|
+
Models were defined in three separate steps:
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
// Step 1: Define table schema
|
|
26
|
+
const TABLE_NAME = 'Configuration';
|
|
27
|
+
|
|
28
|
+
export const configurationTable = pgTable(TABLE_NAME, {
|
|
29
|
+
...generateIdColumnDefs({ id: { dataType: 'string' } }),
|
|
30
|
+
...generateTzColumnDefs(),
|
|
31
|
+
code: text('code').notNull(),
|
|
32
|
+
group: text('group').notNull(),
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Step 2: Define relations separately
|
|
36
|
+
export const configurationRelations = createRelations({
|
|
37
|
+
source: configurationTable,
|
|
38
|
+
relations: [
|
|
39
|
+
{
|
|
40
|
+
name: 'creator',
|
|
41
|
+
type: RelationTypes.ONE,
|
|
42
|
+
schema: userTable,
|
|
43
|
+
metadata: {
|
|
44
|
+
fields: [configurationTable.createdBy],
|
|
45
|
+
references: [userTable.id],
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Step 3: Create model class
|
|
52
|
+
@model({ type: 'entity', skipMigrate: false })
|
|
53
|
+
export class Configuration extends BaseEntity<typeof configurationTable> {
|
|
54
|
+
static readonly TABLE_NAME = Configuration.name;
|
|
55
|
+
|
|
56
|
+
constructor() {
|
|
57
|
+
super({
|
|
58
|
+
name: Configuration.TABLE_NAME,
|
|
59
|
+
schema: configurationTable,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### DataSource Definition
|
|
66
|
+
|
|
67
|
+
DataSources required manual schema registration:
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
@datasource({})
|
|
71
|
+
export class PostgresDataSource extends BaseDataSource<TNodePostgresConnector, IDSConfigs> {
|
|
72
|
+
constructor() {
|
|
73
|
+
super({
|
|
74
|
+
name: PostgresDataSource.name,
|
|
75
|
+
driver: 'node-postgres',
|
|
76
|
+
config: { /* connection config */ },
|
|
77
|
+
|
|
78
|
+
// Manual schema registration - verbose and error-prone
|
|
79
|
+
schema: Object.assign(
|
|
80
|
+
{},
|
|
81
|
+
{
|
|
82
|
+
[User.TABLE_NAME]: userTable,
|
|
83
|
+
[Configuration.TABLE_NAME]: configurationTable,
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
userRelations: userRelations.relations,
|
|
87
|
+
configurationRelations: configurationRelations.relations,
|
|
88
|
+
},
|
|
89
|
+
),
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Repository Definition
|
|
96
|
+
|
|
97
|
+
Repositories required explicit constructor injection:
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
@repository({})
|
|
101
|
+
export class ConfigurationRepository extends DefaultCRUDRepository<typeof configurationTable> {
|
|
102
|
+
constructor(@inject({ key: 'datasources.PostgresDataSource' }) dataSource: IDataSource) {
|
|
103
|
+
super({
|
|
104
|
+
dataSource,
|
|
105
|
+
entityClass: Configuration,
|
|
106
|
+
relations: configurationRelations.definitions,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Pain Points
|
|
113
|
+
|
|
114
|
+
- **Verbose Model Definition**: Three separate declarations (table, relations, class) for each model
|
|
115
|
+
- **Manual Schema Registration**: DataSource required explicit registration of every model and relation
|
|
116
|
+
- **Unclear Repository Role**: Repository just wrapped datasource without defining the model-datasource binding
|
|
117
|
+
- **Declaration Order Issues**: Had to declare table before relations, relations before class
|
|
118
|
+
- **No Auto-Discovery**: Adding a new model required updates in multiple places
|
|
119
|
+
- **Tight Coupling**: Changes to model structure required updates in datasource configuration
|
|
120
|
+
|
|
121
|
+
## File Structure
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
src/
|
|
125
|
+
├── models/
|
|
126
|
+
│ └── entities/
|
|
127
|
+
│ ├── user.model.ts # Table + Relations + Class
|
|
128
|
+
│ └── configuration.model.ts # Table + Relations + Class
|
|
129
|
+
├── datasources/
|
|
130
|
+
│ └── postgres.datasource.ts # Manual schema assembly
|
|
131
|
+
└── repositories/
|
|
132
|
+
├── user.repository.ts # Explicit constructor injection
|
|
133
|
+
└── configuration.repository.ts
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Dependencies
|
|
137
|
+
|
|
138
|
+
- `@venizia/ignis-helpers`: Core utilities and types
|
|
139
|
+
- `@venizia/ignis-inversion`: Dependency injection
|
|
140
|
+
- `drizzle-orm`: ORM layer
|
|
141
|
+
- `drizzle-zod`: Schema validation
|
|
142
|
+
|
|
143
|
+
## No Breaking Changes
|
|
144
|
+
|
|
145
|
+
This document describes the initial state of the architecture.
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Model-Repository-DataSource Refactor
|
|
3
|
+
description: Major architecture refactor following Loopback 4 patterns with auto-discovery
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Changelog - 2025-12-16
|
|
7
|
+
|
|
8
|
+
## Model-Repository-DataSource Architecture Refactor
|
|
9
|
+
|
|
10
|
+
Major architecture refactor following Loopback 4 patterns with auto-discovery.
|
|
11
|
+
|
|
12
|
+
## Overview
|
|
13
|
+
|
|
14
|
+
- **Self-Contained Models**: Model is self-contained with schema and relations.
|
|
15
|
+
- **Repository Auto-Resolution**: Repository connects Model to DataSource (defines the binding).
|
|
16
|
+
- **DataSource Auto-Discovery**: DataSource auto-discovers schemas from registered repositories.
|
|
17
|
+
|
|
18
|
+
## Breaking Changes
|
|
19
|
+
|
|
20
|
+
> [!WARNING]
|
|
21
|
+
> This section contains changes that require migration or manual updates to existing code.
|
|
22
|
+
|
|
23
|
+
### 1. Model Static Properties
|
|
24
|
+
|
|
25
|
+
**Before:**
|
|
26
|
+
```typescript
|
|
27
|
+
const userTable = pgTable('User', {...});
|
|
28
|
+
const userRelations = createRelations({...});
|
|
29
|
+
|
|
30
|
+
@model({ type: 'entity' })
|
|
31
|
+
export class User extends BaseEntity<typeof userTable> {
|
|
32
|
+
constructor() {
|
|
33
|
+
super({ name: 'User', schema: userTable });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**After:**
|
|
39
|
+
```typescript
|
|
40
|
+
@model({ type: 'entity' })
|
|
41
|
+
export class User extends BaseEntity<typeof User.schema> {
|
|
42
|
+
static override schema = pgTable('User', {...});
|
|
43
|
+
static override relations = () => ({...});
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 2. Repository Constructor
|
|
48
|
+
|
|
49
|
+
**Before:**
|
|
50
|
+
```typescript
|
|
51
|
+
@repository({})
|
|
52
|
+
export class UserRepository extends DefaultCRUDRepository<typeof userTable> {
|
|
53
|
+
constructor(@inject({ key: 'datasources.PostgresDataSource' }) dataSource: IDataSource) {
|
|
54
|
+
super({ dataSource, entityClass: User, relations: userRelations.definitions });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**After:**
|
|
60
|
+
```typescript
|
|
61
|
+
@repository({ model: User, dataSource: PostgresDataSource })
|
|
62
|
+
export class UserRepository extends DefaultCRUDRepository<typeof User.schema> {
|
|
63
|
+
// No constructor needed!
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 3. DataSource Schema
|
|
68
|
+
|
|
69
|
+
**Before:**
|
|
70
|
+
```typescript
|
|
71
|
+
@datasource({})
|
|
72
|
+
export class PostgresDataSource extends BaseDataSource {
|
|
73
|
+
constructor() {
|
|
74
|
+
super({
|
|
75
|
+
name: PostgresDataSource.name,
|
|
76
|
+
driver: 'node-postgres',
|
|
77
|
+
config: {...},
|
|
78
|
+
schema: { User: userTable, userRelations: userRelations.relations, ... },
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**After:**
|
|
85
|
+
```typescript
|
|
86
|
+
@datasource({ driver: 'node-postgres' })
|
|
87
|
+
export class PostgresDataSource extends BaseDataSource {
|
|
88
|
+
constructor() {
|
|
89
|
+
super({
|
|
90
|
+
name: PostgresDataSource.name,
|
|
91
|
+
driver: 'node-postgres',
|
|
92
|
+
config: {...},
|
|
93
|
+
// NO schema - auto-discovered!
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## New Features
|
|
100
|
+
|
|
101
|
+
### Self-Contained Models
|
|
102
|
+
|
|
103
|
+
**File:** `packages/core/src/base/models/base.ts`
|
|
104
|
+
|
|
105
|
+
**Problem:** Models were defined in three separate declarations (table, relations, class).
|
|
106
|
+
|
|
107
|
+
**Solution:** Models now define schema and relations as static properties.
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
@model({ type: 'entity' })
|
|
111
|
+
export class Configuration extends BaseEntity<typeof Configuration.schema> {
|
|
112
|
+
static override schema = pgTable('Configuration', {
|
|
113
|
+
...generateIdColumnDefs({ id: { dataType: 'string' } }),
|
|
114
|
+
...generateTzColumnDefs(),
|
|
115
|
+
code: text('code').notNull(),
|
|
116
|
+
group: text('group').notNull(),
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
static override relations = () => ({
|
|
120
|
+
creator: {
|
|
121
|
+
type: 'one' as const,
|
|
122
|
+
target: () => User,
|
|
123
|
+
fields: [Configuration.schema.createdBy],
|
|
124
|
+
references: () => [User.schema.id],
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**Benefits:**
|
|
131
|
+
- Simplified Model Definition
|
|
132
|
+
- Better Type Safety
|
|
133
|
+
|
|
134
|
+
### Repository Auto-Resolution
|
|
135
|
+
|
|
136
|
+
**File:** `packages/core/src/base/repositories/core/base.ts`
|
|
137
|
+
|
|
138
|
+
**Problem:** Repositories required explicit constructor injection and parameter passing.
|
|
139
|
+
|
|
140
|
+
**Solution:** Repositories now use `@repository` decorator for model-datasource binding.
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
@repository({
|
|
144
|
+
model: Configuration,
|
|
145
|
+
dataSource: PostgresDataSource,
|
|
146
|
+
})
|
|
147
|
+
export class ConfigurationRepository extends DefaultCRUDRepository<typeof Configuration.schema> {
|
|
148
|
+
// No constructor needed!
|
|
149
|
+
|
|
150
|
+
async findByCode(code: string) {
|
|
151
|
+
return this.findOne({ filter: { where: { code } } });
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Benefits:**
|
|
157
|
+
- Reduced Boilerplate
|
|
158
|
+
- Clear Repository Role
|
|
159
|
+
|
|
160
|
+
### DataSource Auto-Discovery
|
|
161
|
+
|
|
162
|
+
**File:** `packages/core/src/base/datasources/base.ts`
|
|
163
|
+
|
|
164
|
+
**Problem:** DataSources required manual schema registration of every model and relation.
|
|
165
|
+
|
|
166
|
+
**Solution:** DataSources automatically discover their schema from repository bindings.
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
@datasource({ driver: 'node-postgres' })
|
|
170
|
+
export class PostgresDataSource extends BaseDataSource<TNodePostgresConnector, IDSConfigs> {
|
|
171
|
+
constructor() {
|
|
172
|
+
super({
|
|
173
|
+
name: PostgresDataSource.name,
|
|
174
|
+
driver: 'node-postgres',
|
|
175
|
+
config: { /* connection config */ },
|
|
176
|
+
// NO schema property - auto-discovered!
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
override configure(): ValueOrPromise<void> {
|
|
181
|
+
const schema = this.getSchema(); // Auto-discovers from @repository bindings
|
|
182
|
+
this.connector = drizzle({ client: new Pool(this.settings), schema });
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**Benefits:**
|
|
188
|
+
- No Manual Schema Registration
|
|
189
|
+
- Decoupled Models and DataSources
|
|
190
|
+
|
|
191
|
+
## Files Changed
|
|
192
|
+
|
|
193
|
+
### Core Package (`packages/core`)
|
|
194
|
+
|
|
195
|
+
| File | Changes |
|
|
196
|
+
|------|---------|
|
|
197
|
+
| `src/base/models/base.ts` | Added static `schema`, `relations`, `TABLE_NAME` |
|
|
198
|
+
| `src/base/datasources/base.ts` | Added auto-discovery via `buildAutoDiscoveredSchema()` |
|
|
199
|
+
| `src/base/repositories/core/base.ts` | Added lazy resolution, static container reference |
|
|
200
|
+
| `src/base/repositories/core/readable.ts` | Made constructor opts optional |
|
|
201
|
+
| `src/base/repositories/core/persistable.ts` | Made constructor opts optional |
|
|
202
|
+
| `src/base/repositories/core/default-crud.ts` | Added documentation |
|
|
203
|
+
| `src/base/metadata/persistents.ts` | Updated decorators for auto-discovery |
|
|
204
|
+
| `src/base/applications/base.ts` | Added `AbstractRepository.setContainer(this)` |
|
|
205
|
+
| `src/components/static-asset/models/base.model.ts` | Updated to new pattern |
|
|
206
|
+
|
|
207
|
+
### Helpers Package (`packages/helpers`)
|
|
208
|
+
|
|
209
|
+
| File | Changes |
|
|
210
|
+
|------|---------|
|
|
211
|
+
| `src/helpers/inversion/common/types.ts` | Added `IModelMetadata`, `IRelationDefinition`, `IModelStatic`, `IRepositoryMetadata`, `IRepositoryBinding` |
|
|
212
|
+
| `src/helpers/inversion/registry.ts` | Added `registerModel`, `registerRepositoryBinding`, `buildDataSourceSchema` |
|
|
213
|
+
|
|
214
|
+
### Examples (`examples/vert`)
|
|
215
|
+
|
|
216
|
+
| File | Changes |
|
|
217
|
+
|------|---------|
|
|
218
|
+
| `src/models/entities/user.model.ts` | Updated to static schema pattern |
|
|
219
|
+
| `src/models/entities/configuration.model.ts` | Updated to static schema pattern |
|
|
220
|
+
| `src/datasources/postgres.datasource.ts` | Removed manual schema registration |
|
|
221
|
+
| `src/repositories/user.repository.ts` | Updated to use `@repository` decorator |
|
|
222
|
+
| `src/repositories/configuration.repository.ts` | Updated to use `@repository` decorator |
|
|
223
|
+
|
|
224
|
+
## Migration Guide
|
|
225
|
+
|
|
226
|
+
> [!NOTE]
|
|
227
|
+
> Follow these steps if you're upgrading from a previous version.
|
|
228
|
+
|
|
229
|
+
### Step 1: Update Models
|
|
230
|
+
|
|
231
|
+
Update models to use static properties for schema and relations.
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
// From
|
|
235
|
+
@model({ type: 'entity' })
|
|
236
|
+
export class User extends BaseEntity<typeof userTable> {
|
|
237
|
+
constructor() {
|
|
238
|
+
super({ name: 'User', schema: userTable });
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// To
|
|
243
|
+
@model({ type: 'entity' })
|
|
244
|
+
export class User extends BaseEntity<typeof User.schema> {
|
|
245
|
+
static override schema = pgTable('User', {...});
|
|
246
|
+
static override relations = () => ({...});
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Step 2: Update Repositories
|
|
251
|
+
|
|
252
|
+
Update repositories to use the `@repository` decorator with `model` and `dataSource`.
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
// From
|
|
256
|
+
@repository({})
|
|
257
|
+
export class UserRepository extends DefaultCRUDRepository<typeof userTable> {
|
|
258
|
+
constructor(@inject({ key: 'datasources.PostgresDataSource' }) dataSource: IDataSource) {
|
|
259
|
+
super({ dataSource, entityClass: User, relations: userRelations.definitions });
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// To
|
|
264
|
+
@repository({ model: User, dataSource: PostgresDataSource })
|
|
265
|
+
export class UserRepository extends DefaultCRUDRepository<typeof User.schema> {
|
|
266
|
+
// No constructor needed!
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### Step 3: Update DataSources
|
|
271
|
+
|
|
272
|
+
Remove manual schema registration from DataSources.
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
// From
|
|
276
|
+
@datasource({})
|
|
277
|
+
export class PostgresDataSource extends BaseDataSource {
|
|
278
|
+
constructor() {
|
|
279
|
+
super({
|
|
280
|
+
name: PostgresDataSource.name,
|
|
281
|
+
driver: 'node-postgres',
|
|
282
|
+
config: {...},
|
|
283
|
+
schema: { User: userTable, userRelations: userRelations.relations, ... },
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// To
|
|
289
|
+
@datasource({ driver: 'node-postgres' })
|
|
290
|
+
export class PostgresDataSource extends BaseDataSource {
|
|
291
|
+
constructor() {
|
|
292
|
+
super({
|
|
293
|
+
name: PostgresDataSource.name,
|
|
294
|
+
driver: 'node-postgres',
|
|
295
|
+
config: {...},
|
|
296
|
+
// NO schema - auto-discovered!
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
```
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Inversion of Control Refactor
|
|
3
|
+
description: Dependency Injection system extracted to standalone package
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Changelog - 2025-12-17
|
|
7
|
+
|
|
8
|
+
## Inversion of Control Refactor
|
|
9
|
+
|
|
10
|
+
The Dependency Injection (DI) system has been extracted from `packages/helpers` into a standalone package `@venizia/ignis-inversion`.
|
|
11
|
+
|
|
12
|
+
## Overview
|
|
13
|
+
|
|
14
|
+
- **New Package**: `@venizia/ignis-inversion` created.
|
|
15
|
+
- **Separation of Concerns**: `inversion` package has zero dependencies on the rest of the framework (except `lodash`, `reflect-metadata`, `zod`).
|
|
16
|
+
- **Refactor**: `packages/core` now imports DI primitives from `@venizia/ignis-inversion`.
|
|
17
|
+
|
|
18
|
+
## Breaking Changes
|
|
19
|
+
|
|
20
|
+
> [!WARNING]
|
|
21
|
+
> This section contains changes that require migration or manual updates to existing code.
|
|
22
|
+
|
|
23
|
+
### 1. Deep Imports
|
|
24
|
+
|
|
25
|
+
**Before:**
|
|
26
|
+
```typescript
|
|
27
|
+
import { inject } from '@venizia/ignis-helpers/src/helpers/inversion';
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**After:**
|
|
31
|
+
```typescript
|
|
32
|
+
import { inject } from '@venizia/ignis-inversion';
|
|
33
|
+
// OR via re-exports (if available)
|
|
34
|
+
import { inject } from '@venizia/ignis';
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Deep imports to `helpers/inversion` within `@venizia/ignis-helpers` will no longer work as the directory has been removed.
|
|
38
|
+
|
|
39
|
+
## Files Changed
|
|
40
|
+
|
|
41
|
+
### Core Package (`packages/core`)
|
|
42
|
+
|
|
43
|
+
| File | Changes |
|
|
44
|
+
|------|---------|
|
|
45
|
+
| `src/helpers/inversion/` | Refactored to re-export from `@venizia/ignis-inversion` and add core extensions |
|
|
46
|
+
| `src/mixins/server-config.mixin.ts` | Removed |
|
|
47
|
+
|
|
48
|
+
### Helpers Package (`packages/helpers`)
|
|
49
|
+
|
|
50
|
+
| File | Changes |
|
|
51
|
+
|------|---------|
|
|
52
|
+
| `src/helpers/inversion/` | **Deleted** (Moved to new package) |
|
|
53
|
+
|
|
54
|
+
### Inversion Package (`packages/inversion`)
|
|
55
|
+
|
|
56
|
+
| File | Changes |
|
|
57
|
+
|------|---------|
|
|
58
|
+
| `package.json` | **Created** |
|
|
59
|
+
| `src/` | **Created** (Content moved from helpers) |
|
|
60
|
+
|
|
61
|
+
### Examples (`examples/vert`)
|
|
62
|
+
|
|
63
|
+
| File | Changes |
|
|
64
|
+
|------|---------|
|
|
65
|
+
| `package.json` | Added `@venizia/ignis-inversion` dependency |
|
|
66
|
+
|
|
67
|
+
## Migration Guide
|
|
68
|
+
|
|
69
|
+
> [!NOTE]
|
|
70
|
+
> Follow these steps if you're upgrading from a previous version.
|
|
71
|
+
|
|
72
|
+
### Step 1: Update Imports
|
|
73
|
+
|
|
74
|
+
Check for any deep imports to `packages/helpers/src/helpers/inversion` and update them to point to `@venizia/ignis-inversion`.
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
// Find
|
|
78
|
+
from '@venizia/ignis-helpers/src/helpers/inversion'
|
|
79
|
+
|
|
80
|
+
// Replace with
|
|
81
|
+
from '@venizia/ignis-inversion'
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Step 2: Install New Package
|
|
85
|
+
|
|
86
|
+
If you are using the DI system directly, add the new package to your dependencies.
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
npm install @venizia/ignis-inversion
|
|
90
|
+
```
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Performance Optimizations
|
|
3
|
+
description: Repository layer performance improvements reducing GC pressure and improving query speed
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Changelog - 2025-12-18
|
|
7
|
+
|
|
8
|
+
## Performance Optimizations
|
|
9
|
+
|
|
10
|
+
This update focuses on performance improvements for the repository layer, reducing GC pressure and improving query execution speed.
|
|
11
|
+
|
|
12
|
+
## Overview
|
|
13
|
+
|
|
14
|
+
- **WeakMap Cache**: `DrizzleFilterBuilder` now caches `getTableColumns()` results.
|
|
15
|
+
- **Core API for Flat Queries**: `ReadableRepository` uses faster Drizzle Core API when possible.
|
|
16
|
+
- **Static schemaFactory Singleton**: `BaseEntity` shares a single `schemaFactory` instance across all entities.
|
|
17
|
+
- **Async/Await Refactor**: Removed redundant Promise wrappers from repository methods.
|
|
18
|
+
|
|
19
|
+
## Performance Improvements
|
|
20
|
+
|
|
21
|
+
### 1. WeakMap Cache for Filter Builder
|
|
22
|
+
|
|
23
|
+
**File:** `packages/core/src/base/repositories/operators/filter.ts`
|
|
24
|
+
|
|
25
|
+
**Problem:** `getTableColumns()` was called on every filter operation, causing repeated reflection overhead.
|
|
26
|
+
|
|
27
|
+
**Solution:** Added static WeakMap cache that stores column metadata per schema.
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
export class DrizzleFilterBuilder extends BaseHelper {
|
|
31
|
+
// Static cache shared across all instances
|
|
32
|
+
private static columnCache = new WeakMap<
|
|
33
|
+
TTableSchemaWithId,
|
|
34
|
+
ReturnType<typeof getTableColumns>
|
|
35
|
+
>();
|
|
36
|
+
|
|
37
|
+
private getColumns<Schema extends TTableSchemaWithId>(schema: Schema) {
|
|
38
|
+
let columns = DrizzleFilterBuilder.columnCache.get(schema);
|
|
39
|
+
if (!columns) {
|
|
40
|
+
columns = getTableColumns(schema);
|
|
41
|
+
DrizzleFilterBuilder.columnCache.set(schema, columns);
|
|
42
|
+
}
|
|
43
|
+
return columns;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Benefits:**
|
|
49
|
+
- First call: `getTableColumns(schema)` → cached
|
|
50
|
+
- Subsequent calls: Retrieved from WeakMap (O(1) lookup)
|
|
51
|
+
- WeakMap allows garbage collection when schema is no longer referenced
|
|
52
|
+
|
|
53
|
+
### 2. Core API for Flat Queries
|
|
54
|
+
|
|
55
|
+
**File:** `packages/core/src/base/repositories/core/readable.ts`
|
|
56
|
+
|
|
57
|
+
**Problem:** All queries used Drizzle's Query API, which has overhead for relational mapping even when not needed.
|
|
58
|
+
|
|
59
|
+
**Solution:** Automatically use Drizzle Core API for flat queries (no relations, no field selection).
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
// Automatic optimization - no code changes needed
|
|
63
|
+
const users = await repo.find({
|
|
64
|
+
filter: {
|
|
65
|
+
where: { status: 'active' },
|
|
66
|
+
limit: 10,
|
|
67
|
+
order: ['createdAt DESC'],
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
// Uses: db.select().from(table).where(...).orderBy(...).limit(10)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
| Scenario | Improvement |
|
|
74
|
+
|----------|-------------|
|
|
75
|
+
| Simple `find()` queries | ~15-20% faster |
|
|
76
|
+
|
|
77
|
+
### 3. Static schemaFactory Singleton
|
|
78
|
+
|
|
79
|
+
**File:** `packages/core/src/base/models/base.ts`
|
|
80
|
+
|
|
81
|
+
**Problem:** New `schemaFactory` was created for every `BaseEntity` instance, causing memory overhead.
|
|
82
|
+
|
|
83
|
+
**Solution:** Lazy singleton pattern shared across all instances.
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
// After - shared singleton
|
|
87
|
+
private static _schemaFactory?: ReturnType<typeof createSchemaFactory>;
|
|
88
|
+
protected static get schemaFactory(): ReturnType<typeof createSchemaFactory> {
|
|
89
|
+
return (BaseEntity._schemaFactory ??= createSchemaFactory());
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Benefits:**
|
|
94
|
+
- Single instance for all entities
|
|
95
|
+
- Lazy initialization (created on first use)
|
|
96
|
+
- Reduced memory footprint
|
|
97
|
+
|
|
98
|
+
### 4. Async/Await Refactor
|
|
99
|
+
|
|
100
|
+
**Files:** `packages/core/src/base/repositories/core/readable.ts`, `packages/core/src/base/repositories/core/persistable.ts`
|
|
101
|
+
|
|
102
|
+
**Problem:** Every CRUD method wrapped existing promises in `new Promise()`.
|
|
103
|
+
|
|
104
|
+
**Solution:** Direct async/await.
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
// After - Clean and efficient
|
|
108
|
+
const count = await this.connector.$count(this.entity.schema, where);
|
|
109
|
+
return { count };
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Benefits:**
|
|
113
|
+
- Eliminates extra microtask queue entries
|
|
114
|
+
- Reduces ~200-400 bytes memory per Promise on V8
|
|
115
|
+
- Cleaner stack traces for debugging
|
|
116
|
+
|
|
117
|
+
## Files Changed
|
|
118
|
+
|
|
119
|
+
### Core Package (`packages/core`)
|
|
120
|
+
|
|
121
|
+
| File | Changes |
|
|
122
|
+
|------|---------|
|
|
123
|
+
| `src/base/repositories/operators/filter.ts` | WeakMap cache for `getTableColumns()` |
|
|
124
|
+
| `src/base/repositories/core/readable.ts` | Core API optimization, async/await refactor |
|
|
125
|
+
| `src/base/repositories/core/persistable.ts` | Async/await refactor |
|
|
126
|
+
| `src/base/models/base.ts` | Static schemaFactory singleton |
|
|
127
|
+
|
|
128
|
+
## No Breaking Changes
|
|
129
|
+
|
|
130
|
+
All changes are internal optimizations. No API changes or migration required.
|