@axiosleo/orm-mysql 0.9.4 → 0.9.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vscode/extensions.json +15 -0
- package/README.md +1 -0
- package/bin/orm-mysql.js +1 -1
- package/index.d.ts +17 -21
- package/package.json +15 -13
- package/src/builder.js +54 -35
- package/src/migration.d.ts +11 -0
- package/src/query.js +23 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"recommendations": [
|
|
3
|
+
"vscode-icons-team.vscode-icons",
|
|
4
|
+
"formulahendry.docker-extension-pack",
|
|
5
|
+
"mikestead.dotenv",
|
|
6
|
+
"dbaeumer.vscode-eslint",
|
|
7
|
+
"codezombiech.gitignore",
|
|
8
|
+
"eamodio.gitlens",
|
|
9
|
+
"esbenp.prettier-vscode",
|
|
10
|
+
"wayou.vscode-todo-highlight",
|
|
11
|
+
"vue.vscode-typescript-vue-plugin",
|
|
12
|
+
"octref.vetur",
|
|
13
|
+
"pflannery.vscode-versionlens"
|
|
14
|
+
]
|
|
15
|
+
}
|
package/README.md
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
[](https://npmjs.org/package/@axiosleo/orm-mysql)
|
|
5
5
|
[](https://npmjs.org/package/@axiosleo/orm-mysql)
|
|
6
|
+
[](http://nodejs.org/download/)
|
|
6
7
|
[](LICENSE)
|
|
7
8
|
[](https://app.fossa.com/projects/git%2Bgithub.com%2FAxiosLeo%2Fnode-orm-mysql?ref=badge_shield)
|
|
8
9
|
|
package/bin/orm-mysql.js
CHANGED
package/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
PoolOptions,
|
|
6
6
|
QueryOptions,
|
|
7
7
|
RowDataPacket,
|
|
8
|
+
ResultSetHeader,
|
|
8
9
|
ConnectionOptions
|
|
9
10
|
} from 'mysql2';
|
|
10
11
|
|
|
@@ -12,6 +13,8 @@ import {
|
|
|
12
13
|
Connection as PromiseConnection,
|
|
13
14
|
} from 'mysql2/promise';
|
|
14
15
|
|
|
16
|
+
type MySQLQueryResult = OkPacket | ResultSetHeader;
|
|
17
|
+
|
|
15
18
|
export type Clients = {
|
|
16
19
|
[key: string]: Connection | Pool
|
|
17
20
|
}
|
|
@@ -34,13 +37,15 @@ export interface OrderByOptions {
|
|
|
34
37
|
}
|
|
35
38
|
|
|
36
39
|
export type OperatorType = 'select' | 'find' | 'insert' | 'update' | 'delete' | 'count';
|
|
40
|
+
export type CascadeType = 'RESTRICT' | 'CASCADE' | 'SET NULL' | 'NO ACTION' | 'restrict' | 'cascade' | 'set null' | 'no action';
|
|
37
41
|
|
|
38
42
|
export interface JoinOption {
|
|
39
43
|
table: string | Query;
|
|
40
44
|
table_alias?: string;
|
|
41
|
-
self_column
|
|
42
|
-
foreign_column
|
|
45
|
+
self_column?: string;
|
|
46
|
+
foreign_column?: string;
|
|
43
47
|
join_type?: 'left' | 'right' | 'inner';
|
|
48
|
+
on?: string;
|
|
44
49
|
}
|
|
45
50
|
|
|
46
51
|
export interface TableOption {
|
|
@@ -54,7 +59,7 @@ export type QueryOperatorBaseOptions = {
|
|
|
54
59
|
};
|
|
55
60
|
|
|
56
61
|
export type AttrSubQuery = () => Query;
|
|
57
|
-
export type Attr = string | AttrSubQuery;
|
|
62
|
+
export type Attr = string | AttrSubQuery | Query;
|
|
58
63
|
|
|
59
64
|
export type QueryOperatorOptions = QueryOperatorBaseOptions & {
|
|
60
65
|
conditions: WhereOptions[];
|
|
@@ -110,7 +115,7 @@ export declare class Query {
|
|
|
110
115
|
join(opt: JoinOption): this;
|
|
111
116
|
}
|
|
112
117
|
|
|
113
|
-
export type QueryResult = any | undefined | RowDataPacket[] | RowDataPacket |
|
|
118
|
+
export type QueryResult = any | undefined | RowDataPacket[] | RowDataPacket | MySQLQueryResult;
|
|
114
119
|
|
|
115
120
|
export declare class QueryOperator extends Query {
|
|
116
121
|
conn: Connection | Pool;
|
|
@@ -126,9 +131,9 @@ export declare class QueryOperator extends Query {
|
|
|
126
131
|
|
|
127
132
|
find<T>(): Promise<T>;
|
|
128
133
|
|
|
129
|
-
update(data?: any): Promise<
|
|
134
|
+
update(data?: any): Promise<MySQLQueryResult>;
|
|
130
135
|
|
|
131
|
-
insert(data?: any): Promise<
|
|
136
|
+
insert(data?: any): Promise<MySQLQueryResult>;
|
|
132
137
|
|
|
133
138
|
count(): Promise<number>;
|
|
134
139
|
|
|
@@ -137,7 +142,7 @@ export declare class QueryOperator extends Query {
|
|
|
137
142
|
* @param id
|
|
138
143
|
* @param index_field_name default is 'id'
|
|
139
144
|
*/
|
|
140
|
-
delete(id?: number, index_field_name?: string): Promise<
|
|
145
|
+
delete(id?: number, index_field_name?: string): Promise<MySQLQueryResult>;
|
|
141
146
|
}
|
|
142
147
|
|
|
143
148
|
export declare class QueryHandler {
|
|
@@ -165,7 +170,7 @@ export declare class QueryHandler {
|
|
|
165
170
|
* @param data
|
|
166
171
|
* @param condition
|
|
167
172
|
*/
|
|
168
|
-
upsert(tableName: string, data: any, condition: Record<string, ConditionValueType>): Promise<
|
|
173
|
+
upsert(tableName: string, data: any, condition: Record<string, ConditionValueType>): Promise<MySQLQueryResult>;
|
|
169
174
|
|
|
170
175
|
/**
|
|
171
176
|
* @param database default is options.database
|
|
@@ -211,7 +216,7 @@ export declare class TransactionHandler {
|
|
|
211
216
|
|
|
212
217
|
rollback(): Promise<void>;
|
|
213
218
|
|
|
214
|
-
upsert(tableName: string, data: any, condition: Record<string, ConditionValueType>): Promise<
|
|
219
|
+
upsert(tableName: string, data: any, condition: Record<string, ConditionValueType>): Promise<MySQLQueryResult>;
|
|
215
220
|
}
|
|
216
221
|
|
|
217
222
|
export function createClient(options: ConnectionOptions, name?: string | null | undefined): Connection;
|
|
@@ -319,12 +324,6 @@ interface CreateIndexOptions {
|
|
|
319
324
|
spatial?: boolean
|
|
320
325
|
}
|
|
321
326
|
|
|
322
|
-
export type ManageBuilderOptions = {
|
|
323
|
-
operator: 'create' | 'drop' | 'alter';
|
|
324
|
-
columns: Record<string, ColumnItem>;
|
|
325
|
-
target: 'table' | 'column' | 'index' | 'foreign_key';
|
|
326
|
-
}
|
|
327
|
-
|
|
328
327
|
export declare class MigrationInterface {
|
|
329
328
|
|
|
330
329
|
/**
|
|
@@ -348,7 +347,7 @@ export declare class MigrationInterface {
|
|
|
348
347
|
unsigned?: boolean,
|
|
349
348
|
allowNull?: boolean,
|
|
350
349
|
default?: string | number | boolean | null | 'timestamp',
|
|
351
|
-
onUpdate?:
|
|
350
|
+
onUpdate?: boolean,
|
|
352
351
|
comment?: string,
|
|
353
352
|
autoIncrement?: boolean,
|
|
354
353
|
primaryKey?: boolean,
|
|
@@ -370,8 +369,8 @@ export declare class MigrationInterface {
|
|
|
370
369
|
reference: {
|
|
371
370
|
tableName: string,
|
|
372
371
|
columnName: string,
|
|
373
|
-
onDelete?:
|
|
374
|
-
onUpdate?:
|
|
372
|
+
onDelete?: CascadeType,
|
|
373
|
+
onUpdate?: CascadeType,
|
|
375
374
|
}
|
|
376
375
|
}): void;
|
|
377
376
|
|
|
@@ -383,6 +382,3 @@ export declare class MigrationInterface {
|
|
|
383
382
|
|
|
384
383
|
dropForeignKey(foreign_key: string, tableName: string): void;
|
|
385
384
|
}
|
|
386
|
-
|
|
387
|
-
export declare function up(migration: MigrationInterface): Promise<void>;
|
|
388
|
-
export declare function down(migration: MigrationInterface): Promise<void>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axiosleo/orm-mysql",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.6",
|
|
4
4
|
"description": "MySQL ORM tool",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mysql",
|
|
@@ -19,12 +19,15 @@
|
|
|
19
19
|
"test-cov": "nyc -r=lcov -r=html -r=text -r=json mocha -t 10000 -R spec tests/*.tests.js",
|
|
20
20
|
"test-one": "mocha --reporter spec --timeout 3000 ",
|
|
21
21
|
"ci": "npm run lint && npm run test-cov",
|
|
22
|
-
"clear": "rm -rf ./nyc_output ./coverage"
|
|
22
|
+
"clear": "rm -rf ./nyc_output ./coverage && rm -rf ./node_modules && npm cache clean --force"
|
|
23
23
|
},
|
|
24
24
|
"license": "MIT",
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=16.0.0"
|
|
27
|
+
},
|
|
25
28
|
"dependencies": {
|
|
26
|
-
"@axiosleo/cli-tool": "^1.6.
|
|
27
|
-
"mysql2": "^
|
|
29
|
+
"@axiosleo/cli-tool": "^1.6.1",
|
|
30
|
+
"mysql2": "^3.9.1",
|
|
28
31
|
"validatorjs": "^3.22.1"
|
|
29
32
|
},
|
|
30
33
|
"repository": {
|
|
@@ -32,19 +35,18 @@
|
|
|
32
35
|
"url": "https://github.com/AxiosLeo/node-orm-mysql"
|
|
33
36
|
},
|
|
34
37
|
"devDependencies": {
|
|
35
|
-
"@types/node": "^20.
|
|
36
|
-
"chai": "^
|
|
37
|
-
"
|
|
38
|
-
"eslint": "^7.0",
|
|
38
|
+
"@types/node": "^20.11.16",
|
|
39
|
+
"chai": "^5.0.3",
|
|
40
|
+
"eslint": "^8.56.0",
|
|
39
41
|
"expect.js": "^0.3.1",
|
|
40
|
-
"has-flag": "^
|
|
41
|
-
"mm": "^3.
|
|
42
|
-
"mocha": "^
|
|
42
|
+
"has-flag": "^5.0.1",
|
|
43
|
+
"mm": "^3.4.0",
|
|
44
|
+
"mocha": "^10.2.0",
|
|
43
45
|
"mocha-sinon": "^2.1.2",
|
|
44
46
|
"nyc": "^15.1.0",
|
|
45
47
|
"pre-commit": "^1.2.2",
|
|
46
|
-
"sinon": "^
|
|
47
|
-
"typescript": "^
|
|
48
|
+
"sinon": "^17.0.1",
|
|
49
|
+
"typescript": "^5.3.3"
|
|
48
50
|
},
|
|
49
51
|
"pre-commit": {
|
|
50
52
|
"silent": false,
|
package/src/builder.js
CHANGED
|
@@ -17,6 +17,8 @@ const emit = (arr, res) => {
|
|
|
17
17
|
}
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
+
const operations = ['find', 'select', 'insert', 'update', 'delete', 'count', 'manage'];
|
|
21
|
+
|
|
20
22
|
class Builder {
|
|
21
23
|
/**
|
|
22
24
|
* @param {import('../index').QueryOperatorOptions} options
|
|
@@ -35,12 +37,15 @@ class Builder {
|
|
|
35
37
|
options.attrs = options.attrs || [];
|
|
36
38
|
const attrs = options.attrs.map((attr) => {
|
|
37
39
|
if (attr instanceof Function) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
+
attr = attr();
|
|
41
|
+
}
|
|
42
|
+
if (attr instanceof Query) {
|
|
43
|
+
const builder = new Builder(attr.options);
|
|
44
|
+
this.values = this.values.concat(builder.values);
|
|
40
45
|
let s = `(${builder.sql})`;
|
|
41
|
-
if (
|
|
42
|
-
return
|
|
43
|
-
: s + ' AS ' + this._buildFieldKey(
|
|
46
|
+
if (attr.alias) {
|
|
47
|
+
return attr.alias.indexOf(' ') > -1 ? s + ' ' + this._buildFieldKey(attr.alias)
|
|
48
|
+
: s + ' AS ' + this._buildFieldKey(attr.alias);
|
|
44
49
|
}
|
|
45
50
|
return s;
|
|
46
51
|
}
|
|
@@ -48,9 +53,9 @@ class Builder {
|
|
|
48
53
|
});
|
|
49
54
|
emit(tmp, `SELECT ${attrs.length ? attrs.map((a) => this._buildFieldKey(a)).join(',') : '*'} FROM ${this._buildTables(options.tables)}`);
|
|
50
55
|
emit(tmp, this._buildJoins(options.joins));
|
|
51
|
-
emit(tmp, this.
|
|
56
|
+
emit(tmp, this._buildCondition(options.conditions));
|
|
52
57
|
emit(tmp, this._buildOrders(options.orders));
|
|
53
|
-
emit(tmp, this.
|
|
58
|
+
emit(tmp, this._buildPagination(options.pageLimit, options.pageOffset));
|
|
54
59
|
if (options.having && options.having.length && !options.groupField.length) {
|
|
55
60
|
throw new Error('having is not allowed without "GROUP BY"');
|
|
56
61
|
}
|
|
@@ -70,13 +75,16 @@ class Builder {
|
|
|
70
75
|
break;
|
|
71
76
|
}
|
|
72
77
|
case 'update': {
|
|
78
|
+
if (is.invalid(options.data)) {
|
|
79
|
+
throw new Error('Data is required for update operation');
|
|
80
|
+
}
|
|
73
81
|
const fields = this._buildValues(options.data);
|
|
74
82
|
emit(tmp, `UPDATE ${this._buildTables(options.tables)}`);
|
|
75
83
|
emit(tmp, `SET ${fields.map((f) => `\`${f}\` = ?`).join(',')}`);
|
|
76
84
|
if (!options.conditions.length) {
|
|
77
85
|
throw new Error('At least one condition is required for update operation');
|
|
78
86
|
}
|
|
79
|
-
emit(tmp, this.
|
|
87
|
+
emit(tmp, this._buildCondition(options.conditions));
|
|
80
88
|
sql = tmp.join(' ');
|
|
81
89
|
break;
|
|
82
90
|
}
|
|
@@ -85,16 +93,20 @@ class Builder {
|
|
|
85
93
|
if (!options.conditions.length) {
|
|
86
94
|
throw new Error('At least one where condition is required for delete operation');
|
|
87
95
|
}
|
|
88
|
-
emit(tmp, this.
|
|
96
|
+
emit(tmp, this._buildCondition(options.conditions));
|
|
89
97
|
sql = tmp.join(' ');
|
|
90
98
|
break;
|
|
91
99
|
}
|
|
92
100
|
case 'count': {
|
|
93
|
-
|
|
101
|
+
let fieldName = 'count';
|
|
102
|
+
if (!is.empty(options.attrs)) {
|
|
103
|
+
fieldName = this._buildFieldKey(options.attrs[0]);
|
|
104
|
+
}
|
|
105
|
+
emit(tmp, `SELECT COUNT(*) AS ${fieldName} FROM ${this._buildTables(options.tables)}`);
|
|
94
106
|
emit(tmp, this._buildJoins(options.joins));
|
|
95
|
-
emit(tmp, this.
|
|
107
|
+
emit(tmp, this._buildCondition(options.conditions));
|
|
96
108
|
if (options.having && options.having.length && !options.groupField.length) {
|
|
97
|
-
throw new Error('
|
|
109
|
+
throw new Error('"HAVING" is not allowed without "GROUP BY"');
|
|
98
110
|
}
|
|
99
111
|
emit(tmp, this._buildGroupField(options.groupField));
|
|
100
112
|
emit(tmp, this._buildHaving(options.having));
|
|
@@ -122,7 +134,7 @@ class Builder {
|
|
|
122
134
|
if (!having || !having.length) {
|
|
123
135
|
return '';
|
|
124
136
|
}
|
|
125
|
-
return this.
|
|
137
|
+
return this._buildCondition(having, 'HAVING ');
|
|
126
138
|
}
|
|
127
139
|
|
|
128
140
|
_buildJoins(joins = []) {
|
|
@@ -130,7 +142,7 @@ class Builder {
|
|
|
130
142
|
let { table, alias, self_column, foreign_column, join_type } = j;
|
|
131
143
|
if (table instanceof Query) {
|
|
132
144
|
if (!alias) {
|
|
133
|
-
throw new Error('Alias is required for
|
|
145
|
+
throw new Error('Alias is required for subQuery');
|
|
134
146
|
}
|
|
135
147
|
const builder = new Builder(table.options);
|
|
136
148
|
this.values = this.values.concat(builder.values);
|
|
@@ -153,7 +165,11 @@ class Builder {
|
|
|
153
165
|
sql = 'INNER JOIN ';
|
|
154
166
|
break;
|
|
155
167
|
}
|
|
156
|
-
|
|
168
|
+
if (j.on) {
|
|
169
|
+
sql += `${table} ON ${j.on}`;
|
|
170
|
+
} else {
|
|
171
|
+
sql += `${table} ON ${this._buildFieldWithTableName(self_column)} = ${this._buildFieldWithTableName(foreign_column)}`;
|
|
172
|
+
}
|
|
157
173
|
return sql;
|
|
158
174
|
}).join(' ');
|
|
159
175
|
}
|
|
@@ -186,7 +202,7 @@ class Builder {
|
|
|
186
202
|
}).join(' , ');
|
|
187
203
|
}
|
|
188
204
|
|
|
189
|
-
|
|
205
|
+
_buildPagination(limit, offset) {
|
|
190
206
|
let sql = '';
|
|
191
207
|
if (limit) {
|
|
192
208
|
sql += ` LIMIT ${limit}`;
|
|
@@ -227,7 +243,7 @@ class Builder {
|
|
|
227
243
|
return null;
|
|
228
244
|
}
|
|
229
245
|
|
|
230
|
-
|
|
246
|
+
_buildConditionIn(condition, isNot = false) {
|
|
231
247
|
if (Array.isArray(condition.value) && !condition.value.length) {
|
|
232
248
|
throw new Error('Value must not be empty for "IN" condition');
|
|
233
249
|
} else if (!Array.isArray(condition.value) && !(condition.value instanceof Query)) {
|
|
@@ -244,7 +260,7 @@ class Builder {
|
|
|
244
260
|
return res ? `${this._buildFieldKey(condition.key)} ${opt} (${res})` : `${this._buildFieldKey(condition.key)} ${opt} (?)`;
|
|
245
261
|
}
|
|
246
262
|
|
|
247
|
-
|
|
263
|
+
_buildCondition(conditions, prefix) {
|
|
248
264
|
if (!conditions || !conditions.length) {
|
|
249
265
|
return '';
|
|
250
266
|
}
|
|
@@ -265,7 +281,7 @@ class Builder {
|
|
|
265
281
|
}
|
|
266
282
|
if (c.key && c.key.indexOf('->') !== -1) {
|
|
267
283
|
const keys = c.key.split('->');
|
|
268
|
-
return this.
|
|
284
|
+
return this._buildCondition([
|
|
269
285
|
{
|
|
270
286
|
key: `JSON_EXTRACT(${this._buildFieldKey(keys[0])}, '${keys[1]}')`,
|
|
271
287
|
opt: c.opt,
|
|
@@ -275,11 +291,11 @@ class Builder {
|
|
|
275
291
|
}
|
|
276
292
|
const opt = c.opt.toLowerCase();
|
|
277
293
|
if (opt === 'in') {
|
|
278
|
-
return this.
|
|
294
|
+
return this._buildConditionIn(c);
|
|
279
295
|
} else if (opt === 'not in') {
|
|
280
|
-
return this.
|
|
296
|
+
return this._buildConditionIn(c, true);
|
|
281
297
|
} else if (opt === 'group' && Array.isArray(c.value)) {
|
|
282
|
-
return `(${this.
|
|
298
|
+
return `(${this._buildCondition(c.value, '')})`;
|
|
283
299
|
}
|
|
284
300
|
let res = this._buildConditionValues(c.value);
|
|
285
301
|
if (!is.empty(res)) {
|
|
@@ -325,21 +341,24 @@ class Builder {
|
|
|
325
341
|
|
|
326
342
|
class ManageSQLBuilder extends Builder {
|
|
327
343
|
/**
|
|
328
|
-
* @param {import('
|
|
344
|
+
* @param {import('./migration').ManageBuilderOptions} options
|
|
329
345
|
*/
|
|
330
346
|
constructor(options) {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
347
|
+
if (operations.indexOf(options.operator) > -1) {
|
|
348
|
+
super(options);
|
|
349
|
+
} else {
|
|
350
|
+
super({ operator: 'manage' });
|
|
351
|
+
const action = `${options.operator}_${options.target}`;
|
|
352
|
+
const method = _caml_case(action, false);
|
|
353
|
+
if (!this[method]) {
|
|
354
|
+
throw new Error(`'${options.target}' Unsupported '${options.operator}' operation.`);
|
|
355
|
+
}
|
|
356
|
+
try {
|
|
357
|
+
this.sql = this[method].call(this, options);
|
|
358
|
+
} catch (err) {
|
|
359
|
+
debug.dump(`${options.operator} ${options.target} error: ${err.message}`);
|
|
360
|
+
throw err;
|
|
361
|
+
}
|
|
343
362
|
}
|
|
344
363
|
}
|
|
345
364
|
|
package/src/migration.d.ts
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
|
+
import { ColumnItem } from '../index';
|
|
2
|
+
|
|
1
3
|
type QueryItem = {
|
|
2
4
|
sql: string,
|
|
3
5
|
values: any[],
|
|
4
6
|
};
|
|
5
7
|
|
|
8
|
+
export type ManageBuilderOptions = {
|
|
9
|
+
operator: 'create' | 'drop' | 'alter';
|
|
10
|
+
columns: Record<string, ColumnItem>;
|
|
11
|
+
target: 'table' | 'column' | 'index' | 'foreign_key';
|
|
12
|
+
name?: string;
|
|
13
|
+
engine?: 'InnoDB' | 'MyISAM' | 'MEMORY',
|
|
14
|
+
charset?: string
|
|
15
|
+
}
|
|
16
|
+
|
|
6
17
|
export type Context = {
|
|
7
18
|
action: 'up' | 'down',
|
|
8
19
|
connection: {
|
package/src/query.js
CHANGED
|
@@ -180,6 +180,29 @@ class Query {
|
|
|
180
180
|
this.options.joins.push({ table, alias: table_alias, self_column, foreign_column, join_type });
|
|
181
181
|
return this;
|
|
182
182
|
}
|
|
183
|
+
|
|
184
|
+
joinOn(table, alias, on, type = 'LEFT') {
|
|
185
|
+
if (!table) {
|
|
186
|
+
throw new Error('table is required');
|
|
187
|
+
}
|
|
188
|
+
if (!on) {
|
|
189
|
+
throw new Error('on is required');
|
|
190
|
+
}
|
|
191
|
+
this.options.joins.push({ table, alias, on, join_type: type });
|
|
192
|
+
return this;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
leftJoin(table, alias, on) {
|
|
196
|
+
return this.joinOn(table, alias, on, 'LEFT');
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
rightJoin(table, alias, on) {
|
|
200
|
+
return this.joinOn(table, alias, on, 'RIGHT');
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
innerJoin(table, alias, on) {
|
|
204
|
+
return this.joinOn(table, alias, on, 'INNER');
|
|
205
|
+
}
|
|
183
206
|
}
|
|
184
207
|
|
|
185
208
|
module.exports = Query;
|