@ballistix.digital/odata-query-builder 0.7.0 → 0.8.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.
Files changed (31) hide show
  1. package/dist/module/query/domain/filter/node.model.d.ts +3 -2
  2. package/dist/module/query/domain/filter/node.model.js +3 -2
  3. package/dist/module/query/domain/filter/node.model.js.map +1 -1
  4. package/dist/module/query/service/emit/emit.facade.d.ts +2 -8
  5. package/dist/module/query/service/emit/emit.facade.js +3 -17
  6. package/dist/module/query/service/emit/emit.facade.js.map +1 -1
  7. package/dist/module/query/service/emit/emit.service.d.ts +38 -0
  8. package/dist/module/query/service/emit/emit.service.js +89 -0
  9. package/dist/module/query/service/emit/emit.service.js.map +1 -0
  10. package/dist/module/query/service/filter/filter.facade.d.ts +4 -17
  11. package/dist/module/query/service/filter/filter.facade.js +12 -61
  12. package/dist/module/query/service/filter/filter.facade.js.map +1 -1
  13. package/dist/module/query/service/filter/filter.service.d.ts +51 -0
  14. package/dist/module/query/service/filter/filter.service.js +88 -0
  15. package/dist/module/query/service/filter/filter.service.js.map +1 -0
  16. package/dist/module/query/service/filter/scope.service.d.ts +70 -0
  17. package/dist/module/query/service/filter/scope.service.js +260 -0
  18. package/dist/module/query/service/filter/scope.service.js.map +1 -0
  19. package/package.json +1 -1
  20. package/dist/module/query/util/emit/queryParts.util.d.ts +0 -16
  21. package/dist/module/query/util/emit/queryParts.util.js +0 -60
  22. package/dist/module/query/util/emit/queryParts.util.js.map +0 -1
  23. package/dist/module/query/util/filter/filterFunction.util.d.ts +0 -9
  24. package/dist/module/query/util/filter/filterFunction.util.js +0 -111
  25. package/dist/module/query/util/filter/filterFunction.util.js.map +0 -1
  26. package/dist/module/query/util/filter/literal.util.d.ts +0 -23
  27. package/dist/module/query/util/filter/literal.util.js +0 -81
  28. package/dist/module/query/util/filter/literal.util.js.map +0 -1
  29. package/dist/module/query/util/filter/scopeProxy.util.d.ts +0 -22
  30. package/dist/module/query/util/filter/scopeProxy.util.js +0 -93
  31. package/dist/module/query/util/filter/scopeProxy.util.js.map +0 -1
@@ -2,8 +2,9 @@
2
2
  * The two shapes every filter fragment is one of.
3
3
  *
4
4
  * Nothing in this file has a runtime body — the whole implementation is one
5
- * Proxy per scope, in `util/filter/scopeProxy.util.ts`. A construct the server
6
- * rejects is not typed here at all, so a 400 becomes a red squiggle.
5
+ * Proxy per scope, made by `ScopeService` in `service/filter/scope.service.ts`.
6
+ * A construct the server rejects is not typed here at all, so a 400 becomes a
7
+ * red squiggle.
7
8
  */
8
9
  /** An emitted fragment. `text` is the OData source of this node. */
9
10
  export interface Node {
@@ -3,8 +3,9 @@
3
3
  * The two shapes every filter fragment is one of.
4
4
  *
5
5
  * Nothing in this file has a runtime body — the whole implementation is one
6
- * Proxy per scope, in `util/filter/scopeProxy.util.ts`. A construct the server
7
- * rejects is not typed here at all, so a 400 becomes a red squiggle.
6
+ * Proxy per scope, made by `ScopeService` in `service/filter/scope.service.ts`.
7
+ * A construct the server rejects is not typed here at all, so a 400 becomes a
8
+ * red squiggle.
8
9
  */
9
10
  Object.defineProperty(exports, "__esModule", { value: true });
10
11
  //# sourceMappingURL=node.model.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"node.model.js","sourceRoot":"","sources":["../../../../../src/module/query/domain/filter/node.model.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG"}
1
+ {"version":3,"file":"node.model.js","sourceRoot":"","sources":["../../../../../src/module/query/domain/filter/node.model.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG"}
@@ -2,15 +2,9 @@
2
2
  * The only file that other code imports from the emit stage: a `QueryState`
3
3
  * in, the query text out.
4
4
  *
5
- * Both entry functions read the same ordered parts, so the string form and the
6
- * map form can never disagree about what the query says — they differ only in
7
- * the transport escaping each one leaves in place.
5
+ * Each function here is one call into a new `EmitService` and holds no logic
6
+ * of its own.
8
7
  */
9
8
  import type { QueryState } from '../../domain/queryState.model';
10
9
  export declare const emitQueryString: (queryState: QueryState) => string;
11
- /**
12
- * The same parts as a map, with the transport escaping undone so the caller's
13
- * own encoder does not double-encode. `$filter`, `$search` and `$expand` are
14
- * the only parts that ever carry that escaping.
15
- */
16
10
  export declare const emitQueryParams: (queryState: QueryState) => Record<string, string>;
@@ -1,23 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.emitQueryParams = exports.emitQueryString = void 0;
4
- const queryParts_util_1 = require("../../util/emit/queryParts.util");
5
- const escape_util_1 = require("../../util/filter/escape.util");
6
- const emitQueryString = (queryState) => (0, queryParts_util_1.toQueryParts)(queryState)
7
- .map(([key, value]) => `${key}=${value}`)
8
- .join('&');
4
+ const emit_service_1 = require("./emit.service");
5
+ const emitQueryString = (queryState) => new emit_service_1.EmitService(queryState).toQueryString();
9
6
  exports.emitQueryString = emitQueryString;
10
- /**
11
- * The same parts as a map, with the transport escaping undone so the caller's
12
- * own encoder does not double-encode. `$filter`, `$search` and `$expand` are
13
- * the only parts that ever carry that escaping.
14
- */
15
- const emitQueryParams = (queryState) => {
16
- const queryParams = {};
17
- for (const [key, value] of (0, queryParts_util_1.toQueryParts)(queryState)) {
18
- queryParams[key] = (0, escape_util_1.unescapeParamValue)(value);
19
- }
20
- return queryParams;
21
- };
7
+ const emitQueryParams = (queryState) => new emit_service_1.EmitService(queryState).toParams();
22
8
  exports.emitQueryParams = emitQueryParams;
23
9
  //# sourceMappingURL=emit.facade.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"emit.facade.js","sourceRoot":"","sources":["../../../../../src/module/query/service/emit/emit.facade.ts"],"names":[],"mappings":";;;AASA,qEAA+D;AAC/D,+DAAmE;AAE5D,MAAM,eAAe,GAAG,CAAC,UAAsB,EAAU,EAAE,CACjE,IAAA,8BAAY,EAAC,UAAU,CAAC;KACtB,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,KAAK,EAAE,CAAC;KACxC,IAAI,CAAC,GAAG,CAAC,CAAC;AAHA,QAAA,eAAe,mBAGf;AAEb;;;;GAIG;AACI,MAAM,eAAe,GAAG,CAC9B,UAAsB,EACG,EAAE;IAC3B,MAAM,WAAW,GAA2B,EAAE,CAAC;IAC/C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAA,8BAAY,EAAC,UAAU,CAAC,EAAE,CAAC;QACrD,WAAW,CAAC,GAAG,CAAC,GAAG,IAAA,gCAAkB,EAAC,KAAK,CAAC,CAAC;IAC9C,CAAC;IACD,OAAO,WAAW,CAAC;AACpB,CAAC,CAAC;AARW,QAAA,eAAe,mBAQ1B"}
1
+ {"version":3,"file":"emit.facade.js","sourceRoot":"","sources":["../../../../../src/module/query/service/emit/emit.facade.ts"],"names":[],"mappings":";;;AAQA,iDAA6C;AAEtC,MAAM,eAAe,GAAG,CAAC,UAAsB,EAAU,EAAE,CACjE,IAAI,0BAAW,CAAC,UAAU,CAAC,CAAC,aAAa,EAAE,CAAC;AADhC,QAAA,eAAe,mBACiB;AAEtC,MAAM,eAAe,GAAG,CAC9B,UAAsB,EACG,EAAE,CAAC,IAAI,0BAAW,CAAC,UAAU,CAAC,CAAC,QAAQ,EAAE,CAAC;AAFvD,QAAA,eAAe,mBAEwC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * `EmitService` prints one finished `QueryState`. Nothing here builds state
3
+ * and nothing here validates it: the chain has already decided what the query
4
+ * says, and this class only decides how it is printed. That split is why a
5
+ * golden-string test can be written against a hand-built state.
6
+ *
7
+ * `toQueryString()` and `toParams()` read the same ordered parts from
8
+ * `toQueryParts()`, so the string form and the map form can never disagree
9
+ * about what the query says. They differ only in the transport escaping each
10
+ * one leaves in place.
11
+ */
12
+ import type { QueryState } from '../../domain/queryState.model';
13
+ export declare class EmitService {
14
+ private readonly queryState;
15
+ constructor(queryState: QueryState);
16
+ toQueryString(): string;
17
+ /**
18
+ * The same parts as a map, with the transport escaping undone so the
19
+ * caller's own encoder does not double-encode. `$filter`, `$search` and
20
+ * `$expand` are the only parts that ever carry that escaping.
21
+ */
22
+ toParams(): Record<string, string>;
23
+ /**
24
+ * The root's options, as `$key=value` pairs in a stable order. The order is
25
+ * the one a reader scans for: what is selected, then how it is shaped, then
26
+ * how it is paged.
27
+ */
28
+ private toQueryParts;
29
+ /**
30
+ * The options of ONE expanded level, in the order the root prints them.
31
+ * They are joined with `;` inside the relation's parentheses.
32
+ */
33
+ private nestedParts;
34
+ /** `a($select=x),b` — a relation with no options of its own prints bare. */
35
+ private expandList;
36
+ /** Repeated `.filter()` calls AND together. */
37
+ private filterText;
38
+ }
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EmitService = void 0;
4
+ const escape_util_1 = require("../../util/filter/escape.util");
5
+ const predicate_util_1 = require("../../util/filter/predicate.util");
6
+ class EmitService {
7
+ queryState;
8
+ constructor(queryState) {
9
+ this.queryState = queryState;
10
+ }
11
+ toQueryString() {
12
+ return this.toQueryParts()
13
+ .map(([key, value]) => `${key}=${value}`)
14
+ .join('&');
15
+ }
16
+ /**
17
+ * The same parts as a map, with the transport escaping undone so the
18
+ * caller's own encoder does not double-encode. `$filter`, `$search` and
19
+ * `$expand` are the only parts that ever carry that escaping.
20
+ */
21
+ toParams() {
22
+ const queryParams = {};
23
+ for (const [key, value] of this.toQueryParts()) {
24
+ queryParams[key] = (0, escape_util_1.unescapeParamValue)(value);
25
+ }
26
+ return queryParams;
27
+ }
28
+ /**
29
+ * The root's options, as `$key=value` pairs in a stable order. The order is
30
+ * the one a reader scans for: what is selected, then how it is shaped, then
31
+ * how it is paged.
32
+ */
33
+ toQueryParts() {
34
+ const { queryState } = this;
35
+ const parts = [];
36
+ if (queryState.filters.length)
37
+ parts.push(['$filter', this.filterText(queryState)]);
38
+ if (queryState.search) {
39
+ parts.push(['$search', queryState.search.term]);
40
+ parts.push(['$searchColumns', queryState.search.columns.join(',')]);
41
+ }
42
+ if (queryState.select.length)
43
+ parts.push(['$select', queryState.select.join(',')]);
44
+ if (queryState.expand.length)
45
+ parts.push(['$expand', this.expandList(queryState)]);
46
+ if (queryState.orderBy.length)
47
+ parts.push(['$orderby', queryState.orderBy.join(',')]);
48
+ if (queryState.top !== undefined)
49
+ parts.push(['$top', String(queryState.top)]);
50
+ if (queryState.skip !== undefined)
51
+ parts.push(['$skip', String(queryState.skip)]);
52
+ if (queryState.count)
53
+ parts.push(['$count', 'true']);
54
+ return parts;
55
+ }
56
+ /**
57
+ * The options of ONE expanded level, in the order the root prints them.
58
+ * They are joined with `;` inside the relation's parentheses.
59
+ */
60
+ nestedParts(queryState) {
61
+ const parts = [];
62
+ if (queryState.filters.length)
63
+ parts.push(`$filter=${this.filterText(queryState)}`);
64
+ if (queryState.select.length)
65
+ parts.push(`$select=${queryState.select.join(',')}`);
66
+ if (queryState.expand.length)
67
+ parts.push(`$expand=${this.expandList(queryState)}`);
68
+ if (queryState.top !== undefined)
69
+ parts.push(`$top=${queryState.top}`);
70
+ if (queryState.skip !== undefined)
71
+ parts.push(`$skip=${queryState.skip}`);
72
+ return parts;
73
+ }
74
+ /** `a($select=x),b` — a relation with no options of its own prints bare. */
75
+ expandList(queryState) {
76
+ return queryState.expand
77
+ .map((entry) => {
78
+ const parts = this.nestedParts(entry.queryState);
79
+ return parts.length ? `${entry.name}(${parts.join(';')})` : entry.name;
80
+ })
81
+ .join(',');
82
+ }
83
+ /** Repeated `.filter()` calls AND together. */
84
+ filterText(queryState) {
85
+ return (0, predicate_util_1.combine)('and', queryState.filters).text;
86
+ }
87
+ }
88
+ exports.EmitService = EmitService;
89
+ //# sourceMappingURL=emit.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit.service.js","sourceRoot":"","sources":["../../../../../src/module/query/service/emit/emit.service.ts"],"names":[],"mappings":"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"}
@@ -3,14 +3,12 @@
3
3
  * a caller writes, and the four entry functions that run a caller's callback
4
4
  * against a fresh scope.
5
5
  *
6
- * A scope proxy never leaves this stage as itself. `buildFilterPredicate`
7
- * hands one to the callback and returns the predicate that comes back;
8
- * `pickSearchColumns`, `pickOrderColumn` and `pickSelectColumns` hand one out
9
- * and return plain text. Nothing outside the stage therefore has to know that
10
- * a scope is a Proxy at all.
6
+ * Every function here is one call into `FilterService` and holds no logic of
7
+ * its own. An entry function creates one `FilterService` per callback, so
8
+ * every callback gets its own scope.
11
9
  */
12
- import type { Node, Predicate } from '../../domain/filter/node.model';
13
10
  import type { DateExpr } from '../../domain/filter/dateExpr.model';
11
+ import type { Node, Predicate } from '../../domain/filter/node.model';
14
12
  import type { Operators } from '../../domain/filter/operators.model';
15
13
  import type { SearchState } from '../../domain/queryState.model';
16
14
  export declare const and: (...predicates: Predicate[]) => Predicate;
@@ -20,18 +18,7 @@ export declare const now: () => DateExpr;
20
18
  export declare const maxdatetime: () => DateExpr;
21
19
  export declare const mindatetime: () => DateExpr;
22
20
  export declare const raw: (odataExpression: string) => Predicate;
23
- /**
24
- * Run one `.filter()` callback. A callback that returns a bare column rather
25
- * than a predicate is a runtime error here, because the type layer cannot see
26
- * through a caller's `any`.
27
- */
28
21
  export declare const buildFilterPredicate: (build: (scope: unknown, operators: Operators) => Predicate) => Predicate;
29
- /**
30
- * Run one `.search()` callback. `$search` is a 400 without `$searchColumns`,
31
- * so an empty column list is rejected before the query is ever emitted.
32
- */
33
22
  export declare const pickSearchColumns: (term: string, columns: (scope: unknown) => Node | readonly Node[]) => SearchState;
34
- /** Run one `.orderBy()` callback and return the path of the column it picks. */
35
23
  export declare const pickOrderColumn: (column: (scope: unknown) => unknown) => string;
36
- /** Run one `.select()` callback and return the paths of the columns it picks. */
37
24
  export declare const pickSelectColumns: (columns: (scope: unknown) => unknown) => string[];
@@ -1,76 +1,27 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.pickSelectColumns = exports.pickOrderColumn = exports.pickSearchColumns = exports.buildFilterPredicate = exports.raw = exports.mindatetime = exports.maxdatetime = exports.now = exports.not = exports.or = exports.and = void 0;
4
- const invalidFilter_exception_1 = require("../../exception/invalidFilter.exception");
5
- const escape_util_1 = require("../../util/filter/escape.util");
6
- const literal_util_1 = require("../../util/filter/literal.util");
7
- const predicate_util_1 = require("../../util/filter/predicate.util");
8
- const scopeProxy_util_1 = require("../../util/filter/scopeProxy.util");
9
- const and = (...predicates) => (0, predicate_util_1.combine)('and', predicates);
4
+ const filter_service_1 = require("./filter.service");
5
+ const and = (...predicates) => filter_service_1.FilterService.and(...predicates);
10
6
  exports.and = and;
11
- const or = (...predicates) => (0, predicate_util_1.combine)('or', predicates);
7
+ const or = (...predicates) => filter_service_1.FilterService.or(...predicates);
12
8
  exports.or = or;
13
- const not = (predicate) =>
14
- // `not (…)` carries its own grouping, so it never needs wrapping again.
15
- new predicate_util_1.PredicateNode(`not (${predicate.text})`);
9
+ const not = (predicate) => filter_service_1.FilterService.not(predicate);
16
10
  exports.not = not;
17
- const now = () => (0, scopeProxy_util_1.createMember)(new literal_util_1.ExpressionNode('now()', 0));
11
+ const now = () => filter_service_1.FilterService.now();
18
12
  exports.now = now;
19
- const maxdatetime = () => (0, scopeProxy_util_1.createMember)(new literal_util_1.ExpressionNode('maxdatetime()', 0));
13
+ const maxdatetime = () => filter_service_1.FilterService.maxdatetime();
20
14
  exports.maxdatetime = maxdatetime;
21
- const mindatetime = () => (0, scopeProxy_util_1.createMember)(new literal_util_1.ExpressionNode('mindatetime()', 0));
15
+ const mindatetime = () => filter_service_1.FilterService.mindatetime();
22
16
  exports.mindatetime = mindatetime;
23
- const raw = (odataExpression) => new predicate_util_1.PredicateNode(odataExpression, true);
17
+ const raw = (odataExpression) => filter_service_1.FilterService.raw(odataExpression);
24
18
  exports.raw = raw;
25
- /** The second argument of every filter callback. */
26
- const operators = {
27
- and: exports.and,
28
- or: exports.or,
29
- not: exports.not,
30
- now: exports.now,
31
- maxdatetime: exports.maxdatetime,
32
- mindatetime: exports.mindatetime,
33
- raw: exports.raw,
34
- };
35
- /**
36
- * Run one `.filter()` callback. A callback that returns a bare column rather
37
- * than a predicate is a runtime error here, because the type layer cannot see
38
- * through a caller's `any`.
39
- */
40
- const buildFilterPredicate = (build) => {
41
- const predicate = build((0, scopeProxy_util_1.rootScope)(), operators);
42
- if (!(predicate instanceof predicate_util_1.PredicateNode))
43
- throw new invalidFilter_exception_1.InvalidFilterError('a filter callback must return a predicate, not a bare column');
44
- return predicate;
45
- };
19
+ const buildFilterPredicate = (build) => new filter_service_1.FilterService().buildPredicate(build);
46
20
  exports.buildFilterPredicate = buildFilterPredicate;
47
- /**
48
- * Run one `.search()` callback. `$search` is a 400 without `$searchColumns`,
49
- * so an empty column list is rejected before the query is ever emitted.
50
- */
51
- const pickSearchColumns = (term, columns) => {
52
- const paths = columnPaths(columns((0, scopeProxy_util_1.rootScope)()), '$searchColumns');
53
- if (paths.length === 0)
54
- throw new invalidFilter_exception_1.InvalidFilterError('$search needs at least one column');
55
- return { term: (0, escape_util_1.escapeBareValue)(term), columns: paths };
56
- };
21
+ const pickSearchColumns = (term, columns) => new filter_service_1.FilterService().pickSearchColumns(term, columns);
57
22
  exports.pickSearchColumns = pickSearchColumns;
58
- /** Run one `.orderBy()` callback and return the path of the column it picks. */
59
- const pickOrderColumn = (column) => columnPath(column((0, scopeProxy_util_1.rootScope)()), '$orderby');
23
+ const pickOrderColumn = (column) => new filter_service_1.FilterService().pickOrderColumn(column);
60
24
  exports.pickOrderColumn = pickOrderColumn;
61
- /** Run one `.select()` callback and return the paths of the columns it picks. */
62
- const pickSelectColumns = (columns) => columnPaths(columns((0, scopeProxy_util_1.rootScope)()), '$select');
25
+ const pickSelectColumns = (columns) => new filter_service_1.FilterService().pickSelectColumns(columns);
63
26
  exports.pickSelectColumns = pickSelectColumns;
64
- /** One column or a list of them, as a callback returns it. */
65
- const columnPaths = (picked, option) => (Array.isArray(picked) ? picked : [picked]).map((column) => columnPath(column, option));
66
- /**
67
- * `$searchColumns`, `$orderby` and `$select` take plain property paths: a
68
- * function call is a 400.
69
- */
70
- const columnPath = (value, option) => {
71
- const node = (0, scopeProxy_util_1.nodeOf)(value);
72
- if (node === undefined || node.text === '' || /[(),']/.test(node.text))
73
- throw new invalidFilter_exception_1.InvalidFilterError(`${option} takes property paths only, not expressions`);
74
- return node.text;
75
- };
76
27
  //# sourceMappingURL=filter.facade.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"filter.facade.js","sourceRoot":"","sources":["../../../../../src/module/query/service/filter/filter.facade.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"filter.facade.js","sourceRoot":"","sources":["../../../../../src/module/query/service/filter/filter.facade.ts"],"names":[],"mappings":";;;AAaA,qDAAiD;AAE1C,MAAM,GAAG,GAAG,CAAC,GAAG,UAAuB,EAAa,EAAE,CAC5D,8BAAa,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC;AADrB,QAAA,GAAG,OACkB;AAC3B,MAAM,EAAE,GAAG,CAAC,GAAG,UAAuB,EAAa,EAAE,CAC3D,8BAAa,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,CAAC;AADpB,QAAA,EAAE,MACkB;AAC1B,MAAM,GAAG,GAAG,CAAC,SAAoB,EAAa,EAAE,CACtD,8BAAa,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AADjB,QAAA,GAAG,OACc;AACvB,MAAM,GAAG,GAAG,GAAa,EAAE,CAAC,8BAAa,CAAC,GAAG,EAAE,CAAC;AAA1C,QAAA,GAAG,OAAuC;AAChD,MAAM,WAAW,GAAG,GAAa,EAAE,CAAC,8BAAa,CAAC,WAAW,EAAE,CAAC;AAA1D,QAAA,WAAW,eAA+C;AAChE,MAAM,WAAW,GAAG,GAAa,EAAE,CAAC,8BAAa,CAAC,WAAW,EAAE,CAAC;AAA1D,QAAA,WAAW,eAA+C;AAChE,MAAM,GAAG,GAAG,CAAC,eAAuB,EAAa,EAAE,CACzD,8BAAa,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;AADvB,QAAA,GAAG,OACoB;AAE7B,MAAM,oBAAoB,GAAG,CACnC,KAA0D,EAC9C,EAAE,CAAC,IAAI,8BAAa,EAAE,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;AAF7C,QAAA,oBAAoB,wBAEyB;AAEnD,MAAM,iBAAiB,GAAG,CAChC,IAAY,EACZ,OAAmD,EACrC,EAAE,CAAC,IAAI,8BAAa,EAAE,CAAC,iBAAiB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAH1D,QAAA,iBAAiB,qBAGyC;AAEhE,MAAM,eAAe,GAAG,CAAC,MAAmC,EAAU,EAAE,CAC9E,IAAI,8BAAa,EAAE,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;AADhC,QAAA,eAAe,mBACiB;AAEtC,MAAM,iBAAiB,GAAG,CAChC,OAAoC,EACzB,EAAE,CAAC,IAAI,8BAAa,EAAE,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;AAFjD,QAAA,iBAAiB,qBAEgC"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * `FilterService` runs one caller callback against a fresh scope and turns
3
+ * what comes back into filter text or column paths. Its static methods are the
4
+ * combinators a caller writes (`and`, `or`, `not`, `raw`, `now`,
5
+ * `maxdatetime`, `mindatetime`); they need no scope, so they need no instance.
6
+ *
7
+ * A scope proxy never leaves this class as itself. `buildPredicate` hands one
8
+ * to the callback and returns the predicate that comes back;
9
+ * `pickSearchColumns`, `pickOrderColumn` and `pickSelectColumns` hand one out
10
+ * and return plain text. Nothing outside the filter stage therefore has to
11
+ * know that a scope is a Proxy at all.
12
+ */
13
+ import type { DateExpr } from '../../domain/filter/dateExpr.model';
14
+ import type { Node, Predicate } from '../../domain/filter/node.model';
15
+ import type { Operators } from '../../domain/filter/operators.model';
16
+ import type { SearchState } from '../../domain/queryState.model';
17
+ export declare class FilterService {
18
+ static and(...predicates: Predicate[]): Predicate;
19
+ static or(...predicates: Predicate[]): Predicate;
20
+ static not(predicate: Predicate): Predicate;
21
+ static now(): DateExpr;
22
+ static maxdatetime(): DateExpr;
23
+ static mindatetime(): DateExpr;
24
+ static raw(odataExpression: string): Predicate;
25
+ /** The second argument of every filter callback. */
26
+ private static readonly operators;
27
+ /** The scope this instance hands to its one callback. */
28
+ private readonly scope;
29
+ /**
30
+ * Run one `.filter()` callback. A callback that returns a bare column rather
31
+ * than a predicate is a runtime error here, because the type layer cannot see
32
+ * through a caller's `any`.
33
+ */
34
+ buildPredicate(build: (scope: unknown, operators: Operators) => Predicate): Predicate;
35
+ /**
36
+ * Run one `.search()` callback. `$search` is a 400 without `$searchColumns`,
37
+ * so an empty column list is rejected before the query is ever emitted.
38
+ */
39
+ pickSearchColumns(term: string, columns: (scope: unknown) => Node | readonly Node[]): SearchState;
40
+ /** Run one `.orderBy()` callback and return the path of the column it picks. */
41
+ pickOrderColumn(column: (scope: unknown) => unknown): string;
42
+ /** Run one `.select()` callback and return the paths of the columns it picks. */
43
+ pickSelectColumns(columns: (scope: unknown) => unknown): string[];
44
+ /** One column or a list of them, as a callback returns it. */
45
+ private columnPaths;
46
+ /**
47
+ * `$searchColumns`, `$orderby` and `$select` take plain property paths: a
48
+ * function call is a 400.
49
+ */
50
+ private columnPath;
51
+ }
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FilterService = void 0;
4
+ const invalidFilter_exception_1 = require("../../exception/invalidFilter.exception");
5
+ const escape_util_1 = require("../../util/filter/escape.util");
6
+ const predicate_util_1 = require("../../util/filter/predicate.util");
7
+ const scope_service_1 = require("./scope.service");
8
+ class FilterService {
9
+ static and(...predicates) {
10
+ return (0, predicate_util_1.combine)('and', predicates);
11
+ }
12
+ static or(...predicates) {
13
+ return (0, predicate_util_1.combine)('or', predicates);
14
+ }
15
+ static not(predicate) {
16
+ // `not (…)` carries its own grouping, so it never needs wrapping again.
17
+ return new predicate_util_1.PredicateNode(`not (${predicate.text})`);
18
+ }
19
+ static now() {
20
+ return scope_service_1.ScopeService.createMember(new scope_service_1.ExpressionNode('now()', 0));
21
+ }
22
+ static maxdatetime() {
23
+ return scope_service_1.ScopeService.createMember(new scope_service_1.ExpressionNode('maxdatetime()', 0));
24
+ }
25
+ static mindatetime() {
26
+ return scope_service_1.ScopeService.createMember(new scope_service_1.ExpressionNode('mindatetime()', 0));
27
+ }
28
+ static raw(odataExpression) {
29
+ return new predicate_util_1.PredicateNode(odataExpression, true);
30
+ }
31
+ /** The second argument of every filter callback. */
32
+ static operators = {
33
+ and: FilterService.and,
34
+ or: FilterService.or,
35
+ not: FilterService.not,
36
+ now: FilterService.now,
37
+ maxdatetime: FilterService.maxdatetime,
38
+ mindatetime: FilterService.mindatetime,
39
+ raw: FilterService.raw,
40
+ };
41
+ /** The scope this instance hands to its one callback. */
42
+ scope = scope_service_1.ScopeService.rootScope();
43
+ /**
44
+ * Run one `.filter()` callback. A callback that returns a bare column rather
45
+ * than a predicate is a runtime error here, because the type layer cannot see
46
+ * through a caller's `any`.
47
+ */
48
+ buildPredicate(build) {
49
+ const predicate = build(this.scope, FilterService.operators);
50
+ if (!(predicate instanceof predicate_util_1.PredicateNode))
51
+ throw new invalidFilter_exception_1.InvalidFilterError('a filter callback must return a predicate, not a bare column');
52
+ return predicate;
53
+ }
54
+ /**
55
+ * Run one `.search()` callback. `$search` is a 400 without `$searchColumns`,
56
+ * so an empty column list is rejected before the query is ever emitted.
57
+ */
58
+ pickSearchColumns(term, columns) {
59
+ const paths = this.columnPaths(columns(this.scope), '$searchColumns');
60
+ if (paths.length === 0)
61
+ throw new invalidFilter_exception_1.InvalidFilterError('$search needs at least one column');
62
+ return { term: (0, escape_util_1.escapeBareValue)(term), columns: paths };
63
+ }
64
+ /** Run one `.orderBy()` callback and return the path of the column it picks. */
65
+ pickOrderColumn(column) {
66
+ return this.columnPath(column(this.scope), '$orderby');
67
+ }
68
+ /** Run one `.select()` callback and return the paths of the columns it picks. */
69
+ pickSelectColumns(columns) {
70
+ return this.columnPaths(columns(this.scope), '$select');
71
+ }
72
+ /** One column or a list of them, as a callback returns it. */
73
+ columnPaths(picked, option) {
74
+ return (Array.isArray(picked) ? picked : [picked]).map((column) => this.columnPath(column, option));
75
+ }
76
+ /**
77
+ * `$searchColumns`, `$orderby` and `$select` take plain property paths: a
78
+ * function call is a 400.
79
+ */
80
+ columnPath(value, option) {
81
+ const node = scope_service_1.ScopeService.nodeOf(value);
82
+ if (node === undefined || node.text === '' || /[(),']/.test(node.text))
83
+ throw new invalidFilter_exception_1.InvalidFilterError(`${option} takes property paths only, not expressions`);
84
+ return node.text;
85
+ }
86
+ }
87
+ exports.FilterService = FilterService;
88
+ //# sourceMappingURL=filter.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter.service.js","sourceRoot":"","sources":["../../../../../src/module/query/service/filter/filter.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ export declare class ExpressionNode {
2
+ readonly text: string;
3
+ /** lambda nesting level, for deterministic alias letters */
4
+ readonly depth: number;
5
+ /** true for `a add 1`: needs parentheses as an operand of `mul`. */
6
+ readonly arithmetic: boolean;
7
+ constructor(text: string,
8
+ /** lambda nesting level, for deterministic alias letters */
9
+ depth: number,
10
+ /** true for `a add 1`: needs parentheses as an operand of `mul`. */
11
+ arithmetic?: boolean);
12
+ }
13
+ export declare class ScopeService {
14
+ /** The only key that reads a node. A DTO key can never be a symbol. */
15
+ private static readonly NODE;
16
+ /**
17
+ * The filter scope of an entity: an empty path at lambda depth 0. An
18
+ * expanded entity is filtered relative to itself, so it takes the same empty
19
+ * root.
20
+ */
21
+ static rootScope(): any;
22
+ /**
23
+ * `createMember(node)` is a value; `createMember(node, parent, name)` is a
24
+ * member of `parent` that has not yet decided whether it is a path segment
25
+ * or a function call.
26
+ *
27
+ * The target is an arrow function so the proxy is callable. An arrow
28
+ * function has no `prototype`, and its `name`/`length` are configurable, so
29
+ * no Proxy invariant forces a value through — a DTO column called `name` or
30
+ * `length` still reaches the trap.
31
+ *
32
+ * `v.name.eq('x')` on `rootScope()` gives `name eq 'x'`. See
33
+ * docs/maintainer/architecture.md, How `Proxy` works here.
34
+ */
35
+ static createMember(node: ExpressionNode, parent?: ExpressionNode, name?: string): any;
36
+ /** The node behind a scope proxy, or `undefined` for a plain value. */
37
+ static nodeOf(value: unknown): ExpressionNode | undefined;
38
+ /** `a add 1` used as an operand of `mul` must become `(a add 1)`. */
39
+ private static parenthesiseArithmetic;
40
+ private static isLuxonLike;
41
+ /**
42
+ * @param allowNull `in()` accepts a null member (`in (2024,null)` is a legal
43
+ * set test); every other position rejects it — `eq(null)` must look nothing
44
+ * like "no filter", so `isNull()`/`isNotNull()` are the only way to test for
45
+ * null. `undefined` is never a literal, in any position: it means "nothing
46
+ * was passed", not "the value is null", and reaching this method with it is
47
+ * only possible through an `any`/`as never` cast around the type layer.
48
+ */
49
+ private static literal;
50
+ private static comparison;
51
+ /** A one-argument SQL function: `name(self)`. */
52
+ private static unaryFunction;
53
+ /** A two-argument SQL function: `name(self,argument)`. */
54
+ private static binaryFunction;
55
+ private static arithmetic;
56
+ private static stringMatch;
57
+ /**
58
+ * A distinct alias letter per lambda nesting level, so an inner lambda never
59
+ * shadows the outer one and `b/x ne a/y` stays expressible.
60
+ */
61
+ private static lambdaAlias;
62
+ private static lambda;
63
+ private static readonly FILTER_FUNCTIONS;
64
+ /**
65
+ * Look a called name up in the table. `hasOwnProperty` rather than a plain
66
+ * index read, so `constructor` or `__proto__` cannot resolve to an inherited
67
+ * member of `Object.prototype`.
68
+ */
69
+ private static filterFunction;
70
+ }