Skip to content

Commit

Permalink
Added bound parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
ackava committed Jul 8, 2023
1 parent bc76f4a commit a6d9fff
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 38 deletions.
3 changes: 0 additions & 3 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@
"<node_internals>/**"
],
"program": "${workspaceFolder}/test.js",
"args": [
"no-db"
],
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
]
Expand Down
4 changes: 3 additions & 1 deletion src/model/EntityQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,9 @@ export default class EntityQuery<T = any>
})
] };

const query = this.context.driver.compiler.compileExpression(this, select);
const nq = new EntityQuery({ ... this, selectStatement: select });

const query = this.context.driver.compiler.compileExpression(nq, select);
const reader = await this.context.driver.executeReader(query);

try {
Expand Down
31 changes: 18 additions & 13 deletions src/query/ast/ExpressionToSql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,14 @@ export default class ExpressionToSql extends Visitor<ITextQuery> {
}

visitSelectStatement(e: SelectStatement): ITextQuery {
const fields = this.visitArray(e.fields, ",\n\t\t");
const orderBy = e.orderBy?.length > 0 ? prepare `\n\t\tORDER BY ${this.visitArray(e.orderBy)}` : "";
const source = this.visit(e.source);
const where = e.where ? prepare `\n\tWHERE ${this.visit(e.where)}` : "";
const as = e.as ? prepare ` AS ${this.compiler.quotedLiteral(e.as.name)}` : "";
const joins = e.joins?.length > 0 ? prepare `\n\t\t${this.visitArray(e.joins)}` : [];
const orderBy = e.orderBy?.length > 0 ? prepare `\n\t\tORDER BY ${this.visitArray(e.orderBy)}` : "";
const limit = e.limit > 0 ? prepare ` LIMIT ${Number(e.limit).toString()}` : "";
const offset = e.offset > 0 ? prepare ` OFFSET ${Number(e.offset).toString()}` : "";
const source = this.visit(e.source);
const as = e.as ? prepare ` AS ${this.compiler.quotedLiteral(e.as.name)}` : "";
const fields = this.visitArray(e.fields, ",\n\t\t");
return prepare `SELECT
${fields}
FROM ${source}${as}${joins}${where}${orderBy}${limit}${offset}`;
Expand Down Expand Up @@ -129,9 +129,10 @@ export default class ExpressionToSql extends Visitor<ITextQuery> {
const relatedModel = relation.relation.relatedEntity;
const relatedType = relatedModel.typeClass;
let query = this.source.context.query(relatedType);
let select = (query as EntityQuery).selectStatement;
let select = { ... (query as EntityQuery).selectStatement };

const replaceParam = this.createParameter(this.source.selectStatement, relatedModel.name[0]);
select.as = replaceParam;

this.targets.set(param1, { parameter: param1, model: relatedModel, replace: replaceParam });
this.targets.set(select.as, { parameter: param1, model: relatedModel, replace: replaceParam });
Expand Down Expand Up @@ -174,7 +175,7 @@ export default class ExpressionToSql extends Visitor<ITextQuery> {
where = join;
}

select = { ... select, where };
select.where = where;

select.fields = [
Identifier.create({ value: "1"})
Expand Down Expand Up @@ -233,7 +234,7 @@ export default class ExpressionToSql extends Visitor<ITextQuery> {
}
if (parameter.value) {
const value = parameter.value;
return [() => value];
return [() => value[chain[0]]];
}
return [ QueryParameter.create(() => parameter.name, this.compiler.quotedLiteral) , "." , chain.map((x) => this.compiler.quotedLiteral(x)).join(".")];
}
Expand Down Expand Up @@ -335,7 +336,9 @@ export default class ExpressionToSql extends Visitor<ITextQuery> {
}
const table = this.visit(e.source);
const where = this.visit(e.where);
const as = e.as ? prepare ` AS ${this.visit(e.as)}` : "";
const as = e.as ? prepare ` AS ${ e.as.type === "QuotedLiteral"
? this.compiler.quotedLiteral(e.as.literal)
: this.compiler.quotedLiteral((e.as as any).name)}` : "";
return prepare ` ${e.joinType || "LEFT"} JOIN ${table}${as} ON ${where}`;
}

Expand Down Expand Up @@ -432,7 +435,7 @@ export default class ExpressionToSql extends Visitor<ITextQuery> {
while(chain.length > 1) {
const property = chain.shift();
const propertyInfo = type.getProperty(property);
if (!propertyInfo.relation || propertyInfo.relation?.isCollection) {
if (!propertyInfo.relation || propertyInfo.relation.isCollection) {
return pc;
}

Expand All @@ -442,23 +445,25 @@ export default class ExpressionToSql extends Visitor<ITextQuery> {
return pc;
}

const { fkColumn } = relation;

const join = select.joins.find((x) => x.model === relation.relatedEntity);
if (!join) {
const joinType = relation.fkColumn.nullable ? "LEFT" : "INNER";
const joinType = fkColumn.nullable ? "LEFT" : "INNER";
const joinParameter = this.createParameter(select, relation.relatedEntity.name[0]);
select.joins.push(JoinExpression.create({
as: joinParameter,
joinType,
model: relation.relatedEntity,
source: Expression.quotedLiteral(relation.relatedEntity.name),
where: Expression.equal(
Expression.member(parameter, property),
Expression.member(joinParameter, relation.relatedKey)
Expression.member(parameter, fkColumn.columnName),
Expression.member(joinParameter, relation.relatedEntity.keys[0].columnName)
)
}));
parameter = joinParameter;
type = relation.relatedEntity;
this.targets.set(parameter, { parameter, model: type});
this.targets.set(parameter, { parameter, model: type, replace: parameter});
}
}

Expand Down
34 changes: 13 additions & 21 deletions src/tests/expressions/left-joins/child-joins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,42 +5,34 @@ import { assertSqlMatch, trimInternal } from "../trimInternal.js";
import PostgreSqlDriver from "../../../drivers/postgres/PostgreSqlDriver.js";

const sql1 = `SELECT
"P1"."productID",
"P1"."name",
"P1"."ownerID"
"P1"."productID","P1"."name","P1"."ownerID"
FROM "Products" AS "P1"
WHERE
EXISTS (SELECT
1
FROM "OrderItems" AS "O0"
WHERE
("P1"."productID" = "O0"."productID")
AND ("O0"."productID" = $1)
)
`;
WHERE EXISTS (SELECT
1
FROM "OrderItems" AS "O0"
WHERE ("P1"."productID" = "O0"."productID") AND ("O0"."productID" = $1))`;

const sql2 = `SELECT
"P1"."productID","P1"."name","P1"."ownerID"
FROM "Products" AS "P1"
WHERE EXISTS (SELECT
1
FROM "OrderItems" AS "O0"
WHERE ("P1"."productID" = "O0"."productID") AND ("O0"."productID" = $1)) AND EXISTS (SELECT
1
FROM "OrderItems" AS "O1"
WHERE ("P1"."productID" = "O1"."productID") AND ("O1"."amount" > $2))`;
WHERE ("P1"."productID" = "O1"."productID") AND ("O1"."productID" = $1)) AND EXISTS (SELECT
1
FROM "OrderItems" AS "O2"
WHERE ("P1"."productID" = "O2"."productID") AND ("O2"."amount" > $2))`;

const sql3 = `SELECT
"P1"."productID","P1"."name","P1"."ownerID"
FROM "Products" AS "P1"
WHERE EXISTS (SELECT
1
FROM "OrderItems" AS "O0"
WHERE ("P1"."productID" = "O0"."productID") AND ("O0"."productID" = $1)) AND EXISTS (SELECT
1
FROM "OrderItems" AS "O1"
INNER JOIN "Orders" AS "O2" ON "O1"."orderID" = "O2"."orderID"
WHERE ("P1"."productID" = "O1"."productID") AND ("O2"."orderDate" > $2))`;
WHERE ("P1"."productID" = "O1"."productID") AND ("O1"."productID" = $1)) AND EXISTS (SELECT
1
FROM "OrderItems" AS "O2"
WHERE ("P1"."productID" = "O2"."productID") AND ("O2"."order"."orderDate" > $2))`;

const productJoin = `SELECT
"P1"."productID","P1"."name","P1"."ownerID"
Expand Down

0 comments on commit a6d9fff

Please sign in to comment.