-
-
Notifications
You must be signed in to change notification settings - Fork 94
/
order-by.ts
111 lines (94 loc) · 3.25 KB
/
order-by.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import { IValue, _ISelection, _Transaction, _Explainer, _SelectExplanation, Stats, _IAggregation } from '../interfaces-private.ts';
import { FilterBase } from './transform-base.ts';
import { OrderByStatement, ExprCall } from 'https://deno.land/x/pgsql_ast_parser@12.0.1/mod.ts';
import { buildValue } from '../parser/expression-builder.ts';
import { nullIsh } from '../utils.ts';
import { withSelection } from '../parser/context.ts';
export function buildOrderBy(on: _ISelection, order: OrderByStatement[]) {
return new OrderBy(on, order);
}
class OrderBy<T> extends FilterBase<any> implements _IAggregation {
order: {
by: IValue<any>;
order: 'ASC' | 'DESC';
nullsLast: boolean;
}[];
get index() {
return null;
}
isAggregation() {
return this.selection.isAggregation();
}
getAggregation(name: string, call: ExprCall): IValue {
return this.asAggreg.getAggregation(name, call);
}
checkIfIsKey(got: IValue<any>): IValue<any> {
return this.asAggreg.checkIfIsKey(got);
}
private get asAggreg(): _IAggregation {
if (!this.selection.isAggregation()) {
throw new Error('Not an aggregation');
}
return this.selection;
}
entropy(t: _Transaction) {
const ret = this.selection.entropy(t);
// sort algorithm is n*log(n)
return ret * Math.log(ret + 1);
}
hasItem(raw: T, t: _Transaction): boolean {
return this.base.hasItem(raw, t);
}
constructor(private selection: _ISelection<T>, order: OrderByStatement[]) {
super(selection);
this.order = withSelection(selection,
() => order.map(x => {
const order = x.order ?? 'ASC';
return ({
by: buildValue(x.by),
order,
nullsLast: order === 'ASC' ? x.nulls !== 'FIRST' : x.nulls === 'LAST',
});
}));
}
stats(t: _Transaction): Stats | null {
return this.base.stats(t);
}
getIndex(...forValue: IValue<any>[]) {
// same index as underlying selection, given that ordering does not modify indices.
return this.base.getIndex(...forValue);
}
enumerate(t: _Transaction): Iterable<T> {
const all = [...this.base.enumerate(t)];
all.sort((a, b) => {
for (const o of this.order) {
const aval = o.by.get(a, t);
const bval = o.by.get(b, t);
const na = nullIsh(aval);
const nb = nullIsh(bval);
if (na && nb) {
continue;
}
if (na || nb) {
return nb === o.nullsLast ? -1 : 1;
}
if (o.by.type.equals(aval, bval)) {
continue;
}
if (o.by.type.gt(aval, bval)) {
return o.order === 'ASC' ? 1 : -1;
}
return o.order === 'ASC' ? -1 : 1;
}
return 0;
});
return all;
}
explain(e: _Explainer): _SelectExplanation {
return {
id: e.idFor(this),
_: 'orderBy',
of: this.selection.explain(e),
};
}
}