@uniqu/core 0.0.4 → 0.0.6
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/dist/index.cjs +5 -3
- package/dist/index.d.ts +37 -10
- package/dist/index.mjs +5 -3
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -8,6 +8,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
8
8
|
* - Bare primitive values are normalized to `comparison(field, '$eq', value)`.
|
|
9
9
|
* - Multi-field ComparisonNodes are combined via `visitor.and(...)`.
|
|
10
10
|
*/ function walkFilter(expr, visitor) {
|
|
11
|
+
if (!expr) return void 0;
|
|
11
12
|
if ("$and" in expr && expr.$and !== void 0) {
|
|
12
13
|
const children = expr.$and.map((child) => walkFilter(child, visitor));
|
|
13
14
|
return visitor.and(children);
|
|
@@ -54,14 +55,15 @@ function isPrimitive(x) {
|
|
|
54
55
|
}
|
|
55
56
|
set.add(op);
|
|
56
57
|
}
|
|
57
|
-
|
|
58
|
+
const visitor = {
|
|
58
59
|
comparison(field, op) {
|
|
59
60
|
capture(field, op);
|
|
60
61
|
},
|
|
61
62
|
and() {},
|
|
62
63
|
or() {},
|
|
63
64
|
not() {}
|
|
64
|
-
}
|
|
65
|
+
};
|
|
66
|
+
if (filter) walkFilter(filter, visitor);
|
|
65
67
|
if (controls?.$select) if (Array.isArray(controls.$select)) for (const field of controls.$select) capture(field, "$select");
|
|
66
68
|
else for (const field of Object.keys(controls.$select)) capture(field, "$select");
|
|
67
69
|
if (controls?.$sort) for (const field of Object.keys(controls.$sort)) capture(field, "$order");
|
|
@@ -80,7 +82,7 @@ function isPrimitive(x) {
|
|
|
80
82
|
* Return insights for a query — uses pre-computed insights when present,
|
|
81
83
|
* computes lazily otherwise.
|
|
82
84
|
*/ function getInsights(query) {
|
|
83
|
-
return query.insights ?? computeInsights(query.filter, query.controls);
|
|
85
|
+
return query.insights ?? computeInsights(query.filter ?? {}, query.controls);
|
|
84
86
|
}
|
|
85
87
|
|
|
86
88
|
//#endregion
|
package/dist/index.d.ts
CHANGED
|
@@ -66,14 +66,14 @@ type LogicalNode<T = Record<string, unknown>> = {
|
|
|
66
66
|
$or?: never;
|
|
67
67
|
};
|
|
68
68
|
/** Query controls (pagination, projection, sorting). Generic `T` constrains field names in `$select` and `$sort`. */
|
|
69
|
-
interface UniqueryControls<T = Record<string, unknown>> {
|
|
69
|
+
interface UniqueryControls<T = Record<string, unknown>, Nav extends Record<string, unknown> = Record<string, unknown>> {
|
|
70
70
|
$sort?: Partial<Record<keyof T & string, 1 | -1>>;
|
|
71
71
|
$skip?: number;
|
|
72
72
|
$limit?: number;
|
|
73
73
|
$count?: boolean;
|
|
74
74
|
$select?: (keyof T & string)[] | Partial<Record<keyof T & string, 0 | 1>>;
|
|
75
75
|
/** Relations to populate alongside the query. */
|
|
76
|
-
$with?:
|
|
76
|
+
$with?: TypedWithRelation<Nav>[];
|
|
77
77
|
/** Pass-through for unknown $-prefixed keywords. */
|
|
78
78
|
[key: `$${string}`]: unknown;
|
|
79
79
|
}
|
|
@@ -82,17 +82,44 @@ interface UniqueryControls<T = Record<string, unknown>> {
|
|
|
82
82
|
* When `name` is present this is a nested relation (sub-query inside `$with`).
|
|
83
83
|
* When absent it is the root query.
|
|
84
84
|
*/
|
|
85
|
-
interface Uniquery<T = Record<string, unknown>> {
|
|
85
|
+
interface Uniquery<T = Record<string, unknown>, Nav extends Record<string, unknown> = Record<string, unknown>> {
|
|
86
86
|
/** Relation name. Present only for nested `$with` sub-queries. */
|
|
87
87
|
name?: string;
|
|
88
|
-
filter
|
|
89
|
-
controls
|
|
88
|
+
filter?: FilterExpr<T>;
|
|
89
|
+
controls?: UniqueryControls<T, Nav>;
|
|
90
90
|
/** Pre-computed insights. */
|
|
91
91
|
insights?: UniqueryInsights;
|
|
92
92
|
}
|
|
93
|
-
/**
|
|
94
|
-
type
|
|
93
|
+
/** Unwrap array types to get the element type for nav props. */
|
|
94
|
+
type NavTarget<T> = T extends Array<infer U> ? U : T;
|
|
95
|
+
/**
|
|
96
|
+
* A typed $with relation entry.
|
|
97
|
+
* When Nav is typed (from __navProps), name is constrained to known nav prop keys.
|
|
98
|
+
* Each entry gets its own filter/controls typed to the target entity.
|
|
99
|
+
* Falls back to untyped WithRelation when Nav has no known keys.
|
|
100
|
+
*/
|
|
101
|
+
type TypedWithRelation<Nav extends Record<string, unknown>> = [
|
|
102
|
+
keyof Nav & string
|
|
103
|
+
] extends [never] ? WithRelation : {
|
|
104
|
+
[K in keyof Nav & string]: {
|
|
105
|
+
name: K;
|
|
106
|
+
filter?: FilterExpr<NavTarget<Nav[K]> extends {
|
|
107
|
+
__ownProps: infer F;
|
|
108
|
+
} ? F : Record<string, unknown>>;
|
|
109
|
+
controls?: UniqueryControls<NavTarget<Nav[K]> extends {
|
|
110
|
+
__ownProps: infer F;
|
|
111
|
+
} ? F : Record<string, unknown>, NavTarget<Nav[K]> extends {
|
|
112
|
+
__navProps: infer N extends Record<string, unknown>;
|
|
113
|
+
} ? N : Record<string, unknown>>;
|
|
114
|
+
insights?: UniqueryInsights;
|
|
115
|
+
};
|
|
116
|
+
}[keyof Nav & string];
|
|
117
|
+
/** Untyped $with relation — used when Nav generic is not provided. */
|
|
118
|
+
type WithRelation = {
|
|
95
119
|
name: string;
|
|
120
|
+
filter?: FilterExpr;
|
|
121
|
+
controls?: UniqueryControls;
|
|
122
|
+
insights?: UniqueryInsights;
|
|
96
123
|
};
|
|
97
124
|
/** Insight operator includes comparison ops plus control-derived ops. */
|
|
98
125
|
type InsightOp = ComparisonOp | '$select' | '$order' | '$with';
|
|
@@ -122,7 +149,7 @@ interface FilterVisitor<R> {
|
|
|
122
149
|
* - Bare primitive values are normalized to `comparison(field, '$eq', value)`.
|
|
123
150
|
* - Multi-field ComparisonNodes are combined via `visitor.and(...)`.
|
|
124
151
|
*/
|
|
125
|
-
declare function walkFilter<R>(expr: FilterExpr, visitor: FilterVisitor<R>): R;
|
|
152
|
+
declare function walkFilter<R>(expr: FilterExpr | undefined, visitor: FilterVisitor<R>): R | undefined;
|
|
126
153
|
declare function isPrimitive(x: unknown): x is Primitive;
|
|
127
154
|
|
|
128
155
|
/**
|
|
@@ -130,7 +157,7 @@ declare function isPrimitive(x: unknown): x is Primitive;
|
|
|
130
157
|
* This is the lazy counterpart to the eager insight capture done during
|
|
131
158
|
* URL parsing.
|
|
132
159
|
*/
|
|
133
|
-
declare function computeInsights(filter
|
|
160
|
+
declare function computeInsights(filter?: FilterExpr, controls?: UniqueryControls): UniqueryInsights;
|
|
134
161
|
/**
|
|
135
162
|
* Return insights for a query — uses pre-computed insights when present,
|
|
136
163
|
* computes lazily otherwise.
|
|
@@ -138,4 +165,4 @@ declare function computeInsights(filter: FilterExpr, controls?: UniqueryControls
|
|
|
138
165
|
declare function getInsights(query: Uniquery): UniqueryInsights;
|
|
139
166
|
|
|
140
167
|
export { computeInsights, getInsights, isPrimitive, walkFilter };
|
|
141
|
-
export type { ComparisonNode, ComparisonOp, FieldOps, FieldOpsFor, FieldValue, FilterExpr, FilterVisitor, InsightOp, LogicalNode, Primitive, Uniquery, UniqueryControls, UniqueryInsights, WithRelation };
|
|
168
|
+
export type { ComparisonNode, ComparisonOp, FieldOps, FieldOpsFor, FieldValue, FilterExpr, FilterVisitor, InsightOp, LogicalNode, NavTarget, Primitive, TypedWithRelation, Uniquery, UniqueryControls, UniqueryInsights, WithRelation };
|
package/dist/index.mjs
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* - Bare primitive values are normalized to `comparison(field, '$eq', value)`.
|
|
7
7
|
* - Multi-field ComparisonNodes are combined via `visitor.and(...)`.
|
|
8
8
|
*/ function walkFilter(expr, visitor) {
|
|
9
|
+
if (!expr) return void 0;
|
|
9
10
|
if ("$and" in expr && expr.$and !== void 0) {
|
|
10
11
|
const children = expr.$and.map((child) => walkFilter(child, visitor));
|
|
11
12
|
return visitor.and(children);
|
|
@@ -52,14 +53,15 @@ function isPrimitive(x) {
|
|
|
52
53
|
}
|
|
53
54
|
set.add(op);
|
|
54
55
|
}
|
|
55
|
-
|
|
56
|
+
const visitor = {
|
|
56
57
|
comparison(field, op) {
|
|
57
58
|
capture(field, op);
|
|
58
59
|
},
|
|
59
60
|
and() {},
|
|
60
61
|
or() {},
|
|
61
62
|
not() {}
|
|
62
|
-
}
|
|
63
|
+
};
|
|
64
|
+
if (filter) walkFilter(filter, visitor);
|
|
63
65
|
if (controls?.$select) if (Array.isArray(controls.$select)) for (const field of controls.$select) capture(field, "$select");
|
|
64
66
|
else for (const field of Object.keys(controls.$select)) capture(field, "$select");
|
|
65
67
|
if (controls?.$sort) for (const field of Object.keys(controls.$sort)) capture(field, "$order");
|
|
@@ -78,7 +80,7 @@ function isPrimitive(x) {
|
|
|
78
80
|
* Return insights for a query — uses pre-computed insights when present,
|
|
79
81
|
* computes lazily otherwise.
|
|
80
82
|
*/ function getInsights(query) {
|
|
81
|
-
return query.insights ?? computeInsights(query.filter, query.controls);
|
|
83
|
+
return query.insights ?? computeInsights(query.filter ?? {}, query.controls);
|
|
82
84
|
}
|
|
83
85
|
|
|
84
86
|
//#endregion
|