@ballistix.digital/odata-query-builder 0.4.0 → 0.5.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.
package/dist/index.d.ts CHANGED
@@ -12,7 +12,7 @@ import type { Scalar, Unwrap } from './module/common/domain/scalar.model';
12
12
  import { QueryBuilderException } from './module/common/exception/queryBuilder.exception';
13
13
  import type { Chain, QueryParams } from './module/query/domain/chain/chain.model';
14
14
  import type { ExpandChain } from './module/query/domain/chain/expandChain.model';
15
- import type { EmbeddedPathKeys, ExpandKey, ExpandNamespace, FieldKey, OrderKey } from './module/query/domain/chain/expandNamespace.model';
15
+ import type { ExpandKey, ExpandNamespace } from './module/query/domain/chain/expandNamespace.model';
16
16
  import type { ItemChain } from './module/query/domain/chain/itemChain.model';
17
17
  import type { BooleanExpr } from './module/query/domain/filter/booleanExpr.model';
18
18
  import type { Castable, CastResult, EdmTarget } from './module/query/domain/filter/castable.model';
@@ -28,4 +28,4 @@ import { ReservedNameError } from './module/query/exception/reservedName.excepti
28
28
  import { and, maxdatetime, mindatetime, not, now, or, raw } from './module/query/service/filter/filter.facade';
29
29
  import { odataItem, odataQuery } from './module/query/service/queryChain.service';
30
30
  export { InvalidFilterError, QueryBuilderException, QueryBuilderExceptionCode, ReservedNameError, and, maxdatetime, mindatetime, not, now, odataItem, odataQuery, or, raw, };
31
- export type { BooleanExpr, CastResult, Castable, Chain, Comparable, DateExpr, DateInput, EdmTarget, EmbeddedObjectKeys, EmbeddedOf, EmbeddedPathKeys, ExceptionDetail, ExpandChain, ExpandKey, ExpandNamespace, ExprFor, FieldKey, ItemChain, LambdaNamespace, Node, NumberExpr, Operators, OrderKey, OwnKeys, Predicate, PrimitiveArrayKeys, PrimitiveLambdaNamespace, QueryParams, Relation, Scalar, ScalarFieldKeys, Scope, StringExpr, ToManyKeys, ToOneKeys, Unwrap, };
31
+ export type { BooleanExpr, CastResult, Castable, Chain, Comparable, DateExpr, DateInput, EdmTarget, EmbeddedObjectKeys, EmbeddedOf, ExceptionDetail, ExpandChain, ExpandKey, ExpandNamespace, ExprFor, ItemChain, LambdaNamespace, Node, NumberExpr, Operators, OwnKeys, Predicate, PrimitiveArrayKeys, PrimitiveLambdaNamespace, QueryParams, Relation, Scalar, ScalarFieldKeys, Scope, StringExpr, ToManyKeys, ToOneKeys, Unwrap, };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;AAEH,oFAAuF;AAiEtF,0GAjEQ,+CAAyB,OAiER;AA9D1B,6FAAyF;AA6DxF,sGA7DQ,8CAAqB,OA6DR;AAlBtB,8FAAsF;AAiBrF,mGAjBQ,4CAAkB,OAiBR;AAhBnB,4FAAoF;AAmBnF,kGAnBQ,0CAAiB,OAmBR;AAlBlB,+EAQqD;AAWpD,oFAlBA,mBAAG,OAkBA;AACH,4FAlBA,2BAAW,OAkBA;AACX,4FAlBA,2BAAW,OAkBA;AACX,oFAlBA,mBAAG,OAkBA;AACH,oFAlBA,mBAAG,OAkBA;AAGH,mFApBA,kBAAE,OAoBA;AACF,oFApBA,mBAAG,OAoBA;AAlBJ,kFAGmD;AAYlD,0FAdA,8BAAS,OAcA;AACT,2FAdA,+BAAU,OAcA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;AAEH,oFAAuF;AA8DtF,0GA9DQ,+CAAyB,OA8DR;AA3D1B,6FAAyF;AA0DxF,sGA1DQ,8CAAqB,OA0DR;AAlBtB,8FAAsF;AAiBrF,mGAjBQ,4CAAkB,OAiBR;AAhBnB,4FAAoF;AAmBnF,kGAnBQ,0CAAiB,OAmBR;AAlBlB,+EAQqD;AAWpD,oFAlBA,mBAAG,OAkBA;AACH,4FAlBA,2BAAW,OAkBA;AACX,4FAlBA,2BAAW,OAkBA;AACX,oFAlBA,mBAAG,OAkBA;AACH,oFAlBA,mBAAG,OAkBA;AAGH,mFApBA,kBAAE,OAoBA;AACF,oFApBA,mBAAG,OAoBA;AAlBJ,kFAGmD;AAYlD,0FAdA,8BAAS,OAcA;AACT,2FAdA,+BAAU,OAcA"}
@@ -6,20 +6,28 @@
6
6
  */
7
7
  import type { Predicate } from '../filter/node.model';
8
8
  import type { Operators } from '../filter/operators.model';
9
- import type { Scope } from '../filter/scope.model';
9
+ import type { ColumnExpr, ScalarFieldKeys, Scope, SelectScope } from '../filter/scope.model';
10
10
  import type { StringExpr } from '../filter/stringExpr.model';
11
- import type { ExpandNamespace, FieldKey, OrderKey } from './expandNamespace.model';
11
+ import type { ExpandNamespace } from './expandNamespace.model';
12
12
  /** A flat `{ $option: value }` map, for a caller that serialises its own URL. */
13
13
  export type QueryParams = Record<string, string>;
14
14
  export interface Chain<T> {
15
15
  readonly expand: ExpandNamespace<T, Chain<T>>;
16
- select(...keys: FieldKey<T>[]): Chain<T>;
16
+ /** Own columns, by name. */
17
+ select(...keys: ScalarFieldKeys<T>[]): Chain<T>;
18
+ /** Own columns and embedded leaves: `select((v) => [v.id, v.address.city])`. */
19
+ select(columns: (scope: SelectScope<T>) => ColumnExpr | readonly ColumnExpr[]): Chain<T>;
17
20
  /** Repeated calls AND together. */
18
21
  filter(build: (scope: Scope<T>, operators: Operators) => Predicate): Chain<T>;
19
22
  /** `$search` + its mandatory `$searchColumns`, as one verb. */
20
23
  search(term: string, columns: (scope: Scope<T>) => StringExpr | readonly StringExpr[]): Chain<T>;
21
- /** Sorts on an own column, an embedded leaf, or a to-one relation path. */
22
- orderBy(key: OrderKey<T>, direction?: 'asc' | 'desc'): Chain<T>;
24
+ /** Sorts on an own column, by name. */
25
+ orderBy(key: ScalarFieldKeys<T>, direction?: 'asc' | 'desc'): Chain<T>;
26
+ /**
27
+ * Sorts on the column the callback reads: an embedded leaf, or a column at
28
+ * any depth of to-one relations: `orderBy((v) => v.owner.organisation.code)`.
29
+ */
30
+ orderBy(column: (scope: Scope<T>) => ColumnExpr, direction?: 'asc' | 'desc'): Chain<T>;
23
31
  top(count: number): Chain<T>;
24
32
  skip(count: number): Chain<T>;
25
33
  count(on?: boolean): Chain<T>;
@@ -15,11 +15,14 @@
15
15
  */
16
16
  import type { Predicate } from '../filter/node.model';
17
17
  import type { Operators } from '../filter/operators.model';
18
- import type { Scope } from '../filter/scope.model';
19
- import type { ExpandNamespace, FieldKey } from './expandNamespace.model';
18
+ import type { ColumnExpr, ScalarFieldKeys, Scope, SelectScope } from '../filter/scope.model';
19
+ import type { ExpandNamespace } from './expandNamespace.model';
20
20
  export interface ExpandChain<T> {
21
21
  readonly expand: ExpandNamespace<T, ExpandChain<T>>;
22
- select(...keys: FieldKey<T>[]): ExpandChain<T>;
22
+ /** Own columns, by name. */
23
+ select(...keys: ScalarFieldKeys<T>[]): ExpandChain<T>;
24
+ /** Own columns and embedded leaves: `select((v) => [v.id, v.address.city])`. */
25
+ select(columns: (scope: SelectScope<T>) => ColumnExpr | readonly ColumnExpr[]): ExpandChain<T>;
23
26
  /**
24
27
  * `$expand=rel($filter=…)`. The scope is the EXPANDED entity, so paths are
25
28
  * written relative to it, not to the root. Repeated calls AND together.
@@ -5,63 +5,10 @@
5
5
  * relations `_embedded` declares, each callback typed to the entity that
6
6
  * relation reaches, with no build step and no `$metadata` document.
7
7
  */
8
- import type { EmbeddedObjectKeys, Relation, ScalarFieldKeys, ToManyKeys, ToOneKeys } from '../filter/scope.model';
8
+ import type { Relation, ToManyKeys, ToOneKeys } from '../filter/scope.model';
9
9
  import type { ExpandChain } from './expandChain.model';
10
10
  /** Every expandable relation name of a DTO. A real allowlist. */
11
11
  export type ExpandKey<T> = ToOneKeys<T> | ToManyKeys<T>;
12
- /**
13
- * The budget a path type spends, one unit per segment it descends.
14
- *
15
- * A DTO graph is cyclic — `ProjectDto` reaches itself through `parent` — so a
16
- * path type that recursed freely would never terminate and TypeScript would
17
- * answer TS2589. Indexing `Down` with the remaining budget yields the budget
18
- * one segment deeper; `[D] extends [0]` stops the descent.
19
- *
20
- * The budget also sets what a caller can write. `OrderKey` (default 3) admits
21
- * up to three to-one hops; `EmbeddedPathKeys` (default 2) admits three object
22
- * segments before the leaf. A deeper path is a compile error, which
23
- * `test/types/err/orderBy.err.ts` pins.
24
- *
25
- * ```ts
26
- * orderBy('owner/organisation/code') // 2 to-one hops: compiles
27
- * orderBy('parent/parent/parent/name') // 3 to-one hops: compiles, the default budget
28
- * orderBy('parent/parent/parent/parent/name') // 4 to-one hops: TS2345, past the budget
29
- * // Down[3] is 2, Down[1] is 0, and at 0 the path stops.
30
- * ```
31
- *
32
- * To allow a deeper path, raise the default `D` and move the pinned case to
33
- * `test/types/ok/`. Each extra unit multiplies the key strings TypeScript
34
- * builds, so compile time grows.
35
- */
36
- type Budget = 0 | 1 | 2 | 3;
37
- type Down = [never, 0, 1, 2, 3];
38
- /**
39
- * Every leaf path an embedded object of a DTO exposes: `address/city`,
40
- * `address/geo/lat`, `address/supplier/name`.
41
- *
42
- * The budget admits three object segments before the leaf, which is one more
43
- * than any embedded the dialect models nests.
44
- */
45
- export type EmbeddedPathKeys<T, D extends Budget = 2> = {
46
- [K in EmbeddedObjectKeys<T>]: `${K}/${ScalarFieldKeys<NonNullable<T[K]>>}` | ([D] extends [0] ? never : `${K}/${EmbeddedPathKeys<NonNullable<T[K]>, Down[D]>}`);
47
- }[EmbeddedObjectKeys<T>];
48
- /**
49
- * Every selectable column of a DTO: its own scalar columns, plus the leaf paths
50
- * of its embedded objects. `_embedded` is excluded, and an embedded object is
51
- * not selectable on its own — only its leaves are.
52
- */
53
- export type FieldKey<T> = ScalarFieldKeys<T> | EmbeddedPathKeys<T>;
54
- /**
55
- * Every sortable key of a DTO: everything `FieldKey` admits, plus the same set
56
- * reached across up to three to-one relation hops (`owner/email`,
57
- * `owner/organisation/code`, `parent/parent/parent/name`).
58
- *
59
- * A to-many relation is never a sort key — the server has no single row to sort
60
- * by — so only `ToOneKeys` opens a hop.
61
- */
62
- export type OrderKey<T, D extends Budget = 3> = FieldKey<T> | ([D] extends [0] ? never : {
63
- [K in ToOneKeys<T>]: `${K}/${OrderKey<Relation<T, K>, Down[D]>}`;
64
- }[ToOneKeys<T>]);
65
12
  /**
66
13
  * `Self` is the chain the call returns, so `expand.a(...).expand.b(...)`
67
14
  * chains at whatever level it is written.
@@ -69,4 +16,3 @@ export type OrderKey<T, D extends Budget = 3> = FieldKey<T> | ([D] extends [0] ?
69
16
  export type ExpandNamespace<T, Self> = {
70
17
  readonly [K in ExpandKey<T>]: (build?: (chain: ExpandChain<Relation<T, K>>) => unknown) => Self;
71
18
  };
72
- export {};
@@ -5,11 +5,15 @@
5
5
  * `$count` and `$search` have nothing to act on. Only the shaping options are
6
6
  * offered.
7
7
  */
8
+ import type { ColumnExpr, ScalarFieldKeys, SelectScope } from '../filter/scope.model';
8
9
  import type { QueryParams } from './chain.model';
9
- import type { ExpandNamespace, FieldKey } from './expandNamespace.model';
10
+ import type { ExpandNamespace } from './expandNamespace.model';
10
11
  export interface ItemChain<T> {
11
12
  readonly expand: ExpandNamespace<T, ItemChain<T>>;
12
- select(...keys: FieldKey<T>[]): ItemChain<T>;
13
+ /** Own columns, by name. */
14
+ select(...keys: ScalarFieldKeys<T>[]): ItemChain<T>;
15
+ /** Own columns and embedded leaves: `select((v) => [v.id, v.address.city])`. */
16
+ select(columns: (scope: SelectScope<T>) => ColumnExpr | readonly ColumnExpr[]): ItemChain<T>;
13
17
  toQueryString(): string;
14
18
  /**
15
19
  * The same query as separate parts, with the transport escaping undone, for
@@ -92,3 +92,19 @@ export type Scope<T> = {
92
92
  } & {
93
93
  readonly [K in Exclude<ToManyKeys<T>, OwnKeys<T>>]: LambdaNamespace<Relation<T, K>>;
94
94
  };
95
+ /**
96
+ * One column, as a `select` or `orderBy` callback returns it. A to-one
97
+ * relation reads as a `Scope` and a to-many as a `LambdaNamespace`, so neither
98
+ * fits.
99
+ */
100
+ export type ColumnExpr = StringExpr<string> | NumberExpr<number | bigint> | DateExpr | BooleanExpr;
101
+ /**
102
+ * What a `select` callback reads: own columns and embedded objects, never a
103
+ * relation. A relation column comes through `$expand`, so `owner/email` is
104
+ * not a `$select` path.
105
+ */
106
+ export type SelectScope<T> = {
107
+ readonly [K in ScalarFieldKeys<T>]: ExprFor<T[K]>;
108
+ } & {
109
+ readonly [K in EmbeddedObjectKeys<T>]: SelectScope<NonNullable<T[K]>>;
110
+ };
@@ -20,3 +20,7 @@ export declare const buildFilterPredicate: (build: (scope: unknown, operators: O
20
20
  * so an empty column list is rejected before the query is ever emitted.
21
21
  */
22
22
  export declare const pickSearchColumns: (term: string, columns: (scope: unknown) => Node | readonly Node[]) => SearchState;
23
+ /** Run one `.orderBy()` callback and return the path of the column it picks. */
24
+ export declare const pickOrderColumn: (column: (scope: unknown) => unknown) => string;
25
+ /** Run one `.select()` callback and return the paths of the columns it picks. */
26
+ export declare const pickSelectColumns: (columns: (scope: unknown) => unknown) => string[];
@@ -1,15 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.pickSearchColumns = exports.buildFilterPredicate = exports.raw = exports.mindatetime = exports.maxdatetime = exports.now = exports.not = exports.or = exports.and = void 0;
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
4
  /**
5
5
  * The only file that other code imports from the filter stage: the combinators
6
- * a caller writes, and the two entry functions that run a caller's callback
6
+ * a caller writes, and the four entry functions that run a caller's callback
7
7
  * against a fresh scope.
8
8
  *
9
9
  * A scope proxy never leaves this stage as itself. `buildFilterPredicate`
10
10
  * hands one to the callback and returns the predicate that comes back;
11
- * `pickSearchColumns` hands one out and returns plain text. Nothing outside
12
- * the stage therefore has to know that a scope is a Proxy at all.
11
+ * `pickSearchColumns`, `pickOrderColumn` and `pickSelectColumns` hand one out
12
+ * and return plain text. Nothing outside the stage therefore has to know that
13
+ * a scope is a Proxy at all.
13
14
  */
14
15
  const escape_util_1 = require("../../../common/util/escape.util");
15
16
  const invalidFilter_exception_1 = require("../../exception/invalidFilter.exception");
@@ -59,21 +60,28 @@ exports.buildFilterPredicate = buildFilterPredicate;
59
60
  * so an empty column list is rejected before the query is ever emitted.
60
61
  */
61
62
  const pickSearchColumns = (term, columns) => {
62
- const picked = columns((0, scopeProxy_util_1.rootScope)());
63
- const list = Array.isArray(picked) ? picked : [picked];
64
- if (list.length === 0)
63
+ const paths = columnPaths(columns((0, scopeProxy_util_1.rootScope)()), '$searchColumns');
64
+ if (paths.length === 0)
65
65
  throw new invalidFilter_exception_1.InvalidFilterError('$search needs at least one column');
66
- return {
67
- term: (0, escape_util_1.escapeBareValue)(term),
68
- columns: list.map(searchColumnPath),
69
- };
66
+ return { term: (0, escape_util_1.escapeBareValue)(term), columns: paths };
70
67
  };
71
68
  exports.pickSearchColumns = pickSearchColumns;
72
- /** `$searchColumns` takes plain property paths — a function call is a 400. */
73
- const searchColumnPath = (value) => {
69
+ /** Run one `.orderBy()` callback and return the path of the column it picks. */
70
+ const pickOrderColumn = (column) => columnPath(column((0, scopeProxy_util_1.rootScope)()), '$orderby');
71
+ exports.pickOrderColumn = pickOrderColumn;
72
+ /** Run one `.select()` callback and return the paths of the columns it picks. */
73
+ const pickSelectColumns = (columns) => columnPaths(columns((0, scopeProxy_util_1.rootScope)()), '$select');
74
+ exports.pickSelectColumns = pickSelectColumns;
75
+ /** One column or a list of them, as a callback returns it. */
76
+ const columnPaths = (picked, option) => (Array.isArray(picked) ? picked : [picked]).map((column) => columnPath(column, option));
77
+ /**
78
+ * `$searchColumns`, `$orderby` and `$select` take plain property paths: a
79
+ * function call is a 400.
80
+ */
81
+ const columnPath = (value, option) => {
74
82
  const node = (0, scopeProxy_util_1.nodeOf)(value);
75
83
  if (node === undefined || node.text === '' || /[(),']/.test(node.text))
76
- throw new invalidFilter_exception_1.InvalidFilterError('$searchColumns takes property paths only, not expressions');
84
+ throw new invalidFilter_exception_1.InvalidFilterError(`${option} takes property paths only, not expressions`);
77
85
  return node.text;
78
86
  };
79
87
  //# 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":"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"}
@@ -3,9 +3,10 @@
3
3
  * one member per OData system query option. This file also exports the two
4
4
  * factories a caller starts from: `odataQuery()` and `odataItem()`.
5
5
  *
6
- * Each member only writes to `this.queryState`. `buildFilterPredicate()` and
7
- * `pickSearchColumns()` in `service/filter/filter.facade.ts` build the filter
8
- * and search text. `emitQueryString()` and `emitQueryParams()` in
6
+ * Each member only writes to `this.queryState`. `buildFilterPredicate()`,
7
+ * `pickSearchColumns()`, `pickOrderColumn()` and `pickSelectColumns()` in
8
+ * `service/filter/filter.facade.ts` build the filter, search, sort and select
9
+ * text. `emitQueryString()` and `emitQueryParams()` in
9
10
  * `service/emit/emit.facade.ts` print the state. A change to the printed
10
11
  * query therefore does not change this class, and a change to this class does
11
12
  * not change how the query is printed.
@@ -37,10 +38,10 @@ export declare class QueryChainService {
37
38
  * `Proxy` works here.
38
39
  */
39
40
  get expand(): unknown;
40
- select(...keys: string[]): this;
41
+ select(...keys: string[] | [(scope: unknown) => unknown]): this;
41
42
  filter(build: (scope: unknown, operators: Operators) => Predicate): this;
42
43
  search(term: string, columns: (scope: unknown) => Node | readonly Node[]): this;
43
- orderBy(key: string, direction?: 'asc' | 'desc'): this;
44
+ orderBy(key: string | ((scope: unknown) => unknown), direction?: 'asc' | 'desc'): this;
44
45
  top(count: number): this;
45
46
  skip(count: number): this;
46
47
  count(on?: boolean): this;
@@ -47,7 +47,10 @@ class QueryChainService {
47
47
  });
48
48
  }
49
49
  select(...keys) {
50
- this.queryState.select.push(...keys);
50
+ const [first] = keys;
51
+ this.queryState.select.push(...(typeof first === 'function'
52
+ ? (0, filter_facade_1.pickSelectColumns)(first)
53
+ : keys));
51
54
  return this;
52
55
  }
53
56
  filter(build) {
@@ -59,7 +62,8 @@ class QueryChainService {
59
62
  return this;
60
63
  }
61
64
  orderBy(key, direction = 'asc') {
62
- this.queryState.orderBy.push(`${key} ${direction}`);
65
+ const path = typeof key === 'string' ? key : (0, filter_facade_1.pickOrderColumn)(key);
66
+ this.queryState.orderBy.push(`${path} ${direction}`);
63
67
  return this;
64
68
  }
65
69
  top(count) {
@@ -1 +1 @@
1
- {"version":3,"file":"queryChain.service.js","sourceRoot":"","sources":["../../../../src/module/query/service/queryChain.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"queryChain.service.js","sourceRoot":"","sources":["../../../../src/module/query/service/queryChain.service.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ballistix.digital/odata-query-builder",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Typed, fluent OData v4 query-string builder for the dialect @ballistix.digital/typeorm-extensions serves.",
5
5
  "license": "MIT",
6
6
  "repository": {