@venizia/ignis-docs 0.0.3 → 0.0.4-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +4 -2
- package/wiki/best-practices/api-usage-examples.md +591 -0
- package/wiki/best-practices/architectural-patterns.md +415 -0
- package/wiki/best-practices/architecture-decisions.md +488 -0
- package/wiki/{get-started/best-practices → best-practices}/code-style-standards.md +406 -17
- package/wiki/{get-started/best-practices → best-practices}/common-pitfalls.md +109 -4
- package/wiki/{get-started/best-practices → best-practices}/contribution-workflow.md +34 -7
- package/wiki/best-practices/data-modeling.md +376 -0
- package/wiki/best-practices/deployment-strategies.md +698 -0
- package/wiki/best-practices/index.md +27 -0
- package/wiki/best-practices/performance-optimization.md +196 -0
- package/wiki/best-practices/security-guidelines.md +218 -0
- package/wiki/{get-started/best-practices → best-practices}/troubleshooting-tips.md +97 -1
- package/wiki/changelogs/2025-12-16-initial-architecture.md +1 -1
- package/wiki/changelogs/2025-12-16-model-repo-datasource-refactor.md +1 -1
- package/wiki/changelogs/2025-12-17-refactor.md +1 -1
- package/wiki/changelogs/2025-12-18-performance-optimizations.md +5 -5
- package/wiki/changelogs/2025-12-18-repository-validation-security.md +13 -7
- package/wiki/changelogs/2025-12-26-nested-relations-and-generics.md +2 -2
- package/wiki/changelogs/2025-12-29-dynamic-binding-registration.md +104 -0
- package/wiki/changelogs/2025-12-29-snowflake-uid-helper.md +100 -0
- package/wiki/changelogs/2025-12-30-repository-enhancements.md +214 -0
- package/wiki/changelogs/2025-12-31-json-path-filtering-array-operators.md +214 -0
- package/wiki/changelogs/2025-12-31-string-id-custom-generator.md +137 -0
- package/wiki/changelogs/2026-01-02-default-filter-and-repository-mixins.md +418 -0
- package/wiki/changelogs/index.md +6 -0
- package/wiki/changelogs/planned-schema-migrator.md +0 -8
- package/wiki/{get-started/core-concepts → guides/core-concepts/application}/bootstrapping.md +18 -5
- package/wiki/{get-started/core-concepts/application.md → guides/core-concepts/application/index.md} +47 -104
- package/wiki/guides/core-concepts/components-guide.md +509 -0
- package/wiki/{get-started → guides}/core-concepts/components.md +24 -17
- package/wiki/{get-started → guides}/core-concepts/controllers.md +30 -13
- package/wiki/{get-started → guides}/core-concepts/dependency-injection.md +97 -0
- package/wiki/guides/core-concepts/persistent/datasources.md +179 -0
- package/wiki/guides/core-concepts/persistent/index.md +119 -0
- package/wiki/guides/core-concepts/persistent/models.md +241 -0
- package/wiki/guides/core-concepts/persistent/repositories.md +219 -0
- package/wiki/guides/core-concepts/persistent/transactions.md +170 -0
- package/wiki/{get-started → guides}/core-concepts/services.md +26 -3
- package/wiki/{get-started → guides/get-started}/5-minute-quickstart.md +59 -14
- package/wiki/guides/get-started/philosophy.md +682 -0
- package/wiki/guides/get-started/setup.md +157 -0
- package/wiki/guides/index.md +89 -0
- package/wiki/guides/reference/glossary.md +243 -0
- package/wiki/{get-started → guides/reference}/mcp-docs-server.md +0 -10
- package/wiki/{get-started → guides/tutorials}/building-a-crud-api.md +134 -132
- package/wiki/{get-started/quickstart.md → guides/tutorials/complete-installation.md} +107 -71
- package/wiki/guides/tutorials/ecommerce-api.md +1399 -0
- package/wiki/guides/tutorials/realtime-chat.md +1261 -0
- package/wiki/guides/tutorials/testing.md +723 -0
- package/wiki/index.md +176 -37
- package/wiki/references/base/application.md +27 -0
- package/wiki/references/base/bootstrapping.md +30 -26
- package/wiki/references/base/components.md +24 -7
- package/wiki/references/base/controllers.md +51 -20
- package/wiki/references/base/datasources.md +30 -0
- package/wiki/references/base/dependency-injection.md +39 -3
- package/wiki/references/base/filter-system/application-usage.md +224 -0
- package/wiki/references/base/filter-system/array-operators.md +132 -0
- package/wiki/references/base/filter-system/comparison-operators.md +109 -0
- package/wiki/references/base/filter-system/default-filter.md +428 -0
- package/wiki/references/base/filter-system/fields-order-pagination.md +155 -0
- package/wiki/references/base/filter-system/index.md +127 -0
- package/wiki/references/base/filter-system/json-filtering.md +197 -0
- package/wiki/references/base/filter-system/list-operators.md +71 -0
- package/wiki/references/base/filter-system/logical-operators.md +156 -0
- package/wiki/references/base/filter-system/null-operators.md +58 -0
- package/wiki/references/base/filter-system/pattern-matching.md +108 -0
- package/wiki/references/base/filter-system/quick-reference.md +431 -0
- package/wiki/references/base/filter-system/range-operators.md +63 -0
- package/wiki/references/base/filter-system/tips.md +190 -0
- package/wiki/references/base/filter-system/use-cases.md +452 -0
- package/wiki/references/base/index.md +90 -0
- package/wiki/references/base/middlewares.md +602 -0
- package/wiki/references/base/models.md +215 -23
- package/wiki/references/base/providers.md +732 -0
- package/wiki/references/base/repositories/advanced.md +555 -0
- package/wiki/references/base/repositories/index.md +228 -0
- package/wiki/references/base/repositories/mixins.md +331 -0
- package/wiki/references/base/repositories/relations.md +486 -0
- package/wiki/references/base/repositories.md +40 -635
- package/wiki/references/base/services.md +28 -4
- package/wiki/references/components/authentication.md +22 -2
- package/wiki/references/components/health-check.md +12 -0
- package/wiki/references/components/index.md +23 -0
- package/wiki/references/components/mail.md +687 -0
- package/wiki/references/components/request-tracker.md +16 -0
- package/wiki/references/components/socket-io.md +18 -0
- package/wiki/references/components/static-asset.md +14 -26
- package/wiki/references/components/swagger.md +17 -0
- package/wiki/references/configuration/environment-variables.md +427 -0
- package/wiki/references/configuration/index.md +73 -0
- package/wiki/references/helpers/cron.md +14 -0
- package/wiki/references/helpers/crypto.md +15 -0
- package/wiki/references/helpers/env.md +16 -0
- package/wiki/references/helpers/error.md +17 -0
- package/wiki/references/helpers/index.md +14 -0
- package/wiki/references/helpers/inversion.md +24 -4
- package/wiki/references/helpers/logger.md +19 -0
- package/wiki/references/helpers/network.md +11 -0
- package/wiki/references/helpers/queue.md +19 -0
- package/wiki/references/helpers/redis.md +21 -0
- package/wiki/references/helpers/socket-io.md +24 -5
- package/wiki/references/helpers/storage.md +18 -10
- package/wiki/references/helpers/testing.md +18 -0
- package/wiki/references/helpers/types.md +16 -0
- package/wiki/references/helpers/uid.md +167 -0
- package/wiki/references/helpers/worker-thread.md +16 -0
- package/wiki/references/index.md +177 -0
- package/wiki/references/quick-reference.md +634 -0
- package/wiki/references/src-details/boot.md +3 -3
- package/wiki/references/src-details/dev-configs.md +0 -4
- package/wiki/references/src-details/docs.md +2 -2
- package/wiki/references/src-details/index.md +86 -0
- package/wiki/references/src-details/inversion.md +1 -6
- package/wiki/references/src-details/mcp-server.md +3 -15
- package/wiki/references/utilities/index.md +86 -10
- package/wiki/references/utilities/jsx.md +577 -0
- package/wiki/references/utilities/request.md +0 -2
- package/wiki/references/utilities/statuses.md +740 -0
- package/wiki/get-started/best-practices/api-usage-examples.md +0 -266
- package/wiki/get-started/best-practices/architectural-patterns.md +0 -170
- package/wiki/get-started/best-practices/data-modeling.md +0 -177
- package/wiki/get-started/best-practices/deployment-strategies.md +0 -121
- package/wiki/get-started/best-practices/performance-optimization.md +0 -97
- package/wiki/get-started/best-practices/security-guidelines.md +0 -99
- package/wiki/get-started/core-concepts/persistent.md +0 -539
- package/wiki/get-started/index.md +0 -65
- package/wiki/get-started/philosophy.md +0 -296
- package/wiki/get-started/prerequisites.md +0 -113
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Pattern Matching Operators
|
|
3
|
+
description: Operators for string pattern matching and regular expressions
|
|
4
|
+
difficulty: intermediate
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Pattern Matching Operators
|
|
8
|
+
|
|
9
|
+
Operators for string pattern matching and regular expressions.
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
## like - Pattern Matching (Case-Sensitive)
|
|
13
|
+
|
|
14
|
+
Matches strings using SQL LIKE patterns.
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
// Starts with
|
|
18
|
+
{ where: { email: { like: '%@gmail.com' } } }
|
|
19
|
+
// SQL: WHERE "email" LIKE '%@gmail.com'
|
|
20
|
+
|
|
21
|
+
// Contains
|
|
22
|
+
{ where: { name: { like: '%john%' } } }
|
|
23
|
+
// SQL: WHERE "name" LIKE '%john%'
|
|
24
|
+
|
|
25
|
+
// Ends with
|
|
26
|
+
{ where: { filename: { like: '%.pdf' } } }
|
|
27
|
+
// SQL: WHERE "filename" LIKE '%.pdf'
|
|
28
|
+
|
|
29
|
+
// Single character wildcard
|
|
30
|
+
{ where: { code: { like: 'A_B' } } } // Matches 'A1B', 'AXB', etc.
|
|
31
|
+
// SQL: WHERE "code" LIKE 'A_B'
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**Pattern Characters:**
|
|
35
|
+
- `%` - Matches any sequence of characters (including empty)
|
|
36
|
+
- `_` - Matches exactly one character
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
## nlike - Not Like
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
{ where: { email: { nlike: '%@test.com' } } }
|
|
43
|
+
// SQL: WHERE "email" NOT LIKE '%@test.com'
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
## ilike - Case-Insensitive Pattern Matching
|
|
48
|
+
|
|
49
|
+
PostgreSQL-specific case-insensitive LIKE.
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
{ where: { name: { ilike: '%john%' } } }
|
|
53
|
+
// SQL: WHERE "name" ILIKE '%john%'
|
|
54
|
+
// Matches: 'John', 'JOHN', 'john', 'JoHn'
|
|
55
|
+
|
|
56
|
+
{ where: { email: { ilike: '%@GMAIL.COM' } } }
|
|
57
|
+
// Matches: 'user@gmail.com', 'USER@Gmail.Com'
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
## nilike - Not ILike
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
{ where: { email: { nilike: '%@example%' } } }
|
|
65
|
+
// SQL: WHERE NOT ("email" ILIKE '%@example%')
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
## regexp - Regular Expression (Case-Sensitive)
|
|
70
|
+
|
|
71
|
+
PostgreSQL POSIX regex matching.
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
// Starts with letter
|
|
75
|
+
{ where: { code: { regexp: '^[A-Z]' } } }
|
|
76
|
+
// SQL: WHERE "code" ~ '^[A-Z]'
|
|
77
|
+
|
|
78
|
+
// Email pattern
|
|
79
|
+
{ where: { email: { regexp: '^[a-z]+@[a-z]+\\.[a-z]+$' } } }
|
|
80
|
+
// SQL: WHERE "email" ~ '^[a-z]+@[a-z]+\.[a-z]+$'
|
|
81
|
+
|
|
82
|
+
// Phone number pattern
|
|
83
|
+
{ where: { phone: { regexp: '^\\+?[0-9]{10,15}$' } } }
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
> [!NOTE]
|
|
87
|
+
> Escape backslashes in TypeScript strings: `\\d` for regex `\d`.
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
## iregexp - Case-Insensitive Regular Expression
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
{ where: { name: { iregexp: '^john' } } }
|
|
94
|
+
// SQL: WHERE "name" ~* '^john'
|
|
95
|
+
// Matches: 'John Doe', 'JOHN SMITH', 'john'
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
## Summary
|
|
100
|
+
|
|
101
|
+
| Operator | SQL | Case | Description |
|
|
102
|
+
|----------|-----|------|-------------|
|
|
103
|
+
| `like` | `LIKE` | Sensitive | Pattern with wildcards |
|
|
104
|
+
| `nlike` | `NOT LIKE` | Sensitive | Negative pattern |
|
|
105
|
+
| `ilike` | `ILIKE` | Insensitive | PostgreSQL only |
|
|
106
|
+
| `nilike` | `NOT ILIKE` | Insensitive | PostgreSQL only |
|
|
107
|
+
| `regexp` | `~` | Sensitive | POSIX regex match |
|
|
108
|
+
| `iregexp` | `~*` | Insensitive | POSIX regex match |
|
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Filter Operators Quick Reference
|
|
3
|
+
description: Single-page cheat sheet of all filter operators
|
|
4
|
+
difficulty: intermediate
|
|
5
|
+
lastUpdated: 2026-01-03
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Filter Operators Quick Reference
|
|
9
|
+
|
|
10
|
+
Complete single-page reference for all IGNIS filter operators. For detailed explanations and examples, see the individual operator guides.
|
|
11
|
+
|
|
12
|
+
## Comparison Operators
|
|
13
|
+
|
|
14
|
+
| Operator | SQL | TypeScript Example | Description |
|
|
15
|
+
|----------|-----|-------------------|-------------|
|
|
16
|
+
| `eq` | `=` | `{ status: { eq: 'active' } }` | Equal to |
|
|
17
|
+
| `neq` | `!=` | `{ status: { neq: 'deleted' } }` | Not equal to |
|
|
18
|
+
| `gt` | `>` | `{ age: { gt: 18 } }` | Greater than |
|
|
19
|
+
| `gte` | `>=` | `{ age: { gte: 18 } }` | Greater than or equal |
|
|
20
|
+
| `lt` | `<` | `{ price: { lt: 100 } }` | Less than |
|
|
21
|
+
| `lte` | `<=` | `{ price: { lte: 100 } }` | Less than or equal |
|
|
22
|
+
|
|
23
|
+
**See:** [Comparison Operators Guide](./comparison-operators.md)
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Range Operators
|
|
28
|
+
|
|
29
|
+
| Operator | SQL | TypeScript Example | Description |
|
|
30
|
+
|----------|-----|-------------------|-------------|
|
|
31
|
+
| `between` | `BETWEEN` | `{ age: { between: [18, 65] } }` | Value is within range (inclusive) |
|
|
32
|
+
| `notBetween` | `NOT BETWEEN` | `{ age: { notBetween: [0, 18] } }` | Value is outside range |
|
|
33
|
+
|
|
34
|
+
**See:** [Range Operators Guide](./range-operators.md)
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## List Operators
|
|
39
|
+
|
|
40
|
+
| Operator | SQL | TypeScript Example | Description |
|
|
41
|
+
|----------|-----|-------------------|-------------|
|
|
42
|
+
| `in` / `inq` | `IN` | `{ status: { in: ['active', 'pending'] } }` | Value matches any in array |
|
|
43
|
+
| `notIn` / `nin` | `NOT IN` | `{ status: { notIn: ['deleted', 'banned'] } }` | Value doesn't match any in array |
|
|
44
|
+
|
|
45
|
+
**See:** [List Operators Guide](./list-operators.md)
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Pattern Matching Operators
|
|
50
|
+
|
|
51
|
+
| Operator | SQL | TypeScript Example | Description |
|
|
52
|
+
|----------|-----|-------------------|-------------|
|
|
53
|
+
| `like` | `LIKE` | `{ name: { like: '%john%' } }` | Pattern match (case-sensitive) |
|
|
54
|
+
| `ilike` | `ILIKE` | `{ email: { ilike: '%@gmail.com' } }` | Pattern match (case-insensitive) |
|
|
55
|
+
| `notLike` | `NOT LIKE` | `{ name: { notLike: '%test%' } }` | Inverse pattern match (case-sensitive) |
|
|
56
|
+
| `notILike` | `NOT ILIKE` | `{ email: { notILike: '%spam%' } }` | Inverse pattern match (case-insensitive) |
|
|
57
|
+
| `startsWith` | `LIKE 'value%'` | `{ name: { startsWith: 'John' } }` | Starts with value |
|
|
58
|
+
| `endsWith` | `LIKE '%value'` | `{ email: { endsWith: '@example.com' } }` | Ends with value |
|
|
59
|
+
| `regexp` | `~` | `{ code: { regexp: '^[A-Z]{3}$' } }` | Regular expression (PostgreSQL) |
|
|
60
|
+
| `iregexp` | `~*` | `{ code: { iregexp: '^[a-z]{3}$' } }` | Case-insensitive regex (PostgreSQL) |
|
|
61
|
+
|
|
62
|
+
**Wildcard Patterns:**
|
|
63
|
+
- `%` - Matches any sequence of characters
|
|
64
|
+
- `_` - Matches any single character
|
|
65
|
+
|
|
66
|
+
**See:** [Pattern Matching Guide](./pattern-matching.md)
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Null Check Operators
|
|
71
|
+
|
|
72
|
+
| Operator | SQL | TypeScript Example | Description |
|
|
73
|
+
|----------|-----|-------------------|-------------|
|
|
74
|
+
| `isNull` | `IS NULL` | `{ deletedAt: { isNull: true } }` | Value is NULL |
|
|
75
|
+
| `isNotNull` | `IS NOT NULL` | `{ email: { isNotNull: true } }` | Value is not NULL |
|
|
76
|
+
|
|
77
|
+
**Alternative Syntax:**
|
|
78
|
+
```typescript
|
|
79
|
+
// Using 'is' operator
|
|
80
|
+
{ deletedAt: { is: null } } // IS NULL
|
|
81
|
+
{ email: { is: { not: null } } } // IS NOT NULL
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**See:** [Null Operators Guide](./null-operators.md)
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Logical Operators
|
|
89
|
+
|
|
90
|
+
| Operator | SQL | TypeScript Example | Description |
|
|
91
|
+
|----------|-----|-------------------|-------------|
|
|
92
|
+
| `and` | `AND` | `{ and: [{ age: { gt: 18 } }, { status: 'active' }] }` | All conditions must be true |
|
|
93
|
+
| `or` | `OR` | `{ or: [{ role: 'admin' }, { role: 'moderator' }] }` | At least one condition must be true |
|
|
94
|
+
| `not` | `NOT` | `{ not: { status: 'deleted' } }` | Inverts the condition |
|
|
95
|
+
|
|
96
|
+
**Implicit AND:**
|
|
97
|
+
```typescript
|
|
98
|
+
// Multiple fields = implicit AND
|
|
99
|
+
{
|
|
100
|
+
status: 'active',
|
|
101
|
+
age: { gte: 18 },
|
|
102
|
+
role: 'user'
|
|
103
|
+
}
|
|
104
|
+
// WHERE status = 'active' AND age >= 18 AND role = 'user'
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**See:** [Logical Operators Guide](./logical-operators.md)
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## PostgreSQL Array Operators
|
|
112
|
+
|
|
113
|
+
These operators work with PostgreSQL array columns (`varchar[]`, `text[]`, `integer[]`, etc.).
|
|
114
|
+
|
|
115
|
+
| Operator | PostgreSQL | TypeScript Example | Description |
|
|
116
|
+
|----------|------------|-------------------|-------------|
|
|
117
|
+
| `contains` | `@>` | `{ tags: { contains: ['typescript', 'nodejs'] } }` | Array contains **ALL** specified elements |
|
|
118
|
+
| `containedBy` | `<@` | `{ tags: { containedBy: ['ts', 'js', 'go', 'rust'] } }` | Array is subset of specified array |
|
|
119
|
+
| `overlaps` | `&&` | `{ tags: { overlaps: ['react', 'vue', 'angular'] } }` | Arrays have at least one common element |
|
|
120
|
+
|
|
121
|
+
**Important:** These are array-specific operators, not to be confused with `in`/`notIn` which match scalar values against an array.
|
|
122
|
+
|
|
123
|
+
**See:** [Array Operators Guide](./array-operators.md)
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## JSON/JSONB Operators (PostgreSQL)
|
|
128
|
+
|
|
129
|
+
Query nested fields within JSON/JSONB columns using dot notation.
|
|
130
|
+
|
|
131
|
+
### Basic JSON Path
|
|
132
|
+
|
|
133
|
+
| Syntax | Example | Description |
|
|
134
|
+
|--------|---------|-------------|
|
|
135
|
+
| Dot notation | `metadata.user.name` | Access nested properties |
|
|
136
|
+
| Array index | `metadata.tags[0]` | Access array elements |
|
|
137
|
+
| Combined | `metadata.users[0].email` | Nested arrays and objects |
|
|
138
|
+
|
|
139
|
+
### JSON Path with Filters
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
// Query JSON field
|
|
143
|
+
{
|
|
144
|
+
metadata: {
|
|
145
|
+
jsonPath: '$.user.name',
|
|
146
|
+
eq: 'John'
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Multiple JSON conditions
|
|
151
|
+
{
|
|
152
|
+
and: [
|
|
153
|
+
{ metadata: { jsonPath: '$.user.age', gt: 18 } },
|
|
154
|
+
{ metadata: { jsonPath: '$.user.country', eq: 'US' } }
|
|
155
|
+
]
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Supported Operators with JSON
|
|
160
|
+
|
|
161
|
+
All comparison operators work with JSON path queries:
|
|
162
|
+
- `eq`, `neq`, `gt`, `gte`, `lt`, `lte`
|
|
163
|
+
- `in`, `notIn`
|
|
164
|
+
- `like`, `ilike` (for string fields)
|
|
165
|
+
- `isNull`, `isNotNull`
|
|
166
|
+
|
|
167
|
+
**See:** [JSON Filtering Guide](./json-filtering.md)
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Fields, Ordering & Pagination
|
|
172
|
+
|
|
173
|
+
### Select Specific Fields
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
const users = await userRepo.find({
|
|
177
|
+
where: { isActive: true },
|
|
178
|
+
fields: ['id', 'name', 'email'], // Only return these fields
|
|
179
|
+
});
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Ordering
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
// Single field
|
|
186
|
+
{ orderBy: { createdAt: 'desc' } }
|
|
187
|
+
|
|
188
|
+
// Multiple fields
|
|
189
|
+
{ orderBy: [
|
|
190
|
+
{ createdAt: 'desc' },
|
|
191
|
+
{ name: 'asc' }
|
|
192
|
+
]}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Pagination
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
{
|
|
199
|
+
limit: 10, // Max records to return
|
|
200
|
+
offset: 20, // Skip first 20 records
|
|
201
|
+
orderBy: { id: 'asc' }
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Page 3 with 10 items per page
|
|
205
|
+
{
|
|
206
|
+
limit: 10,
|
|
207
|
+
offset: 20, // (page - 1) * limit = (3 - 1) * 10
|
|
208
|
+
orderBy: { createdAt: 'desc' }
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
**See:** [Fields, Ordering & Pagination Guide](./fields-order-pagination.md)
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## Default Filters
|
|
217
|
+
|
|
218
|
+
Automatically apply filters to all repository queries (e.g., soft delete, multi-tenant).
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
import { model, DefaultFilterMixin } from '@venizia/ignis';
|
|
222
|
+
|
|
223
|
+
@model()
|
|
224
|
+
class User extends DefaultFilterMixin(BaseEntity) {
|
|
225
|
+
static readonly schema = pgTable('users', {
|
|
226
|
+
id: integer('id').primaryKey(),
|
|
227
|
+
name: text('name'),
|
|
228
|
+
isDeleted: boolean('is_deleted').default(false),
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
// Define default filter
|
|
232
|
+
static getDefaultFilter() {
|
|
233
|
+
return {
|
|
234
|
+
isDeleted: false, // Exclude deleted users by default
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// All queries automatically exclude deleted users
|
|
240
|
+
await userRepo.find({});
|
|
241
|
+
// WHERE is_deleted = false
|
|
242
|
+
|
|
243
|
+
// Skip default filter for admin operations
|
|
244
|
+
await userRepo.find({
|
|
245
|
+
where: {},
|
|
246
|
+
options: { shouldSkipDefaultFilter: true },
|
|
247
|
+
});
|
|
248
|
+
// No automatic filter applied
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
**See:** [Default Filter Guide](./default-filter.md)
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## Common Filter Patterns
|
|
256
|
+
|
|
257
|
+
### Multi-Condition Search
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
{
|
|
261
|
+
and: [
|
|
262
|
+
{ age: { gte: 18, lte: 65 } }, // Between 18 and 65
|
|
263
|
+
{ status: { in: ['active', 'pending'] } },
|
|
264
|
+
{ or: [
|
|
265
|
+
{ email: { endsWith: '@company.com' } },
|
|
266
|
+
{ role: 'admin' }
|
|
267
|
+
]}
|
|
268
|
+
]
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Text Search
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
{
|
|
276
|
+
or: [
|
|
277
|
+
{ name: { ilike: '%john%' } },
|
|
278
|
+
{ email: { ilike: '%john%' } },
|
|
279
|
+
{ username: { ilike: '%john%' } }
|
|
280
|
+
]
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Date Range
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
{
|
|
288
|
+
createdAt: {
|
|
289
|
+
gte: new Date('2024-01-01'),
|
|
290
|
+
lt: new Date('2024-02-01')
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Exclude Soft Deleted
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
{
|
|
299
|
+
and: [
|
|
300
|
+
{ isDeleted: false },
|
|
301
|
+
{ status: 'active' }
|
|
302
|
+
]
|
|
303
|
+
}
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### Multi-Tenant Filtering
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
{
|
|
310
|
+
and: [
|
|
311
|
+
{ tenantId: currentTenantId },
|
|
312
|
+
{ isActive: true }
|
|
313
|
+
]
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
## Operator Precedence
|
|
320
|
+
|
|
321
|
+
When combining operators, IGNIS follows standard SQL precedence:
|
|
322
|
+
|
|
323
|
+
1. **NOT** - Highest precedence
|
|
324
|
+
2. **AND** - Medium precedence
|
|
325
|
+
3. **OR** - Lowest precedence
|
|
326
|
+
|
|
327
|
+
Use explicit parentheses (via nested `and`/`or`) for clarity:
|
|
328
|
+
|
|
329
|
+
```typescript
|
|
330
|
+
// Clear precedence
|
|
331
|
+
{
|
|
332
|
+
and: [
|
|
333
|
+
{ status: 'active' },
|
|
334
|
+
{ or: [
|
|
335
|
+
{ role: 'admin' },
|
|
336
|
+
{ role: 'moderator' }
|
|
337
|
+
]}
|
|
338
|
+
]
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
## Type Safety
|
|
345
|
+
|
|
346
|
+
All filter operators are fully typed based on your model schema:
|
|
347
|
+
|
|
348
|
+
```typescript
|
|
349
|
+
interface User {
|
|
350
|
+
id: number;
|
|
351
|
+
name: string;
|
|
352
|
+
age: number;
|
|
353
|
+
email: string;
|
|
354
|
+
tags: string[];
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// ✅ Type-safe filters
|
|
358
|
+
await userRepo.find({
|
|
359
|
+
where: {
|
|
360
|
+
age: { gt: 18 }, // number operators
|
|
361
|
+
name: { like: '%john%' }, // string operators
|
|
362
|
+
tags: { contains: ['typescript'] } // array operators
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
// ❌ TypeScript error: wrong operator for type
|
|
367
|
+
await userRepo.find({
|
|
368
|
+
where: {
|
|
369
|
+
age: { like: '%18%' } // Error: 'like' not valid for numbers
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
## Performance Tips
|
|
377
|
+
|
|
378
|
+
1. **Index frequently filtered columns:**
|
|
379
|
+
```sql
|
|
380
|
+
CREATE INDEX idx_users_status ON users(status);
|
|
381
|
+
CREATE INDEX idx_posts_created_at ON posts(created_at DESC);
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
2. **Use `eq` instead of `like` when possible:**
|
|
385
|
+
```typescript
|
|
386
|
+
// ✅ Fast: Uses index
|
|
387
|
+
{ status: { eq: 'active' } }
|
|
388
|
+
|
|
389
|
+
// ❌ Slower: Full table scan
|
|
390
|
+
{ status: { like: 'active' } }
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
3. **Limit array contains operations:**
|
|
394
|
+
```typescript
|
|
395
|
+
// Better performance with smaller arrays
|
|
396
|
+
{ tags: { contains: ['typescript'] } } // ✅ Good
|
|
397
|
+
{ tags: { contains: ['tag1', 'tag2', /* ... 100 tags */] } } // ❌ Slow
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
4. **Use pagination for large result sets:**
|
|
401
|
+
```typescript
|
|
402
|
+
{
|
|
403
|
+
where: { isActive: true },
|
|
404
|
+
limit: 100,
|
|
405
|
+
offset: 0,
|
|
406
|
+
orderBy: { id: 'asc' }
|
|
407
|
+
}
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
## See Also
|
|
413
|
+
|
|
414
|
+
- **Detailed Guides:**
|
|
415
|
+
- [Comparison Operators](./comparison-operators.md)
|
|
416
|
+
- [Logical Operators](./logical-operators.md)
|
|
417
|
+
- [Pattern Matching](./pattern-matching.md)
|
|
418
|
+
- [JSON Filtering](./json-filtering.md)
|
|
419
|
+
- [Array Operators](./array-operators.md)
|
|
420
|
+
|
|
421
|
+
- **Related References:**
|
|
422
|
+
- [Repositories](../repositories/) - Using filters in repository queries
|
|
423
|
+
- [Models](../models.md) - Defining model schemas
|
|
424
|
+
|
|
425
|
+
- **Usage Guides:**
|
|
426
|
+
- [Application Usage](./application-usage.md) - Filters in the full stack
|
|
427
|
+
- [Use Case Gallery](./use-cases.md) - Real-world examples
|
|
428
|
+
- [Pro Tips & Edge Cases](./tips.md) - Advanced patterns
|
|
429
|
+
|
|
430
|
+
- **Quick Reference:**
|
|
431
|
+
- [Main Quick Reference](/references/quick-reference.md) - All IGNIS APIs
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Range Operators
|
|
3
|
+
description: Operators for matching values within or outside a range
|
|
4
|
+
difficulty: intermediate
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Range Operators
|
|
8
|
+
|
|
9
|
+
Operators for matching values within or outside a range.
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
## between
|
|
13
|
+
|
|
14
|
+
Find values within a range (inclusive):
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
// Numeric range
|
|
18
|
+
{ where: { price: { between: [100, 500] } } }
|
|
19
|
+
// SQL: WHERE "price" BETWEEN 100 AND 500
|
|
20
|
+
|
|
21
|
+
// Date range
|
|
22
|
+
{
|
|
23
|
+
where: {
|
|
24
|
+
createdAt: {
|
|
25
|
+
between: [new Date('2024-01-01'), new Date('2024-12-31')]
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// SQL: WHERE "created_at" BETWEEN '2024-01-01' AND '2024-12-31'
|
|
30
|
+
|
|
31
|
+
// String range (lexicographic)
|
|
32
|
+
{ where: { lastName: { between: ['A', 'M'] } } }
|
|
33
|
+
// SQL: WHERE "last_name" BETWEEN 'A' AND 'M'
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
> [!WARNING]
|
|
37
|
+
> The value MUST be an array with exactly 2 elements `[min, max]`. Invalid values throw an error.
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
## notBetween
|
|
41
|
+
|
|
42
|
+
Find values outside a range:
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
{ where: { score: { notBetween: [40, 60] } } }
|
|
46
|
+
// SQL: WHERE NOT ("score" BETWEEN 40 AND 60)
|
|
47
|
+
// Matches: scores < 40 OR scores > 60
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
## Alternative: Using gte/lte
|
|
52
|
+
|
|
53
|
+
You can also express ranges using comparison operators:
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
// Equivalent to between: [100, 500]
|
|
57
|
+
{ where: { price: { gte: 100, lte: 500 } } }
|
|
58
|
+
// SQL: WHERE "price" >= 100 AND "price" <= 500
|
|
59
|
+
|
|
60
|
+
// Exclusive range (not including boundaries)
|
|
61
|
+
{ where: { price: { gt: 100, lt: 500 } } }
|
|
62
|
+
// SQL: WHERE "price" > 100 AND "price" < 500
|
|
63
|
+
```
|