@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 CHANGED
@@ -1,2 +1,85 @@
1
- # node-orm-mysql
2
- MySQL ORM tool
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 QueryOperator {
60
- conn: Connection;
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
- } = require('./src/query');
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axiosleo/orm-mysql",
3
- "version": "0.1.0-pre-alpha.3",
3
+ "version": "0.1.1",
4
4
  "description": "MySQL ORM tool",
5
5
  "keywords": [
6
6
  "mysql",
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/query');
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
- // query.attr('UNIX_TIMESTAMP(deleted_at) AS deleted_at');
18
- query.where('u.meta->$.id', '06fbd857-7006-fee7-259d-fd3ed8f19b35');
19
- debug.log(query.buildSql('select').sql);
20
- // expect(query.buildSql('select').sql).to.be.equal('SELECT * FROM `users` AS `u` WHERE `u`.`id` = ?');
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
- const _buildFieldWithTableName = (key) => {
6
- if (key.indexOf('$') !== -1) {
7
- return key;
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
- const _buildContidion = (conditions, prefix) => {
31
- const values = [];
32
- if (is.empty(conditions)) {
33
- return { sql: '', values };
34
- }
35
- let sql = typeof prefix === 'undefined' ? ' WHERE ' : '';
36
- if (conditions.length) {
37
- sql += `${conditions.map((c) => {
38
- if (c.key === null && c.value === null) {
39
- return ` ${c.opt} `;
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
- if (c.value === null) {
42
- return c.opt === '=' ? `ISNULL(${_buildFieldKey(c.key)})` : `!ISNULL(${_buildFieldKey(c.key)})`;
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
- if (c.key && c.key.indexOf('->') !== -1) {
45
- const keys = c.key.split('->');
46
- values.push(c.value);
47
- const res = _buildContidion([
48
- {
49
- key: `JSON_EXTRACT(${_buildFieldKey(keys[0])}, '${keys[1]}')`,
50
- opt: c.opt,
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
- const opt = c.opt.toLowerCase();
58
- if (opt === 'in' && Array.isArray(c.value)) {
59
- values.push(c.value.join(','));
60
- return `${_buildFieldKey(c.key)} IN (?)`;
61
- } else if (opt === 'group' && Array.isArray(c.value)) {
62
- const res = _buildContidion(c.value, '');
63
- values.push(...res.values);
64
- return `(${res.sql})`;
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
- values.push(c.value);
67
- return `${_buildFieldKey(c.key)} ${c.opt} ?`;
68
- }).join('')}`;
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
- const _buildValues = (obj) => {
77
- const fields = [];
78
- const values = [];
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
- if (Array.isArray(obj[key]) || is.object(obj[key])) {
86
- values.push(JSON.stringify(obj[key]));
87
- } else {
88
- values.push(obj[key]);
89
- }
90
- });
91
- return { fields, values };
92
- };
72
+ return this._buildContidion(having, ' HAVING ');
73
+ }
93
74
 
94
- const _buldPagenation = (limit, offset) => {
95
- let sql = '';
96
- if (limit) {
97
- sql += ` LIMIT ${limit}`;
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
- if (offset) {
100
- sql += ` OFFSET ${offset}`;
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
- const _buildTables = (tables) => {
106
- return tables.map((t) => {
107
- if (t.alias) {
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 `\`${t.tableName}\``;
111
- }).join(' , ');
112
- };
113
-
114
- const _buildOrders = (orders = []) => {
115
- const sql = ' ORDER BY ' + orders.map((o) => {
116
- return `\`${o.sortField}\` ${o.sortOrder}`;
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
- const _buildJoins = (joins = []) => {
122
- return joins.map((j) => {
123
- switch (j.type) {
124
- case 'left':
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
- }).join(' ');
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
- // eslint-disable-next-line no-fallthrough
143
- case 'select': {
144
- sql = `SELECT ${options.attrs ? options.attrs.map((a) => _buildFieldKey(a)).join(',') : '*'} FROM ${_buildTables(options.tables)}`;
145
- sql += _buildJoins(options.joins);
146
- const res = _buildContidion(options.conditions);
147
- sql += res.sql;
148
- values = options.values.concat(res.values);
149
- sql += options.orders.length > 0 ? _buildOrders(options.orders) : '';
150
- sql += _buldPagenation(options.pageLimit, options.pageOffset);
151
- if (options.groupField.length) {
152
- sql += ` GROUP BY ${options.groupField.join(',')}`;
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
- break;
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
- case 'insert': {
157
- const buildValueRes = _buildValues(options.data);
158
- sql = `INSERT INTO ${_buildTables(options.tables)}(${buildValueRes.fields.map((f) => _buildFieldKey(f))}) VALUES (${buildValueRes.fields.map(() => '?').join(',')})`;
159
- values = values.concat(buildValueRes.values);
160
- break;
139
+ return null;
140
+ }
141
+
142
+ _buildContidion(conditions, prefix) {
143
+ if (!conditions.length) {
144
+ return '';
161
145
  }
162
- case 'update': {
163
- const buildValueRes = _buildValues(options.data);
164
- sql = `UPDATE ${_buildTables(options.tables)} SET ${buildValueRes.fields.map(f => `${_buildFieldKey(f)} = ?`).join(',')}`;
165
- values = values.concat(buildValueRes.values);
166
- const buildConditionRes = _buildContidion(options.conditions);
167
- sql += buildConditionRes.sql;
168
- values = values.concat(buildConditionRes.values);
169
- break;
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
- case 'delete': {
172
- sql = `DELETE FROM ${_buildTables(options.tables)}`;
173
- if (!options.conditions.length) {
174
- throw new Error('At least one where condition is required for delete operation');
175
- }
176
- const buildConditionRes = _buildContidion(options.conditions);
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
- case 'count': {
182
- sql = `SELECT COUNT(*) AS count FROM ${_buildTables(options.tables)}`;
183
- const buildConditionRes = _buildContidion(options.conditions);
184
- sql += buildConditionRes.sql;
185
- values = values.concat(buildConditionRes.values);
186
- if (options.groupField.length) {
187
- sql += ` GROUP BY ${options.groupField.join(',')}`;
188
- }
189
- break;
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
- default:
192
- throw new Error('Invalid operator: ' + options.operator);
194
+ return this._buildFieldWithTableName(key);
193
195
  }
194
196
 
195
- return {
196
- sql,
197
- values: values
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
- buildSql
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 = options.name ? options.name :
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];
@@ -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
- const { buildSql } = require('./builder');
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: null,
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;