tspace-mysql 1.2.1 → 1.2.3

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
@@ -45,12 +45,13 @@ DB_USERNAME = root
45
45
  DB_PASSWORD = password
46
46
  DB_DATABASE = database
47
47
 
48
- /** default
49
- DB_CONNECTION_LIMIT = 30
50
- DB_CONNECTION_ERROR = true
51
- DB_QUEUE_LIMIT = 25
52
- DB_TIMEOUT = 30000
53
- DB_DATE_STRINGS = true
48
+ /**
49
+ * @default
50
+ * DB_CONNECTION_LIMIT = 10
51
+ * DB_CONNECTION_ERROR = true
52
+ * DB_QUEUE_LIMIT = 0
53
+ * DB_TIMEOUT = 60000
54
+ * DB_DATE_STRINGS = true
54
55
  */
55
56
 
56
57
  ```
@@ -358,16 +359,31 @@ import { Model } from 'tspace-mysql'
358
359
  class User extends Model {
359
360
  constructor(){
360
361
  super()
361
- this.useTimestamp() /** created_at , updated_at
362
362
  /**
363
363
  *
364
- * @Custom
365
- *
364
+ * Assign setting global in your model
365
+ * @useMethod
366
+ *
367
+ * this.useDebug()
368
+ * this.usePrimaryKey('id')
366
369
  * this.useTimestamp({
367
370
  * createdAt : 'created_at',
368
371
  * updatedAt : 'updated_at'
369
- * })
370
- */
372
+ * }) // runing a timestamp when insert or update
373
+ * this.useSoftDelete()
374
+ * this.useTable('users')
375
+ * this.useTableSingular() // 'user'
376
+ * this.useTablePlural() // 'users'
377
+ * this.usePattern('snake_case')
378
+ * this.useUUID('uuid') // => runing a uuid (universally unique identifier) when insert new data
379
+ * this.useRegistry()
380
+ * this.useSchema({
381
+ * id : Number,
382
+ * username : String
383
+ * created_at : Date,
384
+ * updated_at : Date,
385
+ * }) // validate type of schema when return result
386
+ */
371
387
 
372
388
  /*
373
389
  * the "snake case", plural name of the class will be used as the table name
@@ -624,7 +640,7 @@ hook((result) => ...) // callback result to function
624
640
  hasOne({ name , model , localKey , foreignKey , freezeTable , as })
625
641
  hasMany({ name , model , localKey , foreignKey , freezeTable , as })
626
642
  belongsTo({ name , model , localKey , foreignKey , freezeTable , as })
627
- belongsToMany({ name , model , localKey , foreignKey , freezeTable , as })
643
+ belongsToMany({ name , model , localKey , foreignKey , freezeTable , as , pivot })
628
644
  /**
629
645
  * @relation using registry in your models
630
646
  */
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const model_1 = __importDefault(require("../models/model"));
6
+ const model_1 = __importDefault(require("./model"));
7
7
  const pluralize_1 = __importDefault(require("pluralize"));
8
8
  const lib_1 = require("../../lib");
9
9
  exports.default = (cmd) => {
@@ -0,0 +1,2 @@
1
+ declare const Model: (model: string, npm: string) => string;
2
+ export default Model;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const Model = (model, npm) => {
4
+ return `import { Model } from '${npm}'
5
+ class ${model} extends Model {
6
+ constructor(){
7
+ super()
8
+ /**
9
+ *
10
+ * Assign setting global in your model
11
+ * @useMethod
12
+ *
13
+ * this.useDebug() // => runing a uuid (universally unique identifier) when insert new data
14
+ * this.usePrimaryKey('id') // => runing a uuid (universally unique identifier) when insert new data
15
+ * this.useTimestamp({ createdAt : 'created_at' , updatedAt : 'updated_at' }) // runing a timestamp when insert or update
16
+ * this.useSoftDelete()
17
+ * this.useTable('users')
18
+ * this.useTableSingular() // 'user'
19
+ * this.useTablePlural() // 'users'
20
+ * this.usePattern('snake_case')
21
+ * this.useUUID('uuid')
22
+ * this.useRegistry()
23
+ */
24
+ }
25
+ }
26
+ export { ${model} }
27
+ export default ${model}
28
+ `;
29
+ };
30
+ exports.default = Model;
@@ -109,7 +109,7 @@ class PoolConnection {
109
109
  "password" : "",
110
110
  "connectionLimit" : "",
111
111
  "dateStrings" : "",
112
- "connectTimeout" : "",
112
+ "idleTimeout" : "",
113
113
  "waitForConnections" : "",
114
114
  "queueLimit" : "",
115
115
  "charset" : ""
@@ -24,9 +24,9 @@ const env = {
24
24
  USERNAME: process.env.DB_USERNAME || process.env.TSPACE_USERNAME,
25
25
  PASSWORD: process.env.DB_PASSWORD || process.env.TSPACE_PASSWORD || '',
26
26
  DATABASE: process.env.DB_DATABASE || process.env.TSPACE_DATABASE,
27
- CONNECTION_LIMIT: process.env.DB_CONNECTION_LIMIT || process.env.TSPACE_CONNECTION_LIMIT || 151,
28
- QUEUE_LIMIT: process.env.DB_QUEUE_LIMIT || process.env.TSPACE_QUEUE_LIMIT || 25,
29
- TIMEOUT: process.env.DB_TIMEOUT || process.env.TSPACE_TIMEOUT || 1000 * 30,
27
+ CONNECTION_LIMIT: process.env.DB_CONNECTION_LIMIT || process.env.TSPACE_CONNECTION_LIMIT || 10,
28
+ QUEUE_LIMIT: process.env.DB_QUEUE_LIMIT || process.env.TSPACE_QUEUE_LIMIT || 0,
29
+ TIMEOUT: process.env.DB_TIMEOUT || process.env.TSPACE_TIMEOUT || 1000 * 60,
30
30
  CHARSET: process.env.DB_CHARSET || process.env.TSPACE_CHARSET || 'utf8mb4',
31
31
  CONNECTION_ERROR: process.env.DB_CONNECTION_ERROR || process.env.TSPACE_CONNECTION_ERROR || true,
32
32
  WAIT_FOR_CONNECTIONS: process.env.DB_WAIT_FOR_CONNECTIONS || process.env.TSPACE_WAIT_FOR_CONNECTIONS || true,
@@ -151,6 +151,7 @@ const CONSTANTS = {
151
151
  CREATED_AT: 'created_at',
152
152
  UPDATED_AT: 'updated_at'
153
153
  },
154
+ SCHEMA: null
154
155
  }
155
156
  };
156
157
  exports.CONSTANTS = CONSTANTS;
@@ -1283,16 +1283,14 @@ class Database extends AbstractDatabase_1.default {
1283
1283
  throw new Error(`can't find property '${pluck}' of result`);
1284
1284
  const r = newData[pluck] || null;
1285
1285
  const hook = this.$state.get('HOOK');
1286
- if (hook)
1287
- for (let i in hook)
1288
- yield hook[i](r);
1286
+ for (let i in hook)
1287
+ yield hook[i](r);
1289
1288
  return r;
1290
1289
  }
1291
1290
  const r = (result === null || result === void 0 ? void 0 : result.shift()) || null;
1292
1291
  const hook = this.$state.get('HOOK');
1293
- if (hook)
1294
- for (let i in hook)
1295
- yield hook[i](r);
1292
+ for (let i in hook)
1293
+ yield hook[i](r);
1296
1294
  return r;
1297
1295
  });
1298
1296
  }
@@ -1338,9 +1336,8 @@ class Database extends AbstractDatabase_1.default {
1338
1336
  throw Object.assign({ message }, options);
1339
1337
  }
1340
1338
  const hook = this.$state.get('HOOK');
1341
- if (hook)
1342
- for (let i in hook)
1343
- yield hook[i](data);
1339
+ for (let i in hook)
1340
+ yield hook[i](data);
1344
1341
  return data;
1345
1342
  }
1346
1343
  const data = (result === null || result === void 0 ? void 0 : result.shift()) || null;
@@ -1351,9 +1348,8 @@ class Database extends AbstractDatabase_1.default {
1351
1348
  throw Object.assign({ message }, options);
1352
1349
  }
1353
1350
  const hook = this.$state.get('HOOK');
1354
- if (hook)
1355
- for (let i in hook)
1356
- yield hook[i](data);
1351
+ for (let i in hook)
1352
+ yield hook[i](data);
1357
1353
  return data;
1358
1354
  });
1359
1355
  }
@@ -1390,9 +1386,8 @@ class Database extends AbstractDatabase_1.default {
1390
1386
  return resultArray;
1391
1387
  }, []);
1392
1388
  const hook = this.$state.get('HOOK');
1393
- if (hook)
1394
- for (let i in hook)
1395
- yield hook[i](data || []);
1389
+ for (let i in hook)
1390
+ yield hook[i](data || []);
1396
1391
  return data || [];
1397
1392
  }
1398
1393
  if (this.$state.get('PLUCK')) {
@@ -1402,15 +1397,13 @@ class Database extends AbstractDatabase_1.default {
1402
1397
  throw new Error(`can't find property '${pluck}' of result`);
1403
1398
  }
1404
1399
  const hook = this.$state.get('HOOK');
1405
- if (hook)
1406
- for (let i in hook)
1407
- yield hook[i](newData || []);
1400
+ for (let i in hook)
1401
+ yield hook[i](newData || []);
1408
1402
  return newData || [];
1409
1403
  }
1410
1404
  const hook = this.$state.get('HOOK');
1411
- if (hook)
1412
- for (let i in hook)
1413
- yield hook[i](result || []);
1405
+ for (let i in hook)
1406
+ yield hook[i](result || []);
1414
1407
  return result || [];
1415
1408
  });
1416
1409
  }
@@ -5,6 +5,7 @@ export interface Relation {
5
5
  localKey?: string | undefined;
6
6
  foreignKey?: string | undefined;
7
7
  freezeTable?: string | undefined;
8
+ pivot?: string | undefined;
8
9
  query?: any | undefined;
9
10
  relation?: Object | undefined;
10
11
  }
@@ -15,6 +16,7 @@ export interface RelationQuery {
15
16
  localKey?: string | undefined;
16
17
  foreignKey?: string | undefined;
17
18
  freezeTable?: string | undefined;
19
+ pivot?: string | undefined;
18
20
  query?: any | undefined;
19
21
  relation?: Object | undefined;
20
22
  }
@@ -15,10 +15,10 @@ declare class Model extends AbstractModel {
15
15
  */
16
16
  protected useRegistry(): this;
17
17
  /**
18
- *
19
- * Assign primary column in model
20
- * @return {this} this
21
- */
18
+ *
19
+ * Assign primary column in model
20
+ * @return {this} this
21
+ */
22
22
  protected usePrimaryKey(primary: string): this;
23
23
  /**
24
24
  * Assign generate uuid when creating in model
@@ -77,6 +77,15 @@ declare class Model extends AbstractModel {
77
77
  * @return {this} this
78
78
  */
79
79
  protected useTablePlural(): this;
80
+ /**
81
+ *
82
+ * Assign schema column in model
83
+ * @param {Object<Function>} schema type String Number and Date
84
+ * @return {this} this
85
+ */
86
+ protected useSchema(schema: {
87
+ [key: string]: Function;
88
+ }): this;
80
89
  /**
81
90
  * Build method for relation in model
82
91
  * @param {string} name name relation registry in your model
@@ -222,7 +231,7 @@ declare class Model extends AbstractModel {
222
231
  * @property {string} relation.freezeTable
223
232
  * @return {this} this
224
233
  */
225
- protected belongsToMany({ name, as, model, localKey, foreignKey, freezeTable }: Relation): this;
234
+ protected belongsToMany({ name, as, model, localKey, foreignKey, freezeTable, pivot }: Relation): this;
226
235
  /**
227
236
  * Assign the relation in model Objects
228
237
  * @param {object} relation registry relation in your model
@@ -278,7 +287,7 @@ declare class Model extends AbstractModel {
278
287
  * @param {function?} callback callback of query
279
288
  * @return {this} this
280
289
  */
281
- protected belongsToManyBuilder({ name, as, model, localKey, foreignKey, freezeTable }: RelationQuery, callback?: Function): this;
290
+ protected belongsToManyBuilder({ name, as, model, localKey, foreignKey, freezeTable, pivot }: RelationQuery, callback?: Function): this;
282
291
  /**
283
292
  * return only in trashed (data has been remove)
284
293
  * @return {promise}
@@ -540,6 +549,7 @@ declare class Model extends AbstractModel {
540
549
  * @return {this} this this
541
550
  */
542
551
  createNotExists(data: object): this;
552
+ getSchema(): Promise<any>;
543
553
  /**
544
554
  *
545
555
  * @override Method
@@ -566,13 +576,13 @@ declare class Model extends AbstractModel {
566
576
  private _handleSoftDelete;
567
577
  private _buildQueryModel;
568
578
  private _showOnly;
579
+ private _validateSchema;
569
580
  private _execute;
570
581
  private _executeGroup;
571
582
  private _relationMapData;
572
583
  private _handleRelationsExists;
573
584
  private _queryRelationsExists;
574
585
  private _relation;
575
- private _handleBelongsToMany;
576
586
  private _belongsToMany;
577
587
  private _pagination;
578
588
  private _result;
@@ -37,8 +37,7 @@ class Model extends AbstractModel_1.AbstractModel {
37
37
  * define for initialize of models
38
38
  * @return {void} void
39
39
  */
40
- define() {
41
- }
40
+ define() { }
42
41
  /**
43
42
  *
44
43
  * Assign function callback in model
@@ -49,10 +48,10 @@ class Model extends AbstractModel_1.AbstractModel {
49
48
  return this;
50
49
  }
51
50
  /**
52
- *
53
- * Assign primary column in model
54
- * @return {this} this
55
- */
51
+ *
52
+ * Assign primary column in model
53
+ * @return {this} this
54
+ */
56
55
  usePrimaryKey(primary) {
57
56
  this.$state.set('PRIMARY_KEY', primary);
58
57
  return this;
@@ -154,6 +153,16 @@ class Model extends AbstractModel_1.AbstractModel {
154
153
  this.$state.set('TABLE_NAME', `\`${pluralize_1.default.plural(table)}\``);
155
154
  return this;
156
155
  }
156
+ /**
157
+ *
158
+ * Assign schema column in model
159
+ * @param {Object<Function>} schema type String Number and Date
160
+ * @return {this} this
161
+ */
162
+ useSchema(schema) {
163
+ this.$state.set('SCHEMA', schema);
164
+ return this;
165
+ }
157
166
  /**
158
167
  * Build method for relation in model
159
168
  * @param {string} name name relation registry in your model
@@ -444,7 +453,7 @@ class Model extends AbstractModel_1.AbstractModel {
444
453
  * @property {string} relation.freezeTable
445
454
  * @return {this} this
446
455
  */
447
- belongsToMany({ name, as, model, localKey, foreignKey, freezeTable }) {
456
+ belongsToMany({ name, as, model, localKey, foreignKey, freezeTable, pivot }) {
448
457
  const relation = {
449
458
  name,
450
459
  model,
@@ -453,6 +462,7 @@ class Model extends AbstractModel_1.AbstractModel {
453
462
  localKey,
454
463
  foreignKey,
455
464
  freezeTable,
465
+ pivot,
456
466
  query: null
457
467
  };
458
468
  this.$state.set('RELATION', [...this.$state.get('RELATION'), relation]);
@@ -576,7 +586,7 @@ class Model extends AbstractModel_1.AbstractModel {
576
586
  * @param {function?} callback callback of query
577
587
  * @return {this} this
578
588
  */
579
- belongsToManyBuilder({ name, as, model, localKey, foreignKey, freezeTable }, callback) {
589
+ belongsToManyBuilder({ name, as, model, localKey, foreignKey, freezeTable, pivot }, callback) {
580
590
  const nameRelation = name == null
581
591
  ? this._functionRelationName()
582
592
  : String(name);
@@ -588,6 +598,7 @@ class Model extends AbstractModel_1.AbstractModel {
588
598
  localKey,
589
599
  foreignKey,
590
600
  freezeTable,
601
+ pivot,
591
602
  query: null
592
603
  };
593
604
  const r = this._handleRelationsQuery(nameRelation, relation);
@@ -1307,6 +1318,54 @@ class Model extends AbstractModel_1.AbstractModel {
1307
1318
  this.$state.set('SAVE', 'INSERT_NOT_EXISTS');
1308
1319
  return this;
1309
1320
  }
1321
+ getSchema() {
1322
+ return __awaiter(this, void 0, void 0, function* () {
1323
+ const sql = [
1324
+ `${this.$constants('SHOW')}`,
1325
+ `${this.$constants('COLUMNS')}`,
1326
+ `${this.$constants('FROM')}`,
1327
+ `\`${this.$state.get('TABLE_NAME').replace(/\`/g, '')}\``
1328
+ ].join(' ');
1329
+ const raw = yield this.queryStatement(sql);
1330
+ const schemas = raw.map((r) => {
1331
+ let schema = { [r.Field]: String };
1332
+ const numberLists = [
1333
+ 'tinyint',
1334
+ 'smallint',
1335
+ 'mediumint',
1336
+ 'int',
1337
+ 'bigint',
1338
+ 'float',
1339
+ 'double',
1340
+ 'decimal',
1341
+ 'real',
1342
+ 'bit',
1343
+ 'boolean',
1344
+ 'serial'
1345
+ ];
1346
+ const dateAndTimeLists = [
1347
+ 'date',
1348
+ 'datetime',
1349
+ 'time',
1350
+ 'timestamp',
1351
+ 'year'
1352
+ ];
1353
+ if (numberLists.includes(r.Type)) {
1354
+ schema = {
1355
+ [r.Field]: Number
1356
+ };
1357
+ }
1358
+ if (dateAndTimeLists.includes(r.Type)) {
1359
+ schema = {
1360
+ [r.Field]: Date
1361
+ };
1362
+ }
1363
+ return schema;
1364
+ });
1365
+ const result = Object.assign({}, ...schemas);
1366
+ return result;
1367
+ });
1368
+ }
1310
1369
  /**
1311
1370
  *
1312
1371
  * @override Method
@@ -1314,6 +1373,7 @@ class Model extends AbstractModel_1.AbstractModel {
1314
1373
  */
1315
1374
  save() {
1316
1375
  return __awaiter(this, void 0, void 0, function* () {
1376
+ this._validateMethod('save');
1317
1377
  const attributes = this.$attributes;
1318
1378
  if (attributes != null) {
1319
1379
  while (true) {
@@ -1418,12 +1478,13 @@ class Model extends AbstractModel_1.AbstractModel {
1418
1478
  return (_a = this.$state.get('TABLE_NAME')) === null || _a === void 0 ? void 0 : _a.replace(/`/g, '');
1419
1479
  }
1420
1480
  _valueInRelation(relationModel) {
1421
- var _a, _b;
1481
+ var _a, _b, _c, _d;
1422
1482
  const relation = relationModel.relation;
1423
1483
  const model = (_a = relationModel.model) === null || _a === void 0 ? void 0 : _a.name;
1424
1484
  const table = relationModel.freezeTable
1425
1485
  ? relationModel.freezeTable
1426
1486
  : (_b = relationModel.query) === null || _b === void 0 ? void 0 : _b._tableName();
1487
+ let pivot = null;
1427
1488
  const name = relationModel.name;
1428
1489
  const as = relationModel.as;
1429
1490
  this._assertError(!model || model == null, 'not found model');
@@ -1459,8 +1520,12 @@ class Model extends AbstractModel_1.AbstractModel {
1459
1520
  `${this.$state.get('PRIMARY_KEY')}`
1460
1521
  ].join('_'));
1461
1522
  foreignKey = 'id';
1523
+ pivot = (_c = relationModel.pivot) !== null && _c !== void 0 ? _c : this._valuePattern([
1524
+ pluralize_1.default.singular(this === null || this === void 0 ? void 0 : this._tableName()),
1525
+ pluralize_1.default.singular((_d = relationModel.query) === null || _d === void 0 ? void 0 : _d._tableName())
1526
+ ].sort().join('_'));
1462
1527
  }
1463
- return { name, as, relation, table, localKey, foreignKey, model };
1528
+ return { name, as, relation, table, localKey, foreignKey, model, pivot };
1464
1529
  }
1465
1530
  _handleSoftDelete() {
1466
1531
  if (this.$state.get('SOFT_DELETE')) {
@@ -1527,9 +1592,36 @@ class Model extends AbstractModel_1.AbstractModel {
1527
1592
  });
1528
1593
  return result;
1529
1594
  }
1595
+ _validateSchema(results) {
1596
+ const schema = this.$state.get('SCHEMA');
1597
+ if (schema == null)
1598
+ return;
1599
+ if (!results.length)
1600
+ return;
1601
+ const typeOf = (data) => Object.prototype.toString.apply(data).slice(8, -1).toLocaleLowerCase();
1602
+ for (const result of results) {
1603
+ for (const key in result) {
1604
+ const s = schema[key];
1605
+ if (s == null)
1606
+ this._assertError(`not found this column [${key}] in schema`);
1607
+ const regexDate = /[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])/;
1608
+ const regexDateTime = /[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1]) (2[0-3]|[01][0-9]):[0-5][0-9]/;
1609
+ if (regexDate.test(result[key]) || regexDateTime.test(result[key])) {
1610
+ if (typeOf(new Date(result[key])) === typeOf(new s()))
1611
+ continue;
1612
+ this._assertError(`this column [${key}] is invalid schema field type`);
1613
+ }
1614
+ if (typeOf(result[key]) === typeOf(new s()))
1615
+ continue;
1616
+ this._assertError(`this column [${key}] is invalid schema field type`);
1617
+ }
1618
+ }
1619
+ return this;
1620
+ }
1530
1621
  _execute({ sql, type, message, options }) {
1531
1622
  return __awaiter(this, void 0, void 0, function* () {
1532
1623
  let result = yield this.queryStatement(sql);
1624
+ this._validateSchema(result);
1533
1625
  if (!result.length)
1534
1626
  return this._returnEmpty(type, result, message, options);
1535
1627
  const relations = this.$state.get('WITH');
@@ -1629,7 +1721,7 @@ class Model extends AbstractModel_1.AbstractModel {
1629
1721
  const relation = relations[index];
1630
1722
  if (!((_a = Object.keys(relation)) === null || _a === void 0 ? void 0 : _a.length))
1631
1723
  continue;
1632
- const { localKey, foreignKey } = this._valueInRelation(relation);
1724
+ const { localKey, foreignKey, pivot } = this._valueInRelation(relation);
1633
1725
  const query = relation.query;
1634
1726
  this._assertError(query == null, `unknown callback query in [relation : '${relation.name}']`);
1635
1727
  let clone = new Model().clone(query);
@@ -1641,6 +1733,21 @@ class Model extends AbstractModel_1.AbstractModel {
1641
1733
  clone.whereExists(sql);
1642
1734
  }
1643
1735
  }
1736
+ if (relation.relation === this.$constants('RELATIONSHIP').belongsToMany) {
1737
+ const sql = clone
1738
+ .bind(this.$pool.get())
1739
+ .whereReference(`\`${this._tableName()}\`.\`${localKey}\``, `\`${query._tableName()}\`.\`${foreignKey}\``)
1740
+ .toString();
1741
+ this.whereExists(sql);
1742
+ const thisPivot = new Model();
1743
+ thisPivot.$state.set('TABLE_NAME', `\`${pivot}\``);
1744
+ const sqlPivot = thisPivot
1745
+ .bind(this.$pool.get())
1746
+ .whereReference(`\`${this._tableName()}\`.\`${foreignKey}\``, `\`${pivot}\`.\`${this._valuePattern([pluralize_1.default.singular(this._tableName()), foreignKey].join("_"))}\``)
1747
+ .toString();
1748
+ this.whereExists(sqlPivot);
1749
+ continue;
1750
+ }
1644
1751
  const sql = clone
1645
1752
  .bind(this.$pool.get())
1646
1753
  .whereReference(`\`${this._tableName()}\`.\`${localKey}\``, `\`${query._tableName()}\`.\`${foreignKey}\``)
@@ -1676,66 +1783,15 @@ class Model extends AbstractModel_1.AbstractModel {
1676
1783
  return dataFromRelation;
1677
1784
  });
1678
1785
  }
1679
- _handleBelongsToMany(dataFromParent, relation, pivotTable) {
1786
+ _belongsToMany(dataFromParent, relation) {
1787
+ var _a;
1680
1788
  return __awaiter(this, void 0, void 0, function* () {
1681
- if (this.$state.get('WITH_EXISTS')) {
1682
- let { name, localKey, foreignKey, model, table } = this._valueInRelation(relation);
1683
- const localKeyId = dataFromParent.map((parent) => {
1684
- const data = parent[localKey];
1685
- if (!parent.hasOwnProperty(localKey)) {
1686
- this._assertError(data == null, "unknown relationship without primary or foreign key");
1687
- }
1688
- return data;
1689
- }).filter((data) => data != null);
1690
- const dataPerentId = Array.from(new Set(localKeyId)).join(',') || [];
1691
- if (!dataPerentId.length && this.$state.get('WITH_EXISTS'))
1692
- return [];
1693
- const modelOther = new relation.model();
1694
- const other = this._classToTableName(modelOther.constructor.name, { singular: true });
1695
- const otherlocalKey = 'id';
1696
- const otherforeignKey = this._valuePattern(`${other}Id`);
1697
- const sqldataChilds = [
1698
- `${this.$constants('SELECT')}`,
1699
- `*`,
1700
- `${this.$constants('FROM')}`,
1701
- `${pivotTable}`,
1702
- `${this.$constants('WHERE')}`,
1703
- `${otherforeignKey} ${this.$constants('IN')} (${dataPerentId})`
1704
- ].join(' ');
1705
- let dataChilds = yield this.queryStatement(sqldataChilds);
1706
- const otherId = dataChilds.map((sub) => sub[otherforeignKey]).filter((data) => data != null);
1707
- const otherArrId = Array.from(new Set(otherId)) || [];
1708
- const otherdataChilds = yield this.queryStatement(modelOther
1709
- .bind(this.$pool.get())
1710
- .whereIn(otherlocalKey, otherArrId)
1711
- .debug(this.$state.get('DEBUG'))
1712
- .toString());
1713
- dataChilds.forEach((sub) => {
1714
- sub[other] = [];
1715
- otherdataChilds.forEach((otherSub) => {
1716
- if (otherSub[otherlocalKey] === sub[otherforeignKey]) {
1717
- sub[other] = otherSub;
1718
- }
1719
- });
1720
- });
1721
- dataFromParent.forEach((dataPerent) => {
1722
- if (dataPerent[name] == null)
1723
- dataPerent[name] = [];
1724
- dataChilds.forEach((sub) => {
1725
- if (sub[localKey] === dataPerent[otherforeignKey]) {
1726
- dataPerent[name].push(sub);
1727
- }
1728
- });
1729
- });
1730
- if (this.$state.get('HIDDEN').length)
1731
- this._hiddenColumnModel(dataFromParent);
1732
- return dataFromParent;
1733
- }
1734
- let { name, localKey, foreignKey } = this._valueInRelation(relation);
1789
+ const { name, foreignKey, pivot } = this._valueInRelation(relation);
1790
+ const pivotTable = String(((_a = relation.pivot) !== null && _a !== void 0 ? _a : pivot));
1735
1791
  const localKeyId = dataFromParent.map((parent) => {
1736
- const data = parent[localKey];
1737
- if (!parent.hasOwnProperty(localKey)) {
1738
- this._assertError(data == null, "unknown relationship without primary or foreign key");
1792
+ const data = parent[foreignKey];
1793
+ if (!parent.hasOwnProperty(foreignKey)) {
1794
+ this._assertError(data == null, `unknown relationship without primary or foreign key in relation : [${relation === null || relation === void 0 ? void 0 : relation.name}]`);
1739
1795
  }
1740
1796
  return data;
1741
1797
  }).filter((data) => data != null);
@@ -1746,13 +1802,14 @@ class Model extends AbstractModel_1.AbstractModel {
1746
1802
  const other = this._classToTableName(modelOther.constructor.name, { singular: true });
1747
1803
  const otherlocalKey = 'id';
1748
1804
  const otherforeignKey = this._valuePattern(`${other}Id`);
1805
+ const localKeyPivotTable = this._valuePattern([pluralize_1.default.singular(this._tableName()), foreignKey].join("_"));
1749
1806
  const sqldataChilds = [
1750
1807
  `${this.$constants('SELECT')}`,
1751
1808
  `*`,
1752
1809
  `${this.$constants('FROM')}`,
1753
1810
  `${pivotTable}`,
1754
1811
  `${this.$constants('WHERE')}`,
1755
- `${foreignKey} ${this.$constants('IN')} (${dataPerentId})`
1812
+ `${localKeyPivotTable} ${this.$constants('IN')} (${dataPerentId})`
1756
1813
  ].join(' ');
1757
1814
  let dataChilds = yield this.queryStatement(sqldataChilds);
1758
1815
  const otherId = dataChilds.map((sub) => sub[otherforeignKey]).filter((data) => data != null);
@@ -1763,7 +1820,6 @@ class Model extends AbstractModel_1.AbstractModel {
1763
1820
  .debug(this.$state.get('DEBUG'))
1764
1821
  .toString());
1765
1822
  dataChilds.forEach((sub) => {
1766
- sub[other] = [];
1767
1823
  otherdataChilds.forEach((otherSub) => {
1768
1824
  if (otherSub[otherlocalKey] === sub[otherforeignKey]) {
1769
1825
  sub[other] = otherSub;
@@ -1774,7 +1830,7 @@ class Model extends AbstractModel_1.AbstractModel {
1774
1830
  if (dataPerent[name] == null)
1775
1831
  dataPerent[name] = [];
1776
1832
  dataChilds.forEach((sub) => {
1777
- if (sub[foreignKey] === dataPerent[localKey]) {
1833
+ if (sub[localKeyPivotTable] === dataPerent[foreignKey]) {
1778
1834
  dataPerent[name].push(sub);
1779
1835
  }
1780
1836
  });
@@ -1784,27 +1840,6 @@ class Model extends AbstractModel_1.AbstractModel {
1784
1840
  return dataFromParent;
1785
1841
  });
1786
1842
  }
1787
- _belongsToMany(dataFromParent, relation) {
1788
- var _a, _b;
1789
- return __awaiter(this, void 0, void 0, function* () {
1790
- const local = this._classToTableName(this.constructor.name, { singular: true });
1791
- const modelOther = new relation.model();
1792
- const other = this._classToTableName(modelOther.constructor.name, { singular: true });
1793
- try {
1794
- const pivotTable = (_a = relation.freezeTable) !== null && _a !== void 0 ? _a : `${local}_${other}`;
1795
- return yield this._handleBelongsToMany(dataFromParent, relation, pivotTable);
1796
- }
1797
- catch (err) {
1798
- try {
1799
- const pivotTable = (_b = relation.freezeTable) !== null && _b !== void 0 ? _b : `${other}_${local}`;
1800
- return yield this._handleBelongsToMany(dataFromParent, relation, pivotTable);
1801
- }
1802
- catch (e) {
1803
- throw new Error(err.message);
1804
- }
1805
- }
1806
- });
1807
- }
1808
1843
  _pagination(data) {
1809
1844
  var _a, _b;
1810
1845
  return __awaiter(this, void 0, void 0, function* () {
@@ -1896,16 +1931,14 @@ class Model extends AbstractModel_1.AbstractModel {
1896
1931
  if (this._isPatternSnakeCase()) {
1897
1932
  const empty = this.$utils.snakeCase(this._result(emptyData));
1898
1933
  const hook = this.$state.get('HOOK');
1899
- if (hook === null || hook === void 0 ? void 0 : hook.length)
1900
- for (let i in hook)
1901
- yield hook[i](empty);
1934
+ for (let i in hook)
1935
+ yield hook[i](empty);
1902
1936
  return empty;
1903
1937
  }
1904
1938
  const empty = this._result(emptyData);
1905
1939
  const hook = this.$state.get('HOOK');
1906
- if (hook === null || hook === void 0 ? void 0 : hook.length)
1907
- for (let i in hook)
1908
- yield hook[i](empty);
1940
+ for (let i in hook)
1941
+ yield hook[i](empty);
1909
1942
  return empty;
1910
1943
  });
1911
1944
  }
@@ -1980,9 +2013,8 @@ class Model extends AbstractModel_1.AbstractModel {
1980
2013
  }
1981
2014
  }
1982
2015
  const hook = this.$state.get('HOOK');
1983
- if (hook === null || hook === void 0 ? void 0 : hook.length)
1984
- for (let i in hook)
1985
- yield hook[i](result);
2016
+ for (let i in hook)
2017
+ yield hook[i](result);
1986
2018
  return result;
1987
2019
  });
1988
2020
  }
@@ -2222,15 +2254,13 @@ class Model extends AbstractModel_1.AbstractModel {
2222
2254
  const result = (data === null || data === void 0 ? void 0 : data.shift()) || null;
2223
2255
  this.$state.set('RESULT', result);
2224
2256
  const hook = this.$state.get('HOOK');
2225
- if (hook === null || hook === void 0 ? void 0 : hook.length)
2226
- for (let i in hook)
2227
- yield hook[i](result);
2257
+ for (let i in hook)
2258
+ yield hook[i](result);
2228
2259
  return result;
2229
2260
  }
2230
2261
  const hook = this.$state.get('HOOK');
2231
- if (hook === null || hook === void 0 ? void 0 : hook.length)
2232
- for (let i in hook)
2233
- yield hook[i](result || []);
2262
+ for (let i in hook)
2263
+ yield hook[i](result || []);
2234
2264
  return null;
2235
2265
  });
2236
2266
  }
@@ -2373,12 +2403,27 @@ class Model extends AbstractModel_1.AbstractModel {
2373
2403
  'updateOrCreate',
2374
2404
  'updateOrInsert',
2375
2405
  'insertOrUpdate',
2376
- 'update'
2406
+ 'update',
2407
+ 'delete'
2377
2408
  ];
2378
2409
  const findMethodNotAllowed = methodCallings.find((methodCalling) => methodsNotAllowed.includes(methodCalling));
2379
2410
  this._assertError(methodCallings.some((methodCalling) => methodsNotAllowed.includes(methodCalling)), `this method ${method} can't using method : [ ${findMethodNotAllowed} ]`);
2380
2411
  break;
2381
2412
  }
2413
+ case 'save': {
2414
+ const methodCallings = this.$logger.get();
2415
+ const methodsSomeAllowed = [
2416
+ 'create',
2417
+ 'createNotExists',
2418
+ 'updateOrCreate',
2419
+ 'updateOrInsert',
2420
+ 'insertOrUpdate',
2421
+ 'update',
2422
+ 'delete'
2423
+ ];
2424
+ this._assertError(!methodCallings.some((methodCalling) => methodsSomeAllowed.includes(methodCalling)), `this ${method} method need some : [ ${methodsSomeAllowed.join(', ')} ] methods`);
2425
+ break;
2426
+ }
2382
2427
  }
2383
2428
  }
2384
2429
  _initialModel() {
@@ -123,7 +123,7 @@ const camelCase = (obj) => {
123
123
  const consoleDebug = (debug) => {
124
124
  if (debug == null)
125
125
  return;
126
- console.log(`-----\n\x1b[33m${debug.replace(/(\r\n|\n|\r|\t)/gm, "").trim()}\x1b[0m`);
126
+ console.log(`\n\x1b[33m${debug.replace(/(\r\n|\n|\r|\t)/gm, "").trim()};\x1b[0m`);
127
127
  };
128
128
  const faker = (value) => {
129
129
  if (!value.search('timestamp'))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tspace-mysql",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
4
4
  "description": "mysql query builder object relational mapping",
5
5
  "main": "dist/lib/index.js",
6
6
  "types": "dist/lib/index.d.ts",