@venizia/ignis-docs 0.0.1-7 → 0.0.1-9
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/package.json +12 -12
- package/wiki/changelogs/2025-12-17-refactor.md +22 -0
- package/wiki/changelogs/2025-12-18-performance-optimizations.md +192 -0
- package/wiki/changelogs/2025-12-18-repository-validation-security.md +445 -0
- package/wiki/changelogs/index.md +22 -0
- package/wiki/changelogs/v0.0.1-7-initial-architecture.md +137 -0
- package/wiki/changelogs/v0.0.1-8-model-repo-datasource-refactor.md +278 -0
- package/wiki/get-started/5-minute-quickstart.md +1 -1
- package/wiki/get-started/best-practices/api-usage-examples.md +12 -8
- package/wiki/get-started/best-practices/common-pitfalls.md +2 -2
- package/wiki/get-started/best-practices/data-modeling.md +14 -20
- package/wiki/get-started/building-a-crud-api.md +60 -75
- package/wiki/get-started/core-concepts/controllers.md +14 -14
- package/wiki/get-started/core-concepts/persistent.md +110 -130
- package/wiki/get-started/quickstart.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 +5 -5
- package/wiki/references/base/models.md +398 -28
- package/wiki/references/base/repositories.md +475 -22
- package/wiki/references/components/authentication.md +224 -7
- package/wiki/references/components/health-check.md +1 -1
- package/wiki/references/components/swagger.md +1 -1
- package/wiki/references/helpers/inversion.md +8 -3
- package/wiki/references/src-details/core.md +6 -5
- package/wiki/references/src-details/inversion.md +4 -4
- package/wiki/references/utilities/request.md +16 -7
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
# Changelog - 2025-12-18
|
|
2
|
+
|
|
3
|
+
## Repository Validation & Security Improvements
|
|
4
|
+
|
|
5
|
+
This update adds strict validation to the `@repository` decorator and fixes several security vulnerabilities in the filter operators.
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
- **@repository Decorator**: Now requires both `model` AND `dataSource` for schema auto-discovery
|
|
10
|
+
- **Constructor Validation**: First parameter must extend `AbstractDataSource` (enforced via reflection)
|
|
11
|
+
- **DataSource Auto-Discovery**: Schema is automatically built from `@repository` bindings - no manual merging needed!
|
|
12
|
+
- **Filter Security**: Fixed empty IN array bypass, invalid column handling, BETWEEN validation
|
|
13
|
+
- **PostgreSQL Compatibility**: REGEXP now uses PostgreSQL POSIX operators
|
|
14
|
+
- **UUID Generation**: Now uses native PostgreSQL `uuid` type with `gen_random_uuid()`
|
|
15
|
+
|
|
16
|
+
## Breaking Changes
|
|
17
|
+
|
|
18
|
+
### 1. Repository Constructor Signature Changed
|
|
19
|
+
|
|
20
|
+
**This is a major breaking change.** The constructor signature for all repository classes has changed.
|
|
21
|
+
|
|
22
|
+
**Before:**
|
|
23
|
+
```typescript
|
|
24
|
+
constructor(opts: {
|
|
25
|
+
entityClass: TClass<BaseEntity<EntitySchema>>;
|
|
26
|
+
relations: { [relationName: string]: TRelationConfig };
|
|
27
|
+
dataSource: IDataSource;
|
|
28
|
+
})
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**After:**
|
|
32
|
+
```typescript
|
|
33
|
+
constructor(ds?: IDataSource, opts?: { entityClass?: TClass<BaseEntity<EntitySchema>> })
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Key changes:**
|
|
37
|
+
- DataSource is now the first parameter (auto-injected from `@repository` decorator)
|
|
38
|
+
- `relations` parameter removed - now auto-resolved from entity's static `relations` property
|
|
39
|
+
- Both parameters are optional when using `@repository` decorator with `model` and `dataSource`
|
|
40
|
+
|
|
41
|
+
**Migration:**
|
|
42
|
+
```typescript
|
|
43
|
+
// Before
|
|
44
|
+
@repository({})
|
|
45
|
+
export class UserRepository extends DefaultCRUDRepository<typeof User.schema> {
|
|
46
|
+
constructor(
|
|
47
|
+
@inject({ key: 'datasources.PostgresDataSource' }) ds: PostgresDataSource,
|
|
48
|
+
) {
|
|
49
|
+
super({
|
|
50
|
+
entityClass: User,
|
|
51
|
+
relations: userRelations.definitions,
|
|
52
|
+
dataSource: ds,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// After - Zero boilerplate
|
|
58
|
+
@repository({ model: User, dataSource: PostgresDataSource })
|
|
59
|
+
export class UserRepository extends DefaultCRUDRepository<typeof User.schema> {
|
|
60
|
+
// No constructor needed!
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// After - With explicit constructor
|
|
64
|
+
@repository({ model: User, dataSource: PostgresDataSource })
|
|
65
|
+
export class UserRepository extends DefaultCRUDRepository<typeof User.schema> {
|
|
66
|
+
constructor(
|
|
67
|
+
@inject({ key: 'datasources.PostgresDataSource' }) ds: PostgresDataSource,
|
|
68
|
+
) {
|
|
69
|
+
super(ds); // Just pass dataSource, entity and relations auto-resolved
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 2. @repository Decorator Requires Both `model` AND `dataSource`
|
|
75
|
+
|
|
76
|
+
**Before (would silently fail to register model):**
|
|
77
|
+
```typescript
|
|
78
|
+
// ❌ This would not register User for schema auto-discovery
|
|
79
|
+
@repository({ model: User })
|
|
80
|
+
export class UserRepository extends DefaultCRUDRepository<typeof User.schema> {}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**After (throws error):**
|
|
84
|
+
```typescript
|
|
85
|
+
// Error: [@repository][UserRepository] Invalid metadata | Missing 'dataSource'
|
|
86
|
+
@repository({ model: User })
|
|
87
|
+
export class UserRepository extends DefaultCRUDRepository<typeof User.schema> {}
|
|
88
|
+
|
|
89
|
+
// ✅ Correct usage
|
|
90
|
+
@repository({ model: User, dataSource: PostgresDataSource })
|
|
91
|
+
export class UserRepository extends DefaultCRUDRepository<typeof User.schema> {}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### 2. Constructor First Parameter Must Be DataSource Type
|
|
95
|
+
|
|
96
|
+
When using explicit `@inject` in constructor, the first parameter **must** extend `AbstractDataSource`:
|
|
97
|
+
|
|
98
|
+
**Before (would work with wrong type):**
|
|
99
|
+
```typescript
|
|
100
|
+
@repository({ model: User, dataSource: PostgresDataSource })
|
|
101
|
+
export class UserRepository extends ReadableRepository<typeof User.schema> {
|
|
102
|
+
constructor(
|
|
103
|
+
@inject({ key: 'datasources.PostgresDataSource' })
|
|
104
|
+
dataSource: any, // ❌ This would compile but is wrong
|
|
105
|
+
) {
|
|
106
|
+
super(dataSource);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**After (enforced at decorator time):**
|
|
112
|
+
```typescript
|
|
113
|
+
@repository({ model: User, dataSource: PostgresDataSource })
|
|
114
|
+
export class UserRepository extends ReadableRepository<typeof User.schema> {
|
|
115
|
+
constructor(
|
|
116
|
+
@inject({ key: 'datasources.PostgresDataSource' })
|
|
117
|
+
dataSource: PostgresDataSource, // ✅ Must be concrete DataSource type
|
|
118
|
+
) {
|
|
119
|
+
super(dataSource);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### 3. Filter Column Validation
|
|
125
|
+
|
|
126
|
+
Invalid column names now throw errors instead of being silently ignored:
|
|
127
|
+
|
|
128
|
+
**Before:**
|
|
129
|
+
```typescript
|
|
130
|
+
// Would silently ignore 'invalidColumn'
|
|
131
|
+
await repo.find({ filter: { where: { invalidColumn: 'value' } } });
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**After:**
|
|
135
|
+
```typescript
|
|
136
|
+
// Error: [toWhere] Table: User | Column NOT FOUND | key: 'invalidColumn'
|
|
137
|
+
await repo.find({ filter: { where: { invalidColumn: 'value' } } });
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Security Fixes
|
|
141
|
+
|
|
142
|
+
### Empty IN Array Bypass (CVE-like)
|
|
143
|
+
|
|
144
|
+
**Vulnerability:** Empty `IN` arrays would return `true`, bypassing security filters.
|
|
145
|
+
|
|
146
|
+
**Fix:** Empty `IN` arrays now return `sql\`false\``, correctly matching no records.
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
// Before: WHERE id IN () => true (security bypass!)
|
|
150
|
+
// After: WHERE false => no records (correct)
|
|
151
|
+
await repo.find({ filter: { where: { id: { IN: [] } } } });
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### BETWEEN Validation
|
|
155
|
+
|
|
156
|
+
**Vulnerability:** Invalid `BETWEEN` values could cause unexpected behavior.
|
|
157
|
+
|
|
158
|
+
**Fix:** BETWEEN now validates input is array of exactly 2 elements.
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
// Throws: [BETWEEN] Invalid value: expected array of 2 elements
|
|
162
|
+
await repo.find({ filter: { where: { age: { BETWEEN: [10] } } } });
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### PostgreSQL REGEXP Compatibility
|
|
166
|
+
|
|
167
|
+
**Issue:** MySQL-style REGEXP operator doesn't work in PostgreSQL.
|
|
168
|
+
|
|
169
|
+
**Fix:** Now uses PostgreSQL POSIX regex operators:
|
|
170
|
+
- `REGEXP` → `~` (case-sensitive)
|
|
171
|
+
- `IREGEXP` → `~*` (case-insensitive, new!)
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
// PostgreSQL-compatible regex
|
|
175
|
+
await repo.find({ filter: { where: { name: { REGEXP: '^John' } } } });
|
|
176
|
+
await repo.find({ filter: { where: { name: { IREGEXP: '^john' } } } }); // Case-insensitive
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## New Features
|
|
180
|
+
|
|
181
|
+
### DataSource Schema Auto-Discovery
|
|
182
|
+
|
|
183
|
+
DataSources can now automatically discover their schema from registered `@repository` decorators:
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
// Before: Manual schema merging required
|
|
187
|
+
@datasource({ driver: 'node-postgres' })
|
|
188
|
+
export class PostgresDataSource extends BaseDataSource<...> {
|
|
189
|
+
constructor() {
|
|
190
|
+
super({
|
|
191
|
+
name: PostgresDataSource.name,
|
|
192
|
+
config: { /* ... */ },
|
|
193
|
+
schema: Object.assign({}, // Manual merge!
|
|
194
|
+
{ [User.TABLE_NAME]: userTable },
|
|
195
|
+
userRelations.relations,
|
|
196
|
+
),
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// After: Auto-discovery - no schema needed!
|
|
202
|
+
@datasource({ driver: 'node-postgres' })
|
|
203
|
+
export class PostgresDataSource extends BaseDataSource<...> {
|
|
204
|
+
constructor() {
|
|
205
|
+
super({
|
|
206
|
+
name: PostgresDataSource.name,
|
|
207
|
+
config: { /* ... */ },
|
|
208
|
+
// Schema auto-discovered from @repository decorators!
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
When repositories are defined with `@repository({ model: User, dataSource: PostgresDataSource })`, the framework automatically builds the schema.
|
|
215
|
+
|
|
216
|
+
### Schema Key Mismatch Validation
|
|
217
|
+
|
|
218
|
+
Added helpful error when entity name doesn't match schema keys:
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
// Error: [UserRepository] Schema key mismatch | Entity name 'User' not found in connector.query | Available keys: [Configuration, Post]
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### UUID Type Improvement
|
|
225
|
+
|
|
226
|
+
Changed from `text` type with JS-generated UUID to native PostgreSQL `uuid`:
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
// Before: text('id').primaryKey().$defaultFn(() => crypto.randomUUID())
|
|
230
|
+
// After: uuid('id').defaultRandom().primaryKey()
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Benefits:
|
|
234
|
+
- Native PostgreSQL UUID type (16 bytes vs 36 bytes)
|
|
235
|
+
- Uses `gen_random_uuid()` - no extension required
|
|
236
|
+
- Better indexing performance
|
|
237
|
+
|
|
238
|
+
### Case-Insensitive REGEXP (IREGEXP)
|
|
239
|
+
|
|
240
|
+
Added new `IREGEXP` operator for case-insensitive regex matching:
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
// Case-sensitive (existing)
|
|
244
|
+
await repo.find({ filter: { where: { name: { REGEXP: '^John' } } } });
|
|
245
|
+
|
|
246
|
+
// Case-insensitive (new!)
|
|
247
|
+
await repo.find({ filter: { where: { name: { IREGEXP: '^john' } } } });
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### BaseEntity Static Schema & Relations
|
|
251
|
+
|
|
252
|
+
Models can now define schema and relations as static properties, enabling cleaner syntax:
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
// Before - Constructor-based schema
|
|
256
|
+
@model({ type: 'entity' })
|
|
257
|
+
export class User extends BaseEntity<typeof userTable> {
|
|
258
|
+
constructor() {
|
|
259
|
+
super({ name: 'User', schema: userTable });
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// After - Static schema (recommended)
|
|
264
|
+
@model({ type: 'entity' })
|
|
265
|
+
export class User extends BaseEntity<typeof User.schema> {
|
|
266
|
+
static override schema = userTable;
|
|
267
|
+
static override relations = () => userRelations.definitions;
|
|
268
|
+
static override TABLE_NAME = 'User';
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Relations are now auto-resolved from the entity's static `relations` property - no need to pass them in repository constructor.
|
|
273
|
+
|
|
274
|
+
### Repository Log Option
|
|
275
|
+
|
|
276
|
+
All CRUD operations now support a `log` option for debugging:
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
// Enable logging for a specific operation
|
|
280
|
+
await repo.create({
|
|
281
|
+
data: { name: 'John' },
|
|
282
|
+
options: {
|
|
283
|
+
log: { use: true, level: 'debug' }
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
// Log output: [_create] Executing with opts: { data: [...], options: {...} }
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
**Available on:** `create`, `createAll`, `updateById`, `updateAll`, `deleteById`, `deleteAll`
|
|
291
|
+
|
|
292
|
+
### Improved TypeScript Return Types
|
|
293
|
+
|
|
294
|
+
Repository methods now have better type inference based on `shouldReturn`:
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
// When shouldReturn: false - returns null
|
|
298
|
+
const result1 = await repo.create({
|
|
299
|
+
data: { name: 'John' },
|
|
300
|
+
options: { shouldReturn: false }
|
|
301
|
+
});
|
|
302
|
+
// Type: Promise<TCount & { data: null }>
|
|
303
|
+
|
|
304
|
+
// When shouldReturn: true (default) - returns the entity
|
|
305
|
+
const result2 = await repo.create({
|
|
306
|
+
data: { name: 'John' },
|
|
307
|
+
options: { shouldReturn: true }
|
|
308
|
+
});
|
|
309
|
+
// Type: Promise<TCount & { data: User }>
|
|
310
|
+
|
|
311
|
+
// TypeScript now correctly infers the return type!
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### IEntity Interface
|
|
315
|
+
|
|
316
|
+
New interface for model classes with static schema and relations:
|
|
317
|
+
|
|
318
|
+
```typescript
|
|
319
|
+
interface IEntity<Schema extends TTableSchemaWithId = TTableSchemaWithId> {
|
|
320
|
+
TABLE_NAME?: string;
|
|
321
|
+
schema: Schema;
|
|
322
|
+
relations?: TValueOrResolver<Array<TRelationConfig>>;
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
## Files Changed
|
|
327
|
+
|
|
328
|
+
### Core Package - Models
|
|
329
|
+
- `packages/core/src/base/models/base.ts` - Static schema/relations support, IEntity interface
|
|
330
|
+
- `packages/core/src/base/models/common/types.ts` - IEntity interface definition
|
|
331
|
+
- `packages/core/src/base/models/enrichers/id.enricher.ts` - Native PostgreSQL UUID type
|
|
332
|
+
- `packages/core/src/base/models/enrichers/tz.enricher.ts` - Type naming fix
|
|
333
|
+
|
|
334
|
+
### Core Package - Repositories
|
|
335
|
+
- `packages/core/src/base/repositories/core/base.ts` - Constructor signature change, relations auto-resolution
|
|
336
|
+
- `packages/core/src/base/repositories/core/readable.ts` - Constructor change, getQueryInterface validation
|
|
337
|
+
- `packages/core/src/base/repositories/core/persistable.ts` - Constructor change, log option, TypeScript overloads
|
|
338
|
+
- `packages/core/src/base/repositories/core/default-crud.ts` - Documentation update
|
|
339
|
+
- `packages/core/src/base/repositories/common/types.ts` - TRepositoryLogOptions, TypeScript overloads
|
|
340
|
+
- `packages/core/src/base/repositories/operators/filter.ts` - Column validation, error throwing
|
|
341
|
+
- `packages/core/src/base/repositories/operators/query.ts` - REGEXP/IREGEXP fix, BETWEEN validation, IN empty array fix
|
|
342
|
+
|
|
343
|
+
### Core Package - DataSources & Metadata
|
|
344
|
+
- `packages/core/src/base/datasources/base.ts` - Schema auto-discovery feature
|
|
345
|
+
- `packages/core/src/base/metadata/persistents.ts` - Repository decorator validation, constructor type validation
|
|
346
|
+
|
|
347
|
+
### Examples
|
|
348
|
+
- `examples/vert/src/repositories/user.repository.ts` - Updated to proper types
|
|
349
|
+
- `examples/vert/src/repositories/configuration.repository.ts` - Updated patterns
|
|
350
|
+
- `examples/vert/src/datasources/postgres.datasource.ts` - Using auto-discovery
|
|
351
|
+
- `examples/vert/src/models/entities/user.model.ts` - Static schema pattern
|
|
352
|
+
- `examples/vert/src/models/entities/configuration.model.ts` - Static schema pattern
|
|
353
|
+
|
|
354
|
+
## Migration Guide
|
|
355
|
+
|
|
356
|
+
### Step 1: Update Repository Constructors (BREAKING)
|
|
357
|
+
|
|
358
|
+
The repository constructor signature has changed:
|
|
359
|
+
|
|
360
|
+
```typescript
|
|
361
|
+
// Before
|
|
362
|
+
@repository({})
|
|
363
|
+
export class UserRepository extends DefaultCRUDRepository<typeof User.schema> {
|
|
364
|
+
constructor(
|
|
365
|
+
@inject({ key: 'datasources.PostgresDataSource' }) ds: PostgresDataSource,
|
|
366
|
+
) {
|
|
367
|
+
super({
|
|
368
|
+
entityClass: User,
|
|
369
|
+
relations: userRelations.definitions,
|
|
370
|
+
dataSource: ds,
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// After - Option A: Zero boilerplate (recommended)
|
|
376
|
+
@repository({ model: User, dataSource: PostgresDataSource })
|
|
377
|
+
export class UserRepository extends DefaultCRUDRepository<typeof User.schema> {
|
|
378
|
+
// No constructor needed!
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// After - Option B: With explicit constructor
|
|
382
|
+
@repository({ model: User, dataSource: PostgresDataSource })
|
|
383
|
+
export class UserRepository extends DefaultCRUDRepository<typeof User.schema> {
|
|
384
|
+
constructor(
|
|
385
|
+
@inject({ key: 'datasources.PostgresDataSource' }) ds: PostgresDataSource,
|
|
386
|
+
) {
|
|
387
|
+
super(ds); // Just pass dataSource
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### Step 2: Update Model Definitions (Optional but Recommended)
|
|
393
|
+
|
|
394
|
+
Add static properties to your models for relations auto-resolution:
|
|
395
|
+
|
|
396
|
+
```typescript
|
|
397
|
+
// Before
|
|
398
|
+
@model({ type: 'entity' })
|
|
399
|
+
export class User extends BaseEntity<typeof userTable> {
|
|
400
|
+
constructor() {
|
|
401
|
+
super({ name: 'User', schema: userTable });
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// After - Static properties
|
|
406
|
+
@model({ type: 'entity' })
|
|
407
|
+
export class User extends BaseEntity<typeof User.schema> {
|
|
408
|
+
static override schema = userTable;
|
|
409
|
+
static override relations = () => userRelations.definitions;
|
|
410
|
+
static override TABLE_NAME = 'User';
|
|
411
|
+
}
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
### Step 3: Update @repository Decorators
|
|
415
|
+
|
|
416
|
+
Ensure all `@repository` decorators have both `model` and `dataSource`:
|
|
417
|
+
|
|
418
|
+
```typescript
|
|
419
|
+
// Find and update all occurrences
|
|
420
|
+
@repository({ model: YourModel, dataSource: YourDataSource })
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
### Step 4: Fix Constructor Types
|
|
424
|
+
|
|
425
|
+
If using explicit `@inject`, ensure first parameter has correct type:
|
|
426
|
+
|
|
427
|
+
```typescript
|
|
428
|
+
constructor(
|
|
429
|
+
@inject({ key: 'datasources.YourDataSource' })
|
|
430
|
+
dataSource: YourDataSource, // Not 'any' or 'object'
|
|
431
|
+
) {}
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
### Step 5: Review Filter Queries
|
|
435
|
+
|
|
436
|
+
Check for any queries using:
|
|
437
|
+
- Empty `IN` arrays (now return no results instead of all)
|
|
438
|
+
- Invalid column names (now throw errors)
|
|
439
|
+
- `BETWEEN` with non-array or wrong-length values
|
|
440
|
+
|
|
441
|
+
### Step 6: REGEXP Migration (PostgreSQL Users)
|
|
442
|
+
|
|
443
|
+
Replace MySQL-style REGEXP with PostgreSQL syntax:
|
|
444
|
+
- REGEXP already works (uses `~` operator)
|
|
445
|
+
- For case-insensitive, use new `IREGEXP` (uses `~*` operator)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Changelogs
|
|
2
|
+
|
|
3
|
+
This section tracks the history of significant changes, refactors, and updates to the Ignis framework.
|
|
4
|
+
|
|
5
|
+
## Version History
|
|
6
|
+
|
|
7
|
+
| Version | Date | Description |
|
|
8
|
+
|---------|------|-------------|
|
|
9
|
+
| [2025-12-18 Performance](./2025-12-18-performance-optimizations.md) | 2025-12-18 | Performance Optimizations (Core API, WeakMap Cache) |
|
|
10
|
+
| [2025-12-18](./2025-12-18-repository-validation-security.md) | 2025-12-18 | Repository Validation & Security Improvements |
|
|
11
|
+
| [2025-12-17](./2025-12-17-refactor.md) | 2025-12-17 | Inversion of Control Refactor |
|
|
12
|
+
| [v0.0.1-8](./v0.0.1-8-model-repo-datasource-refactor.md) | 2025-12-16 | Model-Repository-DataSource Architecture Refactor |
|
|
13
|
+
| [v0.0.1-7](./v0.0.1-7-initial-architecture.md) | 2025-12-16 | Initial Architecture (Pre-Refactor) |
|
|
14
|
+
|
|
15
|
+
## How to Read Changelogs
|
|
16
|
+
|
|
17
|
+
Each changelog entry includes:
|
|
18
|
+
- **Overview**: Summary of changes
|
|
19
|
+
- **Breaking Changes**: Any changes that require migration
|
|
20
|
+
- **New Features**: New capabilities added
|
|
21
|
+
- **Files Changed**: List of modified files
|
|
22
|
+
- **Migration Guide**: Steps to update existing code (if applicable)
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# v0.0.1-7 - Initial Architecture (Pre-Refactor)
|
|
2
|
+
|
|
3
|
+
**Release Date**: 2025-12-16
|
|
4
|
+
**Status**: Superseded by v0.0.1-8
|
|
5
|
+
|
|
6
|
+
## Overview
|
|
7
|
+
|
|
8
|
+
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.
|
|
9
|
+
|
|
10
|
+
## Architecture Pattern
|
|
11
|
+
|
|
12
|
+
### Model Definition
|
|
13
|
+
|
|
14
|
+
Models were defined in three separate steps:
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
// Step 1: Define table schema
|
|
18
|
+
const TABLE_NAME = 'Configuration';
|
|
19
|
+
|
|
20
|
+
export const configurationTable = pgTable(TABLE_NAME, {
|
|
21
|
+
...generateIdColumnDefs({ id: { dataType: 'string' } }),
|
|
22
|
+
...generateTzColumnDefs(),
|
|
23
|
+
code: text('code').notNull(),
|
|
24
|
+
group: text('group').notNull(),
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Step 2: Define relations separately
|
|
28
|
+
export const configurationRelations = createRelations({
|
|
29
|
+
source: configurationTable,
|
|
30
|
+
relations: [
|
|
31
|
+
{
|
|
32
|
+
name: 'creator',
|
|
33
|
+
type: RelationTypes.ONE,
|
|
34
|
+
schema: userTable,
|
|
35
|
+
metadata: {
|
|
36
|
+
fields: [configurationTable.createdBy],
|
|
37
|
+
references: [userTable.id],
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Step 3: Create model class
|
|
44
|
+
@model({ type: 'entity', skipMigrate: false })
|
|
45
|
+
export class Configuration extends BaseEntity<typeof configurationTable> {
|
|
46
|
+
static readonly TABLE_NAME = Configuration.name;
|
|
47
|
+
|
|
48
|
+
constructor() {
|
|
49
|
+
super({
|
|
50
|
+
name: Configuration.TABLE_NAME,
|
|
51
|
+
schema: configurationTable,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### DataSource Definition
|
|
58
|
+
|
|
59
|
+
DataSources required manual schema registration:
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
@datasource({})
|
|
63
|
+
export class PostgresDataSource extends BaseDataSource<TNodePostgresConnector, IDSConfigs> {
|
|
64
|
+
constructor() {
|
|
65
|
+
super({
|
|
66
|
+
name: PostgresDataSource.name,
|
|
67
|
+
driver: 'node-postgres',
|
|
68
|
+
config: { /* connection config */ },
|
|
69
|
+
|
|
70
|
+
// Manual schema registration - verbose and error-prone
|
|
71
|
+
schema: Object.assign(
|
|
72
|
+
{},
|
|
73
|
+
{
|
|
74
|
+
[User.TABLE_NAME]: userTable,
|
|
75
|
+
[Configuration.TABLE_NAME]: configurationTable,
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
userRelations: userRelations.relations,
|
|
79
|
+
configurationRelations: configurationRelations.relations,
|
|
80
|
+
},
|
|
81
|
+
),
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Repository Definition
|
|
88
|
+
|
|
89
|
+
Repositories required explicit constructor injection:
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
@repository({})
|
|
93
|
+
export class ConfigurationRepository extends DefaultCRUDRepository<typeof configurationTable> {
|
|
94
|
+
constructor(@inject({ key: 'datasources.PostgresDataSource' }) dataSource: IDataSource) {
|
|
95
|
+
super({
|
|
96
|
+
dataSource,
|
|
97
|
+
entityClass: Configuration,
|
|
98
|
+
relations: configurationRelations.definitions,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Pain Points
|
|
105
|
+
|
|
106
|
+
1. **Verbose Model Definition**: Three separate declarations (table, relations, class) for each model
|
|
107
|
+
2. **Manual Schema Registration**: DataSource required explicit registration of every model and relation
|
|
108
|
+
3. **Unclear Repository Role**: Repository just wrapped datasource without defining the model-datasource binding
|
|
109
|
+
4. **Declaration Order Issues**: Had to declare table before relations, relations before class
|
|
110
|
+
5. **No Auto-Discovery**: Adding a new model required updates in multiple places
|
|
111
|
+
6. **Tight Coupling**: Changes to model structure required updates in datasource configuration
|
|
112
|
+
|
|
113
|
+
## File Structure
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
src/
|
|
117
|
+
├── models/
|
|
118
|
+
│ └── entities/
|
|
119
|
+
│ ├── user.model.ts # Table + Relations + Class
|
|
120
|
+
│ └── configuration.model.ts # Table + Relations + Class
|
|
121
|
+
├── datasources/
|
|
122
|
+
│ └── postgres.datasource.ts # Manual schema assembly
|
|
123
|
+
└── repositories/
|
|
124
|
+
├── user.repository.ts # Explicit constructor injection
|
|
125
|
+
└── configuration.repository.ts
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Dependencies
|
|
129
|
+
|
|
130
|
+
- `@venizia/ignis-helpers`: Core utilities and types
|
|
131
|
+
- `@venizia/ignis-inversion`: Dependency injection
|
|
132
|
+
- `drizzle-orm`: ORM layer
|
|
133
|
+
- `drizzle-zod`: Schema validation
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
*This architecture was superseded by the Loopback 4-style refactor in v0.0.1-8*
|