Skip to content

Commit e00c52f

Browse files
committed
2 parents 1e8014c + dbcfdba commit e00c52f

8 files changed

Lines changed: 132 additions & 63 deletions

File tree

content/docs/references/api/contract.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ const result = ApiError.parse(data);
150150
| **cursor** | `Record<string, any>` | optional | Cursor for keyset pagination |
151151
| **joins** | `Object[]` | optional | Explicit Table Joins |
152152
| **aggregations** | `Object[]` | optional | Aggregation functions |
153-
| **groupBy** | `string[]` | optional | GROUP BY fields |
153+
| **groupBy** | `string \| Object[]` | optional | GROUP BY targets (strings or ``{field, dateGranularity?}`` objects for date bucketing) |
154154
| **having** | `[__schema2](./__schema2)` | optional | HAVING clause for aggregation filtering |
155155
| **windowFunctions** | `Object[]` | optional | Window functions with OVER clause |
156156
| **distinct** | `boolean` | optional | SELECT DISTINCT flag |

content/docs/references/automation/approval.mdx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const result = ApprovalAction.parse(data);
2929

3030
| Property | Type | Required | Description |
3131
| :--- | :--- | :--- | :--- |
32-
| **type** | `Enum<'field_update' \| 'email_alert' \| 'webhook' \| 'script' \| 'connector_action'>` || |
32+
| **type** | `Enum<'field_update' \| 'email_alert' \| 'webhook' \| 'script' \| 'connector_action' \| 'inbox_notify'>` || |
3333
| **name** | `string` || Action name |
3434
| **config** | `Record<string, any>` || Action configuration |
3535
| **connectorId** | `string` | optional | |
@@ -47,6 +47,7 @@ const result = ApprovalAction.parse(data);
4747
* `webhook`
4848
* `script`
4949
* `connector_action`
50+
* `inbox_notify`
5051

5152

5253
---
@@ -57,6 +58,8 @@ const result = ApprovalAction.parse(data);
5758

5859
* `user`
5960
* `role`
61+
* `team`
62+
* `department`
6063
* `manager`
6164
* `field`
6265
* `queue`

content/docs/references/data/driver.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ const result = DriverCapabilities.parse(data);
4343
| **isolationLevels** | `Enum<'read_uncommitted' \| 'read_committed' \| 'repeatable_read' \| 'serializable' \| 'snapshot'>[]` | optional | Supported isolation levels |
4444
| **queryFilters** | `boolean` || Supports WHERE clause filtering |
4545
| **queryAggregations** | `boolean` || Supports GROUP BY and aggregation functions |
46+
| **queryDateGranularity** | `Record<string, boolean>` | optional | Per-granularity native date bucketing (day/week/month/quarter/year). Missing keys fall back to in-memory bucketing. |
4647
| **querySorting** | `boolean` || Supports ORDER BY sorting |
4748
| **queryPagination** | `boolean` || Supports LIMIT/OFFSET pagination |
4849
| **queryWindowFunctions** | `boolean` || Supports window functions with OVER clause |

content/docs/references/data/query.mdx

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ Represents "Order By".
1616
## TypeScript Usage
1717

1818
```typescript
19-
import { AggregationFunction, AggregationNode, FieldNode, FullTextSearch, JoinNode, JoinStrategy, JoinType, Query, SortNode, WindowFunction, WindowFunctionNode, WindowSpec } from '@objectstack/spec/data';
20-
import type { AggregationFunction, AggregationNode, FieldNode, FullTextSearch, JoinNode, JoinStrategy, JoinType, Query, SortNode, WindowFunction, WindowFunctionNode, WindowSpec } from '@objectstack/spec/data';
19+
import { AggregationFunction, AggregationNode, DateGranularity, FieldNode, FullTextSearch, GroupByNode, JoinNode, JoinStrategy, JoinType, Query, SortNode, WindowFunction, WindowFunctionNode, WindowSpec } from '@objectstack/spec/data';
20+
import type { AggregationFunction, AggregationNode, DateGranularity, FieldNode, FullTextSearch, GroupByNode, JoinNode, JoinStrategy, JoinType, Query, SortNode, WindowFunction, WindowFunctionNode, WindowSpec } from '@objectstack/spec/data';
2121

2222
// Validate data
2323
const result = AggregationFunction.parse(data);
@@ -54,6 +54,19 @@ const result = AggregationFunction.parse(data);
5454
| **filter** | `[__schema0](./__schema0)` | optional | Filter/Condition to apply to the aggregation (FILTER WHERE clause) |
5555

5656

57+
---
58+
59+
## DateGranularity
60+
61+
### Allowed Values
62+
63+
* `day`
64+
* `week`
65+
* `month`
66+
* `quarter`
67+
* `year`
68+
69+
5770
---
5871

5972
## FieldNode
@@ -99,6 +112,33 @@ Type: `string`
99112
| **highlight** | `boolean` || Enable search result highlighting |
100113

101114

115+
---
116+
117+
## GroupByNode
118+
119+
### Union Options
120+
121+
This schema accepts one of the following structures:
122+
123+
#### Option 1
124+
125+
Type: `string`
126+
127+
---
128+
129+
#### Option 2
130+
131+
### Properties
132+
133+
| Property | Type | Required | Description |
134+
| :--- | :--- | :--- | :--- |
135+
| **field** | `string` || Field to group by |
136+
| **dateGranularity** | `Enum<'day' \| 'week' \| 'month' \| 'quarter' \| 'year'>` | optional | Bucket date values into uniform periods (day/week/month/quarter/year) |
137+
| **alias** | `string` | optional | Alias for the projected group value |
138+
139+
---
140+
141+
102142
---
103143

104144
## JoinNode
@@ -158,7 +198,7 @@ Type: `string`
158198
| **cursor** | `Record<string, any>` | optional | Cursor for keyset pagination |
159199
| **joins** | `Object[]` | optional | Explicit Table Joins |
160200
| **aggregations** | `Object[]` | optional | Aggregation functions |
161-
| **groupBy** | `string[]` | optional | GROUP BY fields |
201+
| **groupBy** | `string \| Object[]` | optional | GROUP BY targets (strings or ``{field, dateGranularity?}`` objects for date bucketing) |
162202
| **having** | `[__schema1](./__schema1)` | optional | HAVING clause for aggregation filtering |
163203
| **windowFunctions** | `Object[]` | optional | Window functions with OVER clause |
164204
| **distinct** | `boolean` | optional | SELECT DISTINCT flag |

content/docs/references/ui/report.mdx

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,33 @@ Report Type Enum
1414
## TypeScript Usage
1515

1616
```typescript
17-
import { Report, ReportChart, ReportColumn, ReportGrouping, ReportType } from '@objectstack/spec/ui';
18-
import type { Report, ReportChart, ReportColumn, ReportGrouping, ReportType } from '@objectstack/spec/ui';
17+
import { JoinedReportBlock, Report, ReportChart, ReportColumn, ReportGrouping, ReportType } from '@objectstack/spec/ui';
18+
import type { JoinedReportBlock, Report, ReportChart, ReportColumn, ReportGrouping, ReportType } from '@objectstack/spec/ui';
1919

2020
// Validate data
21-
const result = Report.parse(data);
21+
const result = JoinedReportBlock.parse(data);
2222
```
2323

24+
---
25+
26+
## JoinedReportBlock
27+
28+
### Properties
29+
30+
| Property | Type | Required | Description |
31+
| :--- | :--- | :--- | :--- |
32+
| **name** | `string` || Snake case identifier (lowercase with underscores only) |
33+
| **label** | `string` | optional | Display label (plain string; i18n keys are auto-generated by the framework) |
34+
| **description** | `string` | optional | Display label (plain string; i18n keys are auto-generated by the framework) |
35+
| **type** | `Enum<'tabular' \| 'summary' \| 'matrix'>` || |
36+
| **objectName** | `string` | optional | |
37+
| **columns** | `Object[]` || |
38+
| **groupingsDown** | `Object[]` | optional | |
39+
| **groupingsAcross** | `Object[]` | optional | |
40+
| **filter** | `[__schema0](./__schema0)` | optional | |
41+
| **chart** | `Object` | optional | |
42+
43+
2444
---
2545

2646
## Report
@@ -41,6 +61,7 @@ const result = Report.parse(data);
4161
| **chart** | `Object` | optional | Embedded chart configuration |
4262
| **aria** | `Object` | optional | ARIA accessibility attributes |
4363
| **performance** | `Object` | optional | Performance optimization settings |
64+
| **blocks** | `Object[]` | optional | Sub-reports for type=joined |
4465

4566

4667
---

packages/plugins/driver-memory/src/memory-driver.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -874,13 +874,18 @@ export class InMemoryDriver implements IDataDriver {
874874
const { groupBy, aggregations } = query;
875875
const groups: Map<string, any[]> = new Map();
876876

877+
const normalizeGroupBy = (node: any): { field: string; alias: string } => {
878+
if (typeof node === 'string') return { field: node, alias: node };
879+
return { field: node.field, alias: node.alias ?? node.field };
880+
};
881+
877882
// 1. Group records
878883
if (groupBy && groupBy.length > 0) {
879884
for (const record of records) {
880885
// Create a composite key from group values
881-
const keyParts = groupBy.map(g => {
882-
const fieldPath = typeof g === 'string' ? g : g.field;
883-
const val = getValueByPath(record, fieldPath);
886+
const keyParts = groupBy.map(node => {
887+
const { field } = normalizeGroupBy(node);
888+
const val = getValueByPath(record, field);
884889
return val === undefined || val === null ? 'null' : String(val);
885890
});
886891
const key = JSON.stringify(keyParts);
@@ -904,10 +909,9 @@ export class InMemoryDriver implements IDataDriver {
904909
if (groupBy && groupBy.length > 0) {
905910
if (groupRecords.length > 0) {
906911
const firstRecord = groupRecords[0];
907-
for (const g of groupBy) {
908-
const fieldPath = typeof g === 'string' ? g : (g.alias ?? g.field);
909-
const sourcePath = typeof g === 'string' ? g : g.field;
910-
this.setValueByPath(row, fieldPath, getValueByPath(firstRecord, sourcePath));
912+
for (const node of groupBy) {
913+
const { field, alias } = normalizeGroupBy(node);
914+
this.setValueByPath(row, alias, getValueByPath(firstRecord, field));
911915
}
912916
}
913917
}

packages/plugins/driver-mongodb/src/mongodb-driver.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ describe('MongoDBDriver', () => {
1313
const uri = mongod.getUri();
1414
driver = new MongoDBDriver({ url: uri, database: 'test_db' });
1515
await driver.connect();
16-
});
16+
}, 60_000);
1717

1818
afterAll(async () => {
19-
await driver.disconnect();
20-
await mongod.stop();
19+
if (driver) await driver.disconnect();
20+
if (mongod) await mongod.stop();
2121
});
2222

2323
beforeEach(async () => {

packages/plugins/driver-turso/src/turso-driver.ts

Lines changed: 45 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -169,51 +169,51 @@ export class TursoDriver extends SqlDriver {
169169

170170
public override get supports() {
171171
return {
172-
// Basic CRUD Operations
173-
create: true,
174-
read: true,
175-
update: true,
176-
delete: true,
177-
178-
// Bulk Operations
179-
bulkCreate: true,
180-
bulkUpdate: true,
181-
bulkDelete: true,
182-
183-
// Transaction & Connection Management
184-
transactions: true,
185-
savepoints: true,
186-
187-
// Query Operations
188-
queryFilters: true,
189-
queryAggregations: true,
190-
querySorting: true,
191-
queryPagination: true,
192-
queryWindowFunctions: true,
193-
querySubqueries: true,
194-
queryCTE: true,
195-
joins: true,
196-
queryDateGranularity: this.dateGranularityCapabilities,
197-
198-
// Advanced Features — Turso/libSQL native capabilities
199-
fullTextSearch: true, // FTS5
200-
jsonQuery: true, // JSON1 extension
201-
geospatialQuery: false,
202-
streaming: false,
203-
jsonFields: true,
204-
arrayFields: true,
205-
vectorSearch: false,
206-
207-
// Schema Management
208-
schemaSync: true,
209-
batchSchemaSync: true,
210-
migrations: false,
211-
indexes: true,
212-
213-
// Performance & Optimization
214-
connectionPooling: false, // Turso uses concurrency limits, not connection pools
215-
preparedStatements: true,
216-
queryCache: false,
172+
// Basic CRUD Operations
173+
create: true,
174+
read: true,
175+
update: true,
176+
delete: true,
177+
178+
// Bulk Operations
179+
bulkCreate: true,
180+
bulkUpdate: true,
181+
bulkDelete: true,
182+
183+
// Transaction & Connection Management
184+
transactions: true,
185+
savepoints: true,
186+
187+
// Query Operations
188+
queryFilters: true,
189+
queryAggregations: true,
190+
queryDateGranularity: this.dateGranularityCapabilities,
191+
querySorting: true,
192+
queryPagination: true,
193+
queryWindowFunctions: true,
194+
querySubqueries: true,
195+
queryCTE: true,
196+
joins: true,
197+
198+
// Advanced Features — Turso/libSQL native capabilities
199+
fullTextSearch: true, // FTS5
200+
jsonQuery: true, // JSON1 extension
201+
geospatialQuery: false,
202+
streaming: false,
203+
jsonFields: true,
204+
arrayFields: true,
205+
vectorSearch: false,
206+
207+
// Schema Management
208+
schemaSync: true,
209+
batchSchemaSync: true,
210+
migrations: false,
211+
indexes: true,
212+
213+
// Performance & Optimization
214+
connectionPooling: false, // Turso uses concurrency limits, not connection pools
215+
preparedStatements: true,
216+
queryCache: false,
217217
};
218218
}
219219

0 commit comments

Comments
 (0)