@venizia/ignis-docs 0.2.1-0 → 0.2.1-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.
- package/content/best-practices/architectural-patterns.md +3 -3
- package/content/best-practices/code-style-standards/naming-conventions.md +1 -1
- package/content/best-practices/contribution-workflow.md +2 -2
- package/content/best-practices/error-handling.md +94 -89
- package/content/best-practices/security-guidelines.md +5 -5
- package/content/extensions/components/api-reference.md +22 -21
- package/content/extensions/components/authentication/api.md +64 -28
- package/content/extensions/components/authentication/errors.md +19 -5
- package/content/extensions/components/authentication/index.md +19 -18
- package/content/extensions/components/authentication/usage.md +55 -30
- package/content/extensions/components/authorization/api.md +351 -84
- package/content/extensions/components/authorization/errors.md +51 -17
- package/content/extensions/components/authorization/getting-started.md +227 -0
- package/content/extensions/components/authorization/index.md +24 -16
- package/content/extensions/components/authorization/usage.md +45 -21
- package/content/extensions/components/health-check.md +15 -9
- package/content/extensions/components/index.md +24 -90
- package/content/extensions/components/mail/api.md +105 -54
- package/content/extensions/components/mail/errors.md +12 -10
- package/content/extensions/components/mail/index.md +32 -13
- package/content/extensions/components/mail/usage.md +26 -18
- package/content/extensions/components/request-tracker.md +18 -14
- package/content/extensions/components/socket-io/api.md +377 -882
- package/content/extensions/components/socket-io/errors.md +49 -51
- package/content/extensions/components/socket-io/index.md +72 -88
- package/content/extensions/components/socket-io/usage.md +107 -117
- package/content/extensions/components/static-asset/api.md +83 -31
- package/content/extensions/components/static-asset/errors.md +18 -7
- package/content/extensions/components/static-asset/index.md +18 -11
- package/content/extensions/components/static-asset/usage.md +11 -6
- package/content/extensions/components/template/index.md +3 -3
- package/content/extensions/components/websocket/api.md +58 -27
- package/content/extensions/components/websocket/errors.md +3 -3
- package/content/extensions/components/websocket/index.md +8 -7
- package/content/extensions/components/websocket/usage.md +21 -8
- package/content/extensions/helpers/cron/index.md +8 -7
- package/content/extensions/helpers/crypto/index.md +16 -8
- package/content/extensions/helpers/crypto/reference.md +96 -24
- package/content/extensions/helpers/env/index.md +14 -10
- package/content/extensions/helpers/error/index.md +99 -23
- package/content/extensions/helpers/index.md +61 -47
- package/content/extensions/helpers/inversion/index.md +23 -6
- package/content/extensions/helpers/inversion/reference.md +30 -22
- package/content/extensions/helpers/kafka/admin.md +3 -2
- package/content/extensions/helpers/kafka/compile-binary.md +69 -44
- package/content/extensions/helpers/kafka/consumer.md +24 -21
- package/content/extensions/helpers/kafka/examples.md +22 -234
- package/content/extensions/helpers/kafka/index.md +30 -62
- package/content/extensions/helpers/kafka/producer.md +31 -26
- package/content/extensions/helpers/kafka/schema-registry.md +19 -14
- package/content/extensions/helpers/logger/hf-logger.md +49 -22
- package/content/extensions/helpers/logger/index.md +37 -12
- package/content/extensions/helpers/logger/pino.md +31 -11
- package/content/extensions/helpers/logger/reference.md +243 -52
- package/content/extensions/helpers/network/api.md +65 -30
- package/content/extensions/helpers/network/index.md +32 -11
- package/content/extensions/helpers/queue/index.md +17 -6
- package/content/extensions/helpers/queue/reference.md +52 -25
- package/content/extensions/helpers/redis/index.md +29 -11
- package/content/extensions/helpers/redis/reference.md +85 -28
- package/content/extensions/helpers/secrets/index.md +82 -12
- package/content/extensions/helpers/socket-io/api.md +40 -21
- package/content/extensions/helpers/socket-io/index.md +26 -10
- package/content/extensions/helpers/storage/api.md +42 -24
- package/content/extensions/helpers/storage/index.md +10 -7
- package/content/extensions/helpers/types/index.md +20 -7
- package/content/extensions/helpers/types/reference.md +53 -14
- package/content/extensions/helpers/uid/index.md +166 -10
- package/content/extensions/helpers/websocket/api.md +52 -13
- package/content/extensions/helpers/websocket/index.md +7 -4
- package/content/extensions/helpers/worker-thread/index.md +9 -5
- package/content/extensions/helpers/worker-thread/reference.md +20 -20
- package/content/extensions/index.md +38 -39
- package/content/extensions/src-details/mcp-server.md +96 -548
- package/content/guides/core-concepts/persistent/datasources.md +2 -2
- package/content/guides/core-concepts/persistent/index.md +5 -1
- package/content/guides/core-concepts/persistent/pglite.md +218 -0
- package/content/guides/core-concepts/persistent/postgres-drivers.md +21 -15
- package/content/guides/core-concepts/persistent/search-meilisearch.md +22 -12
- package/content/guides/core-concepts/persistent/search-typesense.md +26 -14
- package/content/guides/core-concepts/persistent/sqlite.md +296 -0
- package/content/guides/core-concepts/persistent/transactions.md +12 -11
- package/content/guides/get-started/5-minute-quickstart.md +59 -206
- package/content/guides/get-started/philosophy.md +135 -670
- package/content/guides/get-started/setup.md +53 -74
- package/content/guides/migrations/redis-helpers-migration.md +4 -3
- package/content/guides/migrations/scoped-rbac-migration.md +5 -5
- package/content/guides/migrations/unified-connectors-migration.md +7 -6
- package/content/guides/tutorials/realtime-chat.md +1 -1
- package/content/references/base/application.md +63 -21
- package/content/references/base/components.md +3 -3
- package/content/references/base/connectors.md +14 -14
- package/content/references/base/controllers.md +12 -12
- package/content/references/base/datasources-reference.md +32 -31
- package/content/references/base/datasources.md +6 -6
- package/content/references/base/dependency-injection.md +12 -11
- package/content/references/base/filter-system/application-usage.md +54 -30
- package/content/references/base/filter-system/array-operators.md +24 -46
- package/content/references/base/filter-system/comparison-operators.md +47 -67
- package/content/references/base/filter-system/default-filter.md +59 -53
- package/content/references/base/filter-system/fields-order-pagination.md +92 -146
- package/content/references/base/filter-system/index.md +25 -13
- package/content/references/base/filter-system/json-filtering.md +45 -184
- package/content/references/base/filter-system/list-operators.md +23 -53
- package/content/references/base/filter-system/logical-operators.md +63 -121
- package/content/references/base/filter-system/null-operators.md +34 -104
- package/content/references/base/filter-system/pattern-matching.md +40 -55
- package/content/references/base/filter-system/quick-reference.md +86 -198
- package/content/references/base/filter-system/range-operators.md +18 -46
- package/content/references/base/filter-system/tips.md +6 -6
- package/content/references/base/filter-system/use-cases.md +33 -15
- package/content/references/base/grpc-controllers.md +53 -17
- package/content/references/base/index.md +5 -3
- package/content/references/base/middlewares.md +11 -10
- package/content/references/base/models-reference.md +17 -17
- package/content/references/base/models.md +4 -3
- package/content/references/base/providers.md +8 -8
- package/content/references/base/repositories/advanced.md +224 -326
- package/content/references/base/repositories/index.md +19 -6
- package/content/references/base/repositories/mixins.md +5 -5
- package/content/references/base/repositories/relations.md +160 -293
- package/content/references/base/repositories/soft-deletable.md +16 -6
- package/content/references/base/secrets.md +17 -13
- package/content/references/base/services.md +6 -4
- package/content/references/configuration/environment-variables.md +31 -23
- package/content/references/configuration/index.md +6 -4
- package/content/references/index.md +1 -1
- package/content/references/utilities/duration.md +85 -0
- package/content/references/utilities/index.md +5 -1
- package/content/references/utilities/jsx-reference.md +11 -11
- package/content/references/utilities/jsx.md +2 -2
- package/content/references/utilities/module.md +78 -25
- package/content/references/utilities/request.md +2 -1
- package/content/references/utilities/retry.md +139 -0
- package/content/references/utilities/schema.md +2 -2
- package/content/references/utilities/statuses-reference.md +4 -4
- package/content/references/utilities/statuses.md +5 -5
- package/dist/mcp-server/index.js +0 -0
- package/dist/mcp-server/tools/github/list-project-files.tool.d.ts +1 -1
- package/dist/mcp-server/tools/github/list-project-files.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/github/list-project-files.tool.js +3 -3
- package/dist/mcp-server/tools/github/search-code.tool.js +1 -1
- package/dist/mcp-server/tools/github/verify-dependencies.tool.js +1 -1
- package/dist/mcp-server/tools/github/view-source-file.tool.js +1 -1
- package/package.json +17 -16
|
@@ -10,12 +10,12 @@ Exhaustive reference for `IDataSource`, `AbstractDataSource`, the PostgreSQL con
|
|
|
10
10
|
|
|
11
11
|
**Files:**
|
|
12
12
|
|
|
13
|
-
- [`packages/core/src/base/datasources/abstract.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/base/datasources/abstract.ts) - neutral `AbstractDataSource`
|
|
14
|
-
- [`packages/core/src/base/datasources/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/base/datasources/common/types.ts) - `IDataSource`, `DataSourceDrivers`, neutral transaction types
|
|
15
|
-
- [`packages/core/src/connectors/postgres/datasources/abstract.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/connectors/postgres/datasources/abstract.ts) - `AbstractPostgresDataSource`
|
|
16
|
-
- [`packages/core/src/connectors/postgres/datasources/base.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/connectors/postgres/datasources/base.ts) - `BasePostgresDataSource`
|
|
17
|
-
- [`packages/core/src/connectors/postgres/datasources/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/connectors/postgres/datasources/common/types.ts) - PostgreSQL connector types, `IsolationLevels`
|
|
18
|
-
- [`packages/core/src/connectors/postgres/drivers`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/connectors/postgres/drivers) - `IRelationalDriver`, `NodePostgresDriver`, `PostgresJsDriver`
|
|
13
|
+
- [`packages/core-server/src/base/datasources/abstract.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/base/datasources/abstract.ts) - neutral `AbstractDataSource`
|
|
14
|
+
- [`packages/core-server/src/base/datasources/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/base/datasources/common/types.ts) - `IDataSource`, `DataSourceDrivers`, neutral transaction types
|
|
15
|
+
- [`packages/core-server/src/connectors/postgres/datasources/abstract.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/connectors/postgres/datasources/abstract.ts) - `AbstractPostgresDataSource`
|
|
16
|
+
- [`packages/core-server/src/connectors/postgres/datasources/base.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/connectors/postgres/datasources/base.ts) - `BasePostgresDataSource`
|
|
17
|
+
- [`packages/core-server/src/connectors/postgres/datasources/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/connectors/postgres/datasources/common/types.ts) - PostgreSQL connector types, `IsolationLevels`
|
|
18
|
+
- [`packages/core-server/src/connectors/postgres/drivers`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/connectors/postgres/drivers) - `IRelationalDriver`, `NodePostgresDriver`, `PostgresJsDriver`
|
|
19
19
|
|
|
20
20
|
> [!IMPORTANT] Base vs. connectors
|
|
21
21
|
> - **Split.** Engine-neutral root at `src/base/datasources/`; per-engine connectors at `src/connectors/{postgres,typesense}/datasources/`.
|
|
@@ -39,7 +39,7 @@ Exhaustive reference for `IDataSource`, `AbstractDataSource`, the PostgreSQL con
|
|
|
39
39
|
|
|
40
40
|
Engine-neutral contract implemented by every datasource in the framework, regardless of engine.
|
|
41
41
|
|
|
42
|
-
`Source ->` [`packages/core/src/base/datasources/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/base/datasources/common/types.ts)
|
|
42
|
+
`Source ->` [`packages/core-server/src/base/datasources/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/base/datasources/common/types.ts)
|
|
43
43
|
|
|
44
44
|
```typescript
|
|
45
45
|
interface IDataSource<
|
|
@@ -82,7 +82,7 @@ interface IDataSource<
|
|
|
82
82
|
|
|
83
83
|
Top-level abstract class extended by every engine. Extends `BaseHelper` for scoped logging. Contains **no SQL, no Drizzle, and no connection-pool members** - those are added by each connector.
|
|
84
84
|
|
|
85
|
-
`Source ->` [`packages/core/src/base/datasources/abstract.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/base/datasources/abstract.ts)
|
|
85
|
+
`Source ->` [`packages/core-server/src/base/datasources/abstract.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/base/datasources/abstract.ts)
|
|
86
86
|
|
|
87
87
|
```typescript
|
|
88
88
|
abstract class AbstractDataSource<
|
|
@@ -104,7 +104,7 @@ abstract class AbstractDataSource<
|
|
|
104
104
|
|
|
105
105
|
| Method | Return type | Description |
|
|
106
106
|
|---|---|---|
|
|
107
|
-
| `configure(opts?)` | `ValueOrPromise<void>` | Initialize the underlying connection. This is the **only** abstract member of the neutral root
|
|
107
|
+
| `configure(opts?)` | `ValueOrPromise<void>` | Initialize the underlying connection. This is the **only** abstract member of the neutral root. `getConnectionString()` is not part of it - it is declared one level down, on `AbstractPostgresDataSource` (see below) |
|
|
108
108
|
|
|
109
109
|
**Concrete methods** (defaults, overridable by connectors):
|
|
110
110
|
|
|
@@ -123,7 +123,7 @@ abstract class AbstractDataSource<
|
|
|
123
123
|
| `discoverDefinitions({ read, kind })` | Walks the bound model classes, reads a connector-specific artifact via `read`, and returns a name-keyed registry. Skips undefined reads, throws on duplicate names, honors `autoDiscovery: false`. Shared plumbing every connector's own `discoverSchema()`-equivalent builds on |
|
|
124
124
|
|
|
125
125
|
> [!NOTE] NotSupported convention
|
|
126
|
-
> Every capability an engine does not implement - transactions, row-level locking - uses the same `throwNotSupported` utility ([`packages/core/src/utilities/error.utility.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/utilities/error.utility.ts))
|
|
126
|
+
> Every capability an engine does not implement - transactions, row-level locking - uses the same `throwNotSupported` utility ([`packages/core-server/src/utilities/error.utility.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/utilities/error.utility.ts)). It produces a consistent `501 Not Implemented` whose `normalized.code` resolves to `'core.not_supported'`. This is how the typesense connector signals "not applicable to this engine" instead of silently no-op-ing.
|
|
127
127
|
|
|
128
128
|
### `IDataSourceCapabilities`
|
|
129
129
|
|
|
@@ -137,7 +137,7 @@ Only `BasePostgresDataSource` overrides `getCapabilities()` to return `{ transac
|
|
|
137
137
|
|
|
138
138
|
## PostgreSQL connector: `AbstractPostgresDataSource` and `BasePostgresDataSource`
|
|
139
139
|
|
|
140
|
-
`Source ->` [`packages/core/src/connectors/postgres/datasources/abstract.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/connectors/postgres/datasources/abstract.ts), [`packages/core/src/connectors/postgres/datasources/base.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/connectors/postgres/datasources/base.ts)
|
|
140
|
+
`Source ->` [`packages/core-server/src/connectors/postgres/datasources/abstract.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/connectors/postgres/datasources/abstract.ts), [`packages/core-server/src/connectors/postgres/datasources/base.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/connectors/postgres/datasources/base.ts)
|
|
141
141
|
|
|
142
142
|
### `AbstractPostgresDataSource`
|
|
143
143
|
|
|
@@ -176,20 +176,20 @@ The fourth generic, `Client = Pool`, is what lets a postgres-js datasource decla
|
|
|
176
176
|
|---|---|---|
|
|
177
177
|
| `getConnector()` | `TRelationalConnector<Schema>` | Wires the driver on first use (via `wireDriverFromMetadata()`), then returns `this.connector` |
|
|
178
178
|
| `getClient()` | `Client` | Raw driver client escape hatch - `pg.Pool` for node-postgres, `Sql` for postgres-js. Reads `this.driver.getClient()` if a driver is resolved, else `this.client` directly. Throws if neither is set |
|
|
179
|
-
| `getQueryDialect()` | `IRelationalQueryDialect` | Returns a shared, lazily-constructed `
|
|
180
|
-
| `onSecretRotated(opts)` | `Promise<void>` | Applies rotated credentials to `this.settings
|
|
179
|
+
| `getQueryDialect()` | `IRelationalQueryDialect` | Returns a shared, lazily-constructed `PostgresQueryDialect` instance (static, one per process) |
|
|
180
|
+
| `onSecretRotated(opts)` | `Promise<void>` | Applies rotated credentials to `this.settings` and rebuilds the driver/connector/client against a fresh pool. Calls `this.configure()` and `this.resolveDriver()`, then drains the old pool once the new one is in place. See [Secrets & Vault](/guides/core-concepts/secrets-vault) |
|
|
181
181
|
|
|
182
182
|
**Protected methods:**
|
|
183
183
|
|
|
184
184
|
| Method | Description |
|
|
185
185
|
|---|---|
|
|
186
|
-
| `wireDriverFromMetadata()` | Idempotent, lazy. If `this.connector` already exists, no-ops. If `this.driver` exists but `this.connector` does not, builds the connector from it. Otherwise reads the class named in `@datasource({ driver })` from `MetadataRegistry`, instantiates it over `this.client`, and calls `useDriver()`. Throws if neither `client` nor `driver` is set
|
|
186
|
+
| `wireDriverFromMetadata()` | Idempotent, lazy. If `this.connector` already exists, no-ops. If `this.driver` exists but `this.connector` does not, builds the connector from it. Otherwise reads the class named in `@datasource({ driver })` from `MetadataRegistry`, instantiates it over `this.client`, and calls `useDriver()`. Throws if neither `client` nor `driver` is set. It also throws if the named `driver` metadata is not a class. A string, historically valid for search engines, is rejected here with a message pointing at `NodePostgresDriver` |
|
|
187
187
|
| `resolveDriver()` | Calls `wireDriverFromMetadata()`, then returns `this.driver` |
|
|
188
188
|
| `useDriver({ driver, schema? })` | Assigns `this.driver` **and** builds `this.connector` from it in one step - the two-step form (driver set, connector forgotten) is unrepresentable. `schema` defaults to `getSchema()`. The public escape hatch for a custom or third-party driver, bypassing `@datasource({ driver })` entirely |
|
|
189
189
|
| `mapSecretToSettings({ secret })` | Maps Vault's `{ username, password }` secret shape to `pg`'s `{ user, password }` settings shape, for `onSecretRotated()` |
|
|
190
190
|
|
|
191
191
|
> [!NOTE] Driver seam
|
|
192
|
-
> - **Class, not a string.** `@datasource({ driver })` names the driver **class** (`NodePostgresDriver` or `PostgresJsDriver`)
|
|
192
|
+
> - **Class, not a string.** `@datasource({ driver })` names the driver **class** (`NodePostgresDriver` or `PostgresJsDriver`). A driver-name string cannot carry `pg`/`postgres` into the app's bundle - only a real class reference can.
|
|
193
193
|
> - **`configure()` only assigns `this.client`.** The protected `wireDriverFromMetadata()` (called internally by `getConnector()`/`resolveDriver()`) instantiates the named class over it and builds `this.connector`, lazily and idempotently.
|
|
194
194
|
> - **Where the drivers live.** `pg` and `postgres` are both optional peer dependencies; concrete drivers live at `@venizia/ignis/postgres/node-postgres` and `@venizia/ignis/postgres/postgres-js`, and Supabase support at `@venizia/ignis/postgres/supabase`. See [Postgres Drivers & Supabase](/guides/core-concepts/persistent/postgres-drivers).
|
|
195
195
|
|
|
@@ -197,7 +197,7 @@ The fourth generic, `Client = Pool`, is what lets a postgres-js datasource decla
|
|
|
197
197
|
|
|
198
198
|
Extends `AbstractPostgresDataSource` with a constructor, **schema auto-discovery**, and a real `beginTransaction()` implementation backed by the connection pool. Internally named `BaseRelationalDataSource`.
|
|
199
199
|
|
|
200
|
-
`Source ->` [`packages/core/src/connectors/postgres/datasources/base.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/connectors/postgres/datasources/base.ts)
|
|
200
|
+
`Source ->` [`packages/core-server/src/connectors/postgres/datasources/base.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/connectors/postgres/datasources/base.ts)
|
|
201
201
|
|
|
202
202
|
```typescript
|
|
203
203
|
abstract class BaseRelationalDataSource<
|
|
@@ -246,7 +246,7 @@ This means tables and relations never need to be manually merged in the datasour
|
|
|
246
246
|
|
|
247
247
|
1. **Your DataSource's `constructor` runs.** You call `super()` with `name` and `config`. Schema is auto-discovered from `@repository` bindings unless `schema` is provided manually.
|
|
248
248
|
2. **`Application.registerDataSources()` runs during startup.** The application fetches your datasource instance from the DI container and calls `configure()` on it.
|
|
249
|
-
3. **Your `configure()` method runs.** Its only job is to create the raw client and assign it to `this.client
|
|
249
|
+
3. **Your `configure()` method runs.** Its only job is to create the raw client and assign it to `this.client`. `getConnector()`/`beginTransaction()` lazily instantiate the class named in `@datasource({ driver })` over it and build the Drizzle connector. `configure()` never touches `this.connector` directly.
|
|
250
250
|
|
|
251
251
|
### Example implementations
|
|
252
252
|
|
|
@@ -362,11 +362,11 @@ export class PostgresDataSource extends BasePostgresDataSource<IDataSourceConfig
|
|
|
362
362
|
```
|
|
363
363
|
|
|
364
364
|
> [!IMPORTANT]
|
|
365
|
-
> `configure()` must leave the datasource with a way to reach the database
|
|
365
|
+
> `configure()` must leave the datasource with a way to reach the database. Either assign the raw client to `this.client`, paired with naming the driver class in `@datasource({ driver })`. Or wire a driver directly with `this.useDriver({ driver })` for a custom or third-party driver. `getConnector()`/`beginTransaction()` resolve the driver lazily from whichever you provided. With neither, `wireDriverFromMetadata()` throws `No driver and no client`.
|
|
366
366
|
|
|
367
367
|
### `@datasource` decorator
|
|
368
368
|
|
|
369
|
-
`Source ->` [`packages/core/src/base/metadata/persistents.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/base/metadata/persistents.ts)
|
|
369
|
+
`Source ->` [`packages/core-server/src/base/metadata/persistents.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/base/metadata/persistents.ts)
|
|
370
370
|
|
|
371
371
|
```typescript
|
|
372
372
|
@datasource({
|
|
@@ -404,7 +404,7 @@ export class PostgresDataSource extends BasePostgresDataSource<IDataSourceConfig
|
|
|
404
404
|
|
|
405
405
|
## Driver interface
|
|
406
406
|
|
|
407
|
-
`Source ->` [`packages/core/src/connectors/postgres/drivers`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/connectors/postgres/drivers)
|
|
407
|
+
`Source ->` [`packages/core-server/src/connectors/postgres/drivers`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/connectors/postgres/drivers)
|
|
408
408
|
|
|
409
409
|
`IRelationalDriver` owns connection acquisition and the raw control statements (`BEGIN`/`COMMIT`/`ROLLBACK`) - the only two places the connector is hard-wired to a specific client library.
|
|
410
410
|
|
|
@@ -434,7 +434,7 @@ interface IStatementResult {
|
|
|
434
434
|
| `getClient()` | Raw client escape - `pg.Pool` for node-postgres, `Sql` for postgres-js |
|
|
435
435
|
| `end()` | Closes the underlying client/pool |
|
|
436
436
|
| `IRelationalConnection.execute({ statement })` | Runs a control statement verbatim (never parameterized - `BEGIN TRANSACTION ISOLATION LEVEL $1` is not valid SQL) |
|
|
437
|
-
| `IRelationalConnection.release({ destroy? })` | Returns the connection to the pool, or discards it when `destroy: true
|
|
437
|
+
| `IRelationalConnection.release({ destroy? })` | Returns the connection to the pool, or discards it when `destroy: true`. Required after a failed `COMMIT`/`ROLLBACK`, since the session may still hold an open transaction |
|
|
438
438
|
|
|
439
439
|
Two concrete drivers ship today, both satisfying `IRelationalDriver` and both proven by the same conformance suite:
|
|
440
440
|
|
|
@@ -443,12 +443,12 @@ Two concrete drivers ship today, both satisfying `IRelationalDriver` and both pr
|
|
|
443
443
|
| `NodePostgresDriver` | `pg` | Rejects a client without `connect()` **and** `totalCount` (pool accounting) - catches a bare `pg.Client` |
|
|
444
444
|
| `PostgresJsDriver` | `postgres` | Rejects a client without `reserve()` **and** `unsafe()` - catches a `pg.Pool` passed to the wrong driver |
|
|
445
445
|
|
|
446
|
-
- **Driver asymmetry, deliberate.** After a failed `COMMIT`, `pg` can destroy the poisoned connection (`release(err)`)
|
|
446
|
+
- **Driver asymmetry, deliberate.** After a failed `COMMIT`, `pg` can destroy the poisoned connection (`release(err)`). postgres-js has no destroy semantics - `ReservedSql.release()` takes no argument - so it returns the connection to the pool regardless.
|
|
447
447
|
- **Both drivers accept the same call.** `IRelationalConnection.release({ destroy: true })` is accepted by both drivers and honored by one. See [Postgres Drivers & Supabase](/guides/core-concepts/persistent/postgres-drivers) for the full driver comparison and Supabase's transaction-pooler requirements.
|
|
448
448
|
|
|
449
449
|
## Connector types
|
|
450
450
|
|
|
451
|
-
`Source ->` [`packages/core/src/connectors/postgres/datasources/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/connectors/postgres/datasources/common/types.ts)
|
|
451
|
+
`Source ->` [`packages/core-server/src/connectors/postgres/datasources/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/connectors/postgres/datasources/common/types.ts)
|
|
452
452
|
|
|
453
453
|
| Type | Description |
|
|
454
454
|
|---|---|
|
|
@@ -460,7 +460,7 @@ Two concrete drivers ship today, both satisfying `IRelationalDriver` and both pr
|
|
|
460
460
|
|
|
461
461
|
### `DataSourceDrivers`
|
|
462
462
|
|
|
463
|
-
`Source ->` [`packages/core/src/base/datasources/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/base/datasources/common/types.ts)
|
|
463
|
+
`Source ->` [`packages/core-server/src/base/datasources/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/base/datasources/common/types.ts)
|
|
464
464
|
|
|
465
465
|
An identity-only const-class - the engine actually used is chosen by which driver **class** `@datasource({ driver })` names, not by this constant. `DataSourceDrivers` is read by nothing else in `src`; it never routes connector configuration.
|
|
466
466
|
|
|
@@ -484,7 +484,7 @@ DataSourceDrivers.isValid('node-postgres') // true
|
|
|
484
484
|
```
|
|
485
485
|
|
|
486
486
|
> [!NOTE]
|
|
487
|
-
> `NODE_POSTGRES`/`POSTGRES_JS` remain valid `TDataSourceDriver` string values
|
|
487
|
+
> `NODE_POSTGRES`/`POSTGRES_JS` remain valid `TDataSourceDriver` string values. But `@datasource({ driver })` on a **relational** datasource no longer accepts them - it takes the `NodePostgresDriver`/`PostgresJsDriver` class instead (see [Postgres Drivers & Supabase](/guides/core-concepts/persistent/postgres-drivers)). Search connectors (`TYPESENSE`, `MEILISEARCH`) still take the driver-name string form. `extends TypesenseDataSource` already names the engine, and that is what carries the client into the bundle.
|
|
488
488
|
|
|
489
489
|
## Transaction support
|
|
490
490
|
|
|
@@ -499,28 +499,29 @@ Only engines that declare `getCapabilities().transactions === true` implement re
|
|
|
499
499
|
3. On a failed `BEGIN`, destroys the connection (`release({ destroy: true })`) and rethrows - it is never leaked back to the pool in an unknown state
|
|
500
500
|
4. Returns an `IDatabaseTransaction` object exposing `isActive`, `commit()`, `rollback()`, and the connection-scoped `connector`
|
|
501
501
|
|
|
502
|
-
- **Shared `finish()`.** `commit()`/`rollback()` share one internal `finish()
|
|
502
|
+
- **Shared `finish()`.** `commit()`/`rollback()` share one internal `finish()`. It flips `isActive` to `false` **before** issuing the statement, so a commit racing a rollback cannot double-release the same connection, then runs `COMMIT`/`ROLLBACK`.
|
|
503
503
|
- **Outcome handling.** On success the connection is released back to the pool; on failure it is destroyed and the error is rethrown.
|
|
504
504
|
|
|
505
505
|
> [!WARNING] `commit()`/`rollback()` throw on failure
|
|
506
506
|
> - **A failed `COMMIT` or `ROLLBACK` throws** - a failed `COMMIT` never resolves as success.
|
|
507
|
-
> - **The poisoned connection is destroyed**, not returned to the pool, where the driver supports it
|
|
507
|
+
> - **The poisoned connection is destroyed**, not returned to the pool, where the driver supports it. `node-postgres` can discard a connection; `postgres-js` has no destroy semantics and pools it anyway.
|
|
508
508
|
> - **Nest `rollback()` in its own `try...catch`.** It can throw and is normally called from a `catch`, so nesting keeps the rollback error from replacing the original cause.
|
|
509
|
-
> - **Calling `rollback()` twice is safe.** After a transaction already ended by failure, `rollback()` is a silent no-op
|
|
509
|
+
> - **Calling `rollback()` twice is safe.** After a transaction already ended by failure, `rollback()` is a silent no-op, because it's already torn down.
|
|
510
|
+
> - **The canonical shape.** `catch { await tx.rollback(); throw error; }` always works. See [Transactions](/guides/core-concepts/persistent/transactions) and [Postgres Drivers & Supabase](/guides/core-concepts/persistent/postgres-drivers).
|
|
510
511
|
|
|
511
512
|
### Neutral vs. PostgreSQL transaction types
|
|
512
513
|
|
|
513
514
|
`src/base` declares the engine-neutral shape; the PostgreSQL connector narrows it with connection details.
|
|
514
515
|
|
|
515
516
|
```typescript
|
|
516
|
-
// packages/core/src/base/datasources/common/types.ts - engine-neutral
|
|
517
|
+
// packages/core-server/src/base/datasources/common/types.ts - engine-neutral
|
|
517
518
|
interface ITransaction {
|
|
518
519
|
isActive: boolean;
|
|
519
520
|
commit(): Promise<void>;
|
|
520
521
|
rollback(): Promise<void>;
|
|
521
522
|
}
|
|
522
523
|
|
|
523
|
-
// packages/core/src/connectors/postgres/datasources/common/types.ts - PostgreSQL
|
|
524
|
+
// packages/core-server/src/connectors/postgres/datasources/common/types.ts - PostgreSQL
|
|
524
525
|
interface IDatabaseTransaction<Schema extends TAnyDataSourceSchema = TAnyDataSourceSchema>
|
|
525
526
|
extends ITransaction {
|
|
526
527
|
connector: TRelationalConnector<Schema>;
|
|
@@ -585,7 +586,7 @@ try {
|
|
|
585
586
|
> [!TIP]
|
|
586
587
|
> For most use cases, prefer `repository.beginTransaction()`, which provides a higher-level API. See [Repositories](/references/base/repositories/#run-inside-a-transaction).
|
|
587
588
|
|
|
588
|
-
This architecture
|
|
589
|
+
This architecture keeps datasource configuration consistent. The fully-initialized Drizzle connector, aware of all schemas and relations, is available to repositories for querying.
|
|
589
590
|
|
|
590
591
|
## See also
|
|
591
592
|
|
|
@@ -43,10 +43,10 @@ A `@repository` binds a model to `PostgresDataSource`, and the schema is auto-di
|
|
|
43
43
|
|
|
44
44
|
## How it works
|
|
45
45
|
|
|
46
|
-
- **Driver is a class, not a string.** `@datasource({ driver })` names `NodePostgresDriver` or `PostgresJsDriver` as a class reference
|
|
46
|
+
- **Driver is a class, not a string.** `@datasource({ driver })` names `NodePostgresDriver` or `PostgresJsDriver` as a class reference, never a driver-name string. Only a class reference carries `pg`/`postgres` into the bundle, keeping both packages optional.
|
|
47
47
|
- **`configure()` has exactly one job.** Build the raw client and assign it to `this.client` (a `pg.Pool` for node-postgres, or a postgres-js `Sql`). It never touches `this.connector` directly.
|
|
48
|
-
- **The driver wires lazily.** The first time `getConnector()` or `beginTransaction()` is called, the base class reads the class named in `@datasource({ driver })
|
|
49
|
-
- **Base vs. connector split.** IGNIS splits datasources into an engine-neutral root (`AbstractDataSource` - no SQL, no Drizzle, no pool) and per-engine connectors
|
|
48
|
+
- **The driver wires lazily.** The first time `getConnector()` or `beginTransaction()` is called, the base class reads the class named in `@datasource({ driver })`. It instantiates that class over `this.client` and builds `this.connector` from it.
|
|
49
|
+
- **Base vs. connector split.** IGNIS splits datasources into an engine-neutral root (`AbstractDataSource` - no SQL, no Drizzle, no pool) and per-engine connectors. `BasePostgresDataSource` is the PostgreSQL connector; typesense has a parallel class. See [Connectors](/references/base/connectors) for the full architecture.
|
|
50
50
|
- **Naming.** The PostgreSQL connector's canonical class is `BaseRelationalDataSource`; `BasePostgresDataSource` and `BaseDataSource` are compatibility aliases re-exporting the same class.
|
|
51
51
|
|
|
52
52
|
## Common tasks
|
|
@@ -139,7 +139,7 @@ try {
|
|
|
139
139
|
|
|
140
140
|
### Share one datasource across repositories
|
|
141
141
|
|
|
142
|
-
One `PostgresDataSource` instance is shared by every repository bound to it
|
|
142
|
+
One `PostgresDataSource` instance is shared by every repository bound to it. `@repository` auto-injects the datasource, and `getSchema()` merges the tables and relations of every model bound to it.
|
|
143
143
|
|
|
144
144
|
```typescript
|
|
145
145
|
@repository({ model: User, dataSource: PostgresDataSource })
|
|
@@ -161,5 +161,5 @@ export class ConfigurationRepository extends DefaultCRUDRepository<typeof Config
|
|
|
161
161
|
|
|
162
162
|
**Files:**
|
|
163
163
|
|
|
164
|
-
- [`packages/core/src/base/datasources/abstract.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/base/datasources/abstract.ts) - neutral `AbstractDataSource`
|
|
165
|
-
- [`packages/core/src/connectors/postgres/datasources/base.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/connectors/postgres/datasources/base.ts) - PostgreSQL `BasePostgresDataSource`
|
|
164
|
+
- [`packages/core-server/src/base/datasources/abstract.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/base/datasources/abstract.ts) - neutral `AbstractDataSource`
|
|
165
|
+
- [`packages/core-server/src/connectors/postgres/datasources/base.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/connectors/postgres/datasources/base.ts) - PostgreSQL `BasePostgresDataSource`
|
|
@@ -13,9 +13,9 @@ Technical reference for the DI system in IGNIS - managing resource lifecycles an
|
|
|
13
13
|
- `packages/inversion/src/modules/registry/index.ts` - Base `MetadataRegistry`
|
|
14
14
|
- `packages/inversion/src/modules/metadata/injectors.ts` - Base `@inject` decorator
|
|
15
15
|
- `packages/inversion/src/common/types.ts` - `BindingScopes`, `BindingValueTypes`, `BindingKeys`, `IProvider`
|
|
16
|
-
- `packages/core/src/helpers/inversion/container.ts` - Extended `Container` with `ApplicationLogger`
|
|
17
|
-
- `packages/core/src/helpers/inversion/registry.ts` - Extended `MetadataRegistry` (singleton, with model/repository/datasource mixins)
|
|
18
|
-
- `packages/core/src/base/metadata/injectors.ts` - Core `@inject` (wired to extended registry)
|
|
16
|
+
- `packages/core-server/src/helpers/inversion/container.ts` - Extended `Container` with `ApplicationLogger`
|
|
17
|
+
- `packages/core-server/src/helpers/inversion/registry.ts` - Extended `MetadataRegistry` (singleton, with model/repository/datasource mixins)
|
|
18
|
+
- `packages/core-server/src/base/metadata/injectors.ts` - Core `@inject` (wired to extended registry)
|
|
19
19
|
|
|
20
20
|
## Quick Reference
|
|
21
21
|
|
|
@@ -41,7 +41,7 @@ Before reading this document, you should understand:
|
|
|
41
41
|
|
|
42
42
|
Heart of the DI system - registry managing all application resources.
|
|
43
43
|
|
|
44
|
-
**File:** `packages/inversion/src/modules/container/index.ts` (Base) & `packages/core/src/helpers/inversion/container.ts` (Extended)
|
|
44
|
+
**File:** `packages/inversion/src/modules/container/index.ts` (Base) & `packages/core-server/src/helpers/inversion/container.ts` (Extended)
|
|
45
45
|
|
|
46
46
|
The base `Container` extends `BaseHelper` (which provides `scope` and `identifier` properties). The core `Container` extends the base and adds a `Logger` instance.
|
|
47
47
|
|
|
@@ -73,7 +73,8 @@ const container = new Container({ scope: 'MyApp' }); // scope is optional, defau
|
|
|
73
73
|
|
|
74
74
|
When `container.instantiate(MyClass)` is called:
|
|
75
75
|
|
|
76
|
-
1. **Constructor injection** - Reads `@inject` metadata from the class by parameter index
|
|
76
|
+
1. **Constructor injection** - Reads `@inject` metadata from the class by parameter index. The `Reflect`-stored array is already index-keyed, so there is no sort step; the container resolves each dependency and passes them as constructor arguments.
|
|
77
|
+
- If any index in range has no `@inject` metadata, `instantiate()` throws immediately rather than passing `undefined`.
|
|
77
78
|
2. **Property injection** - After the instance is created, reads property metadata, resolves each dependency, and assigns them directly to the instance properties.
|
|
78
79
|
|
|
79
80
|
```typescript
|
|
@@ -90,16 +91,16 @@ class UserController {
|
|
|
90
91
|
```
|
|
91
92
|
|
|
92
93
|
> [!IMPORTANT]
|
|
93
|
-
> **Every constructor parameter of a container-instantiated class must carry `@inject`.** Mixing decorated and undecorated parameters is forbidden
|
|
94
|
+
> **Every constructor parameter of a container-instantiated class must carry `@inject`.** Mixing decorated and undecorated parameters is forbidden. `@inject` stores its metadata at the parameter's index, so an undecorated parameter leaves a hole in that array. There is no channel through which the container could supply it anyway - it would resolve to `undefined`. `instantiate()` refuses the shape by class name and parameter index instead of silently dereferencing the hole:
|
|
94
95
|
>
|
|
95
96
|
> ```
|
|
96
97
|
> [NoteController] Constructor parameter 0 has no @inject | Every parameter of a container-instantiated
|
|
97
98
|
> class must be decorated - the container cannot supply an undecorated one
|
|
98
99
|
> ```
|
|
99
100
|
>
|
|
100
|
-
> The check lives in `instantiate()`, not in the `@inject` decorator itself
|
|
101
|
+
> The check lives in `instantiate()`, not in the `@inject` decorator itself. Parameter decorators run right-to-left, so when `@inject` on parameter 1 runs, parameter 0 has not been visited yet - nothing at that point can know whether it will end up decorated.
|
|
101
102
|
>
|
|
102
|
-
> This does not apply to `@repository`-decorated classes whose constructor appears undecorated at index 0
|
|
103
|
+
> This does not apply to `@repository`-decorated classes whose constructor appears undecorated at index 0. The `@repository` decorator programmatically writes that inject metadata (`registry.setInjectMetadata({ target, index: 0, ... })`), even though no literal `@inject` appears in source. See [Repositories](./repositories/).
|
|
103
104
|
|
|
104
105
|
## `Binding` Class
|
|
105
106
|
|
|
@@ -205,7 +206,7 @@ This is also used internally by `container.get()` and `container.getBinding()` w
|
|
|
205
206
|
|
|
206
207
|
The `@inject` decorator marks where dependencies should be injected - either on constructor parameters or class properties.
|
|
207
208
|
|
|
208
|
-
**File:** `packages/inversion/src/modules/metadata/injectors.ts` (base) & `packages/core/src/base/metadata/injectors.ts` (core wrapper)
|
|
209
|
+
**File:** `packages/inversion/src/modules/metadata/injectors.ts` (base) & `packages/core-server/src/base/metadata/injectors.ts` (core wrapper)
|
|
209
210
|
|
|
210
211
|
### Signature
|
|
211
212
|
|
|
@@ -261,7 +262,7 @@ import { inject } from '@venizia/ignis';
|
|
|
261
262
|
|
|
262
263
|
## Registering a Class
|
|
263
264
|
|
|
264
|
-
No class decorator is needed to make a class injectable. A class becomes resolvable once a binding exists for it
|
|
265
|
+
No class decorator is needed to make a class injectable. A class becomes resolvable once a binding exists for it. That binding can come from boot auto-discovery, from a framework helper (`app.controller()`, `app.service()`, `@repository`), or explicitly from `container.bind()`. Scope is configured on the binding, never on the class:
|
|
265
266
|
|
|
266
267
|
```typescript
|
|
267
268
|
class UserService extends BaseService {
|
|
@@ -305,7 +306,7 @@ A singleton exported as `metadataRegistry`. Extends `BaseHelper`.
|
|
|
305
306
|
|
|
306
307
|
### Core MetadataRegistry
|
|
307
308
|
|
|
308
|
-
**File:** `packages/core/src/helpers/inversion/registry.ts`
|
|
309
|
+
**File:** `packages/core-server/src/helpers/inversion/registry.ts`
|
|
309
310
|
|
|
310
311
|
Extends the base with controller, repository, model, and datasource metadata support via mixins. Accessed as a singleton via `MetadataRegistry.getInstance()`.
|
|
311
312
|
|
|
@@ -6,7 +6,7 @@ difficulty: intermediate
|
|
|
6
6
|
|
|
7
7
|
# Using Filters in Your Application
|
|
8
8
|
|
|
9
|
-
A `filter`
|
|
9
|
+
A `filter` starts as a JSON-encoded query string on an HTTP request and ends as a Drizzle query. Here is where to hook into each layer in between.
|
|
10
10
|
|
|
11
11
|
```
|
|
12
12
|
HTTP Request GET /products?filter={"where":{"status":"active"},"limit":10}
|
|
@@ -22,11 +22,9 @@ Repository Layer applyDefaultFilter() merges the @model default filter,
|
|
|
22
22
|
FilterBuilder converts Filter -> Drizzle query options, executes
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
##
|
|
25
|
+
## Generate a CRUD controller from an entity
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
`ControllerFactory.defineCrudController` generates a full CRUD controller, including filter parsing and validation, from an entity and a repository binding:
|
|
27
|
+
For a standard `GET`/`POST`/`PATCH`/`DELETE` resource, generate the controller instead of writing filter parsing by hand. `ControllerFactory.defineCrudController` builds it from an entity and a repository binding:
|
|
30
28
|
|
|
31
29
|
```typescript
|
|
32
30
|
// src/controllers/product.controller.ts
|
|
@@ -65,7 +63,7 @@ export class ProductController extends _Controller {
|
|
|
65
63
|
}
|
|
66
64
|
```
|
|
67
65
|
|
|
68
|
-
|
|
66
|
+
This generates every filter-bearing endpoint the resource needs:
|
|
69
67
|
|
|
70
68
|
| Method | Endpoint | Query param |
|
|
71
69
|
|---|---|---|
|
|
@@ -74,17 +72,34 @@ export class ProductController extends _Controller {
|
|
|
74
72
|
| GET | `/products/find-one` | `filter` |
|
|
75
73
|
| GET | `/products/count` | `where` |
|
|
76
74
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
75
|
+
Set `isStrict.requestSchema: true` to make these query params Zod-required; set `isStrict.path: true` to reject trailing-slash variants of the route. Write endpoints (`POST /`, `PATCH /{id}`, `DELETE /{id}`, ...) come from the same factory call and take no filter.
|
|
76
|
+
|
|
77
|
+
## Map a request query string to a parsed filter
|
|
78
|
+
|
|
79
|
+
`FilterSchema` and `WhereSchema` both accept a JSON string or a plain object, so the same schema validates a Hono query param (always a string) and a filter built in code:
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
| Request | Parsed filter |
|
|
82
|
+
|---|---|
|
|
83
|
+
| `GET /products?filter={"where":{"status":"active"}}` | `{ where: { status: 'active' } }` |
|
|
84
|
+
| `GET /products?filter={"limit":10,"skip":20}` | `{ limit: 10, skip: 20 }` |
|
|
85
|
+
| `GET /products?filter={"where":{"price":{"gte":100,"lte":500}},"order":["price ASC"]}` | `{ where: { price: { gte: 100, lte: 500 } }, order: ['price ASC'] }` |
|
|
86
|
+
| `GET /products/count?where={"role":"admin"}` | `{ role: 'admin' }` |
|
|
87
|
+
|
|
88
|
+
`WhereSchema` is independent of `FilterSchema` - it backs the `count` endpoint, which takes `where` directly rather than a full filter.
|
|
82
89
|
|
|
83
|
-
|
|
90
|
+
## Write a custom route that accepts a filter
|
|
91
|
+
|
|
92
|
+
For a route outside the generated CRUD set, use `FilterQuerySchema` - the same query shape the generated `find` route takes:
|
|
84
93
|
|
|
85
94
|
```typescript
|
|
86
95
|
import { z } from '@hono/zod-openapi';
|
|
87
|
-
import {
|
|
96
|
+
import {
|
|
97
|
+
BaseRestController,
|
|
98
|
+
controller,
|
|
99
|
+
FilterQuerySchema,
|
|
100
|
+
inject,
|
|
101
|
+
jsonResponse,
|
|
102
|
+
} from '@venizia/ignis';
|
|
88
103
|
|
|
89
104
|
@controller({ path: '/products' })
|
|
90
105
|
export class ProductController extends BaseRestController {
|
|
@@ -100,7 +115,7 @@ export class ProductController extends BaseRestController {
|
|
|
100
115
|
configs: {
|
|
101
116
|
path: '/search',
|
|
102
117
|
method: 'get',
|
|
103
|
-
request: { query:
|
|
118
|
+
request: { query: FilterQuerySchema },
|
|
104
119
|
responses: jsonResponse({ schema: z.array(z.object({ id: z.string() })) }),
|
|
105
120
|
},
|
|
106
121
|
handler: async context => {
|
|
@@ -113,23 +128,29 @@ export class ProductController extends BaseRestController {
|
|
|
113
128
|
}
|
|
114
129
|
```
|
|
115
130
|
|
|
116
|
-
|
|
131
|
+
### The two query shapes
|
|
117
132
|
|
|
118
|
-
|
|
133
|
+
Reach for these instead of rebuilding the same object at every route.
|
|
119
134
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
135
|
+
| Schema | Query shape | Use it for |
|
|
136
|
+
|---|---|---|
|
|
137
|
+
| `FilterQuerySchema` | `{ filter?: TFilter }` | Any route that takes a full filter |
|
|
138
|
+
| `WhereQuerySchema` | `{ where?: TWhere }` | Any route that takes conditions and no pagination |
|
|
139
|
+
|
|
140
|
+
Both are plain Zod objects, so a route that takes more than one parameter extends rather than rebuilds:
|
|
123
141
|
|
|
124
|
-
|
|
125
|
-
|
|
142
|
+
```typescript
|
|
143
|
+
request: { query: WhereQuerySchema.extend({ q: z.string().max(255).optional() }) },
|
|
126
144
|
```
|
|
127
145
|
|
|
128
|
-
|
|
146
|
+
Neither needs an extra `.optional()`. `FilterSchema` already carries one, so `FilterSchema.optional()` is the same schema written longer, and a trailing `.partial()` on a single optional key does nothing.
|
|
129
147
|
|
|
130
|
-
|
|
148
|
+
> [!NOTE]
|
|
149
|
+
> The generated `updateBy` and `deleteBy` routes deliberately do not use `WhereQuerySchema`. They require `where`, because a missing one rewrites or deletes every row in the table.
|
|
131
150
|
|
|
132
|
-
|
|
151
|
+
## Rewrite a filter before it reaches the repository
|
|
152
|
+
|
|
153
|
+
Add a service between the controller and the repository when a constraint is a caller or session concern rather than a per-model constant - a tenant ID pulled from the request context, for example. Use [Default Filter](./default-filter) instead when the constraint applies to every caller of the model:
|
|
133
154
|
|
|
134
155
|
```typescript
|
|
135
156
|
@service()
|
|
@@ -147,7 +168,9 @@ export class ProductService {
|
|
|
147
168
|
}
|
|
148
169
|
```
|
|
149
170
|
|
|
150
|
-
##
|
|
171
|
+
## Build a filter query string from a client
|
|
172
|
+
|
|
173
|
+
Encode the filter as JSON and pass it as the `filter` query param, whichever HTTP client you use:
|
|
151
174
|
|
|
152
175
|
**cURL:**
|
|
153
176
|
```bash
|
|
@@ -166,9 +189,9 @@ const response = await fetch(`/api/products?filter=${encodeURIComponent(JSON.str
|
|
|
166
189
|
const response = await axios.get('/api/products', { params: { filter: JSON.stringify(filter) } });
|
|
167
190
|
```
|
|
168
191
|
|
|
169
|
-
##
|
|
192
|
+
## Debug what a filter compiles to
|
|
170
193
|
|
|
171
|
-
`buildQuery`
|
|
194
|
+
Call `buildQuery` to compile a filter into Drizzle query options without executing it - the fastest way to check what a filter actually resolves to:
|
|
172
195
|
|
|
173
196
|
```typescript
|
|
174
197
|
const queryOptions = repository.buildQuery({ filter: complexFilter });
|
|
@@ -180,12 +203,13 @@ console.log('Generated query options:', queryOptions);
|
|
|
180
203
|
## See also
|
|
181
204
|
|
|
182
205
|
- [Filter System Overview](./) - the `filter` shape and every `where` operator family
|
|
183
|
-
- [Default Filter](./default-filter) - `shouldSkipDefaultFilter`, and the model-level alternative to the service-layer
|
|
206
|
+
- [Default Filter](./default-filter) - `shouldSkipDefaultFilter`, and the model-level alternative to the service-layer rewrite above
|
|
184
207
|
- [Use Case Gallery](./use-cases) - more filter shapes with their generated SQL
|
|
185
208
|
- [Advanced Repository Features](../repositories/advanced.md) - transactions, locking, and the full `log`/`lock` options
|
|
186
209
|
|
|
187
210
|
**Files:**
|
|
188
211
|
|
|
189
|
-
- [`packages/
|
|
190
|
-
- [`packages/
|
|
191
|
-
- [`packages/
|
|
212
|
+
- [`packages/kernel/src/base/controllers/factory/controller.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/kernel/src/base/controllers/factory/controller.ts) - `ControllerFactory.defineCrudController`
|
|
213
|
+
- [`packages/kernel/src/base/repositories/query-schemas/index.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/kernel/src/base/repositories/query-schemas/index.ts) - `FilterSchema`, `WhereSchema`, `FilterQuerySchema`, `WhereQuerySchema`
|
|
214
|
+
- [`packages/filter/src/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/filter/src/common/types.ts) - `TFilter`, `TInclusion`
|
|
215
|
+
- [`packages/connectors/src/relational/core/repositories/core/base.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/connectors/src/relational/core/repositories/core/base.ts) - `RelationalBaseRepository.buildQuery`
|