@object-ui/data-objectstack 4.0.11 → 4.2.1
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/CHANGELOG.md +28 -0
- package/dist/index.cjs +36 -3
- package/dist/index.d.cts +1 -6
- package/dist/index.d.ts +1 -6
- package/dist/index.js +36 -3
- package/package.json +3 -3
- package/src/index.ts +80 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# @object-ui/data-objectstack
|
|
2
2
|
|
|
3
|
+
## 4.2.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- @object-ui/types@4.2.1
|
|
8
|
+
- @object-ui/core@4.2.1
|
|
9
|
+
|
|
10
|
+
## 4.2.0
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- @object-ui/types@4.2.0
|
|
15
|
+
- @object-ui/core@4.2.0
|
|
16
|
+
|
|
17
|
+
## 4.1.0
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- @object-ui/types@4.1.0
|
|
22
|
+
- @object-ui/core@4.1.0
|
|
23
|
+
|
|
24
|
+
## 4.0.12
|
|
25
|
+
|
|
26
|
+
### Patch Changes
|
|
27
|
+
|
|
28
|
+
- @object-ui/types@4.0.12
|
|
29
|
+
- @object-ui/core@4.0.12
|
|
30
|
+
|
|
3
31
|
## 4.0.11
|
|
4
32
|
|
|
5
33
|
### Patch Changes
|
package/dist/index.cjs
CHANGED
|
@@ -881,6 +881,26 @@ function objectFilterEntryToAST(entry) {
|
|
|
881
881
|
if (!field || !op) return null;
|
|
882
882
|
return [String(field), op, entry.value];
|
|
883
883
|
}
|
|
884
|
+
function translateFilterToAST(filter) {
|
|
885
|
+
if (filter === void 0 || filter === null) return void 0;
|
|
886
|
+
if (Array.isArray(filter)) {
|
|
887
|
+
if (filter.length === 0) return void 0;
|
|
888
|
+
const first = filter[0];
|
|
889
|
+
const isObjectForm = filter.length > 0 && typeof first === "object" && first !== null && !Array.isArray(first) && first.field !== void 0;
|
|
890
|
+
if (isObjectForm) {
|
|
891
|
+
const tuples = filter.map((entry) => objectFilterEntryToAST(entry)).filter((t) => t !== null);
|
|
892
|
+
if (tuples.length === 0) return void 0;
|
|
893
|
+
if (tuples.length === 1) return tuples[0];
|
|
894
|
+
return ["and", ...tuples];
|
|
895
|
+
}
|
|
896
|
+
return filter;
|
|
897
|
+
}
|
|
898
|
+
if (typeof filter === "object") {
|
|
899
|
+
if (Object.keys(filter).length === 0) return void 0;
|
|
900
|
+
return filter;
|
|
901
|
+
}
|
|
902
|
+
return void 0;
|
|
903
|
+
}
|
|
884
904
|
var discoveryCache = /* @__PURE__ */ new Map();
|
|
885
905
|
async function getSharedDiscovery(baseUrl, fetcher) {
|
|
886
906
|
const key = baseUrl || "<default>";
|
|
@@ -1387,9 +1407,9 @@ var ObjectStackAdapter = class {
|
|
|
1387
1407
|
}
|
|
1388
1408
|
}
|
|
1389
1409
|
if (params.$filter !== void 0 && params.$filter !== null) {
|
|
1390
|
-
const
|
|
1391
|
-
if (
|
|
1392
|
-
queryParams.set("filter", JSON.stringify(
|
|
1410
|
+
const translated = translateFilterToAST(params.$filter);
|
|
1411
|
+
if (translated !== void 0) {
|
|
1412
|
+
queryParams.set("filter", JSON.stringify(translated));
|
|
1393
1413
|
}
|
|
1394
1414
|
}
|
|
1395
1415
|
const baseUrl = this.baseUrl.replace(/\/$/, "");
|
|
@@ -1802,6 +1822,19 @@ var ObjectStackAdapter = class {
|
|
|
1802
1822
|
*/
|
|
1803
1823
|
async aggregate(resource, params) {
|
|
1804
1824
|
await this.connect();
|
|
1825
|
+
const looksLikeSpecShape = params != null && (Array.isArray(params.groupBy) || Array.isArray(params.aggregations) || params.where !== void 0);
|
|
1826
|
+
if (looksLikeSpecShape) {
|
|
1827
|
+
const queryAst = {};
|
|
1828
|
+
if (Array.isArray(params.groupBy)) queryAst.groupBy = params.groupBy;
|
|
1829
|
+
if (Array.isArray(params.aggregations)) queryAst.aggregations = params.aggregations;
|
|
1830
|
+
if (params.where !== void 0) queryAst.where = params.where;
|
|
1831
|
+
if (typeof params.limit === "number") queryAst.limit = params.limit;
|
|
1832
|
+
const result = await this.client.data.query(resource, queryAst);
|
|
1833
|
+
if (Array.isArray(result)) return result;
|
|
1834
|
+
if (Array.isArray(result?.records)) return result.records;
|
|
1835
|
+
if (Array.isArray(result?.data)) return result.data;
|
|
1836
|
+
return [];
|
|
1837
|
+
}
|
|
1805
1838
|
try {
|
|
1806
1839
|
const measureName = params.function === "count" ? "count" : `${params.field}_${params.function}`;
|
|
1807
1840
|
const payload = {
|
package/dist/index.d.cts
CHANGED
|
@@ -968,12 +968,7 @@ declare class ObjectStackAdapter<T = unknown> implements DataSource<T> {
|
|
|
968
968
|
* Falls back to client-side aggregation via find() if the analytics endpoint
|
|
969
969
|
* is not available.
|
|
970
970
|
*/
|
|
971
|
-
aggregate(resource: string, params:
|
|
972
|
-
field: string;
|
|
973
|
-
function: string;
|
|
974
|
-
groupBy: string;
|
|
975
|
-
filter?: any;
|
|
976
|
-
}): Promise<any[]>;
|
|
971
|
+
aggregate(resource: string, params: any): Promise<any[]>;
|
|
977
972
|
/** Client-side aggregation fallback */
|
|
978
973
|
private aggregateClientSide;
|
|
979
974
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -968,12 +968,7 @@ declare class ObjectStackAdapter<T = unknown> implements DataSource<T> {
|
|
|
968
968
|
* Falls back to client-side aggregation via find() if the analytics endpoint
|
|
969
969
|
* is not available.
|
|
970
970
|
*/
|
|
971
|
-
aggregate(resource: string, params:
|
|
972
|
-
field: string;
|
|
973
|
-
function: string;
|
|
974
|
-
groupBy: string;
|
|
975
|
-
filter?: any;
|
|
976
|
-
}): Promise<any[]>;
|
|
971
|
+
aggregate(resource: string, params: any): Promise<any[]>;
|
|
977
972
|
/** Client-side aggregation fallback */
|
|
978
973
|
private aggregateClientSide;
|
|
979
974
|
/**
|
package/dist/index.js
CHANGED
|
@@ -838,6 +838,26 @@ function objectFilterEntryToAST(entry) {
|
|
|
838
838
|
if (!field || !op) return null;
|
|
839
839
|
return [String(field), op, entry.value];
|
|
840
840
|
}
|
|
841
|
+
function translateFilterToAST(filter) {
|
|
842
|
+
if (filter === void 0 || filter === null) return void 0;
|
|
843
|
+
if (Array.isArray(filter)) {
|
|
844
|
+
if (filter.length === 0) return void 0;
|
|
845
|
+
const first = filter[0];
|
|
846
|
+
const isObjectForm = filter.length > 0 && typeof first === "object" && first !== null && !Array.isArray(first) && first.field !== void 0;
|
|
847
|
+
if (isObjectForm) {
|
|
848
|
+
const tuples = filter.map((entry) => objectFilterEntryToAST(entry)).filter((t) => t !== null);
|
|
849
|
+
if (tuples.length === 0) return void 0;
|
|
850
|
+
if (tuples.length === 1) return tuples[0];
|
|
851
|
+
return ["and", ...tuples];
|
|
852
|
+
}
|
|
853
|
+
return filter;
|
|
854
|
+
}
|
|
855
|
+
if (typeof filter === "object") {
|
|
856
|
+
if (Object.keys(filter).length === 0) return void 0;
|
|
857
|
+
return filter;
|
|
858
|
+
}
|
|
859
|
+
return void 0;
|
|
860
|
+
}
|
|
841
861
|
var discoveryCache = /* @__PURE__ */ new Map();
|
|
842
862
|
async function getSharedDiscovery(baseUrl, fetcher) {
|
|
843
863
|
const key = baseUrl || "<default>";
|
|
@@ -1344,9 +1364,9 @@ var ObjectStackAdapter = class {
|
|
|
1344
1364
|
}
|
|
1345
1365
|
}
|
|
1346
1366
|
if (params.$filter !== void 0 && params.$filter !== null) {
|
|
1347
|
-
const
|
|
1348
|
-
if (
|
|
1349
|
-
queryParams.set("filter", JSON.stringify(
|
|
1367
|
+
const translated = translateFilterToAST(params.$filter);
|
|
1368
|
+
if (translated !== void 0) {
|
|
1369
|
+
queryParams.set("filter", JSON.stringify(translated));
|
|
1350
1370
|
}
|
|
1351
1371
|
}
|
|
1352
1372
|
const baseUrl = this.baseUrl.replace(/\/$/, "");
|
|
@@ -1759,6 +1779,19 @@ var ObjectStackAdapter = class {
|
|
|
1759
1779
|
*/
|
|
1760
1780
|
async aggregate(resource, params) {
|
|
1761
1781
|
await this.connect();
|
|
1782
|
+
const looksLikeSpecShape = params != null && (Array.isArray(params.groupBy) || Array.isArray(params.aggregations) || params.where !== void 0);
|
|
1783
|
+
if (looksLikeSpecShape) {
|
|
1784
|
+
const queryAst = {};
|
|
1785
|
+
if (Array.isArray(params.groupBy)) queryAst.groupBy = params.groupBy;
|
|
1786
|
+
if (Array.isArray(params.aggregations)) queryAst.aggregations = params.aggregations;
|
|
1787
|
+
if (params.where !== void 0) queryAst.where = params.where;
|
|
1788
|
+
if (typeof params.limit === "number") queryAst.limit = params.limit;
|
|
1789
|
+
const result = await this.client.data.query(resource, queryAst);
|
|
1790
|
+
if (Array.isArray(result)) return result;
|
|
1791
|
+
if (Array.isArray(result?.records)) return result.records;
|
|
1792
|
+
if (Array.isArray(result?.data)) return result.data;
|
|
1793
|
+
return [];
|
|
1794
|
+
}
|
|
1762
1795
|
try {
|
|
1763
1796
|
const measureName = params.function === "count" ? "count" : `${params.field}_${params.function}`;
|
|
1764
1797
|
const payload = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@object-ui/data-objectstack",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.2.1",
|
|
4
4
|
"description": "ObjectStack Data Adapter for Object UI",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@objectstack/client": "^4.0.5",
|
|
26
|
-
"@object-ui/core": "4.
|
|
27
|
-
"@object-ui/types": "4.
|
|
26
|
+
"@object-ui/core": "4.2.1",
|
|
27
|
+
"@object-ui/types": "4.2.1"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"tsup": "^8.5.1",
|
package/src/index.ts
CHANGED
|
@@ -78,6 +78,54 @@ function objectFilterEntryToAST(entry: any): [string, string, any] | null {
|
|
|
78
78
|
return [String(field), op, entry.value];
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Translate any of the filter shapes accepted by ObjectUI into the AST format
|
|
83
|
+
* understood by the ObjectStack server's `parseFilterAST()`.
|
|
84
|
+
*
|
|
85
|
+
* Accepted inputs:
|
|
86
|
+
* - `[{ field, operator, value }, ...]` — ViewFilterRule[] from view configs
|
|
87
|
+
* - `[field, op, value]` — single AST tuple (passed through)
|
|
88
|
+
* - `['and'|'or', ...children]` — logical AST node (passed through)
|
|
89
|
+
* - `[[...], [...]]` — legacy nested AST (passed through)
|
|
90
|
+
* - `{ field: value }` / `{ field: { $op: value } }` — MongoDB-style object
|
|
91
|
+
*
|
|
92
|
+
* Returns `undefined` when the input is empty/unrecognized so callers can
|
|
93
|
+
* skip emitting `?filter=` entirely.
|
|
94
|
+
*/
|
|
95
|
+
function translateFilterToAST(filter: unknown): unknown | undefined {
|
|
96
|
+
if (filter === undefined || filter === null) return undefined;
|
|
97
|
+
|
|
98
|
+
if (Array.isArray(filter)) {
|
|
99
|
+
if (filter.length === 0) return undefined;
|
|
100
|
+
|
|
101
|
+
// Object form: [{ field, operator, value }, ...]
|
|
102
|
+
const first = filter[0];
|
|
103
|
+
const isObjectForm = filter.length > 0
|
|
104
|
+
&& typeof first === 'object'
|
|
105
|
+
&& first !== null
|
|
106
|
+
&& !Array.isArray(first)
|
|
107
|
+
&& (first as any).field !== undefined;
|
|
108
|
+
if (isObjectForm) {
|
|
109
|
+
const tuples = (filter as any[])
|
|
110
|
+
.map(entry => objectFilterEntryToAST(entry))
|
|
111
|
+
.filter((t): t is [string, string, any] => t !== null);
|
|
112
|
+
if (tuples.length === 0) return undefined;
|
|
113
|
+
if (tuples.length === 1) return tuples[0];
|
|
114
|
+
return ['and', ...tuples];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Already AST — pass through.
|
|
118
|
+
return filter;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (typeof filter === 'object') {
|
|
122
|
+
if (Object.keys(filter as Record<string, unknown>).length === 0) return undefined;
|
|
123
|
+
return filter;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
|
|
81
129
|
// Module-level discovery cache. Multiple ObjectStackAdapter instances pointed
|
|
82
130
|
// at the same baseUrl (e.g. ConditionalAuthWrapper's throwaway adapter +
|
|
83
131
|
// AdapterProvider's main adapter) would otherwise each fire `/discovery`. By
|
|
@@ -844,13 +892,15 @@ export class ObjectStackAdapter<T = unknown> implements DataSource<T> {
|
|
|
844
892
|
}
|
|
845
893
|
}
|
|
846
894
|
|
|
847
|
-
// Filter —
|
|
895
|
+
// Filter — translate ViewFilterRule[] (`[{field, operator, value}]`)
|
|
896
|
+
// and other shapes into AST tuples the server understands. Without this,
|
|
897
|
+
// server-driven views (e.g. `at_risk_accounts`, `hot_leads`) ship raw
|
|
898
|
+
// `[{field,operator,value}]` arrays which `parseFilterAST` silently
|
|
899
|
+
// discards, returning every record instead of the filtered subset.
|
|
848
900
|
if (params.$filter !== undefined && params.$filter !== null) {
|
|
849
|
-
const
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
if (!isEmpty) {
|
|
853
|
-
queryParams.set('filter', JSON.stringify(params.$filter));
|
|
901
|
+
const translated = translateFilterToAST(params.$filter);
|
|
902
|
+
if (translated !== undefined) {
|
|
903
|
+
queryParams.set('filter', JSON.stringify(translated));
|
|
854
904
|
}
|
|
855
905
|
}
|
|
856
906
|
|
|
@@ -1384,9 +1434,32 @@ export class ObjectStackAdapter<T = unknown> implements DataSource<T> {
|
|
|
1384
1434
|
* Falls back to client-side aggregation via find() if the analytics endpoint
|
|
1385
1435
|
* is not available.
|
|
1386
1436
|
*/
|
|
1387
|
-
async aggregate(resource: string, params:
|
|
1437
|
+
async aggregate(resource: string, params: any): Promise<any[]> {
|
|
1388
1438
|
await this.connect();
|
|
1389
1439
|
|
|
1440
|
+
// Spec-shape aggregation: `{ groupBy: GroupByNode[], aggregations: AggregationNode[], where?, limit? }`
|
|
1441
|
+
// per spec/data/query.zod.ts. Sent directly to the server's POST
|
|
1442
|
+
// /data/:object/query endpoint, which routes through engine.aggregate
|
|
1443
|
+
// and returns bucketed rows with the requested aliases.
|
|
1444
|
+
const looksLikeSpecShape =
|
|
1445
|
+
params != null &&
|
|
1446
|
+
(Array.isArray((params as any).groupBy) ||
|
|
1447
|
+
Array.isArray((params as any).aggregations) ||
|
|
1448
|
+
(params as any).where !== undefined);
|
|
1449
|
+
if (looksLikeSpecShape) {
|
|
1450
|
+
const queryAst: Record<string, unknown> = {};
|
|
1451
|
+
if (Array.isArray(params.groupBy)) queryAst.groupBy = params.groupBy;
|
|
1452
|
+
if (Array.isArray(params.aggregations)) queryAst.aggregations = params.aggregations;
|
|
1453
|
+
if (params.where !== undefined) queryAst.where = params.where;
|
|
1454
|
+
if (typeof params.limit === 'number') queryAst.limit = params.limit;
|
|
1455
|
+
const result: any = await this.client.data.query(resource, queryAst as any);
|
|
1456
|
+
// client.data.query returns { object, records, total, hasMore }
|
|
1457
|
+
if (Array.isArray(result)) return result;
|
|
1458
|
+
if (Array.isArray(result?.records)) return result.records;
|
|
1459
|
+
if (Array.isArray(result?.data)) return result.data;
|
|
1460
|
+
return [];
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1390
1463
|
try {
|
|
1391
1464
|
// Build measure name in the format expected by the backend analytics
|
|
1392
1465
|
// service (memory-analytics / cube). For 'count' the measure key is
|