Skip to content

Commit

Permalink
fix: allow periods in parameter identifiers (#8022)
Browse files Browse the repository at this point in the history
updates the character set for parameter identifiers to include
periods.  also update the `setParameter` function on query builder
to validate these identifiers to ensure have explicit failures
when invalid keys are used
  • Loading branch information
imnotjames committed Aug 5, 2021
1 parent 768b4fe commit 4201938
Show file tree
Hide file tree
Showing 11 changed files with 74 additions and 8 deletions.
2 changes: 1 addition & 1 deletion src/driver/aurora-data-api/AuroraDataApiDriver.ts
Expand Up @@ -384,7 +384,7 @@ export class AuroraDataApiDriver implements Driver {
if (!parameters || !Object.keys(parameters).length)
return [sql, escapedParameters];

sql = sql.replace(/:(\.\.\.)?([A-Za-z0-9_]+)/g, (full, isArray: string, key: string): string => {
sql = sql.replace(/:(\.\.\.)?([A-Za-z0-9_.]+)/g, (full, isArray: string, key: string): string => {
if (!parameters.hasOwnProperty(key)) {
return full;
}
Expand Down
2 changes: 1 addition & 1 deletion src/driver/cockroachdb/CockroachDriver.ts
Expand Up @@ -388,7 +388,7 @@ export class CockroachDriver implements Driver {
if (!parameters || !Object.keys(parameters).length)
return [sql, escapedParameters];

sql = sql.replace(/:(\.\.\.)?([A-Za-z0-9_]+)/g, (full, isArray: string, key: string): string => {
sql = sql.replace(/:(\.\.\.)?([A-Za-z0-9_.]+)/g, (full, isArray: string, key: string): string => {
if (!parameters.hasOwnProperty(key)) {
return full;
}
Expand Down
2 changes: 1 addition & 1 deletion src/driver/mysql/MysqlDriver.ts
Expand Up @@ -403,7 +403,7 @@ export class MysqlDriver implements Driver {
if (!parameters || !Object.keys(parameters).length)
return [sql, escapedParameters];

sql = sql.replace(/:(\.\.\.)?([A-Za-z0-9_]+)/g, (full, isArray: string, key: string): string => {
sql = sql.replace(/:(\.\.\.)?([A-Za-z0-9_.]+)/g, (full, isArray: string, key: string): string => {
if (!parameters.hasOwnProperty(key)) {
return full;
}
Expand Down
2 changes: 1 addition & 1 deletion src/driver/oracle/OracleDriver.ts
Expand Up @@ -311,7 +311,7 @@ export class OracleDriver implements Driver {
if (!parameters || !Object.keys(parameters).length)
return [sql, escapedParameters];

sql = sql.replace(/:(\.\.\.)?([A-Za-z0-9_]+)/g, (full, isArray: string, key: string): string => {
sql = sql.replace(/:(\.\.\.)?([A-Za-z0-9_.]+)/g, (full, isArray: string, key: string): string => {
if (!parameters.hasOwnProperty(key)) {
return full;
}
Expand Down
2 changes: 1 addition & 1 deletion src/driver/postgres/PostgresDriver.ts
Expand Up @@ -628,7 +628,7 @@ export class PostgresDriver implements Driver {
if (!parameters || !Object.keys(parameters).length)
return [sql, escapedParameters];

sql = sql.replace(/:(\.\.\.)?([A-Za-z0-9_]+)/g, (full, isArray: string, key: string): string => {
sql = sql.replace(/:(\.\.\.)?([A-Za-z0-9_.]+)/g, (full, isArray: string, key: string): string => {
if (!parameters.hasOwnProperty(key)) {
return full;
}
Expand Down
2 changes: 1 addition & 1 deletion src/driver/sap/SapDriver.ts
Expand Up @@ -307,7 +307,7 @@ export class SapDriver implements Driver {
if (!parameters || !Object.keys(parameters).length)
return [sql, escapedParameters];

sql = sql.replace(/:(\.\.\.)?([A-Za-z0-9_]+)/g, (full, isArray: string, key: string): string => {
sql = sql.replace(/:(\.\.\.)?([A-Za-z0-9_.]+)/g, (full, isArray: string, key: string): string => {
if (!parameters.hasOwnProperty(key)) {
return full;
}
Expand Down
2 changes: 1 addition & 1 deletion src/driver/sqlite-abstract/AbstractSqliteDriver.ts
Expand Up @@ -372,7 +372,7 @@ export abstract class AbstractSqliteDriver implements Driver {
if (!parameters || !Object.keys(parameters).length)
return [sql, escapedParameters];

sql = sql.replace(/:(\.\.\.)?([A-Za-z0-9_]+)/g, (full, isArray: string, key: string): string => {
sql = sql.replace(/:(\.\.\.)?([A-Za-z0-9_.]+)/g, (full, isArray: string, key: string): string => {
if (!parameters.hasOwnProperty(key)) {
return full;
}
Expand Down
2 changes: 1 addition & 1 deletion src/driver/sqlserver/SqlServerDriver.ts
Expand Up @@ -316,7 +316,7 @@ export class SqlServerDriver implements Driver {
if (!parameters || !Object.keys(parameters).length)
return [sql, escapedParameters];

sql = sql.replace(/:(\.\.\.)?([A-Za-z0-9_]+)/g, (full, isArray: string, key: string): string => {
sql = sql.replace(/:(\.\.\.)?([A-Za-z0-9_.]+)/g, (full, isArray: string, key: string): string => {
if (!parameters.hasOwnProperty(key)) {
return full;
}
Expand Down
6 changes: 6 additions & 0 deletions src/query-builder/QueryBuilder.ts
Expand Up @@ -339,12 +339,18 @@ export abstract class QueryBuilder<Entity> {

/**
* Sets parameter name and its value.
*
* The key for this parametere may contain numbers, letters, underscores, or periods.
*/
setParameter(key: string, value: any): this {
if (value instanceof Function) {
throw new TypeORMError(`Function parameter isn't supported in the parameters. Please check "${key}" parameter.`);
}

if (!key.match(/^([A-Za-z0-9_.]+)$/)) {
throw new TypeORMError("QueryBuilder parameter keys may only contain numbers, letters, underscores, or periods.");
}

if (this.parentQueryBuilder) {
this.parentQueryBuilder.setParameter(key, value);
}
Expand Down
7 changes: 7 additions & 0 deletions test/functional/query-builder/parameters/entity/Example.ts
@@ -0,0 +1,7 @@
import { Entity, PrimaryColumn } from "../../../../../src";

@Entity()
export class Example {
@PrimaryColumn()
id: string
}
@@ -0,0 +1,53 @@
import "reflect-metadata";
import { Example } from "./entity/Example";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../../utils/test-utils";
import {expect} from "chai";
import { Connection } from "../../../../src";

describe("query builder > parameters", () => {

let connections: Connection[];
before(async () => connections = await createTestingConnections({
entities: [ Example ],
enabledDrivers: [ "sqlite" ]

}));
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));

it("should replace basic parameters when executing", () => Promise.all(connections.map(async connection => {
const repo = connection.getRepository(Example);

await repo.save({ id: 'bar' });

const example = await repo.createQueryBuilder()
.setParameter('foo', 'bar')
.where('example.id = :foo')
.getOne();

expect(example?.id).to.be.equal('bar')
})))

it("should prevent invalid characters from being used as identifiers", () => Promise.all(connections.map(async connection => {
const b = connection.createQueryBuilder();

expect(() => b.setParameter(':foo', 'bar')).to.throw();
expect(() => b.setParameter('@foo', 'bar')).to.throw();
expect(() => b.setParameter('😋', 'bar')).to.throw();
expect(() => b.setParameter('foo bar', 'bar')).to.throw();
})))

it("should allow periods in parameters", () => Promise.all(connections.map(async connection => {
const repo = connection.getRepository(Example);

await repo.save({ id: 'bar' });

const example = await repo.createQueryBuilder()
.setParameter('f.o.o', 'bar')
.where('example.id = :f.o.o')
.getOne();

expect(example?.id).to.be.equal('bar')
})))

});

0 comments on commit 4201938

Please sign in to comment.