@docyrus/docyrus 0.0.16 → 0.0.17
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 +25 -2
- package/main.js +867 -505
- package/main.js.map +4 -4
- package/package.json +2 -1
- package/resources/pi-agent/prompts/agent-system.md +25 -0
- package/resources/pi-agent/prompts/coder-append-system.md +19 -0
- package/resources/pi-agent/skills/docyrus-ai/SKILL.md +28 -0
- package/resources/pi-agent/skills/docyrus-api-dev/SKILL.md +161 -0
- package/resources/pi-agent/skills/docyrus-api-dev/references/api-client.md +349 -0
- package/resources/pi-agent/skills/docyrus-api-dev/references/authentication.md +238 -0
- package/resources/pi-agent/skills/docyrus-api-dev/references/data-source-query-guide.md +2059 -0
- package/resources/pi-agent/skills/docyrus-api-dev/references/formula-design-guide-llm.md +320 -0
- package/resources/pi-agent/skills/docyrus-api-dev/references/query-and-formulas.md +592 -0
- package/resources/pi-agent/skills/docyrus-api-doctor/SKILL.md +70 -0
- package/resources/pi-agent/skills/docyrus-api-doctor/references/checklist-details.md +588 -0
- package/resources/pi-agent/skills/docyrus-app-dev/SKILL.md +159 -0
- package/resources/pi-agent/skills/docyrus-app-dev/references/api-client-and-auth.md +275 -0
- package/resources/pi-agent/skills/docyrus-app-dev/references/collections-and-patterns.md +352 -0
- package/resources/pi-agent/skills/docyrus-app-dev/references/data-source-query-guide.md +2059 -0
- package/resources/pi-agent/skills/docyrus-app-dev/references/formula-design-guide-llm.md +320 -0
- package/resources/pi-agent/skills/docyrus-app-dev/references/query-guide.md +525 -0
- package/resources/pi-agent/skills/docyrus-app-ui-design/SKILL.md +466 -0
- package/resources/pi-agent/skills/docyrus-app-ui-design/references/component-selection-guide.md +602 -0
- package/resources/pi-agent/skills/docyrus-app-ui-design/references/icon-usage-guide.md +463 -0
- package/resources/pi-agent/skills/docyrus-app-ui-design/references/preferred-components-catalog.md +242 -0
- package/resources/pi-agent/skills/docyrus-apps/SKILL.md +54 -0
- package/resources/pi-agent/skills/docyrus-architect/SKILL.md +174 -0
- package/resources/pi-agent/skills/docyrus-architect/references/custom-query-guide.md +410 -0
- package/resources/pi-agent/skills/docyrus-architect/references/data-source-query-guide.md +2059 -0
- package/resources/pi-agent/skills/docyrus-architect/references/formula-design-guide-llm.md +320 -0
- package/resources/pi-agent/skills/docyrus-architect/references/formula-reference.md +145 -0
- package/resources/pi-agent/skills/docyrus-auth/SKILL.md +100 -0
- package/resources/pi-agent/skills/docyrus-cli-app/SKILL.md +279 -0
- package/resources/pi-agent/skills/docyrus-cli-app/references/cli-manifest.md +532 -0
- package/resources/pi-agent/skills/docyrus-cli-app/references/list-query-examples.md +248 -0
- package/resources/pi-agent/skills/docyrus-curl/SKILL.md +32 -0
- package/resources/pi-agent/skills/docyrus-discover/SKILL.md +63 -0
- package/resources/pi-agent/skills/docyrus-ds/SKILL.md +95 -0
- package/resources/pi-agent/skills/docyrus-env/SKILL.md +21 -0
- package/resources/pi-agent/skills/docyrus-studio/SKILL.md +369 -0
- package/resources/pi-agent/skills/docyrus-tui/SKILL.md +15 -0
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
# Docyrus Data Source Query Guide
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
|
|
5
|
+
1. [Query Payload Overview](#query-payload-overview)
|
|
6
|
+
2. [Columns](#columns)
|
|
7
|
+
3. [Filters](#filters)
|
|
8
|
+
4. [Filter Operators](#filter-operators)
|
|
9
|
+
5. [Order By](#order-by)
|
|
10
|
+
6. [Pagination](#pagination)
|
|
11
|
+
7. [Calculations (Aggregations)](#calculations)
|
|
12
|
+
8. [Formulas](#formulas)
|
|
13
|
+
9. [Block Formulas](#block-formulas)
|
|
14
|
+
10. [Subquery Formulas](#subquery-formulas)
|
|
15
|
+
11. [Child Queries](#child-queries)
|
|
16
|
+
12. [Pivot](#pivot)
|
|
17
|
+
13. [Expand](#expand)
|
|
18
|
+
14. [Complete Examples](#complete-examples)
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Query Payload Overview
|
|
23
|
+
|
|
24
|
+
All data source reads use `ICollectionListParams` (client-side) which maps to `ZodSelectQueryPayload` (server-side).
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
collection.list({
|
|
28
|
+
columns: ['name', 'email', 'status'],
|
|
29
|
+
filters: { rules: [...], combinator: 'and' },
|
|
30
|
+
filterKeyword: 'search term',
|
|
31
|
+
orderBy: 'created_on desc',
|
|
32
|
+
limit: 50,
|
|
33
|
+
offset: 0,
|
|
34
|
+
fullCount: true,
|
|
35
|
+
calculations: [...],
|
|
36
|
+
formulas: { ... },
|
|
37
|
+
childQueries: { ... },
|
|
38
|
+
pivot: { ... },
|
|
39
|
+
expand: ['relation_field'],
|
|
40
|
+
})
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Critical rule**: Always send `columns` parameter. If omitted, only `id` is returned.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Columns
|
|
48
|
+
|
|
49
|
+
**Type**: `Array<string>` (client) or comma-separated `string` (server)
|
|
50
|
+
|
|
51
|
+
### Basic
|
|
52
|
+
```typescript
|
|
53
|
+
columns: ['task_name', 'created_on', 'record_owner']
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Aliasing with `:`
|
|
57
|
+
```typescript
|
|
58
|
+
columns: ['ra:related_account']
|
|
59
|
+
// Result: { ra: { id: "uuid", name: "account name" } }
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Relation Expansion with `()`
|
|
63
|
+
```typescript
|
|
64
|
+
columns: ['task_name', 'related_account(name:account_name, phone:account_phone)']
|
|
65
|
+
// Result: { task_name: "...", related_account: { name: "...", phone: "..." } }
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Spread with `...`
|
|
69
|
+
Flattens relation fields to root:
|
|
70
|
+
```typescript
|
|
71
|
+
columns: ['task_name', '...related_account(account_name, phone:account_phone)']
|
|
72
|
+
// Result: { task_name: "...", account_name: "...", phone: "..." }
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Functions with `@`
|
|
76
|
+
```typescript
|
|
77
|
+
columns: ['...related_account(an:account_name@upper, ap:account_phone)']
|
|
78
|
+
// Result: { an: "ACCOUNT NAME", ap: "05556668899" }
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Date Grouping Formulas with `@`
|
|
82
|
+
For aggregation queries — groups records by time intervals:
|
|
83
|
+
|
|
84
|
+
| Formula | Description |
|
|
85
|
+
|---------|-------------|
|
|
86
|
+
| `hours_of_today@field` | Groups by hour for today |
|
|
87
|
+
| `days_of_week@field` | Groups by day for current week |
|
|
88
|
+
| `days_of_month@field` | Groups by day for current month |
|
|
89
|
+
| `weeks_of_month@field` | Groups by week for current month |
|
|
90
|
+
| `months_of_year@field` | Groups by month (YYYY-MM) |
|
|
91
|
+
| `quarters_of_year@field` | Groups by quarter (YYYY-Q) |
|
|
92
|
+
|
|
93
|
+
### to_char Formatting
|
|
94
|
+
```typescript
|
|
95
|
+
columns: ['day:to_char[DD/MM/YYYY]@created_on']
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Filters
|
|
101
|
+
|
|
102
|
+
Recursive group structure with AND/OR combinators.
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
interface ICollectionFilterGroup {
|
|
106
|
+
rules: Array<ICollectionFilterRule | ICollectionFilterGroup>
|
|
107
|
+
combinator?: 'and' | 'or' // default: 'and'
|
|
108
|
+
not?: boolean // negate entire group
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
interface ICollectionFilterRule {
|
|
112
|
+
field?: string
|
|
113
|
+
operator: string
|
|
114
|
+
value?: unknown
|
|
115
|
+
filterType?: string | null // NUMERIC, ALPHA, BOOL, DATE, DATETIME, etc.
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Basic AND
|
|
120
|
+
```typescript
|
|
121
|
+
filters: {
|
|
122
|
+
combinator: 'and',
|
|
123
|
+
rules: [
|
|
124
|
+
{ field: 'task_status', operator: '=', value: 1 },
|
|
125
|
+
{ field: 'priority', operator: '>=', value: 3 },
|
|
126
|
+
],
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Nested AND + OR
|
|
131
|
+
```typescript
|
|
132
|
+
filters: {
|
|
133
|
+
combinator: 'and',
|
|
134
|
+
rules: [
|
|
135
|
+
{ field: 'created_on', operator: 'between', value: ['2025-10-01', '2025-11-01'] },
|
|
136
|
+
{
|
|
137
|
+
combinator: 'or',
|
|
138
|
+
rules: [
|
|
139
|
+
{ field: 'email', operator: 'empty' },
|
|
140
|
+
{ field: 'phone', operator: 'not empty' },
|
|
141
|
+
],
|
|
142
|
+
},
|
|
143
|
+
],
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Filtering by Related Record's Field
|
|
148
|
+
Use `rel_{{relation_field}}/{{field}}` syntax:
|
|
149
|
+
```typescript
|
|
150
|
+
{ field: 'rel_client/account_status', operator: '=', value: 2 }
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Negated Group
|
|
154
|
+
```typescript
|
|
155
|
+
{ combinator: 'and', not: true, rules: [{ field: 'status', operator: '=', value: 'archived' }] }
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Filter Operators
|
|
161
|
+
|
|
162
|
+
### Comparison
|
|
163
|
+
`=`, `!=`, `<>`, `>`, `<`, `>=`, `<=`, `between`
|
|
164
|
+
|
|
165
|
+
### Text
|
|
166
|
+
`like`, `not like`, `starts with`, `ends with`
|
|
167
|
+
|
|
168
|
+
### Collection
|
|
169
|
+
`in`, `not in`, `exists`, `contains any`, `contains all`, `not contains`
|
|
170
|
+
|
|
171
|
+
### Null/Empty
|
|
172
|
+
`is`, `is not`, `empty`, `not empty`, `null`, `not null`
|
|
173
|
+
|
|
174
|
+
### Boolean
|
|
175
|
+
`true`, `false`
|
|
176
|
+
|
|
177
|
+
### User-Related
|
|
178
|
+
`active_user`, `not_active_user`, `in_active_user_scope`, `in_role`, `not_in_role`, `in_team`, `in_active_user_team`, `in_unit`
|
|
179
|
+
|
|
180
|
+
### Date Shortcuts (no value needed)
|
|
181
|
+
`today`, `tomorrow`, `yesterday`, `last_7_days`, `last_15_days`, `last_30_days`, `last_60_days`, `last_90_days`, `last_120_days`, `next_7_days`, `next_15_days`, `next_30_days`, `next_60_days`, `next_90_days`, `next_120_days`, `last_week`, `this_week`, `next_week`, `last_month`, `this_month`, `next_month`, `before_today`, `after_today`, `last_year`, `this_year`, `next_year`, `first_quarter`, `second_quarter`, `third_quarter`, `fourth_quarter`, `last_3_months`, `last_6_months`
|
|
182
|
+
|
|
183
|
+
### Dynamic Date (value = number)
|
|
184
|
+
`x_days_ago`, `x_days_later`, `before_last_x_days`, `in_last_x_days`, `after_last_x_days`, `in_next_x_days`
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Order By
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
// String
|
|
192
|
+
orderBy: 'created_on DESC'
|
|
193
|
+
|
|
194
|
+
// Object
|
|
195
|
+
orderBy: { field: 'created_on', direction: 'desc' }
|
|
196
|
+
|
|
197
|
+
// Multi-column
|
|
198
|
+
orderBy: [
|
|
199
|
+
{ field: 'status', direction: 'asc' },
|
|
200
|
+
{ field: 'created_on', direction: 'desc' },
|
|
201
|
+
]
|
|
202
|
+
|
|
203
|
+
// By related field
|
|
204
|
+
orderBy: 'relation_field_slug(field_name DESC), id ASC'
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Pagination
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
{
|
|
213
|
+
limit: 25, // default: 100
|
|
214
|
+
offset: 50, // default: 0
|
|
215
|
+
fullCount: true, // returns total matching count
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Calculations
|
|
222
|
+
|
|
223
|
+
Aggregate functions with grouping. Selected `columns` become GROUP BY fields.
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
interface ICollectionCalculation {
|
|
227
|
+
func: 'count' | 'sum' | 'avg' | 'min' | 'max' | 'jsonb_agg' | 'json_agg' | 'array_agg'
|
|
228
|
+
field: string // use 'id' for counting records
|
|
229
|
+
name?: string // alias for result column
|
|
230
|
+
isDistinct?: boolean
|
|
231
|
+
minValue?: number // aggregate values greater than this
|
|
232
|
+
maxValue?: number // aggregate values less than this
|
|
233
|
+
numberType?: 'bigint' | 'int' | 'decimal'
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Count per Group
|
|
238
|
+
```typescript
|
|
239
|
+
{
|
|
240
|
+
columns: ['record_owner(name)'],
|
|
241
|
+
calculations: [{ field: 'id', func: 'count', name: 'task_count' }],
|
|
242
|
+
filters: { rules: [{ field: 'task_status', operator: '=', value: 1 }] },
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Multiple Aggregations
|
|
247
|
+
```typescript
|
|
248
|
+
{
|
|
249
|
+
columns: ['category'],
|
|
250
|
+
calculations: [
|
|
251
|
+
{ field: 'id', func: 'count', name: 'total' },
|
|
252
|
+
{ field: 'amount', func: 'sum', name: 'totalAmount' },
|
|
253
|
+
{ field: 'amount', func: 'avg', name: 'avgAmount' },
|
|
254
|
+
],
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Formulas
|
|
261
|
+
|
|
262
|
+
Virtual computed columns. Key = column alias, must appear in `columns`.
|
|
263
|
+
|
|
264
|
+
### Simple Formula
|
|
265
|
+
```typescript
|
|
266
|
+
formulas: {
|
|
267
|
+
formatted_date: { func: 'to_char', args: ['{created_on}', 'DD/MM/YYYY'] },
|
|
268
|
+
full_name: { func: 'concat', args: ['{first_name}', ' ', '{last_name}'] },
|
|
269
|
+
upper_name: { func: 'upper', args: ['{name}'] },
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
Column refs use `{column_name}` syntax.
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## Block Formulas
|
|
277
|
+
|
|
278
|
+
AST-based formulas for complex expressions.
|
|
279
|
+
|
|
280
|
+
### Structure
|
|
281
|
+
```typescript
|
|
282
|
+
{ inputs: [rootBlock] } // exactly 1 root block
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Block Kinds
|
|
286
|
+
|
|
287
|
+
**literal** — Static value:
|
|
288
|
+
```json
|
|
289
|
+
{ "kind": "literal", "literal": 42 }
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
**column** — Column reference:
|
|
293
|
+
```json
|
|
294
|
+
{ "kind": "column", "name": "balance" }
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
**builtin** — SQL constant (`current_date`, `current_time`, `current_timestamp`, `now`):
|
|
298
|
+
```json
|
|
299
|
+
{ "kind": "builtin", "name": "current_date" }
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
**function** — Whitelisted SQL function:
|
|
303
|
+
```json
|
|
304
|
+
{ "kind": "function", "name": "round", "inputs": [{ "kind": "column", "name": "price" }, { "kind": "literal", "literal": 2 }] }
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
**math** — Arithmetic (`+`, `-`, `*`, `/`, `%`, min 2 operands):
|
|
308
|
+
```json
|
|
309
|
+
{ "kind": "math", "op": "*", "inputs": [{ "kind": "column", "name": "qty" }, { "kind": "column", "name": "price" }] }
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
**compare** — Comparison (`=`, `!=`, `>`, `<`, `>=`, `<=`, `like`, `ilike`, `in`, `not in`):
|
|
313
|
+
```json
|
|
314
|
+
{ "kind": "compare", "op": ">", "left": { "kind": "column", "name": "price" }, "right": { "kind": "literal", "literal": 100 } }
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
**boolean** — Logical (`and`, `or`, `not`):
|
|
318
|
+
```json
|
|
319
|
+
{ "kind": "boolean", "op": "and", "inputs": [compareBlock1, compareBlock2] }
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
**case** — CASE WHEN:
|
|
323
|
+
```json
|
|
324
|
+
{ "kind": "case", "cases": [{ "when": compareBlock, "then": literalBlock }], "else": literalBlock }
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
**aggregate** — `count`, `sum`, `avg`, `min`, `max`, etc.:
|
|
328
|
+
```json
|
|
329
|
+
{ "kind": "aggregate", "name": "count", "inputs": [] }
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
**extract** — Date part (`year`, `month`, `day`, `hour`, `minute`, `second`):
|
|
333
|
+
```json
|
|
334
|
+
{ "kind": "extract", "part": "month", "inputs": [columnBlock] }
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### Type Casting
|
|
338
|
+
Any block can include `"cast": "decimal"` → SQL: `(expr)::decimal`
|
|
339
|
+
|
|
340
|
+
### Timezone
|
|
341
|
+
Any block can include `"tz": "UTC"` → SQL: `expr at time zone 'UTC'`
|
|
342
|
+
|
|
343
|
+
### Example: CASE with Multiple Conditions
|
|
344
|
+
```typescript
|
|
345
|
+
formulas: {
|
|
346
|
+
deal_tier: {
|
|
347
|
+
inputs: [{
|
|
348
|
+
kind: 'case',
|
|
349
|
+
cases: [
|
|
350
|
+
{ when: { kind: 'compare', op: '>=', left: { kind: 'column', name: 'amount' }, right: { kind: 'literal', literal: 100000 } }, then: { kind: 'literal', literal: 'Enterprise' } },
|
|
351
|
+
{ when: { kind: 'compare', op: '>=', left: { kind: 'column', name: 'amount' }, right: { kind: 'literal', literal: 25000 } }, then: { kind: 'literal', literal: 'Mid-Market' } },
|
|
352
|
+
],
|
|
353
|
+
else: { kind: 'literal', literal: 'SMB' },
|
|
354
|
+
}],
|
|
355
|
+
},
|
|
356
|
+
}
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
---
|
|
360
|
+
|
|
361
|
+
## Subquery Formulas
|
|
362
|
+
|
|
363
|
+
Correlated subquery against a child data source.
|
|
364
|
+
|
|
365
|
+
```typescript
|
|
366
|
+
formulas: {
|
|
367
|
+
active_deals: {
|
|
368
|
+
from: 'crm_deal', // child table slug: appSlug_tableSlug
|
|
369
|
+
with: 'account', // child field referencing parent id
|
|
370
|
+
filters: { rules: [{ field: 'stage', operator: '!=', value: 'lost' }] },
|
|
371
|
+
inputs: [{ kind: 'aggregate', name: 'count', inputs: [] }],
|
|
372
|
+
},
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
Multi-field join:
|
|
377
|
+
```typescript
|
|
378
|
+
with: { child_field1: 'parent_field1', child_field2: 'parent_field2' }
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
## Child Queries
|
|
384
|
+
|
|
385
|
+
Fetch related records as nested JSON arrays per parent row.
|
|
386
|
+
|
|
387
|
+
```typescript
|
|
388
|
+
{
|
|
389
|
+
columns: ['id', 'name', 'recent_orders'],
|
|
390
|
+
childQueries: {
|
|
391
|
+
recent_orders: {
|
|
392
|
+
from: 'shop_order_item', // appSlug_slug format
|
|
393
|
+
using: 'product', // child field referencing parent id
|
|
394
|
+
columns: ['order_date', 'quantity', 'total_price'],
|
|
395
|
+
orderBy: 'order_date DESC',
|
|
396
|
+
limit: 5,
|
|
397
|
+
filters: { rules: [{ field: 'order_date', operator: 'last_30_days' }] },
|
|
398
|
+
},
|
|
399
|
+
},
|
|
400
|
+
}
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
**Rules:**
|
|
404
|
+
- Child query key must also appear in parent's `columns`.
|
|
405
|
+
- `from` uses `appSlug_slug` format.
|
|
406
|
+
- `using` is the field in **child** DS referencing parent's `id`.
|
|
407
|
+
|
|
408
|
+
---
|
|
409
|
+
|
|
410
|
+
## Pivot
|
|
411
|
+
|
|
412
|
+
Cross-tab grouping with matrix CTEs.
|
|
413
|
+
|
|
414
|
+
```typescript
|
|
415
|
+
{
|
|
416
|
+
columns: ['...order_status(status_name:name)'],
|
|
417
|
+
pivot: {
|
|
418
|
+
matrix: [
|
|
419
|
+
{
|
|
420
|
+
using: 'created_on',
|
|
421
|
+
columns: 'day:to_char[DD/MM/YYYY]@created_on',
|
|
422
|
+
dateRange: { interval: 'day', min: '2025-09-01T00:00:00Z', max: '2025-09-30T23:59:59Z' },
|
|
423
|
+
spread: true,
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
using: 'record_owner',
|
|
427
|
+
columns: 'userName:name',
|
|
428
|
+
spread: true,
|
|
429
|
+
filters: { rules: [{ field: 'primary_role', operator: '=', value: 'role-uuid' }] },
|
|
430
|
+
},
|
|
431
|
+
],
|
|
432
|
+
hideEmptyRows: false,
|
|
433
|
+
orderBy: 'day ASC',
|
|
434
|
+
},
|
|
435
|
+
calculations: [
|
|
436
|
+
{ field: 'id', func: 'count', name: 'total' },
|
|
437
|
+
{ field: 'amount', func: 'sum', name: 'totalSold' },
|
|
438
|
+
],
|
|
439
|
+
}
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
### Date Range Intervals
|
|
443
|
+
`day`, `week`, `month`, `year`, `hour`, `minute`, `second`
|
|
444
|
+
|
|
445
|
+
---
|
|
446
|
+
|
|
447
|
+
## Expand
|
|
448
|
+
|
|
449
|
+
Expand relation/user/enum fields to return full objects instead of IDs:
|
|
450
|
+
```typescript
|
|
451
|
+
expand: ['record_owner', 'related_account', 'status']
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
---
|
|
455
|
+
|
|
456
|
+
## Complete Examples
|
|
457
|
+
|
|
458
|
+
### Full-Featured Select
|
|
459
|
+
```typescript
|
|
460
|
+
collection.list({
|
|
461
|
+
columns: ['id', 'task_name', '...record_owner(owner_name:name)', '...related_account(account_name:name)'],
|
|
462
|
+
filters: {
|
|
463
|
+
combinator: 'and',
|
|
464
|
+
rules: [
|
|
465
|
+
{ field: 'task_status', operator: 'in', value: [1, 2] },
|
|
466
|
+
{ field: 'due_date', operator: 'in_next_x_days', value: 7 },
|
|
467
|
+
{ field: 'record_owner', operator: 'in_active_user_team' },
|
|
468
|
+
],
|
|
469
|
+
},
|
|
470
|
+
orderBy: 'due_date ASC',
|
|
471
|
+
limit: 50,
|
|
472
|
+
fullCount: true,
|
|
473
|
+
})
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
### Monthly Sales Report
|
|
477
|
+
```typescript
|
|
478
|
+
collection.list({
|
|
479
|
+
columns: ['months_of_year@created_on', '...category(cat:name)'],
|
|
480
|
+
calculations: [
|
|
481
|
+
{ field: 'id', func: 'count', name: 'order_count' },
|
|
482
|
+
{ field: 'total_amount', func: 'sum', name: 'revenue' },
|
|
483
|
+
{ field: 'total_amount', func: 'avg', name: 'avg_order' },
|
|
484
|
+
],
|
|
485
|
+
filters: { rules: [
|
|
486
|
+
{ field: 'created_on', operator: 'this_year' },
|
|
487
|
+
{ field: 'order_status', operator: '!=', value: 'cancelled' },
|
|
488
|
+
]},
|
|
489
|
+
orderBy: 'months_of_year@created_on ASC',
|
|
490
|
+
})
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
### Customers with Nested Orders
|
|
494
|
+
```typescript
|
|
495
|
+
collection.list({
|
|
496
|
+
columns: ['id', 'name', 'email', 'recent_orders'],
|
|
497
|
+
childQueries: {
|
|
498
|
+
recent_orders: {
|
|
499
|
+
from: 'shop_order',
|
|
500
|
+
using: 'customer',
|
|
501
|
+
columns: ['id', 'order_date', 'total_amount'],
|
|
502
|
+
orderBy: 'order_date DESC',
|
|
503
|
+
limit: 10,
|
|
504
|
+
filters: { rules: [{ field: 'order_date', operator: 'last_90_days' }] },
|
|
505
|
+
},
|
|
506
|
+
},
|
|
507
|
+
filters: { rules: [{ field: 'status', operator: '=', value: 'active' }] },
|
|
508
|
+
limit: 25,
|
|
509
|
+
})
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
### Allowed SQL Functions (Postgres)
|
|
513
|
+
|
|
514
|
+
**String**: `length`, `lower`, `upper`, `substr`, `replace`, `concat`, `trim`, `ltrim`, `rtrim`, `btrim`, `split_part`, `initcap`, `reverse`, `strpos`, `lpad`, `rpad`
|
|
515
|
+
|
|
516
|
+
**Number**: `abs`, `ceil`, `floor`, `round`, `sqrt`, `power`, `mod`, `greatest`, `least`, `trunc`
|
|
517
|
+
|
|
518
|
+
**Date/Time**: `now`, `age`, `date_part`, `date_trunc`, `extract`, `to_timestamp`, `to_char`, `to_date`, `make_date`
|
|
519
|
+
|
|
520
|
+
**Utility**: `coalesce`
|
|
521
|
+
|
|
522
|
+
**JSON**: `jsonb_array_length`, `jsonb_extract_path`, `jsonb_extract_path_text`, `jsonb_build_object`, `json_build_object`
|
|
523
|
+
|
|
524
|
+
### Allowed Cast Types
|
|
525
|
+
`int`, `bigint`, `real`, `float`, `numeric`, `decimal`, `money`, `timestamp`, `timestamptz`, `date`, `time`, `interval`, `bool`, `boolean`, `uuid`, `text` (and array variants)
|