leoric 2.6.1 → 2.6.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "leoric",
3
- "version": "2.6.1",
3
+ "version": "2.6.2",
4
4
  "description": "JavaScript Object-relational mapping alchemy",
5
5
  "main": "index.js",
6
6
  "types": "types/index.d.ts",
package/src/constants.js CHANGED
@@ -8,6 +8,8 @@ const AGGREGATOR_MAP = {
8
8
  sum: 'sum'
9
9
  };
10
10
 
11
+ const AGGREGATORS = Object.values(AGGREGATOR_MAP);
12
+
11
13
  const LEGACY_TIMESTAMP_MAP = {
12
14
  gmtCreate: 'createdAt',
13
15
  gmtModified: 'updatedAt',
@@ -20,7 +22,7 @@ const LEGACY_TIMESTAMP_COLUMN_MAP = {
20
22
  deleted_at: 'gmt_deleted',
21
23
  };
22
24
 
23
- const TIMESTAMP_ATTRIBUTE_NAMES = [
25
+ const TIMESTAMP_ATTRIBUTE_NAMES = [
24
26
  'createdAt', 'updatedAt', 'deletedAt',
25
27
  'gmtCreate', 'gmtModified', 'gmtDeleted',
26
28
  'created_at', 'updated_at', 'deleted_at',
@@ -40,5 +42,6 @@ module.exports = {
40
42
  TIMESTAMP_NAMES,
41
43
  LEGACY_TIMESTAMP_COLUMN_MAP,
42
44
  ASSOCIATE_METADATA_MAP,
43
- TIMESTAMP_ATTRIBUTE_NAMES
45
+ TIMESTAMP_ATTRIBUTE_NAMES,
46
+ AGGREGATORS,
44
47
  };
@@ -3,7 +3,7 @@
3
3
  const SqlString = require('sqlstring');
4
4
 
5
5
  const { copyExpr, findExpr, walkExpr } = require('../../expr');
6
- const { formatExpr, formatConditions, collectLiteral } = require('../../expr_formatter');
6
+ const { formatExpr, formatConditions, collectLiteral, isAggregatorExpr } = require('../../expr_formatter');
7
7
  const Raw = require('../../raw');
8
8
 
9
9
  /**
@@ -91,10 +91,12 @@ function formatSelectExpr(spell, values) {
91
91
  const baseName = Model.tableAlias;
92
92
  const selects = new Set();
93
93
  const map = {};
94
+ let isAggregate = false;
94
95
 
95
96
  for (const token of columns) {
96
97
  collectLiteral(spell, token, values);
97
98
  const selectExpr = formatExpr(spell, token);
99
+ isAggregate = isAggregate || isAggregatorExpr(spell, token);
98
100
  const qualifier = token.qualifiers ? token.qualifiers[0] : '';
99
101
  const list = map[qualifier] || (map[qualifier] = []);
100
102
  list.push(selectExpr);
@@ -104,7 +106,7 @@ function formatSelectExpr(spell, values) {
104
106
  const list = map[qualifier];
105
107
  if (list) {
106
108
  for (const selectExpr of list) selects.add(selectExpr);
107
- } else if (groups.length === 0 && Model.driver.type !== 'sqlite') {
109
+ } else if (groups.length === 0 && Model.driver.type !== 'sqlite' && !isAggregate) {
108
110
  selects.add(`${escapeId(qualifier)}.*`);
109
111
  }
110
112
  }
@@ -163,7 +165,7 @@ class SpellBook {
163
165
  const { escapeId } = Model.driver;
164
166
  let columns = [];
165
167
  let updateOnDuplicateColumns = [];
166
-
168
+
167
169
  let values = [];
168
170
  let placeholders = [];
169
171
  if (Array.isArray(sets)) {
@@ -181,14 +183,14 @@ class SpellBook {
181
183
  columnAttributes.push(Model.columnAttributes[name]);
182
184
  }
183
185
  }
184
-
186
+
185
187
  for (const entry of columnAttributes) {
186
188
  columns.push(entry.columnName);
187
- if (updateOnDuplicate && createdAt && entry.name === createdAt
189
+ if (updateOnDuplicate && createdAt && entry.name === createdAt
188
190
  && !(Array.isArray(updateOnDuplicate) && updateOnDuplicate.includes(createdAt))) continue;
189
191
  updateOnDuplicateColumns.push(entry.columnName);
190
192
  }
191
-
193
+
192
194
  for (const entry of sets) {
193
195
  if (shardingKey && entry[shardingKey] == null) {
194
196
  throw new Error(`Sharding key ${Model.table}.${shardingKey} cannot be NULL.`);
@@ -199,7 +201,7 @@ class SpellBook {
199
201
  }
200
202
  placeholders.push(`(${new Array(columnAttributes.length).fill('?').join(',')})`);
201
203
  }
202
-
204
+
203
205
  } else {
204
206
  if (shardingKey && sets[shardingKey] == null) {
205
207
  throw new Error(`Sharding key ${Model.table}.${shardingKey} cannot be NULL.`);
@@ -216,10 +218,10 @@ class SpellBook {
216
218
  updateOnDuplicateColumns.push(Model.unalias(name));
217
219
  }
218
220
  }
219
-
220
-
221
+
222
+
221
223
  const chunks = ['INSERT'];
222
-
224
+
223
225
  // see https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html
224
226
  const hintStr = this.formatOptimizerHints(spell);
225
227
  if (hintStr) {
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const { precedes, walkExpr } = require('./expr');
4
+ const { AGGREGATORS } = require('./constants');
4
5
 
5
6
  /**
6
7
  * Find model by qualifiers.
@@ -65,6 +66,31 @@ function formatLiteral(spell, ast) {
65
66
  return '?';
66
67
  }
67
68
 
69
+ /**
70
+ * Format the abstract syntax tree of an expression into escaped string.
71
+ * @param {Spell} spell
72
+ * @param {Object} ast
73
+ */
74
+ function isAggregatorExpr(spell, ast) {
75
+ const { type, name, args } = ast;
76
+ switch (type) {
77
+ case 'literal':
78
+ case 'subquery':
79
+ case 'wildcard':
80
+ case 'mod':
81
+ case 'id':
82
+ case 'raw':
83
+ case 'op':
84
+ return false;
85
+ case 'alias':
86
+ return isAggregatorExpr(spell, args[0]);
87
+ case 'func':
88
+ return AGGREGATORS.includes(name);
89
+ default:
90
+ throw new Error(`Unexpected type ${type}`);
91
+ }
92
+ }
93
+
68
94
  /**
69
95
  * Format the abstract syntax tree of an expression into escaped string.
70
96
  * @param {Spell} spell
@@ -216,4 +242,4 @@ function coerceLiteral(spell, ast) {
216
242
  }
217
243
  }
218
244
 
219
- module.exports = { formatExpr, formatConditions, collectLiteral };
245
+ module.exports = { formatExpr, formatConditions, collectLiteral, isAggregatorExpr };
package/types/index.d.ts CHANGED
@@ -205,6 +205,11 @@ interface QueryOptions {
205
205
  hooks?: boolean;
206
206
  paranoid?: boolean;
207
207
  silent?: boolean;
208
+ connection?: Connection;
209
+ }
210
+
211
+ interface TransactionOptions {
212
+ connection: Connection;
208
213
  }
209
214
 
210
215
  interface QueryResult {
@@ -214,7 +219,7 @@ interface QueryResult {
214
219
  fields?: Array<{ table: string, name: string }>,
215
220
  }
216
221
 
217
- interface Connection {
222
+ export interface Connection {
218
223
  /**
219
224
  * MySQL
220
225
  */
@@ -322,10 +327,10 @@ declare class AbstractDriver {
322
327
  * @param callback
323
328
  */
324
329
  disconnect(callback?: Function): Promise<boolean | void>;
325
-
330
+
326
331
  /**
327
332
  * query with spell
328
- * @param spell
333
+ * @param spell
329
334
  */
330
335
  cast(spell: Spell<typeof Bone, ResultSet | number | null>): Promise<QueryResult>;
331
336
 
@@ -424,7 +429,7 @@ declare class AbstractDriver {
424
429
  * remove index in table
425
430
  * @param table string
426
431
  * @param attributes attributes name
427
- * @param opts
432
+ * @param opts
428
433
  */
429
434
  removeIndex(table: string, attributes: string[], opts?: { unique?: boolean, type?: string }): Promise<void>;
430
435
 
@@ -695,7 +700,7 @@ export class Bone {
695
700
  * });
696
701
  */
697
702
  static transaction(callback: GeneratorFunction): Promise<RawQueryResult>;
698
- static transaction(callback: (connection: Connection) => Promise<RawQueryResult>): Promise<RawQueryResult>;
703
+ static transaction(callback: (connection: TransactionOptions) => Promise<RawQueryResult | void>): Promise<RawQueryResult>;
699
704
 
700
705
  /**
701
706
  * DROP the table