tspace-mysql 1.5.0 → 1.5.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.
Files changed (53) hide show
  1. package/README.md +1856 -701
  2. package/build/cli/dump/db.js +3 -2
  3. package/build/cli/generate/make.js +17 -15
  4. package/build/cli/generate/modelDecorator.d.ts +1 -1
  5. package/build/cli/generate/modelDecorator.js +2 -3
  6. package/build/cli/index.js +45 -27
  7. package/build/cli/migrate/make.d.ts +1 -1
  8. package/build/cli/migrate/make.js +2 -2
  9. package/build/cli/migrations/make-db.d.ts +4 -0
  10. package/build/cli/migrations/make-db.js +58 -0
  11. package/build/cli/migrations/make.d.ts +2 -0
  12. package/build/cli/migrations/make.js +201 -0
  13. package/build/lib/Interface.d.ts +24 -5
  14. package/build/lib/connection/index.d.ts +5 -1
  15. package/build/lib/connection/index.js +65 -8
  16. package/build/lib/connection/options.js +2 -2
  17. package/build/lib/constants/index.js +13 -3
  18. package/build/lib/{tspace → core}/Abstracts/AbstractBuilder.d.ts +1 -1
  19. package/build/lib/{tspace → core}/Abstracts/AbstractModel.d.ts +15 -13
  20. package/build/lib/{tspace → core}/Blueprint.d.ts +14 -3
  21. package/build/lib/{tspace → core}/Blueprint.js +30 -4
  22. package/build/lib/{tspace → core}/Builder.d.ts +140 -44
  23. package/build/lib/{tspace → core}/Builder.js +772 -459
  24. package/build/lib/{tspace → core}/DB.d.ts +20 -4
  25. package/build/lib/{tspace → core}/DB.js +73 -39
  26. package/build/lib/{tspace → core}/Decorator.js +2 -2
  27. package/build/lib/{tspace → core/Handlers}/Logger.d.ts +3 -3
  28. package/build/lib/{tspace → core/Handlers}/Logger.js +4 -4
  29. package/build/lib/{tspace → core}/Handlers/Proxy.js +2 -2
  30. package/build/lib/{tspace → core}/Handlers/Relation.d.ts +2 -4
  31. package/build/lib/{tspace → core}/Handlers/Relation.js +69 -48
  32. package/build/lib/{tspace → core}/Handlers/State.d.ts +1 -1
  33. package/build/lib/{tspace → core}/Handlers/State.js +3 -3
  34. package/build/lib/{tspace → core}/Model.d.ts +358 -133
  35. package/build/lib/{tspace → core}/Model.js +1316 -558
  36. package/build/lib/core/Schema.d.ts +137 -0
  37. package/build/lib/{tspace → core}/Schema.js +147 -52
  38. package/build/lib/core/Type.d.ts +6 -0
  39. package/build/lib/core/Type.js +2 -0
  40. package/build/lib/{tspace → core}/index.d.ts +2 -1
  41. package/build/lib/{tspace → core}/index.js +3 -2
  42. package/build/lib/index.d.ts +2 -2
  43. package/build/lib/index.js +2 -2
  44. package/build/lib/utils/index.d.ts +1 -0
  45. package/build/lib/utils/index.js +17 -7
  46. package/package.json +6 -4
  47. package/build/lib/tspace/Schema.d.ts +0 -70
  48. /package/build/lib/{tspace → core}/Abstracts/AbstractBuilder.js +0 -0
  49. /package/build/lib/{tspace → core}/Abstracts/AbstractDB.d.ts +0 -0
  50. /package/build/lib/{tspace → core}/Abstracts/AbstractDB.js +0 -0
  51. /package/build/lib/{tspace → core}/Abstracts/AbstractModel.js +0 -0
  52. /package/build/lib/{tspace → core}/Decorator.d.ts +0 -0
  53. /package/build/lib/{tspace → core}/Handlers/Proxy.d.ts +0 -0
package/README.md CHANGED
@@ -11,16 +11,61 @@ Install with [npm](https://www.npmjs.com/):
11
11
 
12
12
  ```sh
13
13
  npm install tspace-mysql --save
14
+ npm install tspace-mysql -g
14
15
  ```
16
+
15
17
  ## Basic Usage
18
+
16
19
  - [Configuration](#configuration)
17
- - [Running Queries](#running-queries)
20
+ - [Query Builder](#query-builder)
21
+ - [Returning Results](#returning-results)
22
+ - [Select Statements](#select-statements)
23
+ - [Raw Expressions](#raw-expressions)
24
+ - [Ordering, Grouping, Limit and Offset](#ordering-grouping-limit-and-offset)
25
+ - [Ordering](#ordering)
26
+ - [Grouping](#grouping)
27
+ - [Limit and Offset](#limit-and-offset)
28
+ - [Joins](#joins)
29
+ - [Inner Join Clause](#inner-join-clause)
30
+ - [Left Join, Right Join Clause](#left-join-right-join-clause)
31
+ - [Cross Join Clause](#cross-join-clause)
32
+ - [Basic Where Clauses](#basic-where-clauses)
33
+ - [Where Clauses](#where-clauses)
34
+ - [Or Where Clauses](#or-where-clauses)
35
+ - [JSON Where Clauses](#json-where-clauses)
36
+ - [Additional Where Clauses](#additional-where-clauses)
37
+ - [Logical Grouping](#logical-grouping)
38
+ - [Advanced Where Clauses](#advanced-where-clauses)
39
+ - [Where Exists Clauses](#where-exists-clauses)
40
+ - [Subquery Where Clauses](#subquery-where-clauses)
41
+ - [Conditional Where Clauses](#conditional-where-clauses)
42
+ - [Paginating](#paginating)
43
+ - [Insert Statements](#insert-statements)
44
+ - [Update Statements](#update-statements)
45
+ - [Delete Statements](#delete-statements)
46
+ - [Hook Statements](#hook-statements)
47
+ - [Faker Statements](#faker-statements)
48
+ - [More Methods](#more-methods)
18
49
  - [Database Transactions](#database-transactions)
19
50
  - [Connection](#connection)
20
51
  - [Backup](#backup)
21
52
  - [Injection](#injection)
22
53
  - [Generating Model Classes](#generating-model-classes)
23
54
  - [Model Conventions](#model-conventions)
55
+ - [Basic Model Setup](#basic-model-setup)
56
+ - [Table Name](#table-name)
57
+ - [Pattern](#pattern)
58
+ - [UUID](#uuid)
59
+ - [Timestamp](#timestamp)
60
+ - [Debug](#debug)
61
+ - [Observer](#observer)
62
+ - [Logger](#logger)
63
+ - [Hooks](#hooks)
64
+ - [SoftDelete](#soft-delete)
65
+ - [Schema](#schema)
66
+ - [Schema Model](#schema-model)
67
+ - [Validation](#validation)
68
+ - [Sync](#sync)
24
69
  - [Relationships](#relationships)
25
70
  - [One To One](#one-to-one)
26
71
  - [One To Many](#one-to-many)
@@ -29,11 +74,17 @@ npm install tspace-mysql --save
29
74
  - [Deeply Nested Relations](#deeply-nested-relations)
30
75
  - [Relation Exists](#relation-exists)
31
76
  - [Built in Relation Functions](#built-in-relation-functions)
32
- - [Decorator](#decorator)
33
- - [Schema Model](#schema-model)
34
- - [Validation](#validation)
35
- - [Sync](#sync)
36
- - [Query Builder](#query-builder)
77
+ - [Decorator](#decorator)
78
+ - [Type Safety](#type-safety)
79
+ - [Safety Select](#safety-select)
80
+ - [Safety OrderBy](#safety-order-by)
81
+ - [Safety GroupBy](#safety-group-by)
82
+ - [Safety Where](#safety-where)
83
+ - [Safety Insert](#safety-insert)
84
+ - [Safety Update](#safety-update)
85
+ - [Safety Delete](#safety-delete)
86
+ - [Safety Relationships](#safety-relationships)
87
+ - [Blueprint](#blueprint)
37
88
  - [Cli](#cli)
38
89
  - [Make Model](#make-model)
39
90
  - [Make Migration](#make-migration)
@@ -41,26 +92,30 @@ npm install tspace-mysql --save
41
92
  - [Query](#query)
42
93
  - [Dump](#dump)
43
94
  - [Generate Models](#generate-models)
44
- - [Blueprint](#blueprint)
95
+ - [Migration Models](#migrate-models)
45
96
 
46
97
  ## Configuration
98
+
47
99
  To establish a connection, the recommended method for creating your environment variables is by using a '.env' file. using the following:
100
+
48
101
  ```js
49
- DB_HOST = localhost
50
- DB_PORT = 3306
51
- DB_USERNAME = root
52
- DB_PASSWORD = password
53
- DB_DATABASE = database
102
+ DB_HOST = localhost;
103
+ DB_PORT = 3306;
104
+ DB_USERNAME = root;
105
+ DB_PASSWORD = password;
106
+ DB_DATABASE = database;
54
107
 
55
- /**
108
+ /**
56
109
  * @default
57
110
  * DB_CONNECTION_LIMIT = 10
58
111
  * DB_QUEUE_LIMIT = 0
59
112
  * DB_TIMEOUT = 60000
60
113
  * DB_DATE_STRINGS = true
61
- */
114
+ */
62
115
  ```
116
+
63
117
  You can also create a file named 'db.tspace' to configure the connection. using the following:
118
+
64
119
  ```js
65
120
  source db {
66
121
  host = localhost
@@ -68,7 +123,7 @@ source db {
68
123
  database = npm
69
124
  user = root
70
125
  password = database
71
- connectionLimit = 10
126
+ connectionLimit = 10
72
127
  dateStrings = true
73
128
  connectTimeout = 60000
74
129
  waitForConnections = true
@@ -77,8 +132,11 @@ source db {
77
132
  }
78
133
 
79
134
  ```
80
- ## Running Queries
81
- Once you have configured your database connection, you can execute queries using the following:
135
+
136
+ ## Query Builder
137
+
138
+ How a database query builder works with a simple example using the following:
139
+
82
140
  ```js
83
141
  +-------------+--------------+----------------------------+
84
142
  | table users |
@@ -99,508 +157,1228 @@ Once you have configured your database connection, you can execute queries using
99
157
  | 2 | 2 | posts tspace2 |
100
158
  +-------------+--------------+----------------------------+
101
159
 
102
- import { DB } from 'tspace-mysql'
103
- (async () => {
104
- await new DB('users').findMany()
105
- // SELECT * FROM users => Array
106
- await new DB('users').findOne()
107
- // SELECT * FROM users LIMIT 1 => Object
108
- })()
109
-
110
160
  ```
111
- Running A Raw Query
161
+
162
+ ### Returning Results
163
+
112
164
  ```js
113
- const rawQuery = await new DB().query('SELECT * FROM users')
114
- // SELECT * FROM users;
165
+ const user = await new DB("users").find(1); // Object or null
166
+
167
+ const user = await new DB("users").findOne(); // Object or null
168
+
169
+ const user = await new DB("users").first(); // Object or null
170
+
171
+ const user = await new DB("users").firstOrError(message); // Object or error
172
+
173
+ const users = await new DB("users").findMany(); // Array-object of users
115
174
 
175
+ const users = await new DB("users").get(); // Array-object of users
176
+
177
+ const users = await new DB("users").toArray(); // Array of users
178
+
179
+ const users = await new DB("users").toJSON(); // JSON of users
180
+
181
+ const user = await new DB("users").exists(); // Boolean true if user exists otherwise false
182
+
183
+ const user = await new DB("users").count(); // Number of users counted
184
+
185
+ const user = await new DB("users").avg(); // Number of users avg
186
+
187
+ const user = await new DB("users").sum(); // Number of users sum
188
+
189
+ const user = await new DB("users").max(); // Number of users max
190
+
191
+ const user = await new DB("user").min(); // Number of users min
192
+
193
+ const users = await new DB("users").toString(); // sql query string
194
+
195
+ const users = await new DB("users").toSQL(); // sql query string
196
+
197
+ const users = await new DB("users").toRawSQL(); // sql query string
198
+
199
+ const users = await new DB("users").pagination(); // Object of pagination
200
+
201
+ const users = await new DB("users").makeSelectStatement() // query string for select statement
202
+
203
+ const users = await new DB("users").makeInsertStatement() // query string for insert statement
204
+
205
+ const users = await new DB("users").makeUpdateStatement() // query string for update statement
206
+
207
+ const users = await new DB("users").makeDeleteStatement() // query string for delete statement
208
+
209
+ const users = await new DB("users").makeCreateTableStatement() // query string for create table statement
116
210
  ```
117
- Running A Select Query
211
+
212
+ ## Select Statements
213
+
118
214
  ```js
119
- const select = await new DB('users').select('id','username').findOne()
215
+ const select = await new DB("users").select("id", "username").findOne();
120
216
  // SELECT `users`.`id`, `users`.`username` FROM `users` LIMIT 1;
121
217
 
122
- const selectRaw = await new DB('users').selectRaw('COUNT(id)').findMany()
218
+ const selectRaw = await new DB("users").selectRaw("COUNT(id)").findMany();
123
219
  // SELECT COUNT(id) FROM `users`;
220
+ // also you can use the DB.raw() function
221
+ // const selectRaw = await new DB("users").selec(DB.raw("COUNT(id)")).findMany();
222
+
223
+ const selectObject = await new DB("posts")
224
+ .join("posts.user_id", "users.id")
225
+ .select("posts.*")
226
+ .selectObject(
227
+ { id: "users.id", name: "users.name", email: "users.email" },
228
+ "user"
229
+ )
230
+ .findOne();
231
+
232
+ // SELECT posts.*, JSON_OBJECT('id' , `users`.`id` , 'name' , `users`.`name` , 'email' , `users`.`email`) AS `user`
233
+ // FROM `posts` INNER JOIN `users` ON `posts`.`user_id` = `users`.`id` LIMIT 1;
124
234
 
125
- const selectObject = await new DB('posts')
126
- .join('posts.user_id', 'users.id')
127
- .select('posts.*')
128
- .selectObject({ id : 'users.id', name : 'users.name' , email : 'users.email'} , 'user')
129
- .findOne()
235
+ await new DB("users").except("id").findOne();
236
+ // SELECT `users`.`email`, `users`.`username` FROM `users` LIMIT 1;
130
237
 
131
- // SELECT posts.*, JSON_OBJECT('id' , `users`.`id` , 'name' , `users`.`name` , 'email' , `users`.`email`) AS `user`
132
- // FROM `posts` INNER JOIN `users` ON `posts`.`user_id` = `users`.`id` LIMIT 1;
238
+ await new DB("users").distinct().select("id").findOne();
239
+ // SELECT DISTINCT `users`.`id` FROM `users` LIMIT 1;
240
+ ```
133
241
 
134
- /**
135
- * @example except
136
- */
137
- await new DB('users').except('id').findOne()
138
- // SELECT `users`.`email`, `users`.`username` FROM `users` LIMIT 1;
242
+ ## Raw Expressions
243
+
244
+ ```js
245
+ const users = await new DB("users")
246
+ .select(DB.raw("COUNT(`username`) as c"), "username")
247
+ .groupBy("username")
248
+ .having("c > 1")
249
+ .findMany();
250
+ // SELECT COUNT(`username`) as c, `users`.`username` FROM `users` GROUP BY `username` HAVING c > 1;
251
+
252
+ const users = await new DB("users")
253
+ .where(
254
+ "id",
255
+ DB.raw(new DB("users").select("id").where("id", "1").limit(1).toString())
256
+ )
257
+ .findMany();
258
+ // SELECT * FROM `users` WHERE `users`.`id` = (SELECT `users`.`id` FROM `users` WHERE `users`.`id` = '1' LIMIT 1);
139
259
  ```
140
260
 
141
- Running A OrderBy & GroupBy Query
261
+ ## Ordering, Grouping, Limit and Offset
262
+
263
+ ### Ordering
264
+
142
265
  ```js
143
- await new DB('users').orderBy('id','asc').findOne()
266
+ await new DB("users").orderBy("id", "asc").findOne();
144
267
  // SELECT * FROM `users` ORDER BY `id` ASC LIMIT 1;
145
268
 
146
- await new DB('users').orderBy('id','desc').findOne()
269
+ await new DB("users").orderBy("id", "desc").findOne();
147
270
  // SELECT * FROM `users` ORDER BY `id` DESC LIMIT 1;
148
271
 
149
- await new DB('users').oldest('id').findOne()
272
+ await new DB("users").oldest("id").findOne();
150
273
  // SELECT * FROM `users` ORDER BY `id` ASC LIMIT 1;
151
274
 
152
- await new DB('users').latest('id').findOne()
275
+ await new DB("users").latest("id").findOne();
153
276
  // SELECT * FROM `users` ORDER BY `id` DESC LIMIT 1;
154
277
 
155
- await new DB('users').groupBy('id').findOne()
278
+ await new DB("users").random().findMany();
279
+ // SELECT * FROM `users` ORDER BY RAND();
280
+ ```
281
+
282
+ ### Grouping
283
+
284
+ ```js
285
+ await new DB("users").groupBy("id").findOne();
156
286
  // SELECT * FROM `users` GROUP BY `id` LIMIT 1;
157
287
 
158
- await new DB('users').groupBy('id','username').findOne()
288
+ await new DB("users").groupBy("id", "username").findOne();
159
289
  // SELECT * FROM `users` GROUP BY `id`, `username` LIMIT 1;
160
290
 
161
- await new DB('users').orderBy('id').groupBy('id','username').findOne()
162
- // SELECT * FROM `users` GROUP BY `id`, `username` ORDER BY `id` ASC LIMIT 1;
291
+ await new DB("users")
292
+ .select(DB.raw("COUNT(username) as c"), "username")
293
+ .groupBy("username")
294
+ .having("c > 1")
295
+ .findMany();
296
+ // SELECT COUNT(username) as c, `users`.`username` FROM `users` GROUP BY `username` HAVING c > 1;
297
+ ```
298
+
299
+ ### Limit and Offset
300
+
301
+ ```js
302
+ await new DB("users").limit(5).findMany();
303
+ // SELECT * FROM `users` LIMIT 5;
163
304
 
305
+ await new DB("users").offset(1).findOne();
306
+ // SELECT * FROM `users` LIMIT 1 OFFSET 1;
164
307
  ```
165
308
 
166
- Running A Join Query
309
+ ## Joins
310
+
311
+ ### Inner Join Clause
312
+
167
313
  ```js
168
- await new DB('posts').join('posts.user_id' , 'users.id').findMany()
314
+ await new DB("posts").join("posts.user_id", "users.id").findMany();
169
315
  // SELECT * FROM `posts` INNER JOIN `users` ON `posts`.`user_id` = `users`.`id`;
316
+ ```
317
+
318
+ ### Left Join, Right Join Clause
170
319
 
171
- await new DB('posts').leftJoin('posts.user_id' , 'users.id').findMany()
320
+ ```js
321
+ await new DB("posts").leftJoin("posts.user_id", "users.id").findMany();
172
322
  // SELECT * FROM `posts` LEFT JOIN `users` ON `posts`.`user_id` = `users`.`id`;
173
323
 
174
- await new DB('posts').rightJoin('posts.user_id' , 'users.id').findMany()
324
+ await new DB("posts").rightJoin("posts.user_id", "users.id").findMany();
175
325
  // SELECT * FROM `posts` RIGHT JOIN `users` ON `posts`.`user_id` = `users`.`id`;
176
326
  ```
177
327
 
178
- Running A Where Query
179
- ```js
180
- const whereEqual = await new DB('users').where('id',1).findOne()
181
- // SELECT * FROM `users` WHERE `users`.`id` = '1' LIMIT 1;
182
-
183
- const whereNotEqual = await new DB('users').where('id','!=',1).findMany()
184
- // SELECT * FROM `users` WHERE `users`.`id` != '1';
328
+ ### Cross Join Clause
185
329
 
186
- const whereIn = await new DB('users').whereIn('id',[1,2]).findMany()
187
- // SELECT * FROM `users` WHERE `users`.`id` BETWEEN '1' AND '2';
330
+ ```js
331
+ await new DB("posts").crossJoin("posts.user_id", "users.id").findMany();
332
+ // SELECT * FROM `posts` CROSS JOIN `users` ON `posts`.`user_id` = `users`.`id`;
333
+ ```
188
334
 
189
- const whereBetween = await new DB('users').whereBetween('id',[1,2]).findMany()
190
- // SELECT * FROM `users` WHERE `users`.`id` BETWEEN '1' AND '2';
335
+ ## Basic Where Clauses
191
336
 
192
- const whereSubQuery = await new DB('users').whereSubQuery('id','SELECT id FROM users').findMany()
193
- // SELECT * FROM `users` WHERE `users`.`id` IN (SELECT id FROM users);
194
- // also you can use -> await new DB('users').whereSubQuery('id',new DB('users').select('id').toString()).findMany()
337
+ ### Where Clauses
195
338
 
196
- const whereNull = await new DB('users').whereNull('username').findOne()
197
- // SELECT * FROM `users` WHERE `users`.`username` IS NULL LIMIT 1;
339
+ ```js
340
+ const users = await new DB("users").where("id", 1).findMany();
341
+ // SELECT * FROM `users` WHERE `users`.`id` = '1'
198
342
 
199
- const whereNotNull = await new DB('users').whereNotNull('username').findOne()
200
- // SELECT * FROM `users` WHERE `users`.`username` IS NOT NULL LIMIT 1;
343
+ const users = await new DB("users")
344
+ .where("id", 1)
345
+ .where("username", "try to find")
346
+ .findMany();
347
+ // SELECT * FROM `users` WHERE `users`.`id` = '1' and `users`.`username` = 'try to find'
201
348
 
202
- const whereQuery = await new DB('users').whereQuery(query => query.where('id',1).where('username','values')).whereIn('id',[1,2]).findOne()
203
- // SELECT * FROM `users` WHERE ( `users`.`id` = '1' AND `users`.`username` = 'values') AND `users`.`id` IN ('1','2'') LIMIT 1;
349
+ const users = await new DB("users").where("id", ">", 1).findMany();
350
+ // SELECT * FROM `users` WHERE `users`.`id` > '1';
204
351
 
205
- const whereExists = await new DB('users').whereExists(new DB('users').select('id').where('id',1).toString()).findOne()
206
- // SELECT * FROM `users` WHERE EXISTS (SELECT `id` FROM `users` WHERE id = 1) LIMIT 1;
352
+ const users = await new DB("users").where("id", "<>", 1).findMany();
353
+ // SELECT * FROM `users` WHERE `users`.`id` <> '1';
354
+ ```
207
355
 
208
- const whereJSON = await new DB('users').whereJSON('json', { key : 'id', value : '1234' }).findOne()
209
- // SELECT * FROM `users` WHERE `users`.`json`->>'$.id' = '1234' LIMIT 1;
356
+ ### Or Where Clauses
210
357
 
211
- const whereWhenIsTrue = await new DB('users').where('id',1).when(true, (query) => query.where('username','when is actived')).findOne()
212
- // SELECT * FROM `users` WHERE `users`.`id` = '1' AND `users`.`username` = 'when is actived' LIMIT 1;
358
+ ```js
359
+ const users = await new DB("users").where("id", 1).orWhere("id", 2).findMany();
360
+ // SELECT * FROM `users` WHERE `users`.`id` = '1' OR `users`.`id` = '2'
213
361
 
214
- const whereWhenIsFalse = await new DB('users').where('id',1).when(false, (query) => query.where('username','when is actived')).findOne()
215
- // SELECT * FROM `users` WHERE `users`.`id` = '1' LIMIT 1;
362
+ const users = await new DB("users")
363
+ .where("id", 1)
364
+ .whereQuery((query) => {
365
+ return query
366
+ .where("id", "<>", 2)
367
+ .orWhere("username", "try to find")
368
+ .orWhere("email", "find@example.com");
369
+ })
370
+ .findMany();
371
+ // SELECT * FROM `users` WHERE `users`.`id` = '1'
372
+ // AND
373
+ // ( `users`.`id` <> '2' OR `users`.`username` = 'try to find' OR `users`.`email` = 'find@example.com');
374
+
375
+ const users = await new DB("users")
376
+ .where("id", 1)
377
+ .orWhereQuery((query) => {
378
+ return query
379
+ .where("id", "<>", 2)
380
+ .where("username", "try to find")
381
+ .where("email", "find@example.com");
382
+ })
383
+ .findMany();
384
+ // SELECT * FROM `users` WHERE `users`.`id` = '1'
385
+ // OR
386
+ // ( `users`.`id` <> '2' AND `users`.`username` = 'try to find' AND `users`.`email` = 'find@example.com');
216
387
  ```
217
388
 
218
- Running A Hook Query
389
+ ### JSON Where Clauses
390
+
219
391
  ```js
220
- const hookResult = (result) => console.log('hook!! result => ',result)
221
- const user = await new DB('users').where('id',1).hook(hookResult).findMany()
392
+ const whereJSON = await new DB("users")
393
+ .whereJSON("json", { key: "id", value: "1234" })
394
+ .findMany();
395
+ // SELECT * FROM `users` WHERE `users`.`json`->>'$.id' = '1234';
222
396
  ```
223
397
 
224
- Running A Faker
398
+ ### Additional Where Clauses
399
+
225
400
  ```js
401
+ const users = await new DB("users").whereIn("id", [1, 2]).findMany();
402
+ // SELECT * FROM `users` WHERE `users`.`id` IN ('1','2');
226
403
 
227
- await new DB('users').faker(10)
404
+ const users = await new DB("users").whereNotIn("id", [1, 2]).findMany();
405
+ // SELECT * FROM `users` WHERE `users`.`id` NOT IN ('1','2');
228
406
 
229
- // custom faker
230
- await new DB('users').faker(10 , (row , index) => {
231
- return {
232
- ...row,
233
- custom : 'custom' + index
234
- }
235
- })
407
+ const users = await new DB("users").whereBetween("id", [1, 2]).findMany();
408
+ // SELECT * FROM `users` WHERE `users`.`id` BETWEEN '1' AND '2';
409
+
410
+ const users = await new DB("users").whereNotBetween("id", [1, 2]).findMany();
411
+ // SELECT * FROM `users` WHERE `users`.`id` NOT BETWEEN '1' AND '2';
412
+
413
+ const users = await new DB("users").whereNull("username").findMany();
414
+ // SELECT * FROM `users` WHERE `users`.`username` IS NULL;
415
+
416
+ const users = await new DB("users").whereNotNull("username").findMany();
417
+ // SELECT * FROM `users` WHERE `users`.`username` IS NOT NULL;
236
418
  ```
237
419
 
238
- Running A Insert Query
420
+ ### Logical Grouping
421
+
239
422
  ```js
240
- const user = await new DB('users')
241
- .create({
242
- name : 'tspace3',
243
- email : 'tspace3@gmail.com'
244
- })
245
- .save()
246
- // INSERT INTO `users` (`name`,`email`) VALUES ('tspace3','tspace3@gmail.com');
423
+ const users = await new DB("users")
424
+ .whereQuery((query) => query.where("id", 1).where("username", "values"))
425
+ .whereIn("id", [1, 2])
426
+ .findOne();
427
+ // SELECT * FROM `users` WHERE ( `users`.`id` = '1' AND `users`.`username` = 'values') AND `users`.`id` IN ('1','2'') LIMIT 1;
247
428
 
248
- +--------------------------------------------------------------------------+
249
- const users = await new DB('users')
250
- .createMultiple([
251
- {
252
- name :'tspace4',
253
- email : 'tspace4@gmail.com'
254
- },
255
- {
256
- name :'tspace5',
257
- email : 'tspace5@gmail.com'
258
- },
259
- {
260
- name :'tspace6',
261
- email : 'tspace6@gmail.com'
262
- },
263
- ])
264
- .save()
429
+ const users = await new DB("users")
430
+ .where("id", 1)
431
+ .whereQuery((query) => {
432
+ return query
433
+ .where("id", "<>", 2)
434
+ .where("username", "try to find")
435
+ .where("email", "find@example.com");
436
+ })
437
+ .findMany();
438
+ // SELECT * FROM `users` WHERE `users`.`id` = '1'
439
+ // AND
440
+ // ( `users`.`id` <> '2' AND `users`.`username` = 'try to find' AND `users`.`email` = 'find@example.com');
441
+
442
+ const users = await new DB("users")
443
+ .whereAny(["name", "username", "email"], "like", `%v%`)
444
+ .findMany();
445
+ // SELECT * FROM `users` WHERE ( `users`.`name` LIKE '%v%' OR `users`.`username` LIKE '%v%' OR `users`.`email` LIKE '%v%');
446
+
447
+ const users = await new DB("users")
448
+ .whereAll(["name", "username", "email"], "like", `%v%`)
449
+ .findMany();
450
+ // SELECT * FROM `users` WHERE ( `users`.`name` LIKE '%v%' AND `users`.`username` LIKE '%v%' AND `users`.`email` LIKE '%v%');
451
+ ```
265
452
 
266
- // INSERT INTO `users` (`name`,`email`) VALUES ('tspace4','tspace4@gmail.com'),('tspace5','tspace5@gmail.com'),('tspace6','tspace6@gmail.com');
453
+ ## Advanced Where Clauses
267
454
 
268
- const users = await new DB('users')
269
- .where('name','tspace4')
270
- .where('email','tspace4@gmail.com')
271
- .createNotExists({
272
- name :'tspace4',
273
- email : 'tspace4@gmail.com'
274
- })
275
- .save()
276
- // if exists return null, if not exists created new data
277
- // SELECT EXISTS(SELECT 1 FROM `users` WHERE `users`.`name` = 'tspace4' AND `users`.`email` = 'tspace4@gmail.com' LIMIT 1) AS 'exists';
278
- // INSERT INTO `users` (`name`,`email`) VALUES ('tspace4','tspace4@gmail.com');
455
+ ### Where Exists Clauses
279
456
 
457
+ ```js
458
+ const users = await new DB("users")
459
+ .whereExists(new DB("users").select("id").where("id", 1).toString())
460
+ .findMany();
461
+ // SELECT * FROM `users` WHERE EXISTS (SELECT `id` FROM `users` WHERE id = 1);
462
+
463
+ const users = await new DB("users")
464
+ .wherNoteExists(new DB("users").select("id").where("id", 1).toString())
465
+ .findMany();
466
+ // SELECT * FROM `users` WHERE NOT EXISTS (SELECT `id` FROM `users` WHERE id = 1);
467
+ ```
280
468
 
281
- const users = await new DB('users')
282
- .where('name','tspace4')
283
- .where('email','tspace4@gmail.com')
284
- .createOrSelect({
285
- name :'tspace4',
286
- email : 'tspace4@gmail.com'
287
- })
288
- .save()
289
- // if has exists return data, if not exists created new data
290
- // SELECT EXISTS(SELECT 1 FROM `users` WHERE `users`.`name` = 'tspace4' AND `users`.`email` = 'tspace4@gmail.com' LIMIT 1) AS 'exists';
291
- // SELECT * FROM `users` WHERE `users`.`name` = 'tspace4' AND `users`.`email` = 'tspace4@gmail.com';
292
- // INSERT INTO `users` (`name`,`email`) VALUES ('tspace4','tspace4@gmail.com');
469
+ ### Subquery Where Clauses
293
470
 
294
- ```
295
- Running A Update Query
296
471
  ```js
297
- const user = await new DB('users')
298
- .where('id',1)
299
- .update({
300
- name : 'tspace1**',
301
- email : 'tspace1@gmail.com'
302
- })
303
- .save()
304
- // UPDATE `users` SET `name` = 'tspace1**',`email` = 'tspace1@gmail.com' WHERE `users`.`id` = '1' LIMIT 1;
472
+ const users = await new DB("users")
473
+ .whereSubQuery("id", "SELECT id FROM users")
474
+ .findMany();
475
+ // SELECT * FROM `users` WHERE `users`.`id` IN (SELECT id FROM users);
476
+
477
+ const users = await new DB("users")
478
+ .whereSubQuery("id", new DB("users").select("id").toString())
479
+ .findMany();
480
+ // SELECT * FROM `users` WHERE `users`.`id` IN (SELECT id FROM users);
305
481
 
306
- const user = await new DB('users')
307
- .where('id',1)
308
- .update({
309
- name : 'tspace1**',
310
- email : 'tspace1@gmail.com'
311
- },['name'])
312
- .save()
313
- // UPDATE `users` SET `name` = CASE WHEN (`name` = "" OR `name` IS NULL) THEN "tspace1**" ELSE `name` END,`email` = 'tspace1@gmail.com' WHERE `users`.`id` = '1' LIMIT 1;
482
+ const users = await new DB("users")
483
+ .whereSubQuery(
484
+ "id",
485
+ new DB("users")
486
+ .select("id")
487
+ .whereSubQuery("id", new DB("posts").select("user_id").toString())
488
+ .toString()
489
+ )
490
+ .findMany();
491
+ /*
314
492
 
493
+ SELECT * FROM `users`
494
+ WHERE `users`.`id`
495
+ IN (
496
+ SELECT `users`.`id` FROM `users`
497
+ WHERE `users`.`id`
498
+ IN (
499
+ SELECT `posts`.`user_id` FROM `posts`
500
+ )
501
+ );
502
+ */
315
503
  ```
316
- Running A Update Or Created Query
504
+
505
+ ### Conditional Where Clauses
506
+
317
507
  ```js
318
- const user = await new DB('users')
319
- .where('id',1)
320
- .updateOrCreate({
321
- name : 'tspace1**',
322
- email : 'tspace1@gmail.com'
323
- }).save()
324
- // INSERT INTO `users` (`name`,`email`) VALUES ('tspace1**','tspace1@gmail.com');
508
+ const users = await new DB("users")
509
+ .where("id", 1)
510
+ .when(true, (query) => query.where("username", "when is actived"))
511
+ .findMany();
512
+ // SELECT * FROM `users` WHERE `users`.`id` = '1' AND `users`.`username` = 'when is actived';
513
+
514
+ const users = await new DB("users")
515
+ .where("id", 1)
516
+ .when(false, (query) => query.where("username", "when is actived"))
517
+ .findMany();
518
+ // SELECT * FROM `users` WHERE `users`.`id` = '1';
519
+ ```
325
520
 
326
- // UPDATE `users` SET `name` = 'tspace1**',`email` = 'tspace1@gmail.com' WHERE `users`.`id` = '1' LIMIT 1;
327
- ```
521
+ ## Paginating
328
522
 
329
- Running A Delete Query
330
523
  ```js
331
- const deleted = await new DB('users').where('id',1).delete()
332
- // DELETE FROM `users` WHERE `users`.`id` = '1' LIMIT 1;
333
- ```
334
- ## Database Transactions
524
+ const users = await new DB("users").paginate();
525
+ // SELECT * FROM `users` LIMIT 15 OFFSET 0;
526
+ // SELECT COUNT(*) AS total FROM `users`;
335
527
 
336
- Within a database transaction, you can utilize the following:
528
+ const pageTwoUsers = await new DB("users").paginate({ page: 2, limit: 5 });
529
+
530
+ /*
531
+ SELECT * FROM `users` LIMIT 5 OFFSET 5;
532
+ SELECT COUNT(*) AS total FROM `users`;
533
+
534
+ the results are returned
535
+ {
536
+ meta: {
537
+ total: n,
538
+ limit: 5,
539
+ total_page: 5,
540
+ current_page: 2,
541
+ last_page: n,
542
+ next_page: 3,
543
+ prev_page: 1
544
+ },
545
+ data: [...your data here]
546
+ }
547
+
548
+ */
549
+ ```
550
+
551
+ ## Insert Statement
337
552
 
338
553
  ```js
339
- const connection = await new DB().beginTransaction()
554
+ const user = await new DB("users")
555
+ .create({
556
+ name: "tspace3",
557
+ email: "tspace3@gmail.com",
558
+ })
559
+ .save();
560
+ /**
561
+ INSERT INTO `users`
562
+ (`users`.`name`,`users`.`email`)
563
+ VALUES
564
+ ('tspace3','tspace3@gmail.com');
340
565
 
341
- try {
342
- /**
343
- *
344
- * @startTransaction start transaction in scopes function
345
- */
346
- await connection.startTransaction()
566
+ -- then return the result inserted --
567
+ SELECT * FROM `users` WHERE `users`.`id` = ${INSERT ID};
568
+ */
347
569
 
348
- const user = await new User()
349
- .create({
350
- name : `tspace`,
351
- email : 'tspace@example.com'
352
- })
353
- /**
354
- *
355
- * bind method for make sure this connection has same transaction in connection
356
- * @params {Function} connection
357
- */
358
- .bind(connection)
359
- .save()
570
+ const users = await new DB("users")
571
+ .createMultiple([
572
+ {
573
+ name: "tspace4",
574
+ email: "tspace4@gmail.com",
575
+ },
576
+ {
577
+ name: "tspace5",
578
+ email: "tspace5@gmail.com",
579
+ },
580
+ {
581
+ name: "tspace6",
582
+ email: "tspace6@gmail.com",
583
+ },
584
+ ])
585
+ .save();
360
586
 
361
- const posts = await new Post()
362
- .createMultiple([
363
- {
364
- user_id : user.id,
365
- title : `tspace-post1`
366
- },
367
- {
368
- user_id : user.id,
369
- title : `tspace-post2`
370
- },
371
- {
372
- user_id : user.id,
373
- title : `tspace-post3`
374
- }
375
- ])
376
- .bind(connection) // don't forget this
377
- .save()
587
+ /**
588
+ INSERT INTO `users`
589
+ (`users`.`name`,`users`.`email`)
590
+ VALUES
591
+ ('tspace4','tspace4@gmail.com'),
592
+ ('tspace5','tspace5@gmail.com'),
593
+ ('tspace6','tspace6@gmail.com');
594
+ */
378
595
 
379
- /**
380
- *
381
- * @commit commit transaction to database
382
- */
383
- await connection.commit()
596
+ const users = await new DB("users")
597
+ .where("name", "tspace4")
598
+ .where("email", "tspace4@gmail.com")
599
+ .createNotExists({
600
+ name: "tspace4",
601
+ email: "tspace4@gmail.com",
602
+ })
603
+ .save();
604
+ /*
605
+ -- if exists return null, if not exists created new data --
606
+ SELECT EXISTS(
607
+ SELECT 1 FROM `users`
608
+ WHERE `users`.`name` = 'tspace4'
609
+ AND `users`.`email` = 'tspace4@gmail.com'
610
+ LIMIT 1
611
+ ) AS 'exists';
612
+
613
+ INSERT INTO `users` (`users`.`name`,`users`.`email`) VALUES ('tspace4','tspace4@gmail.com');
614
+ */
384
615
 
385
- } catch (err) {
616
+ const users = await new DB("users")
617
+ .where("name", "tspace4")
618
+ .where("email", "tspace4@gmail.com")
619
+ .createOrSelect({
620
+ name: "tspace4",
621
+ email: "tspace4@gmail.com",
622
+ })
623
+ .save();
624
+ /**
625
+ -- if has exists return data, if not exists created new data --
626
+ SELECT EXISTS(
627
+ SELECT 1 FROM `users`
628
+ WHERE `users`.`name` = 'tspace4'
629
+ AND `users`.`email` = 'tspace4@gmail.com'
630
+ LIMIT 1
631
+ ) AS 'exists';
386
632
 
387
- /**
388
- *
389
- * @rollback rollback transaction
390
- */
391
- await connection.rollback()
392
- }
633
+ INSERT INTO `users` (`users`.`name`,`users`.`email`) VALUES ('tspace4','tspace4@gmail.com');
393
634
 
635
+ SELECT * FROM `users` WHERE `users`.`id` = '4';
636
+ */
394
637
  ```
395
- ## Connection
396
- When establishing a connection, you can specify options as follows:
397
- ```js
398
- const connection = await new DB().getConnection({
399
- host: 'localhost',
400
- port : 3306,
401
- database: 'database'
402
- username: 'username',
403
- password: 'password',
404
- })
405
638
 
406
- const users = await new DB('users')
407
- .bind(connection) // don't forget this
408
- .findMany()
409
- ```
639
+ ## Update Statements
410
640
 
411
- ## Backup
412
- To backup a database, you can perform the following steps:
413
641
  ```js
642
+ const user = await new DB("users")
643
+ .where("id", 1)
644
+ .update({
645
+ name: "tspace1**",
646
+ email: "tspace1@gmail.com",
647
+ })
648
+ .save();
414
649
  /**
415
- *
416
- * @param {string} database Database selected
417
- * @param {object | null} to defalut new current connection
650
+
651
+ UPDATE `users` SET
652
+ `users`.`name` = 'tspace1',
653
+ `users`.`email` = 'tspace1@gmail.com'
654
+ WHERE `users`.`id` = '1' LIMIT 1;
655
+
418
656
  */
419
- const backup = await new DB().backup({
420
- database: 'try-to-backup', // clone current database to this database
421
- to ?: {
422
- host: 'localhost',
423
- port : 3306,
424
- username: 'username',
425
- password: 'password',
426
- }
427
- })
657
+
658
+ const user = await new DB("users")
659
+ .where("id", 1)
660
+ .updateMany({
661
+ name: "tspace1",
662
+ email: "tspace1@gmail.com",
663
+ })
664
+ .save();
428
665
  /**
429
- *
430
- * @param {string} database Database selected
431
- * @param {string} filePath file path
432
- * @param {object | null} conection defalut current connection
666
+ UPDATE `users` SET
667
+ `users`.`name` = 'tspace1',
668
+ `users`.`email` = 'tspace1@gmail.com'
669
+ WHERE `users`.`id` = '1';
433
670
  */
434
- const backupToFile = await new DB().backupToFile({
435
- database: 'try-to-backup',
436
- filePath: 'backup.sql',
437
- connection ?: {
438
- host: 'localhost',
439
- port : 3306,
440
- database: 'database'
441
- username: 'username',
442
- password: 'password',
443
- }
444
- })
445
- // backupToFile => backup.sql
446
671
 
672
+ const user = await new DB("users")
673
+ .where("id", 1)
674
+ .update(
675
+ {
676
+ name: "tspace1",
677
+ email: "tspace1@gmail.com",
678
+ },
679
+ ["name"]
680
+ )
681
+ .save();
447
682
  /**
448
- *
449
- * @param {string} database new db name
683
+ UPDATE `users` SET
684
+ `name` =
685
+ CASE WHEN (`name` = '' OR `name` IS NULL)
686
+ THEN 'tspace1' ELSE `name`
687
+ END,
688
+ `email` =
689
+ 'tspace1@gmail.com'
690
+ WHERE `users`.`id` = '1' LIMIT 1;
450
691
  */
451
- await new DB().cloneDB('try-to-clone')
452
692
 
693
+ const user = await new DB("users")
694
+ .updateMultiple([
695
+ {
696
+ when: {
697
+ id: 1,
698
+ name: "name1",
699
+ },
700
+ columns: {
701
+ name: "update row1",
702
+ email: "row1@example.com",
703
+ },
704
+ },
705
+ {
706
+ when: {
707
+ id: 2,
708
+ },
709
+ columns: {
710
+ name: "update row2",
711
+ email: "row2@example.com",
712
+ },
713
+ },
714
+ ])
715
+ .whereIn("id", [1, 2])
716
+ .save();
717
+
718
+ /**
719
+ UPDATE `users` SET
720
+ `users`.`name` = (
721
+ CASE WHEN `users`.`id` = '1'
722
+ AND `users`.`name` = 'name1'
723
+ THEN 'update row1'
724
+ WHEN `users`.`id` = '2'
725
+ THEN 'update row2'
726
+ ELSE `users`.`name`
727
+ END
728
+ ),
729
+ `users`.`email` = (
730
+ CASE WHEN `users`.`id` = '1'
731
+ AND `users`.`name` = 'name1'
732
+ THEN 'row1@example.com'
733
+ WHEN `users`.`id` = '2'
734
+ THEN 'row2@example.com'
735
+ ELSE `users`.`email`
736
+ END
737
+ )
738
+ WHERE `users`.`id` IN ('1','2') LIMIT 2;
739
+
740
+ */
741
+
742
+ const user = await new DB("users")
743
+ .where("id", 1)
744
+ .updateOrCreate({
745
+ name: "tspace1**",
746
+ email: "tspace1@gmail.com",
747
+ })
748
+ .save();
749
+ // if has exists return update, if not exists created new data
750
+ // UPDATE `users` SET `name` = 'tspace1**',`email` = 'tspace1@gmail.com' WHERE `users`.`id` = '1' LIMIT 1;
751
+ // INSERT INTO `users` (`name`,`email`) VALUES ('tspace1**','tspace1@gmail.com');
453
752
  ```
454
753
 
455
- ## Injection
456
- The 'tspace-mysql' library is configured to automatically escape SQL injection by default.
457
- Let's example a escape SQL injection and XSs injection:
754
+ ## Delete Statements
755
+
458
756
  ```js
459
- const input = "admin' OR '1'='1"
460
- DB.escape(input)
461
- // admin OR 1=1
757
+ const deleted = await new DB("users").where("id", 1).delete();
758
+ // DELETE FROM `users` WHERE `users`.`id` = '1' LIMIT 1;
462
759
 
463
- //XSS
464
- const input = "text hello!<script>alert('XSS attack');</script>"
465
- DB.escapeXSS(input)
466
- // text hello!
760
+ const deleted = await new DB("users").where("id", 1).deleteMany();
761
+ // DELETE FROM `users` WHERE `users`.`id` = '1' ;
762
+ ```
763
+
764
+ ## Hook Statements
467
765
 
766
+ ```js
767
+ const hookImage = async (results) => {
768
+ for(const result of results) {
769
+ result.image = await ...getImage()
770
+ }
771
+ };
772
+ const user = await new DB("users").where("id", 1).hook(hookResult).findMany();
468
773
  ```
469
774
 
470
- ## Generating Model Classes
471
- To get started, install the 'tspace-mysql' package globally using the following npm command:
775
+ ## Faker Statements
472
776
 
473
777
  ```js
778
+ await new DB("users").faker(2);
474
779
  /**
475
- *
476
- * @install global command
780
+ INSERT INTO `users`
781
+ (`users`.`username`,`users`.`email`)
782
+ VALUES
783
+ ('ivsvtagyta86n571z9d81maz','fxcwkubccdi5ewos521uqexy'),
784
+ ('rnr4esoki7fgekmdtarqewt','gv0mzb1m3rlbinsdyb6')
477
785
  */
478
- npm install tspace-mysql -g
786
+
787
+ // custom faker
788
+ await new DB("users").faker(5, (row, index) => {
789
+ return {
790
+ username: `username-${index + 1}`,
791
+ email: `email-${index + 1}`,
792
+ };
793
+ });
479
794
 
480
795
  /**
481
- *
796
+
797
+ INSERT INTO `users`
798
+ (`users`.`username`,`users`.`email`)
799
+ VALUES
800
+ ('username-1','email-1'),
801
+ ('username-2','email-2'),
802
+ ('username-3','email-3'),
803
+ ('username-4','email-4'),
804
+ ('username-5','email-5');
805
+
806
+ */
807
+ ```
808
+
809
+ ## More Methods
810
+
811
+ ```js
812
+ where(column , operator , value)
813
+ whereSensitive(column , operator , value)
814
+ whereId(id)
815
+ whereUser(userId)
816
+ whereEmail(value)
817
+ whereIn(column , [])
818
+ whereNotIn(column , [])
819
+ whereNull(column)
820
+ whereNotNull(column)
821
+ whereBetween (column , [value1 , value2])
822
+ whereQuery(callback)
823
+ whereJson(column, { targetKey, value , operator })
824
+ whereRaw(sql)
825
+ whereExists(sql)
826
+ whereSubQuery(colmn , rawSQL)
827
+ whereNotSubQuery(colmn , rawSQL)
828
+ orWhere(column , operator , value)
829
+ orWhereRaw(sql)
830
+ orWhereIn(column , [])
831
+ orWhereSubQuery(colmn , rawSQL)
832
+ when(contition , callback)
833
+ select(column1 ,column2 ,...N)
834
+ distinct()
835
+ selectRaw(column1 ,column2 ,...N)
836
+ except(column1 ,column2 ,...N)
837
+ exceptTimestamp()
838
+ only(column1 ,column2 ,...N)
839
+ hidden(column1 ,column2 ,...N)
840
+ join(primary key , table.foreign key)
841
+ rightJoin (primary key , table.foreign key)
842
+ leftJoin (primary key , table.foreign key)
843
+ limit (limit)
844
+ having (condition)
845
+ havingRaw (condition)
846
+ orderBy (column ,'ASC' || 'DSCE')
847
+ orderByRaw(column ,'ASC' || 'DSCE')
848
+ latest (column)
849
+ latestRaw (column)
850
+ oldest (column)
851
+ oldestRaw (column)
852
+ groupBy (column)
853
+ groupByRaw (column)
854
+ create(objects)
855
+ createMultiple(array objects)
856
+ update (objects)
857
+ updateMany (objects)
858
+ updateMultiple(array objects)
859
+ createNotExists(objects)
860
+ updateOrCreate (objects)
861
+ onlyTrashed()
862
+ connection(options)
863
+ backup({ database , connection })
864
+ backupToFile({ filePath, database , connection })
865
+ hook((result) => ...) // callback result to function
866
+ sleep(seconds)
867
+
868
+ /**
869
+ * registry relation in your models
870
+ * @relationship
871
+ */
872
+ hasOne({ name, model, localKey, foreignKey, freezeTable , as })
873
+ hasMany({ name, model, localKey, foreignKey, freezeTable , as })
874
+ belongsTo({ name, model, localKey, foreignKey, freezeTable , as })
875
+ belongsToMany({ name, model, localKey, foreignKey, freezeTable, as, pivot })
876
+ /**
877
+ * @relation using registry in your models
878
+ */
879
+ relations(name1 , name2,...nameN) // with(name1, name2,...nameN)
880
+ /**
881
+ * @relation using registry in your models ignore soft delete
882
+ */
883
+ relationsAll(name1 , name2,...nameN) // withAll(name1, name2,...nameN)
884
+ /**
885
+ * @relation using registry in your models. if exists child data remove this data
886
+ */
887
+ relationsExists(name1 , name2,...nameN) // withExists(name1, name2,...nameN)
888
+ /**
889
+ * @relation using registry in your models return only in trash (soft delete)
890
+ */
891
+ relationsTrashed(name1 , name2,...nameN) // withTrashed(name1, name2,...nameN)
892
+ /**
893
+ * @relation call a name of relation in registry, callback query of data
894
+ */
895
+ relationQuery(name, (callback) ) // withQuery(name1, (callback))
896
+
897
+
898
+ /**
899
+ * queries statements
900
+ * @execute data of statements
901
+ */
902
+ findMany() // get()
903
+ findOne() // first()
904
+ find(id)
905
+ delelte()
906
+ delelteMany()
907
+ exists()
908
+ toString()
909
+ toJSON()
910
+ toArray(column)
911
+ count(column)
912
+ sum(column)
913
+ avg(column)
914
+ max(column)
915
+ min(column)
916
+ pagination({ limit , page })
917
+ save() /* for actions statements insert or update */
918
+ makeSelectStatement()
919
+ makeInsertStatement()
920
+ makeUpdateStatement()
921
+ makeDeleteStatement()
922
+ makeCreateTableStatement()
923
+
924
+ ```
925
+
926
+ ## Database Transactions
927
+
928
+ Within a database transaction, you can utilize the following:
929
+
930
+ ```js
931
+ const connection = await new DB().beginTransaction();
932
+
933
+ try {
934
+ /**
935
+ *
936
+ * @startTransaction start transaction in scopes function
937
+ */
938
+ await connection.startTransaction();
939
+
940
+ const user = await new User()
941
+ .create({
942
+ name: `tspace`,
943
+ email: "tspace@example.com",
944
+ })
945
+ /**
946
+ *
947
+ * bind method for make sure this connection has same transaction in connection
948
+ * @params {Function} connection
949
+ */
950
+ .bind(connection)
951
+ .save();
952
+
953
+ const posts = await new Post()
954
+ .createMultiple([
955
+ {
956
+ user_id: user.id,
957
+ title: `tspace-post1`,
958
+ },
959
+ {
960
+ user_id: user.id,
961
+ title: `tspace-post2`,
962
+ },
963
+ {
964
+ user_id: user.id,
965
+ title: `tspace-post3`,
966
+ },
967
+ ])
968
+ .bind(connection) // don't forget this
969
+ .save();
970
+
971
+ /**
972
+ *
973
+ * @commit commit transaction to database
974
+ */
975
+ await connection.commit();
976
+ } catch (err) {
977
+ /**
978
+ *
979
+ * @rollback rollback transaction
980
+ */
981
+ await connection.rollback();
982
+ }
983
+ ```
984
+
985
+ ## Connection
986
+
987
+ When establishing a connection, you can specify options as follows:
988
+
989
+ ```js
990
+ const connection = await new DB().getConnection({
991
+ host: 'localhost',
992
+ port : 3306,
993
+ database: 'database'
994
+ username: 'username',
995
+ password: 'password',
996
+ })
997
+
998
+ const users = await new DB('users')
999
+ .bind(connection) // don't forget this
1000
+ .findMany()
1001
+ ```
1002
+
1003
+ ## Backup
1004
+
1005
+ To backup a database, you can perform the following steps:
1006
+
1007
+ ```js
1008
+ /**
1009
+ *
1010
+ * @param {string} database Database selected
1011
+ * @param {object | null} to defalut new current connection
1012
+ */
1013
+ const backup = await new DB().backup({
1014
+ database: 'try-to-backup', // clone current database to this database
1015
+ to ?: {
1016
+ host: 'localhost',
1017
+ port : 3306,
1018
+ username: 'username',
1019
+ password: 'password',
1020
+ }
1021
+ })
1022
+ /**
1023
+ *
1024
+ * @param {string} database Database selected
1025
+ * @param {string} filePath file path
1026
+ * @param {object | null} conection defalut current connection
1027
+ */
1028
+ const backupToFile = await new DB().backupToFile({
1029
+ database: 'try-to-backup',
1030
+ filePath: 'backup.sql',
1031
+ connection ?: {
1032
+ host: 'localhost',
1033
+ port : 3306,
1034
+ database: 'database'
1035
+ username: 'username',
1036
+ password: 'password',
1037
+ }
1038
+ })
1039
+ // backupToFile => backup.sql
1040
+
1041
+ /**
1042
+ *
1043
+ * @param {string} database new db name
1044
+ */
1045
+ await new DB().cloneDB('try-to-clone')
1046
+
1047
+ ```
1048
+
1049
+ ## Injection
1050
+
1051
+ The 'tspace-mysql' library is configured to automatically escape SQL injection by default.
1052
+ Let's example a escape SQL injection and XSs injection:
1053
+
1054
+ ```js
1055
+ const input = "admin' OR '1'='1";
1056
+ DB.escape(input);
1057
+ // "admin\' OR \'1\'=\'1"
1058
+
1059
+ //XSS
1060
+ const input = "text hello!<script>alert('XSS attack');</script>";
1061
+ DB.escapeXSS(input);
1062
+ // "text hello!"
1063
+ ```
1064
+
1065
+ ## Generating Model Classes
1066
+
1067
+ To get started, install the 'tspace-mysql' package globally using the following npm command:
1068
+
1069
+ ```js
1070
+ /**
1071
+ *
1072
+ * @install global command
1073
+ */
1074
+ npm install tspace-mysql -g
1075
+
1076
+ /**
1077
+ *
482
1078
  * @make Model
483
- */
1079
+ */
484
1080
  tspace-mysql make:model <model name> --dir=< directory >
485
1081
 
486
- # tspace-mysql make:model User --dir=App/Models
1082
+ # tspace-mysql make:model User --dir=App/Models
487
1083
  # App/Models/User.ts
488
1084
  ```
1085
+
489
1086
  ## Model Conventions
490
- Models generated by the make:model command will be placed in the specific directory.
1087
+
1088
+ Models generated by the make:model command will be placed in the specific directory.
491
1089
  Let's example a basic model class:
492
1090
 
493
1091
  ```js
494
- import { Model } from 'tspace-mysql'
1092
+ import { Model } from "tspace-mysql";
495
1093
  // If you want to specify a global setting for the 'Model'
496
1094
  Model.global({
497
1095
  uuid: true,
498
1096
  softDelete: true,
499
- timestamp: true
500
- })
1097
+ timestamp: true,
1098
+ logger: true,
1099
+ });
1100
+
1101
+ class User extends Model {
1102
+ constructor() {
1103
+ super();
1104
+ /**
1105
+ *
1106
+ * Assign setting global in your model
1107
+ * @useMethod
1108
+ * this.usePattern('camelCase') // => default 'snake_case'
1109
+ * this.useCamelCase()
1110
+ * this.useSnakeCase()
1111
+ * this.useLogger()
1112
+ * this.useDebug()
1113
+ * this.usePrimaryKey('id')
1114
+ * this.useTimestamp({
1115
+ * createdAt : 'created_at',
1116
+ * updatedAt : 'updated_at'
1117
+ * }) // runing a timestamp when insert or update
1118
+ * this.useSoftDelete('deletedAt') // => default target to colmun deleted_at
1119
+ * this.useTable('users')
1120
+ * this.useTableSingular() // => 'user'
1121
+ * this.useTablePlural() // => 'users'
1122
+ * this.useUUID('uuid') // => runing a uuid (universally unique identifier) when insert new data
1123
+ * this.useRegistry() // => build-in functions registry
1124
+ * this.useLoadRelationsInRegistry() // => auto generated result from relationship to results
1125
+ * this.useBuiltInRelationFunctions() // => build-in functions relationships to results
1126
+ * this.useHooks([(r) => console.log(r)])
1127
+ * this.useObserver(Observe)
1128
+ * this.useSchema ({
1129
+ * id : new Blueprint().int().notNull().primary().autoIncrement(),
1130
+ * uuid : new Blueprint().varchar(50).null(),
1131
+ * name : new Blueprint().varchar(191).notNull(),
1132
+ * email : new Blueprint().varchar(191).notNull(),
1133
+ * created_at : new Blueprint().timestamp().null(),
1134
+ * updated_at : new Blueprint().timestamp().null(),
1135
+ * deleted_at : new Blueprint().timestamp().null()
1136
+ * }) // auto-generated table when table is not exists and auto-create column when column not exists
1137
+ *
1138
+ * // validate input when create or update reference to the schema in 'this.useSchema'
1139
+ * this.useValidateSchema({
1140
+ * id : Number,
1141
+ * uuid : Number,
1142
+ * name : {
1143
+ * type : String,
1144
+ * length : 191
1145
+ * require : true
1146
+ * },
1147
+ * email : {
1148
+ * type : String,
1149
+ * require : true,
1150
+ * length : 191,
1151
+ * match: /^[a-zA-Z0-9._]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
1152
+ * unique : true,
1153
+ * fn : (email : string) => !/^[a-zA-Z0-9._]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(email)
1154
+ * },
1155
+ * created_at : Date,
1156
+ * updated_at : Date,
1157
+ * deleted_at : Date
1158
+ * })
1159
+ */
1160
+
1161
+ /*
1162
+ * the "snake case", plural name of the class will be used as the table name
1163
+ *
1164
+ * @param {string} name The table associated with the model.
1165
+ */
1166
+ this.useTable("users");
1167
+ }
1168
+ }
1169
+ export { User };
1170
+ export default User;
1171
+ ```
1172
+
1173
+ ### Basic Model Setup
1174
+
1175
+ #### Table Name
1176
+
1177
+ ```js
1178
+ import { Model } from 'tspace-mysql'
1179
+ class User extends Model {
1180
+ constructor() {
1181
+ super()
1182
+ // By default, the model knows that the table name for this User is 'users'
1183
+
1184
+ this.useTable('fixtable') // fixtable
1185
+ this.useTablePlural() // users
1186
+ this.useTableSingular() // user
1187
+ }
1188
+ }
1189
+
1190
+ ```
1191
+
1192
+ #### Pattern
1193
+
1194
+ ```js
1195
+
1196
+ import { Model } from 'tspace-mysql'
1197
+ class UserPhone extends Model {
1198
+ constructor() {
1199
+ super()
1200
+ // By default, the model is pattern snake_case
1201
+ // The table name is user_phones
1202
+ this.useSnakeCase()
1203
+
1204
+
1205
+ this.useCamelCase()
1206
+ // The table name is userPhones
1207
+ }
1208
+ }
1209
+
1210
+ // set the pattern CamelCase for the model
1211
+ const userPhone = await new UserPhone().where('user_id',1).findOne()
1212
+ // covert 'user_id' to 'userId'
1213
+ // SELECT * FROM `userPhones` WHERE `userPhones`.`userId` = '1' LIMIT 1;
1214
+
1215
+ ```
1216
+
1217
+ #### UUID
1218
+
1219
+ ```js
1220
+
1221
+ import { Model } from 'tspace-mysql'
1222
+ class User extends Model {
1223
+ constructor() {
1224
+ super()
1225
+ this.useUUID() // insert uuid when creating
1226
+ }
1227
+ }
1228
+
1229
+ ```
1230
+
1231
+ #### Timestamp
1232
+
1233
+ ```js
1234
+
1235
+ import { Model } from 'tspace-mysql'
1236
+ class User extends Model {
1237
+ constructor() {
1238
+ super()
1239
+ // insert created_at and updated_at when creating
1240
+ // update updated_at when updating
1241
+ // 'created_at' and 'updated_at' still relate to pettern the model
1242
+ // this.useCamelCase() will covert 'created_at' to 'createdAt' and 'updated_at' to 'updatedAt'
1243
+ this.useTimestamp()
1244
+
1245
+ // custom the columns
1246
+ this.useTimestamp({
1247
+ createdAt : 'createdAtCustom',
1248
+ updatedAt : 'updatedAtCustom'
1249
+ })
1250
+
1251
+ }
1252
+ }
1253
+
1254
+ ```
1255
+
1256
+ #### Debug
1257
+
1258
+ ```js
1259
+
1260
+ import { Model } from 'tspace-mysql'
1261
+ class User extends Model {
1262
+ constructor() {
1263
+ super()
1264
+ this.useDebug() // show the query sql in console when executing
1265
+ }
1266
+ }
1267
+
1268
+ ```
1269
+ #### Observer
1270
+
1271
+ ```js
501
1272
 
502
- /**
503
1273
  class Observe {
504
1274
 
505
- public selected(results : unknown) {
1275
+ public selected(results) {
506
1276
  console.log({ results , selected : true })
507
1277
  }
508
1278
 
509
- public created(results : unknown) {
1279
+ public created(results) {
510
1280
  console.log({ results , created : true })
511
1281
  }
512
1282
 
513
- public updated(results : unknown) {
1283
+ public updated(results) {
514
1284
  console.log({ results , updated : true })
515
1285
  }
516
1286
 
517
- public deleted(results : unknown) {
1287
+ public deleted(results) {
518
1288
  console.log({ results , deleted : true })
519
1289
  }
520
1290
  }
521
- */
1291
+
1292
+ import { Model } from 'tspace-mysql'
1293
+ class User extends Model {
1294
+ constructor() {
1295
+ super()
1296
+ this.useObserver(Observe) // returning to the observers by statements
1297
+ }
1298
+ }
1299
+
1300
+ ```
1301
+
1302
+ #### Logger
1303
+
1304
+ ```js
1305
+
1306
+ import { Model } from 'tspace-mysql'
1307
+ class User extends Model {
1308
+ constructor() {
1309
+ super()
1310
+ // keep logging everything except select to the table '$loggers'
1311
+ // the table will automatically be created
1312
+ this.useLogger()
1313
+
1314
+ // keep logging everything
1315
+ this.useLogger({
1316
+ selected : true,
1317
+ inserted : true,
1318
+ updated : true,
1319
+ deleted : true,
1320
+ })
1321
+ }
1322
+ }
1323
+
1324
+ ```
1325
+
1326
+ #### Hooks
1327
+
1328
+ ```js
1329
+
1330
+ import { Model } from 'tspace-mysql'
522
1331
  class User extends Model {
523
- constructor(){
1332
+ constructor() {
524
1333
  super()
525
- /**
526
- *
527
- * Assign setting global in your model
528
- * @useMethod
529
- * this.usePattern('camelCase') // => default 'snake_case'
530
- * this.useDebug()
531
- * this.usePrimaryKey('id')
532
- * this.useTimestamp({
533
- * createdAt : 'created_at',
534
- * updatedAt : 'updated_at'
535
- * }) // runing a timestamp when insert or update
536
- * this.useSoftDelete('deletedAt') // => default target to colmun deleted_at
537
- * this.useTable('users')
538
- * this.useTableSingular() // => 'user'
539
- * this.useTablePlural() // => 'users'
540
- * this.useUUID('uuid') // => runing a uuid (universally unique identifier) when insert new data
541
- * this.useRegistry() // => build-in functions registry
542
- * this.useLoadRelationsInRegistry() // => auto generated result from relationship to results
543
- * this.useBuiltInRelationFunctions() // => build-in functions relationships to results
544
- * this.useHooks([(r) => console.log(r)])
545
- * this.useObserver(Observe)
546
- * this.useSchema ({
547
- * id : new Blueprint().int().notNull().primary().autoIncrement(),
548
- * uuid : new Blueprint().varchar(50).null(),
549
- * name : new Blueprint().varchar(191).notNull(),
550
- * email : new Blueprint().varchar(191).notNull(),
551
- * created_at : new Blueprint().timestamp().null(),
552
- * updated_at : new Blueprint().timestamp().null(),
553
- * deleted_at : new Blueprint().timestamp().null()
554
- * }) // auto-generated table when table is not exists and auto-create column when column not exists
555
- *
556
- * // validate input when create or update reference to the schema in 'this.useSchema'
557
- * this.useValidateSchema({
558
- * id : Number,
559
- * uuid : Number,
560
- * name : {
561
- * type : String,
562
- * length : 191
563
- * require : true
564
- * },
565
- * email : {
566
- * type : String,
567
- * require : true,
568
- * length : 191,
569
- * match: /^[a-zA-Z0-9._]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
570
- * unique : true,
571
- * fn : (email : string) => !/^[a-zA-Z0-9._]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(email)
572
- * },
573
- * created_at : Date,
574
- * updated_at : Date,
575
- * deleted_at : Date
576
- * })
577
- */
1334
+ // when executed will returning the results to any hooks function
1335
+ this.useHooks([
1336
+ (results1) => console.log(results1),
1337
+ (results2) => console.log(results2),
1338
+ (results3) => console.log(results3)
1339
+ ])
1340
+ }
1341
+ }
578
1342
 
1343
+ ```
579
1344
 
580
- /*
581
- * the "snake case", plural name of the class will be used as the table name
582
- *
583
- * @param {string} name The table associated with the model.
584
- */
585
- this.useTable('users')
586
- }
1345
+ ### SoftDelete
1346
+
1347
+ ```js
1348
+
1349
+ import { Model } from 'tspace-mysql'
1350
+ class User extends Model {
1351
+ constructor() {
1352
+ super()
1353
+ this.useSoftDelete() // All query will be where 'deleted_at' is null
1354
+
1355
+ // you can also use patterns camelCase to covert the 'deleted_at' to 'deletedAt'
1356
+ // you can also customize the column 'deleted_at'
1357
+ this.useSoftDelete('deletedAtCustom')
1358
+ }
587
1359
  }
588
- export { User }
589
- export default User
1360
+
1361
+ const user = await new User().where('user_id',1).findOne()
1362
+ // SELECT * FROM `users` WHERE `users`.`userId` = '1' and `users`.`deletedAtCustom` IS NULL LIMIT 1;
1363
+
590
1364
  ```
591
- ## Relationships
592
- Relationships are defined as methods on your Model classes.
1365
+
1366
+ ### Relationships
1367
+
1368
+ Relationships are defined as methods on your Model classes.
593
1369
  Let's example a basic relationship:
594
1370
 
595
- ## One To One
1371
+ #### One To One
1372
+
596
1373
  A one-to-one relationship is used to define relationships where a single model is the parent to one child models
1374
+
597
1375
  ```js
598
1376
  import { Model } from 'tspace-mysql'
599
1377
  import Phone from '../Phone'
600
1378
  class User extends Model {
601
1379
  constructor(){
602
1380
  super()
603
- this.useTimestamp()
1381
+ this.useTimestamp()
604
1382
  /**
605
1383
  *
606
1384
  * @hasOne Get the phone associated with the user.
@@ -609,12 +1387,12 @@ class User extends Model {
609
1387
  this.hasOne({ name : 'phone' , model : Phone })
610
1388
  }
611
1389
  /**
612
- * Mark a method for relationship
1390
+ * Mark a method for relationship
613
1391
  * @hasOne Get the phone associated with the user. using function callback
614
- * @function
1392
+ * @function
615
1393
  */
616
- phone (callback ?: Function) {
617
- return this.hasOneBuilder({ name : 'phone' , model : Phone } , callback)
1394
+ phone (callback) {
1395
+ return this.hasOneBuilder({ name : 'phone' , model : Phone } , callback)
618
1396
  }
619
1397
  }
620
1398
  export default User
@@ -622,14 +1400,16 @@ export default User
622
1400
  +--------------------------------------------------------------------------+
623
1401
 
624
1402
  import User from '../User'
625
- const user = await new User().relations('brand').findOne()
626
- // user?.phone => {...}
1403
+ const user = await new User().relations('phone').findOne() // can use the method .with('roles') also
1404
+ // user?.phone => {...}
627
1405
  const userUsingFunction = await new User().phone().findOne()
628
- // userUsingFunction?.phone => {...}
1406
+ // userUsingFunction?.phone => {...}
629
1407
  ```
630
1408
 
631
- ## One To Many
1409
+ ### One To Many
1410
+
632
1411
  A one-to-many relationship is used to define relationships where a single model is the parent to one or more child models.
1412
+
633
1413
  ```js
634
1414
  import { Model } from 'tspace-mysql'
635
1415
  import Comment from '../Comment'
@@ -645,11 +1425,11 @@ class Post extends Model {
645
1425
  this.hasMany({ name : 'comments' , model : Comment })
646
1426
  }
647
1427
  /**
648
- *
1428
+ *
649
1429
  * @hasManyQuery Get the comments for the post. using function callback
650
- * @function
1430
+ * @function
651
1431
  */
652
- comments (callback ?: Function) {
1432
+ comments (callback) {
653
1433
  return this.hasManyBuilder({ name : 'comments' , model : Comment } , callback)
654
1434
  }
655
1435
  }
@@ -664,8 +1444,10 @@ const postsUsingFunction = await new Post().comments().findOne()
664
1444
  // postsUsingFunction?.comments => [{...}]
665
1445
  ```
666
1446
 
667
- ## Belongs To
1447
+ #### Belongs To
1448
+
668
1449
  A belongsto relationship is used to define relationships where a single model is the child to parent models.
1450
+
669
1451
  ```js
670
1452
  import { Model } from 'tspace-mysql'
671
1453
  import User from '../User'
@@ -681,11 +1463,11 @@ class Phone extends Model {
681
1463
  this.belognsTo({ name : 'user' , model : User })
682
1464
  }
683
1465
  /**
684
- *
1466
+ *
685
1467
  * @belongsToBuilder Get the user that owns the phone.. using function callback
686
- * @function
1468
+ * @function
687
1469
  */
688
- user (callback ?: Function) {
1470
+ user (callback) {
689
1471
  return this.belongsToBuilder({ name : 'user' , model : User }, callback)
690
1472
  }
691
1473
  }
@@ -700,8 +1482,10 @@ const phoneUsingFunction = await new Phone().user().findOne()
700
1482
  // phoneUsingFunction?.user => {...}
701
1483
  ```
702
1484
 
703
- ## Many To Many
1485
+ #### Many To Many
1486
+
704
1487
  Many-to-many relations are slightly more complicated than hasOne and hasMany relationships.
1488
+
705
1489
  ```js
706
1490
  import { Model } from 'tspace-mysql'
707
1491
  import Role from '../Role'
@@ -718,9 +1502,9 @@ class User extends Model {
718
1502
  }
719
1503
  /**
720
1504
  * @belongsToBuilder Get the user that owns the phone.. using function callback
721
- * @function
1505
+ * @function
722
1506
  */
723
- roles (callback ?: Function) {
1507
+ roles (callback) {
724
1508
  return this.belognsToManyBuilder({ model : Role } , callback)
725
1509
  }
726
1510
  }
@@ -735,9 +1519,11 @@ const userUsingFunction = await new User().roles().findOne()
735
1519
  // user?.roles => [{...}]
736
1520
  ```
737
1521
 
738
- ## Deeply Nested Relations
739
- Relationships can involve deep connections.
1522
+ #### Deeply Nested Relations
1523
+
1524
+ Relationships can involve deep connections.
740
1525
  Let's example of a deep relationship:
1526
+
741
1527
  ```js
742
1528
  import { Model } from 'tspace-mysql'
743
1529
 
@@ -767,7 +1553,7 @@ class Comment extends Model {
767
1553
  // Deeply nested relations
768
1554
  await new User()
769
1555
  .relations('posts')
770
- .relationQuery('posts', (query : Post) => {
1556
+ .relationQuery('posts', (query : Post) => {
771
1557
  return query.relations('comments','user')
772
1558
  .relationQuery('comments', (query : Comment) => {
773
1559
  return query.relations('user','post')
@@ -781,7 +1567,7 @@ await new User()
781
1567
  })
782
1568
  .findMany()
783
1569
 
784
- // Select some columns in nested relations
1570
+ // Select some columns in nested relations
785
1571
  await new User()
786
1572
  .relations('posts')
787
1573
  .relationQuery('posts', (query : Post) => query.select('id','user_id','title'))
@@ -811,9 +1597,12 @@ await new User()
811
1597
  .findMany()
812
1598
 
813
1599
  ```
814
- ## Relation Exists
815
- Relationships can return results only if they are not empty in relations, considering soft deletes.
1600
+
1601
+ #### Relation Exists
1602
+
1603
+ Relationships can return results only if they are not empty in relations, considering soft deletes.
816
1604
  Let's illustrate this with an example of an existence check in relations:
1605
+
817
1606
  ```js
818
1607
  +-------------+--------------+----------------------------+--------------------+
819
1608
  | table users | |
@@ -864,7 +1653,7 @@ await new User().relations('posts').findMany()
864
1653
  * id : 1,
865
1654
  * username: "tspace1",
866
1655
  * email : "tspace1@gmail.com",
867
- * posts : []
1656
+ * posts : []
868
1657
  * },
869
1658
  * {
870
1659
  * id : 2,
@@ -876,19 +1665,19 @@ await new User().relations('posts').findMany()
876
1665
  * user_id : 2,
877
1666
  * title : "posts 2"
878
1667
  * }
879
- * ]
1668
+ * ]
880
1669
  * },
881
1670
  * {
882
1671
  * id : 3,
883
1672
  * username: "tspace3",
884
1673
  * email : "tspace3@gmail.com",
885
- * posts : []
1674
+ * posts : []
886
1675
  * }
887
1676
  * ]
888
1677
  */
889
1678
 
890
1679
  await new User().relationsExists('posts').findMany()
891
- /*
1680
+ /*
892
1681
  * @returns [
893
1682
  * {
894
1683
  * id : 2,
@@ -900,7 +1689,7 @@ await new User().relationsExists('posts').findMany()
900
1689
  * user_id : 2,
901
1690
  * title : "posts 2"
902
1691
  * }
903
- * ]
1692
+ * ]
904
1693
  * }
905
1694
  * ]
906
1695
  * because posts id 1 and id 3 has been removed from database (using soft delete)
@@ -908,8 +1697,11 @@ await new User().relationsExists('posts').findMany()
908
1697
 
909
1698
 
910
1699
  ```
911
- ## Built in Relation Functions
1700
+
1701
+ ### Built in Relation Functions
1702
+
912
1703
  Certainly, let's illustrate the use of a built-in function in the results of relationships:
1704
+
913
1705
  ```js
914
1706
  import { Model } from 'tspace-mysql'
915
1707
 
@@ -949,38 +1741,38 @@ for (const post of posts) {
949
1741
 
950
1742
  ```
951
1743
 
952
- ## Decorator
1744
+ ### Decorator
1745
+
953
1746
  Decorators can be used in a Model.
954
1747
  Let's illustrate this with an example of a decorators:
1748
+
955
1749
  ```js
956
1750
 
957
- import {
958
- Blueprint, Model ,
959
- Table ,TableSingular, TablePlural,
1751
+ import {
1752
+ Blueprint, Model ,
1753
+ Table ,TableSingular, TablePlural,
960
1754
  UUID, SoftDelete, Timestamp,
961
1755
  Pattern, CamelCase , snakeCase ,
962
- Column, Validate, Observer,
963
- HasMany, HasOne, BelongsTo, BelongsToMany
964
-
1756
+ Column, Validate, Observer
965
1757
  } from 'tspace-mysql'
966
1758
  import { Post } from './Post'
967
1759
  import { PostUser } from './PostUser'
968
1760
 
969
1761
  class UserObserve {
970
1762
 
971
- public selected(results : any) {
1763
+ public selected(results) {
972
1764
  console.log({ results , selected : true })
973
1765
  }
974
-
975
- public created(results : unknown) {
1766
+
1767
+ public created(results) {
976
1768
  console.log({ results , created : true })
977
1769
  }
978
-
979
- public updated(results : unknown) {
1770
+
1771
+ public updated(results) {
980
1772
  console.log({ results , updated : true })
981
1773
  }
982
-
983
- public deleted(results : unknown) {
1774
+
1775
+ public deleted(results) {
984
1776
  console.log({ results , deleted : true })
985
1777
  }
986
1778
  }
@@ -1027,244 +1819,643 @@ class User extends Model {
1027
1819
 
1028
1820
  @Column(() => new Blueprint().timestamp().null())
1029
1821
  public deletedAt!: Date
1030
-
1031
- @HasMany({ model : Post })
1032
- public posts!: Post[]
1033
1822
 
1034
- @HasOne({ model : Post })
1035
- public post!: Post
1823
+ }
1824
+
1825
+ export { User }
1826
+ export default User
1827
+
1828
+ ```
1829
+
1830
+ ### Schema
1831
+
1832
+ The schema refers to the structure of the database as it pertains to the objects and classes in the model.
1833
+ using the following:
1834
+
1835
+ #### Schema Model
1836
+
1837
+ ```js
1838
+ import { Model, Blueprint } from "tspace-mysql";
1839
+ class User extends Model {
1840
+ constructor() {
1841
+ super();
1842
+ this.useCamelCase()
1843
+ this.useSchema({
1844
+ id: new Blueprint().int().notNull().primary().autoIncrement(),
1845
+ uuid: new Blueprint().varchar(50).null(),
1846
+ name: new Blueprint().varchar(191).notNull(),
1847
+ email: new Blueprint().varchar(191).notNull(),
1848
+ createdAt: new Blueprint().timestamp().null().bindColumn('created_at'), // you can fix the column name with 'bindColumn'
1849
+ updatedAt: new Blueprint().timestamp().null().bindColumn('updated_at'),
1850
+ deletedAt: new Blueprint().timestamp().null().bindColumn('deleted_at')
1851
+ })
1852
+ }
1853
+ }
1854
+
1855
+
1856
+ ```
1857
+
1858
+ #### Validation
1859
+
1860
+ Validate the schema of Model
1861
+ let's example a validator model:
1862
+
1863
+ ```js
1864
+ import { Model, Blueprint } from "tspace-mysql";
1865
+ class User extends Model {
1866
+ constructor() {
1867
+ super();
1868
+ this.useCamelCase();
1869
+ this.useSchema({
1870
+ id: new Blueprint().int().notNull().primary().autoIncrement(),
1871
+ uuid: new Blueprint().varchar(50).null(),
1872
+ name: new Blueprint().varchar(191).notNull(),
1873
+ email: new Blueprint().varchar(191).notNull(),
1874
+ createdAt: new Blueprint().timestamp().null(),
1875
+ updatedAt: new Blueprint().timestamp().null(),
1876
+ deletedAt: new Blueprint().timestamp().null(),
1877
+ });
1878
+
1879
+ // validate input when create or update reference to the schema in 'this.useSchema'
1880
+ this.useValidateSchema({
1881
+ id: Number,
1882
+ uuid: Number,
1883
+ name: {
1884
+ type: String,
1885
+ length: 191,
1886
+ require: true,
1887
+ json: true,
1888
+ },
1889
+ email: {
1890
+ type: String,
1891
+ require: true,
1892
+ length: 191,
1893
+ match: /^[a-zA-Z0-9._]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
1894
+ unique: true,
1895
+ fn: (email: string) => {
1896
+ return /^[a-zA-Z0-9._]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(email)
1897
+ }
1898
+ },
1899
+ createdAt: Date,
1900
+ updatedAt: Date,
1901
+ deletedAt: Date,
1902
+ });
1903
+ }
1904
+ }
1905
+ ```
1906
+
1907
+ #### Sync
1908
+
1909
+ Sync the schema with the "Models" setting in your directory.
1910
+ This process will verify and update table columns and foreign keys as needed.
1911
+ Ensure that the relationships are correctly established through the 'useSchema' method in your models.
1912
+ Let's examine a basic sync class:
1913
+
1914
+ ```js
1915
+ /**
1916
+ *
1917
+ * @Ex directory
1918
+ *
1919
+ * - node_modules
1920
+ * - src
1921
+ * - index.ts
1922
+ * - Models
1923
+ * - User.ts
1924
+ * - Post.ts
1925
+ */
1926
+
1927
+ // file User
1928
+ class User extends Model {
1929
+ constructor() {
1930
+ super();
1931
+ this.hasMany({ name: "posts", model: Post });
1932
+
1933
+ // if you need to initialize data when creating the table, you can use the following.
1934
+ this.beforeCreatingTable(async () => {
1935
+ return await new User()
1936
+ .create({
1937
+ ...columns,
1938
+ })
1939
+ .void()
1940
+ .save();
1941
+ });
1942
+
1943
+ this.useSchema({
1944
+ id: new Blueprint().int().notNull().primary().autoIncrement(),
1945
+ uuid: new Blueprint().varchar(50).null(),
1946
+ email: new Blueprint().int().notNull().unique(),
1947
+ name: new Blueprint().varchar(255).null(),
1948
+ created_at: new Blueprint().timestamp().null(),
1949
+ updated_at: new Blueprint().timestamp().null(),
1950
+ deleted_at: new Blueprint().timestamp().null(),
1951
+ });
1952
+ }
1953
+ }
1954
+
1955
+ // file Post
1956
+ import User from "./User";
1957
+ class Post extends Model {
1958
+ constructor() {
1959
+ super();
1960
+ this.hasMany({ name: "comments", model: Comment });
1961
+ this.belongsTo({ name: "user", model: User });
1962
+ this.useSchema({
1963
+ id: new Blueprint().int().notNull().primary().autoIncrement(),
1964
+ uuid: new Blueprint().varchar(50).null(),
1965
+ user_id: new Blueprint().int().notNull().foreign({
1966
+ references: "id",
1967
+ on: User,
1968
+ onDelete: "CASCADE",
1969
+ onUpdate: "CASCADE",
1970
+ }),
1971
+ title: new Blueprint().varchar(255).null(),
1972
+ created_at: new Blueprint().timestamp().null(),
1973
+ updated_at: new Blueprint().timestamp().null(),
1974
+ deleted_at: new Blueprint().timestamp().null(),
1975
+ });
1976
+ }
1977
+ }
1978
+
1979
+ await Schema.sync(`/src/Models`, {
1980
+ force: true,
1981
+ log: true,
1982
+ foreign: true,
1983
+ changed: true,
1984
+ });
1985
+
1986
+ // also you can sync by Model
1987
+ await new User().sync({ force: true, foreign: true, changed: true });
1988
+ ```
1989
+
1990
+ ### Type Safety
1991
+ Type safety in TypeScript refers to the ability of the language to detect and prevent type errors during compile-time.
1992
+ Type safety still works when you add additional types to your model, using the following:
1993
+
1994
+ ```js
1995
+ // in file User.ts
1996
+ import { Model , Blueprint , SchemaType } from 'tspace-mysql'
1997
+ import Phone from '../Phone'
1998
+
1999
+ const schemaUser = {
2000
+ id :new Blueprint().int().notNull().primary().autoIncrement(),
2001
+ uuid :new Blueprint().varchar(50).null(),
2002
+ email :new Blueprint().varchar(50).null(),
2003
+ name :new Blueprint().varchar(255).null(),
2004
+ username : new Blueprint().varchar(255).null(),
2005
+ password : new Blueprint().varchar(255).null(),
2006
+ createdAt :new Blueprint().timestamp().null(),
2007
+ updatedAt :new Blueprint().timestamp().null()
2008
+ }
2009
+
2010
+ type SchemaUserType = SchemaType<typeof schemaUser>
2011
+
2012
+ // you can re-assign type for schema
2013
+ /**
2014
+ type SchemaUserType = SchemaType<typeof schemaUser , {
2015
+ id : number,
2016
+ uuid : string,
2017
+ ...
2018
+ }>
2019
+
2020
+ */
2021
+
2022
+ class User extends Model<SchemaUserType> { // add this type for the Model
2023
+ constructor() {
2024
+ super()
2025
+ this.useSchema(schemaUser)
2026
+ this.hasOne({ model : Phone, name : 'phone' })
2027
+ this.hasMany({ model : Phone, name : 'phones' })
2028
+ }
2029
+ }
2030
+
2031
+ export { User , SchemaUserType }
2032
+ export default User
2033
+
2034
+ +--------------------------------------------------------------------------+
2035
+
2036
+ // in file Phone.ts
2037
+ import { Model , Blueprint , SchemaType } from 'tspace-mysql'
2038
+ import { User } from './User.ts'
2039
+ const schemaPhone = {
2040
+ id :new Blueprint().int().notNull().primary().autoIncrement(),
2041
+ uuid :new Blueprint().varchar(50).null(),
2042
+ userId : new Blueprint().int().notNull(),
2043
+ number :new Blueprint().varchar(50).notNull(),
2044
+ createdAt :new Blueprint().timestamp().null(),
2045
+ updatedAt :new Blueprint().timestamp().null()
2046
+ }
2047
+
2048
+ type SchemaPhoneType = SchemaType<typeof schemaPhone>
2049
+
2050
+ class Phone extends Model<SchemaPhoneType> {
2051
+ constructor() {
2052
+ super()
2053
+ this.useSchema(schemaPhone)
2054
+ this.useBelongsTo({ model : User, name : 'user'})
2055
+ }
2056
+ }
2057
+
2058
+ export { Phone , SchemaPhoneType }
2059
+ export default Phone
2060
+
2061
+ +--------------------------------------------------------------------------+
2062
+ ```
2063
+
2064
+ ### Safety Select
2065
+
2066
+ ```js
2067
+ import { User , schemaUserType } from './User.ts'
2068
+ import { Phone, schemaPhoneType } from './Phone.ts'
2069
+
2070
+ const users = await new User().select('id','username').findMany() ✅
2071
+ const users = await new User().select('idx','username').findMany() ❌
2072
+
2073
+ const users = await new User().except('id','username').findMany() ✅
2074
+ const users = await new User().except('idx','username').findMany() ❌
2075
+
2076
+ ```
2077
+
2078
+ ### Safety OrderBy
2079
+
2080
+ ```js
2081
+
2082
+ import { User , schemaUserType } from './User.ts'
2083
+ import { Phone, schemaPhoneType } from './Phone.ts'
2084
+
2085
+ const users = await new User().orderBy('id','DESC').findMany() ✅
2086
+ const users = await new User().orderBy('idx','DESC').findMany() ❌
2087
+
2088
+ const users = await new User().latest('id').findMany() ✅
2089
+ const users = await new User().latest('idx').findMany() ❌
2090
+
2091
+ const users = await new User().oldest('id').findMany() ✅
2092
+ const users = await new User().oldest('idx').findMany() ❌
2093
+
2094
+ ```
2095
+
2096
+ ### Safety GroupBy
2097
+
2098
+ ```js
2099
+ import { User , schemaUserType } from './User.ts'
2100
+ import { Phone, schemaPhoneType } from './Phone.ts'
2101
+
2102
+ const users = await new User().groupBy('id').findMany() ✅
2103
+ const users = await new User().groupBy('idx').findMany() ❌
2104
+
2105
+ ```
2106
+
2107
+ ### Safety Where
2108
+
2109
+ ```js
2110
+ import { User , schemaUserType } from './User.ts'
2111
+ import { Phone, schemaPhoneType } from './Phone.ts'
2112
+
2113
+ const users = await new User().where('id',1).findMany() ✅
2114
+ const users = await new User().where('idxx',1).findMany() ❌
2115
+
2116
+ const users = await new User().where('id',1).orWhere('id',5).findMany() ✅
2117
+ const users = await new User().where('id',1).orWhere('idxx',5).findMany() ❌
2118
+
2119
+ const users = await new User().whereIn('id',[1]).findMany() ✅
2120
+ const users = await new User().whereIn('idx',[1]).findMany() ❌
2121
+
2122
+ const users = await new User().whereNull('id').findMany() ✅
2123
+ const users = await new User().whereNull('idx').findMany() ❌
2124
+
2125
+ const users = await new User().whereNotNull('id').findMany()
2126
+ const users = await new User().whereNotNull('idx').findMany()
2127
+
2128
+ const users = await new User().whereBetween('id',[1,2]).findMany() ✅
2129
+ const users = await new User().whereBetween('idx',[1,2]).findMany() ❌
2130
+
2131
+ const users = await new User()
2132
+ .whereSubQuery(
2133
+ 'id',
2134
+ new User().select('id').toString()
2135
+ ).findMany() ✅
2136
+
2137
+ const users = await new User()
2138
+ .whereSubQuery(
2139
+ 'idx',
2140
+ new User().select('id').toString()
2141
+ ).findMany() ❌
2142
+
2143
+ ```
2144
+
2145
+ ### Safety Insert
2146
+
2147
+ ```js
2148
+ import { User , schemaUserType } from './User.ts'
2149
+ import { Phone, schemaPhoneType } from './Phone.ts'
2150
+
2151
+ const users = await new User().create({ id : 10 }).save() ✅
2152
+
2153
+ const users = await new User().create({ idx : 10 }).save() ❌
2154
+
2155
+ ```
2156
+
2157
+ ### Safety Update
2158
+
2159
+ ```js
2160
+ import { User , schemaUserType } from './User.ts'
2161
+ import { Phone, schemaPhoneType } from './Phone.ts'
2162
+
2163
+ const users = await new User().update({ id : 10 }).where('id',1).save() ✅
2164
+ const users = await new User().update({ id : 10 }).where('idx',1).save() ❌
2165
+ const users = await new User().update({ idx : 10 }).where('idx',1).save() ❌
2166
+
2167
+ ```
2168
+
2169
+ ### Safety Delete
2170
+
2171
+ ```js
2172
+ import { User , schemaUserType } from './User.ts'
2173
+ import { Phone, schemaPhoneType } from './Phone.ts'
2174
+
2175
+ const users = await new User().where('id',1).delete() ✅
2176
+ const users = await new User().where('idx',1).delete() ❌
2177
+
2178
+ ```
2179
+
2180
+ ### Safety Relationships
2181
+
2182
+ ```js
2183
+ import { User } from './User.ts'
2184
+ import { Phone } from './Phone.ts'
2185
+ // Case #1 : Relationship with 2 relations 'phone' and 'phones'
2186
+ const users = await new User()
2187
+ .relations('phone','phones')
2188
+ .findMany()
2189
+
2190
+ for(const user of users) {
2191
+ user.phone ❌
2192
+ user.phones ❌
2193
+ }
2194
+
2195
+ // You can also specify the type for the results
2196
+ // bad 👎👎👎
2197
+ const users = await new User()
2198
+ .relations('phone','phones')
2199
+ .findMany<{ phone : Record<string,any> , phones : any[]}>()
2200
+
2201
+ for(const user of users) {
2202
+ user.phone ✅
2203
+ user.phones ✅
2204
+ user.phone.id ✅
2205
+ user.phone.idx ✅💩💩💩
2206
+ user.phones.map(phone => phone.id) ✅
2207
+ user.phones.map(phone => phone.idx) ✅💩💩💩
2208
+ }
2209
+
2210
+ // good 👍👍👍
2211
+ const users = await new User()
2212
+ .relations('phone','phones')
2213
+ .findMany<{ phone : schemaPhoneType , phones : schemaPhoneType[] }>()
2214
+
2215
+ for(const user of users) {
2216
+ user.phone ✅
2217
+ user.phones ✅
2218
+ user.phone.id ✅
2219
+ user.phone.idx ❌
2220
+ user.phones.map(phone => phone.id) ✅
2221
+ user.phones.map(phone => phone.idx) ❌
2222
+ }
2223
+
2224
+ +--------------------------------------------------------------------------+
2225
+
2226
+ // Case #2 : There is a relationship between two entities, 'phone' and 'phones', both of which are related to the 'user' entity through nested relations
2227
+ const users = await new User()
2228
+ .relations('phone','phones')
2229
+ .relationQuery('phone' , (query : Phone) => query.relations('user'))
2230
+ .relationQuery('phones' , (query : Phone) => query.relations('user'))
2231
+ .findMany<{ phone : schemaPhoneType , phones : schemaPhoneType[] }>()
2232
+
2233
+ for(const user of users) {
2234
+ user.phone.user ❌
2235
+ user.phones.map(phone =>phone.user) ❌
2236
+ }
2237
+
2238
+ // You can also specify the type for the results
2239
+ // bad 👎👎👎
2240
+ const users = await new User()
2241
+ .relations('phone','phones')
2242
+ .relationQuery('phone' , (query : Phone) => query.relations('user'))
2243
+ .relationQuery('phones' , (query : Phone) => query.relations('user'))
2244
+ .findMany<{ phone : Record<string,any> , phones : Record<string,any>[] }>()
2245
+
2246
+ for(const user of users) {
2247
+ user.phone.user ✅💩💩💩
2248
+ user.phones.map(phone =>phone.user) ✅💩💩💩
2249
+ user.phone.user.idx ✅💩💩💩
2250
+ user.phones.map(phone =>phone.user.idx) ✅💩💩💩
2251
+ }
2252
+
2253
+ // good 👍👍👍
2254
+ const users = await new User()
2255
+ .relations('phone','phones')
2256
+ .relationQuery('phone' , (query : Phone) => query.relations('user'))
2257
+ .relationQuery('phones' , (query : Phone) => query.relations('user'))
2258
+ .findMany<{
2259
+ phone : Partial<SchemaPhoneType> & { user : SchemaUserType};
2260
+ phones : (Partial<SchemaPhoneType> & { user : SchemaUserType})[];
2261
+ }>()
2262
+
2263
+ for(const user of users) {
2264
+ user.phone.user ✅
2265
+ user.phone.user.id ✅
2266
+ user.phone.userx ❌
2267
+ user.phone.user.idx ❌
2268
+ user.phones.map(phone =>phone.user.id) ✅
2269
+ user.phones.map(phone =>phone.user.idx) ❌
2270
+ }
2271
+
2272
+ +--------------------------------------------------------------------------+
2273
+ // If you don't want to set types for every returning method such as 'findOne', 'findMany', and so on...
2274
+
2275
+ import { Model , Blueprint , SchemaType , RelationType } from 'tspace-mysql'
2276
+ import { Phone , SchemaPhoneType } from '../Phone'
2277
+
2278
+ const schemaUser = {
2279
+ id :new Blueprint().int().notNull().primary().autoIncrement(),
2280
+ uuid :new Blueprint().varchar(50).null(),
2281
+ email :new Blueprint().varchar(50).null(),
2282
+ name :new Blueprint().varchar(255).null(),
2283
+ username : new Blueprint().varchar(255).null(),
2284
+ password : new Blueprint().varchar(255).null(),
2285
+ createdAt :new Blueprint().timestamp().null(),
2286
+ updatedAt :new Blueprint().timestamp().null()
2287
+ }
2288
+
2289
+ type SchemaUserType = SchemaType<typeof schemaUser>
1036
2290
 
1037
- @BelongsToMany({ model : Post , modelPivot : PostUser })
1038
- public users!: PostUser[]
2291
+ type RelationUserType = RelationType<{
2292
+ phones : SchemaPhoneType[]
2293
+ phone : SchemaPhoneType
2294
+ }>
2295
+
2296
+ class User extends Model<SchemaUserType, RelationUserType> {
2297
+ constructor() {
2298
+ super()
2299
+ this.useSchema(schemaUser)
2300
+ this.hasOne({ model : Phone, name : 'phonex' }) ❌
2301
+ this.hasMany({ model : Phone, name : 'phonesx' }) ❌
2302
+ this.hasOne({ model : Phone, name : 'phone' }) ✅
2303
+ this.hasMany({ model : Phone, name : 'phones' }) ✅
2304
+ }
1039
2305
  }
1040
2306
 
1041
- export { User }
2307
+ export { User , SchemaUserType }
1042
2308
  export default User
1043
2309
 
1044
- ```
1045
- ## Schema Model
1046
- Define the schema of a Model
2310
+ +--------------------------------------------------------------------------+
1047
2311
 
1048
- ## Validation
1049
- Validate the schema of Model
1050
- let's example a validator model:
1051
- ```js
1052
- import { Model , Blueprint , Column } from 'tspace-mysql'
1053
- class User extends Model {
1054
- constructor(){
2312
+ // in file Phone.ts
2313
+ import { Model , Blueprint , SchemaType , RelationType} from 'tspace-mysql'
2314
+ import { User } from './User.ts'
2315
+ const schemaPhone = {
2316
+ id :new Blueprint().int().notNull().primary().autoIncrement(),
2317
+ uuid :new Blueprint().varchar(50).null(),
2318
+ userId : new Blueprint().int().notNull(),
2319
+ number :new Blueprint().varchar(50).notNull(),
2320
+ createdAt :new Blueprint().timestamp().null(),
2321
+ updatedAt :new Blueprint().timestamp().null()
2322
+ }
2323
+
2324
+ type SchemaPhoneType = SchemaType<typeof schemaPhone>
2325
+
2326
+ type RelationPhoneType = RelationType<{
2327
+ user : SchemaPhoneType[]
2328
+ }>
2329
+
2330
+ class Phone extends Model<SchemaPhoneType,RelationPhoneType> {
2331
+ constructor() {
1055
2332
  super()
1056
- this.useCamelCase()
1057
- this.useSchema ({
1058
- id : new Blueprint().int().notNull().primary().autoIncrement(),
1059
- uuid : new Blueprint().varchar(50).null(),
1060
- name : new Blueprint().varchar(191).notNull(),
1061
- email : new Blueprint().varchar(191).notNull(),
1062
- createdAt : new Blueprint().timestamp().null(),
1063
- updatedAt : new Blueprint().timestamp().null(),
1064
- deletedAt : new Blueprint().timestamp().null()
1065
- })
1066
- // validate input when create or update reference to the schema in 'this.useSchema'
1067
- this.useValidateSchema({
1068
- id : Number,
1069
- uuid : Number,
1070
- name : {
1071
- type : String,
1072
- length : 191,
1073
- require : true,
1074
- json : true
1075
- },
1076
- email : {
1077
- type : String,
1078
- require : true,
1079
- length : 191,
1080
- match: /^[a-zA-Z0-9._]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
1081
- unique : true,
1082
- fn : (email : string) => /^[a-zA-Z0-9._]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(email)
1083
- },
1084
- createdAt : Date,
1085
- updatedAt : Date,
1086
- deletedAt : Date
1087
- })
2333
+ this.useSchema(schemaPhone)
2334
+ this.useBelongsTo({ model : User, name : 'userx'}) ❌
2335
+ this.useBelongsTo({ model : User, name : 'user'})
1088
2336
  }
1089
2337
  }
1090
2338
 
2339
+ export { Phone , SchemaPhoneType }
2340
+ export default Phone
2341
+
2342
+ +--------------------------------------------------------------------------+
2343
+
2344
+ const users = await new User()
2345
+ .relations('phonex','phonesx') ❌
2346
+ .relationQuery('phonex' ❌ , (query : Phone) => query.relations('user')) ✅
2347
+ .relationQuery('phonesx' ❌ , (query : Phone) => query.relations('user')) ✅
2348
+ .findMany()
2349
+
2350
+ const users = await new User()
2351
+ .relations('phone','phones') ✅
2352
+ .relationQuery('phonex' ❌ , (query : Phone) => query.relations('user')) ✅
2353
+ .relationQuery('phonesx' ❌ , (query : Phone) => query.relations('user')) ✅
2354
+ .findMany()
2355
+
2356
+ const users = await new User()
2357
+ .relations('phone','phones')
2358
+ .relationQuery('phone' , (query : Phone) => query.relations('userx')) ❌
2359
+ .relationQuery('phones' , (query : Phone) => query.relations('userx')) ❌
2360
+ .findMany()
2361
+
2362
+ const users = await new User()
2363
+ .relations('phone','phones') ✅
2364
+ .relationQuery('phone' ✅ , (query : Phone) => query.relations('user')) ✅
2365
+ .relationQuery('phones'✅ , (query : Phone) => query.relations('user')) ✅
2366
+ .findMany()
2367
+
2368
+ for(const user of users) {
2369
+ user.phone.user ✅
2370
+ user.phone.user.id ✅
2371
+ user.phone.userx ❌
2372
+ user.phone.user.idx ❌
2373
+ user.phones.map(phone =>phone.user.id) ✅
2374
+ user.phones.map(phone =>phone.user.idx) ❌
2375
+ }
2376
+
1091
2377
  ```
1092
2378
 
1093
- ## Sync
1094
- Sync schema with Models setting in your directory,
1095
- Sync will check for create or update table columns and foreign keys,
1096
- Related by method 'useSchema' in your models.
1097
- Let's examine a basic model sync class:
2379
+ ## Blueprint
2380
+
2381
+ Schema table created by command make:migration, you may use the:
1098
2382
 
1099
2383
  ```js
2384
+ import { Schema , Blueprint , DB } from 'tspace-mysql'
2385
+ (async () => {
2386
+ await new Schema().table('users', {
2387
+ id : new Blueprint().int().notNull().primary().autoIncrement(),
2388
+ uuid : new Blueprint().varchar(120).null()
2389
+ name : new Blueprint().varchar(120).default('name'),
2390
+ email : new Blueprint().varchar(255).unique().notNull(),
2391
+ email_verify : new Blueprint().tinyInt(),
2392
+ password : new Blueprint().varchar(255),
2393
+ json : new Blueprint().json(),
2394
+ created_at : new Blueprint().null().timestamp(),
2395
+ updated_at : new Blueprint().null().timestamp(),
2396
+ deleted_at : new Blueprint().null().timestamp()
2397
+ })
2398
+ /**
2399
+ *
2400
+ * @Faker fake data 5 raw
2401
+ * await new DB().table('users').faker(5)
2402
+ */
2403
+ })()
2404
+
1100
2405
  /**
1101
- *
1102
- * @Ex directory
1103
- *
1104
- * - node_modules
1105
- * - src
1106
- * - index.ts
1107
- * - Models
1108
- * - User.ts
1109
- * - Post.ts
2406
+ * To add types of the schema to the database
2407
+ * @Types
2408
+ *
1110
2409
  */
2410
+ int (number)
2411
+ tinyInt (number)
2412
+ bigInt (number)
2413
+ double ()
2414
+ float ()
2415
+ json ()
2416
+ varchar (number)
2417
+ char (number)
2418
+ longText()
2419
+ mediumText()
2420
+ tinyText()
2421
+ text()
2422
+ enum(...n)
2423
+ date()
2424
+ dateTime()
2425
+ timestamp ()
1111
2426
 
1112
- // file User
1113
- class User extends Model {
1114
- constructor(){
1115
- super()
1116
- this.hasMany({ name : 'posts' , model : Post })
1117
- this.useSchema ({
1118
- id : new Blueprint().int().notNull().primary().autoIncrement(),
1119
- uuid : new Blueprint().varchar(50).null(),
1120
- email : new Blueprint().int().notNull().unique(),
1121
- name : new Blueprint().varchar(255).null(),
1122
- created_at : new Blueprint().timestamp().null(),
1123
- updated_at : new Blueprint().timestamp().null(),
1124
- deleted_at : new Blueprint().timestamp().null()
1125
- })
1126
- }
1127
- }
1128
-
1129
- // file Post
1130
- import User from './User'
1131
- class Post extends Model {
1132
- constructor(){
1133
- super()
1134
- this.hasMany({ name : 'comments' , model : Comment })
1135
- this.belongsTo({ name : 'user' , model : User })
1136
- this.useSchema ({
1137
- id : new Blueprint().int().notNull().primary().autoIncrement(),
1138
- uuid : new Blueprint().varchar(50).null(),
1139
- user_id : new Blueprint().int().notNull()
1140
- .foreign({ references : 'id' , on : User ,onDelete : 'CASCADE' , onUpdate : 'CASCADE' }),
1141
- title : new Blueprint().varchar(255).null(),
1142
- created_at : new Blueprint().timestamp().null(),
1143
- updated_at : new Blueprint().timestamp().null(),
1144
- deleted_at : new Blueprint().timestamp().null()
1145
- })
1146
- }
1147
- }
1148
- await Schema.sync(`src/Models` , { force : true })
1149
-
1150
- // also you can sync by Model
1151
- await new User().sync({ force : true })
1152
-
1153
- ```
1154
- ## Query Builder
1155
- Methods builder for queries
1156
- ```js
1157
- where(column , operator , value)
1158
- whereSensitive(column , operator , value)
1159
- whereId(id)
1160
- whereUser(userId)
1161
- whereEmail(value)
1162
- whereIn(column , [])
1163
- whereNotIn(column , [])
1164
- whereNull(column)
1165
- whereNotNull(column)
1166
- whereBetween (column , [value1 , value2])
1167
- whereQuery(callback)
1168
- whereJson(column, { targetKey, value , operator })
1169
- whereRaw(sql)
1170
- whereExists(sql)
1171
- whereSubQuery(colmn , rawSQL)
1172
- whereNotSubQuery(colmn , rawSQL)
1173
- orWhere(column , operator , value)
1174
- orWhereRaw(sql)
1175
- orWhereIn(column , [])
1176
- orWhereSubQuery(colmn , rawSQL)
1177
- when(contition , callback)
1178
- select(column1 ,column2 ,...N)
1179
- distinct()
1180
- selectRaw(column1 ,column2 ,...N)
1181
- except(column1 ,column2 ,...N)
1182
- only(column1 ,column2 ,...N)
1183
- hidden(column1 ,column2 ,...N)
1184
- join(primary key , table.foreign key)
1185
- rightJoin (primary key , table.foreign key)
1186
- leftJoin (primary key , table.foreign key)
1187
- limit (limit)
1188
- having (condition)
1189
- havingRaw (condition)
1190
- orderBy (column ,'ASC' || 'DSCE')
1191
- orderByRaw(column ,'ASC' || 'DSCE')
1192
- latest (column)
1193
- latestRaw (column)
1194
- oldest (column)
1195
- oldestRaw (column)
1196
- groupBy (column)
1197
- groupByRaw (column)
1198
- create(objects)
1199
- createMultiple(array objects)
1200
- update (objects)
1201
- updateMany (objects)
1202
- createNotExists(objects)
1203
- updateOrCreate (objects)
1204
- onlyTrashed()
1205
- connection(options)
1206
- backup({ database , connection })
1207
- backupToFile({ filePath, database , connection })
1208
- hook((result) => ...) // callback result to function
2427
+ /**
2428
+ * To add attributes of the schema to the database
2429
+ * @Attrbuites
2430
+ *
2431
+ */
2432
+ unsigned()
2433
+ unique()
2434
+ null()
2435
+ notNull()
2436
+ primary()
2437
+ default(string)
2438
+ defaultTimestamp()
2439
+ autoIncrement()
1209
2440
 
1210
- /**
1211
- * registry relation in your models
1212
- * @relationship
1213
- */
1214
- hasOne({ name, model, localKey, foreignKey, freezeTable , as })
1215
- hasMany({ name, model, localKey, foreignKey, freezeTable , as })
1216
- belongsTo({ name, model, localKey, foreignKey, freezeTable , as })
1217
- belongsToMany({ name, model, localKey, foreignKey, freezeTable, as, pivot })
1218
- /**
1219
- * @relation using registry in your models
1220
- */
1221
- relations(name1 , name2,...nameN)
1222
- /**
1223
- * @relation using registry in your models ignore soft delete
1224
- */
1225
- relationsAll(name1 , name2,...nameN)
1226
- /**
1227
- * @relation using registry in your models. if exists child data remove this data
1228
- */
1229
- relationsExists(name1 , name2,...nameN)
1230
- /**
1231
- * @relation call a name of relation in registry, callback query of data
2441
+ /**
2442
+ * To add a foreign key to the column
2443
+ * @ForeginKey
1232
2444
  */
1233
- relationQuery(name, (callback) )
1234
- /**
1235
- * @relation using registry in your models return only in trash (soft delete)
2445
+ foreign({ references : ${COLUMN} , on : ${TABLE-NAME OR MODEL CLASSES} })
2446
+
2447
+ /**
2448
+ *
2449
+ * Binding a column in the key of the schema forwards the key to the corresponding column in the database.
2450
+ * @BindColumn
1236
2451
  */
1237
- relationsTrashed(name1 , name2,...nameN)
2452
+ bindColumn('<REAL-NAME-COLUMN-IN-DB>')
1238
2453
 
1239
2454
 
1240
- /**
1241
- * queries statements
1242
- * @execute data of statements
1243
- */
1244
- findMany()
1245
- findOne()
1246
- find(id)
1247
- delelte()
1248
- delelteMany()
1249
- exists()
1250
- toString()
1251
- toJSON()
1252
- toArray(column)
1253
- count(column)
1254
- sum(column)
1255
- avg(column)
1256
- max(column)
1257
- min(column)
1258
- pagination({ limit , page })
1259
- save() /* for actions statements insert or update */
1260
- makeSelectStatement()
1261
- makeInsertStatement()
1262
- makeUpdateStatement()
1263
- makeDeleteStatement()
1264
- makeCreateStatement()
1265
2455
  ```
1266
2456
 
1267
2457
  ## Cli
2458
+
1268
2459
  To get started, let's install tspace-mysql
1269
2460
  you may use a basic cli :
1270
2461
 
@@ -1272,12 +2463,15 @@ you may use a basic cli :
1272
2463
  npm install tspace-mysql -g
1273
2464
 
1274
2465
  ```
2466
+
1275
2467
  ## Make Model
2468
+
1276
2469
  Command will be placed Model in the specific directory
2470
+
1277
2471
  ```js
1278
2472
 
1279
- /**
1280
- *
2473
+ /**
2474
+ *
1281
2475
  * @make Model
1282
2476
  * @options
1283
2477
  * @arg --m => created scheme table for migrate. short cut migration table like Make Migration
@@ -1285,12 +2479,12 @@ Command will be placed Model in the specific directory
1285
2479
  * @arg --type=js // extension js. default ts
1286
2480
  */
1287
2481
  tspace-mysql make:model <model name> --m --dir=.... --type=....
1288
-
1289
- tspace-mysql make:model User --m --dir=app/Models
2482
+
2483
+ tspace-mysql make:model User --m --dir=app/Models
1290
2484
  /**
1291
- *
2485
+ *
1292
2486
  * @Ex directory
1293
- */
2487
+ */
1294
2488
  - node_modules
1295
2489
  - app
1296
2490
  - Models
@@ -1298,10 +2492,12 @@ tspace-mysql make:model User --m --dir=app/Models
1298
2492
  ```
1299
2493
 
1300
2494
  ## Make Migration
2495
+
1301
2496
  Command will be placed Migration in the specific directory
2497
+
1302
2498
  ```js
1303
- /**
1304
- *
2499
+ /**
2500
+ *
1305
2501
  * @make Migration Table
1306
2502
  * @options
1307
2503
  * @arg --dir=directory => created scheme table in directory. default root directory
@@ -1311,9 +2507,9 @@ tspace-mysql make:migration <table name> --type=... --dir=....
1311
2507
 
1312
2508
  tspace-mysql make:migration users --dir=app/Models/Migrations
1313
2509
  /**
1314
- *
2510
+ *
1315
2511
  * @Ex directory
1316
- */
2512
+ */
1317
2513
  - node_modules
1318
2514
  - app
1319
2515
  - Models
@@ -1321,23 +2517,25 @@ tspace-mysql make:migration users --dir=app/Models/Migrations
1321
2517
  create_users_table.ts
1322
2518
  User.ts
1323
2519
  ```
2520
+
1324
2521
  ## Migrate
2522
+
1325
2523
  ```js
1326
- /**
1327
- *
2524
+ /**
2525
+ *
1328
2526
  * @run Migrate table
1329
2527
  * @options
1330
2528
  * @arg --dir=directory => find migrate in directory. default find in root folder
1331
2529
  * @arg --type=js // extension js default ts
1332
2530
  */
1333
2531
  tspace-mysql migrate <folder> --type=<type file js or ts> --dir=<directory for migrate>
1334
-
2532
+
1335
2533
  tspace-mysql migrate --dir=app/Models/Migrations --type=js
1336
2534
 
1337
2535
  /**
1338
- *
2536
+ *
1339
2537
  * @Ex directory
1340
- */
2538
+ */
1341
2539
  - node_modules
1342
2540
  - app
1343
2541
  - Models
@@ -1350,13 +2548,18 @@ tspace-mysql migrate --dir=app/Models/Migrations --type=js
1350
2548
  ```
1351
2549
 
1352
2550
  # Query
2551
+
1353
2552
  Command will be execute a query
2553
+
1354
2554
  ```js
1355
2555
  tspace-mysql query "SELECT * FROM users"
1356
2556
 
1357
2557
  ```
2558
+
1358
2559
  # Dump
2560
+
1359
2561
  Command will be dump database or table into file
2562
+
1360
2563
  ```js
1361
2564
  tspace-mysql dump:db "database" --values // backup with values in the tables
1362
2565
 
@@ -1365,73 +2568,25 @@ tspace-mysql dump:table "table" --values // backup with values in the table
1365
2568
  ```
1366
2569
 
1367
2570
  # Generate Models
2571
+
1368
2572
  Command will be generate models from table in database
2573
+
1369
2574
  ```js
1370
- tspace-mysql generate:models --dir=<folder for creating>
1371
- or
1372
- tspace-mysql gen:models --dir=<folder for creating> --env=development
1373
- or
2575
+ tspace-mysql generate:models --dir=<folder for creating>
2576
+
1374
2577
  tspace-mysql generate:models --dir=app/Models --env=development --decorators
1375
2578
 
1376
2579
  ```
1377
2580
 
1378
- ## Blueprint
1379
- Schema table created by command make:migration, you may use the:
2581
+ # Migration Models
2582
+
2583
+ Command will be generate migrations by schema in your models
2584
+
1380
2585
  ```js
1381
- import { Schema , Blueprint , DB } from 'tspace-mysql'
1382
- (async () => {
1383
- await new Schema().table('users', {
1384
- id : new Blueprint().int().notNull().primary().autoIncrement(),
1385
- uuid : new Blueprint().varchar(120).null()
1386
- name : new Blueprint().varchar(120).default('name'),
1387
- email : new Blueprint().varchar(255).unique().notNull(),
1388
- email_verify : new Blueprint().tinyInt(),
1389
- password : new Blueprint().varchar(255),
1390
- json : new Blueprint().json(),
1391
- created_at : new Blueprint().null().timestamp(),
1392
- updated_at : new Blueprint().null().timestamp()
1393
- })
1394
- /**
1395
- *
1396
- * @Faker fake data 5 raw
1397
- * await new DB().table('users').faker(5)
1398
- */
1399
- })()
2586
+ tspace-mysql migrations:models --dir=<path to migration> --models=<path to your models> --generate
2587
+ tspace-mysql migrations:models --dir=<path to migration> --push
1400
2588
 
1401
- /**
1402
- * add Type of schema in database
1403
- * @Types
1404
- *
1405
- */
1406
- int (number)
1407
- tinyInt (number)
1408
- bigInt (number)
1409
- double ()
1410
- float ()
1411
- json ()
1412
- varchar (number)
1413
- char (number)
1414
- longText()
1415
- mediumText()
1416
- tinyText()
1417
- text()
1418
- enum(...n)
1419
- date()
1420
- dateTime()
1421
- timestamp ()
2589
+ tspace-mysql migrations:models --models=src/app/models --dir=migrations --generate
2590
+ tspace-mysql migrations:models --dir=migrations --push
1422
2591
 
1423
- /**
1424
- * add Attrbuites of schema in database
1425
- * @Attrbuites
1426
- *
1427
- */
1428
- unsigned()
1429
- unique()
1430
- null()
1431
- notNull()
1432
- primary()
1433
- default(string)
1434
- defaultTimestamp()
1435
- autoIncrement()
1436
- foreign({ references : <column> , on : <table or model>}),
1437
- ```
2592
+ ```