tspace-mysql 1.2.0 → 1.2.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/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
  ```
@@ -212,7 +213,7 @@ const user = await new DB('users')
212
213
  Running A Delete Query
213
214
  ```js
214
215
  const deleted = await new DB('users').where('id',1).delete()
215
- // deleted => true
216
+ // deleted => Boolean
216
217
  ```
217
218
  ## Database Transactions
218
219
 
@@ -300,7 +301,7 @@ Backup database, you may backup is this:
300
301
  * @param conection defalut current connection
301
302
  */
302
303
  const backup = await new DB().backup({
303
- database: 'try-to-backup', // clone current database to this
304
+ database: 'try-to-backup', // clone current database to this database
304
305
  connection ?: {
305
306
  host: 'localhost',
306
307
  port : 3306,
@@ -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
@@ -565,7 +581,7 @@ await new User().relations('posts')
565
581
  .relationQuery('user', (query : User) => {
566
582
  return query.relations('posts').relationQuery('posts',(query : Post)=> {
567
583
  return query.relations('comments','user')
568
- // relation n to ...n
584
+ // relation n, n, ...n
569
585
  })
570
586
  })
571
587
  })
@@ -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,14 +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
- yield hook(r);
1286
+ for (let i in hook)
1287
+ yield hook[i](r);
1288
1288
  return r;
1289
1289
  }
1290
1290
  const r = (result === null || result === void 0 ? void 0 : result.shift()) || null;
1291
1291
  const hook = this.$state.get('HOOK');
1292
- if (hook)
1293
- yield hook(r);
1292
+ for (let i in hook)
1293
+ yield hook[i](r);
1294
1294
  return r;
1295
1295
  });
1296
1296
  }
@@ -1336,8 +1336,8 @@ class Database extends AbstractDatabase_1.default {
1336
1336
  throw Object.assign({ message }, options);
1337
1337
  }
1338
1338
  const hook = this.$state.get('HOOK');
1339
- if (hook)
1340
- yield hook(data);
1339
+ for (let i in hook)
1340
+ yield hook[i](data);
1341
1341
  return data;
1342
1342
  }
1343
1343
  const data = (result === null || result === void 0 ? void 0 : result.shift()) || null;
@@ -1348,8 +1348,8 @@ class Database extends AbstractDatabase_1.default {
1348
1348
  throw Object.assign({ message }, options);
1349
1349
  }
1350
1350
  const hook = this.$state.get('HOOK');
1351
- if (hook)
1352
- yield hook(data);
1351
+ for (let i in hook)
1352
+ yield hook[i](data);
1353
1353
  return data;
1354
1354
  });
1355
1355
  }
@@ -1386,8 +1386,8 @@ class Database extends AbstractDatabase_1.default {
1386
1386
  return resultArray;
1387
1387
  }, []);
1388
1388
  const hook = this.$state.get('HOOK');
1389
- if (hook)
1390
- yield hook(data || []);
1389
+ for (let i in hook)
1390
+ yield hook[i](data || []);
1391
1391
  return data || [];
1392
1392
  }
1393
1393
  if (this.$state.get('PLUCK')) {
@@ -1397,13 +1397,13 @@ class Database extends AbstractDatabase_1.default {
1397
1397
  throw new Error(`can't find property '${pluck}' of result`);
1398
1398
  }
1399
1399
  const hook = this.$state.get('HOOK');
1400
- if (hook)
1401
- yield hook(newData || []);
1400
+ for (let i in hook)
1401
+ yield hook[i](newData || []);
1402
1402
  return newData || [];
1403
1403
  }
1404
1404
  const hook = this.$state.get('HOOK');
1405
- if (hook)
1406
- yield hook(result || []);
1405
+ for (let i in hook)
1406
+ yield hook[i](result || []);
1407
1407
  return result || [];
1408
1408
  });
1409
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
@@ -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
@@ -1307,6 +1316,54 @@ class Model extends AbstractModel_1.AbstractModel {
1307
1316
  this.$state.set('SAVE', 'INSERT_NOT_EXISTS');
1308
1317
  return this;
1309
1318
  }
1319
+ getSchema() {
1320
+ return __awaiter(this, void 0, void 0, function* () {
1321
+ const sql = [
1322
+ `${this.$constants('SHOW')}`,
1323
+ `${this.$constants('COLUMNS')}`,
1324
+ `${this.$constants('FROM')}`,
1325
+ `\`${this.$state.get('TABLE_NAME').replace(/\`/g, '')}\``
1326
+ ].join(' ');
1327
+ const raw = yield this.queryStatement(sql);
1328
+ const schemas = raw.map((r) => {
1329
+ let schema = { [r.Field]: String };
1330
+ const numberLists = [
1331
+ 'tinyint',
1332
+ 'smallint',
1333
+ 'mediumint',
1334
+ 'int',
1335
+ 'bigint',
1336
+ 'float',
1337
+ 'double',
1338
+ 'decimal',
1339
+ 'real',
1340
+ 'bit',
1341
+ 'boolean',
1342
+ 'serial'
1343
+ ];
1344
+ const dateAndTimeLists = [
1345
+ 'date',
1346
+ 'datetime',
1347
+ 'time',
1348
+ 'timestamp',
1349
+ 'year'
1350
+ ];
1351
+ if (numberLists.includes(r.Type)) {
1352
+ schema = {
1353
+ [r.Field]: Number
1354
+ };
1355
+ }
1356
+ if (dateAndTimeLists.includes(r.Type)) {
1357
+ schema = {
1358
+ [r.Field]: Date
1359
+ };
1360
+ }
1361
+ return schema;
1362
+ });
1363
+ const result = Object.assign({}, ...schemas);
1364
+ return result;
1365
+ });
1366
+ }
1310
1367
  /**
1311
1368
  *
1312
1369
  * @override Method
@@ -1314,6 +1371,7 @@ class Model extends AbstractModel_1.AbstractModel {
1314
1371
  */
1315
1372
  save() {
1316
1373
  return __awaiter(this, void 0, void 0, function* () {
1374
+ this._validateMethod('save');
1317
1375
  const attributes = this.$attributes;
1318
1376
  if (attributes != null) {
1319
1377
  while (true) {
@@ -1418,12 +1476,13 @@ class Model extends AbstractModel_1.AbstractModel {
1418
1476
  return (_a = this.$state.get('TABLE_NAME')) === null || _a === void 0 ? void 0 : _a.replace(/`/g, '');
1419
1477
  }
1420
1478
  _valueInRelation(relationModel) {
1421
- var _a, _b;
1479
+ var _a, _b, _c, _d;
1422
1480
  const relation = relationModel.relation;
1423
1481
  const model = (_a = relationModel.model) === null || _a === void 0 ? void 0 : _a.name;
1424
1482
  const table = relationModel.freezeTable
1425
1483
  ? relationModel.freezeTable
1426
1484
  : (_b = relationModel.query) === null || _b === void 0 ? void 0 : _b._tableName();
1485
+ let pivot = null;
1427
1486
  const name = relationModel.name;
1428
1487
  const as = relationModel.as;
1429
1488
  this._assertError(!model || model == null, 'not found model');
@@ -1459,8 +1518,12 @@ class Model extends AbstractModel_1.AbstractModel {
1459
1518
  `${this.$state.get('PRIMARY_KEY')}`
1460
1519
  ].join('_'));
1461
1520
  foreignKey = 'id';
1521
+ pivot = (_c = relationModel.pivot) !== null && _c !== void 0 ? _c : this._valuePattern([
1522
+ pluralize_1.default.singular(this === null || this === void 0 ? void 0 : this._tableName()),
1523
+ pluralize_1.default.singular((_d = relationModel.query) === null || _d === void 0 ? void 0 : _d._tableName())
1524
+ ].sort().join('_'));
1462
1525
  }
1463
- return { name, as, relation, table, localKey, foreignKey, model };
1526
+ return { name, as, relation, table, localKey, foreignKey, model, pivot };
1464
1527
  }
1465
1528
  _handleSoftDelete() {
1466
1529
  if (this.$state.get('SOFT_DELETE')) {
@@ -1527,9 +1590,36 @@ class Model extends AbstractModel_1.AbstractModel {
1527
1590
  });
1528
1591
  return result;
1529
1592
  }
1593
+ _validateSchema(results) {
1594
+ const schema = this.$state.get('SCHEMA');
1595
+ if (schema == null)
1596
+ return;
1597
+ if (!results.length)
1598
+ return;
1599
+ const typeOf = (data) => Object.prototype.toString.apply(data).slice(8, -1).toLocaleLowerCase();
1600
+ for (const result of results) {
1601
+ for (const key in result) {
1602
+ const s = schema[key];
1603
+ if (s == null)
1604
+ this._assertError(`not found this column [${key}] in schema`);
1605
+ const regexDate = /[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])/;
1606
+ 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]/;
1607
+ if (regexDate.test(result[key]) || regexDateTime.test(result[key])) {
1608
+ if (typeOf(new Date(result[key])) === typeOf(new s()))
1609
+ continue;
1610
+ this._assertError(`this column [${key}] is invalid schema field type`);
1611
+ }
1612
+ if (typeOf(result[key]) === typeOf(new s()))
1613
+ continue;
1614
+ this._assertError(`this column [${key}] is invalid schema field type`);
1615
+ }
1616
+ }
1617
+ return this;
1618
+ }
1530
1619
  _execute({ sql, type, message, options }) {
1531
1620
  return __awaiter(this, void 0, void 0, function* () {
1532
1621
  let result = yield this.queryStatement(sql);
1622
+ this._validateSchema(result);
1533
1623
  if (!result.length)
1534
1624
  return this._returnEmpty(type, result, message, options);
1535
1625
  const relations = this.$state.get('WITH');
@@ -1629,7 +1719,7 @@ class Model extends AbstractModel_1.AbstractModel {
1629
1719
  const relation = relations[index];
1630
1720
  if (!((_a = Object.keys(relation)) === null || _a === void 0 ? void 0 : _a.length))
1631
1721
  continue;
1632
- const { localKey, foreignKey } = this._valueInRelation(relation);
1722
+ const { localKey, foreignKey, pivot } = this._valueInRelation(relation);
1633
1723
  const query = relation.query;
1634
1724
  this._assertError(query == null, `unknown callback query in [relation : '${relation.name}']`);
1635
1725
  let clone = new Model().clone(query);
@@ -1641,6 +1731,21 @@ class Model extends AbstractModel_1.AbstractModel {
1641
1731
  clone.whereExists(sql);
1642
1732
  }
1643
1733
  }
1734
+ if (relation.relation === this.$constants('RELATIONSHIP').belongsToMany) {
1735
+ const sql = clone
1736
+ .bind(this.$pool.get())
1737
+ .whereReference(`\`${this._tableName()}\`.\`${localKey}\``, `\`${query._tableName()}\`.\`${foreignKey}\``)
1738
+ .toString();
1739
+ this.whereExists(sql);
1740
+ const thisPivot = new Model();
1741
+ thisPivot.$state.set('TABLE_NAME', `\`${pivot}\``);
1742
+ const sqlPivot = thisPivot
1743
+ .bind(this.$pool.get())
1744
+ .whereReference(`\`${this._tableName()}\`.\`${foreignKey}\``, `\`${pivot}\`.\`${this._valuePattern([pluralize_1.default.singular(this._tableName()), foreignKey].join("_"))}\``)
1745
+ .toString();
1746
+ this.whereExists(sqlPivot);
1747
+ continue;
1748
+ }
1644
1749
  const sql = clone
1645
1750
  .bind(this.$pool.get())
1646
1751
  .whereReference(`\`${this._tableName()}\`.\`${localKey}\``, `\`${query._tableName()}\`.\`${foreignKey}\``)
@@ -1676,66 +1781,15 @@ class Model extends AbstractModel_1.AbstractModel {
1676
1781
  return dataFromRelation;
1677
1782
  });
1678
1783
  }
1679
- _handleBelongsToMany(dataFromParent, relation, pivotTable) {
1784
+ _belongsToMany(dataFromParent, relation) {
1785
+ var _a;
1680
1786
  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);
1787
+ const { name, localKey, foreignKey, pivot } = this._valueInRelation(relation);
1788
+ const pivotTable = String(((_a = relation.pivot) !== null && _a !== void 0 ? _a : pivot));
1735
1789
  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");
1790
+ const data = parent[foreignKey];
1791
+ if (!parent.hasOwnProperty(foreignKey)) {
1792
+ this._assertError(data == null, `unknown relationship without primary or foreign key in relation : [${relation === null || relation === void 0 ? void 0 : relation.name}]`);
1739
1793
  }
1740
1794
  return data;
1741
1795
  }).filter((data) => data != null);
@@ -1746,13 +1800,14 @@ class Model extends AbstractModel_1.AbstractModel {
1746
1800
  const other = this._classToTableName(modelOther.constructor.name, { singular: true });
1747
1801
  const otherlocalKey = 'id';
1748
1802
  const otherforeignKey = this._valuePattern(`${other}Id`);
1803
+ const localKeyPivotTable = this._valuePattern([pluralize_1.default.singular(this._tableName()), foreignKey].join("_"));
1749
1804
  const sqldataChilds = [
1750
1805
  `${this.$constants('SELECT')}`,
1751
1806
  `*`,
1752
1807
  `${this.$constants('FROM')}`,
1753
1808
  `${pivotTable}`,
1754
1809
  `${this.$constants('WHERE')}`,
1755
- `${foreignKey} ${this.$constants('IN')} (${dataPerentId})`
1810
+ `${localKeyPivotTable} ${this.$constants('IN')} (${dataPerentId})`
1756
1811
  ].join(' ');
1757
1812
  let dataChilds = yield this.queryStatement(sqldataChilds);
1758
1813
  const otherId = dataChilds.map((sub) => sub[otherforeignKey]).filter((data) => data != null);
@@ -1763,7 +1818,6 @@ class Model extends AbstractModel_1.AbstractModel {
1763
1818
  .debug(this.$state.get('DEBUG'))
1764
1819
  .toString());
1765
1820
  dataChilds.forEach((sub) => {
1766
- sub[other] = [];
1767
1821
  otherdataChilds.forEach((otherSub) => {
1768
1822
  if (otherSub[otherlocalKey] === sub[otherforeignKey]) {
1769
1823
  sub[other] = otherSub;
@@ -1774,7 +1828,7 @@ class Model extends AbstractModel_1.AbstractModel {
1774
1828
  if (dataPerent[name] == null)
1775
1829
  dataPerent[name] = [];
1776
1830
  dataChilds.forEach((sub) => {
1777
- if (sub[foreignKey] === dataPerent[localKey]) {
1831
+ if (sub[localKeyPivotTable] === dataPerent[foreignKey]) {
1778
1832
  dataPerent[name].push(sub);
1779
1833
  }
1780
1834
  });
@@ -1784,27 +1838,6 @@ class Model extends AbstractModel_1.AbstractModel {
1784
1838
  return dataFromParent;
1785
1839
  });
1786
1840
  }
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
1841
  _pagination(data) {
1809
1842
  var _a, _b;
1810
1843
  return __awaiter(this, void 0, void 0, function* () {
@@ -1896,16 +1929,14 @@ class Model extends AbstractModel_1.AbstractModel {
1896
1929
  if (this._isPatternSnakeCase()) {
1897
1930
  const empty = this.$utils.snakeCase(this._result(emptyData));
1898
1931
  const hook = this.$state.get('HOOK');
1899
- if (hook === null || hook === void 0 ? void 0 : hook.length)
1900
- for (let i = 0; i < hook.length; i++)
1901
- yield hook[i](empty);
1932
+ for (let i in hook)
1933
+ yield hook[i](empty);
1902
1934
  return empty;
1903
1935
  }
1904
1936
  const empty = this._result(emptyData);
1905
1937
  const hook = this.$state.get('HOOK');
1906
- if (hook === null || hook === void 0 ? void 0 : hook.length)
1907
- for (let i = 0; i < hook.length; i++)
1908
- yield hook[i](empty);
1938
+ for (let i in hook)
1939
+ yield hook[i](empty);
1909
1940
  return empty;
1910
1941
  });
1911
1942
  }
@@ -1980,9 +2011,8 @@ class Model extends AbstractModel_1.AbstractModel {
1980
2011
  }
1981
2012
  }
1982
2013
  const hook = this.$state.get('HOOK');
1983
- if (hook === null || hook === void 0 ? void 0 : hook.length)
1984
- for (let i = 0; i < hook.length; i++)
1985
- yield hook[i](result);
2014
+ for (let i in hook)
2015
+ yield hook[i](result);
1986
2016
  return result;
1987
2017
  });
1988
2018
  }
@@ -2222,15 +2252,13 @@ class Model extends AbstractModel_1.AbstractModel {
2222
2252
  const result = (data === null || data === void 0 ? void 0 : data.shift()) || null;
2223
2253
  this.$state.set('RESULT', result);
2224
2254
  const hook = this.$state.get('HOOK');
2225
- if (hook === null || hook === void 0 ? void 0 : hook.length)
2226
- for (let i = 0; i < hook.length; i++)
2227
- yield hook[i](result);
2255
+ for (let i in hook)
2256
+ yield hook[i](result);
2228
2257
  return result;
2229
2258
  }
2230
2259
  const hook = this.$state.get('HOOK');
2231
- if (hook === null || hook === void 0 ? void 0 : hook.length)
2232
- for (let i = 0; i < hook.length; i++)
2233
- yield hook[i](result || []);
2260
+ for (let i in hook)
2261
+ yield hook[i](result || []);
2234
2262
  return null;
2235
2263
  });
2236
2264
  }
@@ -2373,12 +2401,27 @@ class Model extends AbstractModel_1.AbstractModel {
2373
2401
  'updateOrCreate',
2374
2402
  'updateOrInsert',
2375
2403
  'insertOrUpdate',
2376
- 'update'
2404
+ 'update',
2405
+ 'delete'
2377
2406
  ];
2378
2407
  const findMethodNotAllowed = methodCallings.find((methodCalling) => methodsNotAllowed.includes(methodCalling));
2379
2408
  this._assertError(methodCallings.some((methodCalling) => methodsNotAllowed.includes(methodCalling)), `this method ${method} can't using method : [ ${findMethodNotAllowed} ]`);
2380
2409
  break;
2381
2410
  }
2411
+ case 'save': {
2412
+ const methodCallings = this.$logger.get();
2413
+ const methodsSomeAllowed = [
2414
+ 'create',
2415
+ 'createNotExists',
2416
+ 'updateOrCreate',
2417
+ 'updateOrInsert',
2418
+ 'insertOrUpdate',
2419
+ 'update',
2420
+ 'delete'
2421
+ ];
2422
+ this._assertError(!methodCallings.some((methodCalling) => methodsSomeAllowed.includes(methodCalling)), `this ${method} method need some : [ ${methodsSomeAllowed.join(', ')} ] methods`);
2423
+ break;
2424
+ }
2382
2425
  }
2383
2426
  }
2384
2427
  _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.0",
3
+ "version": "1.2.2",
4
4
  "description": "mysql query builder object relational mapping",
5
5
  "main": "dist/lib/index.js",
6
6
  "types": "dist/lib/index.d.ts",