Add left join to query builder
This commit is contained in:
parent
e965303777
commit
e63b5d21fe
@ -5,6 +5,7 @@ import AuthProof from "../AuthProof";
|
|||||||
import Validator from "../../db/Validator";
|
import Validator from "../../db/Validator";
|
||||||
import User from "./User";
|
import User from "./User";
|
||||||
import argon2 from "argon2";
|
import argon2 from "argon2";
|
||||||
|
import {WhereTest} from "../../db/Query";
|
||||||
|
|
||||||
export default class MagicLink extends Model implements AuthProof {
|
export default class MagicLink extends Model implements AuthProof {
|
||||||
public static async bySessionID(sessionID: string, actionType?: string | string[]): Promise<MagicLink | null> {
|
public static async bySessionID(sessionID: string, actionType?: string | string[]): Promise<MagicLink | null> {
|
||||||
@ -13,7 +14,7 @@ export default class MagicLink extends Model implements AuthProof {
|
|||||||
if (typeof actionType === 'string') {
|
if (typeof actionType === 'string') {
|
||||||
query = query.where('action_type', actionType);
|
query = query.where('action_type', actionType);
|
||||||
} else {
|
} else {
|
||||||
query = query.whereIn('action_type', actionType);
|
query = query.where('action_type', actionType, WhereTest.IN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const links = await this.models<MagicLink>(query.first());
|
const links = await this.models<MagicLink>(query.first());
|
||||||
|
@ -8,23 +8,25 @@ export default class Query {
|
|||||||
|
|
||||||
public static update(table: string, data: {
|
public static update(table: string, data: {
|
||||||
[key: string]: any
|
[key: string]: any
|
||||||
}) {
|
}): Query {
|
||||||
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]));
|
fields.push(new UpdateFieldValue(key, data[key], false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new Query(QueryType.UPDATE, table, fields);
|
return new Query(QueryType.UPDATE, table, fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static delete(table: string) {
|
public static delete(table: string): Query {
|
||||||
return new Query(QueryType.DELETE, table);
|
return new Query(QueryType.DELETE, table);
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly type: QueryType;
|
private readonly type: QueryType;
|
||||||
private readonly table: string;
|
private readonly table: string;
|
||||||
private readonly fields: (string | SelectFieldValue | UpdateFieldValue)[];
|
private readonly fields: (string | SelectFieldValue | UpdateFieldValue)[];
|
||||||
|
private _leftJoin?: string;
|
||||||
|
private _leftJoinOn: WhereFieldValue[] = [];
|
||||||
private _where: WhereFieldValue[] = [];
|
private _where: WhereFieldValue[] = [];
|
||||||
private _limit?: number;
|
private _limit?: number;
|
||||||
private _offset?: number;
|
private _offset?: number;
|
||||||
@ -38,40 +40,38 @@ export default class Query {
|
|||||||
this.fields = fields || [];
|
this.fields = fields || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public where(field: string, value: string | Date | Query | any, operator: WhereOperator = WhereOperator.AND, test: WhereTest = WhereTest.EQUALS): Query {
|
public leftJoin(table: string): this {
|
||||||
this._where.push(new WhereFieldValue(field, value, operator, test));
|
this._leftJoin = table;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public whereNot(field: string, value: string | Date | Query | any, operator: WhereOperator = WhereOperator.AND): Query {
|
public on(field1: string, field2: string, test: WhereTest = WhereTest.EQ, operator: WhereOperator = WhereOperator.AND): this {
|
||||||
return this.where(field, value, operator, WhereTest.DIFFERENT);
|
this._leftJoinOn.push(new WhereFieldValue(field1, field2, true, test, operator));
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public orWhere(field: string, value: string | Date | Query | any): Query {
|
public where(field: string, value: string | Date | Query | any, test: WhereTest = WhereTest.EQ, operator: WhereOperator = WhereOperator.AND): this {
|
||||||
return this.where(field, value, WhereOperator.OR);
|
this._where.push(new WhereFieldValue(field, value, false, test, operator));
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public whereIn(field: string, value: any[]): Query {
|
public limit(limit: number, offset: number = 0): this {
|
||||||
return this.where(field, value, WhereOperator.AND, WhereTest.IN);
|
|
||||||
}
|
|
||||||
|
|
||||||
public limit(limit: number, offset: number = 0): Query {
|
|
||||||
this._limit = limit;
|
this._limit = limit;
|
||||||
this._offset = offset;
|
this._offset = offset;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public first(): Query {
|
public first(): this {
|
||||||
return this.limit(1);
|
return this.limit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public sortBy(field: string, direction: 'ASC' | 'DESC' = 'ASC'): Query {
|
public sortBy(field: string, direction: 'ASC' | 'DESC' = 'ASC'): this {
|
||||||
this._sortBy = field;
|
this._sortBy = field;
|
||||||
this._sortDirection = direction;
|
this._sortDirection = direction;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public withTotalRowCount(): Query {
|
public withTotalRowCount(): this {
|
||||||
this._foundRows = true;
|
this._foundRows = true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -81,6 +81,14 @@ export default class Query {
|
|||||||
|
|
||||||
let fields = this.fields?.join(',');
|
let fields = this.fields?.join(',');
|
||||||
|
|
||||||
|
let join = '';
|
||||||
|
if (this._leftJoin) {
|
||||||
|
join = `LEFT JOIN ${this._leftJoin} ON ${this._leftJoinOn[0]}`;
|
||||||
|
for (let i = 1; i < this._leftJoinOn.length; i++) {
|
||||||
|
join += this._leftJoinOn[i].toString(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let where = '';
|
let where = '';
|
||||||
if (this._where.length > 0) {
|
if (this._where.length > 0) {
|
||||||
where = `WHERE ${this._where[0]}`;
|
where = `WHERE ${this._where[0]}`;
|
||||||
@ -104,7 +112,7 @@ export default class Query {
|
|||||||
|
|
||||||
switch (this.type) {
|
switch (this.type) {
|
||||||
case QueryType.SELECT:
|
case QueryType.SELECT:
|
||||||
query = `SELECT ${this._foundRows ? 'SQL_CALC_FOUND_ROWS' : ''} ${fields} FROM ${this.table} ${where} ${orderBy} ${limit}`;
|
query = `SELECT ${this._foundRows ? 'SQL_CALC_FOUND_ROWS' : ''} ${fields} FROM ${this.table} ${join} ${where} ${orderBy} ${limit}`;
|
||||||
break;
|
break;
|
||||||
case QueryType.UPDATE:
|
case QueryType.UPDATE:
|
||||||
query = `UPDATE ${this.table} SET ${fields} ${where} ${orderBy} ${limit}`;
|
query = `UPDATE ${this.table} SET ${fields} ${where} ${orderBy} ${limit}`;
|
||||||
@ -152,28 +160,34 @@ export enum QueryType {
|
|||||||
DELETE,
|
DELETE,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum WhereOperator {
|
export enum WhereOperator {
|
||||||
AND = 'AND',
|
AND = 'AND',
|
||||||
OR = 'OR',
|
OR = 'OR',
|
||||||
}
|
}
|
||||||
|
|
||||||
enum WhereTest {
|
export enum WhereTest {
|
||||||
EQUALS = '=',
|
EQ = '=',
|
||||||
DIFFERENT = '!=',
|
NE = '!=',
|
||||||
|
GT = '>',
|
||||||
|
GE = '>=',
|
||||||
|
LT = '<',
|
||||||
|
LE = '<=',
|
||||||
IN = ' IN ',
|
IN = ' IN ',
|
||||||
}
|
}
|
||||||
|
|
||||||
class FieldValue {
|
class FieldValue {
|
||||||
protected readonly field: string;
|
protected readonly field: string;
|
||||||
protected value: any;
|
protected value: any;
|
||||||
|
protected raw: boolean;
|
||||||
|
|
||||||
constructor(field: string, value: any) {
|
constructor(field: string, value: any, raw: boolean) {
|
||||||
this.field = field;
|
this.field = field;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
|
this.raw = raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
public toString(first: boolean = true): string {
|
public toString(first: boolean = true): string {
|
||||||
return `${!first ? ',' : ''}${this.field}${this.test}${this.value instanceof Query ? this.value : (Array.isArray(this.value) ? '(?)' : '?')}`;
|
return `${!first ? ',' : ''}${this.field}${this.test}${this.raw || this.value instanceof Query ? this.value : (Array.isArray(this.value) ? '(?)' : '?')}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected get test(): string {
|
protected get test(): string {
|
||||||
@ -195,13 +209,13 @@ class UpdateFieldValue extends FieldValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class WhereFieldValue extends FieldValue {
|
class WhereFieldValue extends FieldValue {
|
||||||
private readonly operator: WhereOperator;
|
|
||||||
private readonly _test: WhereTest;
|
private readonly _test: WhereTest;
|
||||||
|
private readonly operator: WhereOperator;
|
||||||
|
|
||||||
constructor(field: string, value: any, operator: WhereOperator, test: WhereTest) {
|
constructor(field: string, value: any, raw: boolean, test: WhereTest, operator: WhereOperator) {
|
||||||
super(field, value);
|
super(field, value, raw);
|
||||||
this.operator = operator;
|
|
||||||
this._test = test;
|
this._test = test;
|
||||||
|
this.operator = operator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public toString(first: boolean = true): string {
|
public toString(first: boolean = true): string {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import Model from "./Model";
|
import Model from "./Model";
|
||||||
import Query from "./Query";
|
import Query, {WhereTest} from "./Query";
|
||||||
import {Connection} from "mysql";
|
import {Connection} from "mysql";
|
||||||
import {Type} from "../Utils";
|
import {Type} from "../Utils";
|
||||||
|
|
||||||
@ -184,7 +184,7 @@ export default class Validator<T> {
|
|||||||
} else {
|
} else {
|
||||||
query = (model instanceof Model ? <any>model.constructor : model).select('1').where(foreignKey, val);
|
query = (model instanceof Model ? <any>model.constructor : model).select('1').where(foreignKey, val);
|
||||||
}
|
}
|
||||||
if (model instanceof Model && typeof model.id === 'number') query = query.whereNot('id', model.id);
|
if (model instanceof Model && typeof model.id === 'number') query = query.where('id', model.id, WhereTest.NE);
|
||||||
return (await query.execute(c)).results.length === 0;
|
return (await query.execute(c)).results.length === 0;
|
||||||
},
|
},
|
||||||
throw: () => new AlreadyExistsValidationError((<any>model).table),
|
throw: () => new AlreadyExistsValidationError((<any>model).table),
|
||||||
|
Loading…
Reference in New Issue
Block a user