@venizia/ignis-docs 0.0.2 → 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 (134) 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 +647 -182
  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 +86 -0
  21. package/wiki/changelogs/2025-12-26-transaction-support.md +57 -0
  22. package/wiki/changelogs/2025-12-29-dynamic-binding-registration.md +104 -0
  23. package/wiki/changelogs/2025-12-29-snowflake-uid-helper.md +100 -0
  24. package/wiki/changelogs/2025-12-30-repository-enhancements.md +214 -0
  25. package/wiki/changelogs/2025-12-31-json-path-filtering-array-operators.md +214 -0
  26. package/wiki/changelogs/2025-12-31-string-id-custom-generator.md +137 -0
  27. package/wiki/changelogs/2026-01-02-default-filter-and-repository-mixins.md +418 -0
  28. package/wiki/changelogs/index.md +8 -1
  29. package/wiki/changelogs/planned-schema-migrator.md +2 -10
  30. package/wiki/{get-started/core-concepts → guides/core-concepts/application}/bootstrapping.md +18 -5
  31. package/wiki/{get-started/core-concepts/application.md → guides/core-concepts/application/index.md} +47 -104
  32. package/wiki/guides/core-concepts/components-guide.md +509 -0
  33. package/wiki/guides/core-concepts/components.md +122 -0
  34. package/wiki/{get-started → guides}/core-concepts/controllers.md +30 -13
  35. package/wiki/{get-started → guides}/core-concepts/dependency-injection.md +97 -0
  36. package/wiki/guides/core-concepts/persistent/datasources.md +179 -0
  37. package/wiki/guides/core-concepts/persistent/index.md +119 -0
  38. package/wiki/guides/core-concepts/persistent/models.md +241 -0
  39. package/wiki/guides/core-concepts/persistent/repositories.md +219 -0
  40. package/wiki/guides/core-concepts/persistent/transactions.md +170 -0
  41. package/wiki/{get-started → guides}/core-concepts/services.md +26 -3
  42. package/wiki/{get-started → guides/get-started}/5-minute-quickstart.md +59 -14
  43. package/wiki/guides/get-started/philosophy.md +682 -0
  44. package/wiki/guides/get-started/setup.md +157 -0
  45. package/wiki/guides/index.md +89 -0
  46. package/wiki/guides/reference/glossary.md +243 -0
  47. package/wiki/{get-started → guides/reference}/mcp-docs-server.md +0 -10
  48. package/wiki/{get-started → guides/tutorials}/building-a-crud-api.md +134 -132
  49. package/wiki/{get-started/quickstart.md → guides/tutorials/complete-installation.md} +107 -71
  50. package/wiki/guides/tutorials/ecommerce-api.md +1399 -0
  51. package/wiki/guides/tutorials/realtime-chat.md +1261 -0
  52. package/wiki/guides/tutorials/testing.md +723 -0
  53. package/wiki/index.md +176 -37
  54. package/wiki/references/base/application.md +27 -0
  55. package/wiki/references/base/bootstrapping.md +30 -26
  56. package/wiki/references/base/components.md +532 -31
  57. package/wiki/references/base/controllers.md +136 -38
  58. package/wiki/references/base/datasources.md +108 -5
  59. package/wiki/references/base/dependency-injection.md +39 -3
  60. package/wiki/references/base/filter-system/application-usage.md +224 -0
  61. package/wiki/references/base/filter-system/array-operators.md +132 -0
  62. package/wiki/references/base/filter-system/comparison-operators.md +109 -0
  63. package/wiki/references/base/filter-system/default-filter.md +428 -0
  64. package/wiki/references/base/filter-system/fields-order-pagination.md +155 -0
  65. package/wiki/references/base/filter-system/index.md +127 -0
  66. package/wiki/references/base/filter-system/json-filtering.md +197 -0
  67. package/wiki/references/base/filter-system/list-operators.md +71 -0
  68. package/wiki/references/base/filter-system/logical-operators.md +156 -0
  69. package/wiki/references/base/filter-system/null-operators.md +58 -0
  70. package/wiki/references/base/filter-system/pattern-matching.md +108 -0
  71. package/wiki/references/base/filter-system/quick-reference.md +431 -0
  72. package/wiki/references/base/filter-system/range-operators.md +63 -0
  73. package/wiki/references/base/filter-system/tips.md +190 -0
  74. package/wiki/references/base/filter-system/use-cases.md +452 -0
  75. package/wiki/references/base/index.md +90 -0
  76. package/wiki/references/base/middlewares.md +602 -0
  77. package/wiki/references/base/models.md +215 -23
  78. package/wiki/references/base/providers.md +732 -0
  79. package/wiki/references/base/repositories/advanced.md +555 -0
  80. package/wiki/references/base/repositories/index.md +228 -0
  81. package/wiki/references/base/repositories/mixins.md +331 -0
  82. package/wiki/references/base/repositories/relations.md +486 -0
  83. package/wiki/references/base/repositories.md +40 -549
  84. package/wiki/references/base/services.md +28 -4
  85. package/wiki/references/components/authentication.md +22 -2
  86. package/wiki/references/components/health-check.md +12 -0
  87. package/wiki/references/components/index.md +23 -0
  88. package/wiki/references/components/mail.md +687 -0
  89. package/wiki/references/components/request-tracker.md +16 -0
  90. package/wiki/references/components/socket-io.md +18 -0
  91. package/wiki/references/components/static-asset.md +14 -26
  92. package/wiki/references/components/swagger.md +17 -0
  93. package/wiki/references/configuration/environment-variables.md +427 -0
  94. package/wiki/references/configuration/index.md +73 -0
  95. package/wiki/references/helpers/cron.md +14 -0
  96. package/wiki/references/helpers/crypto.md +15 -0
  97. package/wiki/references/helpers/env.md +16 -0
  98. package/wiki/references/helpers/error.md +17 -0
  99. package/wiki/references/helpers/index.md +15 -0
  100. package/wiki/references/helpers/inversion.md +24 -4
  101. package/wiki/references/helpers/logger.md +19 -0
  102. package/wiki/references/helpers/network.md +11 -0
  103. package/wiki/references/helpers/queue.md +19 -0
  104. package/wiki/references/helpers/redis.md +21 -0
  105. package/wiki/references/helpers/socket-io.md +24 -5
  106. package/wiki/references/helpers/storage.md +18 -10
  107. package/wiki/references/helpers/testing.md +18 -0
  108. package/wiki/references/helpers/types.md +167 -0
  109. package/wiki/references/helpers/uid.md +167 -0
  110. package/wiki/references/helpers/worker-thread.md +16 -0
  111. package/wiki/references/index.md +177 -0
  112. package/wiki/references/quick-reference.md +634 -0
  113. package/wiki/references/src-details/boot.md +3 -3
  114. package/wiki/references/src-details/dev-configs.md +0 -4
  115. package/wiki/references/src-details/docs.md +2 -2
  116. package/wiki/references/src-details/index.md +86 -0
  117. package/wiki/references/src-details/inversion.md +1 -6
  118. package/wiki/references/src-details/mcp-server.md +3 -15
  119. package/wiki/references/utilities/index.md +86 -10
  120. package/wiki/references/utilities/jsx.md +577 -0
  121. package/wiki/references/utilities/request.md +0 -2
  122. package/wiki/references/utilities/statuses.md +740 -0
  123. package/wiki/changelogs/planned-transaction-support.md +0 -216
  124. package/wiki/get-started/best-practices/api-usage-examples.md +0 -266
  125. package/wiki/get-started/best-practices/architectural-patterns.md +0 -170
  126. package/wiki/get-started/best-practices/data-modeling.md +0 -177
  127. package/wiki/get-started/best-practices/deployment-strategies.md +0 -121
  128. package/wiki/get-started/best-practices/performance-optimization.md +0 -88
  129. package/wiki/get-started/best-practices/security-guidelines.md +0 -99
  130. package/wiki/get-started/core-concepts/components.md +0 -98
  131. package/wiki/get-started/core-concepts/persistent.md +0 -543
  132. package/wiki/get-started/index.md +0 -65
  133. package/wiki/get-started/philosophy.md +0 -296
  134. package/wiki/get-started/prerequisites.md +0 -113
@@ -0,0 +1,122 @@
1
+ # Components
2
+
3
+ Components are reusable, pluggable modules that encapsulate a group of related features. A component acts as a powerful container for various resources—including providers, services, controllers, repositories, and even entire mini-applications—making it easy to share and integrate complex functionality across projects.
4
+
5
+ > **Deep Dive:** See [Components Reference](../../references/base/components.md) for detailed implementation patterns, directory structure, and best practices.
6
+
7
+ ## What is a Component?
8
+
9
+ A component is a class that extends `BaseComponent` and is responsible for:
10
+
11
+ - **Binding Dependencies**: Registering services, controllers, repositories, providers, or other resources with the application's dependency injection container.
12
+ - **Configuring Features**: Setting up middlewares, initializing services, or performing any other setup required for the feature to work.
13
+
14
+ A single component can bundle everything needed for a specific domain—for example, an "AuthComponent" might include multiple services for token management, repositories for user data, and controllers for login/signup endpoints, essentially functioning as a plug-and-play mini-application.
15
+
16
+ ## Built-in Components
17
+
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.
19
+
20
+ ## Creating a Simple Component
21
+
22
+ ```typescript
23
+ import { BaseApplication, BaseComponent, inject, CoreBindings, ValueOrPromise, Binding } from '@venizia/ignis';
24
+
25
+ // Define a service
26
+ class NotificationService {
27
+ send(opts: { message: string }) { /* ... */ }
28
+ }
29
+
30
+ // Define a controller
31
+ @controller({ path: '/notifications' })
32
+ class NotificationController extends BaseController {
33
+ constructor(
34
+ @inject({ key: 'services.NotificationService' })
35
+ private _notificationService: NotificationService
36
+ ) {
37
+ super({ scope: NotificationController.name });
38
+ }
39
+ }
40
+
41
+ // Create the component
42
+ export class NotificationComponent extends BaseComponent {
43
+ constructor(
44
+ @inject({ key: CoreBindings.APPLICATION_INSTANCE })
45
+ private _application: BaseApplication,
46
+ ) {
47
+ super({
48
+ scope: NotificationComponent.name,
49
+ initDefault: { enable: true, container: _application },
50
+ bindings: {
51
+ 'services.NotificationService': Binding.bind({ key: 'services.NotificationService' })
52
+ .toClass(NotificationService),
53
+ },
54
+ });
55
+ }
56
+
57
+ override binding(): ValueOrPromise<void> {
58
+ this._application.controller(NotificationController);
59
+ }
60
+ }
61
+ ```
62
+
63
+ ## Component Lifecycle
64
+
65
+ | Stage | Method | Description |
66
+ | :--- | :--- | :--- |
67
+ | **1. Instantiation** | `constructor()` | Component is created. Define default `bindings` here. |
68
+ | **2. Configuration** | `binding()` | Called during startup. Register controllers and resources here. |
69
+
70
+ ## Registering a Component
71
+
72
+ Register components in your application's `preConfigure` method:
73
+
74
+ ```typescript
75
+ // src/application.ts
76
+ export class Application extends BaseApplication {
77
+ preConfigure(): ValueOrPromise<void> {
78
+ this.component(HealthCheckComponent);
79
+ this.component(SwaggerComponent);
80
+ this.component(NotificationComponent);
81
+ }
82
+ }
83
+ ```
84
+
85
+ ## Customizing Component Options
86
+
87
+ Most components accept configuration options. Override them before registration:
88
+
89
+ ```typescript
90
+ // src/application.ts
91
+ export class Application extends BaseApplication {
92
+ preConfigure(): ValueOrPromise<void> {
93
+ // Override options BEFORE registering component
94
+ this.bind<IHealthCheckOptions>({ key: HealthCheckBindingKeys.HEALTH_CHECK_OPTIONS })
95
+ .toValue({ restOptions: { path: '/api/health' } });
96
+
97
+ this.component(HealthCheckComponent);
98
+ }
99
+ }
100
+ ```
101
+
102
+ > **Next Steps:**
103
+ > - [Creating Components Guide](./components-guide.md) - Step-by-step tutorial for building your own components
104
+ > - [Components Reference](../../references/base/components.md) - Directory structure, keys, types, constants patterns
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