@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.
Files changed (43) hide show
  1. package/LICENSE.md +1 -0
  2. package/package.json +2 -2
  3. package/wiki/changelogs/2025-12-16-initial-architecture.md +145 -0
  4. package/wiki/changelogs/2025-12-16-model-repo-datasource-refactor.md +300 -0
  5. package/wiki/changelogs/2025-12-17-refactor.md +90 -0
  6. package/wiki/changelogs/2025-12-18-performance-optimizations.md +130 -0
  7. package/wiki/changelogs/2025-12-18-repository-validation-security.md +249 -0
  8. package/wiki/changelogs/index.md +33 -0
  9. package/wiki/changelogs/planned-transaction-support.md +216 -0
  10. package/wiki/changelogs/template.md +123 -0
  11. package/wiki/get-started/5-minute-quickstart.md +1 -1
  12. package/wiki/get-started/best-practices/api-usage-examples.md +12 -10
  13. package/wiki/get-started/best-practices/architectural-patterns.md +2 -2
  14. package/wiki/get-started/best-practices/common-pitfalls.md +7 -5
  15. package/wiki/get-started/best-practices/contribution-workflow.md +2 -0
  16. package/wiki/get-started/best-practices/data-modeling.md +91 -40
  17. package/wiki/get-started/best-practices/security-guidelines.md +3 -1
  18. package/wiki/get-started/building-a-crud-api.md +63 -78
  19. package/wiki/get-started/core-concepts/application.md +72 -3
  20. package/wiki/get-started/core-concepts/bootstrapping.md +566 -0
  21. package/wiki/get-started/core-concepts/components.md +4 -2
  22. package/wiki/get-started/core-concepts/controllers.md +14 -14
  23. package/wiki/get-started/core-concepts/persistent.md +383 -431
  24. package/wiki/get-started/core-concepts/services.md +21 -27
  25. package/wiki/get-started/quickstart.md +1 -1
  26. package/wiki/references/base/bootstrapping.md +789 -0
  27. package/wiki/references/base/components.md +1 -1
  28. package/wiki/references/base/controllers.md +40 -16
  29. package/wiki/references/base/datasources.md +195 -33
  30. package/wiki/references/base/dependency-injection.md +98 -5
  31. package/wiki/references/base/models.md +398 -28
  32. package/wiki/references/base/repositories.md +475 -22
  33. package/wiki/references/base/services.md +2 -2
  34. package/wiki/references/components/authentication.md +228 -10
  35. package/wiki/references/components/health-check.md +1 -1
  36. package/wiki/references/components/index.md +1 -1
  37. package/wiki/references/components/swagger.md +1 -1
  38. package/wiki/references/helpers/error.md +2 -2
  39. package/wiki/references/helpers/inversion.md +8 -3
  40. package/wiki/references/src-details/boot.md +379 -0
  41. package/wiki/references/src-details/core.md +8 -7
  42. package/wiki/references/src-details/inversion.md +4 -4
  43. 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-8",
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.1-4",
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.