@axiosleo/orm-mysql 0.1.0-pre-alpha.3 → 0.1.1
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/README.md +85 -2
- package/index.d.ts +17 -8
- package/index.js +4 -2
- package/package.json +1 -1
- package/runtimes/test.js +11 -7
- package/src/builder.js +176 -172
- package/src/client.js +2 -3
- package/src/operator.js +129 -0
- package/src/query.js +21 -119
package/README.md
CHANGED
|
@@ -1,2 +1,85 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
1
|
+
# @axiosleo/orm-mysql
|
|
2
|
+
|
|
3
|
+
## Installation
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install @axiosleo/orm-mysql
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```javascript
|
|
12
|
+
const { createClient, QueryHandler } = require('@axiosleo/orm-mysql');
|
|
13
|
+
|
|
14
|
+
const conn = createClient({
|
|
15
|
+
host: process.env.MYSQL_HOST,
|
|
16
|
+
port: process.env.MYSQL_PORT,
|
|
17
|
+
user: process.env.MYSQL_USER,
|
|
18
|
+
password: process.env.MYSQL_PASS,
|
|
19
|
+
database: process.env.MYSQL_DB,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const hanlder = new QueryHandler(conn);
|
|
23
|
+
|
|
24
|
+
async function selectExample(){
|
|
25
|
+
const query = handler.table('users'); // init QueryOperator by table name
|
|
26
|
+
|
|
27
|
+
query.attr('id', 'name', 'age'); // set attributes
|
|
28
|
+
query.where('name','Joe'); // set where condition
|
|
29
|
+
query.orWhere('age', '>', 18); // set or where condition
|
|
30
|
+
query.andWhere('age', '<', 30); // set and where condition
|
|
31
|
+
query.orderBy('age', 'desc'); // set order by
|
|
32
|
+
query.limit(10); // set limit
|
|
33
|
+
query.offset(0); // set offset
|
|
34
|
+
|
|
35
|
+
let rows = await query.select(); // select
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function findExample(){
|
|
39
|
+
const query = handler.table('users'); // init QueryOperator by table name
|
|
40
|
+
|
|
41
|
+
query.attr('id', 'name', 'age'); // set attributes
|
|
42
|
+
query.where('name','Joe'); // set where condition
|
|
43
|
+
query.orWhere('age', '>', 18); // set or where condition
|
|
44
|
+
query.andWhere('age', '<', 30); // set and where condition
|
|
45
|
+
query.orderBy('age', 'desc'); // set order by
|
|
46
|
+
// query.limit(10); // not supported set limit
|
|
47
|
+
// query.offset(10); // not supported set offset
|
|
48
|
+
|
|
49
|
+
let row = await query.find(); // find single row
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function insertExample(){
|
|
53
|
+
const query = handler.table('users');
|
|
54
|
+
|
|
55
|
+
// insert
|
|
56
|
+
let row = await query.insert({
|
|
57
|
+
name: 'Joe',
|
|
58
|
+
age: 18,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async function updateExample(){
|
|
63
|
+
const query = handler.table('users');
|
|
64
|
+
|
|
65
|
+
// update
|
|
66
|
+
let row = await query.where('name','Joe').update({
|
|
67
|
+
name: 'Joe',
|
|
68
|
+
age: 18,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function deleteExample(){
|
|
73
|
+
const query = handler.table('users');
|
|
74
|
+
|
|
75
|
+
// delete with conditions
|
|
76
|
+
let result = await query.where('name','Joe').delete();
|
|
77
|
+
|
|
78
|
+
// delete by id
|
|
79
|
+
result = await query.delete(1);
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## License
|
|
84
|
+
|
|
85
|
+
This project is open-sourced software licensed under the [MIT](LICENSE).
|
package/index.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export type Clients = {
|
|
|
10
10
|
[key: string]: Connection
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
export type ConditionValueType = null | string | number | boolean | Date | Array<string | number | boolean | Date
|
|
13
|
+
export type ConditionValueType = null | string | number | boolean | Date | Array<string | number | boolean | Date> | Query;
|
|
14
14
|
|
|
15
15
|
export type OptType = '=' | '!=' | '>' | '<' | '>=' | '<=' | 'LIKE'
|
|
16
16
|
| 'NOT LIKE' | 'IN' | 'NOT IN' | 'BETWEEN' | 'NOT BETWEEN' | 'IS' | 'IS NOT' | 'REGEXP' | 'NOT REGEXP'
|
|
@@ -53,14 +53,12 @@ export interface QueryOperatorOptions {
|
|
|
53
53
|
operator: OperatorType | null;
|
|
54
54
|
data: any | null;
|
|
55
55
|
groupField: string[];
|
|
56
|
-
joins: JoinOption[]
|
|
56
|
+
joins: JoinOption[];
|
|
57
|
+
having: WhereOptions[];
|
|
57
58
|
}
|
|
58
59
|
|
|
59
|
-
export declare class
|
|
60
|
-
|
|
61
|
-
options: QueryOperatorOptions
|
|
62
|
-
|
|
63
|
-
constructor(conn: Connection, table: TableOption);
|
|
60
|
+
export declare class Query {
|
|
61
|
+
constructor(operator?: OperatorType);
|
|
64
62
|
|
|
65
63
|
table(tableName: string, alias: string | null): this;
|
|
66
64
|
|
|
@@ -84,11 +82,20 @@ export declare class QueryOperator {
|
|
|
84
82
|
|
|
85
83
|
groupBy(...groupField: string[]): this;
|
|
86
84
|
|
|
85
|
+
having(key: string | null, opt: OptType, value: ConditionValueType | WhereOptions[]): this;
|
|
86
|
+
|
|
87
87
|
page(limit: number, offset?: number): this;
|
|
88
88
|
|
|
89
89
|
set(data: any): this;
|
|
90
90
|
|
|
91
91
|
join(table: string, alias: string, on: string, type: 'left' | 'right' | 'inner'): this;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export declare class QueryOperator extends Query {
|
|
95
|
+
conn: Connection;
|
|
96
|
+
options: QueryOperatorOptions
|
|
97
|
+
|
|
98
|
+
constructor(conn: Connection);
|
|
92
99
|
|
|
93
100
|
buildSql(operator: OperatorType): { sql: string, values: any[] };
|
|
94
101
|
|
|
@@ -103,6 +110,8 @@ export declare class QueryOperator {
|
|
|
103
110
|
insert(data?: any): Promise<OkPacket>;
|
|
104
111
|
|
|
105
112
|
count(): Promise<number>;
|
|
113
|
+
|
|
114
|
+
delete(id?: number): Promise<OkPacket>;
|
|
106
115
|
}
|
|
107
116
|
|
|
108
117
|
export declare class QueryHandler {
|
|
@@ -117,6 +126,6 @@ export declare class QueryHandler {
|
|
|
117
126
|
upsert(tableName: string, data: any, condition: Record<string, ConditionValueType>): Promise<OkPacket>;
|
|
118
127
|
}
|
|
119
128
|
|
|
120
|
-
export function createClient(options: ConnectionOptions): Connection;
|
|
129
|
+
export function createClient(options: ConnectionOptions, name?: string | null | undefined): Connection;
|
|
121
130
|
|
|
122
131
|
export function getClient(name: string): Connection;
|
package/index.js
CHANGED
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
const {
|
|
4
4
|
QueryHandler,
|
|
5
|
-
QueryOperator
|
|
6
|
-
|
|
5
|
+
QueryOperator,
|
|
6
|
+
Query
|
|
7
|
+
} = require('./src/operator');
|
|
7
8
|
|
|
8
9
|
const { createClient, getClient } = require('./src/client');
|
|
9
10
|
|
|
10
11
|
module.exports = {
|
|
12
|
+
Query,
|
|
11
13
|
QueryHandler,
|
|
12
14
|
QueryOperator,
|
|
13
15
|
|
package/package.json
CHANGED
package/runtimes/test.js
CHANGED
|
@@ -4,18 +4,22 @@ const { debug } = require('@axiosleo/cli-tool');
|
|
|
4
4
|
const mm = require('mm');
|
|
5
5
|
// const expect = require('chai').expect;
|
|
6
6
|
const mysql = require('mysql2');
|
|
7
|
-
const { QueryHandler } = require('../src/
|
|
7
|
+
const { QueryHandler, Query } = require('../src/operator');
|
|
8
8
|
|
|
9
9
|
mm(mysql, 'createConnection', (options) => {
|
|
10
|
-
return {
|
|
10
|
+
return {
|
|
11
|
+
|
|
12
|
+
};
|
|
11
13
|
});
|
|
12
14
|
|
|
13
15
|
const conn = mysql.createConnection({});
|
|
14
16
|
const hanlder = new QueryHandler(conn);
|
|
15
|
-
const query = hanlder.table('meta_items', 'u');
|
|
17
|
+
// const query = hanlder.table('meta_items', 'u');
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
const query = hanlder.table('meta_items');
|
|
20
|
+
const subQuery = new Query('select');
|
|
21
|
+
subQuery.table('meta_items').attr('item_code').groupBy('item_code').having('COUNT(*)', '>', 1);
|
|
22
|
+
const res = query.where('item_code', subQuery, 'IN').buildSql('select');
|
|
23
|
+
// expect(res.sql).to.be.equal('SELECT * FROM `users` AS `u` WHERE `name` IN (SELECT * FROM `users`)');
|
|
21
24
|
|
|
25
|
+
debug.log(res);
|
package/src/builder.js
CHANGED
|
@@ -1,203 +1,207 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const Query = require('./query');
|
|
3
4
|
const is = require('@axiosleo/cli-tool/src/helper/is');
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
return key.split('.').map((k) => k.indexOf('`') !== -1 ? k : `\`${k}\``).join('.');
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
const _buildFieldKey = (key) => {
|
|
13
|
-
if (key === null) {
|
|
14
|
-
return '';
|
|
15
|
-
}
|
|
16
|
-
if (key.indexOf('(') !== -1 && key.indexOf(')') !== -1) {
|
|
17
|
-
let field = key.substring(key.indexOf('(') + 1, key.indexOf(')'));
|
|
18
|
-
key = key.substring(0, key.indexOf('(')) + '(' + _buildFieldWithTableName(field) + ')' + key.substring(key.indexOf(')') + 1);
|
|
19
|
-
}
|
|
20
|
-
if (key.indexOf(' as ') !== -1) {
|
|
21
|
-
const field = key.substring(key.indexOf(' as ') + 4);
|
|
22
|
-
key = key.substring(0, key.indexOf(' as ')) + ' AS ' + _buildFieldWithTableName(field);
|
|
23
|
-
} else if (key.indexOf(' AS ') !== -1) {
|
|
24
|
-
const field = key.substring(key.indexOf(' AS ') + 4);
|
|
25
|
-
key = key.substring(0, key.indexOf(' AS ')) + ' AS ' + _buildFieldWithTableName(field);
|
|
26
|
-
}
|
|
27
|
-
return _buildFieldWithTableName(key);
|
|
28
|
-
};
|
|
6
|
+
class Builder {
|
|
7
|
+
constructor(options) {
|
|
8
|
+
let sql = options.sql;
|
|
9
|
+
this.values = options.values || [];
|
|
29
10
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
11
|
+
switch (options.operator) {
|
|
12
|
+
case 'find': {
|
|
13
|
+
options.pageLimit = 1;
|
|
14
|
+
options.pageOffset = 0;
|
|
15
|
+
}
|
|
16
|
+
// eslint-disable-next-line no-fallthrough
|
|
17
|
+
case 'select': {
|
|
18
|
+
sql = `SELECT ${options.attrs ? options.attrs.map((a) => this._buildFieldKey(a)).join(',') : '*'} FROM ${this._buildTables(options.tables)}`;
|
|
19
|
+
sql += this._buildJoins(options.joins);
|
|
20
|
+
sql += this._buildContidion(options.conditions);
|
|
21
|
+
sql += options.orders.length > 0 ? this._buildOrders(options.orders) : '';
|
|
22
|
+
sql += this._buldPagenation(options.pageLimit, options.pageOffset);
|
|
23
|
+
if (options.groupField.length) {
|
|
24
|
+
sql += ` GROUP BY ${options.groupField.map(f => this._buildFieldKey(f)).join(',')}`;
|
|
25
|
+
sql += this._buildHaving(options.having);
|
|
26
|
+
} else if (options.having && options.having.length) {
|
|
27
|
+
throw new Error('having is not allowed without "GROUP BY"');
|
|
28
|
+
}
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
case 'insert': {
|
|
32
|
+
const fields = this._buildValues(options.data);
|
|
33
|
+
sql = `INSERT INTO ${this._buildTables(options.tables)}(${fields.map((f) => this._buildFieldKey(f))}) VALUES (${fields.map(() => '?').join(',')})`;
|
|
34
|
+
break;
|
|
40
35
|
}
|
|
41
|
-
|
|
42
|
-
|
|
36
|
+
case 'update': {
|
|
37
|
+
const fields = this._buildValues(options.data);
|
|
38
|
+
sql = `UPDATE ${this._buildTables(options.tables)} SET ${fields.map(f => `${this._buildFieldKey(f)} = ?`).join(',')}`;
|
|
39
|
+
sql += this._buildContidion(options.conditions);
|
|
40
|
+
break;
|
|
43
41
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
value: c.value
|
|
52
|
-
}
|
|
53
|
-
], '');
|
|
54
|
-
values.push(...res.values);
|
|
55
|
-
return res.sql;
|
|
42
|
+
case 'delete': {
|
|
43
|
+
sql = `DELETE FROM ${this._buildTables(options.tables)}`;
|
|
44
|
+
if (!options.conditions.length) {
|
|
45
|
+
throw new Error('At least one where condition is required for delete operation');
|
|
46
|
+
}
|
|
47
|
+
sql += this._buildContidion(options.conditions);
|
|
48
|
+
break;
|
|
56
49
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
50
|
+
case 'count': {
|
|
51
|
+
sql = `SELECT COUNT(*) AS count FROM ${this._buildTables(options.tables)}`;
|
|
52
|
+
sql += this._buildContidion(options.conditions);
|
|
53
|
+
if (options.groupField.length) {
|
|
54
|
+
sql += ` GROUP BY ${options.groupField.map(f => this._buildFieldKey(f)).join(',')}`;
|
|
55
|
+
sql += this._buildHaving(options.having);
|
|
56
|
+
} else if (options.having && options.having.length) {
|
|
57
|
+
throw new Error('having is not allowed without "GROUP BY"');
|
|
58
|
+
}
|
|
59
|
+
break;
|
|
65
60
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
61
|
+
default:
|
|
62
|
+
throw new Error('Invalid operator: ' + options.operator);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
this.sql = sql;
|
|
69
66
|
}
|
|
70
|
-
return {
|
|
71
|
-
sql,
|
|
72
|
-
values
|
|
73
|
-
};
|
|
74
|
-
};
|
|
75
67
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
Object.keys(obj).forEach((key) => {
|
|
80
|
-
fields.push(`${key}`);
|
|
81
|
-
if (obj[key] === null) {
|
|
82
|
-
values.push('NULL');
|
|
83
|
-
return;
|
|
68
|
+
_buildHaving(having) {
|
|
69
|
+
if (!having.length) {
|
|
70
|
+
return '';
|
|
84
71
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
} else {
|
|
88
|
-
values.push(obj[key]);
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
return { fields, values };
|
|
92
|
-
};
|
|
72
|
+
return this._buildContidion(having, ' HAVING ');
|
|
73
|
+
}
|
|
93
74
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
75
|
+
_buildJoins(joins = []) {
|
|
76
|
+
return joins.map((j) => {
|
|
77
|
+
switch (j.type) {
|
|
78
|
+
case 'left':
|
|
79
|
+
return ` LEFT JOIN \`${j.table}\` AS \`${j.alias}\` ON ${j.on}`;
|
|
80
|
+
case 'inner':
|
|
81
|
+
return ` INNER JOIN \`${j.table}\` AS \`${j.alias}\` ON ${j.on}`;
|
|
82
|
+
case 'right':
|
|
83
|
+
return ` RIGHT JOIN \`${j.table}\` AS \`${j.alias}\` ON ${j.on}`;
|
|
84
|
+
}
|
|
85
|
+
}).join(' ');
|
|
98
86
|
}
|
|
99
|
-
|
|
100
|
-
|
|
87
|
+
|
|
88
|
+
_buildOrders(orders = []) {
|
|
89
|
+
const sql = ' ORDER BY ' + orders.map((o) => {
|
|
90
|
+
return `\`${o.sortField}\` ${o.sortOrder}`;
|
|
91
|
+
}).join(',');
|
|
92
|
+
return sql;
|
|
101
93
|
}
|
|
102
|
-
return sql;
|
|
103
|
-
};
|
|
104
94
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
return `\`${t.tableName}\` AS \`${t.alias}\``;
|
|
95
|
+
_buildTables(tables) {
|
|
96
|
+
if (!tables.length) {
|
|
97
|
+
throw new Error('At least one table is required');
|
|
109
98
|
}
|
|
110
|
-
return
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}).join(',');
|
|
118
|
-
return sql;
|
|
119
|
-
};
|
|
99
|
+
return tables.map((t) => {
|
|
100
|
+
if (t.alias) {
|
|
101
|
+
return `\`${t.tableName}\` AS \`${t.alias}\``;
|
|
102
|
+
}
|
|
103
|
+
return `\`${t.tableName}\``;
|
|
104
|
+
}).join(' , ');
|
|
105
|
+
}
|
|
120
106
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
return ` LEFT JOIN \`${j.table}\` AS \`${j.alias}\` ON ${j.on}`;
|
|
126
|
-
case 'inner':
|
|
127
|
-
return ` INNER JOIN \`${j.table}\` AS \`${j.alias}\` ON ${j.on}`;
|
|
128
|
-
case 'right':
|
|
129
|
-
return ` RIGHT JOIN \`${j.table}\` AS \`${j.alias}\` ON ${j.on}`;
|
|
107
|
+
_buldPagenation(limit, offset) {
|
|
108
|
+
let sql = '';
|
|
109
|
+
if (limit) {
|
|
110
|
+
sql += ` LIMIT ${limit}`;
|
|
130
111
|
}
|
|
131
|
-
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const buildSql = (options) => {
|
|
135
|
-
let sql = options.sql;
|
|
136
|
-
let values = options.values;
|
|
137
|
-
switch (options.operator) {
|
|
138
|
-
case 'find': {
|
|
139
|
-
options.pageLimit = 1;
|
|
140
|
-
options.pageOffset = 0;
|
|
112
|
+
if (offset) {
|
|
113
|
+
sql += ` OFFSET ${offset}`;
|
|
141
114
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
if (
|
|
152
|
-
|
|
115
|
+
return sql;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
_buildValues(obj) {
|
|
119
|
+
const fields = [];
|
|
120
|
+
Object.keys(obj).forEach((key) => {
|
|
121
|
+
fields.push(`${key}`);
|
|
122
|
+
if (obj[key] instanceof Date) {
|
|
123
|
+
this.values.push(obj[key]);
|
|
124
|
+
} else if (Array.isArray(obj[key]) || is.object(obj[key])) {
|
|
125
|
+
this.values.push(JSON.stringify(obj[key]));
|
|
126
|
+
} else {
|
|
127
|
+
this.values.push(obj[key]);
|
|
153
128
|
}
|
|
154
|
-
|
|
129
|
+
});
|
|
130
|
+
return fields;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
_buildConditionValues(val) {
|
|
134
|
+
if (val instanceof Query) {
|
|
135
|
+
const builder = new Builder(val.options);
|
|
136
|
+
this.values = this.values.concat(builder.values);
|
|
137
|
+
return builder.sql;
|
|
155
138
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
_buildContidion(conditions, prefix) {
|
|
143
|
+
if (!conditions.length) {
|
|
144
|
+
return '';
|
|
161
145
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
sql
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
146
|
+
let sql = typeof prefix === 'undefined' ? ' WHERE ' : prefix;
|
|
147
|
+
if (conditions.length) {
|
|
148
|
+
sql += `${conditions.map((c) => {
|
|
149
|
+
if (c.key === null && c.value === null) {
|
|
150
|
+
return ` ${c.opt} `;
|
|
151
|
+
}
|
|
152
|
+
if (c.value === null) {
|
|
153
|
+
return c.opt === '=' ? `ISNULL(${this._buildFieldKey(c.key)})` : `!ISNULL(${this._buildFieldKey(c.key)})`;
|
|
154
|
+
}
|
|
155
|
+
if (c.key && c.key.indexOf('->') !== -1) {
|
|
156
|
+
const keys = c.key.split('->');
|
|
157
|
+
return this._buildContidion([
|
|
158
|
+
{
|
|
159
|
+
key: `JSON_EXTRACT(${this._buildFieldKey(keys[0])}, '${keys[1]}')`,
|
|
160
|
+
opt: c.opt,
|
|
161
|
+
value: c.value
|
|
162
|
+
}
|
|
163
|
+
], '');
|
|
164
|
+
}
|
|
165
|
+
const opt = c.opt.toLowerCase();
|
|
166
|
+
if (opt === 'in' && Array.isArray(c.value)) {
|
|
167
|
+
let res = this._buildConditionValues(c.value);
|
|
168
|
+
return res ? `${this._buildFieldKey(c.key)} IN (${res})` : `${this._buildFieldKey(c.key)} IN (?)`;
|
|
169
|
+
} else if (opt === 'group' && Array.isArray(c.value)) {
|
|
170
|
+
return `(${this._buildContidion(c.value, '')})`;
|
|
171
|
+
}
|
|
172
|
+
let res = this._buildConditionValues(c.value);
|
|
173
|
+
return res ? `${this._buildFieldKey(c.key)} ${c.opt} (${res})` : `${this._buildFieldKey(c.key)} ${c.opt} ?`;
|
|
174
|
+
}).join('')}`;
|
|
170
175
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
sql += buildConditionRes.sql;
|
|
178
|
-
values = values.concat(buildConditionRes.values);
|
|
179
|
-
break;
|
|
176
|
+
return sql;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
_buildFieldKey(key) {
|
|
180
|
+
if (key === null) {
|
|
181
|
+
return '';
|
|
180
182
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
183
|
+
if (key.indexOf('(') !== -1 && key.indexOf(')') !== -1) {
|
|
184
|
+
let field = key.substring(key.indexOf('(') + 1, key.indexOf(')'));
|
|
185
|
+
key = key.substring(0, key.indexOf('(')) + '(' + this._buildFieldWithTableName(field) + ')' + key.substring(key.indexOf(')') + 1);
|
|
186
|
+
}
|
|
187
|
+
if (key.indexOf(' as ') !== -1) {
|
|
188
|
+
const field = key.substring(key.indexOf(' as ') + 4);
|
|
189
|
+
key = key.substring(0, key.indexOf(' as ')) + ' AS ' + this._buildFieldWithTableName(field);
|
|
190
|
+
} else if (key.indexOf(' AS ') !== -1) {
|
|
191
|
+
const field = key.substring(key.indexOf(' AS ') + 4);
|
|
192
|
+
key = key.substring(0, key.indexOf(' AS ')) + ' AS ' + this._buildFieldWithTableName(field);
|
|
190
193
|
}
|
|
191
|
-
|
|
192
|
-
throw new Error('Invalid operator: ' + options.operator);
|
|
194
|
+
return this._buildFieldWithTableName(key);
|
|
193
195
|
}
|
|
194
196
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
};
|
|
197
|
+
_buildFieldWithTableName(key) {
|
|
198
|
+
if (key.indexOf('$') !== -1 || key.indexOf('*') !== -1) {
|
|
199
|
+
return key;
|
|
200
|
+
}
|
|
201
|
+
return key.split('.').map((k) => k.indexOf('`') !== -1 ? k : `\`${k}\``).join('.');
|
|
202
|
+
}
|
|
203
|
+
}
|
|
200
204
|
|
|
201
205
|
module.exports = {
|
|
202
|
-
|
|
206
|
+
Builder
|
|
203
207
|
};
|
package/src/client.js
CHANGED
|
@@ -10,16 +10,15 @@ const clients = {};
|
|
|
10
10
|
* @param {mysql.ConnectionOptions} options
|
|
11
11
|
* @returns {mysql.Connection}
|
|
12
12
|
*/
|
|
13
|
-
const createClient = (options) => {
|
|
13
|
+
const createClient = (options, name = null) => {
|
|
14
14
|
validate(options, {
|
|
15
|
-
name: 'string',
|
|
16
15
|
host: 'required|string',
|
|
17
16
|
user: 'required|string',
|
|
18
17
|
password: 'required|string',
|
|
19
18
|
port: 'required|integer',
|
|
20
19
|
database: 'required|string',
|
|
21
20
|
});
|
|
22
|
-
const key =
|
|
21
|
+
const key = name ? name :
|
|
23
22
|
`${options.host}:${options.port}:${options.user}:${options.password}:${options.database}`;
|
|
24
23
|
if (clients[key]) {
|
|
25
24
|
return clients[key];
|
package/src/operator.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { Builder } = require('./builder');
|
|
4
|
+
const Query = require('./query');
|
|
5
|
+
|
|
6
|
+
const query = async (conn, options) => {
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
8
|
+
conn.query(options, (err, result) => {
|
|
9
|
+
if (err) {
|
|
10
|
+
reject(err);
|
|
11
|
+
} else {
|
|
12
|
+
resolve(result);
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
class QueryOperator extends Query {
|
|
19
|
+
/**
|
|
20
|
+
* @param {*} conn
|
|
21
|
+
*/
|
|
22
|
+
constructor(conn) {
|
|
23
|
+
super(null);
|
|
24
|
+
this.conn = conn;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
buildSql(operator) {
|
|
28
|
+
this.options.operator = operator;
|
|
29
|
+
return new Builder(this.options);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async exec() {
|
|
33
|
+
if (!this.options.operator) {
|
|
34
|
+
throw new Error('Invalid operator: ' + this.options.operator);
|
|
35
|
+
}
|
|
36
|
+
const builder = this.buildSql(this.options.operator);
|
|
37
|
+
const { sql, values } = builder;
|
|
38
|
+
const options = {
|
|
39
|
+
sql, values
|
|
40
|
+
};
|
|
41
|
+
switch (this.options.operator) {
|
|
42
|
+
case 'find': {
|
|
43
|
+
const res = await query(this.conn, options);
|
|
44
|
+
return res[0];
|
|
45
|
+
}
|
|
46
|
+
case 'count': {
|
|
47
|
+
const [res] = await query(this.conn, options);
|
|
48
|
+
return res.count;
|
|
49
|
+
}
|
|
50
|
+
default:
|
|
51
|
+
return query(this.conn, options);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async select() {
|
|
56
|
+
this.options.operator = 'select';
|
|
57
|
+
return await this.exec();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async find() {
|
|
61
|
+
this.options.operator = 'find';
|
|
62
|
+
return await this.exec();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async update(data) {
|
|
66
|
+
this.options.operator = 'update';
|
|
67
|
+
if (data) {
|
|
68
|
+
this.set(data);
|
|
69
|
+
}
|
|
70
|
+
return await this.exec();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async insert(data) {
|
|
74
|
+
this.options.operator = 'insert';
|
|
75
|
+
if (data) {
|
|
76
|
+
this.set(data);
|
|
77
|
+
}
|
|
78
|
+
return await this.exec();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async count() {
|
|
82
|
+
this.options.operator = 'count';
|
|
83
|
+
return await this.exec();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async delete(id) {
|
|
87
|
+
if (id) {
|
|
88
|
+
this.where('id', id);
|
|
89
|
+
}
|
|
90
|
+
this.options.operator = 'delete';
|
|
91
|
+
return await this.exec();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
class QueryHandler {
|
|
96
|
+
constructor(conn) {
|
|
97
|
+
this.conn = conn;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async query(options) {
|
|
101
|
+
return new Promise((resolve, reject) => {
|
|
102
|
+
this.conn.query(options, (err, result) => {
|
|
103
|
+
if (err) {
|
|
104
|
+
reject(err);
|
|
105
|
+
} else {
|
|
106
|
+
resolve(result);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
table(table, alias = null) {
|
|
113
|
+
return (new QueryOperator(this.conn)).table(table, alias);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async upsert(tableName, data, condition = {}) {
|
|
117
|
+
const count = await this.table(tableName).whereObject(condition).count();
|
|
118
|
+
if (count) {
|
|
119
|
+
return await this.table(tableName).whereObject(condition).update(data);
|
|
120
|
+
}
|
|
121
|
+
return await this.table(tableName).insert(data);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
module.exports = {
|
|
126
|
+
QueryOperator,
|
|
127
|
+
QueryHandler,
|
|
128
|
+
Query
|
|
129
|
+
};
|
package/src/query.js
CHANGED
|
@@ -1,38 +1,18 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const query = async (conn, options) => {
|
|
6
|
-
return new Promise((resolve, reject) => {
|
|
7
|
-
conn.query(options, (err, result) => {
|
|
8
|
-
if (err) {
|
|
9
|
-
reject(err);
|
|
10
|
-
} else {
|
|
11
|
-
resolve(result);
|
|
12
|
-
}
|
|
13
|
-
});
|
|
14
|
-
});
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
class QueryOperator {
|
|
18
|
-
/**
|
|
19
|
-
*
|
|
20
|
-
* @param {*} conn
|
|
21
|
-
* @param {TableOption} table
|
|
22
|
-
*/
|
|
23
|
-
constructor(conn, table) {
|
|
24
|
-
this.conn = conn;
|
|
3
|
+
class Query {
|
|
4
|
+
constructor(operator = 'select') {
|
|
25
5
|
this.options = {
|
|
26
6
|
sql: '',
|
|
27
7
|
values: [],
|
|
28
8
|
conditions: [],
|
|
29
9
|
orders: [],
|
|
30
10
|
tables: [],
|
|
31
|
-
operator
|
|
11
|
+
operator,
|
|
32
12
|
data: null,
|
|
33
13
|
groupField: [],
|
|
14
|
+
having: []
|
|
34
15
|
};
|
|
35
|
-
this.options.tables.push(table);
|
|
36
16
|
}
|
|
37
17
|
|
|
38
18
|
table(tableName, alias) {
|
|
@@ -117,6 +97,22 @@ class QueryOperator {
|
|
|
117
97
|
return this;
|
|
118
98
|
}
|
|
119
99
|
|
|
100
|
+
having(key, opt = '=', value = null) {
|
|
101
|
+
let optUpper = opt.toUpperCase();
|
|
102
|
+
if (optUpper === 'AND' || optUpper === 'OR') {
|
|
103
|
+
this.options.having.push({ key: null, opt: optUpper, value: null });
|
|
104
|
+
return this;
|
|
105
|
+
}
|
|
106
|
+
if (this.options.having.length) {
|
|
107
|
+
let lastOpt = this.options.having[this.options.having.length - 1].opt.toUpperCase();
|
|
108
|
+
if (lastOpt !== 'AND' && lastOpt !== 'OR') {
|
|
109
|
+
this.options.having.push({ key: null, opt: 'AND', value: null });
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
this.options.having.push({ key, opt, value });
|
|
113
|
+
return this;
|
|
114
|
+
}
|
|
115
|
+
|
|
120
116
|
page(limit, offset = 0) {
|
|
121
117
|
this.options.pageLimit = limit;
|
|
122
118
|
this.options.pageOffset = offset;
|
|
@@ -135,100 +131,6 @@ class QueryOperator {
|
|
|
135
131
|
this.options.joins.push({ table, alias, on, type });
|
|
136
132
|
return this;
|
|
137
133
|
}
|
|
138
|
-
|
|
139
|
-
buildSql(operator) {
|
|
140
|
-
this.options.operator = operator;
|
|
141
|
-
return buildSql(this.options);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
async exec() {
|
|
145
|
-
if (!this.options.operator) {
|
|
146
|
-
throw new Error('Invalid operator: ' + this.options.operator);
|
|
147
|
-
}
|
|
148
|
-
const { sql, values } = this.buildSql(this.options.operator);
|
|
149
|
-
const options = {
|
|
150
|
-
sql, values
|
|
151
|
-
};
|
|
152
|
-
switch (this.options.operator) {
|
|
153
|
-
case 'find': {
|
|
154
|
-
const res = await query(this.conn, options);
|
|
155
|
-
return res[0];
|
|
156
|
-
}
|
|
157
|
-
case 'count': {
|
|
158
|
-
const [res] = await query(this.conn, options);
|
|
159
|
-
return res.count;
|
|
160
|
-
}
|
|
161
|
-
default:
|
|
162
|
-
return query(this.conn, options);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
async select() {
|
|
167
|
-
this.options.operator = 'select';
|
|
168
|
-
return await this.exec();
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
async find() {
|
|
172
|
-
this.options.operator = 'find';
|
|
173
|
-
return await this.exec();
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
async update(data) {
|
|
177
|
-
this.options.operator = 'update';
|
|
178
|
-
if (data) {
|
|
179
|
-
this.set(data);
|
|
180
|
-
}
|
|
181
|
-
return await this.exec();
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
async insert(data) {
|
|
185
|
-
this.options.operator = 'insert';
|
|
186
|
-
if (data) {
|
|
187
|
-
this.set(data);
|
|
188
|
-
}
|
|
189
|
-
return await this.exec();
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
async count() {
|
|
193
|
-
this.options.operator = 'count';
|
|
194
|
-
return await this.exec();
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
class QueryHandler {
|
|
199
|
-
constructor(conn) {
|
|
200
|
-
this.conn = conn;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
async query(options) {
|
|
204
|
-
return new Promise((resolve, reject) => {
|
|
205
|
-
this.conn.query(options, (err, result) => {
|
|
206
|
-
if (err) {
|
|
207
|
-
reject(err);
|
|
208
|
-
} else {
|
|
209
|
-
resolve(result);
|
|
210
|
-
}
|
|
211
|
-
});
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
table(table, alias = null) {
|
|
216
|
-
return new QueryOperator(this.conn, {
|
|
217
|
-
tableName: table,
|
|
218
|
-
alias
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
async upsert(tableName, data, condition = {}) {
|
|
223
|
-
const count = await this.table(tableName).whereObject(condition).count();
|
|
224
|
-
if (count) {
|
|
225
|
-
return await this.table(tableName).whereObject(condition).update(data);
|
|
226
|
-
}
|
|
227
|
-
return await this.table(tableName).insert(data);
|
|
228
|
-
}
|
|
229
134
|
}
|
|
230
135
|
|
|
231
|
-
module.exports =
|
|
232
|
-
QueryOperator,
|
|
233
|
-
QueryHandler
|
|
234
|
-
};
|
|
136
|
+
module.exports = Query;
|