Improve field disambiguation to allow raw values when starting with ",',`

This commit is contained in:
Alice Gaudon 2020-09-06 15:38:54 +02:00
parent c2abb1c87a
commit 17685a44be
3 changed files with 28 additions and 17 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "wms-core", "name": "wms-core",
"version": "0.22.0-rc.4", "version": "0.22.0-rc.6",
"description": "Node web application framework and toolbelt.", "description": "Node web application framework and toolbelt.",
"repository": "https://gitlab.com/ArisuOngaku/wms-core", "repository": "https://gitlab.com/ArisuOngaku/wms-core",
"author": "Alice Gaudon <alice@gaudon.pro>", "author": "Alice Gaudon <alice@gaudon.pro>",

View File

@ -18,7 +18,7 @@ export default class ModelQuery<M extends Model> implements WhereFieldConsumer<M
const fields = []; const fields = [];
for (let key in data) { for (let key in data) {
if (data.hasOwnProperty(key)) { if (data.hasOwnProperty(key)) {
fields.push(new UpdateFieldValue(key, data[key], false)); fields.push(new UpdateFieldValue(inputToFieldOrValue(key, factory.table), data[key], false));
} }
} }
return new ModelQuery(QueryType.UPDATE, factory, fields); return new ModelQuery(QueryType.UPDATE, factory, fields);
@ -59,7 +59,7 @@ export default class ModelQuery<M extends Model> implements WhereFieldConsumer<M
} }
public on(field1: string, field2: string, test: WhereTest = WhereTest.EQ, operator: WhereOperator = WhereOperator.AND): this { public on(field1: string, field2: string, test: WhereTest = WhereTest.EQ, operator: WhereOperator = WhereOperator.AND): this {
this._leftJoinOn.push(new WhereFieldValue(field1, field2.split('.').map(v => `\`${v}\``).join('.'), true, test, operator)); this._leftJoinOn.push(new WhereFieldValue(inputToFieldOrValue(field1), inputToFieldOrValue(field2), true, test, operator));
return this; return this;
} }
@ -96,7 +96,7 @@ export default class ModelQuery<M extends Model> implements WhereFieldConsumer<M
} }
public sortBy(field: string, direction: SortDirection = 'ASC', raw: boolean = false): this { public sortBy(field: string, direction: SortDirection = 'ASC', raw: boolean = false): this {
this._sortBy = raw ? field : field.split('.').map(v => v.startsWith('`') ? v : `\`${v}\``).join('.'); this._sortBy = raw ? field : inputToFieldOrValue(field);
this._sortDirection = direction; this._sortDirection = direction;
return this; return this;
} }
@ -119,7 +119,7 @@ export default class ModelQuery<M extends Model> implements WhereFieldConsumer<M
this._union = { this._union = {
query: query, query: query,
sortBy: raw ? sortBy : sortBy.split('.').map(v => v.startsWith('`') ? v : `\`${v}\``).join('.'), sortBy: raw ? sortBy : inputToFieldOrValue(sortBy),
direction: direction, direction: direction,
limit: limit, limit: limit,
}; };
@ -138,18 +138,11 @@ export default class ModelQuery<M extends Model> implements WhereFieldConsumer<M
if (this._pivot) this.fields.push(...this._pivot); if (this._pivot) this.fields.push(...this._pivot);
// Prevent wildcard and fields from conflicting // Prevent wildcard and fields from conflicting
let fieldArray = this.fields.map(f => { let fields = this.fields.map(f => {
let field = f.toString(); const field = f.toString();
if (field.startsWith('(')) return f; // Skip sub-queries if (field.startsWith('(')) return f; // Skip sub-queries
return inputToFieldOrValue(field, this.table);
let parts = field.split('.'); }).join(',');
if (parts.length === 1) parts = [this.table, field]; // Add table disambiguation
return parts.map(v => v.startsWith('`') || v === '*' ? v : `\`${v}\``).join('.');
});
let fields = fieldArray.join(',');
let join = ''; let join = '';
if (this._leftJoin) { if (this._leftJoin) {
@ -316,6 +309,17 @@ export default class ModelQuery<M extends Model> implements WhereFieldConsumer<M
} }
} }
function inputToFieldOrValue(input: string, addTable?: string): string {
if (input.startsWith('`') || input.startsWith('"') || input.startsWith("'")) {
return input;
}
let parts = input.split('.');
if (addTable && parts.length === 1) parts = [addTable, input]; // Add table disambiguation
return parts.map(v => v === '*' ? v : `\`${v}\``).join('.');
}
export interface ModelQueryResult<M extends Model> extends Array<M> { export interface ModelQueryResult<M extends Model> extends Array<M> {
originalData?: any[]; originalData?: any[];
pagination?: Pagination<M>; pagination?: Pagination<M>;
@ -357,7 +361,7 @@ class FieldValue {
public toString(first: boolean = true): string { public toString(first: boolean = true): string {
const valueStr = (this.raw || this.value === null || this.value instanceof ModelQuery) ? this.value : const valueStr = (this.raw || this.value === null || this.value instanceof ModelQuery) ? this.value :
(Array.isArray(this.value) ? `(${'?'.repeat(this.value.length).split('').join(',')})` : '?'); (Array.isArray(this.value) ? `(${'?'.repeat(this.value.length).split('').join(',')})` : '?');
let field = this.field.split('.').map(p => `\`${p}\``).join('.'); let field = inputToFieldOrValue(this.field);
return `${first ? '' : ','}${field}${this.test}${valueStr}`; return `${first ? '' : ','}${field}${this.test}${valueStr}`;
} }

View File

@ -3,6 +3,13 @@ import ModelFactory from "../src/db/ModelFactory";
import Model from "../src/db/Model"; import Model from "../src/db/Model";
describe('Test ModelQuery', () => { describe('Test ModelQuery', () => {
test('select', () => {
const query = ModelQuery.select({table: 'model'} as unknown as ModelFactory<Model>, 'f1', '"Test" as f2')
.where('f4', 'v4');
expect(query.toString(true)).toBe('SELECT `model`.`f1`,"Test" as f2 FROM `model` WHERE `f4`=?');
expect(query.variables).toStrictEqual(['v4']);
});
test('order by', () => { test('order by', () => {
const query = ModelQuery.select({table: 'model'} as unknown as ModelFactory<Model>) const query = ModelQuery.select({table: 'model'} as unknown as ModelFactory<Model>)
.sortBy('model.f2', 'ASC'); .sortBy('model.f2', 'ASC');