@venizia/ignis-docs 0.0.7 → 0.0.8-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.
- package/dist/mcp-server/common/paths.d.ts +4 -2
- package/dist/mcp-server/common/paths.d.ts.map +1 -1
- package/dist/mcp-server/common/paths.js +8 -6
- package/dist/mcp-server/common/paths.js.map +1 -1
- package/dist/mcp-server/tools/docs/get-document-content.tool.d.ts +1 -1
- package/dist/mcp-server/tools/docs/get-document-content.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/docs/get-document-content.tool.js +7 -7
- package/dist/mcp-server/tools/docs/get-document-metadata.tool.js +3 -3
- package/dist/mcp-server/tools/docs/get-package-overview.tool.d.ts +1 -1
- package/dist/mcp-server/tools/docs/get-package-overview.tool.js +1 -1
- package/package.json +1 -1
- package/wiki/best-practices/api-usage-examples.md +9 -9
- package/wiki/best-practices/architectural-patterns.md +19 -3
- package/wiki/best-practices/architecture-decisions.md +6 -6
- package/wiki/best-practices/code-style-standards/advanced-patterns.md +1 -1
- package/wiki/best-practices/code-style-standards/control-flow.md +1 -1
- package/wiki/best-practices/code-style-standards/function-patterns.md +2 -2
- package/wiki/best-practices/code-style-standards/index.md +2 -2
- package/wiki/best-practices/code-style-standards/naming-conventions.md +1 -1
- package/wiki/best-practices/code-style-standards/route-definitions.md +4 -4
- package/wiki/best-practices/data-modeling.md +1 -1
- package/wiki/best-practices/deployment-strategies.md +1 -1
- package/wiki/best-practices/error-handling.md +2 -2
- package/wiki/best-practices/performance-optimization.md +3 -3
- package/wiki/best-practices/security-guidelines.md +2 -2
- package/wiki/best-practices/troubleshooting-tips.md +1 -1
- package/wiki/{references → extensions}/components/authentication/api.md +12 -20
- package/wiki/{references → extensions}/components/authentication/errors.md +1 -1
- package/wiki/{references → extensions}/components/authentication/index.md +5 -8
- package/wiki/{references → extensions}/components/authentication/usage.md +20 -36
- package/wiki/{references → extensions}/components/authorization/api.md +62 -13
- package/wiki/{references → extensions}/components/authorization/errors.md +12 -7
- package/wiki/{references → extensions}/components/authorization/index.md +93 -6
- package/wiki/{references → extensions}/components/authorization/usage.md +42 -4
- package/wiki/{references → extensions}/components/health-check.md +5 -4
- package/wiki/{references → extensions}/components/index.md +2 -0
- package/wiki/{references → extensions}/components/mail/index.md +1 -1
- package/wiki/{references → extensions}/components/request-tracker.md +1 -1
- package/wiki/{references → extensions}/components/socket-io/api.md +2 -2
- package/wiki/{references → extensions}/components/socket-io/errors.md +2 -0
- package/wiki/{references → extensions}/components/socket-io/index.md +24 -20
- package/wiki/{references → extensions}/components/socket-io/usage.md +2 -2
- package/wiki/{references → extensions}/components/static-asset/api.md +14 -15
- package/wiki/{references → extensions}/components/static-asset/errors.md +3 -1
- package/wiki/{references → extensions}/components/static-asset/index.md +158 -89
- package/wiki/{references → extensions}/components/static-asset/usage.md +8 -5
- package/wiki/{references → extensions}/components/swagger.md +3 -3
- package/wiki/{references → extensions}/components/template/index.md +4 -4
- package/wiki/{references → extensions}/components/template/setup-page.md +1 -1
- package/wiki/{references → extensions}/components/template/single-page.md +1 -1
- package/wiki/{references → extensions}/components/websocket/api.md +7 -6
- package/wiki/{references → extensions}/components/websocket/errors.md +17 -3
- package/wiki/{references → extensions}/components/websocket/index.md +17 -11
- package/wiki/{references → extensions}/components/websocket/usage.md +2 -2
- package/wiki/{references → extensions}/helpers/crypto/index.md +1 -1
- package/wiki/{references → extensions}/helpers/env/index.md +9 -5
- package/wiki/{references → extensions}/helpers/error/index.md +2 -7
- package/wiki/{references → extensions}/helpers/index.md +18 -6
- package/wiki/{references → extensions}/helpers/kafka/admin.md +13 -1
- package/wiki/{references → extensions}/helpers/kafka/consumer.md +28 -28
- package/wiki/{references → extensions}/helpers/kafka/examples.md +19 -19
- package/wiki/{references → extensions}/helpers/kafka/index.md +51 -48
- package/wiki/{references → extensions}/helpers/kafka/producer.md +18 -18
- package/wiki/{references → extensions}/helpers/kafka/schema-registry.md +25 -25
- package/wiki/{references → extensions}/helpers/logger/index.md +2 -2
- package/wiki/{references → extensions}/helpers/queue/index.md +400 -4
- package/wiki/{references → extensions}/helpers/storage/api.md +170 -10
- package/wiki/{references → extensions}/helpers/storage/index.md +44 -8
- package/wiki/{references → extensions}/helpers/template/index.md +1 -1
- package/wiki/{references → extensions}/helpers/testing/index.md +4 -4
- package/wiki/{references → extensions}/helpers/types/index.md +63 -16
- package/wiki/{references → extensions}/helpers/websocket/index.md +1 -1
- package/wiki/extensions/index.md +48 -0
- package/wiki/guides/core-concepts/application/bootstrapping.md +55 -37
- package/wiki/guides/core-concepts/application/index.md +95 -35
- package/wiki/guides/core-concepts/components-guide.md +23 -19
- package/wiki/guides/core-concepts/components.md +34 -10
- package/wiki/guides/core-concepts/dependency-injection.md +99 -34
- package/wiki/guides/core-concepts/grpc-controllers.md +295 -0
- package/wiki/guides/core-concepts/persistent/datasources.md +27 -8
- package/wiki/guides/core-concepts/persistent/models.md +43 -1
- package/wiki/guides/core-concepts/persistent/repositories.md +75 -8
- package/wiki/guides/core-concepts/persistent/transactions.md +38 -8
- package/wiki/guides/core-concepts/{controllers.md → rest-controllers.md} +30 -33
- package/wiki/guides/core-concepts/services.md +19 -5
- package/wiki/guides/get-started/5-minute-quickstart.md +6 -7
- package/wiki/guides/get-started/philosophy.md +1 -1
- package/wiki/guides/index.md +2 -2
- package/wiki/guides/reference/glossary.md +7 -7
- package/wiki/guides/reference/mcp-docs-server.md +1 -1
- package/wiki/guides/tutorials/building-a-crud-api.md +2 -2
- package/wiki/guides/tutorials/complete-installation.md +17 -14
- package/wiki/guides/tutorials/ecommerce-api.md +18 -18
- package/wiki/guides/tutorials/realtime-chat.md +8 -8
- package/wiki/guides/tutorials/testing.md +2 -2
- package/wiki/index.md +4 -3
- package/wiki/references/base/application.md +341 -21
- package/wiki/references/base/bootstrapping.md +43 -13
- package/wiki/references/base/components.md +259 -8
- package/wiki/references/base/controllers.md +556 -253
- package/wiki/references/base/datasources.md +159 -79
- package/wiki/references/base/dependency-injection.md +299 -48
- package/wiki/references/base/filter-system/application-usage.md +18 -2
- package/wiki/references/base/filter-system/array-operators.md +14 -6
- package/wiki/references/base/filter-system/comparison-operators.md +9 -3
- package/wiki/references/base/filter-system/default-filter.md +28 -3
- package/wiki/references/base/filter-system/fields-order-pagination.md +17 -13
- package/wiki/references/base/filter-system/index.md +169 -11
- package/wiki/references/base/filter-system/json-filtering.md +51 -18
- package/wiki/references/base/filter-system/list-operators.md +4 -3
- package/wiki/references/base/filter-system/logical-operators.md +7 -2
- package/wiki/references/base/filter-system/null-operators.md +50 -0
- package/wiki/references/base/filter-system/quick-reference.md +82 -243
- package/wiki/references/base/filter-system/range-operators.md +7 -1
- package/wiki/references/base/filter-system/tips.md +34 -7
- package/wiki/references/base/filter-system/use-cases.md +6 -5
- package/wiki/references/base/grpc-controllers.md +984 -0
- package/wiki/references/base/index.md +32 -24
- package/wiki/references/base/middleware.md +347 -0
- package/wiki/references/base/models.md +390 -46
- package/wiki/references/base/providers.md +14 -14
- package/wiki/references/base/repositories/advanced.md +84 -69
- package/wiki/references/base/repositories/index.md +447 -12
- package/wiki/references/base/repositories/mixins.md +103 -98
- package/wiki/references/base/repositories/relations.md +129 -45
- package/wiki/references/base/repositories/soft-deletable.md +104 -23
- package/wiki/references/base/services.md +94 -14
- package/wiki/references/index.md +12 -10
- package/wiki/references/quick-reference.md +98 -65
- package/wiki/references/utilities/crypto.md +21 -4
- package/wiki/references/utilities/date.md +25 -7
- package/wiki/references/utilities/index.md +26 -24
- package/wiki/references/utilities/jsx.md +54 -54
- package/wiki/references/utilities/module.md +8 -6
- package/wiki/references/utilities/parse.md +16 -9
- package/wiki/references/utilities/performance.md +22 -7
- package/wiki/references/utilities/promise.md +19 -16
- package/wiki/references/utilities/request.md +48 -26
- package/wiki/references/utilities/schema.md +69 -6
- package/wiki/references/utilities/statuses.md +131 -140
- /package/wiki/{references → extensions}/components/mail/api.md +0 -0
- /package/wiki/{references → extensions}/components/mail/errors.md +0 -0
- /package/wiki/{references → extensions}/components/mail/usage.md +0 -0
- /package/wiki/{references → extensions}/components/template/api-page.md +0 -0
- /package/wiki/{references → extensions}/components/template/errors-page.md +0 -0
- /package/wiki/{references → extensions}/components/template/usage-page.md +0 -0
- /package/wiki/{references → extensions}/helpers/cron/index.md +0 -0
- /package/wiki/{references → extensions}/helpers/inversion/index.md +0 -0
- /package/wiki/{references → extensions}/helpers/network/api.md +0 -0
- /package/wiki/{references → extensions}/helpers/network/index.md +0 -0
- /package/wiki/{references → extensions}/helpers/redis/index.md +0 -0
- /package/wiki/{references → extensions}/helpers/socket-io/api.md +0 -0
- /package/wiki/{references → extensions}/helpers/socket-io/index.md +0 -0
- /package/wiki/{references → extensions}/helpers/template/single-page.md +0 -0
- /package/wiki/{references → extensions}/helpers/uid/index.md +0 -0
- /package/wiki/{references → extensions}/helpers/websocket/api.md +0 -0
- /package/wiki/{references → extensions}/helpers/worker-thread/index.md +0 -0
- /package/wiki/{references → extensions}/src-details/mcp-server.md +0 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
title: Filter Operators Quick Reference
|
|
3
3
|
description: Single-page cheat sheet of all filter operators
|
|
4
4
|
difficulty: intermediate
|
|
5
|
-
lastUpdated: 2026-
|
|
5
|
+
lastUpdated: 2026-03-15
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Filter Operators Quick Reference
|
|
@@ -14,7 +14,8 @@ Complete single-page reference for all IGNIS filter operators. For detailed expl
|
|
|
14
14
|
| Operator | SQL | TypeScript Example | Description |
|
|
15
15
|
|----------|-----|-------------------|-------------|
|
|
16
16
|
| `eq` | `=` | `{ status: { eq: 'active' } }` | Equal to |
|
|
17
|
-
| `
|
|
17
|
+
| `ne` | `!=` | `{ status: { ne: 'deleted' } }` | Not equal to |
|
|
18
|
+
| `neq` | `!=` | `{ status: { neq: 'deleted' } }` | Not equal to (alias for `ne`) |
|
|
18
19
|
| `gt` | `>` | `{ age: { gt: 18 } }` | Greater than |
|
|
19
20
|
| `gte` | `>=` | `{ age: { gte: 18 } }` | Greater than or equal |
|
|
20
21
|
| `lt` | `<` | `{ price: { lt: 100 } }` | Less than |
|
|
@@ -37,8 +38,9 @@ Complete single-page reference for all IGNIS filter operators. For detailed expl
|
|
|
37
38
|
|
|
38
39
|
| Operator | SQL | TypeScript Example | Description |
|
|
39
40
|
|----------|-----|-------------------|-------------|
|
|
40
|
-
| `in`
|
|
41
|
-
| `
|
|
41
|
+
| `in` | `IN` | `{ status: { in: ['active', 'pending'] } }` | Value matches any in array |
|
|
42
|
+
| `inq` | `IN` | `{ status: { inq: ['active', 'pending'] } }` | Alias for `in` |
|
|
43
|
+
| `nin` | `NOT IN` | `{ status: { nin: ['deleted', 'banned'] } }` | Value doesn't match any in array |
|
|
42
44
|
|
|
43
45
|
**See:** [List Operators Guide](./list-operators.md)
|
|
44
46
|
|
|
@@ -48,11 +50,9 @@ Complete single-page reference for all IGNIS filter operators. For detailed expl
|
|
|
48
50
|
| Operator | SQL | TypeScript Example | Description |
|
|
49
51
|
|----------|-----|-------------------|-------------|
|
|
50
52
|
| `like` | `LIKE` | `{ name: { like: '%john%' } }` | Pattern match (case-sensitive) |
|
|
53
|
+
| `nlike` | `NOT LIKE` | `{ name: { nlike: '%test%' } }` | Inverse pattern match (case-sensitive) |
|
|
51
54
|
| `ilike` | `ILIKE` | `{ email: { ilike: '%@gmail.com' } }` | Pattern match (case-insensitive) |
|
|
52
|
-
| `
|
|
53
|
-
| `notILike` | `NOT ILIKE` | `{ email: { notILike: '%spam%' } }` | Inverse pattern match (case-insensitive) |
|
|
54
|
-
| `startsWith` | `LIKE 'value%'` | `{ name: { startsWith: 'John' } }` | Starts with value |
|
|
55
|
-
| `endsWith` | `LIKE '%value'` | `{ email: { endsWith: '@example.com' } }` | Ends with value |
|
|
55
|
+
| `nilike` | `NOT ILIKE` | `{ email: { nilike: '%spam%' } }` | Inverse pattern match (case-insensitive) |
|
|
56
56
|
| `regexp` | `~` | `{ code: { regexp: '^[A-Z]{3}$' } }` | Regular expression (PostgreSQL) |
|
|
57
57
|
| `iregexp` | `~*` | `{ code: { iregexp: '^[a-z]{3}$' } }` | Case-insensitive regex (PostgreSQL) |
|
|
58
58
|
|
|
@@ -67,14 +67,22 @@ Complete single-page reference for all IGNIS filter operators. For detailed expl
|
|
|
67
67
|
|
|
68
68
|
| Operator | SQL | TypeScript Example | Description |
|
|
69
69
|
|----------|-----|-------------------|-------------|
|
|
70
|
-
| `
|
|
71
|
-
| `
|
|
70
|
+
| `is` | `IS NULL` / `=` | `{ deletedAt: { is: null } }` | IS NULL when value is `null`, equality otherwise |
|
|
71
|
+
| `isn` | `IS NOT NULL` / `!=` | `{ email: { isn: null } }` | IS NOT NULL when value is `null`, not-equal otherwise |
|
|
72
72
|
|
|
73
|
-
**
|
|
73
|
+
**Shorthand Syntax:**
|
|
74
74
|
```typescript
|
|
75
|
-
//
|
|
76
|
-
{ deletedAt:
|
|
77
|
-
|
|
75
|
+
// Direct null assignment (implicit IS NULL)
|
|
76
|
+
{ deletedAt: null }
|
|
77
|
+
// SQL: WHERE "deleted_at" IS NULL
|
|
78
|
+
|
|
79
|
+
// Using eq with null
|
|
80
|
+
{ deletedAt: { eq: null } }
|
|
81
|
+
// SQL: WHERE "deleted_at" IS NULL
|
|
82
|
+
|
|
83
|
+
// Using ne with null
|
|
84
|
+
{ deletedAt: { ne: null } }
|
|
85
|
+
// SQL: WHERE "deleted_at" IS NOT NULL
|
|
78
86
|
```
|
|
79
87
|
|
|
80
88
|
**See:** [Null Operators Guide](./null-operators.md)
|
|
@@ -86,7 +94,6 @@ Complete single-page reference for all IGNIS filter operators. For detailed expl
|
|
|
86
94
|
|----------|-----|-------------------|-------------|
|
|
87
95
|
| `and` | `AND` | `{ and: [{ age: { gt: 18 } }, { status: 'active' }] }` | All conditions must be true |
|
|
88
96
|
| `or` | `OR` | `{ or: [{ role: 'admin' }, { role: 'moderator' }] }` | At least one condition must be true |
|
|
89
|
-
| `not` | `NOT` | `{ not: { status: 'deleted' } }` | Inverts the condition |
|
|
90
97
|
|
|
91
98
|
**Implicit AND:**
|
|
92
99
|
```typescript
|
|
@@ -99,6 +106,8 @@ Complete single-page reference for all IGNIS filter operators. For detailed expl
|
|
|
99
106
|
// WHERE status = 'active' AND age >= 18 AND role = 'user'
|
|
100
107
|
```
|
|
101
108
|
|
|
109
|
+
**NOT logic** is expressed via negation operators (`ne`, `neq`, `nin`, `nlike`, `nilike`, `notBetween`, `isn`).
|
|
110
|
+
|
|
102
111
|
**See:** [Logical Operators Guide](./logical-operators.md)
|
|
103
112
|
|
|
104
113
|
|
|
@@ -112,50 +121,57 @@ These operators work with PostgreSQL array columns (`varchar[]`, `text[]`, `inte
|
|
|
112
121
|
| `containedBy` | `<@` | `{ tags: { containedBy: ['ts', 'js', 'go', 'rust'] } }` | Array is subset of specified array |
|
|
113
122
|
| `overlaps` | `&&` | `{ tags: { overlaps: ['react', 'vue', 'angular'] } }` | Arrays have at least one common element |
|
|
114
123
|
|
|
115
|
-
**Important:** These are array-specific operators, not to be confused with `in`/`
|
|
124
|
+
**Important:** These are array-specific operators, not to be confused with `in`/`nin` which match scalar values against an array.
|
|
116
125
|
|
|
117
126
|
**See:** [Array Operators Guide](./array-operators.md)
|
|
118
127
|
|
|
119
128
|
|
|
120
129
|
## JSON/JSONB Operators (PostgreSQL)
|
|
121
130
|
|
|
122
|
-
Query nested fields within JSON/JSONB columns using dot notation.
|
|
131
|
+
Query nested fields within JSON/JSONB columns using dot notation as the key.
|
|
123
132
|
|
|
124
|
-
###
|
|
133
|
+
### JSON Path Syntax
|
|
125
134
|
|
|
126
135
|
| Syntax | Example | Description |
|
|
127
136
|
|--------|---------|-------------|
|
|
128
|
-
| Dot notation | `metadata.user.name` | Access nested properties |
|
|
129
|
-
| Array index | `metadata.tags[0]` | Access array elements |
|
|
130
|
-
| Combined | `metadata.users[0].email` | Nested arrays and objects |
|
|
137
|
+
| Dot notation | `{ 'metadata.user.name': 'John' }` | Access nested properties |
|
|
138
|
+
| Array index | `{ 'metadata.tags[0]': 'urgent' }` | Access array elements |
|
|
139
|
+
| Combined | `{ 'metadata.users[0].email': value }` | Nested arrays and objects |
|
|
131
140
|
|
|
132
|
-
### JSON Path with
|
|
141
|
+
### JSON Path with Operators
|
|
133
142
|
|
|
134
143
|
```typescript
|
|
135
|
-
//
|
|
136
|
-
{
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
144
|
+
// Equality (string comparison via #>>)
|
|
145
|
+
{ 'metadata.user.role': 'admin' }
|
|
146
|
+
// SQL: "metadata" #>> '{user,role}' = 'admin'
|
|
147
|
+
|
|
148
|
+
// Numeric comparison (safe casting via CASE/numeric)
|
|
149
|
+
{ 'metadata.score': { gt: 80 } }
|
|
150
|
+
|
|
151
|
+
// Pattern matching
|
|
152
|
+
{ 'metadata.level': { ilike: '%high%' } }
|
|
153
|
+
// SQL: "metadata" #>> '{level}' ILIKE '%high%'
|
|
142
154
|
|
|
143
155
|
// Multiple JSON conditions
|
|
144
156
|
{
|
|
145
157
|
and: [
|
|
146
|
-
{ metadata
|
|
147
|
-
{ metadata
|
|
158
|
+
{ 'metadata.user.age': { gt: 18 } },
|
|
159
|
+
{ 'metadata.user.country': 'US' }
|
|
148
160
|
]
|
|
149
161
|
}
|
|
150
162
|
```
|
|
151
163
|
|
|
152
|
-
### Supported Operators with JSON
|
|
164
|
+
### Supported Operators with JSON Paths
|
|
153
165
|
|
|
154
166
|
All comparison operators work with JSON path queries:
|
|
155
|
-
- `eq`, `neq`, `gt`, `gte`, `lt`, `lte`
|
|
156
|
-
- `in`, `
|
|
157
|
-
- `like`, `ilike`
|
|
158
|
-
- `
|
|
167
|
+
- `eq`, `ne`, `neq`, `gt`, `gte`, `lt`, `lte`
|
|
168
|
+
- `in`, `inq`, `nin`
|
|
169
|
+
- `like`, `nlike`, `ilike`, `nilike`
|
|
170
|
+
- `between`, `notBetween`
|
|
171
|
+
- `regexp`, `iregexp`
|
|
172
|
+
- `is`, `isn`
|
|
173
|
+
|
|
174
|
+
Numeric operators (`gt`, `gte`, `lt`, `lte`, `between`, `notBetween`) use safe numeric casting to handle mixed JSON value types.
|
|
159
175
|
|
|
160
176
|
**See:** [JSON Filtering Guide](./json-filtering.md)
|
|
161
177
|
|
|
@@ -166,8 +182,10 @@ All comparison operators work with JSON path queries:
|
|
|
166
182
|
|
|
167
183
|
```typescript
|
|
168
184
|
const users = await userRepo.find({
|
|
169
|
-
|
|
170
|
-
|
|
185
|
+
filter: {
|
|
186
|
+
where: { isActive: true },
|
|
187
|
+
fields: ['id', 'name', 'email'], // Only return these fields
|
|
188
|
+
}
|
|
171
189
|
});
|
|
172
190
|
```
|
|
173
191
|
|
|
@@ -175,29 +193,30 @@ const users = await userRepo.find({
|
|
|
175
193
|
|
|
176
194
|
```typescript
|
|
177
195
|
// Single field
|
|
178
|
-
{
|
|
196
|
+
{ order: ['createdAt DESC'] }
|
|
179
197
|
|
|
180
198
|
// Multiple fields
|
|
181
|
-
{
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
]}
|
|
199
|
+
{ order: ['status ASC', 'createdAt DESC'] }
|
|
200
|
+
|
|
201
|
+
// Default direction is ASC
|
|
202
|
+
{ order: ['name'] } // Same as 'name ASC'
|
|
203
|
+
|
|
204
|
+
// JSON path ordering
|
|
205
|
+
{ order: ['metadata.priority DESC'] }
|
|
185
206
|
```
|
|
186
207
|
|
|
187
208
|
### Pagination
|
|
188
209
|
|
|
189
210
|
```typescript
|
|
190
211
|
{
|
|
191
|
-
limit: 10, // Max records to return
|
|
192
|
-
|
|
193
|
-
orderBy: { id: 'asc' }
|
|
212
|
+
limit: 10, // Max records to return (default: 10)
|
|
213
|
+
skip: 20, // Skip first 20 records (alias: offset)
|
|
194
214
|
}
|
|
195
215
|
|
|
196
216
|
// Page 3 with 10 items per page
|
|
197
217
|
{
|
|
198
218
|
limit: 10,
|
|
199
|
-
|
|
200
|
-
orderBy: { createdAt: 'desc' }
|
|
219
|
+
skip: 20, // (page - 1) * limit = (3 - 1) * 10
|
|
201
220
|
}
|
|
202
221
|
```
|
|
203
222
|
|
|
@@ -209,209 +228,29 @@ const users = await userRepo.find({
|
|
|
209
228
|
Automatically apply filters to all repository queries (e.g., soft delete, multi-tenant).
|
|
210
229
|
|
|
211
230
|
```typescript
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
static getDefaultFilter() {
|
|
224
|
-
return {
|
|
225
|
-
isDeleted: false, // Exclude deleted users by default
|
|
226
|
-
};
|
|
227
|
-
}
|
|
231
|
+
@model({
|
|
232
|
+
type: 'entity',
|
|
233
|
+
settings: {
|
|
234
|
+
defaultFilter: {
|
|
235
|
+
where: { isDeleted: false },
|
|
236
|
+
limit: 100,
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
})
|
|
240
|
+
export class User extends BaseEntity<typeof User.schema> {
|
|
241
|
+
static override schema = userTable;
|
|
228
242
|
}
|
|
229
243
|
|
|
230
|
-
// All queries automatically
|
|
231
|
-
await userRepo.find({});
|
|
232
|
-
// WHERE
|
|
244
|
+
// All queries automatically include the default filter
|
|
245
|
+
await userRepo.find({ filter: {} });
|
|
246
|
+
// WHERE isDeleted = false LIMIT 100
|
|
233
247
|
|
|
234
248
|
// Skip default filter for admin operations
|
|
235
249
|
await userRepo.find({
|
|
236
|
-
|
|
250
|
+
filter: {},
|
|
237
251
|
options: { shouldSkipDefaultFilter: true },
|
|
238
252
|
});
|
|
239
253
|
// No automatic filter applied
|
|
240
254
|
```
|
|
241
255
|
|
|
242
256
|
**See:** [Default Filter Guide](./default-filter.md)
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
## Common Filter Patterns
|
|
246
|
-
|
|
247
|
-
### Multi-Condition Search
|
|
248
|
-
|
|
249
|
-
```typescript
|
|
250
|
-
{
|
|
251
|
-
and: [
|
|
252
|
-
{ age: { gte: 18, lte: 65 } }, // Between 18 and 65
|
|
253
|
-
{ status: { in: ['active', 'pending'] } },
|
|
254
|
-
{ or: [
|
|
255
|
-
{ email: { endsWith: '@company.com' } },
|
|
256
|
-
{ role: 'admin' }
|
|
257
|
-
]}
|
|
258
|
-
]
|
|
259
|
-
}
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
### Text Search
|
|
263
|
-
|
|
264
|
-
```typescript
|
|
265
|
-
{
|
|
266
|
-
or: [
|
|
267
|
-
{ name: { ilike: '%john%' } },
|
|
268
|
-
{ email: { ilike: '%john%' } },
|
|
269
|
-
{ username: { ilike: '%john%' } }
|
|
270
|
-
]
|
|
271
|
-
}
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
### Date Range
|
|
275
|
-
|
|
276
|
-
```typescript
|
|
277
|
-
{
|
|
278
|
-
createdAt: {
|
|
279
|
-
gte: new Date('2024-01-01'),
|
|
280
|
-
lt: new Date('2024-02-01')
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
### Exclude Soft Deleted
|
|
286
|
-
|
|
287
|
-
```typescript
|
|
288
|
-
{
|
|
289
|
-
and: [
|
|
290
|
-
{ isDeleted: false },
|
|
291
|
-
{ status: 'active' }
|
|
292
|
-
]
|
|
293
|
-
}
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
### Multi-Tenant Filtering
|
|
297
|
-
|
|
298
|
-
```typescript
|
|
299
|
-
{
|
|
300
|
-
and: [
|
|
301
|
-
{ tenantId: currentTenantId },
|
|
302
|
-
{ isActive: true }
|
|
303
|
-
]
|
|
304
|
-
}
|
|
305
|
-
```
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
## Operator Precedence
|
|
309
|
-
|
|
310
|
-
When combining operators, IGNIS follows standard SQL precedence:
|
|
311
|
-
|
|
312
|
-
1. **NOT** - Highest precedence
|
|
313
|
-
2. **AND** - Medium precedence
|
|
314
|
-
3. **OR** - Lowest precedence
|
|
315
|
-
|
|
316
|
-
Use explicit parentheses (via nested `and`/`or`) for clarity:
|
|
317
|
-
|
|
318
|
-
```typescript
|
|
319
|
-
// Clear precedence
|
|
320
|
-
{
|
|
321
|
-
and: [
|
|
322
|
-
{ status: 'active' },
|
|
323
|
-
{ or: [
|
|
324
|
-
{ role: 'admin' },
|
|
325
|
-
{ role: 'moderator' }
|
|
326
|
-
]}
|
|
327
|
-
]
|
|
328
|
-
}
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
## Type Safety
|
|
333
|
-
|
|
334
|
-
All filter operators are fully typed based on your model schema:
|
|
335
|
-
|
|
336
|
-
```typescript
|
|
337
|
-
interface User {
|
|
338
|
-
id: number;
|
|
339
|
-
name: string;
|
|
340
|
-
age: number;
|
|
341
|
-
email: string;
|
|
342
|
-
tags: string[];
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
// ✅ Type-safe filters
|
|
346
|
-
await userRepo.find({
|
|
347
|
-
where: {
|
|
348
|
-
age: { gt: 18 }, // number operators
|
|
349
|
-
name: { like: '%john%' }, // string operators
|
|
350
|
-
tags: { contains: ['typescript'] } // array operators
|
|
351
|
-
}
|
|
352
|
-
});
|
|
353
|
-
|
|
354
|
-
// ❌ TypeScript error: wrong operator for type
|
|
355
|
-
await userRepo.find({
|
|
356
|
-
where: {
|
|
357
|
-
age: { like: '%18%' } // Error: 'like' not valid for numbers
|
|
358
|
-
}
|
|
359
|
-
});
|
|
360
|
-
```
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
## Performance Tips
|
|
364
|
-
|
|
365
|
-
1. **Index frequently filtered columns:**
|
|
366
|
-
```sql
|
|
367
|
-
CREATE INDEX idx_users_status ON users(status);
|
|
368
|
-
CREATE INDEX idx_posts_created_at ON posts(created_at DESC);
|
|
369
|
-
```
|
|
370
|
-
|
|
371
|
-
2. **Use `eq` instead of `like` when possible:**
|
|
372
|
-
```typescript
|
|
373
|
-
// ✅ Fast: Uses index
|
|
374
|
-
{ status: { eq: 'active' } }
|
|
375
|
-
|
|
376
|
-
// ❌ Slower: Full table scan
|
|
377
|
-
{ status: { like: 'active' } }
|
|
378
|
-
```
|
|
379
|
-
|
|
380
|
-
3. **Limit array contains operations:**
|
|
381
|
-
```typescript
|
|
382
|
-
// Better performance with smaller arrays
|
|
383
|
-
{ tags: { contains: ['typescript'] } } // ✅ Good
|
|
384
|
-
{ tags: { contains: ['tag1', 'tag2', /* ... 100 tags */] } } // ❌ Slow
|
|
385
|
-
```
|
|
386
|
-
|
|
387
|
-
4. **Use pagination for large result sets:**
|
|
388
|
-
```typescript
|
|
389
|
-
{
|
|
390
|
-
where: { isActive: true },
|
|
391
|
-
limit: 100,
|
|
392
|
-
offset: 0,
|
|
393
|
-
orderBy: { id: 'asc' }
|
|
394
|
-
}
|
|
395
|
-
```
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
## See Also
|
|
399
|
-
|
|
400
|
-
- **Detailed Guides:**
|
|
401
|
-
- [Comparison Operators](./comparison-operators.md)
|
|
402
|
-
- [Logical Operators](./logical-operators.md)
|
|
403
|
-
- [Pattern Matching](./pattern-matching.md)
|
|
404
|
-
- [JSON Filtering](./json-filtering.md)
|
|
405
|
-
- [Array Operators](./array-operators.md)
|
|
406
|
-
|
|
407
|
-
- **Related References:**
|
|
408
|
-
- [Repositories](../repositories/) - Using filters in repository queries
|
|
409
|
-
- [Models](../models.md) - Defining model schemas
|
|
410
|
-
|
|
411
|
-
- **Usage Guides:**
|
|
412
|
-
- [Application Usage](./application-usage.md) - Filters in the full stack
|
|
413
|
-
- [Use Case Gallery](./use-cases.md) - Real-world examples
|
|
414
|
-
- [Pro Tips & Edge Cases](./tips.md) - Advanced patterns
|
|
415
|
-
|
|
416
|
-
- **Quick Reference:**
|
|
417
|
-
- [Main Quick Reference](/references/quick-reference.md) - All IGNIS APIs
|
|
@@ -34,7 +34,10 @@ Find values within a range (inclusive):
|
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
> [!WARNING]
|
|
37
|
-
> The value MUST be an array with exactly 2 elements `[min, max]`. Invalid values throw an error
|
|
37
|
+
> The value MUST be an array with exactly 2 elements `[min, max]`. Invalid values throw an error:
|
|
38
|
+
> ```
|
|
39
|
+
> Error: [BETWEEN] Invalid value: expected array of 2 elements, got ...
|
|
40
|
+
> ```
|
|
38
41
|
|
|
39
42
|
|
|
40
43
|
## notBetween
|
|
@@ -47,6 +50,9 @@ Find values outside a range:
|
|
|
47
50
|
// Matches: scores < 40 OR scores > 60
|
|
48
51
|
```
|
|
49
52
|
|
|
53
|
+
> [!WARNING]
|
|
54
|
+
> Same validation as `between` -- the value MUST be an array with exactly 2 elements.
|
|
55
|
+
|
|
50
56
|
|
|
51
57
|
## Alternative: Using gte/lte
|
|
52
58
|
|
|
@@ -13,14 +13,17 @@ Advanced tips and common edge cases when working with filters.
|
|
|
13
13
|
|
|
14
14
|
```typescript
|
|
15
15
|
// JSON field contains: { "priority": "3" } (string)
|
|
16
|
-
//
|
|
17
|
-
{ where: { 'metadata.priority': { gt: 2 } } }
|
|
16
|
+
// Numeric comparison uses safe casting:
|
|
17
|
+
{ where: { 'metadata.priority': { gt: 2 } } }
|
|
18
|
+
// The regex '^-?[0-9]+(\.[0-9]+)?$' matches "3", so it casts to numeric 3
|
|
19
|
+
// Result: 3 > 2 -> matches
|
|
18
20
|
|
|
19
|
-
//
|
|
20
|
-
{ where: { 'metadata.priority': { gt:
|
|
21
|
+
// But if JSON field contains: { "priority": "high" }
|
|
22
|
+
{ where: { 'metadata.priority': { gt: 2 } } }
|
|
23
|
+
// "high" fails regex -> NULL -> no match
|
|
21
24
|
|
|
22
|
-
//
|
|
23
|
-
{ "priority": 3 } // Store as number, not string
|
|
25
|
+
// Best practice: ensure your data stores numbers as JSON numbers
|
|
26
|
+
{ "priority": 3 } // Store as number, not string "3"
|
|
24
27
|
```
|
|
25
28
|
|
|
26
29
|
|
|
@@ -73,7 +76,7 @@ for (let i = 0; i < allIds.length; i += chunkSize) {
|
|
|
73
76
|
## Tip 5: Order By JSON Fields
|
|
74
77
|
|
|
75
78
|
```typescript
|
|
76
|
-
// JSON ordering uses #> (preserves
|
|
79
|
+
// JSON ordering uses #> (returns JSONB, preserves types) not #>> (returns text)
|
|
77
80
|
{ order: ['metadata.priority DESC'] }
|
|
78
81
|
// SQL: "metadata" #> '{priority}' DESC
|
|
79
82
|
|
|
@@ -188,3 +191,27 @@ const products = await productRepo.find({
|
|
|
188
191
|
}
|
|
189
192
|
});
|
|
190
193
|
```
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
## Tip 11: Array Operators Accept Single Values
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
// These are equivalent:
|
|
200
|
+
{ where: { tags: { contains: ['featured'] } } }
|
|
201
|
+
{ where: { tags: { contains: 'featured' } } }
|
|
202
|
+
|
|
203
|
+
// Single values are automatically wrapped in an array
|
|
204
|
+
// This works for contains, containedBy, and overlaps
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
## Tip 12: Field Selection Object Format
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
// Object format only supports inclusion (true values)
|
|
212
|
+
{ fields: { id: true, name: true, email: true } }
|
|
213
|
+
|
|
214
|
+
// Setting a field to false does NOT exclude it -- it just ignores that key
|
|
215
|
+
// If you want to exclude fields, list only the ones you want:
|
|
216
|
+
{ fields: ['id', 'name', 'email'] } // Array format is clearer for this
|
|
217
|
+
```
|
|
@@ -178,7 +178,7 @@ const documents = await documentRepo.find({
|
|
|
178
178
|
const searchProducts = async (query: string, filters: {
|
|
179
179
|
minRating?: number;
|
|
180
180
|
maxPrice?: number;
|
|
181
|
-
|
|
181
|
+
categories?: string[];
|
|
182
182
|
}) => {
|
|
183
183
|
const where: TWhere<TProductSchema> = {
|
|
184
184
|
status: 'active',
|
|
@@ -201,8 +201,9 @@ const searchProducts = async (query: string, filters: {
|
|
|
201
201
|
where.price = { lte: filters.maxPrice };
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
-
if (filters.
|
|
205
|
-
|
|
204
|
+
if (filters.categories?.length) {
|
|
205
|
+
// Use array operator on a PostgreSQL array column
|
|
206
|
+
where.categories = { contains: filters.categories };
|
|
206
207
|
}
|
|
207
208
|
|
|
208
209
|
return productRepo.find({
|
|
@@ -214,7 +215,7 @@ const searchProducts = async (query: string, filters: {
|
|
|
214
215
|
});
|
|
215
216
|
};
|
|
216
217
|
|
|
217
|
-
// Example: searchProducts('wireless', { minRating: 4, maxPrice: 200,
|
|
218
|
+
// Example: searchProducts('wireless', { minRating: 4, maxPrice: 200, categories: ['electronics'] })
|
|
218
219
|
//
|
|
219
220
|
// SQL:
|
|
220
221
|
// SELECT *
|
|
@@ -228,7 +229,7 @@ const searchProducts = async (query: string, filters: {
|
|
|
228
229
|
// )
|
|
229
230
|
// AND "rating" >= 4
|
|
230
231
|
// AND "price" <= 200
|
|
231
|
-
// AND "
|
|
232
|
+
// AND "categories"::text[] @> ARRAY['electronics']::text[]
|
|
232
233
|
// ORDER BY "rating" DESC, "created_at" DESC
|
|
233
234
|
// LIMIT 50
|
|
234
235
|
```
|