tspace-mysql 1.4.3 → 1.4.5

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
@@ -29,6 +29,7 @@ npm install tspace-mysql --save
29
29
  - [Deeply Nested Relations](#deeply-nested-relations)
30
30
  - [Relation Exists](#relation-exists)
31
31
  - [Built in Relation Functions](#built-in-relation-functions)
32
+ - [Schema Sync](#schema-sync)
32
33
  - [Query Builder](#query-builder)
33
34
  - [Cli](#cli)
34
35
  - [Make Model](#make-model)
@@ -150,6 +151,7 @@ const whereNull = await new DB('users').whereNull('username').findOne()
150
151
  const whereNotNull = await new DB('users').whereNotNull('username').findOne()
151
152
  const whereQuery = await new DB('users').whereQuery(query => query.where('id',1).where('username','tspace')).whereIn('id',[1,2]).findOne()
152
153
  // SELECT * FROM `users` WHERE ( `users`.`id` = '1' AND `users`.`username` = 'tspace') AND `users`.`id` IN ('1','2'') LIMIT 1
154
+ const whereJson= await new DB('users').whereJson({column : 'json',targetKey : 'id', value : '1234' }).findOne()
153
155
  ```
154
156
 
155
157
  Running A Hook Query
@@ -410,11 +412,12 @@ class User extends Model {
410
412
  * this.useTable('users')
411
413
  * this.useTableSingular() // => 'user'
412
414
  * this.useTablePlural() // => 'users'
413
- * this.usePattern('snake_case') // => default 'snake_case'
415
+ * this.usePattern('camelCase') // => default 'snake_case'
414
416
  * this.useUUID('uuid') // => runing a uuid (universally unique identifier) when insert new data
415
417
  * this.useRegistry() // => build-in functions registry
416
- * this.useLoadRelationsInRegistry() // => auto generated results from relationship to results
418
+ * this.useLoadRelationsInRegistry() // => auto generated result from relationship to results
417
419
  * this.useBuiltInRelationFunctions() // => build-in functions relationships to results
420
+ * this.useHooks([(r) => console.log(r)])
418
421
  * this.useSchema ({
419
422
  * id : new Blueprint().int().notNull().primary().autoIncrement(),
420
423
  * uuid : new Blueprint().varchar(50).null(),
@@ -803,6 +806,61 @@ for (const post of posts) {
803
806
 
804
807
  ```
805
808
 
809
+ ## Schema Sync
810
+ Sync schema to Models in your directory,
811
+ Sync will check for create or update table or columns with useSchema in your model.
812
+ Let's examine a basic model sync class:
813
+
814
+ ```js
815
+ /**
816
+ *
817
+ * @Ex directory
818
+ *
819
+ * - node_modules
820
+ * - app
821
+ * - Models
822
+ * - User.ts
823
+ * - Post.ts
824
+ *
825
+ * // file User.ts
826
+ * class User extends Model {
827
+ * constructor(){
828
+ * super()
829
+ * this.hasMany({ name : 'posts' , model : Post })
830
+ * this.useSchema ({
831
+ * id : new Blueprint().int().notNull().primary().autoIncrement(),
832
+ * uuid : new Blueprint().varchar(50).null(),
833
+ * email : new Blueprint().int().notNull().unique(),
834
+ * name : new Blueprint().varchar(255).null(),
835
+ * created_at : new Blueprint().timestamp().null(),
836
+ * updated_at : new Blueprint().timestamp().null(),
837
+ * deleted_at : new Blueprint().timestamp().null()
838
+ * })
839
+ * }
840
+ * }
841
+ *
842
+ * // file Post.ts
843
+ * class Post extends Model {
844
+ * constructor(){
845
+ * super()
846
+ * this.hasMany({ name : 'comments' , model : Comment })
847
+ * this.belongsTo({ name : 'user' , model : User })
848
+ * this.useSchema ({
849
+ * id : new Blueprint().int().notNull().primary().autoIncrement(),
850
+ * uuid : new Blueprint().varchar(50).null(),
851
+ * user_id : new Blueprint().int().notNull(),
852
+ * title : new Blueprint().varchar(255).null(),
853
+ * created_at : new Blueprint().timestamp().null(),
854
+ * updated_at : new Blueprint().timestamp().null(),
855
+ * deleted_at : new Blueprint().timestamp().null()
856
+ * })
857
+ * }
858
+ * }
859
+ *
860
+ */
861
+ await Schema.sync(`app/Models` , { force : true })
862
+
863
+ ```
806
864
  ## Query Builder
807
865
  Methods builder for queries
808
866
  ```js
@@ -65,9 +65,9 @@ exports.default = (cmd) => {
65
65
  const formattedSchema = formatSchema(schema);
66
66
  let str = "this.useSchema({\n";
67
67
  for (const formatKey in formattedSchema) {
68
- str += ` ${formatKey} : ${formattedSchema[formatKey]} \n`;
68
+ str += ` ${formatKey} : ${formattedSchema[formatKey]} \n`;
69
69
  }
70
- str += " })";
70
+ str += " })";
71
71
  const data = (0, model_1.default)(model, npm, `${str}`);
72
72
  fs.writeFile(`${cwd}/${dir}/${model}${type !== null && type !== void 0 ? type : '.ts'}`, data, (err) => {
73
73
  if (err)
@@ -114,9 +114,9 @@ class PoolConnection {
114
114
  database: String(options_1.default.DATABASE),
115
115
  user: String(options_1.default.USERNAME),
116
116
  password: String(options_1.default.PASSWORD) === '' ? '' : String(options_1.default.PASSWORD),
117
- multipleStatements: options_1.default.MULTIPLE_STATEMENTS || false,
118
- enableKeepAlive: options_1.default.ENABLE_KEEP_ALIVE || false,
119
- keepAliveInitialDelay: options_1.default.KEEP_ALIVE_DELAY || 0,
117
+ multipleStatements: Boolean(options_1.default.MULTIPLE_STATEMENTS || false),
118
+ enableKeepAlive: Boolean(options_1.default.ENABLE_KEEP_ALIVE || false),
119
+ keepAliveInitialDelay: Number.isNaN(Number(options_1.default.KEEP_ALIVE_DELAY || 0) ? 0 : Number(options_1.default.KEEP_ALIVE_DELAY)),
120
120
  }));
121
121
  }
122
122
  _loadOptions() {
@@ -95,13 +95,12 @@ const CONSTANTS = Object.freeze({
95
95
  INSERT: '',
96
96
  SELECT: '',
97
97
  ONLY: [],
98
- EXCEPT: [],
98
+ EXCEPTS: [],
99
99
  CHUNK: 0,
100
100
  COUNT: '',
101
101
  FROM: '',
102
102
  JOIN: '',
103
103
  WHERE: '',
104
- TEST: [],
105
104
  GROUP_BY: '',
106
105
  ORDER_BY: '',
107
106
  LIMIT: '',
@@ -114,7 +113,7 @@ const CONSTANTS = Object.freeze({
114
113
  UUID: false,
115
114
  PAGE: 1,
116
115
  PER_PAGE: 1,
117
- HOOK: []
116
+ HOOKS: []
118
117
  },
119
118
  MODEL: {
120
119
  PRIMARY_KEY: 'id',
@@ -124,7 +123,7 @@ const CONSTANTS = Object.freeze({
124
123
  UPDATE: '',
125
124
  INSERT: '',
126
125
  ONLY: [],
127
- EXCEPT: [],
126
+ EXCEPTS: [],
128
127
  CHUNK: 0,
129
128
  COUNT: '',
130
129
  FROM: '',
@@ -152,7 +151,7 @@ const CONSTANTS = Object.freeze({
152
151
  DISTINCT: '',
153
152
  PLUCK: '',
154
153
  SAVE: '',
155
- HOOK: [],
154
+ HOOKS: [],
156
155
  RELATIONS: [],
157
156
  RELATIONS_TRASHED: false,
158
157
  RELATIONS_EXISTS: false,
@@ -166,7 +165,7 @@ const CONSTANTS = Object.freeze({
166
165
  VALIDATE_SCHEMA_DEFINED: null,
167
166
  FUNCTION_RELATION: false,
168
167
  SCHEMA_TABLE: null,
169
- QUERIES: 0
168
+ RETRY_QUERIES: 0
170
169
  }
171
170
  });
172
171
  exports.CONSTANTS = CONSTANTS;
@@ -10,6 +10,7 @@ declare abstract class AbstractModel extends Builder {
10
10
  protected abstract useTableSingular(): this;
11
11
  protected abstract useTimestamp(): this;
12
12
  protected abstract useSoftDelete(): this;
13
+ protected abstract useHooks(arrayFunctions: Array<Function>): this;
13
14
  protected abstract usePattern(pattern: string): this;
14
15
  protected abstract useLoadRelationsInRegistry(): this;
15
16
  protected abstract useBuiltInRelationFunctions(): this;
@@ -81,6 +81,11 @@ declare class Blueprint {
81
81
  * @return {this} this
82
82
  */
83
83
  longtext(): this;
84
+ /**
85
+ * Assign type 'JSON' in table
86
+ * @return {this} this
87
+ */
88
+ json(): this;
84
89
  /**
85
90
  * Assign type 'MEDIUMTEXT' in table
86
91
  * @return {this} this
@@ -136,6 +136,14 @@ class Blueprint {
136
136
  this._addAssignType(`LONGTEXT`);
137
137
  return this;
138
138
  }
139
+ /**
140
+ * Assign type 'JSON' in table
141
+ * @return {this} this
142
+ */
143
+ json() {
144
+ this._addAssignType(`JSON`);
145
+ return this;
146
+ }
139
147
  /**
140
148
  * Assign type 'MEDIUMTEXT' in table
141
149
  * @return {this} this
@@ -66,6 +66,21 @@ declare class Builder extends AbstractBuilder {
66
66
  whereObject(columns: {
67
67
  [key: string]: any;
68
68
  }): this;
69
+ /**
70
+ * where json target to key in json values default operator '='
71
+ * @param {object} property
72
+ * @property {string} property.column
73
+ * @property {string} property.targetKey
74
+ * @property {string} property.value
75
+ * @property {string?} property.operator
76
+ * @return {this}
77
+ */
78
+ whereJson({ column, targetKey, value, operator }: {
79
+ column: string;
80
+ targetKey: string;
81
+ value: string;
82
+ operator?: string;
83
+ }): this;
69
84
  /**
70
85
  * if has 2 arguments default operator '='
71
86
  * @param {string} column
@@ -265,14 +280,25 @@ declare class Builder extends AbstractBuilder {
265
280
  /**
266
281
  * select by cases
267
282
  * @param {array} cases array object [{ when : 'id < 7' , then : 'id is than under 7'}]
268
- * @param {string} as
283
+ * @param {string} as assign name
269
284
  * @return {this}
270
285
  */
271
- case(cases: string | any[], as: string): this;
286
+ case(cases: {
287
+ when: string;
288
+ then: string;
289
+ }[], as: string): this;
272
290
  /**
273
291
  *
274
292
  * @param {string} pk talbe.pk
275
293
  * @param {string} fk talbe.fk
294
+ * @example
295
+ * await new DB('users')
296
+ * .select('users.id as userId','posts.id as postId','email')
297
+ * .join('users.id','posts.id')
298
+ * .join('posts.category_id','categories.id')
299
+ * .where('users.id',1)
300
+ * .where('posts.id',2)
301
+ * .get()
276
302
  * @return {this}
277
303
  */
278
304
  join(pk: string, fk: string): this;
@@ -52,7 +52,7 @@ class Builder extends AbstractBuilder_1.AbstractBuilder {
52
52
  * @return {this} this
53
53
  */
54
54
  except(...columns) {
55
- this.$state.set('EXCEPT', columns.length ? columns : []);
55
+ this.$state.set('EXCEPTS', columns.length ? columns : []);
56
56
  return this;
57
57
  }
58
58
  /**
@@ -96,6 +96,8 @@ class Builder extends AbstractBuilder_1.AbstractBuilder {
96
96
  const select = columns.map((column) => {
97
97
  if (column === '*')
98
98
  return column;
99
+ if (/\./.test(column))
100
+ return column;
99
101
  if (column.includes(this.$constants('RAW')))
100
102
  return column === null || column === void 0 ? void 0 : column.replace(this.$constants('RAW'), '').replace(/'/g, '');
101
103
  return `\`${column}\``;
@@ -135,7 +137,7 @@ class Builder extends AbstractBuilder_1.AbstractBuilder {
135
137
  return this;
136
138
  const cb = callback(this);
137
139
  if (cb instanceof Promise)
138
- throw new Error('"when" is not supported a Promise');
140
+ throw new Error("'when' is not supported a Promise");
139
141
  return this;
140
142
  }
141
143
  /**
@@ -182,6 +184,28 @@ class Builder extends AbstractBuilder_1.AbstractBuilder {
182
184
  }
183
185
  return this;
184
186
  }
187
+ /**
188
+ * where json target to key in json values default operator '='
189
+ * @param {object} property
190
+ * @property {string} property.column
191
+ * @property {string} property.targetKey
192
+ * @property {string} property.value
193
+ * @property {string?} property.operator
194
+ * @return {this}
195
+ */
196
+ whereJson({ column, targetKey, value, operator }) {
197
+ value = this.$utils.escape(value);
198
+ value = this._valueTrueFalse(value);
199
+ this.$state.set('WHERE', [
200
+ this._queryWhereIsExists()
201
+ ? `${this.$state.get('WHERE')} ${this.$constants('AND')}`
202
+ : `${this.$constants('WHERE')}`,
203
+ `${this._bindTableAndColumnInQueryWhere(column)}->>'$.${targetKey}'`,
204
+ `${operator == null ? '=' : operator}`,
205
+ `${this._checkValueHasRaw(value)}`
206
+ ].join(' '));
207
+ return this;
208
+ }
185
209
  /**
186
210
  * if has 2 arguments default operator '='
187
211
  * @param {string} column
@@ -387,8 +411,8 @@ class Builder extends AbstractBuilder_1.AbstractBuilder {
387
411
  * @return {this}
388
412
  */
389
413
  whereSubQuery(column, subQuery) {
390
- if (!this.$utils.isQuery(subQuery))
391
- throw new Error(`This "${subQuery}" is invalid sub query`);
414
+ if (!this.$utils.isSubQuery(subQuery))
415
+ throw new Error(`This "${subQuery}" is invalid. Sub query is should contain 1 column(s)`);
392
416
  this.$state.set('WHERE', [
393
417
  this._queryWhereIsExists()
394
418
  ? `${this.$state.get('WHERE')} ${this.$constants('AND')}`
@@ -406,8 +430,8 @@ class Builder extends AbstractBuilder_1.AbstractBuilder {
406
430
  * @return {this}
407
431
  */
408
432
  whereNotSubQuery(column, subQuery) {
409
- if (!this.$utils.isQuery(subQuery))
410
- throw new Error(`This "${subQuery}" is invalid sub query`);
433
+ if (!this.$utils.isSubQuery(subQuery))
434
+ throw new Error(`This "${subQuery}" is invalid. Sub query is should contain 1 column(s)`);
411
435
  this.$state.set('WHERE', [
412
436
  this._queryWhereIsExists()
413
437
  ? `${this.$state.get('WHERE')} ${this.$constants('AND')}`
@@ -425,8 +449,8 @@ class Builder extends AbstractBuilder_1.AbstractBuilder {
425
449
  * @return {this}
426
450
  */
427
451
  orWhereSubQuery(column, subQuery) {
428
- if (!this.$utils.isQuery(subQuery))
429
- throw new Error(`This "${subQuery}" is invalid sub query`);
452
+ if (!this.$utils.isSubQuery(subQuery))
453
+ throw new Error(`This "${subQuery}" is invalid. Sub query is should contain 1 column(s)`);
430
454
  this.$state.set('WHERE', [
431
455
  this._queryWhereIsExists()
432
456
  ? `${this.$state.get('WHERE')} ${this.$constants('OR')}`
@@ -444,8 +468,8 @@ class Builder extends AbstractBuilder_1.AbstractBuilder {
444
468
  * @return {this}
445
469
  */
446
470
  orWhereNotSubQuery(column, subQuery) {
447
- if (!this.$utils.isQuery(subQuery))
448
- throw new Error(`This "${subQuery}" is invalid sub query`);
471
+ if (!this.$utils.isSubQuery(subQuery))
472
+ throw new Error(`This "${subQuery}" is invalid sub query (Sub query Operand should contain 1 column(s) not select * )`);
449
473
  this.$state.set('WHERE', [
450
474
  this._queryWhereIsExists()
451
475
  ? `${this.$state.get('WHERE')} ${this.$constants('OR')}`
@@ -745,7 +769,7 @@ class Builder extends AbstractBuilder_1.AbstractBuilder {
745
769
  /**
746
770
  * select by cases
747
771
  * @param {array} cases array object [{ when : 'id < 7' , then : 'id is than under 7'}]
748
- * @param {string} as
772
+ * @param {string} as assign name
749
773
  * @return {this}
750
774
  */
751
775
  case(cases, as) {
@@ -780,6 +804,14 @@ class Builder extends AbstractBuilder_1.AbstractBuilder {
780
804
  *
781
805
  * @param {string} pk talbe.pk
782
806
  * @param {string} fk talbe.fk
807
+ * @example
808
+ * await new DB('users')
809
+ * .select('users.id as userId','posts.id as postId','email')
810
+ * .join('users.id','posts.id')
811
+ * .join('posts.category_id','categories.id')
812
+ * .where('users.id',1)
813
+ * .where('posts.id',2)
814
+ * .get()
783
815
  * @return {this}
784
816
  */
785
817
  join(pk, fk) {
@@ -789,13 +821,13 @@ class Builder extends AbstractBuilder_1.AbstractBuilder {
789
821
  this.$state.set('JOIN', [
790
822
  `${this.$state.get('JOIN')}`,
791
823
  `${this.$constants('INNER_JOIN')}`,
792
- `${table} ${this.$constants('ON')} ${pk} = ${fk}`
824
+ `\`${table}\` ${this.$constants('ON')} ${pk} = ${fk}`
793
825
  ].join(' '));
794
826
  return this;
795
827
  }
796
828
  this.$state.set('JOIN', [
797
829
  `${this.$constants('INNER_JOIN')}`,
798
- `${table} ${this.$constants('ON')} ${pk} = ${fk}`
830
+ `\`${table}\` ${this.$constants('ON')} ${pk} = ${fk}`
799
831
  ].join(' '));
800
832
  return this;
801
833
  }
@@ -812,13 +844,13 @@ class Builder extends AbstractBuilder_1.AbstractBuilder {
812
844
  this.$state.set('JOIN', [
813
845
  `${this.$state.get('JOIN')}`,
814
846
  `${this.$constants('RIGHT_JOIN')}`,
815
- `${table} ${this.$constants('ON')} ${pk} = ${fk}`
847
+ `\`${table}\` ${this.$constants('ON')} ${pk} = ${fk}`
816
848
  ].join(' '));
817
849
  return this;
818
850
  }
819
851
  this.$state.set('JOIN', [
820
852
  `${this.$constants('RIGHT_JOIN')}`,
821
- `${table} ${this.$constants('ON')} ${pk} = ${fk}`
853
+ `\`${table}\` ${this.$constants('ON')} ${pk} = ${fk}`
822
854
  ].join(' '));
823
855
  return this;
824
856
  }
@@ -835,13 +867,13 @@ class Builder extends AbstractBuilder_1.AbstractBuilder {
835
867
  this.$state.set('JOIN', [
836
868
  `${this.$state.get('JOIN')}`,
837
869
  `${this.$constants('LEFT_JOIN')}`,
838
- `${table} ${this.$constants('ON')} ${pk} = ${fk}`
870
+ `\`${table}\` ${this.$constants('ON')} ${pk} = ${fk}`
839
871
  ].join(' '));
840
872
  return this;
841
873
  }
842
874
  this.$state.set('JOIN', [
843
875
  `${this.$constants('LEFT_JOIN')}`,
844
- `${table} ${this.$constants('ON')} ${pk} = ${fk}`
876
+ `\`${table}\` ${this.$constants('ON')} ${pk} = ${fk}`
845
877
  ].join(' '));
846
878
  return this;
847
879
  }
@@ -858,13 +890,13 @@ class Builder extends AbstractBuilder_1.AbstractBuilder {
858
890
  this.$state.set('JOIN', [
859
891
  `${this.$state.get('JOIN')}`,
860
892
  `${this.$constants('CROSS_JOIN')}`,
861
- `${table} ${this.$constants('ON')} ${pk} = ${fk}`
893
+ `\`${table}\` ${this.$constants('ON')} ${pk} = ${fk}`
862
894
  ].join(' '));
863
895
  return this;
864
896
  }
865
897
  this.$state.set('JOIN', [
866
898
  `${this.$constants('CROSS_JOIN')}`,
867
- `${table} ${this.$constants('ON')} ${pk} = ${fk}`
899
+ `\`${table}\` ${this.$constants('ON')} ${pk} = ${fk}`
868
900
  ].join(' '));
869
901
  return this;
870
902
  }
@@ -1227,7 +1259,7 @@ class Builder extends AbstractBuilder_1.AbstractBuilder {
1227
1259
  hook(func) {
1228
1260
  if (typeof func !== "function")
1229
1261
  throw new Error(`this '${func}' is not a function`);
1230
- this.$state.set('HOOK', [...this.$state.get('HOOK'), func]);
1262
+ this.$state.set('HOOKS', [...this.$state.get('HOOKS'), func]);
1231
1263
  return this;
1232
1264
  }
1233
1265
  /**
@@ -1238,7 +1270,7 @@ class Builder extends AbstractBuilder_1.AbstractBuilder {
1238
1270
  before(func) {
1239
1271
  if (typeof func !== "function")
1240
1272
  throw new Error(`this '${func}' is not a function`);
1241
- this.$state.set('HOOK', [...this.$state.get('HOOK'), func]);
1273
+ this.$state.set('HOOKS', [...this.$state.get('HOOKS'), func]);
1242
1274
  return this;
1243
1275
  }
1244
1276
  /**
@@ -1415,19 +1447,36 @@ class Builder extends AbstractBuilder_1.AbstractBuilder {
1415
1447
  */
1416
1448
  exceptColumns() {
1417
1449
  return __awaiter(this, void 0, void 0, function* () {
1418
- const sql = [
1419
- `${this.$constants('SHOW')}`,
1420
- `${this.$constants('COLUMNS')}`,
1421
- `${this.$constants('FROM')}`,
1422
- `${this.$state.get('TABLE_NAME')}`
1423
- ].join(' ');
1424
- const rawColumns = yield this.queryStatement(sql);
1425
- const columns = rawColumns.map((column) => column.Field);
1426
- const removeExcept = columns.filter((column) => {
1427
- const excepts = this.$state.get('EXCEPT');
1428
- return excepts.every((except) => except !== column);
1429
- });
1430
- return removeExcept;
1450
+ const excepts = this.$state.get('EXCEPTS');
1451
+ const hasDot = excepts.some((except) => /\./.test(except));
1452
+ const names = excepts.map((except) => {
1453
+ if (/\./.test(except))
1454
+ return except.split('.')[0];
1455
+ return null;
1456
+ }).filter((d) => d != null);
1457
+ const tableNames = names.length ? [...new Set(names)] : [this.$state.get('TABLE_NAME')];
1458
+ const removeExcepts = [];
1459
+ for (const tableName of tableNames) {
1460
+ const sql = [
1461
+ `${this.$constants('SHOW')}`,
1462
+ `${this.$constants('COLUMNS')}`,
1463
+ `${this.$constants('FROM')}`,
1464
+ `${tableName}`
1465
+ ].join(' ');
1466
+ const rawColumns = yield this.queryStatement(sql);
1467
+ const columns = rawColumns.map((column) => column.Field);
1468
+ const removeExcept = columns.filter((column) => {
1469
+ return excepts.every((except) => {
1470
+ if (/\./.test(except)) {
1471
+ const [table, _] = except.split('.');
1472
+ return except !== `${table}.${column}`;
1473
+ }
1474
+ return except !== column;
1475
+ });
1476
+ });
1477
+ removeExcepts.push(hasDot ? removeExcept.map(r => `\`${tableName}\`.${r}`) : removeExcept);
1478
+ }
1479
+ return removeExcepts.flat();
1431
1480
  });
1432
1481
  }
1433
1482
  /**
@@ -1614,7 +1663,7 @@ class Builder extends AbstractBuilder_1.AbstractBuilder {
1614
1663
  first() {
1615
1664
  var _a, _b;
1616
1665
  return __awaiter(this, void 0, void 0, function* () {
1617
- if ((_a = this.$state.get('EXCEPT')) === null || _a === void 0 ? void 0 : _a.length)
1666
+ if ((_a = this.$state.get('EXCEPTS')) === null || _a === void 0 ? void 0 : _a.length)
1618
1667
  this.select(...yield this.exceptColumns());
1619
1668
  this.limit(1);
1620
1669
  let sql = this._buildQuery();
@@ -1628,15 +1677,11 @@ class Builder extends AbstractBuilder_1.AbstractBuilder {
1628
1677
  if (!checkProperty)
1629
1678
  throw new Error(`can't find property '${pluck}' of result`);
1630
1679
  const r = newData[pluck] || null;
1631
- const hook = this.$state.get('HOOK');
1632
- for (let i in hook)
1633
- yield hook[i](r);
1680
+ yield this.$utils.hookHandle(this.$state.get('HOOKS'), r);
1634
1681
  return r;
1635
1682
  }
1636
1683
  const r = (result === null || result === void 0 ? void 0 : result.shift()) || null;
1637
- const hook = this.$state.get('HOOK');
1638
- for (let i in hook)
1639
- yield hook[i](r);
1684
+ yield this.$utils.hookHandle(this.$state.get('HOOKS'), r);
1640
1685
  return this.resultHandler(r);
1641
1686
  });
1642
1687
  }
@@ -1658,7 +1703,7 @@ class Builder extends AbstractBuilder_1.AbstractBuilder {
1658
1703
  firstOrError(message, options) {
1659
1704
  var _a, _b;
1660
1705
  return __awaiter(this, void 0, void 0, function* () {
1661
- if ((_a = this.$state.get('EXCEPT')) === null || _a === void 0 ? void 0 : _a.length)
1706
+ if ((_a = this.$state.get('EXCEPTS')) === null || _a === void 0 ? void 0 : _a.length)
1662
1707
  this.select(...yield this.exceptColumns());
1663
1708
  let sql = this._buildQuery();
1664
1709
  if (!sql.includes(this.$constants('LIMIT')))
@@ -1676,14 +1721,11 @@ class Builder extends AbstractBuilder_1.AbstractBuilder {
1676
1721
  throw new Error(`can't find property '${pluck}' of result`);
1677
1722
  const data = newData[pluck] || null;
1678
1723
  if (data == null) {
1679
- if (options == null) {
1724
+ if (options == null)
1680
1725
  throw { message, code: 400 };
1681
- }
1682
1726
  throw Object.assign({ message }, options);
1683
1727
  }
1684
- const hook = this.$state.get('HOOK');
1685
- for (let i in hook)
1686
- yield hook[i](data);
1728
+ yield this.$utils.hookHandle(this.$state.get('HOOKS'), data);
1687
1729
  return this.resultHandler(data);
1688
1730
  }
1689
1731
  const data = (result === null || result === void 0 ? void 0 : result.shift()) || null;
@@ -1693,9 +1735,7 @@ class Builder extends AbstractBuilder_1.AbstractBuilder {
1693
1735
  }
1694
1736
  throw Object.assign({ message }, options);
1695
1737
  }
1696
- const hook = this.$state.get('HOOK');
1697
- for (let i in hook)
1698
- yield hook[i](data);
1738
+ yield this.$utils.hookHandle(this.$state.get('HOOKS'), data);
1699
1739
  return this.resultHandler(data);
1700
1740
  });
1701
1741
  }
@@ -1717,7 +1757,7 @@ class Builder extends AbstractBuilder_1.AbstractBuilder {
1717
1757
  get() {
1718
1758
  var _a, _b;
1719
1759
  return __awaiter(this, void 0, void 0, function* () {
1720
- if ((_a = this.$state.get('EXCEPT')) === null || _a === void 0 ? void 0 : _a.length)
1760
+ if ((_a = this.$state.get('EXCEPTS')) === null || _a === void 0 ? void 0 : _a.length)
1721
1761
  this.select(...yield this.exceptColumns());
1722
1762
  const sql = this._buildQuery();
1723
1763
  const result = yield this.queryStatement(sql);
@@ -1731,9 +1771,7 @@ class Builder extends AbstractBuilder_1.AbstractBuilder {
1731
1771
  resultArray[chunkIndex].push(item);
1732
1772
  return resultArray;
1733
1773
  }, []);
1734
- const hook = this.$state.get('HOOK');
1735
- for (let i in hook)
1736
- yield hook[i](data || []);
1774
+ yield this.$utils.hookHandle(this.$state.get('HOOKS'), data || []);
1737
1775
  return this.resultHandler(data || []);
1738
1776
  }
1739
1777
  if (this.$state.get('PLUCK')) {
@@ -1742,14 +1780,10 @@ class Builder extends AbstractBuilder_1.AbstractBuilder {
1742
1780
  if (newData.every((d) => d == null)) {
1743
1781
  throw new Error(`can't find property '${pluck}' of result`);
1744
1782
  }
1745
- const hook = this.$state.get('HOOK');
1746
- for (let i in hook)
1747
- yield hook[i](newData || []);
1783
+ yield this.$utils.hookHandle(this.$state.get('HOOKS'), newData || []);
1748
1784
  return this.resultHandler(newData || []);
1749
1785
  }
1750
- const hook = this.$state.get('HOOK');
1751
- for (let i in hook)
1752
- yield hook[i](result || []);
1786
+ yield this.$utils.hookHandle(this.$state.get('HOOKS'), result || []);
1753
1787
  return this.resultHandler(result || []);
1754
1788
  });
1755
1789
  }
@@ -1771,7 +1805,7 @@ class Builder extends AbstractBuilder_1.AbstractBuilder {
1771
1805
  toJSON() {
1772
1806
  var _a, _b;
1773
1807
  return __awaiter(this, void 0, void 0, function* () {
1774
- if ((_a = this.$state.get('EXCEPT')) === null || _a === void 0 ? void 0 : _a.length)
1808
+ if ((_a = this.$state.get('EXCEPTS')) === null || _a === void 0 ? void 0 : _a.length)
1775
1809
  this.select(...yield this.exceptColumns());
1776
1810
  const sql = this._buildQuery();
1777
1811
  const result = yield this.queryStatement(sql);
@@ -2496,7 +2530,10 @@ class Builder extends AbstractBuilder_1.AbstractBuilder {
2496
2530
  return ((_a = String(this.$state.get('WHERE'))) === null || _a === void 0 ? void 0 : _a.includes(this.$constants('WHERE'))) || false;
2497
2531
  }
2498
2532
  _bindTableAndColumnInQueryWhere(column) {
2499
- return `${this.$state.get('TABLE_NAME')}.\`${column}\``;
2533
+ if (!/\./.test(column))
2534
+ return `${this.$state.get('TABLE_NAME')}.\`${column}\``;
2535
+ const [table, c] = column.split('.');
2536
+ return `\`${table}\`.\`${c}\``;
2500
2537
  }
2501
2538
  _insertNotExists() {
2502
2539
  return __awaiter(this, void 0, void 0, function* () {
@@ -241,7 +241,7 @@ declare class Model extends AbstractModel {
241
241
  * }
242
242
  * @return {this}
243
243
  */
244
- protected useHook(arrayFunctions: Array<Function>): this;
244
+ protected useHooks(arrayFunctions: Array<Function>): this;
245
245
  /**
246
246
  * exceptColumns for method except
247
247
  * @return {promise<string>} string
@@ -711,6 +711,12 @@ declare class Model extends AbstractModel {
711
711
  * @return {string}
712
712
  */
713
713
  toSQL(): string;
714
+ /**
715
+ *
716
+ * @override Method
717
+ * @return {string}
718
+ */
719
+ toRawSQL(): string;
714
720
  /**
715
721
  *
716
722
  * @override Method
@@ -974,6 +980,8 @@ declare class Model extends AbstractModel {
974
980
  * @return {this} this this
975
981
  */
976
982
  getSchema(): Promise<any>;
983
+ getSchemaModel(): Promise<any>;
984
+ getTableName(): any;
977
985
  /**
978
986
  *
979
987
  * @override Method
@@ -339,11 +339,11 @@ class Model extends AbstractModel_1.AbstractModel {
339
339
  * }
340
340
  * @return {this}
341
341
  */
342
- useHook(arrayFunctions) {
342
+ useHooks(arrayFunctions) {
343
343
  for (const func of arrayFunctions) {
344
344
  if (typeof func !== "function")
345
345
  throw new Error(`this '${func}' is not a function`);
346
- this.$state.set('HOOK', [...this.$state.get('HOOK'), func]);
346
+ this.$state.set('HOOKS', [...this.$state.get('HOOKS'), func]);
347
347
  }
348
348
  return this;
349
349
  }
@@ -353,26 +353,50 @@ class Model extends AbstractModel_1.AbstractModel {
353
353
  */
354
354
  exceptColumns() {
355
355
  return __awaiter(this, void 0, void 0, function* () {
356
- if (this.$state.get('SCHEMA_TABLE')) {
357
- const columns = Object.keys(this.$state.get('SCHEMA_TABLE'));
356
+ const excepts = this.$state.get('EXCEPTS');
357
+ const hasDot = excepts.some((except) => /\./.test(except));
358
+ const names = excepts.map((except) => {
359
+ if (/\./.test(except))
360
+ return except.split('.')[0];
361
+ return null;
362
+ }).filter((d) => d != null);
363
+ const tableNames = names.length ? [...new Set(names)] : [this.$state.get('TABLE_NAME')];
364
+ const removeExcepts = [];
365
+ for (const tableName of tableNames) {
366
+ if (this.$state.get('SCHEMA_TABLE') && (tableName === this.$state.get('TABLE_NAME').replace(/`/g, ''))) {
367
+ const columns = Object.keys(this.$state.get('SCHEMA_TABLE'));
368
+ const removeExcept = columns.filter((column) => {
369
+ return excepts.every((except) => {
370
+ if (/\./.test(except)) {
371
+ const [table, _] = except.split('.');
372
+ return except !== `${table}.${column}`;
373
+ }
374
+ return except !== column;
375
+ });
376
+ });
377
+ removeExcepts.push(hasDot ? removeExcept.map(r => `\`${tableName}\`.${r}`) : removeExcept);
378
+ continue;
379
+ }
380
+ const sql = [
381
+ `${this.$constants('SHOW')}`,
382
+ `${this.$constants('COLUMNS')}`,
383
+ `${this.$constants('FROM')}`,
384
+ `${tableName}`
385
+ ].join(' ');
386
+ const rawColumns = yield this.queryStatement(sql);
387
+ const columns = rawColumns.map((column) => column.Field);
358
388
  const removeExcept = columns.filter((column) => {
359
- const excepts = this.$state.get('EXCEPT');
360
- return excepts.every((except) => except !== column);
389
+ return excepts.every((except) => {
390
+ if (/\./.test(except)) {
391
+ const [table, _] = except.split('.');
392
+ return except !== `${table}.${column}`;
393
+ }
394
+ return except !== column;
395
+ });
361
396
  });
362
- return removeExcept;
397
+ removeExcepts.push(hasDot ? removeExcept.map(r => `\`${tableName}\`.${r}`) : removeExcept);
363
398
  }
364
- const rawColumns = yield this.queryStatement([
365
- `${this.$constants('SHOW')}`,
366
- `${this.$constants('COLUMNS')}`,
367
- `${this.$constants('FROM')}`,
368
- `${this.$state.get('TABLE_NAME')}`
369
- ].join(' '));
370
- const columns = rawColumns.map((column) => column.Field);
371
- const removeExcept = columns.filter((column) => {
372
- const excepts = this.$state.get('EXCEPT');
373
- return excepts.every((except) => except !== column);
374
- });
375
- return removeExcept;
399
+ return removeExcepts.flat();
376
400
  });
377
401
  }
378
402
  /**
@@ -418,6 +442,8 @@ class Model extends AbstractModel_1.AbstractModel {
418
442
  const copy = Object.fromEntries(instance.$state.get());
419
443
  const newInstance = new Model();
420
444
  newInstance.$state.clone(copy);
445
+ newInstance.$state.set('SAVE', '');
446
+ newInstance.$state.set('DEBUG', false);
421
447
  if ((options === null || options === void 0 ? void 0 : options.insert) == null)
422
448
  newInstance.$state.set('INSERT', '');
423
449
  if ((options === null || options === void 0 ? void 0 : options.update) == null)
@@ -430,7 +456,6 @@ class Model extends AbstractModel_1.AbstractModel {
430
456
  newInstance.$state.set('LIMIT', '');
431
457
  if ((options === null || options === void 0 ? void 0 : options.offset) == null)
432
458
  newInstance.$state.set('OFFSET', '');
433
- newInstance.$state.set('SAVE', '');
434
459
  return newInstance;
435
460
  }
436
461
  /**
@@ -445,12 +470,12 @@ class Model extends AbstractModel_1.AbstractModel {
445
470
  try {
446
471
  if (this.$state.get('DEBUG'))
447
472
  this.$utils.consoleDebug(sql);
448
- this.$state.set('QUERIES', this.$state.get('QUERIES') + 1);
473
+ this.$state.set('RETRY_QUERIES', Number(this.$state.get('RETRY_QUERIES')) + 1);
449
474
  const result = yield this.$pool.query(sql);
450
475
  return result;
451
476
  }
452
- catch (e) {
453
- yield this._checkSchemaOrNextError(e);
477
+ catch (error) {
478
+ yield this._checkSchemaOrNextError(error);
454
479
  return yield this.queryStatement(sql);
455
480
  }
456
481
  });
@@ -469,7 +494,7 @@ class Model extends AbstractModel_1.AbstractModel {
469
494
  try {
470
495
  if (this.$state.get('DEBUG'))
471
496
  this.$utils.consoleDebug(sql);
472
- this.$state.set('QUERIES', this.$state.get('QUERIES') + 1);
497
+ this.$state.set('RETRY_QUERIES', Number(this.$state.get('RETRY_QUERIES')) + 1);
473
498
  if (returnId) {
474
499
  const result = yield this.$pool.query(sql);
475
500
  return [result.affectedRows, result.insertId];
@@ -1173,6 +1198,17 @@ class Model extends AbstractModel_1.AbstractModel {
1173
1198
  this.$utils.consoleDebug(sql);
1174
1199
  return this.resultHandler(sql);
1175
1200
  }
1201
+ /**
1202
+ *
1203
+ * @override Method
1204
+ * @return {string}
1205
+ */
1206
+ toRawSQL() {
1207
+ const sql = this._buildQueryModel();
1208
+ if (this.$state.get('DEBUG'))
1209
+ this.$utils.consoleDebug(sql);
1210
+ return this.resultHandler(sql);
1211
+ }
1176
1212
  /**
1177
1213
  *
1178
1214
  * @override Method
@@ -1344,7 +1380,7 @@ class Model extends AbstractModel_1.AbstractModel {
1344
1380
  this._validateMethod('first');
1345
1381
  if (this.$state.get('VOID'))
1346
1382
  return this.resultHandler(null);
1347
- if ((_a = this.$state.get('EXCEPT')) === null || _a === void 0 ? void 0 : _a.length)
1383
+ if ((_a = this.$state.get('EXCEPTS')) === null || _a === void 0 ? void 0 : _a.length)
1348
1384
  this.select(...yield this.exceptColumns());
1349
1385
  this.limit(1);
1350
1386
  if (this.$state.get('RELATIONS_EXISTS')) {
@@ -1378,7 +1414,7 @@ class Model extends AbstractModel_1.AbstractModel {
1378
1414
  var _a;
1379
1415
  return __awaiter(this, void 0, void 0, function* () {
1380
1416
  this._validateMethod('firstOrError');
1381
- if ((_a = this.$state.get('EXCEPT')) === null || _a === void 0 ? void 0 : _a.length)
1417
+ if ((_a = this.$state.get('EXCEPTS')) === null || _a === void 0 ? void 0 : _a.length)
1382
1418
  this.select(...yield this.exceptColumns());
1383
1419
  this.limit(1);
1384
1420
  if (this.$state.get('RELATIONS_EXISTS')) {
@@ -1416,7 +1452,7 @@ class Model extends AbstractModel_1.AbstractModel {
1416
1452
  this._validateMethod('get');
1417
1453
  if (this.$state.get('VOID'))
1418
1454
  return [];
1419
- if ((_a = this.$state.get('EXCEPT')) === null || _a === void 0 ? void 0 : _a.length)
1455
+ if ((_a = this.$state.get('EXCEPTS')) === null || _a === void 0 ? void 0 : _a.length)
1420
1456
  this.select(...yield this.exceptColumns());
1421
1457
  let sql = this._buildQueryModel();
1422
1458
  if (this.$state.get('RELATIONS_EXISTS'))
@@ -1455,7 +1491,7 @@ class Model extends AbstractModel_1.AbstractModel {
1455
1491
  limit = (paginationOptions === null || paginationOptions === void 0 ? void 0 : paginationOptions.limit) || limit;
1456
1492
  page = (paginationOptions === null || paginationOptions === void 0 ? void 0 : paginationOptions.page) || page;
1457
1493
  }
1458
- if ((_a = this.$state.get('EXCEPT')) === null || _a === void 0 ? void 0 : _a.length)
1494
+ if ((_a = this.$state.get('EXCEPTS')) === null || _a === void 0 ? void 0 : _a.length)
1459
1495
  this.select(...yield this.exceptColumns());
1460
1496
  const offset = (page - 1) * limit;
1461
1497
  this.$state.set('PER_PAGE', limit);
@@ -1493,7 +1529,7 @@ class Model extends AbstractModel_1.AbstractModel {
1493
1529
  getGroupBy(column) {
1494
1530
  var _a;
1495
1531
  return __awaiter(this, void 0, void 0, function* () {
1496
- if ((_a = this.$state.get('EXCEPT')) === null || _a === void 0 ? void 0 : _a.length)
1532
+ if ((_a = this.$state.get('EXCEPTS')) === null || _a === void 0 ? void 0 : _a.length)
1497
1533
  this.select(...yield this.exceptColumns());
1498
1534
  this.$state.set('GROUP_BY', `${this.$constants('GROUP_BY')} ${column}`);
1499
1535
  this.$state.set('SELECT', [
@@ -1723,6 +1759,15 @@ class Model extends AbstractModel_1.AbstractModel {
1723
1759
  return yield this.queryStatement(sql);
1724
1760
  });
1725
1761
  }
1762
+ getSchemaModel() {
1763
+ return __awaiter(this, void 0, void 0, function* () {
1764
+ return this.$state.get('SCHEMA_TABLE');
1765
+ });
1766
+ }
1767
+ getTableName() {
1768
+ var _a;
1769
+ return (_a = this.$state.get('TABLE_NAME')) === null || _a === void 0 ? void 0 : _a.replace(/`/g, '');
1770
+ }
1726
1771
  /**
1727
1772
  *
1728
1773
  * @override Method
@@ -2341,15 +2386,11 @@ class Model extends AbstractModel_1.AbstractModel {
2341
2386
  }
2342
2387
  if (this._isPatternSnakeCase()) {
2343
2388
  const empty = this.$utils.snakeCase(this.resultHandler(emptyData));
2344
- const hook = this.$state.get('HOOK');
2345
- for (let i in hook)
2346
- yield hook[i](empty);
2389
+ yield this.$utils.hookHandle(this.$state.get('HOOKS'), empty);
2347
2390
  return empty;
2348
2391
  }
2349
2392
  const empty = this.resultHandler(emptyData);
2350
- const hook = this.$state.get('HOOK');
2351
- for (let i in hook)
2352
- yield hook[i](empty);
2393
+ yield this.$utils.hookHandle(this.$state.get('HOOKS'), empty);
2353
2394
  return empty;
2354
2395
  });
2355
2396
  }
@@ -2441,9 +2482,7 @@ class Model extends AbstractModel_1.AbstractModel {
2441
2482
  throw new Error('Missing method first get or pagination');
2442
2483
  }
2443
2484
  }
2444
- const hook = this.$state.get('HOOK');
2445
- for (let i in hook)
2446
- yield hook[i](result);
2485
+ yield this.$utils.hookHandle(this.$state.get('HOOKS'), result);
2447
2486
  return result;
2448
2487
  });
2449
2488
  }
@@ -2835,7 +2874,7 @@ class Model extends AbstractModel_1.AbstractModel {
2835
2874
  var _a, _b, _c, _d, _e;
2836
2875
  return __awaiter(this, void 0, void 0, function* () {
2837
2876
  try {
2838
- if (this.$state.get('QUERIES') > 3)
2877
+ if (this.$state.get('RETRY_QUERIES') > 3)
2839
2878
  throw e;
2840
2879
  const schemaTable = this.$state.get('SCHEMA_TABLE');
2841
2880
  if (schemaTable == null)
@@ -2862,7 +2901,8 @@ class Model extends AbstractModel_1.AbstractModel {
2862
2901
  `${this.$state.get('TABLE_NAME')}`,
2863
2902
  `${this.$constants('ADD')}`,
2864
2903
  `\`${column}\` ${type} ${attributes.join(' ')}`,
2865
- `${this.$constants('AFTER')} \`${findAfterIndex !== null && findAfterIndex !== void 0 ? findAfterIndex : ''}\``
2904
+ `${this.$constants('AFTER')}`,
2905
+ `\`${findAfterIndex !== null && findAfterIndex !== void 0 ? findAfterIndex : ''}\``
2866
2906
  ].join(' ');
2867
2907
  yield this.queryStatement(sql);
2868
2908
  return;
@@ -2,6 +2,64 @@ import { Builder } from "./Builder";
2
2
  declare class Schema extends Builder {
3
3
  table: (table: string, schemas: Record<string, any>) => Promise<void>;
4
4
  createTable: (table: string, schemas: Record<string, any>) => string;
5
+ /**
6
+ *
7
+ * Sync will check for create or update table or columns with useSchema in your model.
8
+ * @param {string} pathFolders directory to models
9
+ * @property {boolean} options.force - forec to always check columns is exists
10
+ * @property {boolean} options.log - show log execution with sql statements
11
+ * @property {boolean} options.delay - wait for execution
12
+ * @example
13
+ *
14
+ * - node_modules
15
+ * - app
16
+ * - Models
17
+ * - User.ts
18
+ * - Post.ts
19
+ *
20
+ * // file User.ts
21
+ * class User extends Model {
22
+ * constructor(){
23
+ * super()
24
+ * this.hasMany({ name : 'posts' , model : Post })
25
+ * this.useSchema ({
26
+ * id : new Blueprint().int().notNull().primary().autoIncrement(),
27
+ * uuid : new Blueprint().varchar(50).null(),
28
+ * email : new Blueprint().int().notNull().unique(),
29
+ * name : new Blueprint().varchar(255).null(),
30
+ * created_at : new Blueprint().timestamp().null(),
31
+ * updated_at : new Blueprint().timestamp().null(),
32
+ * deleted_at : new Blueprint().timestamp().null()
33
+ * })
34
+ * }
35
+ * }
36
+ *
37
+ * // file Post.ts
38
+ * class Post extends Model {
39
+ * constructor(){
40
+ * super()
41
+ * this.hasMany({ name : 'comments' , model : Comment })
42
+ * this.belongsTo({ name : 'user' , model : User })
43
+ * this.useSchema ({
44
+ * id : new Blueprint().int().notNull().primary().autoIncrement(),
45
+ * uuid : new Blueprint().varchar(50).null(),
46
+ * user_id : new Blueprint().int().notNull(),
47
+ * title : new Blueprint().varchar(255).null(),
48
+ * created_at : new Blueprint().timestamp().null(),
49
+ * updated_at : new Blueprint().timestamp().null(),
50
+ * deleted_at : new Blueprint().timestamp().null()
51
+ * })
52
+ * }
53
+ * }
54
+ *
55
+ * await Schema.sync(`app/Models` , { force : true })
56
+ */
57
+ static sync(pathFolders: string, { force, log, delay }?: {
58
+ force?: boolean | undefined;
59
+ log?: boolean | undefined;
60
+ delay?: number | undefined;
61
+ }): Promise<void>;
62
+ private static _syncExecute;
5
63
  }
6
64
  export { Schema };
7
65
  export default Schema;
@@ -1,4 +1,27 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
26
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
27
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -8,9 +31,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
31
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
32
  });
10
33
  };
34
+ var __importDefault = (this && this.__importDefault) || function (mod) {
35
+ return (mod && mod.__esModule) ? mod : { "default": mod };
36
+ };
11
37
  Object.defineProperty(exports, "__esModule", { value: true });
12
38
  exports.Schema = void 0;
13
39
  const Builder_1 = require("./Builder");
40
+ const Model_1 = require("./Model");
41
+ const fs_1 = __importDefault(require("fs"));
42
+ const path_1 = __importDefault(require("path"));
14
43
  class Schema extends Builder_1.Builder {
15
44
  constructor() {
16
45
  super(...arguments);
@@ -57,6 +86,119 @@ class Schema extends Builder_1.Builder {
57
86
  return sql;
58
87
  };
59
88
  }
89
+ /**
90
+ *
91
+ * Sync will check for create or update table or columns with useSchema in your model.
92
+ * @param {string} pathFolders directory to models
93
+ * @property {boolean} options.force - forec to always check columns is exists
94
+ * @property {boolean} options.log - show log execution with sql statements
95
+ * @property {boolean} options.delay - wait for execution
96
+ * @example
97
+ *
98
+ * - node_modules
99
+ * - app
100
+ * - Models
101
+ * - User.ts
102
+ * - Post.ts
103
+ *
104
+ * // file User.ts
105
+ * class User extends Model {
106
+ * constructor(){
107
+ * super()
108
+ * this.hasMany({ name : 'posts' , model : Post })
109
+ * this.useSchema ({
110
+ * id : new Blueprint().int().notNull().primary().autoIncrement(),
111
+ * uuid : new Blueprint().varchar(50).null(),
112
+ * email : new Blueprint().int().notNull().unique(),
113
+ * name : new Blueprint().varchar(255).null(),
114
+ * created_at : new Blueprint().timestamp().null(),
115
+ * updated_at : new Blueprint().timestamp().null(),
116
+ * deleted_at : new Blueprint().timestamp().null()
117
+ * })
118
+ * }
119
+ * }
120
+ *
121
+ * // file Post.ts
122
+ * class Post extends Model {
123
+ * constructor(){
124
+ * super()
125
+ * this.hasMany({ name : 'comments' , model : Comment })
126
+ * this.belongsTo({ name : 'user' , model : User })
127
+ * this.useSchema ({
128
+ * id : new Blueprint().int().notNull().primary().autoIncrement(),
129
+ * uuid : new Blueprint().varchar(50).null(),
130
+ * user_id : new Blueprint().int().notNull(),
131
+ * title : new Blueprint().varchar(255).null(),
132
+ * created_at : new Blueprint().timestamp().null(),
133
+ * updated_at : new Blueprint().timestamp().null(),
134
+ * deleted_at : new Blueprint().timestamp().null()
135
+ * })
136
+ * }
137
+ * }
138
+ *
139
+ * await Schema.sync(`app/Models` , { force : true })
140
+ */
141
+ static sync(pathFolders, { force = false, log = false, delay = 3000 } = {}) {
142
+ return __awaiter(this, void 0, void 0, function* () {
143
+ const directories = fs_1.default.readdirSync(pathFolders, { withFileTypes: true });
144
+ const files = yield Promise.all(directories.map((directory) => {
145
+ const newDir = path_1.default.resolve(String(pathFolders), directory.name);
146
+ if (directory.isDirectory() && directory.name.toLocaleLowerCase().includes('migrations'))
147
+ return null;
148
+ return directory.isDirectory() ? Schema.sync(newDir, { force, log, delay }) : newDir;
149
+ }));
150
+ const pathModels = [].concat(...files).filter(d => d != null || d === '');
151
+ yield new Promise(r => setTimeout(r, delay));
152
+ const promises = pathModels.map((pathModel) => Schema._syncExecute({ pathModel, force, log }));
153
+ yield Promise.all(promises);
154
+ return;
155
+ });
156
+ }
157
+ static _syncExecute({ pathModel, force, log }) {
158
+ var _a, _b, _c, _d;
159
+ return __awaiter(this, void 0, void 0, function* () {
160
+ const loadModel = yield Promise.resolve(`${pathModel}`).then(s => __importStar(require(s)));
161
+ if (!loadModel.hasOwnProperty('default') && !(loadModel instanceof Model_1.Model))
162
+ return;
163
+ const model = new loadModel.default();
164
+ const schemaModel = yield model.getSchemaModel();
165
+ if (!schemaModel)
166
+ return;
167
+ const checkTableIsExists = Boolean((yield new Builder_1.Builder().rawQuery(`SHOW TABLES LIKE '${model.getTableName()}';`)).length);
168
+ if (!checkTableIsExists) {
169
+ const sql = new Schema().createTable(model.getTableName(), schemaModel);
170
+ yield new Builder_1.Builder().dd(log).rawQuery(sql);
171
+ return;
172
+ }
173
+ if (!force)
174
+ return;
175
+ const schemaTable = yield model.getSchema();
176
+ const schemaTableKeys = schemaTable.map((k) => k.Field);
177
+ const schemaModelKeys = Object.keys(schemaModel);
178
+ const missingColumns = schemaModelKeys.filter(schemaModelKey => !schemaTableKeys.includes(schemaModelKey));
179
+ if (!missingColumns.length)
180
+ return;
181
+ const entries = Object.entries(schemaModel);
182
+ for (const column of missingColumns) {
183
+ const indexWithColumn = entries.findIndex(([key]) => key === column);
184
+ const findAfterIndex = indexWithColumn ? entries[indexWithColumn - 1][0] : null;
185
+ const type = (_b = (_a = schemaModel[column]) === null || _a === void 0 ? void 0 : _a.type) !== null && _b !== void 0 ? _b : null;
186
+ const attributes = (_d = (_c = schemaModel[column]) === null || _c === void 0 ? void 0 : _c.attributes) !== null && _d !== void 0 ? _d : null;
187
+ if (findAfterIndex == null || type == null || attributes == null)
188
+ continue;
189
+ const sql = [
190
+ 'ALTER TABLE',
191
+ `\`${model.getTableName()}\``,
192
+ 'ADD',
193
+ `\`${column}\` ${type} ${attributes.join(' ')}`,
194
+ 'AFTER',
195
+ `\`${findAfterIndex}\``
196
+ ].join(' ');
197
+ yield new Builder_1.Builder().dd(log).rawQuery(sql);
198
+ }
199
+ return;
200
+ });
201
+ }
60
202
  }
61
203
  exports.Schema = Schema;
62
204
  exports.default = Schema;
@@ -5,12 +5,13 @@ declare const utils: {
5
5
  timestamp: () => string;
6
6
  date: () => string;
7
7
  escape: (str: any) => any;
8
- isQuery: (str: string) => boolean;
8
+ isSubQuery: (subQuery: string) => boolean;
9
9
  generateUUID: () => string;
10
10
  covertBooleanToNumber: (data: any) => any;
11
11
  snakeCase: (data: any) => any;
12
12
  camelCase: (data: any) => any;
13
13
  randomString: (length?: number) => string;
14
+ hookHandle: (hooks: Function[], result: any[] | null) => Promise<void>;
14
15
  };
15
16
  export { utils };
16
17
  export default utils;
@@ -1,4 +1,13 @@
1
1
  "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
2
11
  Object.defineProperty(exports, "__esModule", { value: true });
3
12
  exports.utils = void 0;
4
13
  const timestamp = () => {
@@ -34,7 +43,18 @@ const escape = (str) => {
34
43
  return str;
35
44
  return str.replace(/[\0\b\t\n\r\x1a\'\\]/g, '');
36
45
  };
37
- const isQuery = (str) => /\b(?:SELECT|FROM|WHERE|JOIN|INNER JOIN|LEFT JOIN|RIGHT JOIN|OUTER JOIN|AND|OR|ORDER BY|GROUP BY|LIMIT)\b/i.test(str);
46
+ const isSubQuery = (subQuery) => {
47
+ const checkIsSubQuery = (/\bSELECT\s+(?!\*)/i.test(subQuery));
48
+ if (!checkIsSubQuery)
49
+ return false;
50
+ const selectMatch = subQuery.match(/^\s*SELECT\s+(.*)\s+FROM/i);
51
+ if (!selectMatch)
52
+ return false;
53
+ const selectColumns = selectMatch[1].trim().split(',');
54
+ if (selectColumns.length !== 1)
55
+ return false;
56
+ return true;
57
+ };
38
58
  const columnRelation = (name) => {
39
59
  var _a;
40
60
  const matches = (_a = name === null || name === void 0 ? void 0 : name.match(/[A-Z]/g)) !== null && _a !== void 0 ? _a : [];
@@ -108,7 +128,7 @@ const randomString = (length = 100) => {
108
128
  for (let i = 0; i < length / salt; i++) {
109
129
  str += Math.random().toString(36).substring(salt);
110
130
  }
111
- return str.slice(-length).toLocaleLowerCase().replace(/'/g, 'g');
131
+ return str.toLocaleLowerCase().replace(/'/g, '').slice(-length);
112
132
  };
113
133
  const faker = (value) => {
114
134
  var _a, _b;
@@ -139,6 +159,11 @@ const faker = (value) => {
139
159
  }
140
160
  return 'fake data';
141
161
  };
162
+ const hookHandle = (hooks, result) => __awaiter(void 0, void 0, void 0, function* () {
163
+ for (const hook of hooks)
164
+ yield hook(result);
165
+ return;
166
+ });
142
167
  const utils = {
143
168
  consoleDebug,
144
169
  faker,
@@ -146,12 +171,13 @@ const utils = {
146
171
  timestamp,
147
172
  date,
148
173
  escape,
149
- isQuery,
174
+ isSubQuery,
150
175
  generateUUID,
151
176
  covertBooleanToNumber,
152
177
  snakeCase,
153
178
  camelCase,
154
- randomString
179
+ randomString,
180
+ hookHandle
155
181
  };
156
182
  exports.utils = utils;
157
183
  exports.default = utils;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tspace-mysql",
3
- "version": "1.4.3",
3
+ "version": "1.4.5",
4
4
  "description": "mysql query builder object relational mapping",
5
5
  "main": "dist/lib/index.js",
6
6
  "types": "dist/lib/index.d.ts",