@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.
Files changed (158) hide show
  1. package/dist/mcp-server/common/paths.d.ts +4 -2
  2. package/dist/mcp-server/common/paths.d.ts.map +1 -1
  3. package/dist/mcp-server/common/paths.js +8 -6
  4. package/dist/mcp-server/common/paths.js.map +1 -1
  5. package/dist/mcp-server/tools/docs/get-document-content.tool.d.ts +1 -1
  6. package/dist/mcp-server/tools/docs/get-document-content.tool.d.ts.map +1 -1
  7. package/dist/mcp-server/tools/docs/get-document-content.tool.js +7 -7
  8. package/dist/mcp-server/tools/docs/get-document-metadata.tool.js +3 -3
  9. package/dist/mcp-server/tools/docs/get-package-overview.tool.d.ts +1 -1
  10. package/dist/mcp-server/tools/docs/get-package-overview.tool.js +1 -1
  11. package/package.json +1 -1
  12. package/wiki/best-practices/api-usage-examples.md +9 -9
  13. package/wiki/best-practices/architectural-patterns.md +19 -3
  14. package/wiki/best-practices/architecture-decisions.md +6 -6
  15. package/wiki/best-practices/code-style-standards/advanced-patterns.md +1 -1
  16. package/wiki/best-practices/code-style-standards/control-flow.md +1 -1
  17. package/wiki/best-practices/code-style-standards/function-patterns.md +2 -2
  18. package/wiki/best-practices/code-style-standards/index.md +2 -2
  19. package/wiki/best-practices/code-style-standards/naming-conventions.md +1 -1
  20. package/wiki/best-practices/code-style-standards/route-definitions.md +4 -4
  21. package/wiki/best-practices/data-modeling.md +1 -1
  22. package/wiki/best-practices/deployment-strategies.md +1 -1
  23. package/wiki/best-practices/error-handling.md +2 -2
  24. package/wiki/best-practices/performance-optimization.md +3 -3
  25. package/wiki/best-practices/security-guidelines.md +2 -2
  26. package/wiki/best-practices/troubleshooting-tips.md +1 -1
  27. package/wiki/{references → extensions}/components/authentication/api.md +12 -20
  28. package/wiki/{references → extensions}/components/authentication/errors.md +1 -1
  29. package/wiki/{references → extensions}/components/authentication/index.md +5 -8
  30. package/wiki/{references → extensions}/components/authentication/usage.md +20 -36
  31. package/wiki/{references → extensions}/components/authorization/api.md +62 -13
  32. package/wiki/{references → extensions}/components/authorization/errors.md +12 -7
  33. package/wiki/{references → extensions}/components/authorization/index.md +93 -6
  34. package/wiki/{references → extensions}/components/authorization/usage.md +42 -4
  35. package/wiki/{references → extensions}/components/health-check.md +5 -4
  36. package/wiki/{references → extensions}/components/index.md +2 -0
  37. package/wiki/{references → extensions}/components/mail/index.md +1 -1
  38. package/wiki/{references → extensions}/components/request-tracker.md +1 -1
  39. package/wiki/{references → extensions}/components/socket-io/api.md +2 -2
  40. package/wiki/{references → extensions}/components/socket-io/errors.md +2 -0
  41. package/wiki/{references → extensions}/components/socket-io/index.md +24 -20
  42. package/wiki/{references → extensions}/components/socket-io/usage.md +2 -2
  43. package/wiki/{references → extensions}/components/static-asset/api.md +14 -15
  44. package/wiki/{references → extensions}/components/static-asset/errors.md +3 -1
  45. package/wiki/{references → extensions}/components/static-asset/index.md +158 -89
  46. package/wiki/{references → extensions}/components/static-asset/usage.md +8 -5
  47. package/wiki/{references → extensions}/components/swagger.md +3 -3
  48. package/wiki/{references → extensions}/components/template/index.md +4 -4
  49. package/wiki/{references → extensions}/components/template/setup-page.md +1 -1
  50. package/wiki/{references → extensions}/components/template/single-page.md +1 -1
  51. package/wiki/{references → extensions}/components/websocket/api.md +7 -6
  52. package/wiki/{references → extensions}/components/websocket/errors.md +17 -3
  53. package/wiki/{references → extensions}/components/websocket/index.md +17 -11
  54. package/wiki/{references → extensions}/components/websocket/usage.md +2 -2
  55. package/wiki/{references → extensions}/helpers/crypto/index.md +1 -1
  56. package/wiki/{references → extensions}/helpers/env/index.md +9 -5
  57. package/wiki/{references → extensions}/helpers/error/index.md +2 -7
  58. package/wiki/{references → extensions}/helpers/index.md +18 -6
  59. package/wiki/{references → extensions}/helpers/kafka/admin.md +13 -1
  60. package/wiki/{references → extensions}/helpers/kafka/consumer.md +28 -28
  61. package/wiki/{references → extensions}/helpers/kafka/examples.md +19 -19
  62. package/wiki/{references → extensions}/helpers/kafka/index.md +51 -48
  63. package/wiki/{references → extensions}/helpers/kafka/producer.md +18 -18
  64. package/wiki/{references → extensions}/helpers/kafka/schema-registry.md +25 -25
  65. package/wiki/{references → extensions}/helpers/logger/index.md +2 -2
  66. package/wiki/{references → extensions}/helpers/queue/index.md +400 -4
  67. package/wiki/{references → extensions}/helpers/storage/api.md +170 -10
  68. package/wiki/{references → extensions}/helpers/storage/index.md +44 -8
  69. package/wiki/{references → extensions}/helpers/template/index.md +1 -1
  70. package/wiki/{references → extensions}/helpers/testing/index.md +4 -4
  71. package/wiki/{references → extensions}/helpers/types/index.md +63 -16
  72. package/wiki/{references → extensions}/helpers/websocket/index.md +1 -1
  73. package/wiki/extensions/index.md +48 -0
  74. package/wiki/guides/core-concepts/application/bootstrapping.md +55 -37
  75. package/wiki/guides/core-concepts/application/index.md +95 -35
  76. package/wiki/guides/core-concepts/components-guide.md +23 -19
  77. package/wiki/guides/core-concepts/components.md +34 -10
  78. package/wiki/guides/core-concepts/dependency-injection.md +99 -34
  79. package/wiki/guides/core-concepts/grpc-controllers.md +295 -0
  80. package/wiki/guides/core-concepts/persistent/datasources.md +27 -8
  81. package/wiki/guides/core-concepts/persistent/models.md +43 -1
  82. package/wiki/guides/core-concepts/persistent/repositories.md +75 -8
  83. package/wiki/guides/core-concepts/persistent/transactions.md +38 -8
  84. package/wiki/guides/core-concepts/{controllers.md → rest-controllers.md} +30 -33
  85. package/wiki/guides/core-concepts/services.md +19 -5
  86. package/wiki/guides/get-started/5-minute-quickstart.md +6 -7
  87. package/wiki/guides/get-started/philosophy.md +1 -1
  88. package/wiki/guides/index.md +2 -2
  89. package/wiki/guides/reference/glossary.md +7 -7
  90. package/wiki/guides/reference/mcp-docs-server.md +1 -1
  91. package/wiki/guides/tutorials/building-a-crud-api.md +2 -2
  92. package/wiki/guides/tutorials/complete-installation.md +17 -14
  93. package/wiki/guides/tutorials/ecommerce-api.md +18 -18
  94. package/wiki/guides/tutorials/realtime-chat.md +8 -8
  95. package/wiki/guides/tutorials/testing.md +2 -2
  96. package/wiki/index.md +4 -3
  97. package/wiki/references/base/application.md +341 -21
  98. package/wiki/references/base/bootstrapping.md +43 -13
  99. package/wiki/references/base/components.md +259 -8
  100. package/wiki/references/base/controllers.md +556 -253
  101. package/wiki/references/base/datasources.md +159 -79
  102. package/wiki/references/base/dependency-injection.md +299 -48
  103. package/wiki/references/base/filter-system/application-usage.md +18 -2
  104. package/wiki/references/base/filter-system/array-operators.md +14 -6
  105. package/wiki/references/base/filter-system/comparison-operators.md +9 -3
  106. package/wiki/references/base/filter-system/default-filter.md +28 -3
  107. package/wiki/references/base/filter-system/fields-order-pagination.md +17 -13
  108. package/wiki/references/base/filter-system/index.md +169 -11
  109. package/wiki/references/base/filter-system/json-filtering.md +51 -18
  110. package/wiki/references/base/filter-system/list-operators.md +4 -3
  111. package/wiki/references/base/filter-system/logical-operators.md +7 -2
  112. package/wiki/references/base/filter-system/null-operators.md +50 -0
  113. package/wiki/references/base/filter-system/quick-reference.md +82 -243
  114. package/wiki/references/base/filter-system/range-operators.md +7 -1
  115. package/wiki/references/base/filter-system/tips.md +34 -7
  116. package/wiki/references/base/filter-system/use-cases.md +6 -5
  117. package/wiki/references/base/grpc-controllers.md +984 -0
  118. package/wiki/references/base/index.md +32 -24
  119. package/wiki/references/base/middleware.md +347 -0
  120. package/wiki/references/base/models.md +390 -46
  121. package/wiki/references/base/providers.md +14 -14
  122. package/wiki/references/base/repositories/advanced.md +84 -69
  123. package/wiki/references/base/repositories/index.md +447 -12
  124. package/wiki/references/base/repositories/mixins.md +103 -98
  125. package/wiki/references/base/repositories/relations.md +129 -45
  126. package/wiki/references/base/repositories/soft-deletable.md +104 -23
  127. package/wiki/references/base/services.md +94 -14
  128. package/wiki/references/index.md +12 -10
  129. package/wiki/references/quick-reference.md +98 -65
  130. package/wiki/references/utilities/crypto.md +21 -4
  131. package/wiki/references/utilities/date.md +25 -7
  132. package/wiki/references/utilities/index.md +26 -24
  133. package/wiki/references/utilities/jsx.md +54 -54
  134. package/wiki/references/utilities/module.md +8 -6
  135. package/wiki/references/utilities/parse.md +16 -9
  136. package/wiki/references/utilities/performance.md +22 -7
  137. package/wiki/references/utilities/promise.md +19 -16
  138. package/wiki/references/utilities/request.md +48 -26
  139. package/wiki/references/utilities/schema.md +69 -6
  140. package/wiki/references/utilities/statuses.md +131 -140
  141. /package/wiki/{references → extensions}/components/mail/api.md +0 -0
  142. /package/wiki/{references → extensions}/components/mail/errors.md +0 -0
  143. /package/wiki/{references → extensions}/components/mail/usage.md +0 -0
  144. /package/wiki/{references → extensions}/components/template/api-page.md +0 -0
  145. /package/wiki/{references → extensions}/components/template/errors-page.md +0 -0
  146. /package/wiki/{references → extensions}/components/template/usage-page.md +0 -0
  147. /package/wiki/{references → extensions}/helpers/cron/index.md +0 -0
  148. /package/wiki/{references → extensions}/helpers/inversion/index.md +0 -0
  149. /package/wiki/{references → extensions}/helpers/network/api.md +0 -0
  150. /package/wiki/{references → extensions}/helpers/network/index.md +0 -0
  151. /package/wiki/{references → extensions}/helpers/redis/index.md +0 -0
  152. /package/wiki/{references → extensions}/helpers/socket-io/api.md +0 -0
  153. /package/wiki/{references → extensions}/helpers/socket-io/index.md +0 -0
  154. /package/wiki/{references → extensions}/helpers/template/single-page.md +0 -0
  155. /package/wiki/{references → extensions}/helpers/uid/index.md +0 -0
  156. /package/wiki/{references → extensions}/helpers/websocket/api.md +0 -0
  157. /package/wiki/{references → extensions}/helpers/worker-thread/index.md +0 -0
  158. /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-01-03
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
- | `neq` | `!=` | `{ status: { neq: 'deleted' } }` | Not equal to |
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` / `inq` | `IN` | `{ status: { in: ['active', 'pending'] } }` | Value matches any in array |
41
- | `notIn` / `nin` | `NOT IN` | `{ status: { notIn: ['deleted', 'banned'] } }` | Value doesn't match any in array |
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
- | `notLike` | `NOT LIKE` | `{ name: { notLike: '%test%' } }` | Inverse pattern match (case-sensitive) |
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
- | `isNull` | `IS NULL` | `{ deletedAt: { isNull: true } }` | Value is NULL |
71
- | `isNotNull` | `IS NOT NULL` | `{ email: { isNotNull: true } }` | Value is not NULL |
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
- **Alternative Syntax:**
73
+ **Shorthand Syntax:**
74
74
  ```typescript
75
- // Using 'is' operator
76
- { deletedAt: { is: null } } // IS NULL
77
- { email: { is: { not: null } } } // IS NOT NULL
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`/`notIn` which match scalar values against an array.
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
- ### Basic JSON Path
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 Filters
141
+ ### JSON Path with Operators
133
142
 
134
143
  ```typescript
135
- // Query JSON field
136
- {
137
- metadata: {
138
- jsonPath: '$.user.name',
139
- eq: 'John'
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: { jsonPath: '$.user.age', gt: 18 } },
147
- { metadata: { jsonPath: '$.user.country', eq: 'US' } }
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`, `notIn`
157
- - `like`, `ilike` (for string fields)
158
- - `isNull`, `isNotNull`
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
- where: { isActive: true },
170
- fields: ['id', 'name', 'email'], // Only return these fields
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
- { orderBy: { createdAt: 'desc' } }
196
+ { order: ['createdAt DESC'] }
179
197
 
180
198
  // Multiple fields
181
- { orderBy: [
182
- { createdAt: 'desc' },
183
- { name: 'asc' }
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
- offset: 20, // Skip first 20 records
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
- offset: 20, // (page - 1) * limit = (3 - 1) * 10
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
- import { model, DefaultFilterMixin } from '@venizia/ignis';
213
-
214
- @model()
215
- class User extends DefaultFilterMixin(BaseEntity) {
216
- static readonly schema = pgTable('users', {
217
- id: integer('id').primaryKey(),
218
- name: text('name'),
219
- isDeleted: boolean('is_deleted').default(false),
220
- });
221
-
222
- // Define default filter
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 exclude deleted users
231
- await userRepo.find({});
232
- // WHERE is_deleted = false
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
- where: {},
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
- // This WON'T match numeric comparison!
17
- { where: { 'metadata.priority': { gt: 2 } } } // NULL due to safe casting
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
- // Use string comparison instead
20
- { where: { 'metadata.priority': { gt: '2' } } } // Lexicographic compare
21
+ // But if JSON field contains: { "priority": "high" }
22
+ { where: { 'metadata.priority': { gt: 2 } } }
23
+ // "high" fails regex -> NULL -> no match
21
24
 
22
- // Or ensure your data stores numbers properly
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 type) not #>> (text)
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
- features?: string[];
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.features?.length) {
205
- where['metadata.features'] = { contains: filters.features };
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, features: ['bluetooth'] })
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 "metadata" #>> '{features}' @> '["bluetooth"]'
232
+ // AND "categories"::text[] @> ARRAY['electronics']::text[]
232
233
  // ORDER BY "rating" DESC, "created_at" DESC
233
234
  // LIMIT 50
234
235
  ```