@venizia/ignis-docs 0.0.1-9 → 0.0.2
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/{v0.0.1-7-initial-architecture.md → 2025-12-16-initial-architecture.md} +20 -12
- package/wiki/changelogs/2025-12-16-model-repo-datasource-refactor.md +300 -0
- package/wiki/changelogs/2025-12-17-refactor.md +80 -12
- package/wiki/changelogs/2025-12-18-performance-optimizations.md +28 -90
- package/wiki/changelogs/2025-12-18-repository-validation-security.md +101 -297
- package/wiki/changelogs/index.md +20 -8
- package/wiki/changelogs/planned-schema-migrator.md +561 -0
- package/wiki/changelogs/planned-transaction-support.md +216 -0
- package/wiki/changelogs/template.md +123 -0
- package/wiki/get-started/best-practices/api-usage-examples.md +0 -2
- package/wiki/get-started/best-practices/architectural-patterns.md +2 -2
- package/wiki/get-started/best-practices/code-style-standards.md +575 -10
- package/wiki/get-started/best-practices/common-pitfalls.md +5 -3
- package/wiki/get-started/best-practices/contribution-workflow.md +2 -0
- package/wiki/get-started/best-practices/data-modeling.md +91 -34
- package/wiki/get-started/best-practices/security-guidelines.md +3 -1
- package/wiki/get-started/building-a-crud-api.md +3 -3
- 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/persistent.md +350 -378
- package/wiki/get-started/core-concepts/services.md +21 -27
- package/wiki/references/base/bootstrapping.md +789 -0
- package/wiki/references/base/components.md +1 -1
- package/wiki/references/base/dependency-injection.md +95 -2
- package/wiki/references/base/services.md +2 -2
- package/wiki/references/components/authentication.md +4 -3
- package/wiki/references/components/index.md +1 -1
- package/wiki/references/helpers/error.md +2 -2
- package/wiki/references/src-details/boot.md +379 -0
- package/wiki/references/src-details/core.md +2 -2
- package/wiki/changelogs/v0.0.1-8-model-repo-datasource-refactor.md +0 -278
|
@@ -1,278 +0,0 @@
|
|
|
1
|
-
# v0.0.1-8 - Model-Repository-DataSource Architecture Refactor
|
|
2
|
-
|
|
3
|
-
**Release Date**: 2025-12-16
|
|
4
|
-
**Status**: Current
|
|
5
|
-
|
|
6
|
-
## Overview
|
|
7
|
-
|
|
8
|
-
Major refactor following Loopback 4's architecture pattern where:
|
|
9
|
-
- **Model** is self-contained with schema and relations
|
|
10
|
-
- **Repository** connects Model to DataSource (defines the binding)
|
|
11
|
-
- **DataSource** auto-discovers schemas from registered repositories
|
|
12
|
-
|
|
13
|
-
This eliminates manual schema registration and simplifies the development workflow significantly.
|
|
14
|
-
|
|
15
|
-
## Breaking Changes
|
|
16
|
-
|
|
17
|
-
1. **Model static properties now require `override` keyword**
|
|
18
|
-
- `static override schema = pgTable(...)`
|
|
19
|
-
- `static override relations = () => ({...})`
|
|
20
|
-
|
|
21
|
-
2. **Repository constructor is now optional**
|
|
22
|
-
- Old: Required `entityClass`, `relations`, `dataSource` parameters
|
|
23
|
-
- New: Auto-resolved from `@repository` decorator metadata
|
|
24
|
-
|
|
25
|
-
3. **DataSource schema is now optional**
|
|
26
|
-
- Old: Required manual `schema` property with all models
|
|
27
|
-
- New: Auto-discovered from `@repository` bindings
|
|
28
|
-
|
|
29
|
-
## New Features
|
|
30
|
-
|
|
31
|
-
### Self-Contained Models
|
|
32
|
-
|
|
33
|
-
Models now define schema and relations as static properties:
|
|
34
|
-
|
|
35
|
-
```typescript
|
|
36
|
-
@model({ type: 'entity' })
|
|
37
|
-
export class Configuration extends BaseEntity<typeof Configuration.schema> {
|
|
38
|
-
static override schema = pgTable('Configuration', {
|
|
39
|
-
...generateIdColumnDefs({ id: { dataType: 'string' } }),
|
|
40
|
-
...generateTzColumnDefs(),
|
|
41
|
-
code: text('code').notNull(),
|
|
42
|
-
group: text('group').notNull(),
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
static override relations = () => ({
|
|
46
|
-
creator: {
|
|
47
|
-
type: 'one' as const,
|
|
48
|
-
target: () => User,
|
|
49
|
-
fields: [Configuration.schema.createdBy],
|
|
50
|
-
references: () => [User.schema.id],
|
|
51
|
-
},
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### Repository Auto-Resolution
|
|
57
|
-
|
|
58
|
-
Repositories now use `@repository` decorator for model-datasource binding:
|
|
59
|
-
|
|
60
|
-
```typescript
|
|
61
|
-
@repository({
|
|
62
|
-
model: Configuration,
|
|
63
|
-
datasource: PostgresDataSource,
|
|
64
|
-
})
|
|
65
|
-
export class ConfigurationRepository extends DefaultCRUDRepository<typeof Configuration.schema> {
|
|
66
|
-
// No constructor needed!
|
|
67
|
-
|
|
68
|
-
async findByCode(code: string) {
|
|
69
|
-
return this.findOne({ filter: { where: { code } } });
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
### DataSource Auto-Discovery
|
|
75
|
-
|
|
76
|
-
DataSources automatically discover their schema from repository bindings:
|
|
77
|
-
|
|
78
|
-
```typescript
|
|
79
|
-
@datasource({ driver: 'node-postgres' })
|
|
80
|
-
export class PostgresDataSource extends BaseDataSource<TNodePostgresConnector, IDSConfigs> {
|
|
81
|
-
constructor() {
|
|
82
|
-
super({
|
|
83
|
-
name: PostgresDataSource.name,
|
|
84
|
-
driver: 'node-postgres',
|
|
85
|
-
config: { /* connection config */ },
|
|
86
|
-
// NO schema property - auto-discovered!
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
override configure(): ValueOrPromise<void> {
|
|
91
|
-
const schema = this.getSchema(); // Auto-discovers from @repository bindings
|
|
92
|
-
this.connector = drizzle({ client: new Pool(this.settings), schema });
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
## Files Changed
|
|
98
|
-
|
|
99
|
-
### Core Package (`packages/core`)
|
|
100
|
-
|
|
101
|
-
| File | Changes |
|
|
102
|
-
|------|---------|
|
|
103
|
-
| `src/base/models/base.ts` | Added static `schema`, `relations`, `TABLE_NAME` |
|
|
104
|
-
| `src/base/datasources/base.ts` | Added auto-discovery via `buildAutoDiscoveredSchema()` |
|
|
105
|
-
| `src/base/repositories/core/base.ts` | Added lazy resolution, static container reference |
|
|
106
|
-
| `src/base/repositories/core/readable.ts` | Made constructor opts optional |
|
|
107
|
-
| `src/base/repositories/core/persistable.ts` | Made constructor opts optional |
|
|
108
|
-
| `src/base/repositories/core/default-crud.ts` | Added documentation |
|
|
109
|
-
| `src/base/metadata/persistents.ts` | Updated decorators for auto-discovery |
|
|
110
|
-
| `src/base/applications/base.ts` | Added `AbstractRepository.setContainer(this)` |
|
|
111
|
-
| `src/components/static-asset/models/base.model.ts` | Updated to new pattern |
|
|
112
|
-
|
|
113
|
-
### Helpers Package (`packages/helpers`)
|
|
114
|
-
|
|
115
|
-
| File | Changes |
|
|
116
|
-
|------|---------|
|
|
117
|
-
| `src/helpers/inversion/common/types.ts` | Added `IModelMetadata`, `IRelationDefinition`, `IModelStatic`, `IRepositoryMetadata`, `IRepositoryBinding` |
|
|
118
|
-
| `src/helpers/inversion/registry.ts` | Added `registerModel`, `registerRepositoryBinding`, `buildDataSourceSchema` |
|
|
119
|
-
|
|
120
|
-
### Examples (`examples/vert`)
|
|
121
|
-
|
|
122
|
-
| File | Changes |
|
|
123
|
-
|------|---------|
|
|
124
|
-
| `src/models/entities/user.model.ts` | Updated to static schema pattern |
|
|
125
|
-
| `src/models/entities/configuration.model.ts` | Updated to static schema pattern |
|
|
126
|
-
| `src/datasources/postgres.datasource.ts` | Removed manual schema registration |
|
|
127
|
-
| `src/repositories/user.repository.ts` | Updated to use `@repository` decorator |
|
|
128
|
-
| `src/repositories/configuration.repository.ts` | Updated to use `@repository` decorator |
|
|
129
|
-
|
|
130
|
-
## Migration Guide
|
|
131
|
-
|
|
132
|
-
### Step 1: Update Models
|
|
133
|
-
|
|
134
|
-
**Before:**
|
|
135
|
-
```typescript
|
|
136
|
-
const userTable = pgTable('User', {...});
|
|
137
|
-
const userRelations = createRelations({...});
|
|
138
|
-
|
|
139
|
-
@model({ type: 'entity' })
|
|
140
|
-
export class User extends BaseEntity<typeof userTable> {
|
|
141
|
-
constructor() {
|
|
142
|
-
super({ name: 'User', schema: userTable });
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
**After:**
|
|
148
|
-
```typescript
|
|
149
|
-
@model({ type: 'entity' })
|
|
150
|
-
export class User extends BaseEntity<typeof User.schema> {
|
|
151
|
-
static override schema = pgTable('User', {...});
|
|
152
|
-
static override relations = () => ({...});
|
|
153
|
-
}
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
### Step 2: Update Repositories
|
|
157
|
-
|
|
158
|
-
**Before:**
|
|
159
|
-
```typescript
|
|
160
|
-
@repository({})
|
|
161
|
-
export class UserRepository extends DefaultCRUDRepository<typeof userTable> {
|
|
162
|
-
constructor(@inject({ key: 'datasources.PostgresDataSource' }) dataSource: IDataSource) {
|
|
163
|
-
super({ dataSource, entityClass: User, relations: userRelations.definitions });
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
**After:**
|
|
169
|
-
```typescript
|
|
170
|
-
@repository({ model: User, datasource: PostgresDataSource })
|
|
171
|
-
export class UserRepository extends DefaultCRUDRepository<typeof User.schema> {
|
|
172
|
-
// No constructor needed!
|
|
173
|
-
}
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
### Step 3: Update DataSources
|
|
177
|
-
|
|
178
|
-
**Before:**
|
|
179
|
-
```typescript
|
|
180
|
-
@datasource({})
|
|
181
|
-
export class PostgresDataSource extends BaseDataSource {
|
|
182
|
-
constructor() {
|
|
183
|
-
super({
|
|
184
|
-
name: PostgresDataSource.name,
|
|
185
|
-
driver: 'node-postgres',
|
|
186
|
-
config: {...},
|
|
187
|
-
schema: { User: userTable, userRelations: userRelations.relations, ... },
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
**After:**
|
|
194
|
-
```typescript
|
|
195
|
-
@datasource({ driver: 'node-postgres' })
|
|
196
|
-
export class PostgresDataSource extends BaseDataSource {
|
|
197
|
-
constructor() {
|
|
198
|
-
super({
|
|
199
|
-
name: PostgresDataSource.name,
|
|
200
|
-
driver: 'node-postgres',
|
|
201
|
-
config: {...},
|
|
202
|
-
// NO schema - auto-discovered!
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
## Architecture Diagram
|
|
209
|
-
|
|
210
|
-
```
|
|
211
|
-
┌─────────────────────────────────────────────────────────────────┐
|
|
212
|
-
│ Application │
|
|
213
|
-
│ ┌───────────────────────────────────────────────────────────┐ │
|
|
214
|
-
│ │ preConfigure() │ │
|
|
215
|
-
│ │ this.dataSource(PostgresDataSource) │ │
|
|
216
|
-
│ │ this.repository(UserRepository) ──┐ │ │
|
|
217
|
-
│ │ this.repository(ConfigurationRepository) │ Registers │ │
|
|
218
|
-
│ │ │ bindings │ │
|
|
219
|
-
│ └─────────────────────────────────────────────┼─────────────┘ │
|
|
220
|
-
│ │ │
|
|
221
|
-
│ ┌─────────────────────────────────────────────▼─────────────┐ │
|
|
222
|
-
│ │ MetadataRegistry │ │
|
|
223
|
-
│ │ modelRegistry: Map<tableName, {schema, relations}> │ │
|
|
224
|
-
│ │ repositoryBindings: Map<repoClass, {model, datasource}> │ │
|
|
225
|
-
│ │ datasourceModels: Map<datasource, Set<modelNames>> │ │
|
|
226
|
-
│ └─────────────────────────────────────────────┬─────────────┘ │
|
|
227
|
-
│ │ │
|
|
228
|
-
│ ┌─────────────────────────────────────────────▼─────────────┐ │
|
|
229
|
-
│ │ DataSource.configure() │ │
|
|
230
|
-
│ │ schema = this.getSchema() ◄── Auto-discovers from │ │
|
|
231
|
-
│ │ MetadataRegistry │ │
|
|
232
|
-
│ │ this.connector = drizzle({ schema }) │ │
|
|
233
|
-
│ └───────────────────────────────────────────────────────────┘ │
|
|
234
|
-
└─────────────────────────────────────────────────────────────────┘
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
## Benefits
|
|
238
|
-
|
|
239
|
-
1. **Simplified Model Definition**: Single class with static properties
|
|
240
|
-
2. **No Manual Schema Registration**: DataSource auto-discovers models
|
|
241
|
-
3. **Clear Repository Role**: Explicitly binds model to datasource
|
|
242
|
-
4. **Better Type Safety**: Types flow from `static schema` through the system
|
|
243
|
-
5. **Reduced Boilerplate**: No constructor needed for basic repositories
|
|
244
|
-
6. **Follows Loopback 4 Pattern**: Familiar architecture for developers
|
|
245
|
-
|
|
246
|
-
## Technical Details
|
|
247
|
-
|
|
248
|
-
### IRelationDefinition Interface
|
|
249
|
-
|
|
250
|
-
```typescript
|
|
251
|
-
interface IRelationDefinition<TTarget = any> {
|
|
252
|
-
type: 'one' | 'many';
|
|
253
|
-
target: () => TClass<TTarget>; // Lazy to avoid circular imports
|
|
254
|
-
fields?: AnyColumn[];
|
|
255
|
-
references?: () => AnyColumn[]; // Lazy to avoid circular imports
|
|
256
|
-
relationName?: string;
|
|
257
|
-
}
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
### Repository Auto-Resolution Flow
|
|
261
|
-
|
|
262
|
-
1. `@repository` decorator registers binding in `MetadataRegistry`
|
|
263
|
-
2. When repository is instantiated, constructor checks for explicit opts
|
|
264
|
-
3. If not provided, lazy getters resolve from `MetadataRegistry`:
|
|
265
|
-
- `entity` → resolved from `modelClass` in binding
|
|
266
|
-
- `relations` → built from model's `static relations()`
|
|
267
|
-
- `dataSource` → resolved from container using binding key
|
|
268
|
-
|
|
269
|
-
### DataSource Auto-Discovery Flow
|
|
270
|
-
|
|
271
|
-
1. `@repository` decorators register model-datasource bindings
|
|
272
|
-
2. When `dataSource.configure()` is called, `getSchema()` is invoked
|
|
273
|
-
3. `buildAutoDiscoveredSchema()` queries `MetadataRegistry` for all models bound to this datasource
|
|
274
|
-
4. Schema is assembled from model schemas and relations
|
|
275
|
-
|
|
276
|
-
---
|
|
277
|
-
|
|
278
|
-
*This refactor was inspired by Loopback 4's architecture pattern*
|