Skip to content

Commit 2abd4fb

Browse files
committed
Refactor operators/transformations and add Casting support
1 parent 7009ad8 commit 2abd4fb

8 files changed

Lines changed: 12316 additions & 30 deletions

File tree

projects/angular-odata/src/lib/resources/query/expressions/apply.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import {
99
ODataFunctions,
1010
ODataOperators,
1111
operators,
12-
syntax,
1312
transformations,
1413
Renderable,
1514
RenderableFactory,
@@ -202,7 +201,7 @@ export class ApplyExpression<T> extends Expression<T> {
202201
}
203202

204203
aggregate(value: any, method: AggregateMethod, alias: string): ApplyExpression<T> {
205-
return this._add(syntax.aggregate(value, method, alias));
204+
return this._add(transformations.aggregate(value, method, alias));
206205
}
207206

208207
//topcount
@@ -296,10 +295,10 @@ export class ApplyExpression<T> extends Expression<T> {
296295
props: (e: { rollup: (f: any) => any }) => any | any[],
297296
opts?: (e: GroupByTransformations<T>) => GroupByTransformations<T>,
298297
): ApplyExpression<T> {
299-
let properties = props({ rollup: (e: any) => syntax.rollup(e) });
298+
let properties = props({ rollup: (e: any) => operators.rollup(e) });
300299
properties = Array.isArray(properties) ? properties : [properties];
301-
const transformations = opts !== undefined ? opts(new GroupByTransformations()) : undefined;
302-
return this._add(syntax.groupby(properties, transformations));
300+
const transformation = opts !== undefined ? opts(new GroupByTransformations()) : undefined;
301+
return this._add(transformations.groupby(properties, transformation));
303302
}
304303

305304
//filter

projects/angular-odata/src/lib/resources/query/expressions/expand.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { FilterExpression, FilterExpressionBuilder } from './filter';
77
import { OrderByExpression, OrderByExpressionBuilder } from './orderby';
88
import { SearchExpression, SearchExpressionBuilder } from './search';
99
import { SelectExpression, SelectExpressionBuilder } from './select';
10-
import { FieldFactory, render, Renderable, RenderableFactory, resolve } from './syntax';
10+
import { FieldFactory, ODataOperators, operators, render, Renderable, RenderableFactory, resolve } from './syntax';
1111

1212
export class ExpandField<T> implements Renderable {
1313
constructor(
@@ -193,6 +193,7 @@ export class ExpandField<T> implements Renderable {
193193
export type ExpandExpressionBuilder<T> = {
194194
t: Required<T>;
195195
e: () => ExpandExpression<T>;
196+
o: ODataOperators<T>;
196197
};
197198
export class ExpandExpression<T> extends Expression<T> {
198199
constructor({
@@ -218,6 +219,7 @@ export class ExpandExpression<T> extends Expression<T> {
218219
{
219220
t: FieldFactory<Required<T>>(),
220221
e: () => new ExpandExpression<T>(),
222+
o: operators as ODataOperators<T>,
221223
},
222224
current ?? new ExpandExpression<T>(),
223225
) as ExpandExpression<T>;

projects/angular-odata/src/lib/resources/query/expressions/filter.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import {
1111
operators,
1212
Renderable,
1313
RenderableFactory,
14-
syntax,
1514
} from './syntax';
1615

1716
export type FilterConnector = 'and' | 'or';
@@ -128,7 +127,7 @@ export class FilterExpression<F> extends Expression<F> {
128127
negated: this._negated,
129128
});
130129
if (exp.length() > 1) {
131-
children.push(syntax.group(exp));
130+
children.push(operators.group(exp));
132131
} else {
133132
children.push(exp);
134133
}
@@ -140,7 +139,7 @@ export class FilterExpression<F> extends Expression<F> {
140139
) {
141140
children = [...children, ...node.children()];
142141
} else {
143-
children.push(syntax.group(node));
142+
children.push(operators.group(node));
144143
}
145144
this._connector = connector;
146145
this._children = children;
@@ -152,7 +151,7 @@ export class FilterExpression<F> extends Expression<F> {
152151
this._children = [...this._children, ...node.children()];
153152
} else {
154153
this._children.push(
155-
node instanceof FilterExpression && !node.negated() ? syntax.group(node) : node,
154+
node instanceof FilterExpression && !node.negated() ? operators.group(node) : node,
156155
);
157156
}
158157
return this;
@@ -239,7 +238,7 @@ export class FilterExpression<F> extends Expression<F> {
239238
e: (connector: FilterConnector = 'and') => new FilterExpression<N>({ connector }),
240239
}) as FilterExpression<N>;
241240
}
242-
return this._add(syntax.any(left, exp, alias));
241+
return this._add(operators.any(left, exp, alias));
243242
}
244243

245244
all<N>(
@@ -261,7 +260,7 @@ export class FilterExpression<F> extends Expression<F> {
261260
e: (connector: FilterConnector = 'and') => new FilterExpression<N>({ connector }),
262261
}) as FilterExpression<N>;
263262
}
264-
return this._add(syntax.all(left, exp, alias));
263+
return this._add(operators.all(left, exp, alias));
265264
}
266265

267266
count<N>(
@@ -274,7 +273,7 @@ export class FilterExpression<F> extends Expression<F> {
274273
isof(type: string): FilterExpression<F>;
275274
isof(left: F, type: string): FilterExpression<F>;
276275
isof(left: any, type?: string): FilterExpression<F> {
277-
return this._add(syntax.isof(left, type));
276+
return this._add(functions.isof(left, type));
278277
}
279278

280279
combine(exp: FilterExpression<F>, connector: FilterConnector = 'and'): FilterExpression<F> {

projects/angular-odata/src/lib/resources/query/expressions/orderby.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Parser, ParserOptions } from '../../../types';
22
import { Types } from '../../../utils';
33
import { QueryCustomType } from '../builder';
44
import { Expression } from './base';
5-
import { render, FieldFactory, Renderable, RenderableFactory } from './syntax';
5+
import { render, FieldFactory, Renderable, RenderableFactory, ODataOperators, operators } from './syntax';
66

77
export type OrderAttribute = 'asc' | 'desc';
88
export class OrderByField implements Renderable {
@@ -60,6 +60,7 @@ export class OrderByField implements Renderable {
6060
export type OrderByExpressionBuilder<T> = {
6161
t: Required<T>;
6262
e: () => OrderByExpression<T>;
63+
o: ODataOperators<T>;
6364
};
6465

6566
export class OrderByExpression<T> extends Expression<T> {
@@ -86,6 +87,7 @@ export class OrderByExpression<T> extends Expression<T> {
8687
{
8788
t: FieldFactory<Required<T>>(),
8889
e: () => new OrderByExpression<T>(),
90+
o: operators as ODataOperators<T>,
8991
},
9092
current ?? new OrderByExpression<T>(),
9193
) as OrderByExpression<T>;

projects/angular-odata/src/lib/resources/query/expressions/search.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Parser, ParserOptions } from '../../../types';
22
import { Types } from '../../../utils';
33
import { QueryCustomType } from '../builder';
44
import { Expression } from './base';
5-
import { render, syntax, Renderable, RenderableFactory } from './syntax';
5+
import { operators, render, Renderable, RenderableFactory } from './syntax';
66

77
export type SearchConnector = 'AND' | 'OR';
88

@@ -102,7 +102,7 @@ export class SearchExpression<T> extends Expression<T> {
102102
negated: this._negated,
103103
});
104104
if (exp.length() > 1) {
105-
children.push(syntax.group(exp));
105+
children.push(operators.group(exp));
106106
} else {
107107
children.push(exp);
108108
}
@@ -114,7 +114,7 @@ export class SearchExpression<T> extends Expression<T> {
114114
) {
115115
children = [...children, ...node.children()];
116116
} else {
117-
children.push(syntax.group(node));
117+
children.push(operators.group(node));
118118
}
119119
this._connector = connector;
120120
this._children = children;
@@ -126,7 +126,7 @@ export class SearchExpression<T> extends Expression<T> {
126126
this._children = [...this._children, ...node.children()];
127127
} else {
128128
this._children.push(
129-
node instanceof SearchExpression && !node.negated() ? syntax.group(node) : node,
129+
node instanceof SearchExpression && !node.negated() ? operators.group(node) : node,
130130
);
131131
}
132132
return this;

projects/angular-odata/src/lib/resources/query/expressions/select.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import { Parser, ParserOptions } from '../../../types';
22
import { QueryCustomType } from '../builder';
33
import { Expression } from './base';
4-
import { FieldFactory, Renderable, RenderableFactory } from './syntax';
4+
import { FieldFactory, ODataOperators, operators, Renderable, RenderableFactory } from './syntax';
55

66
export type SelectExpressionBuilder<T> = {
77
t: Required<T>;
88
e: () => SelectExpression<T>;
9+
o: ODataOperators<T>;
910
};
1011
export class SelectExpression<T> extends Expression<T> {
1112
constructor({
@@ -31,6 +32,7 @@ export class SelectExpression<T> extends Expression<T> {
3132
{
3233
t: FieldFactory<Required<T>>(),
3334
e: () => new SelectExpression<T>(),
35+
o: operators as ODataOperators<T>,
3436
},
3537
current ?? new SelectExpression<T>(),
3638
) as SelectExpression<T>;

projects/angular-odata/src/lib/resources/query/expressions/syntax.ts

Lines changed: 77 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ export const RenderableFactory = (value: any): Renderable => {
123123
return Lambda.fromJson(value);
124124
case 'Type':
125125
return Type.fromJson(value);
126+
case 'Casting':
127+
return Casting.fromJson(value);
126128
case 'Field':
127129
return FieldFactory(value['names']);
128130
default:
@@ -145,7 +147,7 @@ function applyMixins(derivedCtor: any, constructors: any[]) {
145147
}
146148

147149
export function render(
148-
value: any,
150+
value: any,
149151
{
150152
aliases,
151153
normalize,
@@ -163,7 +165,7 @@ export function render(
163165
} = {},
164166
): string | number | boolean | null {
165167
if (Types.isFunction(value)) {
166-
return render(value(syntax), {
168+
return render(value({o: operators, f: functions}), {
167169
aliases,
168170
normalize,
169171
prefix,
@@ -647,6 +649,14 @@ export class GroupingOperators<T> {
647649
}
648650
}
649651

652+
export class CastingOperators<T> {
653+
cast<N>(left: T | string, type?: string): N {
654+
return FieldFactory<Required<N>>([
655+
type !== undefined ? new Casting<T>(type, left) : new Casting<T>(left as string),
656+
]);
657+
}
658+
}
659+
650660
export type AggregateMethod = 'sum' | 'min' | 'max' | 'average' | 'countdistinct'; //, or with custom aggregation methods;
651661

652662
export class Aggregate<T> implements Renderable {
@@ -885,6 +895,63 @@ export class Type<T> implements Renderable {
885895
}
886896
}
887897

898+
export class Casting<T> implements Renderable {
899+
constructor(
900+
protected type: string,
901+
protected value?: any,
902+
) {}
903+
get [Symbol.toStringTag]() {
904+
return 'Casting';
905+
}
906+
907+
toJson() {
908+
return {
909+
$type: Types.rawType(this),
910+
type: this.type,
911+
value: this.value,
912+
};
913+
}
914+
915+
static fromJson<T>(json: { [name: string]: any }): Casting<T> {
916+
return new Casting<T>(json['type'], RenderableFactory(json['value']));
917+
}
918+
919+
render({
920+
aliases,
921+
escape,
922+
prefix,
923+
parser,
924+
options,
925+
}: {
926+
aliases?: QueryCustomType[];
927+
escape?: boolean;
928+
prefix?: string;
929+
parser?: Parser<T>;
930+
options?: ParserOptions;
931+
}): string {
932+
let value;
933+
if (this.value) {
934+
parser = resolve([this.value], parser);
935+
let [left, right] = encode([this.value], parser, options);
936+
937+
value = render(left, { aliases, escape, prefix, parser, options });
938+
}
939+
return value ? `${this.value}/${this.type}` : `${this.type}`;
940+
}
941+
942+
clone() {
943+
return new Type(this.type, Objects.clone(this.value));
944+
}
945+
946+
resolve(parser: any) {
947+
parser =
948+
parser instanceof ODataStructuredTypeFieldParser && parser.isStructuredType()
949+
? parser.structuredType()
950+
: parser;
951+
return parser?.findChildParser((p: any) => p.isTypeOf(this.type));
952+
}
953+
}
954+
888955
export class Lambda<T> implements Renderable {
889956
constructor(
890957
protected op: string,
@@ -968,12 +1035,18 @@ export class LambdaOperators<T> {
9681035

9691036
export class ODataOperators<T> {}
9701037
export interface ODataOperators<T>
971-
extends LogicalOperators<T>, ArithmeticOperators<T>, GroupingOperators<T>, LambdaOperators<T> {}
1038+
extends
1039+
LogicalOperators<T>,
1040+
ArithmeticOperators<T>,
1041+
GroupingOperators<T>,
1042+
CastingOperators<T>,
1043+
LambdaOperators<T> {}
9721044

9731045
applyMixins(ODataOperators, [
9741046
LogicalOperators,
9751047
ArithmeticOperators,
9761048
GroupingOperators,
1049+
CastingOperators,
9771050
LambdaOperators,
9781051
]);
9791052
export const operators: ODataOperators<any> = new ODataOperators<any>();
@@ -1006,11 +1079,4 @@ export class ODataTransformations<T> {}
10061079
export interface ODataTransformations<T> extends Transformations<T> {}
10071080

10081081
applyMixins(ODataTransformations, [Transformations]);
1009-
export const transformations: ODataTransformations<any> = new ODataTransformations<any>();
1010-
1011-
export class ODataSyntax<T> {}
1012-
export interface ODataSyntax<T>
1013-
extends ODataOperators<T>, ODataFunctions<T>, ODataTransformations<T> {}
1014-
applyMixins(ODataSyntax, [ODataOperators, ODataFunctions, ODataTransformations]);
1015-
1016-
export const syntax: ODataSyntax<any> = new ODataSyntax<any>();
1082+
export const transformations: ODataTransformations<any> = new ODataTransformations<any>();

0 commit comments

Comments
 (0)