@venizia/ignis-docs 0.0.3 → 0.0.4-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/README.md +1 -1
  2. package/package.json +4 -2
  3. package/wiki/best-practices/api-usage-examples.md +591 -0
  4. package/wiki/best-practices/architectural-patterns.md +415 -0
  5. package/wiki/best-practices/architecture-decisions.md +488 -0
  6. package/wiki/{get-started/best-practices → best-practices}/code-style-standards.md +406 -17
  7. package/wiki/{get-started/best-practices → best-practices}/common-pitfalls.md +109 -4
  8. package/wiki/{get-started/best-practices → best-practices}/contribution-workflow.md +34 -7
  9. package/wiki/best-practices/data-modeling.md +376 -0
  10. package/wiki/best-practices/deployment-strategies.md +698 -0
  11. package/wiki/best-practices/index.md +27 -0
  12. package/wiki/best-practices/performance-optimization.md +196 -0
  13. package/wiki/best-practices/security-guidelines.md +218 -0
  14. package/wiki/{get-started/best-practices → best-practices}/troubleshooting-tips.md +97 -1
  15. package/wiki/changelogs/2025-12-16-initial-architecture.md +1 -1
  16. package/wiki/changelogs/2025-12-16-model-repo-datasource-refactor.md +1 -1
  17. package/wiki/changelogs/2025-12-17-refactor.md +1 -1
  18. package/wiki/changelogs/2025-12-18-performance-optimizations.md +5 -5
  19. package/wiki/changelogs/2025-12-18-repository-validation-security.md +13 -7
  20. package/wiki/changelogs/2025-12-26-nested-relations-and-generics.md +2 -2
  21. package/wiki/changelogs/2025-12-29-dynamic-binding-registration.md +104 -0
  22. package/wiki/changelogs/2025-12-29-snowflake-uid-helper.md +100 -0
  23. package/wiki/changelogs/2025-12-30-repository-enhancements.md +214 -0
  24. package/wiki/changelogs/2025-12-31-json-path-filtering-array-operators.md +214 -0
  25. package/wiki/changelogs/2025-12-31-string-id-custom-generator.md +137 -0
  26. package/wiki/changelogs/2026-01-02-default-filter-and-repository-mixins.md +418 -0
  27. package/wiki/changelogs/index.md +6 -0
  28. package/wiki/changelogs/planned-schema-migrator.md +0 -8
  29. package/wiki/{get-started/core-concepts → guides/core-concepts/application}/bootstrapping.md +18 -5
  30. package/wiki/{get-started/core-concepts/application.md → guides/core-concepts/application/index.md} +47 -104
  31. package/wiki/guides/core-concepts/components-guide.md +509 -0
  32. package/wiki/{get-started → guides}/core-concepts/components.md +24 -17
  33. package/wiki/{get-started → guides}/core-concepts/controllers.md +30 -13
  34. package/wiki/{get-started → guides}/core-concepts/dependency-injection.md +97 -0
  35. package/wiki/guides/core-concepts/persistent/datasources.md +179 -0
  36. package/wiki/guides/core-concepts/persistent/index.md +119 -0
  37. package/wiki/guides/core-concepts/persistent/models.md +241 -0
  38. package/wiki/guides/core-concepts/persistent/repositories.md +219 -0
  39. package/wiki/guides/core-concepts/persistent/transactions.md +170 -0
  40. package/wiki/{get-started → guides}/core-concepts/services.md +26 -3
  41. package/wiki/{get-started → guides/get-started}/5-minute-quickstart.md +59 -14
  42. package/wiki/guides/get-started/philosophy.md +682 -0
  43. package/wiki/guides/get-started/setup.md +157 -0
  44. package/wiki/guides/index.md +89 -0
  45. package/wiki/guides/reference/glossary.md +243 -0
  46. package/wiki/{get-started → guides/reference}/mcp-docs-server.md +0 -10
  47. package/wiki/{get-started → guides/tutorials}/building-a-crud-api.md +134 -132
  48. package/wiki/{get-started/quickstart.md → guides/tutorials/complete-installation.md} +107 -71
  49. package/wiki/guides/tutorials/ecommerce-api.md +1399 -0
  50. package/wiki/guides/tutorials/realtime-chat.md +1261 -0
  51. package/wiki/guides/tutorials/testing.md +723 -0
  52. package/wiki/index.md +176 -37
  53. package/wiki/references/base/application.md +27 -0
  54. package/wiki/references/base/bootstrapping.md +31 -26
  55. package/wiki/references/base/components.md +24 -7
  56. package/wiki/references/base/controllers.md +50 -20
  57. package/wiki/references/base/datasources.md +30 -0
  58. package/wiki/references/base/dependency-injection.md +39 -3
  59. package/wiki/references/base/filter-system/application-usage.md +224 -0
  60. package/wiki/references/base/filter-system/array-operators.md +132 -0
  61. package/wiki/references/base/filter-system/comparison-operators.md +109 -0
  62. package/wiki/references/base/filter-system/default-filter.md +428 -0
  63. package/wiki/references/base/filter-system/fields-order-pagination.md +155 -0
  64. package/wiki/references/base/filter-system/index.md +127 -0
  65. package/wiki/references/base/filter-system/json-filtering.md +197 -0
  66. package/wiki/references/base/filter-system/list-operators.md +71 -0
  67. package/wiki/references/base/filter-system/logical-operators.md +156 -0
  68. package/wiki/references/base/filter-system/null-operators.md +58 -0
  69. package/wiki/references/base/filter-system/pattern-matching.md +108 -0
  70. package/wiki/references/base/filter-system/quick-reference.md +431 -0
  71. package/wiki/references/base/filter-system/range-operators.md +63 -0
  72. package/wiki/references/base/filter-system/tips.md +190 -0
  73. package/wiki/references/base/filter-system/use-cases.md +452 -0
  74. package/wiki/references/base/index.md +90 -0
  75. package/wiki/references/base/middlewares.md +604 -0
  76. package/wiki/references/base/models.md +215 -23
  77. package/wiki/references/base/providers.md +731 -0
  78. package/wiki/references/base/repositories/advanced.md +555 -0
  79. package/wiki/references/base/repositories/index.md +228 -0
  80. package/wiki/references/base/repositories/mixins.md +331 -0
  81. package/wiki/references/base/repositories/relations.md +486 -0
  82. package/wiki/references/base/repositories.md +40 -635
  83. package/wiki/references/base/services.md +28 -4
  84. package/wiki/references/components/authentication.md +22 -2
  85. package/wiki/references/components/health-check.md +12 -0
  86. package/wiki/references/components/index.md +23 -0
  87. package/wiki/references/components/mail.md +687 -0
  88. package/wiki/references/components/request-tracker.md +16 -0
  89. package/wiki/references/components/socket-io.md +18 -0
  90. package/wiki/references/components/static-asset.md +14 -26
  91. package/wiki/references/components/swagger.md +17 -0
  92. package/wiki/references/configuration/environment-variables.md +427 -0
  93. package/wiki/references/configuration/index.md +73 -0
  94. package/wiki/references/helpers/cron.md +14 -0
  95. package/wiki/references/helpers/crypto.md +15 -0
  96. package/wiki/references/helpers/env.md +16 -0
  97. package/wiki/references/helpers/error.md +17 -0
  98. package/wiki/references/helpers/index.md +14 -0
  99. package/wiki/references/helpers/inversion.md +24 -4
  100. package/wiki/references/helpers/logger.md +19 -0
  101. package/wiki/references/helpers/network.md +11 -0
  102. package/wiki/references/helpers/queue.md +19 -0
  103. package/wiki/references/helpers/redis.md +21 -0
  104. package/wiki/references/helpers/socket-io.md +24 -5
  105. package/wiki/references/helpers/storage.md +18 -10
  106. package/wiki/references/helpers/testing.md +18 -0
  107. package/wiki/references/helpers/types.md +16 -0
  108. package/wiki/references/helpers/uid.md +167 -0
  109. package/wiki/references/helpers/worker-thread.md +16 -0
  110. package/wiki/references/index.md +177 -0
  111. package/wiki/references/quick-reference.md +634 -0
  112. package/wiki/references/src-details/boot.md +3 -3
  113. package/wiki/references/src-details/dev-configs.md +0 -4
  114. package/wiki/references/src-details/docs.md +2 -2
  115. package/wiki/references/src-details/index.md +86 -0
  116. package/wiki/references/src-details/inversion.md +1 -6
  117. package/wiki/references/src-details/mcp-server.md +3 -15
  118. package/wiki/references/utilities/index.md +86 -10
  119. package/wiki/references/utilities/jsx.md +577 -0
  120. package/wiki/references/utilities/request.md +0 -2
  121. package/wiki/references/utilities/statuses.md +740 -0
  122. package/wiki/get-started/best-practices/api-usage-examples.md +0 -266
  123. package/wiki/get-started/best-practices/architectural-patterns.md +0 -170
  124. package/wiki/get-started/best-practices/data-modeling.md +0 -177
  125. package/wiki/get-started/best-practices/deployment-strategies.md +0 -121
  126. package/wiki/get-started/best-practices/performance-optimization.md +0 -97
  127. package/wiki/get-started/best-practices/security-guidelines.md +0 -99
  128. package/wiki/get-started/core-concepts/persistent.md +0 -539
  129. package/wiki/get-started/index.md +0 -65
  130. package/wiki/get-started/philosophy.md +0 -296
  131. package/wiki/get-started/prerequisites.md +0 -113
@@ -1,266 +0,0 @@
1
- # API Usage Examples
2
-
3
- Practical examples for defining endpoints and working with data in Ignis applications.
4
-
5
- ## Routing Patterns
6
-
7
- ### Decorator-Based Routing (Recommended)
8
-
9
- Use `@get`, `@post` decorators with `as const` route configs for full type safety:
10
-
11
- **`src/controllers/test/definitions.ts`**
12
- ```typescript
13
- import { z } from '@hono/zod-openapi';
14
- import { Authentication, HTTP, jsonContent, jsonResponse } from '@venizia/ignis';
15
-
16
- // Define route configs as const for type inference
17
- export const ROUTE_CONFIGS = {
18
- // ... (other routes)
19
- ['/4']: {
20
- method: HTTP.Methods.GET,
21
- path: '/4',
22
- responses: jsonResponse({
23
- description: 'Test decorator GET endpoint',
24
- schema: z.object({ message: z.string(), method: z.string() }),
25
- }),
26
- },
27
- ['/5']: {
28
- method: HTTP.Methods.POST,
29
- path: '/5',
30
- authStrategies: [Authentication.STRATEGY_JWT], // Secure this endpoint
31
- request: {
32
- body: jsonContent({
33
- description: 'Request body for POST',
34
- schema: z.object({ name: z.string(), age: z.number().int().positive() }),
35
- }),
36
- },
37
- responses: jsonResponse({
38
- description: 'Test decorator POST endpoint',
39
- schema: z.object({ id: z.string(), name: z.string(), age: z.number() }),
40
- }),
41
- },
42
- } as const;
43
- ```
44
-
45
- Then, use the decorators in your controller class. The `TRouteContext` type provides a fully typed context, including request parameters, body, and response types.
46
-
47
- **`src/controllers/test/controller.ts`**
48
- ```typescript
49
- import {
50
- BaseController,
51
- controller,
52
- get,
53
- post,
54
- TRouteContext,
55
- HTTP,
56
- } from '@venizia/ignis';
57
- import { ROUTE_CONFIGS } from './definitions';
58
-
59
- @controller({ path: '/test' })
60
- export class TestController extends BaseController {
61
- // ...
62
-
63
- @get({ configs: ROUTE_CONFIGS['/4'] })
64
- getWithDecorator(context: TRouteContext<(typeof ROUTE_CONFIGS)['/4']>) {
65
- // context is fully typed!
66
- return context.json({ message: 'Hello from decorator', method: 'GET' }, HTTP.ResultCodes.RS_2.Ok);
67
- }
68
-
69
- @post({ configs: ROUTE_CONFIGS['/5'] })
70
- createWithDecorator(context: TRouteContext<(typeof ROUTE_CONFIGS)['/5']>) {
71
- // context.req.valid('json') is automatically typed as { name: string, age: number }
72
- const body = context.req.valid('json');
73
-
74
- // The response is validated against the schema
75
- return context.json(
76
- {
77
- id: crypto.randomUUID(),
78
- name: body.name,
79
- age: body.age,
80
- },
81
- HTTP.ResultCodes.RS_2.Ok,
82
- );
83
- }
84
- }
85
- ```
86
-
87
- ### Example 2: Manual Route Definition in `binding()`
88
-
89
- You can also define routes manually within the controller's `binding()` method using `defineRoute` or `bindRoute`. This is useful for more complex scenarios or for developers who prefer a non-decorator syntax.
90
-
91
- **`src/controllers/test/controller.ts`**
92
- ```typescript
93
- import { BaseController, controller, HTTP, ValueOrPromise } from '@venizia/ignis';
94
- import { ROUTE_CONFIGS } from './definitions';
95
-
96
- @controller({ path: '/test' })
97
- export class TestController extends BaseController {
98
- // ...
99
- override binding(): ValueOrPromise<void> {
100
- // Using 'defineRoute'
101
- this.defineRoute({
102
- configs: ROUTE_CONFIGS['/1'],
103
- handler: context => {
104
- return context.json({ message: 'Hello' }, HTTP.ResultCodes.RS_2.Ok);
105
- },
106
- });
107
-
108
- // Using 'bindRoute' for a fluent API
109
- this.bindRoute({
110
- configs: ROUTE_CONFIGS['/3'],
111
- }).to({
112
- handler: context => {
113
- return context.json({ message: 'Hello 3' }, HTTP.ResultCodes.RS_2.Ok);
114
- },
115
- });
116
- }
117
- // ...
118
- }
119
- ```
120
-
121
- ### Example 3: Auto-Generated CRUD Controller
122
-
123
- For standard database entities, you can use `ControllerFactory.defineCrudController` to instantly generate a controller with a full set of CRUD endpoints.
124
-
125
- **`src/controllers/configuration.controller.ts`**
126
- ```typescript
127
- import { Configuration } from '@/models';
128
- import { ConfigurationRepository } from '@/repositories';
129
- import {
130
- BindingKeys,
131
- BindingNamespaces,
132
- controller,
133
- ControllerFactory,
134
- inject,
135
- } from '@venizia/ignis';
136
-
137
- const BASE_PATH = '/configurations';
138
-
139
- // 1. The factory generates a controller class with all CRUD routes
140
- const _Controller = ControllerFactory.defineCrudController({
141
- repository: { name: ConfigurationRepository.name },
142
- controller: {
143
- name: 'ConfigurationController',
144
- basePath: BASE_PATH,
145
- },
146
- entity: () => Configuration, // The entity is used to generate OpenAPI schemas
147
- });
148
-
149
- // 2. Extend the generated controller to inject the repository
150
- @controller({ path: BASE_PATH })
151
- export class ConfigurationController extends _Controller {
152
- constructor(
153
- @inject({
154
- key: BindingKeys.build({
155
- namespace: BindingNamespaces.REPOSITORY,
156
- key: ConfigurationRepository.name,
157
- }),
158
- })
159
- repository: ConfigurationRepository,
160
- ) {
161
- super(repository);
162
- }
163
- }
164
- ```
165
- This automatically creates endpoints like `GET /configurations`, `POST /configurations`, `GET /configurations/:id`, etc.
166
-
167
- ## Repository (Data Access) Usage
168
-
169
- Repositories are used to interact with your database. The `DefaultCRUDRepository` provides a rich set of methods for data manipulation. Here are examples from the `postConfigure` method in `src/application.ts`, which demonstrates how to use an injected repository.
170
-
171
- ```typescript
172
- // In src/application.ts
173
-
174
- // Get the repository instance from the DI container
175
- const configurationRepository = this.get<ConfigurationRepository>({
176
- key: BindingKeys.build({
177
- namespace: BindingNamespaces.REPOSITORY,
178
- key: ConfigurationRepository.name,
179
- }),
180
- });
181
-
182
- // --- Find One Record ---
183
- const record = await configurationRepository.findOne({
184
- filter: { where: { code: 'CODE_1' } },
185
- });
186
-
187
- // --- Find Multiple Records with Relations ---
188
- const records = await configurationRepository.find({
189
- filter: {
190
- where: { code: 'CODE_2' },
191
- fields: { id: true, code: true, createdBy: true },
192
- limit: 100,
193
- include: [{ relation: 'creator' }], // Eager load the 'creator' relation
194
- },
195
- });
196
-
197
- // --- Create a Single Record ---
198
- const newRecord = await configurationRepository.create({
199
- data: {
200
- code: 'NEW_CODE',
201
- group: 'SYSTEM',
202
- dataType: 'TEXT',
203
- tValue: 'some value',
204
- },
205
- });
206
-
207
- // --- Create Multiple Records ---
208
- const newRecords = await configurationRepository.createAll({
209
- data: [
210
- { code: 'CODE_A', group: 'SYSTEM' },
211
- { code: 'CODE_B', group: 'SYSTEM' },
212
- ],
213
- });
214
-
215
- // --- Update a Record by ID ---
216
- const updated = await configurationRepository.updateById({
217
- id: 'some-uuid',
218
- data: { tValue: 'new value' },
219
- });
220
-
221
- // --- Delete a Record by ID ---
222
- const deleted = await configurationRepository.deleteById({
223
- id: newRecord.data!.id,
224
- options: { shouldReturn: true }, // Option to return the deleted record
225
- });
226
-
227
- ## Server-Side Rendering (JSX)
228
-
229
- Ignis supports server-side rendering using Hono's JSX middleware. This is useful for returning HTML content, such as landing pages or simple admin views.
230
-
231
- **Usage:**
232
-
233
- Use `defineJSXRoute` in your controller and `htmlResponse` for documentation.
234
-
235
- ```typescript
236
- import { BaseController, controller, htmlResponse } from '@venizia/ignis';
237
-
238
- @controller({ path: '/pages' })
239
- export class PageController extends BaseController {
240
-
241
- override binding(): void {
242
- this.defineJSXRoute({
243
- configs: {
244
- method: 'get',
245
- path: '/welcome',
246
- description: 'Welcome Page',
247
- responses: htmlResponse({ description: 'HTML Welcome Page' }),
248
- },
249
- handler: (c) => {
250
- const title = 'Welcome to Ignis';
251
-
252
- // Return JSX directly
253
- return c.html(
254
- <html>
255
- <head><title>{title}</title></head>
256
- <body>
257
- <h1>{title}</h1>
258
- <p>Server-side rendered content.</p>
259
- </body>
260
- </html>
261
- );
262
- },
263
- });
264
- }
265
- }
266
- ```
@@ -1,170 +0,0 @@
1
- # Architectural Patterns
2
-
3
- Ignis promotes separation of concerns, dependency injection, and modularity for scalable, maintainable applications.
4
-
5
- > **Deep Dive:** See [Core Framework Reference](../../references/src-details/core.md) for implementation details.
6
-
7
- ## 1. Layered Architecture
8
-
9
- Each layer has a single responsibility. Ignis supports **two architectural approaches**:
10
-
11
- ```mermaid
12
- graph TD
13
- Client[Client/API Consumer]
14
-
15
- Client -->|HTTP Request| Controller[Controllers]
16
-
17
- Controller -->|Simple CRUD| Repo[Repositories]
18
- Controller -->|Complex Logic| Service[Services]
19
-
20
- Service --> Repo
21
-
22
- Repo --> DataSource[DataSources]
23
- DataSource --> DB[(Database)]
24
-
25
- style Service fill:#e1f5ff
26
- style Repo fill:#fff4e1
27
- style Controller fill:#ffe1f5
28
- ```
29
-
30
- | Layer | Responsibility | Example |
31
- |-------|---------------|---------|
32
- | **Controllers** | Handle HTTP - parse requests, validate, format responses | `ConfigurationController` (uses `ControllerFactory`) |
33
- | **Services** | Business logic - orchestrate operations | `AuthenticationService` (auth logic) |
34
- | **Repositories** | Data access - CRUD operations | `ConfigurationRepository` (extends `DefaultCRUDRepository`) |
35
- | **DataSources** | Database connections | `PostgresDataSource` (connects to PostgreSQL) |
36
- | **Models** | Data structure - Drizzle schemas + Entity classes | `Configuration`, `User` models |
37
-
38
- **Key Principle - Two Approaches:**
39
-
40
- ```
41
- Simple CRUD (no business logic):
42
- ┌────────────┐
43
- │ Controller │──────────────┐
44
- └────────────┘ │
45
-
46
- ┌──────────────┐
47
- │ Repository │
48
- └──────────────┘
49
-
50
-
51
- Database
52
-
53
- Complex Logic (validation, orchestration):
54
- ┌────────────┐
55
- │ Controller │────┐
56
- └────────────┘ │
57
-
58
- ┌─────────┐
59
- │ Service │
60
- └─────────┘
61
-
62
-
63
- ┌──────────────┐
64
- │ Repository │
65
- └──────────────┘
66
-
67
-
68
- Database
69
- ```
70
-
71
- **When to use each:**
72
- - **Controller → Repository** - Simple CRUD (list, get by ID, create, update, delete)
73
- - **Controller → Service → Repository** - Business logic, validation, orchestrating multiple repositories
74
-
75
- ## 2. Dependency Injection (DI)
76
-
77
- Classes declare dependencies in their constructor - the framework automatically provides them at runtime.
78
-
79
- **Benefits:**
80
- - Loosely coupled code
81
- - Easy to test (mock dependencies)
82
- - Easy to swap implementations
83
-
84
- **Example:**
85
- ```typescript
86
- @controller({ path: BASE_PATH })
87
- export class ConfigurationController extends _Controller {
88
- constructor(
89
- // The @inject decorator tells the container to provide
90
- // an instance of ConfigurationRepository here.
91
- @inject({
92
- key: BindingKeys.build({
93
- namespace: BindingNamespaces.REPOSITORY,
94
- key: ConfigurationRepository.name,
95
- }),
96
- })
97
- repository: ConfigurationRepository,
98
- ) {
99
- super(repository);
100
- }
101
- }
102
- ```
103
-
104
- ## 3. Component-Based Modularity
105
-
106
- Components bundle a group of related, reusable, and pluggable features into self-contained modules. A single component can encapsulate multiple providers, services, controllers, and repositories, essentially functioning as a mini-application that can be easily "plugged in" to any Ignis project.
107
-
108
- **Built-in Components:**
109
- - `AuthenticateComponent` - JWT authentication
110
- - `SwaggerComponent` - OpenAPI documentation
111
- - `HealthCheckComponent` - Health check endpoint
112
- - `RequestTrackerComponent` - Request logging
113
-
114
- **Example:**
115
- ```typescript
116
- // src/application.ts
117
-
118
- export class Application extends BaseApplication {
119
- // ...
120
- preConfigure(): ValueOrPromise<void> {
121
- // ...
122
- // Registering components plugs their functionality into the application.
123
- this.component(HealthCheckComponent);
124
- this.component(SwaggerComponent);
125
- // ...
126
- }
127
- }
128
- ```
129
- This architecture keeps the main `Application` class clean and focused on high-level assembly, while the details of each feature are neatly encapsulated within their respective components.
130
-
131
- ## 4. Custom Components
132
-
133
- You can encapsulate your own logic or third-party integrations (like Socket.IO, Redis, specific Cron jobs) into reusable Components.
134
-
135
- **Structure of a Component:**
136
- 1. Extend `BaseComponent`.
137
- 2. Define default `bindings` (optional configuration/options).
138
- 3. Implement `binding()` to register services, providers, or attach logic to the application.
139
-
140
- **Example (`SocketIOComponent`):**
141
-
142
- ```typescript
143
- import { BaseComponent, inject, CoreBindings, Binding } from '@venizia/ignis';
144
-
145
- export class MySocketComponent extends BaseComponent {
146
- constructor(
147
- @inject({ key: CoreBindings.APPLICATION_INSTANCE }) private application: BaseApplication,
148
- ) {
149
- super({
150
- scope: MySocketComponent.name,
151
- // Automatically register bindings when component is loaded
152
- initDefault: { enable: true, container: application },
153
- bindings: {
154
- // Define default configuration binding
155
- 'my.socket.options': Binding.bind({ key: 'my.socket.options' }).toValue({ port: 8080 }),
156
- },
157
- });
158
- }
159
-
160
- // The binding method is called during application startup (preConfigure)
161
- override binding(): void {
162
- const options = this.application.get({ key: 'my.socket.options' });
163
-
164
- this.logger.info('Initializing Socket.IO with options: %j', options);
165
-
166
- // Perform setup logic, register other services, etc.
167
- // this.application.bind(...).toValue(...);
168
- }
169
- }
170
- ```
@@ -1,177 +0,0 @@
1
- # Data Modeling
2
-
3
- Ignis streamlines data modeling with Drizzle ORM by providing powerful helpers and "enrichers" that reduce boilerplate code for common schema patterns.
4
-
5
- ## 1. Base Entity
6
-
7
- All entity models should extend `BaseEntity`. This provides integration with the framework's repository layer and automatic schema generation support.
8
-
9
- The recommended pattern is to define the schema and relations as **static properties** on the class. This keeps the definition self-contained and enables powerful type inference.
10
-
11
- **Example (`src/models/entities/user.model.ts`):**
12
-
13
- ```typescript
14
- import { BaseEntity, extraUserColumns, generateIdColumnDefs, model } from '@venizia/ignis';
15
- import { pgTable } from 'drizzle-orm/pg-core';
16
-
17
- @model({ type: 'entity' })
18
- export class User extends BaseEntity<typeof User.schema> {
19
- // 1. Define schema as a static property
20
- static override schema = pgTable('User', {
21
- ...generateIdColumnDefs({ id: { dataType: 'string' } }),
22
- ...extraUserColumns({ idType: 'string' }),
23
- });
24
-
25
- // 2. Define relations as a static method (return empty array if none)
26
- static override relations = () => [];
27
- }
28
- ```
29
-
30
- ## 2. Schema Enrichers
31
-
32
- Instead of manually defining common columns like primary keys, timestamps, or audit fields in every table, use Ignis "enrichers".
33
-
34
- **Available Enrichers:**
35
-
36
- | Enricher | Description | Columns Added |
37
- |----------|-------------|---------------|
38
- | `generateIdColumnDefs` | Adds a Primary Key | `id` (string/UUID or number/Serial) |
39
- | `generateTzColumnDefs` | Adds timestamps | `createdAt`, `modifiedAt` (auto-updating) |
40
- | `generateUserAuditColumnDefs` | Adds audit fields | `createdBy`, `modifiedBy` |
41
- | `generateDataTypeColumnDefs` | Adds generic value fields | `nValue` (number), `tValue` (text), `jValue` (json), etc. |
42
- | `extraUserColumns` | Comprehensive user fields | Combines audit, timestamps, status, and type fields |
43
-
44
- **Usage Example:**
45
-
46
- ```typescript
47
- import {
48
- generateIdColumnDefs,
49
- generateTzColumnDefs,
50
- generateUserAuditColumnDefs,
51
- } from '@venizia/ignis';
52
- import { pgTable, text } from 'drizzle-orm/pg-core';
53
-
54
- export const configurationTable = pgTable(
55
- 'Configuration',
56
- {
57
- // 1. Auto-generate UUID Primary Key
58
- ...generateIdColumnDefs({ id: { dataType: 'string' } }),
59
-
60
- // 2. Auto-generate createdAt / modifiedAt
61
- ...generateTzColumnDefs(),
62
-
63
- // 3. Auto-generate createdBy / modifiedBy
64
- ...generateUserAuditColumnDefs({
65
- created: { dataType: 'string', columnName: 'created_by' },
66
- modified: { dataType: 'string', columnName: 'modified_by' },
67
- }),
68
-
69
- // 4. Your custom columns
70
- code: text('code').notNull(),
71
- description: text('description'),
72
- group: text('group').notNull(),
73
- },
74
- (table) => [
75
- // Define indexes/constraints here
76
- unique('UQ_code').on(table.code),
77
- ]
78
- );
79
- ```
80
-
81
- ## 3. Defining Relations
82
-
83
- Relations are defined using the `TRelationConfig` structure within the static `relations` method of your model.
84
-
85
- **Example (`src/models/entities/configuration.model.ts`):**
86
-
87
- ```typescript
88
- import {
89
- BaseEntity,
90
- model,
91
- RelationTypes,
92
- TRelationConfig,
93
- } from '@venizia/ignis';
94
- import { User } from './user.model';
95
-
96
- @model({ type: 'entity' })
97
- export class Configuration extends BaseEntity<typeof Configuration.schema> {
98
- // ... schema definition ...
99
-
100
- // Define relations
101
- static override relations = (): TRelationConfig[] => [
102
- {
103
- name: 'creator',
104
- type: RelationTypes.ONE,
105
- schema: User.schema,
106
- metadata: {
107
- fields: [Configuration.schema.createdBy],
108
- references: [User.schema.id],
109
- },
110
- },
111
- ];
112
- }
113
- ```
114
-
115
- ## 4. Repositories and Auto-Discovery
116
-
117
- Ignis simplifies the connection between models, repositories, and datasources.
118
-
119
- ### DataSource Auto-Discovery
120
-
121
- DataSources automatically discover their schema from the repositories that bind to them. You **do not** need to manually register schemas in the DataSource constructor.
122
-
123
- ```typescript
124
- // src/datasources/postgres.datasource.ts
125
- @datasource({ driver: 'node-postgres' })
126
- export class PostgresDataSource extends BaseDataSource<TNodePostgresConnector, IDSConfigs> {
127
- constructor() {
128
- super({
129
- name: PostgresDataSource.name,
130
- config: { /* connection config */ },
131
- // NO schema property needed - auto-discovered!
132
- });
133
- }
134
-
135
- override configure(): ValueOrPromise<void> {
136
- // This method automatically collects all schemas from bound repositories
137
- const schema = this.getSchema();
138
- this.connector = drizzle({ client: new Pool(this.settings), schema });
139
- }
140
- }
141
- ```
142
-
143
- ### Repository Binding
144
-
145
- Repositories use the `@repository` decorator to bind a **Model** to a **DataSource**. This binding is what powers the auto-discovery mechanism.
146
-
147
- **Pattern 1: Zero Boilerplate (Recommended)**
148
-
149
- For most repositories, you don't need a constructor. The DataSource is automatically injected.
150
-
151
- ```typescript
152
- @repository({ model: Configuration, dataSource: PostgresDataSource })
153
- export class ConfigurationRepository extends DefaultCRUDRepository<typeof Configuration.schema> {
154
- // No constructor needed!
155
- }
156
- ```
157
-
158
- **Pattern 2: Explicit Injection (Advanced)**
159
-
160
- If you need to perform custom initialization or inject additional dependencies, you can define a constructor. **Important:** The first parameter must be the DataSource.
161
-
162
- ```typescript
163
- @repository({ model: User, dataSource: PostgresDataSource })
164
- export class UserRepository extends ReadableRepository<typeof User.schema> {
165
- constructor(
166
- @inject({ key: 'datasources.PostgresDataSource' })
167
- dataSource: PostgresDataSource,
168
- ) {
169
- super(dataSource);
170
- }
171
-
172
- // Custom methods
173
- async findByRealm(realm: string) {
174
- return this.findOne({ filter: { where: { realm } } });
175
- }
176
- }
177
- ```