@venizia/ignis-docs 0.0.3 → 0.0.4-0

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 +30 -26
  55. package/wiki/references/base/components.md +24 -7
  56. package/wiki/references/base/controllers.md +51 -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 +602 -0
  76. package/wiki/references/base/models.md +215 -23
  77. package/wiki/references/base/providers.md +732 -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
@@ -15,16 +15,7 @@ A single component can bundle everything needed for a specific domain—for exam
15
15
 
16
16
  ## Built-in Components
17
17
 
18
- `Ignis` comes with several built-in components, which you can explore in the [**Components Reference**](../../references/components/) section:
19
-
20
- | Component | Description |
21
- |-----------|-------------|
22
- | `AuthenticateComponent` | JWT-based authentication with token services |
23
- | `SwaggerComponent` | Interactive OpenAPI documentation |
24
- | `HealthCheckComponent` | Health check endpoints |
25
- | `RequestTrackerComponent` | Request logging and tracing |
26
- | `SocketIOComponent` | Real-time communication with Socket.IO |
27
- | `StaticAssetComponent` | File upload and storage management |
18
+ Ignis includes ready-to-use components for common features like authentication, API documentation, health checks, and more. See the [**Built-in Components Reference**](../../references/components/) for the complete list with detailed documentation.
28
19
 
29
20
  ## Creating a Simple Component
30
21
 
@@ -33,7 +24,7 @@ import { BaseApplication, BaseComponent, inject, CoreBindings, ValueOrPromise, B
33
24
 
34
25
  // Define a service
35
26
  class NotificationService {
36
- send(message: string) { /* ... */ }
27
+ send(opts: { message: string }) { /* ... */ }
37
28
  }
38
29
 
39
30
  // Define a controller
@@ -41,7 +32,7 @@ class NotificationService {
41
32
  class NotificationController extends BaseController {
42
33
  constructor(
43
34
  @inject({ key: 'services.NotificationService' })
44
- private notificationService: NotificationService
35
+ private _notificationService: NotificationService
45
36
  ) {
46
37
  super({ scope: NotificationController.name });
47
38
  }
@@ -51,11 +42,11 @@ class NotificationController extends BaseController {
51
42
  export class NotificationComponent extends BaseComponent {
52
43
  constructor(
53
44
  @inject({ key: CoreBindings.APPLICATION_INSTANCE })
54
- private application: BaseApplication,
45
+ private _application: BaseApplication,
55
46
  ) {
56
47
  super({
57
48
  scope: NotificationComponent.name,
58
- initDefault: { enable: true, container: application },
49
+ initDefault: { enable: true, container: _application },
59
50
  bindings: {
60
51
  'services.NotificationService': Binding.bind({ key: 'services.NotificationService' })
61
52
  .toClass(NotificationService),
@@ -64,7 +55,7 @@ export class NotificationComponent extends BaseComponent {
64
55
  }
65
56
 
66
57
  override binding(): ValueOrPromise<void> {
67
- this.application.controller(NotificationController);
58
+ this._application.controller(NotificationController);
68
59
  }
69
60
  }
70
61
  ```
@@ -108,8 +99,24 @@ export class Application extends BaseApplication {
108
99
  }
109
100
  ```
110
101
 
111
- ---
112
-
113
102
  > **Next Steps:**
103
+ > - [Creating Components Guide](./components-guide.md) - Step-by-step tutorial for building your own components
114
104
  > - [Components Reference](../../references/base/components.md) - Directory structure, keys, types, constants patterns
115
105
  > - [Built-in Components](../../references/components/) - Detailed documentation for each component
106
+
107
+ ## See Also
108
+
109
+ - **Related Concepts:**
110
+ - [Application](/guides/core-concepts/application/) - Registering components
111
+ - [Dependency Injection](/guides/core-concepts/dependency-injection) - Component bindings
112
+ - [Creating Components](./components-guide) - Build your own components
113
+
114
+ - **References:**
115
+ - [BaseComponent API](/references/base/components) - Complete API reference
116
+ - [Authentication Component](/references/components/authentication) - JWT authentication
117
+ - [Health Check Component](/references/components/health-check) - Health endpoints
118
+ - [Swagger Component](/references/components/swagger) - API documentation
119
+ - [Socket.IO Component](/references/components/socket-io) - WebSocket support
120
+
121
+ - **Best Practices:**
122
+ - [Architectural Patterns](/best-practices/architectural-patterns) - Component design patterns
@@ -74,8 +74,8 @@ import { BaseController, controller, get, post, HTTP, jsonContent, jsonResponse,
74
74
  import { z } from '@hono/zod-openapi';
75
75
 
76
76
  // Define route configs as const for type inference
77
- const TEST_ROUTES = {
78
- getData: {
77
+ const TestRoutes = {
78
+ GET_DATA: {
79
79
  method: HTTP.Methods.GET,
80
80
  path: '/',
81
81
  responses: jsonResponse({
@@ -83,7 +83,7 @@ const TEST_ROUTES = {
83
83
  schema: z.object({ message: z.string(), method: z.string() }),
84
84
  }),
85
85
  },
86
- createItem: {
86
+ CREATE_ITEM: {
87
87
  method: HTTP.Methods.POST,
88
88
  path: '/',
89
89
  request: {
@@ -105,18 +105,18 @@ export class MyItemsController extends BaseController {
105
105
  super({ scope: MyItemsController.name, path: '/my-items' });
106
106
  }
107
107
 
108
- @get({ configs: TEST_ROUTES.getData })
109
- getData(c: TRouteContext<typeof TEST_ROUTES.getData>) { // Return type is automatically inferred
108
+ @get({ configs: TestRoutes.GET_DATA })
109
+ getData(c: TRouteContext<typeof TestRoutes.GET_DATA>) { // Return type is automatically inferred
110
110
  // 'c' is fully typed here, including c.req.valid and c.json return type
111
111
  return c.json({ message: 'Hello from decorator', method: 'GET' }, HTTP.ResultCodes.RS_2.Ok);
112
112
  }
113
113
 
114
- @post({ configs: TEST_ROUTES.createItem })
115
- createItem(c: TRouteContext<typeof TEST_ROUTES.createItem>) { // Return type is automatically inferred
116
- // c.req.valid('json') is automatically typed based on createItem.request.body.content['application/json'].schema
114
+ @post({ configs: TestRoutes.CREATE_ITEM })
115
+ createItem(c: TRouteContext<typeof TestRoutes.CREATE_ITEM>) { // Return type is automatically inferred
116
+ // c.req.valid('json') is automatically typed based on CREATE_ITEM.request.body.content['application/json'].schema
117
117
  const body = c.req.valid('json');
118
118
 
119
- // Return type is automatically validated against createItem.responses[200].content['application/json'].schema
119
+ // Return type is automatically validated against CREATE_ITEM.responses[200].content['application/json'].schema
120
120
  return c.json(
121
121
  {
122
122
  id: 'some-uuid',
@@ -204,7 +204,7 @@ this.bindRoute({
204
204
  configs: GetUserByIdRoute,
205
205
  }).to({
206
206
  handler: (c: TRouteContext<typeof GetUserByIdRoute>) => { // Return type is automatically inferred
207
- const { id } = c.req.param();
207
+ const { id } = c.req.valid('param'); // Use valid() for type-safe validated params
208
208
  return c.json({ id: id, name: 'John Doe' }, HTTP.ResultCodes.RS_2.Ok);
209
209
  },
210
210
  });
@@ -409,7 +409,7 @@ import { jsonContent, put, TRouteContext, HTTP } from '@venizia/ignis';
409
409
 
410
410
  // ... inside a controller class
411
411
 
412
- const updateUserConfig = {
412
+ const UpdateUserConfig = {
413
413
  path: '/:id',
414
414
  method: 'put',
415
415
  request: {
@@ -422,8 +422,8 @@ const updateUserConfig = {
422
422
  // ... responses
423
423
  } as const; // Use 'as const' for strict type inference
424
424
 
425
- @put({ configs: updateUserConfig })
426
- updateUser(c: TRouteContext<typeof updateUserConfig>) {
425
+ @put({ configs: UpdateUserConfig })
426
+ updateUser(c: TRouteContext<typeof UpdateUserConfig>) {
427
427
  // Access validated data from the request
428
428
  const { id } = c.req.valid('param');
429
429
  const { notify } = c.req.valid('query');
@@ -439,3 +439,20 @@ updateUser(c: TRouteContext<typeof updateUserConfig>) {
439
439
  ```
440
440
 
441
441
  Using `TRouteContext` provides full type inference for `c.req.valid()`, so your editor will know that `id` is a string, `notify` is an optional string, and `userUpdateData` matches the body schema.
442
+
443
+ ## See Also
444
+
445
+ - **Related Concepts:**
446
+ - [Application](/guides/core-concepts/application/) - Registering controllers
447
+ - [Services](/guides/core-concepts/services) - Business logic layer called by controllers
448
+ - [Dependency Injection](/guides/core-concepts/dependency-injection) - Injecting services into controllers
449
+
450
+ - **References:**
451
+ - [BaseController API](/references/base/controllers) - Complete API reference
452
+ - [Middlewares](/references/base/middlewares) - Request interceptors
453
+ - [Swagger Component](/references/components/swagger) - Auto-generate API docs
454
+ - [Schema Utilities](/references/utilities/schema) - Request/response helpers
455
+
456
+ - **Tutorials:**
457
+ - [Building a CRUD API](/guides/tutorials/building-a-crud-api) - Controller examples
458
+ - [E-commerce API](/guides/tutorials/ecommerce-api) - Advanced routing patterns
@@ -170,3 +170,100 @@ You would then bind this provider in your application:
170
170
  this.bind<ThirdPartyApiClient>({ key: 'services.ApiClient' })
171
171
  .toProvider(ApiClientProvider);
172
172
  ```
173
+
174
+ ## Standalone Containers
175
+
176
+ You can create independent DI containers using the `Container` class directly. These containers are **completely separate** from the application's context and do not share any bindings.
177
+
178
+ ### Creating an Independent Container
179
+
180
+ ```typescript
181
+ import { Container, BindingScopes } from '@venizia/ignis-inversion';
182
+
183
+ // Create a standalone container
184
+ const container = new Container({ scope: 'MyCustomContainer' });
185
+
186
+ // Bind dependencies
187
+ container.bind({ key: 'config.apiKey' }).toValue('my-secret-key');
188
+ container.bind({ key: 'services.Logger' }).toClass(LoggerService);
189
+ container.bind({ key: 'services.Cache' })
190
+ .toClass(CacheService)
191
+ .setScope(BindingScopes.SINGLETON);
192
+
193
+ // Resolve dependencies
194
+ const logger = container.get<LoggerService>({ key: 'services.Logger' });
195
+ const apiKey = container.getSync<string>({ key: 'config.apiKey' });
196
+ ```
197
+
198
+ ### Use Cases
199
+
200
+ | Use Case | Description |
201
+ |----------|-------------|
202
+ | **Unit Testing** | Create isolated containers with mock dependencies for each test |
203
+ | **Isolated Modules** | Build self-contained modules with their own dependency graph |
204
+ | **Multi-Tenancy** | Separate containers per tenant with tenant-specific configurations |
205
+ | **Worker Threads** | Independent containers for background workers |
206
+ | **Plugin Systems** | Each plugin gets its own container to prevent conflicts |
207
+
208
+ ### Example: Testing with Isolated Container
209
+
210
+ ```typescript
211
+ import { Container } from '@venizia/ignis-inversion';
212
+ import { describe, it, expect, beforeEach } from 'bun:test';
213
+
214
+ describe('UserService', () => {
215
+ let container: Container;
216
+
217
+ beforeEach(() => {
218
+ // Fresh container for each test
219
+ container = new Container({ scope: 'TestContainer' });
220
+
221
+ // Bind mock dependencies
222
+ container.bind({ key: 'repositories.UserRepository' }).toValue({
223
+ findById: async () => ({ id: '1', name: 'Test User' }),
224
+ });
225
+
226
+ container.bind({ key: 'services.UserService' }).toClass(UserService);
227
+ });
228
+
229
+ it('should find user by id', async () => {
230
+ const userService = container.get<UserService>({ key: 'services.UserService' });
231
+ const user = await userService.findById({ id: '1' });
232
+
233
+ expect(user.name).toBe('Test User');
234
+ });
235
+ });
236
+ ```
237
+
238
+ ### Container vs Application
239
+
240
+ | Aspect | `Application` (extends Container) | Standalone `Container` |
241
+ |--------|-----------------------------------|------------------------|
242
+ | **Purpose** | Full HTTP server with routing, middleware | Pure dependency injection |
243
+ | **Bindings** | Shared across entire application | Isolated, no sharing |
244
+ | **Lifecycle** | Managed by framework | You control it |
245
+ | **Use Case** | Main application | Testing, isolated modules, workers |
246
+
247
+ ::: tip
248
+ The `Application` class extends `Container`, so all container methods (`bind`, `get`, `getSync`) are available on your application instance. Standalone containers are useful when you need isolation from the main application context.
249
+ :::
250
+
251
+ ## See Also
252
+
253
+ - **Related Concepts:**
254
+ - [Application](/guides/core-concepts/application/) - Application extends Container
255
+ - [Controllers](/guides/core-concepts/controllers) - Use DI for injecting services
256
+ - [Services](/guides/core-concepts/services) - Use DI for injecting repositories
257
+ - [Providers](/references/base/providers) - Factory pattern for dynamic injection
258
+
259
+ - **References:**
260
+ - [Dependency Injection API](/references/base/dependency-injection) - Complete API reference
261
+ - [Inversion Helper](/references/helpers/inversion) - DI container utilities
262
+ - [Glossary](/guides/reference/glossary#dependency-injection-di) - DI concepts explained
263
+
264
+ - **Tutorials:**
265
+ - [Testing](/guides/tutorials/testing) - Unit testing with mocked dependencies
266
+ - [Building a CRUD API](/guides/tutorials/building-a-crud-api) - DI in practice
267
+
268
+ - **Best Practices:**
269
+ - [Architectural Patterns](/best-practices/architectural-patterns) - DI patterns and anti-patterns
@@ -0,0 +1,179 @@
1
+ # DataSources
2
+
3
+ A DataSource manages database connections and supports **schema auto-discovery** from repositories.
4
+
5
+ ::: info PostgreSQL First
6
+ IGNIS currently focuses on **PostgreSQL** as the primary database. Support for other database systems (MySQL, SQLite, etc.) is planned for future releases.
7
+ :::
8
+
9
+ ## Creating a DataSource
10
+
11
+ ```typescript
12
+ // src/datasources/postgres.datasource.ts
13
+ import {
14
+ BaseDataSource,
15
+ datasource,
16
+ TNodePostgresConnector,
17
+ ValueOrPromise,
18
+ } from '@venizia/ignis';
19
+ import { drizzle } from 'drizzle-orm/node-postgres';
20
+ import { Pool } from 'pg';
21
+
22
+ interface IDSConfigs {
23
+ host: string;
24
+ port: number;
25
+ database: string;
26
+ user: string;
27
+ password: string;
28
+ }
29
+
30
+ @datasource({ driver: 'node-postgres' })
31
+ export class PostgresDataSource extends BaseDataSource<TNodePostgresConnector, IDSConfigs> {
32
+ constructor() {
33
+ super({
34
+ name: PostgresDataSource.name,
35
+ config: {
36
+ host: process.env.POSTGRES_HOST ?? 'localhost',
37
+ port: +(process.env.POSTGRES_PORT ?? 5432),
38
+ database: process.env.POSTGRES_DATABASE ?? 'mydb',
39
+ user: process.env.POSTGRES_USER ?? 'postgres',
40
+ password: process.env.POSTGRES_PASSWORD ?? '',
41
+ },
42
+ // No schema needed - auto-discovered from @repository bindings!
43
+ });
44
+ }
45
+
46
+ override configure(): ValueOrPromise<void> {
47
+ // getSchema() auto-discovers models from @repository bindings
48
+ const schema = this.getSchema();
49
+
50
+ this.logger.debug(
51
+ '[configure] Auto-discovered schema | Keys: %o',
52
+ Object.keys(schema),
53
+ );
54
+
55
+ this.pool = new Pool(this.settings);
56
+ this.connector = drizzle({ client: this.pool, schema });
57
+ }
58
+
59
+ override getConnectionString(): ValueOrPromise<string> {
60
+ const { host, port, user, password, database } = this.settings;
61
+ return `postgresql://${user}:${password}@${host}:${port}/${database}`;
62
+ }
63
+ }
64
+ ```
65
+
66
+ **How auto-discovery works:**
67
+
68
+ 1. `@repository` decorators register model-datasource bindings
69
+ 2. When `configure()` is called, `getSchema()` collects all bound models
70
+ 3. Drizzle is initialized with the complete schema
71
+
72
+ ## Manual Schema (Optional)
73
+
74
+ If you need explicit control, you can still provide schema manually:
75
+
76
+ ```typescript
77
+ @datasource({ driver: 'node-postgres' })
78
+ export class PostgresDataSource extends BaseDataSource<TNodePostgresConnector, IDSConfigs> {
79
+ constructor() {
80
+ super({
81
+ name: PostgresDataSource.name,
82
+ config: { /* ... */ },
83
+ schema: {
84
+ User: User.schema,
85
+ Configuration: Configuration.schema,
86
+ // Add relations if using Drizzle's relational queries
87
+ },
88
+ });
89
+ }
90
+ }
91
+ ```
92
+
93
+ ## Registering a DataSource
94
+
95
+ ```typescript
96
+ // src/application.ts
97
+ export class Application extends BaseApplication {
98
+ preConfigure(): ValueOrPromise<void> {
99
+ this.dataSource(PostgresDataSource);
100
+ }
101
+ }
102
+ ```
103
+
104
+ ## Supported Drivers
105
+
106
+ | Driver | Package | Status |
107
+ |--------|---------|--------|
108
+ | `node-postgres` | `pg` | ✅ Supported |
109
+ | `mysql2` | `mysql2` | 🔜 Planned |
110
+ | `better-sqlite3` | `better-sqlite3` | 🔜 Planned |
111
+
112
+ ## DataSource Template
113
+
114
+ ```typescript
115
+ import { BaseDataSource, datasource, TNodePostgresConnector, ValueOrPromise } from '@venizia/ignis';
116
+ import { drizzle } from 'drizzle-orm/node-postgres';
117
+ import { Pool } from 'pg';
118
+
119
+ interface IDSConfigs {
120
+ host: string;
121
+ port: number;
122
+ database: string;
123
+ user: string;
124
+ password: string;
125
+ }
126
+
127
+ @datasource({ driver: 'node-postgres' })
128
+ export class PostgresDataSource extends BaseDataSource<TNodePostgresConnector, IDSConfigs> {
129
+ constructor() {
130
+ super({
131
+ name: PostgresDataSource.name,
132
+ config: {
133
+ host: process.env.POSTGRES_HOST ?? 'localhost',
134
+ port: +(process.env.POSTGRES_PORT ?? 5432),
135
+ database: process.env.POSTGRES_DATABASE ?? 'mydb',
136
+ user: process.env.POSTGRES_USER ?? 'postgres',
137
+ password: process.env.POSTGRES_PASSWORD ?? '',
138
+ },
139
+ });
140
+ }
141
+
142
+ override configure(): ValueOrPromise<void> {
143
+ const schema = this.getSchema();
144
+ this.pool = new Pool(this.settings);
145
+ this.connector = drizzle({ client: this.pool, schema });
146
+ }
147
+
148
+ override getConnectionString(): ValueOrPromise<string> {
149
+ const { host, port, user, password, database } = this.settings;
150
+ return `postgresql://${user}:${password}@${host}:${port}/${database}`;
151
+ }
152
+ }
153
+ ```
154
+
155
+ > **Deep Dive:** See [BaseDataSource Reference](../../../references/base/datasources.md) for connection pooling and advanced configuration.
156
+
157
+ ## See Also
158
+
159
+ - **Related Concepts:**
160
+ - [Repositories](/guides/core-concepts/persistent/repositories) - Use DataSources for database access
161
+ - [Models](/guides/core-concepts/persistent/models) - Entity schemas loaded by DataSource
162
+ - [Transactions](/guides/core-concepts/persistent/transactions) - Multi-operation database transactions
163
+ - [Application](/guides/core-concepts/application/) - Registering DataSources
164
+
165
+ - **References:**
166
+ - [BaseDataSource API](/references/base/datasources) - Complete API reference
167
+ - [Environment Variables](/references/configuration/environment-variables) - Configuration management
168
+
169
+ - **External Resources:**
170
+ - [Drizzle ORM Documentation](https://orm.drizzle.team/) - ORM configuration
171
+ - [node-postgres Documentation](https://node-postgres.com/) - Connection pooling guide
172
+
173
+ - **Best Practices:**
174
+ - [Performance Optimization](/best-practices/performance-optimization) - Connection pool tuning
175
+ - [Security Guidelines](/best-practices/security-guidelines) - Database credential management
176
+
177
+ - **Tutorials:**
178
+ - [Complete Installation](/guides/tutorials/complete-installation) - Database setup
179
+ - [Building a CRUD API](/guides/tutorials/building-a-crud-api) - DataSource configuration
@@ -0,0 +1,119 @@
1
+ # Persistent Layer
2
+
3
+ The persistent layer manages data using [Drizzle ORM](https://orm.drizzle.team/) for type-safe database access and the Repository pattern for data abstraction.
4
+
5
+ ## Architecture Overview
6
+
7
+ ```
8
+ ┌─────────────────────────────────────────────────────────┐
9
+ │ Application │
10
+ ├─────────────────────────────────────────────────────────┤
11
+ │ Controllers → Services → Repositories → Database │
12
+ └─────────────────────────────────────────────────────────┘
13
+
14
+
15
+ ┌────────────────┴────────────────┐
16
+ │ │
17
+ ┌─────┴─────┐ ┌───────┴───────┐
18
+ │ Models │ │ DataSources │
19
+ │ (Schema) │ │ (Connection) │
20
+ └───────────┘ └───────────────┘
21
+ ```
22
+
23
+ ## Core Components
24
+
25
+ | Component | Description | Learn More |
26
+ |-----------|-------------|------------|
27
+ | **Models** | Define data structure with Drizzle schemas and relations | [Models Guide](./models.md) |
28
+ | **DataSources** | Manage database connections with auto-discovery | [DataSources Guide](./datasources.md) |
29
+ | **Repositories** | Provide type-safe CRUD operations | [Repositories Guide](./repositories.md) |
30
+ | **Transactions** | Handle atomic multi-step operations | [Transactions Guide](./transactions.md) |
31
+
32
+ ## Quick Example
33
+
34
+ ```typescript
35
+ // 1. Define a Model
36
+ @model({ type: 'entity' })
37
+ export class User extends BaseEntity<typeof User.schema> {
38
+ static override schema = pgTable('User', {
39
+ ...generateIdColumnDefs({ id: { dataType: 'string' } }),
40
+ name: text('name').notNull(),
41
+ email: text('email').notNull(),
42
+ });
43
+
44
+ static override relations = () => [];
45
+ }
46
+
47
+ // 2. Create a DataSource
48
+ @datasource({ driver: 'node-postgres' })
49
+ export class PostgresDataSource extends BaseDataSource<TNodePostgresConnector, IDSConfigs> {
50
+ constructor() {
51
+ super({
52
+ name: PostgresDataSource.name,
53
+ config: {
54
+ host: process.env.POSTGRES_HOST ?? 'localhost',
55
+ port: +(process.env.POSTGRES_PORT ?? 5432),
56
+ database: process.env.POSTGRES_DATABASE ?? 'mydb',
57
+ user: process.env.POSTGRES_USER ?? 'postgres',
58
+ password: process.env.POSTGRES_PASSWORD ?? '',
59
+ },
60
+ });
61
+ }
62
+
63
+ override configure(): ValueOrPromise<void> {
64
+ const schema = this.getSchema();
65
+ this.pool = new Pool(this.settings);
66
+ this.connector = drizzle({ client: this.pool, schema });
67
+ }
68
+ }
69
+
70
+ // 3. Create a Repository
71
+ @repository({ model: User, dataSource: PostgresDataSource })
72
+ export class UserRepository extends DefaultCRUDRepository<typeof User.schema> {
73
+ async findByEmail(opts: { email: string }) {
74
+ return this.findOne({ filter: { where: { email: opts.email } } });
75
+ }
76
+ }
77
+
78
+ // 4. Use in Application
79
+ export class Application extends BaseApplication {
80
+ preConfigure() {
81
+ this.dataSource(PostgresDataSource);
82
+ this.repository(UserRepository);
83
+ }
84
+ }
85
+ ```
86
+
87
+ ## Next Steps
88
+
89
+ 1. **[Models](./models.md)** - Learn how to define your data structure
90
+ 2. **[DataSources](./datasources.md)** - Configure database connections
91
+ 3. **[Repositories](./repositories.md)** - Master CRUD operations and queries
92
+ 4. **[Transactions](./transactions.md)** - Handle atomic operations
93
+
94
+ > **Deep Dive:** See [Repository Reference](../../../references/base/repositories/) for advanced filtering, relations, and operators.
95
+
96
+ ## See Also
97
+
98
+ - **Persistent Layer Topics:**
99
+ - [Models](./models) - Entity definitions and schemas
100
+ - [DataSources](./datasources) - Database connections
101
+ - [Repositories](./repositories) - Data access layer
102
+ - [Transactions](./transactions) - Atomic operations
103
+
104
+ - **Related Concepts:**
105
+ - [Services](/guides/core-concepts/services) - Use repositories for business logic
106
+ - [Application](/guides/core-concepts/application/) - Registering persistent resources
107
+
108
+ - **References:**
109
+ - [Models API](/references/base/models) - Complete models reference
110
+ - [DataSources API](/references/base/datasources) - Complete datasources reference
111
+ - [Repositories API](/references/base/repositories/) - Complete repositories reference
112
+ - [Filter System](/references/base/filter-system/) - Query operators
113
+
114
+ - **External Resources:**
115
+ - [Drizzle ORM Documentation](https://orm.drizzle.team/) - ORM guide
116
+
117
+ - **Tutorials:**
118
+ - [Building a CRUD API](/guides/tutorials/building-a-crud-api) - Complete persistence example
119
+ - [E-commerce API](/guides/tutorials/ecommerce-api) - Advanced persistence patterns