Skip to content

Commit cb1cb2f

Browse files
committed
Cache moved inside compiler
1 parent df93fb8 commit cb1cb2f

File tree

4 files changed

+58
-62
lines changed

4 files changed

+58
-62
lines changed

src/compiler/QueryCompiler.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { PostgreSqlMethodTransformer } from "./postgres/PostgreSqlMethodTransfor
77
import EntityQuery from "../model/EntityQuery.js";
88
import { NamingConventions } from "./NamingConventions.js";
99
import RawQuery from "./RawQuery.js";
10+
import TimedCache from "../common/cache/TimedCache.js";
1011

1112
export class CompiledQuery {
1213
constructor(
@@ -28,6 +29,8 @@ export default class QueryCompiler {
2829

2930
public readonly sqlMethodTransformer: ISqlMethodTransformer;
3031

32+
private parserCache = new TimedCache<string, { params: ParameterExpression[], body: Expression, target: ParameterExpression }>();
33+
3134
constructor(
3235
{
3336
arrowToExpression = ArrowToExpression,
@@ -47,20 +50,25 @@ export default class QueryCompiler {
4750
this.sqlMethodTransformer = sqlMethodTransformer;
4851
}
4952

53+
public transform(fx: (p: any) => (x: any) => any, target?: ParameterExpression, outerParameter?: ParameterExpression) {
54+
const key = `${fx.toString()}-${target?.id ?? '_'}-${outerParameter?.id ?? '_'}`;
55+
return this.parserCache.getOrCreate(key, this, (k, self) => self.arrowToExpression.transform(fx, target, outerParameter));
56+
}
57+
5058
public execute<P = any, T = any>(parameters: P, fx: (p: P) => (x: T) => any, source?: EntityQuery) {
51-
const { params, target , body } = this.arrowToExpression.transform(fx, source?.selectStatement.sourceParameter);
59+
const { params, target , body } = this.transform(fx, source?.selectStatement.sourceParameter);
5260
const exp = new this.expressionToSql(source, params[0], target, this);
5361
const query = exp.visit(body);
5462
return this.invoke(query, parameters);
5563
}
5664

5765
public compile(source: EntityQuery, fx: (p) => (x) => any) {
58-
const { params, target , body } = this.arrowToExpression.transform(fx, source?.selectStatement.sourceParameter);
66+
const { params, target , body } = this.transform(fx, source?.selectStatement.sourceParameter);
5967
return { params, target, body };
6068
}
6169

6270
public compileToSql( source: EntityQuery , fx: (p) => (x) => any) {
63-
const { params, target , body } = this.arrowToExpression.transform(fx, source?.selectStatement.sourceParameter);
71+
const { params, target , body } = this.transform(fx, source?.selectStatement.sourceParameter);
6472
const exp = new this.expressionToSql(source, params[0], target, this);
6573
const textQuery = exp.visit(body);
6674
return new CompiledQuery(exp.root,exp.target,textQuery);

src/model/EntityQuery.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ export default class EntityQuery<T = any>
248248

249249
const pq = p as EntityQuery<any>;
250250

251-
const { body } = this.context.driver.compiler.arrowToExpression.transform(
251+
const { body } = this.context.driver.compiler.transform(
252252
fx,
253253
this.selectStatement.sourceParameter,
254254
pq.selectStatement.sourceParameter
@@ -522,7 +522,7 @@ export default class EntityQuery<T = any>
522522

523523
const selectForInclude = { ... this.selectStatement };
524524

525-
this.context.driver.compiler.compileExpression(this, selectForInclude)
525+
this.context.driver.compiler.compileExpression(this, selectForInclude);
526526

527527
// since we will be streaming results...
528528
// it is important that we load all the

src/query/expander/QueryExpander.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { NotSupportedError } from "../parser/NotSupportedError.js";
1212
export class QueryExpander {
1313
static expand(context: EntityContext, select: SelectStatement, p, filter: boolean) {
1414
const qe = new QueryExpander(context, select, filter);
15-
const expression = ArrowToExpression.transform(`(_____________________x) => ${p}` as any);
15+
const expression =context.driver.compiler.transform(`(_____________________x) => ${p}` as any);
1616
qe.expandNode("", select, select.model, expression.body as ExpressionType);
1717
return qe.include;
1818
}

src/query/parser/ArrowToExpression.ts

Lines changed: 44 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,9 @@ import { BabelVisitor } from "./BabelVisitor.js";
44
import * as bpe from "@babel/types";
55
import Restructure from "./Restructure.js";
66
import { NotSupportedError } from "./NotSupportedError.js";
7-
import TimedCache from "../../common/cache/TimedCache.js";
87

98
type IQueryFragment = string | { name?: string, value?: any };
109

11-
const parsedCache = new TimedCache<string, bpe.Node>();
12-
13-
const parameterCacheSymbol = Symbol("parameterCacheSymbol");
14-
1510
const defaultObject = {};
1611

1712
export default class ArrowToExpression extends BabelVisitor<Expression> {
@@ -25,10 +20,8 @@ export default class ArrowToExpression extends BabelVisitor<Expression> {
2520
*/
2621
public static transform(fx: (p: any) => (x: any) => any, target?: ParameterExpression, outerParameter?: ParameterExpression) {
2722
const key = fx.toString();
28-
const node = parsedCache.getOrCreate(key, fx, (k, f) => {
29-
const rs = new Restructure();
30-
return rs.visit(parseExpression(f.toString()));
31-
});
23+
const rs = new Restructure();
24+
const node = rs.visit(parseExpression(key));
3225
return this.transformUncached(node, target, outerParameter);
3326
}
3427

@@ -40,70 +33,65 @@ export default class ArrowToExpression extends BabelVisitor<Expression> {
4033
* @param target parameter to replace
4134
* @returns transformed node
4235
*/
43-
private static transformUncached(node: bpe.Node, tx?: ParameterExpression, outerParameter?: ParameterExpression): { params: Map<string, any>, body: Expression, target: ParameterExpression } {
36+
private static transformUncached(node: bpe.Node, target?: ParameterExpression, outerParameter?: ParameterExpression): { params: ParameterExpression[], body: Expression, target: ParameterExpression } {
4437

45-
const cache = node[parameterCacheSymbol] ??= new TimedCache<ParameterExpression,bpe.Node>();
46-
47-
return cache.getOrCreate(tx ?? defaultObject, tx, (_, target) => {
48-
49-
if (node.type !== "ArrowFunctionExpression") {
50-
throw new Error("Expecting an arrow function");
51-
}
38+
if (node.type !== "ArrowFunctionExpression") {
39+
throw new Error("Expecting an arrow function");
40+
}
5241

53-
const paramSet = new Map<string, any>();
42+
const paramSet = new Map<string, any>();
5443

55-
let firstOuterParam = null;
44+
let firstOuterParam = null;
5645

57-
const params = [];
46+
const params = [];
5847

59-
for (const iterator of node.params) {
60-
if (iterator.type !== "Identifier") {
61-
throw new Error("Expecting an identifier");
62-
}
63-
if (!firstOuterParam && outerParameter) {
64-
firstOuterParam = iterator.name;
65-
paramSet.set(iterator.name, outerParameter);
66-
params.push(outerParameter);
67-
continue;
68-
}
69-
const p1 = ParameterExpression.create({ name: iterator.name });
70-
paramSet.set(iterator.name, p1);
71-
params.push(p1);
48+
for (const iterator of node.params) {
49+
if (iterator.type !== "Identifier") {
50+
throw new Error("Expecting an identifier");
7251
}
73-
74-
if (outerParameter && firstOuterParam) {
75-
paramSet.set(firstOuterParam, outerParameter);
52+
if (!firstOuterParam && outerParameter) {
53+
firstOuterParam = iterator.name;
54+
paramSet.set(iterator.name, outerParameter);
55+
params.push(outerParameter);
56+
continue;
7657
}
58+
const p1 = ParameterExpression.create({ name: iterator.name });
59+
paramSet.set(iterator.name, p1);
60+
params.push(p1);
61+
}
7762

78-
let body = node.body;
79-
if (body.type !== "ArrowFunctionExpression") {
80-
throw new Error("Expecting an arrow function");
81-
}
63+
if (outerParameter && firstOuterParam) {
64+
paramSet.set(firstOuterParam, outerParameter);
65+
}
8266

83-
const firstTarget = body.params[0];
67+
let body = node.body;
68+
if (body.type !== "ArrowFunctionExpression") {
69+
throw new Error("Expecting an arrow function");
70+
}
8471

85-
let name = "____x";
72+
const firstTarget = body.params[0];
8673

87-
if (firstTarget) {
74+
let name = "____x";
8875

89-
if (firstTarget.type !== "Identifier") {
90-
throw new Error("Expecting an identifier");
91-
}
92-
name = firstTarget.name;
76+
if (firstTarget) {
77+
78+
if (firstTarget.type !== "Identifier") {
79+
throw new Error("Expecting an identifier");
9380
}
81+
name = firstTarget.name;
82+
}
9483

9584

96-
target ??= ParameterExpression.create({ name});
85+
target ??= ParameterExpression.create({ name});
9786

98-
body = body.body;
87+
body = body.body;
9988

100-
const visitor = new this(paramSet, target, name);
101-
return {
102-
params,
103-
target,
104-
body: visitor.visit(body)
105-
};
106-
});
89+
const visitor = new this(paramSet, target, name);
90+
return {
91+
params,
92+
target,
93+
body: visitor.visit(body)
94+
};
10795
}
10896

10997
public readonly leftJoins: string[] = [];

0 commit comments

Comments
 (0)