tspace-mysql 1.8.8 → 1.8.9-beta.1

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 (126) hide show
  1. package/README.md +132 -3938
  2. package/build/cli/migrations/make-model.js +1 -1
  3. package/build/cli/migrations/make-model.js.map +1 -1
  4. package/build/lib/config/index.d.ts +31 -0
  5. package/build/lib/config/index.js +92 -0
  6. package/build/lib/config/index.js.map +1 -0
  7. package/build/lib/constants/index.d.ts +13 -1
  8. package/build/lib/constants/index.js +14 -2
  9. package/build/lib/constants/index.js.map +1 -1
  10. package/build/lib/core/Abstracts/AbstractBuilder.d.ts +30 -5
  11. package/build/lib/core/Abstracts/AbstractBuilder.js +16 -1
  12. package/build/lib/core/Abstracts/AbstractBuilder.js.map +1 -1
  13. package/build/lib/core/Abstracts/AbstractDB.d.ts +2 -2
  14. package/build/lib/core/Blueprint.d.ts +20 -14
  15. package/build/lib/core/Blueprint.js +53 -116
  16. package/build/lib/core/Blueprint.js.map +1 -1
  17. package/build/lib/core/Builder.d.ts +70 -68
  18. package/build/lib/core/Builder.js +319 -481
  19. package/build/lib/core/Builder.js.map +1 -1
  20. package/build/lib/core/Cache/index.d.ts +1 -1
  21. package/build/lib/core/Cache/index.js +6 -6
  22. package/build/lib/core/Cache/index.js.map +1 -1
  23. package/build/lib/core/Contracts/Audit.d.ts +27 -0
  24. package/build/lib/core/Contracts/Audit.js +185 -0
  25. package/build/lib/core/Contracts/Audit.js.map +1 -0
  26. package/build/lib/core/Contracts/Logger.d.ts +24 -0
  27. package/build/lib/core/Contracts/Logger.js +159 -0
  28. package/build/lib/core/Contracts/Logger.js.map +1 -0
  29. package/build/lib/core/DB.d.ts +34 -19
  30. package/build/lib/core/DB.js +155 -87
  31. package/build/lib/core/DB.js.map +1 -1
  32. package/build/lib/core/Decorator.d.ts +250 -48
  33. package/build/lib/core/Decorator.js +327 -165
  34. package/build/lib/core/Decorator.js.map +1 -1
  35. package/build/lib/core/Driver/index.d.ts +113 -0
  36. package/build/lib/core/Driver/index.js +137 -0
  37. package/build/lib/core/Driver/index.js.map +1 -0
  38. package/build/lib/core/Driver/mariadb/MariadbDriver.d.ts +17 -0
  39. package/build/lib/core/Driver/mariadb/MariadbDriver.js +137 -0
  40. package/build/lib/core/Driver/mariadb/MariadbDriver.js.map +1 -0
  41. package/build/lib/core/Driver/mariadb/MariadbQueryBuilder.d.ts +90 -0
  42. package/build/lib/core/Driver/mariadb/MariadbQueryBuilder.js +345 -0
  43. package/build/lib/core/Driver/mariadb/MariadbQueryBuilder.js.map +1 -0
  44. package/build/lib/core/Driver/mysql/MysqlDriver.d.ts +17 -0
  45. package/build/lib/core/Driver/mysql/MysqlDriver.js +190 -0
  46. package/build/lib/core/Driver/mysql/MysqlDriver.js.map +1 -0
  47. package/build/lib/core/Driver/mysql/MysqlQueryBuilder.d.ts +94 -0
  48. package/build/lib/core/Driver/mysql/MysqlQueryBuilder.js +362 -0
  49. package/build/lib/core/Driver/mysql/MysqlQueryBuilder.js.map +1 -0
  50. package/build/lib/core/Driver/postgres/PostgresDriver.d.ts +17 -0
  51. package/build/lib/core/Driver/postgres/PostgresDriver.js +167 -0
  52. package/build/lib/core/Driver/postgres/PostgresDriver.js.map +1 -0
  53. package/build/lib/core/Driver/postgres/PostgresQueryBuilder.d.ts +91 -0
  54. package/build/lib/core/Driver/postgres/PostgresQueryBuilder.js +455 -0
  55. package/build/lib/core/Driver/postgres/PostgresQueryBuilder.js.map +1 -0
  56. package/build/lib/core/Handlers/Relation.d.ts +1 -2
  57. package/build/lib/core/Handlers/Relation.js +64 -42
  58. package/build/lib/core/Handlers/Relation.js.map +1 -1
  59. package/build/lib/core/Handlers/State.d.ts +141 -127
  60. package/build/lib/core/Handlers/State.js +14 -13
  61. package/build/lib/core/Handlers/State.js.map +1 -1
  62. package/build/lib/core/Meta.d.ts +54 -31
  63. package/build/lib/core/Meta.js +78 -49
  64. package/build/lib/core/Meta.js.map +1 -1
  65. package/build/lib/core/Model.d.ts +80 -22
  66. package/build/lib/core/Model.js +369 -496
  67. package/build/lib/core/Model.js.map +1 -1
  68. package/build/lib/core/Nest/index.d.ts +75 -4
  69. package/build/lib/core/Nest/index.js +85 -5
  70. package/build/lib/core/Nest/index.js.map +1 -1
  71. package/build/lib/core/Operator.d.ts +27 -27
  72. package/build/lib/core/Operator.js +12 -10
  73. package/build/lib/core/Operator.js.map +1 -1
  74. package/build/lib/core/Pool.d.ts +9 -18
  75. package/build/lib/core/Pool.js +171 -279
  76. package/build/lib/core/Pool.js.map +1 -1
  77. package/build/lib/core/Repository.d.ts +19 -18
  78. package/build/lib/core/Repository.js +59 -67
  79. package/build/lib/core/Repository.js.map +1 -1
  80. package/build/lib/core/Schema.d.ts +3 -2
  81. package/build/lib/core/Schema.js +159 -92
  82. package/build/lib/core/Schema.js.map +1 -1
  83. package/build/lib/core/UtilityTypes.d.ts +3 -6
  84. package/build/lib/core/index.d.ts +1 -1
  85. package/build/lib/types/index.d.ts +154 -36
  86. package/build/lib/utils/index.d.ts +2 -2
  87. package/build/lib/utils/index.js +51 -13
  88. package/build/lib/utils/index.js.map +1 -1
  89. package/build/tests/00-Driver.test.d.ts +1 -0
  90. package/build/tests/00-Driver.test.js +62 -0
  91. package/build/tests/00-Driver.test.js.map +1 -0
  92. package/build/tests/01-Pool.test.js +2 -0
  93. package/build/tests/01-Pool.test.js.map +1 -1
  94. package/build/tests/02-DB.test.js.map +1 -1
  95. package/build/tests/03-Transaction.test.d.ts +1 -0
  96. package/build/tests/03-Transaction.test.js +167 -0
  97. package/build/tests/03-Transaction.test.js.map +1 -0
  98. package/build/tests/04-Model-default.test.d.ts +1 -0
  99. package/build/tests/04-Model-default.test.js +392 -0
  100. package/build/tests/04-Model-default.test.js.map +1 -0
  101. package/build/tests/04.1-Model-camelCase.test.d.ts +1 -0
  102. package/build/tests/04.1-Model-camelCase.test.js +392 -0
  103. package/build/tests/04.1-Model-camelCase.test.js.map +1 -0
  104. package/build/tests/04.2-Model-snake-case.test.d.ts +1 -0
  105. package/build/tests/04.2-Model-snake-case.test.js +392 -0
  106. package/build/tests/04.2-Model-snake-case.test.js.map +1 -0
  107. package/build/tests/05-Repository.test.d.ts +0 -0
  108. package/build/tests/05-Repository.test.js +2 -0
  109. package/build/tests/05-Repository.test.js.map +1 -0
  110. package/build/tests/06-Meta.test.js +35 -30
  111. package/build/tests/06-Meta.test.js.map +1 -1
  112. package/build/tests/07-View.test.d.ts +1 -0
  113. package/build/tests/07-View.test.js +72 -0
  114. package/build/tests/07-View.test.js.map +1 -0
  115. package/build/tests/08-Virtual-column.test.d.ts +1 -0
  116. package/build/tests/08-Virtual-column.test.js +131 -0
  117. package/build/tests/08-Virtual-column.test.js.map +1 -0
  118. package/build/tests/default-spec.js +33 -0
  119. package/build/tests/default-spec.js.map +1 -1
  120. package/build/tests/mock-data-spec.d.ts +0 -4
  121. package/build/tests/mock-data-spec.js +0 -4
  122. package/build/tests/mock-data-spec.js.map +1 -1
  123. package/build/tests/schema-spec.d.ts +0 -9
  124. package/build/tests/schema-spec.js +6 -37
  125. package/build/tests/schema-spec.js.map +1 -1
  126. package/package.json +26 -4
package/README.md CHANGED
@@ -1,14 +1,16 @@
1
- ## tspace-mysql
1
+ # tspace-mysql
2
2
 
3
3
  [![NPM version](https://img.shields.io/npm/v/tspace-mysql.svg)](https://www.npmjs.com)
4
4
  [![NPM downloads](https://img.shields.io/npm/dm/tspace-mysql.svg)](https://www.npmjs.com)
5
5
 
6
6
  tspace-mysql is an Object-Relational Mapping (ORM) tool designed to run seamlessly in Node.js and is fully compatible with TypeScript. It consistently supports the latest features in both TypeScript and JavaScript, providing additional functionalities to enhance your development experience.
7
7
 
8
+
8
9
  ## Feature
9
10
 
10
- | **Feature** | **Description** |
11
- |-------------------------------|----------------------------------------------------------------------------------------------------------|
11
+ | **Feature** | **Description** |
12
+ |--------------------------------|---------------------------------------------------------------------------------------------------------|
13
+ | **Supports Driver** | MySQL ✅ / MariaDB ✅ / Postgres / ✅ MSSQL ⏳ / SQLite3 ⏳ / Oracle ⏳ |
12
14
  | **Query Builder** | Create flexible queries like `SELECT`, `INSERT`, `UPDATE`, and `DELETE`. You can also use raw SQL. |
13
15
  | **Join Clauses** | Use `INNER JOIN`, `LEFT JOIN`, `RIGHT JOIN`, and `CROSS JOIN` to combine data from multiple tables. |
14
16
  | **Model** | Provides a way to interact with database records as objects in code. You can perform create, read, update, and delete (CRUD) operations. Models also support soft deletes and relationship methods. |
@@ -31,3948 +33,140 @@ tspace-mysql is an Object-Relational Mapping (ORM) tool designed to run seamless
31
33
  Install with [npm](https://www.npmjs.com/):
32
34
 
33
35
  ```sh
36
+ # Install tspace-mysql locally for your project
34
37
  npm install tspace-mysql --save
35
- npm install tspace-mysql -g
36
- ```
37
-
38
- ## Basic Usage
39
-
40
- - [Configuration](#configuration)
41
- - [SQL Like](#sql-Like)
42
- - [Query Builder](#query-builder)
43
- - [Table Name & Alias Name](#table-name--alias-name)
44
- - [Returning Results](#returning-results)
45
- - [Query Statement](#query-statements)
46
- - [Select Statements](#select-statements)
47
- - [Raw Expressions](#raw-expressions)
48
- - [Ordering, Grouping, Limit and Offset](#ordering-grouping-limit-and-offset)
49
- - [Ordering](#ordering)
50
- - [Grouping](#grouping)
51
- - [Limit and Offset](#limit-and-offset)
52
- - [Joins](#joins)
53
- - [Inner Join Clause](#inner-join-clause)
54
- - [Left Join, Right Join Clause](#left-join-right-join-clause)
55
- - [Cross Join Clause](#cross-join-clause)
56
- - [Basic Where Clauses](#basic-where-clauses)
57
- - [Where Clauses](#where-clauses)
58
- - [Or Where Clauses](#or-where-clauses)
59
- - [Where cases](#where-cases)
60
- - [Where Object Clauses](#where-object-clauses)
61
- - [JSON Where Clauses](#json-where-clauses)
62
- - [Additional Where Clauses](#additional-where-clauses)
63
- - [Logical Grouping](#logical-grouping)
64
- - [Advanced Where Clauses](#advanced-where-clauses)
65
- - [Where Exists Clauses](#where-exists-clauses)
66
- - [Subquery Where Clauses](#subquery-where-clauses)
67
- - [Conditional Where Clauses](#conditional-where-clauses)
68
- - [GetGroupBy](#getgroupby)
69
- - [Paginating](#paginating)
70
- - [Insert Statements](#insert-statements)
71
- - [Update Statements](#update-statements)
72
- - [Delete Statements](#delete-statements)
73
- - [Hook Statements](#hook-statements)
74
- - [Faker Statements](#faker-statements)
75
- - [Unset Statements](#unset-statements)
76
- - [Common Table Expressions](#common-table-expressions)
77
- - [Union](#union)
78
- - [More Methods](#more-methods)
79
- - [Database Transactions](#database-transactions)
80
- - [Connection](#connection)
81
- - [Backup](#backup)
82
- - [Injection](#injection)
83
- - [Generating Model Classes](#generating-model-classes)
84
- - [Model Conventions](#model-conventions)
85
- - [Basic Model Setup](#basic-model-setup)
86
- - [Table Name](#table-name)
87
- - [Pattern](#pattern)
88
- - [UUID](#uuid)
89
- - [Timestamp](#timestamp)
90
- - [Debug](#debug)
91
- - [Observer](#observer)
92
- - [Logger](#logger)
93
- - [Hooks](#hooks)
94
- - [Global Scope](#global-scope)
95
- - [Schema](#schema)
96
- - [Schema Model](#schema-model)
97
- - [Virtual Column](#virtual-column)
98
- - [Validation](#validation)
99
- - [Sync](#sync)
100
- - [SoftDelete](#softdelete)
101
- - [Joins Model](#joins-model)
102
- - [Inner Join Model Clause](#inner-join-model-clause)
103
- - [Left Join , Right Join Model Clause](#left-join-right-join-model-clause)
104
- - [Cross Join Model Clause](#cross-join-model-clause)
105
- - [Relationships](#relationships)
106
- - [One To One](#one-to-one)
107
- - [One To Many](#one-to-many)
108
- - [Belongs To](#belongs-to)
109
- - [Many To Many](#many-to-many)
110
- - [Relation](#relation)
111
- - [Deeply Nested Relations](#deeply-nested-relations)
112
- - [Relation Exists](#relation-exists)
113
- - [Relation Count](#relation-count)
114
- - [Relation Trashed](#relation-trashed)
115
- - [Built in Relation Functions](#built-in-relation-functions)
116
- - [Cache](#cache)
117
- - [Decorator](#decorator)
118
- - [Type Safety](#type-safety)
119
- - [Type Safety Select](#type-safety-select)
120
- - [Type Safety OrderBy](#type-safety-order-by)
121
- - [Type Safety GroupBy](#type-safety-group-by)
122
- - [Type Safety Where](#type-safety-where)
123
- - [Type Safety Insert](#type-safety-insert)
124
- - [Type Safety Update](#type-safety-update)
125
- - [Type Safety Delete](#type-safety-delete)
126
- - [Type Safety Relationships](#type-safety-relationships)
127
- - [Type Safety Results](#type-safety-results)
128
- - [Metadata](#metadata)
129
- - [Repository](#repository)
130
- - [Repository Select Statements](#repository-select-statements)
131
- - [Repository Insert Statements](#repository-insert-statements)
132
- - [Repository Update Statements](#repository-update-statements)
133
- - [Repository Delete Statements](#repository-delete-statements)
134
- - [Repository Transactions](#repository-transactions)
135
- - [Repository Relations](#repository-relations)
136
- - [View](#view)
137
- - [Stored Procedure](#stored-procedure)
138
- - [Blueprint](#blueprint)
139
- - [Cli](#cli)
140
- - [Make Model](#make-model)
141
- - [Make Migration](#make-migration)
142
- - [Migrate](#migrate)
143
- - [Query](#query)
144
- - [Dump](#dump)
145
- - [Generate Models](#generate-models)
146
- - [Migration Models](#migration-models)
147
- - [Migration DB](#migration-db)
148
-
149
- ## Configuration
150
-
151
- To establish a connection, the recommended method for creating your environment variables is by using a '.env' file. using the following:
152
-
153
- ```js
154
- DB_HOST = localhost;
155
- DB_PORT = 3306;
156
- DB_USERNAME = root;
157
- DB_PASSWORD = password;
158
- DB_DATABASE = database;
159
-
160
- /**
161
- * @default
162
- * DB_CONNECTION_LIMIT = 10
163
- * DB_QUEUE_LIMIT = 0
164
- * DB_TIMEOUT = 60000
165
- * DB_DATE_STRINGS = false
166
- */
167
- ```
168
-
169
- You can also create a file named 'db.tspace' to configure the connection. using the following:
170
-
171
- ```js
172
- source db {
173
- host = localhost
174
- port = 3306
175
- database = npm
176
- user = root
177
- password = database
178
- connectionLimit = 10
179
- dateStrings = true
180
- connectTimeout = 60000
181
- waitForConnections = true
182
- queueLimit = 0
183
- charset = utf8mb4
184
- }
185
-
186
- ```
187
-
188
- ## SQL Like
189
- ```js
190
- import { sql , OP } from 'tspace-mysql'
191
-
192
- // select
193
- await sql()
194
- .select('id','name')
195
- .from('users')
196
- .where({
197
- 'name' : 'tspace'
198
- 'id' : OP.in([1,2,3])
199
- })
200
- .limit(3)
201
- .orderBy('name')
202
-
203
- // insert
204
- await sql()
205
- .insert('users')
206
- .values({
207
- email : 'tspace@example.com'
208
- })
209
-
210
- // insert return data
211
- await sql()
212
- .insert('users')
213
- .values({
214
- email : 'tspace@example.com'
215
- })
216
- .returning({
217
- id : true,
218
- email : true,
219
- enum : true
220
- })
221
-
222
- // update
223
- await sql()
224
- .update('users')
225
- .where({
226
- id : 1
227
- })
228
- .set({
229
- email : 'tspace@example.com'
230
- })
231
-
232
- // update return data
233
- await sql()
234
- .update('users')
235
- .where({
236
- id : 1
237
- })
238
- .set({
239
- email : 'tspace@example.com'
240
- })
241
- .returning()
242
-
243
- //delete
244
- await sql()
245
- .delete('users')
246
- .where({
247
- id : 1
248
- })
249
-
250
-
251
- ```
252
-
253
- ## Query Builder
254
-
255
- How a database query builder works with a simple example using the following:
256
-
257
- ```js
258
- +-------------+--------------+----------------------------+
259
- | table users |
260
- +-------------+--------------+----------------------------+
261
- | id | username | email |
262
- |-------------|--------------|----------------------------|
263
- | 1 | tspace | tspace@gmail.com |
264
- | 2 | tspace2 | tspace2@gmail.com |
265
- +-------------+--------------+----------------------------+
266
-
267
-
268
- +-------------+--------------+----------------------------+
269
- | table posts |
270
- +-------------+--------------+----------------------------+
271
- | id | user_id | title |
272
- |-------------|--------------|----------------------------|
273
- | 1 | 1 | posts tspace |
274
- | 2 | 2 | posts tspace2 |
275
- +-------------+--------------+----------------------------+
276
-
277
- ```
278
-
279
- ### Table Name & Alias Name
280
-
281
- ```js
282
- import { DB } from 'tspace-mysql'
283
-
284
- await new DB().from('users').find(1)
285
- // SELECT * FROM `users` WHERE `users`.`id` = '1' LIMIT 1;
286
-
287
- await new DB().table('users').find(1)
288
- // SELECT * FROM `users` WHERE `users`.`id` = '1' LIMIT 1;
289
-
290
- await new DB().table('users').alias('u').find(1)
291
- // SELECT * FROM `users` AS `u` WHERE `u`.`id` = '1' LIMIT 1;
292
-
293
- await new DB().fromRaw('u',new DB('users').select('*').limit(1).toString()).find(1)
294
- // SELECT * FROM ( SELECT * FROM `users` LIMIT 1 ) AS `u` WHERE `u`.`id` = '1' LIMIT 1;
295
-
296
- await new DB().alias('u',new DB('users').select('*').limit(1).toString()).find(1)
297
- // SELECT * FROM ( SELECT * FROM `users` LIMIT 1 ) AS `u` WHERE `u`.`id` = '1' LIMIT 1;
298
-
299
- ```
300
-
301
- ### Returning Results
302
-
303
- ```js
304
- const user = await new DB("users").find(1); // Object or null
305
-
306
- const user = await new DB("users").findOne(); // Object or null
307
-
308
- const user = await new DB("users").first(); // Object or null
309
-
310
- const user = await new DB("users").firstOrError(message); // Object or error
311
-
312
- const users = await new DB("users").findMany(); // Array-object of users
313
-
314
- const users = await new DB("users").get(); // Array-object of users
315
-
316
- const users = await new DB("users").getGroupBy('name') // Map
317
-
318
- const users = await new DB("users").findGroupBy('name') // Map
319
-
320
- const users = await new DB("users").toArray(); // Array of users
321
-
322
- const users = await new DB("users").toJSON(); // JSON of users
323
-
324
- const user = await new DB("users").exists(); // Boolean true if user exists otherwise false
325
-
326
- const user = await new DB("users").count(); // Number of users counted
327
-
328
- const user = await new DB("users").avg(); // Number of users avg
329
-
330
- const user = await new DB("users").sum(); // Number of users sum
331
-
332
- const user = await new DB("users").max(); // Number of users max
333
-
334
- const user = await new DB("user").min(); // Number of users min
335
-
336
- const users = await new DB("users").toString(); // sql query string
337
-
338
- const users = await new DB("users").toSQL(); // sql query string
339
-
340
- const users = await new DB("users").toRawSQL(); // sql query string
341
-
342
- const users = await new DB("users").pagination(); // Object of pagination
343
-
344
- const users = await new DB("users").makeSelectStatement() // query string for select statement
345
-
346
- const users = await new DB("users").makeInsertStatement() // query string for insert statement
347
-
348
- const users = await new DB("users").makeUpdateStatement() // query string for update statement
349
-
350
- const users = await new DB("users").makeDeleteStatement() // query string for delete statement
351
-
352
- const users = await new DB("users").makeCreateTableStatement() // query string for create table statement
353
-
354
- ```
355
-
356
- ## Query Statements
357
-
358
- ```js
359
- const query = await DB.query(
360
- "SELECT * FROM users WHERE id = :id AND email IS :email AND name IN :username", {
361
- id : 1,
362
- email : null,
363
- username : ['name1','name2']
364
- })
365
- // SELECT * FROM users WHERE id = '1' AND email IS NULL AND username in ('name1','name2');
366
- ```
367
-
368
- ## Select Statements
369
-
370
- ```js
371
- const select = await new DB("users").select("id", "username").findOne();
372
- // SELECT `users`.`id`, `users`.`username` FROM `users` LIMIT 1;
373
-
374
- const selectRaw = await new DB("users").selectRaw("COUNT(id)").findMany();
375
- // SELECT COUNT(id) FROM `users`;
376
- // You can also use the DB.raw() function
377
- // const selectRaw = await new DB("users").selec(DB.raw("COUNT(id)")).findMany();
378
-
379
- const selectObject = await new DB("posts")
380
- .join("posts.user_id", "users.id")
381
- .select("posts.*")
382
- .selectObject(
383
- { id: "users.id", name: "users.name", email: "users.email" },
384
- "user"
385
- )
386
- .findOne();
387
-
388
- /**
389
- SELECT
390
- posts.*, JSON_OBJECT('id' , `users`.`id` , 'name' , `users`.`name` , 'email' , `users`.`email`) AS `user`
391
- FROM `posts`
392
- INNER JOIN `users` ON `posts`.`user_id` = `users`.`id` LIMIT 1;
393
- */
394
-
395
- const selectArray = await new DB("users")
396
- .select('id','name','email')
397
- .join("users.id", "posts.user_id")
398
- .select("posts.*")
399
- .selectArray(
400
- { id: "posts.id", user_id: "posts.user_id", title: "posts.title" },
401
- "posts"
402
- )
403
- .findOne();
404
- /**
405
- SELECT
406
- `users`.`id`, `users`.`name`, `users`.`email`,
407
- CASE WHEN COUNT(`posts`.`id`) = 0 THEN JSON_ARRAY()
408
- ELSE JSON_ARRAYAGG(JSON_OBJECT('id' , `posts`.`id` , 'user_id' , `posts`.`user_id` , 'email' , `posts`.`title`))
409
- END AS `posts`
410
- FROM `users`
411
- INNER JOIN `posts` ON `users`.`id` = `posts`.`user_id` WHERE `users`.`deletedAt` IS NULL GROUP BY `users`.`id` LIMIT 1;
412
- */
413
-
414
- await new DB("users").except("id").findOne();
415
- // SELECT `users`.`email`, `users`.`username` FROM `users` LIMIT 1;
416
-
417
- await new DB("users").distinct().select("id").findOne();
418
- // SELECT DISTINCT `users`.`id` FROM `users` LIMIT 1;
419
- ```
420
-
421
- ## Raw Expressions
422
-
423
- ```js
424
- const users = await new DB("users")
425
- .select(DB.raw("COUNT(`username`) as c"), "username")
426
- .groupBy("username")
427
- .having("c > 1")
428
- .findMany();
429
- // SELECT COUNT(`username`) as c, `users`.`username` FROM `users` GROUP BY `username` HAVING c > 1;
430
-
431
- const users = await new DB("users")
432
- .where(
433
- "id",
434
- DB.raw(new DB("users").select("id").where("id", "1").limit(1).toString())
435
- )
436
- .findMany();
437
- // SELECT * FROM `users` WHERE `users`.`id` = (SELECT `users`.`id` FROM `users` WHERE `users`.`id` = '1' LIMIT 1);
438
-
439
- const findFullName = await new User()
440
- .select('name',`${DB.raw('CONCAT(firstName," ",lastName) as fullName')}`)
441
- .whereRaw(`CONCAT(firstName," ",lastName) LIKE '%${search}%'`)
442
- .findOne()
443
- // SELECT `users`.`name`, CONCAT(firstName," ",lastName) as fullName FROM `users` WHERE CONCAT(firstName," ",lastName) LIKE '%search%' LIMIT 1;
444
-
445
- ```
446
-
447
- ## Ordering, Grouping, Limit and Offset
448
-
449
- ### Ordering
450
-
451
- ```js
452
- await new DB("users").orderBy("id", "asc").findOne();
453
- // SELECT * FROM `users` ORDER BY `id` ASC LIMIT 1;
454
-
455
- await new DB("users").orderBy("id", "desc").findOne();
456
- // SELECT * FROM `users` ORDER BY `id` DESC LIMIT 1;
457
-
458
- await new DB("users").oldest("id").findOne();
459
- // SELECT * FROM `users` ORDER BY `id` ASC LIMIT 1;
460
-
461
- await new DB("users").latest("id").findOne();
462
- // SELECT * FROM `users` ORDER BY `id` DESC LIMIT 1;
463
-
464
- await new DB("users").random().findMany();
465
- // SELECT * FROM `users` ORDER BY RAND();
466
- ```
467
-
468
- ### Grouping
469
-
470
- ```js
471
- await new DB("users").groupBy("id").findOne();
472
- // SELECT * FROM `users` GROUP BY `id` LIMIT 1;
473
-
474
- await new DB("users").groupBy("id", "username").findOne();
475
- // SELECT * FROM `users` GROUP BY `id`, `username` LIMIT 1;
476
-
477
- await new DB("users")
478
- .select(DB.raw("COUNT(username) as c"), "username")
479
- .groupBy("username")
480
- .having("c > 1")
481
- .findMany();
482
- // SELECT COUNT(username) as c, `users`.`username` FROM `users` GROUP BY `username` HAVING c > 1;
483
- ```
484
-
485
- ### Limit and Offset
486
-
487
- ```js
488
- await new DB("users").limit(5).findMany();
489
- // SELECT * FROM `users` LIMIT 5;
490
-
491
- await new DB("users").limit(-1).findMany();
492
- // SELECT * FROM `users` LIMIT 2147483647; // int-32 2**31 - 1
493
-
494
- await new DB("users").offset(1).findOne();
495
- // SELECT * FROM `users` LIMIT 1 OFFSET 1;
496
- ```
497
-
498
- ## Joins
499
-
500
- ### Inner Join Clause
501
-
502
- ```js
503
- await new DB("posts").join("posts.user_id", "users.id").findMany();
504
- // SELECT * FROM `posts` INNER JOIN `users` ON `posts`.`user_id` = `users`.`id`;
505
-
506
- await new DB("posts")
507
- .join((join) => {
508
- return join
509
- .on('posts.user_id','users.id')
510
- .on('users.id','post_user.user_id')
511
- .and('users.id','posts.user_id')
512
- })
513
- .findMany();
514
-
515
- // SELECT * FROM `posts`
516
- // INNER JOIN `users` ON `posts`.`user_id` = `users`.`id`
517
- // INNER JOIN `post_user` ON `users`.`id` = `post_user`.`user_id` AND `users`.`id` = `posts`.`user_id`;
518
- ```
519
-
520
- ### Left Join, Right Join Clause
521
-
522
- ```js
523
- await new DB("posts").leftJoin("posts.user_id", "users.id").findMany();
524
- // SELECT * FROM `posts` LEFT JOIN `users` ON `posts`.`user_id` = `users`.`id`;
525
-
526
- await new DB("posts").rightJoin("posts.user_id", "users.id").findMany();
527
- // SELECT * FROM `posts` RIGHT JOIN `users` ON `posts`.`user_id` = `users`.`id`;
528
- ```
529
-
530
- ### Cross Join Clause
531
-
532
- ```js
533
- await new DB("posts").crossJoin("posts.user_id", "users.id").findMany();
534
- // SELECT * FROM `posts` CROSS JOIN `users` ON `posts`.`user_id` = `users`.`id`;
535
- ```
536
-
537
- ## Basic Where Clauses
538
-
539
- ### Where Clauses
540
-
541
- ```js
542
- const users = await new DB("users").where("id", 1).findMany();
543
- // SELECT * FROM `users` WHERE `users`.`id` = '1'
544
-
545
- const users = await new DB("users")
546
- .where("id", 1)
547
- .where("username", "try to find")
548
- .findMany();
549
- // SELECT * FROM `users` WHERE `users`.`id` = '1' and `users`.`username` = 'try to find'
550
-
551
- const users = await new DB("users").where("id", ">", 1).findMany();
552
- // SELECT * FROM `users` WHERE `users`.`id` > '1';
553
-
554
- const users = await new DB("users").where("id", "<>", 1).findMany();
555
- // SELECT * FROM `users` WHERE `users`.`id` <> '1';
556
- ```
557
-
558
- ### Or Where Clauses
559
-
560
- ```js
561
- const users = await new DB("users").where("id", 1).orWhere("id", 2).findMany();
562
- // SELECT * FROM `users` WHERE `users`.`id` = 1 OR `users`.`id` = 2
563
-
564
- const users = await new DB("users")
565
- .where("id", 1)
566
- .whereQuery((query) => {
567
- return query
568
- .where("id", "<>", 2)
569
- .orWhere("username", "try to find")
570
- .orWhere("email", "find@example.com");
571
- })
572
- .findMany();
573
- // SELECT * FROM `users` WHERE `users`.`id` = 1
574
- // AND
575
- // ( `users`.`id` <> 2 OR `users`.`username` = 'try to find' OR `users`.`email` = 'find@example.com');
576
-
577
- ```
578
-
579
- ### Where cases
580
-
581
- ```js
582
- const payments = await new DB('payments')
583
- .whereCases([
584
- {
585
- when : "payment_type = 'credit'",
586
- then : "status = 'approved'"
587
- },
588
- {
589
- when : "payment_type = 'paypal'",
590
- then : "status = 'pending'"
591
- }
592
- ],"FALSE")
593
- .findMany()
594
-
595
- // SELECT * FROM `payments`
596
- // WHERE (
597
- // CASE
598
- // WHEN payment_type = 'credit' THEN status = 'approved'
599
- // WHEN payment_type = 'paypal' THEN status = 'pending'
600
- // ELSE FALSE
601
- // END
602
- // );
603
-
604
- const tasks = await new DB("tasks")
605
- .whereCases([
606
- {
607
- when : "priority = 'high'",
608
- then : "DATEDIFF(due_date, NOW()) <= 3"
609
- },
610
- ],"DATEDIFF(due_date, NOW()) <= 7")
611
- .findMany()
612
-
613
- // SELECT * FROM `tasks`
614
- // WHERE (
615
- // CASE
616
- // WHEN priority = 'high' THEN DATEDIFF(due_date, NOW()) <= 3
617
- // ELSE DATEDIFF(due_date, NOW()) <= 7
618
- // END
619
- // );
620
-
621
- ```
622
-
623
- ### Where Object Clauses
624
-
625
- ```js
626
- import { OP } from 'tspace-mysql'
627
-
628
- const whereObject = await new DB("users")
629
- .whereObject({
630
- id : OP.notEq(1),
631
- username : OP.in(['user1','user2']),
632
- name : OP.like('%value%')
633
- })
634
- .findMany();
635
-
636
- // SELECT * FROM `users` WHERE `users`.`id` <> '1' AND `users`.`username` = 'user1' AND `users`.`name` LIKE '%value%';
637
-
638
- ```
639
-
640
- ### JSON Where Clauses
641
-
642
- ```js
643
- const whereJSON = await new DB("users")
644
- .whereJSON("json", { key: "id", value: "1234" })
645
- .findMany();
646
- // SELECT * FROM `users` WHERE `users`.`json`->>'$.id' = '1234';
647
- ```
648
-
649
- ### Additional Where Clauses
650
-
651
- ```js
652
- const users = await new DB("users").whereIn("id", [1, 2]).findMany();
653
- // SELECT * FROM `users` WHERE `users`.`id` IN ('1','2');
654
-
655
- const users = await new DB("users").whereNotIn("id", [1, 2]).findMany();
656
- // SELECT * FROM `users` WHERE `users`.`id` NOT IN ('1','2');
657
-
658
- const users = await new DB("users").whereBetween("id", [1, 2]).findMany();
659
- // SELECT * FROM `users` WHERE `users`.`id` BETWEEN '1' AND '2';
660
-
661
- const users = await new DB("users").whereNotBetween("id", [1, 2]).findMany();
662
- // SELECT * FROM `users` WHERE `users`.`id` NOT BETWEEN '1' AND '2';
663
-
664
- const users = await new DB("users").whereNull("username").findMany();
665
- // SELECT * FROM `users` WHERE `users`.`username` IS NULL;
666
-
667
- const users = await new DB("users").whereNotNull("username").findMany();
668
- // SELECT * FROM `users` WHERE `users`.`username` IS NOT NULL;
669
- ```
670
-
671
- ### Logical Grouping
672
-
673
- ```js
674
- const users = await new DB("users")
675
- .whereQuery((query) => query.where("id", 1).where("username", "values"))
676
- .whereIn("id", [1, 2])
677
- .findOne();
678
- // SELECT * FROM `users` WHERE ( `users`.`id` = '1' AND `users`.`username` = 'values') AND `users`.`id` IN ('1','2'') LIMIT 1;
679
-
680
- const users = await new DB("users")
681
- .where("id", 1)
682
- .whereQuery((query) => {
683
- return query
684
- .where("id", "<>", 2)
685
- .where("username", "try to find")
686
- .where("email", "find@example.com");
687
- })
688
- .findMany();
689
- // SELECT * FROM `users` WHERE `users`.`id` = '1'
690
- // AND
691
- // ( `users`.`id` <> '2' AND `users`.`username` = 'try to find' AND `users`.`email` = 'find@example.com');
692
-
693
- const users = await new DB("users")
694
- .whereAny(["name", "username", "email"], "like", `%v%`)
695
- .findMany();
696
- // SELECT * FROM `users` WHERE ( `users`.`name` LIKE '%v%' OR `users`.`username` LIKE '%v%' OR `users`.`email` LIKE '%v%');
697
-
698
- const users = await new DB("users")
699
- .whereAll(["name", "username", "email"], "like", `%v%`)
700
- .findMany();
701
- // SELECT * FROM `users` WHERE ( `users`.`name` LIKE '%v%' AND `users`.`username` LIKE '%v%' AND `users`.`email` LIKE '%v%');
702
- ```
703
-
704
- ## Advanced Where Clauses
705
-
706
- ### Where Exists Clauses
707
-
708
- ```js
709
- const users = await new DB("users")
710
- .whereExists(new DB("users").select("id").where("id", 1).toString())
711
- .findMany();
712
- // SELECT * FROM `users` WHERE EXISTS (SELECT `id` FROM `users` WHERE id = 1);
713
-
714
- const users = await new DB("users")
715
- .wherNoteExists(new DB("users").select("id").where("id", 1).toString())
716
- .findMany();
717
- // SELECT * FROM `users` WHERE NOT EXISTS (SELECT `id` FROM `users` WHERE id = 1);
718
- ```
719
-
720
- ### Subquery Where Clauses
721
-
722
- ```js
723
- const users = await new DB("users")
724
- .whereSubQuery("id", "SELECT id FROM users")
725
- .findMany();
726
- // SELECT * FROM `users` WHERE `users`.`id` IN (SELECT id FROM users);
727
-
728
- const users = await new DB("users")
729
- .whereSubQuery("id", new DB("users").select("id").toString())
730
- .findMany();
731
- // SELECT * FROM `users` WHERE `users`.`id` IN (SELECT id FROM users);
732
-
733
- const users = await new DB("users")
734
- .whereSubQuery(
735
- "id",
736
- new DB("users")
737
- .select("id")
738
- .whereSubQuery("id", new DB("posts").select("user_id").toString())
739
- .toString()
740
- )
741
- .findMany();
742
- /*
743
- SELECT * FROM `users`
744
- WHERE `users`.`id`
745
- IN (
746
- SELECT `users`.`id` FROM `users`
747
- WHERE `users`.`id`
748
- IN (
749
- SELECT `posts`.`user_id` FROM `posts`
750
- )
751
- );
752
- */
753
- ```
754
-
755
- ### Conditional Where Clauses
756
-
757
- ```js
758
- const users = await new DB("users")
759
- .where("id", 1)
760
- .when(true, (query) => query.where("username", "when is actived"))
761
- .findMany();
762
- // SELECT * FROM `users` WHERE `users`.`id` = '1' AND `users`.`username` = 'when is actived';
763
-
764
- const users = await new DB("users")
765
- .where("id", 1)
766
- .when(false, (query) => query.where("username", "when is actived"))
767
- .findMany();
768
- // SELECT * FROM `users` WHERE `users`.`id` = '1';
769
- ```
770
-
771
- ## GetGroupBy
772
-
773
- ```js
774
- const data = await new DB("posts").getGroupBy('user_id')
775
-
776
- // return new Map()
777
- // find posts by user id
778
- const userHasPosts = data.get(1)
779
-
780
- console.log(userHasPosts)
781
-
782
- ```
783
-
784
- ## Paginating
785
-
786
- ```js
787
- const users = await new DB("users").paginate();
788
- // SELECT * FROM `users` LIMIT 15 OFFSET 0;
789
- // SELECT COUNT(*) AS total FROM `users`;
790
-
791
- const pageTwoUsers = await new DB("users").paginate({ page: 2, limit: 5 });
792
-
793
- /*
794
- SELECT * FROM `users` LIMIT 5 OFFSET 5;
795
- SELECT COUNT(*) AS total FROM `users`;
796
-
797
- the results are returned
798
- {
799
- meta: {
800
- total: n,
801
- limit: 5,
802
- total_page: 5,
803
- current_page: 2,
804
- last_page: n,
805
- next_page: 3,
806
- prev_page: 1
807
- },
808
- data: [...your data here]
809
- }
810
-
811
- */
812
- ```
813
-
814
- ## Insert Statements
815
-
816
- ```js
817
- const user = await new DB("users")
818
- .create({
819
- name: "tspace3",
820
- email: "tspace3@gmail.com",
821
- })
822
- .save();
823
- /**
824
- INSERT INTO `users`
825
- (`users`.`name`,`users`.`email`)
826
- VALUES
827
- ('tspace3','tspace3@gmail.com');
828
-
829
- -- then return the result inserted --
830
- SELECT * FROM `users` WHERE `users`.`id` = ${INSERT ID};
831
- */
832
-
833
- const users = await new DB("users")
834
- .createMultiple([
835
- {
836
- name: "tspace4",
837
- email: "tspace4@gmail.com",
838
- },
839
- {
840
- name: "tspace5",
841
- email: "tspace5@gmail.com",
842
- },
843
- {
844
- name: "tspace6",
845
- email: "tspace6@gmail.com",
846
- },
847
- ])
848
- .save();
849
-
850
- /**
851
- INSERT INTO `users`
852
- (`users`.`name`,`users`.`email`)
853
- VALUES
854
- ('tspace4','tspace4@gmail.com'),
855
- ('tspace5','tspace5@gmail.com'),
856
- ('tspace6','tspace6@gmail.com');
857
- */
858
-
859
- const users = await new DB("users")
860
- .where("name", "tspace4")
861
- .where("email", "tspace4@gmail.com")
862
- .createNotExists({
863
- name: "tspace4",
864
- email: "tspace4@gmail.com",
865
- })
866
- .save();
867
- /*
868
- -- if exists return null, if not exists created new data --
869
- SELECT EXISTS(
870
- SELECT 1 FROM `users`
871
- WHERE `users`.`name` = 'tspace4'
872
- AND `users`.`email` = 'tspace4@gmail.com'
873
- LIMIT 1
874
- ) AS 'exists';
875
-
876
- INSERT INTO `users` (`users`.`name`,`users`.`email`) VALUES ('tspace4','tspace4@gmail.com');
877
- */
878
38
 
879
- const users = await new DB("users")
880
- .where("name", "tspace4")
881
- .where("email", "tspace4@gmail.com")
882
- .createOrSelect({
883
- name: "tspace4",
884
- email: "tspace4@gmail.com",
885
- })
886
- .save();
887
- /**
888
- -- if has exists return data, if not exists created new data --
889
- SELECT EXISTS(
890
- SELECT 1 FROM `users`
891
- WHERE `users`.`name` = 'tspace4'
892
- AND `users`.`email` = 'tspace4@gmail.com'
893
- LIMIT 1
894
- ) AS 'exists';
39
+ # Install tspace-mysql globally (optional)
40
+ npm install -g tspace-mysql
895
41
 
896
- INSERT INTO `users` (`users`.`name`,`users`.`email`) VALUES ('tspace4','tspace4@gmail.com');
42
+ # Install database drivers if needed:
43
+ # For MariaDB
44
+ npm install mariadb --save
897
45
 
898
- SELECT * FROM `users` WHERE `users`.`id` = '4';
899
- */
900
- ```
901
-
902
- ## Update Statements
903
-
904
- ```js
905
- const user = await new DB("users")
906
- .where("id", 1)
907
- .update({
908
- name: "tspace1**",
909
- email: "tspace1@gmail.com",
910
- })
911
- .save();
912
- /**
913
-
914
- UPDATE `users` SET
915
- `users`.`name` = 'tspace1',
916
- `users`.`email` = 'tspace1@gmail.com'
917
- WHERE `users`.`id` = '1' LIMIT 1;
918
-
919
- */
920
-
921
- const user = await new DB("users")
922
- .where("id", 1)
923
- .updateMany({
924
- name: "tspace1",
925
- email: "tspace1@gmail.com",
926
- })
927
- .save();
928
- /**
929
- UPDATE `users` SET
930
- `users`.`name` = 'tspace1',
931
- `users`.`email` = 'tspace1@gmail.com'
932
- WHERE `users`.`id` = '1';
933
- */
934
-
935
- const user = await new DB("users")
936
- .where("id", 1)
937
- .update(
938
- {
939
- name: "tspace1",
940
- email: "tspace1@gmail.com",
941
- },
942
- ["name"]
943
- )
944
- .save();
945
- /**
946
- UPDATE `users` SET
947
- `name` =
948
- CASE WHEN (`name` = '' OR `name` IS NULL)
949
- THEN 'tspace1' ELSE `name`
950
- END,
951
- `email` =
952
- 'tspace1@gmail.com'
953
- WHERE `users`.`id` = '1' LIMIT 1;
954
- */
955
-
956
- const user = await new DB("users")
957
- .updateMultiple([
958
- {
959
- when: {
960
- id: 1,
961
- name: "name1",
962
- },
963
- columns: {
964
- name: "update row1",
965
- email: "row1@example.com",
966
- },
967
- },
968
- {
969
- when: {
970
- id: 2,
971
- },
972
- columns: {
973
- name: "update row2",
974
- email: "row2@example.com",
975
- },
976
- },
977
- ])
978
- .save();
979
-
980
- /**
981
- UPDATE `users` SET
982
- `users`.`name` = (
983
- CASE WHEN `users`.`id` = '1'
984
- AND `users`.`name` = 'name1'
985
- THEN 'update row1'
986
- WHEN `users`.`id` = '2'
987
- THEN 'update row2'
988
- ELSE `users`.`name`
989
- END
990
- ),
991
- `users`.`email` = (
992
- CASE WHEN `users`.`id` = '1'
993
- AND `users`.`name` = 'name1'
994
- THEN 'row1@example.com'
995
- WHEN `users`.`id` = '2'
996
- THEN 'row2@example.com'
997
- ELSE `users`.`email`
998
- END
999
- )
1000
- WHERE `users`.`id` IN ('1','2') LIMIT 2;
1001
-
1002
- */
1003
-
1004
- const user = await new DB("users")
1005
- .where("id", 1)
1006
- .updateOrCreate({
1007
- name: "tspace1**",
1008
- email: "tspace1@gmail.com",
1009
- })
1010
- .save();
1011
- // if has exists return update, if not exists created new data
1012
- // UPDATE `users` SET `name` = 'tspace1**',`email` = 'tspace1@gmail.com' WHERE `users`.`id` = '1' LIMIT 1;
1013
- // INSERT INTO `users` (`name`,`email`) VALUES ('tspace1**','tspace1@gmail.com');
1014
- ```
1015
-
1016
- ## Delete Statements
1017
-
1018
- ```js
1019
- const deleted = await new DB("users").where("id", 1).delete();
1020
- // DELETE FROM `users` WHERE `users`.`id` = '1' LIMIT 1;
1021
-
1022
- const deleted = await new DB("users").where("id", 1).deleteMany();
1023
- // DELETE FROM `users` WHERE `users`.`id` = '1' ;
1024
- ```
1025
-
1026
- ## Hook Statements
1027
-
1028
- ```js
1029
- const hookImage = async (results) => {
1030
- for(const result of results) {
1031
- result.image = await ...getImage()
1032
- }
1033
- };
1034
- const user = await new DB("users").where("id", 1).hook(hookResult).findMany();
1035
- ```
1036
-
1037
- ## Faker Statements
1038
-
1039
- ```js
1040
- await new DB("users").faker(2);
1041
- /**
1042
- INSERT INTO `users`
1043
- (`users`.`username`,`users`.`email`)
1044
- VALUES
1045
- ('ivsvtagyta86n571z9d81maz','fxcwkubccdi5ewos521uqexy'),
1046
- ('rnr4esoki7fgekmdtarqewt','gv0mzb1m3rlbinsdyb6')
1047
- */
1048
-
1049
- // custom faker
1050
- await new DB("users").faker(5, (row, index) => {
1051
- return {
1052
- username: `username-${index + 1}`,
1053
- email: `email-${index + 1}`,
1054
- };
1055
- });
1056
-
1057
- /**
1058
-
1059
- INSERT INTO `users`
1060
- (`users`.`username`,`users`.`email`)
1061
- VALUES
1062
- ('username-1','email-1'),
1063
- ('username-2','email-2'),
1064
- ('username-3','email-3'),
1065
- ('username-4','email-4'),
1066
- ('username-5','email-5');
1067
-
1068
- */
1069
-
1070
- // fast to create
1071
- await new DB("users").faker(40_000);
1072
- ```
1073
-
1074
- ## Unset Statements
1075
-
1076
- ```js
1077
-
1078
- const userInstance = new User().where('email','test@gmail.com')
1079
-
1080
- const exits = await userInstance.exists()
1081
- // SELECT EXISTS (SELECT 1 FROM `users` WHERE `users`.`email` = 'test@gmail.com' LIMIT 1) AS `aggregate`;
1082
-
1083
- const user = await userInstance.orderBy('id').findOne()
1084
- // SELECT * FROM `users` WHERE `users`.`email` = 'test@gmail.com' ORDER BY `users`.`id` DESC LIMIT 1;
1085
-
1086
- const users = await userInstance.select('id').unset({ limit : true }).findMany()
1087
- // SELECT `users`.`id` FROM `users` WHERE `users`.`email` = 'test@gmail.com' ORDER BY `users`.`id` DESC;
1088
-
1089
- const usersUnsetWhereStatement = await userInstance.unset({ select : true, where : true , orderBy : true }).findMany()
1090
- // SELECT * FROM `users` WHERE `users`.`deletedAt` IS NULL;
46
+ # For PostgreSQL
47
+ npm install pg --save
1091
48
 
49
+ # MySQL2 driver is installed by default with tspace-mysql
1092
50
  ```
1093
51
 
1094
- ## Common Table Expressions
52
+ ## Documentation
1095
53
 
1096
- ```js
54
+ See the [`docs`](https://thanathip41.github.io/tspace-mysql) directory for full documentation.
1097
55
 
1098
- const user = await new User()
1099
- .CTEs('z', (query) => {
1100
- return query
1101
- .from('posts')
1102
- })
1103
- .CTEs('x', (query) => {
1104
- return query
1105
- .from('post_user')
1106
- })
1107
- .select('users.*','x.*','z.*')
1108
- .join('users.id','x.user_id')
1109
- .join('users.id','z.user_id')
1110
- .findOne()
1111
-
1112
- // WITH z AS (SELECT posts.* FROM `posts`),
1113
- // x AS (SELECT * FROM `post_user`)
1114
- // SELECT users.*, z.*, x.* FROM `users` INNER JOIN `x` ON `users`.`id` = `x`.`user_id` INNER JOIN `z` ON `users`.`id` = `z`.`user_id` WHERE `users`.`deleted_at` IS NULL LIMIT 1;
1115
-
1116
- ```
1117
-
1118
- ### Union
1119
-
1120
- ```js
1121
- const users = await new DB('users')
1122
- .where('id',1)
1123
- .union(new DB('users').whereIn('id',[2]))
1124
- .union(new DB('users').whereIn('id',[3,4]))
1125
- .findMany()
1126
-
1127
- // (SELECT * FROM `users` WHERE `users`.`id` = 1)
1128
- // UNION (SELECT * FROM `users` WHERE `users`.`id` IN (2))
1129
- // UNION (SELECT * FROM `users` WHERE `users`.`id` IN (3,4));
1130
-
1131
-
1132
- const users = await new DB('users')
1133
- .unionAll(new DB('users'))
1134
- .unionAll(new DB('users'))
1135
- .findMany()
1136
-
1137
- // (SELECT * FROM `users`)
1138
- // UNION ALL (SELECT * FROM `users`)
1139
- // UNION ALL (SELECT * FROM `users`);
1140
-
1141
- ```
1142
-
1143
- ## More Methods
1144
-
1145
- ```js
1146
- where(column , OP , value)
1147
- whereSensitive(column , OP , value)
1148
- whereId(id)
1149
- whereUser(userId)
1150
- whereEmail(value)
1151
- whereIn(column , [])
1152
- whereNotIn(column , [])
1153
- whereNull(column)
1154
- whereNotNull(column)
1155
- whereBetween (column , [value1 , value2])
1156
- whereQuery(callback)
1157
- whereJson(column, { targetKey, value , OP })
1158
- whereRaw(sql)
1159
- whereExists(sql)
1160
- whereSubQuery(colmn , rawSQL)
1161
- whereNotSubQuery(colmn , rawSQL)
1162
- orWhere(column , OP , value)
1163
- orWhereRaw(sql)
1164
- orWhereIn(column , [])
1165
- orWhereSubQuery(colmn , rawSQL)
1166
- when(contition , callback)
1167
- select(column1 ,column2 ,...N)
1168
- distinct()
1169
- selectRaw(column1 ,column2 ,...N)
1170
- except(column1 ,column2 ,...N)
1171
- exceptTimestamp()
1172
- only(column1 ,column2 ,...N)
1173
- hidden(column1 ,column2 ,...N)
1174
- join(primary key , table.foreign key)
1175
- rightJoin (primary key , table.foreign key)
1176
- leftJoin (primary key , table.foreign key)
1177
- limit (limit)
1178
- having (condition)
1179
- havingRaw (condition)
1180
- orderBy (column ,'ASC' || 'DSCE')
1181
- orderByRaw(column ,'ASC' || 'DSCE')
1182
- latest (column)
1183
- latestRaw (column)
1184
- oldest (column)
1185
- oldestRaw (column)
1186
- groupBy (column)
1187
- groupByRaw (column)
1188
- create(objects)
1189
- createMultiple(array objects)
1190
- update (objects)
1191
- updateMany (objects)
1192
- updateMultiple(array objects)
1193
- createNotExists(objects)
1194
- updateOrCreate (objects)
1195
- onlyTrashed()
1196
- connection(options)
1197
- backup({ database , connection })
1198
- backupToFile({ filePath, database , connection })
1199
- hook((result) => ...) // callback result to function
1200
- sleep(seconds)
1201
-
1202
- /**
1203
- * registry relation in your models
1204
- * @relationship
1205
- */
1206
- hasOne({ name, model, localKey, foreignKey, freezeTable , as })
1207
- hasMany({ name, model, localKey, foreignKey, freezeTable , as })
1208
- belongsTo({ name, model, localKey, foreignKey, freezeTable , as })
1209
- belongsToMany({ name, model, localKey, foreignKey, freezeTable, as, pivot })
1210
- /**
1211
- * @relation using registry in your models
1212
- */
1213
- relations(name1 , name2,...nameN) // with(name1, name2,...nameN)
1214
- /**
1215
- * @relation using registry in your models ignore soft delete
1216
- */
1217
- relationsAll(name1 , name2,...nameN) // withAll(name1, name2,...nameN)
1218
- /**
1219
- * @relation using registry in your models. if exists child data remove this data
1220
- */
1221
- relationsExists(name1 , name2,...nameN) // withExists(name1, name2,...nameN)
1222
- /**
1223
- * @relation using registry in your models return only in trash (soft delete)
1224
- */
1225
- relationsTrashed(name1 , name2,...nameN) // withTrashed(name1, name2,...nameN)
1226
- /**
1227
- * @relation call a name of relation in registry, callback query of data
1228
- */
1229
- relationQuery(name, (callback) ) // withQuery(name1, (callback))
1230
-
1231
-
1232
- /**
1233
- * queries statements
1234
- * @execute data of statements
1235
- */
1236
- findMany() // get()
1237
- findOne() // first()
1238
- find(id)
1239
- delelte()
1240
- delelteMany()
1241
- exists()
1242
- toString()
1243
- toJSON()
1244
- toArray(column)
1245
- count(column)
1246
- sum(column)
1247
- avg(column)
1248
- max(column)
1249
- min(column)
1250
- pagination({ limit , page })
1251
- save() /* for actions statements insert or update */
1252
- makeSelectStatement()
1253
- makeInsertStatement()
1254
- makeUpdateStatement()
1255
- makeDeleteStatement()
1256
- makeCreateTableStatement()
1257
-
1258
- ```
1259
-
1260
- ## Database Transactions
1261
-
1262
- Within a database transaction, you can utilize the following:
1263
-
1264
- ```js
1265
- const connection = await new DB().beginTransaction();
1266
-
1267
- try {
1268
- /**
1269
- *
1270
- * @startTransaction start transaction in scopes function
1271
- */
1272
- await connection.startTransaction();
1273
-
1274
- const user = await new User()
1275
- .create({
1276
- name: `tspace`,
1277
- email: "tspace@example.com",
1278
- })
1279
- /**
1280
- *
1281
- * bind method for make sure this connection has same transaction in connection
1282
- * @params {Function} connection
1283
- */
1284
- .bind(connection)
1285
- .save();
1286
-
1287
- const posts = await new Post()
1288
- .createMultiple([
1289
- {
1290
- user_id: user.id,
1291
- title: `tspace-post1`,
1292
- },
1293
- {
1294
- user_id: user.id,
1295
- title: `tspace-post2`,
1296
- },
1297
- {
1298
- user_id: user.id,
1299
- title: `tspace-post3`,
1300
- },
1301
- ])
1302
- .bind(connection) // don't forget this
1303
- .save();
1304
-
1305
- /**
1306
- *
1307
- * @commit commit transaction to database
1308
- */
1309
- // After your use commit if use same connection for actions this transction will auto commit
1310
- await connection.commit();
1311
-
1312
- // If you need to start a new transaction again, just use wait connection.startTransaction();
1313
-
1314
- const postsAfterCommited = await new Post()
1315
- .createMultiple([
1316
- {
1317
- user_id: user.id,
1318
- title: `tspace-post1`,
1319
- },
1320
- {
1321
- user_id: user.id,
1322
- title: `tspace-post2`,
1323
- },
1324
- {
1325
- user_id: user.id,
1326
- title: `tspace-post3`,
1327
- },
1328
- ])
1329
- // Using this connection now will auto-commit to the database.
1330
- .bind(connection) // If you need to perform additional operations, use await connection.startTransaction(); again.
1331
- .save();
1332
-
1333
-
1334
- // Do not perform any operations with this connection.
1335
- // The transaction has already been committed, and the connection is closed.
1336
- // Just ensure everything is handled at the end of the transaction.
1337
- await connection.end();
1338
-
1339
- } catch (err) {
1340
- /**
1341
- *
1342
- * @rollback rollback transaction
1343
- */
1344
- await connection.rollback();
1345
- }
1346
- ```
1347
-
1348
- ## Connection
1349
-
1350
- When establishing a connection, you can specify options as follows:
56
+ ## Basic Usage
1351
57
 
1352
- ```js
1353
- const connection = await new DB().getConnection({
1354
- host: 'localhost',
1355
- port : 3306,
1356
- database: 'database'
1357
- username: 'username',
1358
- password: 'password',
1359
- })
1360
-
1361
- const users = await new DB('users')
1362
- .bind(connection) // don't forget this
1363
- .findMany()
1364
- ```
1365
-
1366
- ## Backup
1367
-
1368
- To backup a database, you can perform the following steps:
1369
-
1370
- ```js
1371
- /**
1372
- *
1373
- * @param {string} database Database selected
1374
- * @param {object | null} to defalut new current connection
1375
- */
1376
- const backup = await new DB().backup({
1377
- database: 'try-to-backup', // clone current database to this database
1378
- to ?: {
1379
- host: 'localhost',
1380
- port : 3306,
1381
- username: 'username',
1382
- password: 'password',
1383
- }
1384
- })
1385
- /**
1386
- *
1387
- * @param {string} database Database selected
1388
- * @param {string} filePath file path
1389
- * @param {object | null} conection defalut current connection
1390
- */
1391
- const backupToFile = await new DB().backupToFile({
1392
- database: 'try-to-backup',
1393
- filePath: 'backup.sql',
1394
- connection ?: {
1395
- host: 'localhost',
1396
- port : 3306,
1397
- database: 'database'
1398
- username: 'username',
1399
- password: 'password',
1400
- }
1401
- })
1402
- // backupToFile => backup.sql
1403
-
1404
- /**
1405
- *
1406
- * @param {string} database new db name
1407
- */
1408
- await new DB().cloneDB('try-to-clone')
1409
-
1410
- ```
1411
-
1412
- ## Injection
1413
-
1414
- The 'tspace-mysql' library is configured to automatically escape SQL injection by default.
1415
- Let's example a escape SQL injection and XSs injection:
1416
-
1417
- ```js
1418
- const input = "admin' OR '1'='1";
1419
- DB.escape(input);
1420
- // "admin\' OR \'1\'=\'1"
1421
-
1422
- //XSS
1423
- const input = "text hello!<script>alert('XSS attack');</script>";
1424
- DB.escapeXSS(input);
1425
- // "text hello!"
1426
- ```
1427
-
1428
- ## Generating Model Classes
1429
-
1430
- To get started, install the 'tspace-mysql' package globally using the following npm command:
1431
-
1432
- ```js
1433
- /**
1434
- *
1435
- * @install global command
1436
- */
1437
- npm install tspace-mysql -g
1438
-
1439
- /**
1440
- *
1441
- * @make Model
1442
- */
1443
- tspace-mysql make:model <model name> --dir=< directory >
1444
-
1445
- # tspace-mysql make:model User --dir=App/Models
1446
- # App/Models/User.ts
1447
- ```
1448
-
1449
- ## Model Conventions
1450
-
1451
- Your database schema using models. These models represent tables in the database
1452
- Let's example a basic model class:
1453
-
1454
- ```js
1455
- import { Model } from "tspace-mysql";
1456
- // If you want to specify a global setting for the 'Model'
1457
- Model.global({
1458
- uuid: true,
1459
- softDelete: true,
1460
- timestamp: true,
1461
- logger: true,
1462
- });
1463
-
1464
- class User extends Model {
1465
- constructor() {
1466
- super();
1467
- /**
1468
- *
1469
- * Assign setting global in your model
1470
- * @useMethod
1471
- * this.usePattern('camelCase') // => default 'snake_case'
1472
- * this.useCamelCase()
1473
- * this.useSnakeCase()
1474
- * this.useLogger()
1475
- * this.useDebug()
1476
- * this.usePrimaryKey('id')
1477
- * this.useTimestamp({
1478
- * createdAt : 'created_at',
1479
- * updatedAt : 'updated_at'
1480
- * }) // runing a timestamp when insert or update
1481
- * this.useSoftDelete('deletedAt') // => default target to colmun deleted_at
1482
- * this.useTable('users')
1483
- * this.useTableSingular() // => 'user'
1484
- * this.useTablePlural() // => 'users'
1485
- * this.useUUID('uuid') // => runing a uuid (universally unique identifier) when insert new data
1486
- * this.useRegistry() // => build-in functions registry
1487
- * this.useLoadRelationsInRegistry() // => auto generated result from relationship to results
1488
- * this.useBuiltInRelationFunctions() // => build-in functions relationships to results
1489
- * this.useHooks([(r) => console.log(r)])
1490
- * this.useObserver(Observe)
1491
- * this.useSchema ({
1492
- * id : Blueprint.int().notNull().primary().autoIncrement(),
1493
- * uuid : Blueprint.varchar(50).null(),
1494
- * name : Blueprint.varchar(191).notNull(),
1495
- * email : Blueprint.varchar(191).notNull(),
1496
- * created_at : Blueprint.timestamp().null(),
1497
- * updated_at : Blueprint.timestamp().null(),
1498
- * deleted_at : Blueprint.timestamp().null()
1499
- * }) // auto-generated table when table is not exists and auto-create column when column not exists
1500
- *
1501
- * // validate input when create or update reference to the schema in 'this.useSchema'
1502
- * this.useValidateSchema({
1503
- * id : Number,
1504
- * uuid : Number,
1505
- * name : {
1506
- * type : String,
1507
- * length : 191
1508
- * require : true
1509
- * },
1510
- * email : {
1511
- * type : String,
1512
- * require : true,
1513
- * length : 191,
1514
- * match: /^[a-zA-Z0-9._]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
1515
- * unique : true,
1516
- * fn : (email : string) => !/^[a-zA-Z0-9._]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(email)
1517
- * },
1518
- * created_at : Date,
1519
- * updated_at : Date,
1520
- * deleted_at : Date
1521
- * })
1522
- */
1523
-
1524
- /*
1525
- * the "snake case", plural name of the class will be used as the table name
1526
- *
1527
- * @param {string} name The table associated with the model.
1528
- */
1529
- this.useTable("users");
1530
- }
1531
- }
1532
- export { User };
1533
- export default User;
1534
- ```
1535
-
1536
- ### Basic Model Setup
1537
-
1538
- #### Table Name
1539
-
1540
- ```js
1541
- import { Model } from 'tspace-mysql'
1542
- class User extends Model {
1543
- constructor() {
1544
- super()
1545
- // By default, the model knows that the table name for this User is 'users'
1546
-
1547
- this.useTable('fix_table') // fixtable
1548
- this.useTablePlural() // users
1549
- this.useTableSingular() // user
1550
- }
1551
- }
1552
-
1553
- ```
1554
-
1555
- #### Pattern
1556
-
1557
- ```js
1558
-
1559
- import { Model } from 'tspace-mysql'
1560
- class UserPhone extends Model {
1561
- constructor() {
1562
- super()
1563
- // By default, the model is pattern snake_case
1564
- // The table name is user_phones
1565
- this.useSnakeCase()
1566
-
1567
- this.useCamelCase()
1568
- // The table name is userPhones
1569
- }
1570
- }
1571
-
1572
- // set the pattern CamelCase for the model
1573
- const userPhone = await new UserPhone().where('user_id',1).findOne()
1574
- // covert 'user_id' to 'userId'
1575
- // SELECT * FROM `userPhones` WHERE `userPhones`.`userId` = '1' LIMIT 1;
1576
-
1577
- // avoid the pattern CamelCase for the model
1578
- const userPhone = await new UserPhone().where(DB.freeze('user_id'),1).findOne()
1579
- // SELECT * FROM `userPhones` WHERE `userPhones`.`user_id` = '1' LIMIT 1;
1580
-
1581
- ```
1582
-
1583
- #### UUID
1584
-
1585
- ```js
1586
-
1587
- import { Model } from 'tspace-mysql'
1588
- class User extends Model {
1589
- constructor() {
1590
- super()
1591
- this.useUUID() // insert uuid when creating
1592
- }
1593
- }
1594
-
1595
- ```
1596
-
1597
- #### Timestamp
1598
-
1599
- ```js
1600
-
1601
- import { Model } from 'tspace-mysql'
1602
- class User extends Model {
1603
- constructor() {
1604
- super()
1605
- // insert created_at and updated_at when creating
1606
- // update updated_at when updating
1607
- // 'created_at' and 'updated_at' still relate to pettern the model
1608
- // this.useCamelCase() will covert 'created_at' to 'createdAt' and 'updated_at' to 'updatedAt'
1609
- this.useTimestamp()
1610
-
1611
- // custom the columns
1612
- this.useTimestamp({
1613
- createdAt : 'createdAtCustom',
1614
- updatedAt : 'updatedAtCustom'
1615
- })
1616
-
1617
- }
1618
- }
1619
-
1620
- ```
1621
-
1622
- #### Debug
1623
-
1624
- ```js
1625
-
1626
- import { Model } from 'tspace-mysql'
1627
- class User extends Model {
1628
- constructor() {
1629
- super()
1630
- this.useDebug() // show the query sql in console when executing
1631
- }
1632
- }
1633
-
1634
- ```
1635
- #### Observer
1636
-
1637
- ```js
1638
-
1639
- class Observe {
1640
-
1641
- public selected(results) {
1642
- console.log({ results , selected : true })
1643
- }
1644
-
1645
- public created(results) {
1646
- console.log({ results , created : true })
1647
- }
1648
-
1649
- public updated(results) {
1650
- console.log({ results , updated : true })
1651
- }
1652
-
1653
- public deleted(results) {
1654
- console.log({ results , deleted : true })
1655
- }
1656
- }
1657
-
1658
- import { Model } from 'tspace-mysql'
1659
- class User extends Model {
1660
- constructor() {
1661
- super()
1662
- this.useObserver(Observe) // returning to the observers by statements
1663
- }
1664
- }
1665
-
1666
- ```
1667
-
1668
- #### Logger
1669
-
1670
- ```js
1671
-
1672
- import { Model } from 'tspace-mysql'
1673
- class User extends Model {
1674
- constructor() {
1675
- super()
1676
- // keep logging everything except select to the table '$loggers'
1677
- // the table will automatically be created
1678
- this.useLogger()
1679
-
1680
- // keep logging everything
1681
- this.useLogger({
1682
- selected : true,
1683
- inserted : true,
1684
- updated : true,
1685
- deleted : true,
1686
- })
1687
- }
1688
- }
1689
-
1690
- ```
1691
-
1692
- #### Hooks
1693
-
1694
- ```js
1695
-
1696
- import { Model } from 'tspace-mysql'
1697
- class User extends Model {
1698
- constructor() {
1699
- super()
1700
- // when executed will returning the results to any hooks function
1701
- this.useHooks([
1702
- (results1) => console.log(results1),
1703
- (results2) => console.log(results2),
1704
- (results3) => console.log(results3)
1705
- ])
1706
- }
1707
- }
1708
-
1709
- ```
1710
-
1711
- ### Global Scope
1712
- ```js
1713
-
1714
- class User extends Model {
1715
- constructor() {
1716
- super()
1717
-
1718
- // Every query will have the global scope applied.
1719
- this.globalScope((query : User) => {
1720
- return query.select('id').where('id' , '>' , 10).orderBy('id')
1721
- })
1722
- }
1723
- }
1724
-
1725
- const user = await new User().findMany()
1726
-
1727
- // SELECT `users`.`id` FROM `users` WHERE `users`.`id` > '10' ORDER BY `users`.`id` ASC LIMIT 1
1728
-
1729
- ```
1730
-
1731
- ## Joins Model
1732
-
1733
- ### Inner Join Model Clause
1734
-
1735
- ```js
1736
- await new User().joinModel(User, Post).findMany();
1737
- // SELECT `users`.`id`, `users`.`email`, `users`.`username` FROM `users` INNER JOIN `posts` ON `users`.`id` = `posts`.`user_id`;
1738
-
1739
- // if the model use soft delete
1740
- await new User().joinModel(User, Post).findMany();
1741
- // SELECT `users`.`id`, `users`.`email`, `users`.`username` FROM `users`
1742
- // INNER JOIN `posts` ON `users`.`id` = `posts`.`user_id`
1743
- // WHERE `posts`.`deleted_at` IS NULL AND `users`.`deleted_at` IS NULL;
1744
-
1745
- await new User().select(`${User.table}.*`,`${Post.table}.*`).joinModel(User, Post).findMany();
1746
- // SELECT users.*, posts.* FROM `users`
1747
- // INNER JOIN `posts` ON `users`.`id` = `posts`.`user_id`
1748
- // WHERE `posts`.`deleted_at` IS NULL AND `users`.`deleted_at` IS NULL;
1749
-
1750
- await new User().select('u.*','p.*')
1751
- .joinModel({ model : User , key : 'id' , alias : 'u' }, { model : Post , key : 'user_id', alias : 'p'})
1752
- .findMany();
1753
- // SELECT u.*, p.* FROM `users` AS `u`
1754
- // INNER JOIN `posts` AS `p` ON `u`.`id` = `p`.`user_id`
1755
- // WHERE `p`.`deleted_at` IS NULL AND `u`.`deleted_at` IS NULL;
1756
-
1757
- await new DB("posts")
1758
- .join((join) => {
1759
- return join
1760
- .on('posts.user_id','users.id')
1761
- .on('users.id','post_user.user_id')
1762
- .and('users.id','posts.user_id')
1763
- })
1764
- .findMany()
1765
- // SELECT * FROM `posts`
1766
- // INNER JOIN `users` ON `posts`.`user_id` = `users`.`id`
1767
- // INNER JOIN `post_user` ON `users`.`id` = `post_user`.`user_id` AND `users`.`id` = `posts`.`user_id`;
1768
- ```
1769
- ### Left Join, Right Join Model Clause
1770
-
1771
- ```js
1772
- await new User().leftJoinModel(User, Post).findMany();
1773
- // SELECT `users`.`id`, `users`.`email`, `users`.`username` FROM `users` LEFT JOIN `posts` ON `users`.`id` = `posts`.`user_id`;
1774
-
1775
- await new User().rightJoinModel(User, Post).findMany();
1776
- // SELECT `users`.`id`, `users`.`email`, `users`.`username` FROM `users` RIGHT JOIN `posts` ON `users`.`id` = `posts`.`user_id`;
1777
- ```
1778
-
1779
- ### Cross Join Model Clause
1780
-
1781
- ```js
1782
- await new User().crossJoinModel(User, Post).findMany();
1783
- // SELECT `users`.`id`, `users`.`email`, `users`.`username` FROM `users` CROSS JOIN `posts` ON `users`.`id` = `posts`.`user_id`;
1784
- ```
1785
-
1786
- ### Relationships
1787
-
1788
- Relationships are defined as methods on your Model classes.
1789
- Let's example a basic relationship:
1790
-
1791
- #### One To One
1792
-
1793
- A one-to-one relationship is used to define relationships where a single model is the parent to one child models
1794
-
1795
- ```js
1796
- import { Model } from 'tspace-mysql'
1797
- import Phone from '../Phone'
1798
- class User extends Model {
1799
- constructor(){
1800
- super()
1801
- this.useTimestamp()
1802
- /**
1803
- *
1804
- * @hasOne Get the phone associated with the user.
1805
- * @relationship users.id -> phones.user_id
1806
- */
1807
- this.hasOne({ name : 'phone' , model : Phone })
1808
- }
1809
- /**
1810
- * Mark a method for relationship
1811
- * @hasOne Get the phone associated with the user. using function callback
1812
- * @function
1813
- */
1814
- phone (callback) {
1815
- return this.hasOneBuilder({ name : 'phone' , model : Phone } , callback)
1816
- }
1817
- }
1818
- export default User
1819
-
1820
- +--------------------------------------------------------------------------+
1821
-
1822
- import User from '../User'
1823
- const user = await new User().relations('phone').findOne() // You can also use the method .with('roles').
1824
- // user?.phone => {...}
1825
- const userUsingFunction = await new User().phone().findOne()
1826
- // userUsingFunction?.phone => {...}
1827
- ```
1828
-
1829
- ### One To Many
1830
-
1831
- A one-to-many relationship is used to define relationships where a single model is the parent to one or more child models.
1832
-
1833
- ```js
1834
- import { Model } from 'tspace-mysql'
1835
- import Comment from '../Comment'
1836
- class Post extends Model {
1837
- constructor(){
1838
- super()
1839
- this.useTimestamp()
1840
- /**
1841
- *
1842
- * @hasMany Get the comments for the post.
1843
- * @relationship posts.id -> comments.post_id
1844
- */
1845
- this.hasMany({ name : 'comments' , model : Comment })
1846
- }
1847
- /**
1848
- *
1849
- * @hasManyQuery Get the comments for the post. using function callback
1850
- * @function
1851
- */
1852
- comments (callback) {
1853
- return this.hasManyBuilder({ name : 'comments' , model : Comment } , callback)
1854
- }
1855
- }
1856
- export default Post
1857
-
1858
- +--------------------------------------------------------------------------+
1859
-
1860
- import Post from '../Post'
1861
- const posts = await new Post().relations('comments').findOne()
1862
- // posts?.comments => [{...}]
1863
- const postsUsingFunction = await new Post().comments().findOne()
1864
- // postsUsingFunction?.comments => [{...}]
1865
- ```
1866
-
1867
- #### Belongs To
1868
-
1869
- A belongsto relationship is used to define relationships where a single model is the child to parent models.
1870
-
1871
- ```js
1872
- import { Model } from 'tspace-mysql'
1873
- import User from '../User'
1874
- class Phone extends Model {
1875
- constructor(){
1876
- super()
1877
- this.useTimestamp()
1878
- /**
1879
- *
1880
- * @belongsTo Get the user that owns the phone.
1881
- * @relationship phones.user_id -> users.id
1882
- */
1883
- this.belognsTo({ name : 'user' , model : User })
1884
- }
1885
- /**
1886
- *
1887
- * @belongsToBuilder Get the user that owns the phone.. using function callback
1888
- * @function
1889
- */
1890
- user (callback) {
1891
- return this.belongsToBuilder({ name : 'user' , model : User }, callback)
1892
- }
1893
- }
1894
- export default Phone
1895
-
1896
- +--------------------------------------------------------------------------+
1897
-
1898
- import Phone from '../Phone'
1899
- const phone = await new Phone().relations('user').findOne()
1900
- // phone?.user => {...}
1901
- const phoneUsingFunction = await new Phone().user().findOne()
1902
- // phoneUsingFunction?.user => {...}
1903
- ```
1904
-
1905
- #### Many To Many
1906
-
1907
- Many-to-many relations are slightly more complicated than hasOne and hasMany relationships.
1908
-
1909
- ```js
1910
- import { Model } from 'tspace-mysql'
1911
- import Role from '../Role'
1912
- class User extends Model {
1913
- constructor(){
1914
- super()
1915
- this.useTimestamp()
1916
- /**
1917
- *
1918
- * @belongsToMany Get The roles that belong to the user.
1919
- * @relationship users.id , roles.id => role_user.user_id , role_user.role_id
1920
- */
1921
- this.belognsToMany({ name : 'roles' , model : Role })
1922
- }
1923
- /**
1924
- * @belongsToBuilder Get the user that owns the phone.. using function callback
1925
- * @function
1926
- */
1927
- roles (callback) {
1928
- return this.belognsToManyBuilder({ model : Role } , callback)
1929
- }
1930
- }
1931
- export default User
1932
-
1933
- +--------------------------------------------------------------------------+
1934
-
1935
- import User from '../User'
1936
- const user = await new User().relations('roles').findOne()
1937
- // user?.roles => [{...}]
1938
- const userUsingFunction = await new User().roles().findOne()
1939
- // user?.roles => [{...}]
1940
- ```
1941
-
1942
- #### Relation
1943
-
1944
- Relationships are connections between entities.
1945
- Let's consider an example of a relationship:
1946
-
1947
- ```js
1948
-
1949
- +-------------+--------------+----------------------------+
1950
- | table users |
1951
- +-------------+--------------+----------------------------+
1952
- | id | username | email |
1953
- |-------------|--------------|----------------------------|
1954
- | 1 | tspace1 | tspace1@gmail.com |
1955
- | 2 | tspace2 | tspace2@gmail.com |
1956
- | 3 | tspace3 | tspace3@gmail.com |
1957
- +-------------+--------------+----------------------------+
1958
-
1959
- +-------------+--------------+----------------------------+
1960
- | table posts |
1961
- +-------------+--------------+----------------------------+
1962
- | id | user_id | title |
1963
- |-------------|--------------|----------------------------|
1964
- | 1 | 1 | posts 1 |
1965
- | 2 | 1 | posts 2 |
1966
- | 3 | 3 | posts 3 |
1967
- +-------------+--------------+----------------------------+
1968
-
1969
- import { Model } from 'tspace-mysql'
1970
-
1971
- class User extends Model {
1972
- constructor(){
1973
- super()
1974
- this.hasMany({ name : 'posts' , model : Post })
1975
- }
1976
- }
1977
-
1978
- class Post extends Model {
1979
- constructor(){
1980
- super()
1981
- this.belongsTo({ name : 'user' , model : User })
1982
- }
1983
- }
1984
-
1985
- await new User()
1986
- .relations('posts')
1987
- .findOne()
1988
- // SELECT * FROM `users` LIMIT 1;
1989
- // SELECT * FROM `posts` WHERE `posts`.`userId` IN (...);
1990
-
1991
- /*
1992
- * @returns
1993
- * {
1994
- * id : 1,
1995
- * username: "tspace1",
1996
- * email : "tspace1@gmail.com",
1997
- * posts : [
1998
- * {
1999
- * id : 1 ,
2000
- * user_id : 1,
2001
- * title : "post 1"
2002
- * },
2003
- * {
2004
- * id : 2 ,
2005
- * user_id : 1,
2006
- * title : "post 2"
2007
- * }
2008
- * ]
2009
- * }
2010
- */
2011
-
2012
- ```
2013
-
2014
- #### Deeply Nested Relations
2015
-
2016
- Relationships can involve deep connections.
2017
- Let's consider an example of a deep relationship:
2018
-
2019
- ```js
2020
- import { Model } from 'tspace-mysql'
2021
-
2022
- class User extends Model {
2023
- constructor(){
2024
- super()
2025
- this.hasMany({ name : 'posts' , model : Post })
2026
- }
2027
- }
2028
- +--------------------------------------------------------------------------+
2029
- class Post extends Model {
2030
- constructor(){
2031
- super()
2032
- this.hasMany({ name : 'comments' , model : Comment })
2033
- this.belongsTo({ name : 'user' , model : User })
2034
- this.belongsToMany({ name : 'users' , model : User , modelPivot : PostUser })
2035
- }
2036
- }
2037
- +--------------------------------------------------------------------------+
2038
- class Comment extends Model {
2039
- constructor(){
2040
- super()
2041
- this.hasMany({ name : 'users' , model : User })
2042
- this.belongsTo({ name : 'post' , model : Post })
2043
- }
2044
- }
2045
-
2046
- class PostUser extends Model {}
2047
- +--------------------------------------------------------------------------+
2048
- // Deeply nested relations
2049
- await new User()
2050
- .relations('posts')
2051
- .relationQuery('posts', (query : Post) => {
2052
- return query
2053
- .relations('comments','user','users')
2054
- .relationQuery('comments', (query : Comment) => {
2055
- return query.relations('user','post')
2056
- })
2057
- .relationQuery('user', (query : User) => {
2058
- return query.relations('posts').relationQuery('posts',(query : Post)=> {
2059
- return query.relations('comments','user')
2060
- // relation n, n, ...n
2061
- })
2062
- })
2063
- .relationQuery('users', (query : User) => {
2064
- return query
2065
- })
2066
- .relationQuery('users', (query : PostUser) => {
2067
- return query
2068
- }, { pivot : true })
2069
- })
2070
- .findMany()
2071
-
2072
- // Select some columns in nested relations
2073
- await new User()
2074
- .relations('posts')
2075
- .relationQuery('posts', (query : Post) => query.select('id','user_id','title'))
2076
- .findMany()
2077
-
2078
- // Where some columns in nested relations
2079
- await new User()
2080
- .relations('posts')
2081
- .relationQuery('posts', (query : Post) => query.whereIn('id',[1,3,5]))
2082
- .findMany()
2083
-
2084
- // Sort data in nested relations
2085
- await new User()
2086
- .relations('posts')
2087
- .relationQuery('posts', (query : Post) => query.latest('id'))
2088
- .findMany()
2089
-
2090
- // Limit data in nested relations
2091
- await new User()
2092
- .relations('posts')
2093
- .relationQuery('posts', (query : Post) => {
2094
- return query
2095
- .limit(1)
2096
- .relations('comments')
2097
- .relationQuery('comments', (query : Comment) => query.limit(1))
2098
- })
2099
- .findMany()
2100
-
2101
- ```
2102
-
2103
- #### Relation Exists
2104
-
2105
- Relationships can return results only if they are not empty in relations, considering soft deletes.
2106
- Let's illustrate this with an example of an existence check in relations:
2107
-
2108
- ```js
2109
- +-------------+--------------+----------------------------+--------------------+
2110
- | table users | |
2111
- +-------------+--------------+----------------------------+--------------------+
2112
- | id | username | email | deleted_at |
2113
- |-------------|--------------|----------------------------|--------------------|
2114
- | 1 | tspace1 | tspace1@gmail.com | |
2115
- | 2 | tspace2 | tspace2@gmail.com | |
2116
- | 3 | tspace3 | tspace3@gmail.com | |
2117
- +-------------+--------------+----------------------------+--------------------+
2118
-
2119
-
2120
- +-------------+--------------+----------------------------+--------------------+
2121
- | table posts | |
2122
- +-------------+--------------+----------------------------+--------------------+
2123
- | id | user_id | title | deleted_at |
2124
- |-------------|--------------|----------------------------|--------------------|
2125
- | 1 | 1 | posts 1 |2020-07-15 00:00:00 |
2126
- | 2 | 2 | posts 2 | |
2127
- | 3 | 3 | posts 3 |2020-07-15 00:00:00 |
2128
- +-------------+--------------+----------------------------+--------------------+
2129
-
2130
- import { Model } from 'tspace-mysql'
2131
-
2132
- class User extends Model {
2133
- constructor(){
2134
- super()
2135
- this.hasMany({ name : 'posts' , model : Post })
2136
- this.useSoftDelete()
2137
- }
2138
- }
2139
-
2140
- +--------------------------------------------------------------------------+
2141
-
2142
- class Post extends Model {
2143
- constructor(){
2144
- super()
2145
- this.hasMany({ name : 'comments' , model : Comment })
2146
- this.belongsTo({ name : 'user' , model : User })
2147
- this.useSoftDelete()
2148
- }
2149
- }
2150
- // normal relations
2151
- await new User().relations('posts').findMany()
2152
- // SELECT * FROM `users` WHERE `users`.`deleted_at`;
2153
- // SELECT * FROM `posts` WHERE `posts`.`userId` IN (...) AND `posts`.`deleted_at` IS NULL;
2154
-
2155
- /*
2156
- * @returns [
2157
- * {
2158
- * id : 1,
2159
- * username: "tspace1",
2160
- * email : "tspace1@gmail.com",
2161
- * posts : []
2162
- * },
2163
- * {
2164
- * id : 2,
2165
- * username: "tspace2",
2166
- * email : "tspace2@gmail.com",
2167
- * posts : [
2168
- * {
2169
- * id : 2,
2170
- * user_id : 2,
2171
- * title : "posts 2"
2172
- * }
2173
- * ]
2174
- * },
2175
- * {
2176
- * id : 3,
2177
- * username: "tspace3",
2178
- * email : "tspace3@gmail.com",
2179
- * posts : []
2180
- * }
2181
- * ]
2182
- */
2183
-
2184
- await new User().relationsExists('posts').findMany()
2185
- // SELECT * FROM `users` WHERE `users`.`deleted_at` IS NULL
2186
- // AND EXISTS (SELECT 1 FROM `posts` WHERE `users`.`id` = `posts`.`user_id` AND `posts`.`deletedA_at` IS NULL);
2187
-
2188
- // SELECT * FROM `posts` WHERE `posts`.`user_id` IN (...) AND `posts`.`deleted_at` IS NULL;
2189
-
2190
- /*
2191
- * @returns [
2192
- * {
2193
- * id : 2,
2194
- * username: "tspace2",
2195
- * email : "tspace2@gmail.com",
2196
- * posts : [
2197
- * {
2198
- * id : 2,
2199
- * user_id : 2,
2200
- * title : "posts 2"
2201
- * }
2202
- * ]
2203
- * }
2204
- * ]
2205
- * because posts id 1 and id 3 has been removed from database (using soft delete)
2206
- */
2207
-
2208
- ```
2209
-
2210
- #### Relation Count
2211
- Relationships will retrieving the count of related records without loading the data of related models
2212
- Let's illustrate this with an example of an existence check in relations:
2213
- ```js
2214
-
2215
- +-------------+--------------+----------------------------+
2216
- | table users |
2217
- +-------------+--------------+----------------------------+
2218
- | id | username | email |
2219
- |-------------|--------------|----------------------------|
2220
- | 1 | tspace1 | tspace1@gmail.com |
2221
- | 2 | tspace2 | tspace2@gmail.com |
2222
- +-------------+--------------+----------------------------+
2223
-
2224
- +-------------+--------------+----------------------------+
2225
- | table posts |
2226
- +-------------+--------------+----------------------------+
2227
- | id | user_id | title |
2228
- |-------------|--------------|----------------------------|
2229
- | 1 | 1 | posts 1 |
2230
- | 2 | 1 | posts 2 |
2231
- | 3 | 2 | posts 3 |
2232
- +-------------+--------------+----------------------------+
2233
-
2234
- import { Model } from 'tspace-mysql'
2235
-
2236
- class User extends Model {
2237
- constructor(){
2238
- super()
2239
- this.hasMany({ name : 'posts' , model : Post })
2240
- this.useSoftDelete()
2241
- }
2242
- }
2243
-
2244
- // you also use .withCount()
2245
- await new User().relationsCount('posts').findMany()
2246
- // SELECT * FROM `users` WHERE `users`.`deleted_at` IS NULL;
2247
-
2248
- // SELECT `posts`.`user_id`, COUNT(`user_id`) AS `aggregate` FROM `posts`
2249
- // WHERE `posts`.`user_id` IN ('1','2') AND `posts`.`deleted_at` IS NULL GROUP BY `posts`.`user_id`;
2250
-
2251
- /*
2252
- * @returns [
2253
- * {
2254
- * id : 1,
2255
- * username: "tspace1",
2256
- * email : "tspace1@gmail.com",
2257
- * posts : 2
2258
- * }
2259
- * {
2260
- * id : 2,
2261
- * username: "tspace2",
2262
- * email : "tspace2@gmail.com",
2263
- * posts : 1
2264
- * }
2265
- * ]
2266
- */
2267
-
2268
- ```
2269
-
2270
- #### Relation Trashed
2271
- Relationships can return results only if they are deleted in table, considering soft deletes.
2272
- Let's illustrate this with an example:
2273
- ```js
2274
-
2275
- +-------------+--------------+----------------------------+--------------------+
2276
- | table users | |
2277
- +-------------+--------------+----------------------------+--------------------+
2278
- | id | username | email | deleted_at |
2279
- |-------------|--------------|----------------------------|--------------------|
2280
- | 1 | tspace1 | tspace1@gmail.com | |
2281
- | 2 | tspace2 | tspace2@gmail.com | |
2282
- | 3 | tspace3 | tspace3@gmail.com |2020-07-15 00:00:00 |
2283
- +-------------+--------------+----------------------------+--------------------+
2284
-
2285
- +-------------+--------------+----------------------------+--------------------+
2286
- | table posts | |
2287
- +-------------+--------------+----------------------------+--------------------+
2288
- | id | user_id | title | deleted_at |
2289
- |-------------|--------------|----------------------------|--------------------|
2290
- | 1 | 1 | posts 1 |2020-07-15 00:00:00 |
2291
- | 2 | 2 | posts 2 | |
2292
- | 3 | 3 | posts 3 |2020-07-15 00:00:00 |
2293
- +-------------+--------------+----------------------------+--------------------+
2294
-
2295
- import { Model } from 'tspace-mysql'
2296
-
2297
- class User extends Model {
2298
- constructor(){
2299
- super()
2300
- this.hasMany({ name : 'posts' , model : Post })
2301
- this.useSoftDelete()
2302
- }
2303
- }
2304
-
2305
- +--------------------------------------------------------------------------+
2306
-
2307
- class Post extends Model {
2308
- constructor(){
2309
- super()
2310
- this.hasMany({ name : 'comments' , model : Comment })
2311
- this.belongsTo({ name : 'user' , model : User })
2312
- this.useSoftDelete()
2313
- }
2314
- }
2315
-
2316
- // normal relations
2317
- await new User().relations('posts').findMany()
2318
- // SELECT * FROM `users` WHERE `users`.`deleted_at` IS NULL;
2319
- // SELECT * FROM `posts` WHERE `posts`.`user_id` IN (...) AND `posts`.`deleted_at` IS NULL;
2320
-
2321
- /*
2322
- * @returns [
2323
- * {
2324
- * id : 1,
2325
- * username: "tspace1",
2326
- * email : "tspace1@gmail.com",
2327
- * posts : []
2328
- * }
2329
- * {
2330
- * id : 2,
2331
- * username: "tspace2",
2332
- * email : "tspace2@gmail.com",
2333
- * posts : [
2334
- * {
2335
- * id : 2,
2336
- * user_id : 2,
2337
- * title : "posts 2"
2338
- * }
2339
- * ]
2340
- * }
2341
- * ]
2342
- */
2343
-
2344
- // relationsTrashed
2345
- await new User().relationsTrashed('posts').findMany()
2346
- // SELECT * FROM `users` WHERE `users`.`deleted_at` IS NULL;
2347
- // SELECT * FROM `posts` WHERE `posts`.`user_id` IN (...) AND `posts`.`deleted_at` IS NOT NULL;
2348
-
2349
- /*
2350
- * @returns [
2351
- * {
2352
- * id : 1,
2353
- * username: "tspace1",
2354
- * email : "tspace1@gmail.com",
2355
- * posts : [
2356
- * {
2357
- * id : 1,
2358
- * user_id : 1,
2359
- * title : "posts 1"
2360
- * }
2361
- * ]
2362
- * }
2363
- * {
2364
- * id : 2,
2365
- * username: "tspace2",
2366
- * email : "tspace2@gmail.com",
2367
- * posts : []
2368
- * }
2369
- * ]
2370
- */
2371
-
2372
- // relationsTrashed + trashed
2373
- await new User().relationsTrashed('posts').trashed().findMany()
2374
- // SELECT * FROM `users` WHERE `users`.`deleted_at` IS NOT NULL;
2375
- // SELECT * FROM `posts` WHERE `posts`.`user_id` IN (...) AND `posts`.`deleted_at` IS NOT NULL;
2376
- /*
2377
- * @returns [
2378
- * {
2379
- * id : 3,
2380
- * username: "tspace3",
2381
- * email : "tspace3@gmail.com",
2382
- * posts : [
2383
- * {
2384
- * id : 3,
2385
- * user_id : 3,
2386
- * title : "posts 3"
2387
- * }
2388
- * ]
2389
- * }
2390
- * ]
2391
- */
2392
-
2393
- ```
2394
-
2395
- ### Built in Relation Functions
2396
- Certainly, let's illustrate the use of a built-in function in the results of relationships:
2397
-
2398
- ```js
2399
- import { Model } from 'tspace-mysql'
2400
-
2401
- class User extends Model {
2402
- constructor(){
2403
- super()
2404
- this.hasMany({ name : 'posts' , model : Post })
2405
- this.useBuiltInRelationFunctions()
2406
- }
2407
- }
2408
- +--------------------------------------------------------------------------+
2409
- class Post extends Model {
2410
- constructor(){
2411
- super()
2412
- this.hasMany({ name : 'comments' , model : Comment })
2413
- this.belongsTo({ name : 'user' , model : User })
2414
- this.useBuiltInRelationFunctions()
2415
- }
2416
- }
2417
- +--------------------------------------------------------------------------+
2418
- class Comment extends Model {
2419
- constructor(){
2420
- super()
2421
- this.hasMany({ name : 'users' , model : User })
2422
- this.belongsTo({ name : 'post' , model : Post })
2423
- this.useBuiltInRelationFunctions()
2424
- }
2425
- }
2426
- +--------------------------------------------------------------------------+
2427
- const user = await new User().findOne()
2428
- const posts = await user.$posts()
2429
-
2430
- /** Warning built-in function has Big-O effect */
2431
- for (const post of posts) {
2432
- const comments = await post.$comments()
2433
- }
2434
-
2435
- ```
2436
-
2437
- ### Cache
2438
-
2439
- Cache can be used in a Model.
2440
- Let's illustrate this with an example of a cache:
2441
-
2442
- ```js
2443
- // support memory db and redis
2444
- // set cache in file config .env , .env.development ... etc
2445
- DB_CACHE = memory // by default
2446
-
2447
- // for db
2448
- DB_CACHE = db
2449
-
2450
- // for redis
2451
- DB_CACHE = redis://username:password@server:6379
2452
-
2453
- const users = await new User()
2454
- .cache({
2455
- key : 'users', // key of the cache
2456
- expires : 1000 * 60 // cache expires in 60 seconds
2457
- })
2458
- .sleep(5) // assume the query takes longer than 5 seconds...
2459
- .findMany()
2460
-
2461
- ```
2462
-
2463
- ### Decorator
2464
-
2465
- Decorators can be used in a Model.
2466
- Let's illustrate this with an example of a decorators:
2467
-
2468
- ```js
2469
-
2470
- import {
2471
- Blueprint, Model ,
2472
- Table ,TableSingular, TablePlural,
2473
- UUID, SoftDelete, Timestamp,
2474
- Pattern, CamelCase , snakeCase ,
2475
- Column, Validate, Observer
2476
- } from 'tspace-mysql'
2477
- import { Post } from './Post'
2478
- import { PostUser } from './PostUser'
2479
-
2480
- class UserObserve {
2481
-
2482
- public selected(results) {
2483
- console.log({ results , selected : true })
2484
- }
2485
-
2486
- public created(results) {
2487
- console.log({ results , created : true })
2488
- }
2489
-
2490
- public updated(results) {
2491
- console.log({ results , updated : true })
2492
- }
2493
-
2494
- public deleted(results) {
2495
- console.log({ results , deleted : true })
2496
- }
2497
- }
2498
-
2499
- @Pattern('camelCase')
2500
- @Observer(UserObserve)
2501
- @UUID()
2502
- @SoftDelete()
2503
- @Timestamp()
2504
- @Table('users')
2505
- class User extends Model {
2506
-
2507
- @Column(() => Blueprint.int().notNull().primary().autoIncrement())
2508
- public id!: number
2509
-
2510
- @Column(() => Blueprint.varchar(50).null())
2511
- public uuid!: string
2512
-
2513
- @Column(() => Blueprint.varchar(50).null())
2514
- @Validate({
2515
- type : String,
2516
- require : true,
2517
- length : 50,
2518
- match: /^[a-zA-Z0-9._]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
2519
- unique : true,
2520
- fn : (email : string) => /^[a-zA-Z0-9._]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(email)
2521
- })
2522
- public email!: string
2523
-
2524
- @Column(() => Blueprint.varchar(50).null())
2525
- public name !: string
2526
-
2527
- @Column(() => Blueprint.varchar(50).null())
2528
- public username !: string
2529
-
2530
- @Column(() => Blueprint.varchar(50).null())
2531
- public password !: string
2532
-
2533
- @Column(() => Blueprint.timestamp().null())
2534
- public createdAt!: Date
2535
-
2536
- @Column(() => Blueprint.timestamp().null())
2537
- public updatedAt!: Date
2538
-
2539
- @Column(() => Blueprint.timestamp().null())
2540
- public deletedAt!: Date
2541
-
2542
- }
2543
-
2544
- export { User }
2545
- export default User
2546
-
2547
- ```
2548
-
2549
- ### Schema
2550
-
2551
- The schema refers to the structure of the database as it pertains to the objects and classes in the model.
2552
- using the following:
2553
-
2554
- #### Schema Model
2555
-
2556
- ```js
2557
- import { Model, Blueprint , type T } from "tspace-mysql";
2558
-
2559
- const schema = {
2560
- id: Blueprint.int().notNull().primary().autoIncrement(),
2561
- uuid: Blueprint.varchar(50).null().index(),
2562
- name: Blueprint.varchar(191).notNull(),
2563
- email: Blueprint.varchar(191).notNull(),
2564
- createdAt: Blueprint.timestamp().null(),
2565
- updatedAt: Blueprint.timestamp().null(),
2566
- deletedAt: Blueprint.timestamp().null()
2567
- }
2568
-
2569
-
2570
- // make type in TS
2571
- type TS = T.Schema<typeof Schema>
2572
-
2573
- // the TSchemaUser will be created like that
2574
- /**
2575
- {
2576
- id : number,
2577
- uuid : string | null,
2578
- name : string,
2579
- email : string,
2580
- createdAt : Date | string | null,
2581
- updatedAt : Date | string | null,
2582
- deletedAt : Date | string | null
2583
- }
2584
- */
2585
-
2586
-
2587
- class User extends Model<TS> // use the schema for this User model
2588
- {
2589
- constructor() {
2590
- super();
2591
- this.useCamelCase()
2592
- this.useSchema(schema)
2593
- }
2594
- }
2595
-
2596
- ```
2597
-
2598
- #### Virtual Column
2599
- ```js
2600
-
2601
- import { Model, Blueprint , type T } from "tspace-mysql";
2602
-
2603
- const schema = {
2604
- id: Blueprint.int().notNull().primary().autoIncrement(),
2605
- uuid: Blueprint.varchar(50).null().index(),
2606
- firstName: Blueprint.varchar(191).notNull(),
2607
- lastName : Blueprint.varchar(191).notNull(),
2608
- email: Blueprint.varchar(191).notNull(),
2609
- createdAt: Blueprint.timestamp().null(),
2610
- updatedAt: Blueprint.timestamp().null(),
2611
- deletedAt: Blueprint.timestamp().null(),
2612
-
2613
- // Define you virtual column to schema
2614
- fullName : new Blueprint().virtualColumn(`CONCAT(firstName,' ', lastName)`),
2615
- countPosts : new Blueprint().virtualColumn(`(SELECT COUNT(*) FROM posts WHERE posts.userid = users.id)`)
2616
-
2617
- // if you need to custom the virtualColumn column for some method.
2618
- // fullName : new Blueprint().virtualColumn({
2619
- // select : `CONCAT(firstName,' ', lastName)`,
2620
- // where : `CONCAT(firstName,' ', lastName)`,
2621
- // orderBy : `CONCAT(firstName,' ', lastName)`,
2622
- // groupBy : `CONCAT(firstName,' ', lastName)`,
2623
- // }),
2624
- }
2625
-
2626
- type TS = T.Schema<typeof Schema>
2627
-
2628
- class User extends Model<TS> {
2629
- constructor() {
2630
- super();
2631
- this.useSchema(schema)
2632
- }
2633
- }
2634
- const users = await new User()
2635
- .select('id','firstName','lastName','fullName','countPosts')
2636
- .where('fullName','LIKE',`%tspace-mysql%`)
2637
- .orderBy('fullName','desc')
2638
- .groupBy('fullName')
2639
- .findMany()
2640
-
2641
- // SELECT
2642
- // `users`.`id`, `users`.`firstName`, `users`.`lastName`,
2643
- // CONCAT(firstName,' ', lastName) AS fullName ,
2644
- // (SELECT COUNT(*) FROM posts WHERE posts.userid = users.id) AS countPosts
2645
- // FROM `users`
2646
- // WHERE CONCAT(firstName,' ', lastName) LIKE '%tspace-mysql%'
2647
- // GROUP BY CONCAT(firstName,' ', lastName)
2648
- // ORDER BY CONCAT(firstName,' ', lastName) DESC
2649
-
2650
- ```
2651
-
2652
- #### Validation
2653
-
2654
- Validate the schema of Model
2655
- let's example a validator model:
2656
-
2657
- ```js
2658
- import { Model, Blueprint } from "tspace-mysql";
2659
- class User extends Model {
2660
- constructor() {
2661
- super();
2662
- this.useCamelCase();
2663
- this.useSchema({
2664
- id: Blueprint.int().notNull().primary().autoIncrement(),
2665
- uuid: Blueprint.varchar(50).null(),
2666
- name: Blueprint.varchar(191).notNull(),
2667
- email: Blueprint.varchar(191).notNull(),
2668
- createdAt: Blueprint.timestamp().null(),
2669
- updatedAt: Blueprint.timestamp().null(),
2670
- deletedAt: Blueprint.timestamp().null(),
2671
- });
2672
-
2673
- // validate input when create or update reference to the schema in 'this.useSchema'
2674
- this.useValidateSchema({
2675
- id: Number,
2676
- uuid: Number,
2677
- name: {
2678
- type: String,
2679
- length: 191,
2680
- require: true,
2681
- json: true,
2682
- },
2683
- email: {
2684
- type: String,
2685
- require: true,
2686
- length: 191,
2687
- match: /^[a-zA-Z0-9._]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
2688
- unique: true,
2689
- fn: (email: string) => {
2690
- return /^[a-zA-Z0-9._]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(email)
2691
- }
2692
- },
2693
- createdAt: Date,
2694
- updatedAt: Date,
2695
- deletedAt: Date,
2696
- });
2697
- }
2698
- }
2699
- ```
2700
-
2701
- #### Sync
2702
-
2703
- Sync the schema with the "Models" setting in your directory.
2704
- This process will verify and update table columns and foreign keys as needed.
2705
- Ensure that the relationships are correctly established through the 'useSchema' method in your models.
2706
- Let's examine a basic sync class:
2707
-
2708
- ```js
2709
- /**
2710
- *
2711
- * @Ex directory
2712
- *
2713
- * - node_modules
2714
- * - src
2715
- * - index.ts
2716
- * - Models
2717
- * - User.ts
2718
- * - Post.ts
2719
- */
2720
-
2721
- // file User
2722
- class User extends Model {
2723
- constructor() {
2724
- super();
2725
- this.hasMany({ name: "posts", model: Post });
2726
-
2727
- // if you need to initialize data when creating the table, you can use the following.
2728
- this.whenCreatingTable(async () => {
2729
- return await new User()
2730
- .create({
2731
- ...columns,
2732
- })
2733
- .void()
2734
- .save();
2735
- });
2736
-
2737
- this.useSchema({
2738
- id: Blueprint.int().notNull().primary().autoIncrement(),
2739
- uuid: Blueprint.varchar(50).null(),
2740
- email: Blueprint.int().notNull().unique(),
2741
- name: Blueprint.varchar(255).null(),
2742
- created_at: Blueprint.timestamp().null(),
2743
- updated_at: Blueprint.timestamp().null(),
2744
- deleted_at: Blueprint.timestamp().null(),
2745
- });
2746
- }
2747
- }
2748
-
2749
- // file Post
2750
- import User from "./User";
2751
- class Post extends Model {
2752
- constructor() {
2753
- super();
2754
- this.hasMany({ name: "comments", model: Comment });
2755
- this.belongsTo({ name: "user", model: User });
2756
- this.useSchema({
2757
- id: Blueprint.int().notNull().primary().autoIncrement(),
2758
- uuid: Blueprint.varchar(50).null(),
2759
- user_id: Blueprint.int().notNull().foreign({
2760
- references: "id",
2761
- on: User,
2762
- onDelete: "CASCADE",
2763
- onUpdate: "CASCADE",
2764
- }),
2765
- title: Blueprint.varchar(255).null(),
2766
- created_at: Blueprint.timestamp().null(),
2767
- updated_at: Blueprint.timestamp().null(),
2768
- deleted_at: Blueprint.timestamp().null(),
2769
- });
2770
- }
2771
- }
2772
-
2773
- await Schema.sync(`/src/Models`, {
2774
- force: true,
2775
- log: true,
2776
- foreign: true,
2777
- changed: true,
2778
- });
2779
-
2780
- // You can also synchronize using the Model.
2781
- await new User().sync({ force: true, foreign: true, changed: true });
2782
- ```
2783
-
2784
- ### SoftDelete
2785
-
2786
- ```js
2787
-
2788
- import { Model } from 'tspace-mysql'
2789
- class User extends Model {
2790
- constructor() {
2791
- super()
2792
- this.useSoftDelete() // All query will be where 'deleted_at' is null
2793
-
2794
- // You can also use patterns camelCase to covert the 'deleted_at' to 'deletedAt'
2795
- // You can also customize the column 'deleted_at'
2796
- this.useSoftDelete('deletedAtCustom')
2797
- }
2798
- }
2799
-
2800
- const user = await new User().where('user_id',1).findOne()
2801
- // SELECT * FROM `users` WHERE `users`.`userId` = '1' and `users`.`deletedAtCustom` IS NULL LIMIT 1;
2802
-
2803
- // find in trashed
2804
- const user = await new User().trashed().findMany()
2805
- // SELECT * FROM `users` WHERE `users`.`userId` = '1' and `users`.`deletedAtCustom` IS NOT NULL;
2806
-
2807
- ```
2808
-
2809
- ### Type Safety
2810
- Type Type Safety in TypeScript refers to the ability of the language to detect and prevent type errors during compile-time.
2811
- Type Type Safety still works when you add additional types to your model, using the following:
2812
-
2813
- ```js
2814
- // in file User.ts
2815
- import { Model , Blueprint , type T } from 'tspace-mysql'
2816
- import Phone from '../Phone'
2817
-
2818
- const schemaUser = {
2819
- id :Blueprint.int().notNull().primary().autoIncrement(),
2820
- uuid :Blueprint.varchar(50).null(),
2821
- email :Blueprint.varchar(50).null(),
2822
- name :Blueprint.varchar(255).null(),
2823
- username : Blueprint.varchar(255).null(),
2824
- password : Blueprint.varchar(255).null(),
2825
- createdAt :Blueprint.timestamp().null(),
2826
- updatedAt :Blueprint.timestamp().null()
2827
- }
2828
-
2829
- type TSchemaUser = T.SchemaStatic<typeof schemaUser>
2830
- // TSchemaUser = T.Schema<typeof schemaUser>
2831
-
2832
- // TSchema allowed to set any new keys without in the schema to results
2833
- // TSchemaStatic not allowed to set any new keys without in the schema to results
2834
-
2835
- class User extends Model<TSchemaUser> { // Add this '<TSchemaUser>' to activate the type for the Model.
2836
- constructor() {
2837
- super()
2838
- this.useSchema(schemaUser)
2839
- this.hasOne({ model : Phone, name : 'phone' })
2840
- this.hasMany({ model : Phone, name : 'phones' })
2841
- }
2842
- }
2843
-
2844
- export { User }
2845
- export default User
2846
-
2847
- +--------------------------------------------------------------------------+
2848
-
2849
- // in file Phone.ts
2850
- import { Model , Blueprint , type T } from 'tspace-mysql'
2851
- import { User } from './User.ts'
2852
- const schemaPhone = {
2853
- id :Blueprint.int().notNull().primary().autoIncrement(),
2854
- uuid :Blueprint.varchar(50).null(),
2855
- userId : Blueprint.int().notNull(),
2856
- number :Blueprint.varchar(50).notNull(),
2857
- createdAt :Blueprint.timestamp().null(),
2858
- updatedAt :Blueprint.timestamp().null()
2859
- }
2860
-
2861
- type TSchemaPhone = T.SchemaStatic<typeof schemaPhone>
2862
-
2863
- class Phone extends Model<TSchemaPhone> {
2864
- constructor() {
2865
- super()
2866
- this.useSchema(schemaPhone)
2867
- this.useBelongsTo({ model : User, name : 'user'})
2868
- }
2869
- }
2870
-
2871
- export { Phone }
2872
- export default Phone
2873
-
2874
- // example basic
2875
- type TS = T.Schema<typeof TSchemaUser>
2876
- type TR = T.Relation<{ phone : Phone }>
2877
-
2878
- type TSM = T.SchemaModel<User>
2879
- type TRM = T.RelationModel<User>
2880
-
2881
- type TColumn = T.Column<User>
2882
-
2883
- type TResults = T.Results<User>
2884
- type TPaginateResults = T.Results<User, { paginate : true }>
2885
-
2886
- type TRepository = T.Repository<User>
2887
- type TRepositoryTypeOf = T.RepositoryTypeOf<User>
2888
-
2889
- +--------------------------------------------------------------------------+
2890
- ```
2891
-
2892
- ### Type Safety Select
2893
-
2894
- ```js
2895
- import { User } from './User.ts'
2896
- import { Phone } from './Phone.ts'
2897
-
2898
- const user = await new User().select('id','username').findOne() ✅
2899
- const user = await new User().select('idx','username').findOne() ❌
2900
-
2901
- const user = await new User().except('id','username').findOne() ✅
2902
- const user = await new User().except('idx','username').findOne() ❌
2903
-
2904
- // T.SchemaStatic not allowed to set any new keys without in the schema to results
2905
- user.withoutSchema = 1 ✅ // T.Schema<User>
2906
- user.withoutSchema = 1 ❌ // T.SchemaStatic<User>
2907
- // But can you make like this for cases
2908
- const user = await new User().except('idx','username').findOne<{ withoutSchema : number }>()
2909
- user.withoutSchema = 1 ✅
2910
- ```
2911
-
2912
- ### Type Safety OrderBy
2913
-
2914
- ```js
2915
- import { User } from './User.ts'
2916
- import { Phone } from './Phone.ts'
2917
-
2918
- const users = await new User().orderBy('id','DESC').findMany() ✅
2919
- const users = await new User().orderBy('idx','DESC').findMany() ❌
2920
-
2921
- const users = await new User().latest('id').findMany() ✅
2922
- const users = await new User().latest('idx').findMany() ❌
2923
-
2924
- const users = await new User().oldest('id').findMany() ✅
2925
- const users = await new User().oldest('idx').findMany() ❌
2926
-
2927
- ```
2928
-
2929
- ### Type Safety GroupBy
2930
-
2931
- ```js
2932
- import { User } from './User.ts'
2933
- import { Phone } from './Phone.ts'
2934
-
2935
- const users = await new User().groupBy('id').findMany() ✅
2936
- const users = await new User().groupBy('idx').findMany() ❌
2937
-
2938
- ```
2939
-
2940
- ### Type Safety Where
2941
-
2942
- ```js
2943
- import { User } from './User.ts'
2944
- import { Phone } from './Phone.ts'
2945
-
2946
- const users = await new User().where('id',1).findMany() ✅
2947
- const users = await new User().where('idxx',1).findMany() ❌
2948
-
2949
- const users = await new User().where('id',1).orWhere('id',5).findMany() ✅
2950
- const users = await new User().where('id',1).orWhere('idxx',5).findMany() ❌
2951
-
2952
- const users = await new User().whereIn('id',[1]).findMany() ✅
2953
- const users = await new User().whereIn('idx',[1]).findMany() ❌
2954
-
2955
- const users = await new User().whereNull('id').findMany() ✅
2956
- const users = await new User().whereNull('idx').findMany() ❌
2957
-
2958
- const users = await new User().whereNotNull('id').findMany()
2959
- const users = await new User().whereNotNull('idx').findMany()
2960
-
2961
- const users = await new User().whereBetween('id',[1,2]).findMany() ✅
2962
- const users = await new User().whereBetween('idx',[1,2]).findMany() ❌
2963
-
2964
- const users = await new User()
2965
- .whereSubQuery(
2966
- 'id',
2967
- new User().select('id').toString()
2968
- ).findMany() ✅
2969
-
2970
- const users = await new User()
2971
- .whereSubQuery(
2972
- 'idx',
2973
- new User().select('id').toString()
2974
- ).findMany() ❌
2975
-
2976
- ```
2977
-
2978
- ### Type Safety Insert
2979
-
2980
- ```js
2981
- import { User } from './User.ts'
2982
- import { Phone } from './Phone.ts'
2983
-
2984
- const users = await new User().create({ id : 10 }).save() ✅
2985
-
2986
- const users = await new User().create({ id : "10" }).save() ❌
2987
-
2988
- const users = await new User().create({ idx : 10 }).save() ❌
2989
-
2990
- ```
2991
-
2992
- ### Type Safety Update
2993
-
2994
- ```js
2995
- import { User } from './User.ts'
2996
- import { Phone } from './Phone.ts'
2997
-
2998
- const users = await new User().update({ id : 10 }).where('id',1).save() ✅
2999
- const users = await new User().update({ id : 10 }).where('idx',1).save() ❌
3000
- const users = await new User().update({ id : "10" }).where('id',1).save() ❌
3001
- const users = await new User().update({ idx : 10 }).where('idx',1).save() ❌
3002
-
3003
- ```
3004
-
3005
- ### Type Safety Delete
3006
-
3007
- ```js
3008
- import { User } from './User.ts'
3009
- import { Phone } from './Phone.ts'
3010
-
3011
- const users = await new User().where('id',1).delete() ✅
3012
- const users = await new User().where('idx',1).delete() ❌
3013
-
3014
- ```
3015
-
3016
- ### Type Safety Relationships
3017
-
3018
- ```js
3019
- import { type T } from 'tspace-mysql'
3020
- import { User } from './User.ts'
3021
- import { Phone } from './Phone.ts'
3022
- // Case #1 : Relationship with 2 relations 'phone' and 'phones'
3023
- const users = await new User()
3024
- .relations('phone','phones')
3025
- .findMany()
3026
-
3027
- for(const user of users) {
3028
- user.phone ❌
3029
- user.phones ❌
3030
- }
3031
-
3032
- // You can also specify the type for the results.
3033
- // bad 👎👎👎
3034
- const users = await new User()
3035
- .relations('phone','phones')
3036
- .findMany<{ phone : Record<string,any> , phones : any[]}>()
3037
-
3038
- for(const user of users) {
3039
- user.phone ✅
3040
- user.phones ✅
3041
- user.phone.id ✅
3042
- user.phone.idx ✅💩💩💩
3043
- user.phones.map(phone => phone.id) ✅
3044
- user.phones.map(phone => phone.idx) ✅💩💩💩
3045
- }
3046
-
3047
- // good 👍👍👍
3048
- const users = await new User()
3049
- .relations('phone','phones')
3050
- .findMany<{ phone : T.SchemaModel<Phone> , phones : T.SchemaModel<Phone>[] }>()
3051
-
3052
- for(const user of users) {
3053
- user.phone ✅
3054
- user.phones ✅
3055
- user.phone?.id ✅
3056
- user.phone?.idx ❌
3057
- user.phones.map(phone => phone?.id) ✅
3058
- user.phones.map(phone => phone?.idx) ❌
3059
- }
3060
-
3061
- +--------------------------------------------------------------------------+
3062
-
3063
- // Case #2 : There is a relationship between two entities, 'phone' and 'phones', both of which are related to the 'user' entity through nested relations
3064
- const users = await new User()
3065
- .relations('phone','phones')
3066
- .relationQuery('phone' , (query : Phone) => query.relations('user'))
3067
- .relationQuery('phones' , (query : Phone) => query.relations('user'))
3068
- .findMany<{ phone : T.SchemaModel<Phone> , phones : T.SchemaModel<Phone>[] }>()
3069
-
3070
- for(const user of users) {
3071
- user.phone.user ❌
3072
- user.phones.map(phone =>phone.user) ❌
3073
- }
3074
-
3075
- // You can also specify the type for the results.
3076
- // bad 👎👎👎
3077
- const users = await new User()
3078
- .relations('phone','phones')
3079
- .relationQuery('phone' , (query : Phone) => query.relations('user'))
3080
- .relationQuery('phones' , (query : Phone) => query.relations('user'))
3081
- .findMany<{ phone : Record<string,any> , phones : Record<string,any>[] }>()
3082
-
3083
- for(const user of users) {
3084
- user.phone.user ✅💩💩💩
3085
- user.phones.map(phone =>phone.user) ✅💩💩💩
3086
- user.phone.user.idx ✅💩💩💩
3087
- user.phones.map(phone =>phone.user.idx) ✅💩💩💩
3088
- }
3089
-
3090
- // good 👍👍👍
3091
- const users = await new User()
3092
- .relations('phone','phones')
3093
- .relationQuery('phone' , (query : Phone) => query.relations('user'))
3094
- .relationQuery('phones' , (query : Phone) => query.relations('user'))
3095
- .findMany<{
3096
- phone : Partial<T.SchemaModel<Phone>> & { user : T.SchemaModel<User>};
3097
- phones : (Partial<T.SchemaModel<Phone>> & { user : T.SchemaModel<User>})[];
3098
- }>()
3099
-
3100
- for(const user of users) {
3101
- user.phone.user ✅
3102
- user.phone.user.id ✅
3103
- user.phone.userx ❌
3104
- user.phone.user.idx ❌
3105
- user.phones.map(phone =>phone.user.id) ✅
3106
- user.phones.map(phone =>phone.user.idx) ❌
3107
- }
3108
-
3109
- +--------------------------------------------------------------------------+
3110
- // If you don't want to set types for every returning method such as 'findOne', 'findMany', and so on...
3111
-
3112
- import { Model , Blueprint , type T } from 'tspace-mysql'
3113
- import { Phone } from '../Phone'
3114
-
3115
- const schemaUser = {
3116
- id :Blueprint.int().notNull().primary().autoIncrement(),
3117
- uuid :Blueprint.varchar(50).null(),
3118
- email :Blueprint.varchar(50).null(),
3119
- name :Blueprint.varchar(255).null(),
3120
- username :Blueprint.varchar(255).null(),
3121
- password :Blueprint.varchar(255).null(),
3122
- createdAt :Blueprint.timestamp().null(),
3123
- updatedAt :Blueprint.timestamp().null()
3124
- }
3125
-
3126
- type TSchemaUser = T.SchemaStatic<typeof schemaUser>
3127
-
3128
- type TRelationUser = T.Relation<{
3129
- phones : Phone[]
3130
- phone : Phone
3131
- }>
3132
-
3133
- // Add this '<TSchemaUser, RelationUserType>' to activate the type for the Model.
3134
- class User extends Model< TSchemaUser, TRelationUser > {
3135
- constructor() {
3136
- super()
3137
- this.useSchema(schemaUser)
3138
- this.hasOne({ model : Phone, name : 'phonex' }) ❌
3139
- this.hasMany({ model : Phone, name : 'phonesx' }) ❌
3140
- this.hasOne({ model : Phone, name : 'phone' }) ✅
3141
- this.hasMany({ model : Phone, name : 'phones' }) ✅
3142
- }
3143
- }
3144
-
3145
- export { User }
3146
-
3147
- +--------------------------------------------------------------------------+
3148
-
3149
- // in file Phone.ts
3150
- import { Model , Blueprint , type T } from 'tspace-mysql'
3151
- import { User } from './User.ts'
3152
-
3153
- const schemaPhone = {
3154
- id :Blueprint.int().notNull().primary().autoIncrement(),
3155
- uuid :Blueprint.varchar(50).null(),
3156
- userId :Blueprint.int().notNull(),
3157
- number :Blueprint.varchar(50).notNull(),
3158
- createdAt :Blueprint.timestamp().null(),
3159
- updatedAt :Blueprint.timestamp().null()
3160
- }
3161
-
3162
- type TSchemaPhone = T.Schema<typeof schemaPhone>
3163
-
3164
- type TRelationPhone = T.Relation<{
3165
- user : User[]
3166
- }>
3167
-
3168
- class Phone extends Model<TSchemaPhone,TRelationPhone> {
3169
- constructor() {
3170
- super()
3171
- this.useSchema(schemaPhone)
3172
- this.useBelongsTo({ model : User, name : 'userx'}) ❌
3173
- this.useBelongsTo({ model : User, name : 'user'}) ✅
3174
- }
3175
- }
3176
-
3177
- export { Phone }
3178
-
3179
- +--------------------------------------------------------------------------+
3180
-
3181
- const users = await new User()
3182
- .relations('phonex','phonesx') ❌
3183
- .relationQuery('phonex' ❌ , (query : Phone) => query.relations('user')) ✅
3184
- .relationQuery('phonesx' ❌ , (query : Phone) => query.relations('user')) ✅
3185
- .findMany()
3186
-
3187
- const users = await new User()
3188
- .relations('phone','phones') ✅
3189
- .relationQuery('phonex' ❌ , (query : Phone) => query.relations('user')) ✅
3190
- .relationQuery('phonesx' ❌ , (query : Phone) => query.relations('user')) ✅
3191
- .findMany()
3192
-
3193
- const users = await new User()
3194
- .relations('phone','phones')
3195
- .relationQuery('phone' , (query : Phone) => query.relations('userx')) ❌
3196
- .relationQuery('phones' , (query : Phone) => query.relations('userx')) ❌
3197
- .findMany()
3198
-
3199
- const users = await new User()
3200
- .relations('phone','phones') ✅
3201
- .relationQuery('phone' ✅ , (query : Phone) => query.relations('user')) ✅
3202
- .relationQuery('phones'✅ , (query : Phone) => query.relations('user')) ✅
3203
- .findMany()
3204
-
3205
- for(const user of users) {
3206
- user.phone.user ❌
3207
- user.phone?.user ✅
3208
- user.phone?.user.id ✅
3209
- user.phone?.userx ❌
3210
- user.phone?.user.idx ❌
3211
- user.phones.map(phone =>phone?.user.id) ❌
3212
- user.phones?.map(phone =>phone?.user.id) ✅
3213
- user.phones?.map(phone =>phone?.user.idx) ❌
3214
- }
3215
-
3216
- ```
3217
-
3218
- ## Type Safety Results
3219
- ```js
3220
- import { type T } from 'tspace-mysql'
3221
-
3222
- const fError = async () : Promise<T.Results<User>[]> => {
3223
-
3224
- const users = [{
3225
- id : 1,
3226
- uuid: "12d4f08a-a20d-4f41-abac-81391e135d60",
3227
- email: "tspace@example.com"
3228
- }]
3229
-
3230
- return users // ❌
3231
- }
3232
-
3233
- const fCorrect = async () : Promise<T.Results<User>[]> => {
3234
-
3235
- const users = await new User().findMany()
3236
-
3237
- return users // ✅
3238
- }
3239
-
3240
- ```
3241
-
3242
- ## Metadata
3243
- Get the metadata of a Model works only when a schema is added to the Model.
3244
-
3245
- ```js
3246
- import { Meta, Model , Blueprint , type T } from 'tspace-mysql';
3247
-
3248
- const schema = {
3249
- id : Blueprint.int().notNull().primary().autoIncrement(),
3250
- uuid : Blueprint.varchar(50).null(),
3251
- email : Blueprint.varchar(255).notNull().index('users.email@index'),
3252
- name : Blueprint.varchar(255).null(),
3253
- username : Blueprint.varchar(255).notNull(),
3254
- password : Blueprint.varchar(255).notNull(),
3255
- status : Blueprint.tinyInt().notNull().default(0),
3256
- createdAt : Blueprint.timestamp().null(),
3257
- updatedAt : Blueprint.timestamp().null()
3258
- }
3259
-
3260
- type TS = T.Schema<typeof schema>
3261
-
3262
- class User extends Model<TS> {
3263
- constructor() {
3264
- super()
3265
- this.useSchema(schema)
3266
- this.useUUID()
3267
- this.useTimestamp()
3268
- }
3269
- }
3270
-
3271
- const meta = Meta(User)
3272
-
3273
- const table = meta.table() // 'users'
3274
- const column = meta.column('id') // 'id'
3275
- const columnRef = meta.columnReference('id') // `users`.`id`
3276
- const columnTypeOf = meta.columnTypeOf('id') // number
3277
- const columnType = meta.columnType('id') // Int
3278
- const columns = meta.columns() // ['id','uuid',...'updatedAt']
3279
- const hasColumn = meta.hasColumn('idx') // false
3280
- const primaryKey = meta.primaryKey() // 'id'
3281
- const indexes = meta.indexes() // ['users.email@index']
3282
- const nullable = meta.nullable() // ['uuid','name','createdAt','updatedAt']
3283
- const defaults = meta.defaults() // { status : 0 }
3284
-
3285
- console.log({
3286
- table,
3287
- column,
3288
- columnRef,
3289
- columnTypeOf,
3290
- columnType,
3291
- columns,
3292
- hasColumn,
3293
- primaryKey,
3294
- indexes,
3295
- nullable,
3296
- defaults
3297
- })
3298
-
3299
- ```
3300
-
3301
- ## Repository
3302
- ```js
3303
- Repository is a mechanism that encapsulates all database operations related to a specific model.
3304
- It provides methods for querying, inserting, updating, and deleting records in the database associated with the model.
3305
-
3306
- ** The Repository check always type Type Safety if model is used the type of schema
3307
-
3308
- ```
3309
- ### Repository Select Statements
3310
- ```js
3311
- import { Repository, OP , type T } from 'tspace-mysql'
3312
- import { User } from '../Models/User'
3313
-
3314
- const userRepository = Repository(User)
3315
- const needPhone = true
3316
- const user = await userRepository.findOne({
3317
- select : {
3318
- id : true,
3319
- name : true,
3320
- username : true,
3321
- phone : {
3322
- id : true,
3323
- name : true,
3324
- user_id : true,
3325
- }
3326
- },
3327
- where : {
3328
- id: 1
3329
- },
3330
- when : {
3331
- condition : needPhone,
3332
- query: () => ({
3333
- relations : {
3334
- phone : true
3335
- /**
3336
- You can also specify the phone with any methods of the repository
3337
- phone : {
3338
- where : {
3339
- id : 41
3340
- },
3341
- select : {
3342
- id : true,
3343
- user_id : true
3344
- }
3345
- }
3346
- */
3347
- }
3348
- })
3349
- }
3350
- })
3351
-
3352
- const users = await userRepository.findMany({
3353
- select : {
3354
- id : true,
3355
- name : true,
3356
- username : true,
3357
- },
3358
- limit : 3,
3359
- orderBy : {
3360
- id : 'ASC',
3361
- name : 'DESC'
3362
- }
3363
- groupBy : ['id'],
3364
- where : {
3365
- id: OP.in([1,2,3])
3366
- }
3367
- })
3368
-
3369
- const userPaginate = await userRepository.pagination({
3370
- select : {
3371
- id : true,
3372
- name : true,
3373
- username : true,
3374
- },
3375
- page : 1,
3376
- limit : 3,
3377
- where : {
3378
- id: OP.in([1,2,3])
3379
- }
3380
- })
3381
-
3382
- const findFullName = await userRepository.findOne({
3383
- select : {
3384
- name : true,
3385
- [`${DB.raw('CONCAT(firstName," ",lastName) as fullName')}`]: true
3386
- }
3387
- whereRaw : [
3388
- `CONCAT(firstName," ",lastName) LIKE '%${search}%'`
3389
- ]
3390
- })
3391
- ```
3392
- ### Repository Insert Statements
3393
- ```js
3394
-
3395
- const userRepository = Repository(User)
3396
-
3397
- const created = await userRepository.create({
3398
- data : {
3399
- name : "repository-name",
3400
- // ....
3401
- }
3402
- })
3403
-
3404
- const createdMultiple = await u.createMultiple({
3405
- data : [
3406
- {
3407
- name: "tspace4",
3408
- // ....
3409
- },
3410
- {
3411
- name: "tspace5",
3412
- // ....
3413
- },
3414
- {
3415
- name: "tspace6",
3416
- // ....
3417
- }
3418
- // ....
3419
- ]
3420
- })
3421
-
3422
- const createdNotExists = await userRepository.createNotExists({
3423
- data : {
3424
- name : "repository-name",
3425
- // ....
3426
- },
3427
- where : {
3428
- id : 1
3429
- }
3430
- })
3431
-
3432
- const createdOrSelected = await userRepository.createOrSelect({
3433
- data : {
3434
- name : "repository-name",
3435
- // ....
3436
- },
3437
- where : {
3438
- id : 1
3439
- }
3440
- })
3441
-
3442
-
3443
- ```
3444
- ### Repository Update Statements
3445
- ```js
3446
-
3447
- const userRepository = Repository(User)
3448
-
3449
- const updated = await userRepository.update({
3450
- data : {
3451
- name : "repository-name",
3452
- // ....
3453
- },
3454
- where : {
3455
- id : 1
3456
- }
3457
- })
3458
-
3459
- ```
3460
- ### Repository Delete Statements
3461
- ```js
3462
-
3463
- const userRepository = Repository(User)
3464
-
3465
- const deleted = await userRepository.delete({
3466
- where : {
3467
- id : 1
3468
- }
3469
- })
3470
-
3471
- ```
3472
-
3473
- ### Repository Transactions
3474
-
3475
- ```js
3476
- import { DB , Repository } from 'tspace-mysql'
3477
- import { User } from '../Models/User'
3478
- const userRepository = Repository(User)
3479
-
3480
- const transaction = await DB.beginTransaction()
3481
-
3482
- try {
3483
- await transaction.startTransaction()
3484
-
3485
- const created = await userRepository.create({
3486
- data : {
3487
- name : "repository-name",
3488
- // ....
3489
- },
3490
- transaction // add this for the transaction
3491
- })
3492
-
3493
- const updated = await userRepository.update({
3494
- data : {
3495
- name : "repository-name",
3496
- // ....
3497
- },
3498
- where : {
3499
- id : created.id
3500
- },
3501
- transaction
3502
- })
3503
-
3504
- // after your use commit if use same transction for actions this transction will auto commit
3505
- await transaction.commit()
3506
-
3507
- // ensure the nothing with transction just use end of transction
3508
- await transaction.end();
3509
-
3510
- } catch (err) {
3511
-
3512
- await transaction.rollback()
3513
- }
3514
-
3515
- ```
3516
-
3517
- ### Repository Relations
3518
- ```js
3519
- import { Repository , OP } from 'tspace-mysql'
3520
- import { User } from '../Models/User'
3521
- import { Phone } from '../Models/Phone'
3522
-
3523
- const userRepository = Repository(User)
3524
-
3525
- const userHasPhones = await userRepository.findOne({
3526
- select : {
3527
- id : true,
3528
- name : true,
3529
- username : true,
3530
- phone : {
3531
- id : true,
3532
- user_id : true,
3533
- name: true
3534
- }
3535
- },
3536
- where : {
3537
- id: 1
3538
- },
3539
- relations: {
3540
- phone: {
3541
- user : true
3542
- }
3543
- }
3544
- });
3545
-
3546
- const phoneRepository = Repository(Phone)
3547
-
3548
- const phoneBelongUser = await phoneRepository.findOne({
3549
- select : '*',
3550
- where : {
3551
- id: 1
3552
- },
3553
- relations : {
3554
- user : true
3555
- }
3556
- })
3557
-
3558
- ```
3559
-
3560
- ## View
3561
-
3562
- Your database schema can also use views. These views are represented by classes that behave similarly to models,
3563
- but they are based on stored SQL queries instead of actual tables.
3564
- Let's look at a basic view class example:
3565
- ```js
3566
-
3567
- import { type T, Blueprint, Model , View , Meta } from 'tspace-mysql'
3568
-
3569
- const schemaUser = {
3570
- id: Blueprint.int().notNull().primary().autoIncrement(),
3571
- uuid: Blueprint.varchar(50).null().index(),
3572
- name: Blueprint.varchar(191).notNull(),
3573
- email: Blueprint.varchar(191).notNull()
3574
- }
3575
-
3576
- type TUser = T.Schema<typeof schemaUser>
3577
-
3578
- class User extends Model<TUser> {
3579
- protected boot(): void {
3580
- this.useSchema(schemaUser)
3581
- }
3582
- }
3583
-
3584
- const schemaPost = {
3585
- id: Blueprint.int().notNull().primary().autoIncrement(),
3586
- uuid: Blueprint.varchar(50).null().index(),
3587
- user_id :Blueprint.int().notnull(),
3588
- title: Blueprint.varchar(191).notNull(),
3589
- content: Blueprint.varchar(191).notNull()
3590
- }
3591
-
3592
- type TPost = T.Schema<typeof schemaPost>
3593
-
3594
- class Post extends Model<TPost> {
3595
- protected boot(): void {
3596
- this.useSchema(schemaPost)
3597
- }
3598
- }
3599
-
3600
- const schemaUserPostCountView = {
3601
- id :Blueprint.int().notNull().primary().autoIncrement(),
3602
- user_id :Blueprint.int().notnull(),
3603
- name :Blueprint.varchar(255).null(),
3604
- post_count : Blueprint.int().notnull()
3605
- }
3606
-
3607
- type TSUserPostCountView = T.Schema<typeof schemaUserPostCountView>
3608
- type TRUserPostCountView = T.Relation<{
3609
- user: User
3610
- }>
3611
-
3612
- class UserPostCountView extends View<TSUserPostCountView,TRUserPostCountView> {
3613
-
3614
- protected boot(): void {
3615
- this.useSchema(schemaUserPostCountView)
3616
- const metaUser = Meta(User)
3617
- const metaPost = Meta(Post)
3618
-
3619
- this.createView({
3620
- synchronize: true,
3621
- expression : new User()
3622
- .selectRaw(`ROW_NUMBER() OVER (ORDER BY ${metaUser.columnRef('id')}) AS id`)
3623
- .selectRaw(`${metaUser.columnRef('id')} AS user_id`)
3624
- .selectRaw(metaUser.columnRef('name'))
3625
- .select(metaUser.columnRef('email'))
3626
- .selectRaw(`COUNT(${metaPost.columnRef('id')}) AS post_count`)
3627
- .leftJoin(metaUser.columnRef('id'),metaPost.columnRef('user_id'))
3628
- .groupBy(metaUser.columnRef('id'))
3629
- .groupBy(metaUser.columnRef('name'))
3630
- .toString()
3631
-
3632
- // Look like this
3633
- // expression :
3634
- // SELECT
3635
- // ROW_NUMBER() OVER (ORDER BY `users`.`id`) AS id,
3636
- // `users`.`id` AS user_id, `users`.`name`, `users`.`email`,
3637
- // COUNT(`posts`.`id`) AS post_count
3638
- // FROM `users`
3639
- // LEFT JOIN `posts` ON `users`.`id` = `posts`.`user_id`
3640
- // GROUP BY `users`.`id`, `users`.`name`
3641
- })
3642
-
3643
- this.belongsTo({ name : 'user' , model : User })
3644
- }
3645
- }
3646
-
3647
- new UserPostCountView()
3648
- .with('user')
3649
- .get()
3650
- .then( v=> {
3651
- console.log(v)
3652
- })
3653
-
3654
- ```
3655
-
3656
- ## Stored Procedure
3657
- StoredProcedure is a predefined set of SQL statements stored in the database that you can call (execute) by name.
3658
- ```js
3659
-
3660
- import { StoredProcedure } from 'tspace-mysql'
3661
-
3662
- type T = {
3663
- AddUser: {
3664
- params: {
3665
- name : string;
3666
- email: string;
3667
- } | [string,string];
3668
- result: {
3669
- fieldCount: number;
3670
- affectedRows: number;
3671
- insertId: number;
3672
- info: string;
3673
- serverStatus: number;
3674
- warningStatus: number;
3675
- changedRows: number;
3676
- }
3677
- };
3678
- GetUser: {
3679
- params: [number];
3680
- result: any[]
3681
- },
3682
- GetUsers: {
3683
- params: [];
3684
- result: any[]
3685
- }
3686
- };
3687
-
3688
- class MyStoreProcedure extends StoredProcedure<T> {
3689
- protected boot(): void {
3690
-
3691
- this.createProcedure({
3692
- name: 'AddUser',
3693
- expression: `
3694
- CREATE PROCEDURE AddUser(IN name VARCHAR(255), IN email VARCHAR(255))
3695
- BEGIN
3696
- INSERT INTO users (name, email) VALUES (name, email);
3697
- END;
3698
- `,
3699
- synchronize: true
3700
- });
3701
-
3702
- this.createProcedure({
3703
- name: 'GetUsers',
3704
- expression: `
3705
- CREATE PROCEDURE GetUsers()
3706
- BEGIN
3707
- SELECT * FROM users LIMIT 5;
3708
- END;
3709
- `,
3710
- synchronize: true
3711
- });
3712
-
3713
- this.createProcedure({
3714
- name: 'GetUser',
3715
- expression: `
3716
- CREATE PROCEDURE GetUser(IN userId INT)
3717
- BEGIN
3718
- SELECT * FROM users WHERE id = userId LIMIT 1;
3719
- END;
3720
- `,
3721
- synchronize: true
3722
- })
3723
- }
3724
- }
3725
-
3726
- const storeProcedure = new MyStoreProcedure()
3727
-
3728
- storeProcedure.call('AddUser', { name : 'tspace-mysql' , email : 'tspace-mysql@example.com'})
3729
- .then(r => console.log(r))
3730
- .catch(e => console.log(e))
3731
-
3732
- storeProcedure.call('GetUser',[1])
3733
- .then(r => console.log(r))
3734
- .catch(e => console.log(e))
3735
-
3736
- storeProcedure.call('GetUsers',[])
3737
- .then(r => console.log(r))
3738
- .catch(e => console.log(e))
3739
-
3740
- ```
3741
- ## Blueprint
3742
-
3743
- Blueprint is a tool used for defining database schemas programmatically.
3744
- It allows developers to describe the structure of their database tables using a simple and intuitive syntax rather than writing SQL queries directly., you may use the:
3745
-
3746
- ```js
3747
- import { Schema , Blueprint , DB } from 'tspace-mysql'
3748
- (async () => {
3749
- await new Schema().table('users', {
3750
- id : Blueprint.int().notNull().primary().autoIncrement(),
3751
- // or id : Blueprint.serial().primary(),
3752
- uuid : Blueprint.varchar(120).null()
3753
- name : Blueprint.varchar(120).default('name'),
3754
- email : Blueprint.varchar(255).unique().notNull(),
3755
- email_verify : Blueprint.tinyInt(),
3756
- password : Blueprint.varchar(255),
3757
- json : Blueprint.json(),
3758
- created_at : Blueprint.null().timestamp(),
3759
- updated_at : Blueprint.null().timestamp(),
3760
- deleted_at : Blueprint.null().timestamp()
3761
- })
3762
- /**
3763
- *
3764
- * @Faker fake data 5 raw
3765
- * await new DB().table('users').faker(5)
3766
- */
3767
- })()
3768
-
3769
- /**
3770
- * To add types of the schema to the database
3771
- * @Types
3772
- *
3773
- */
3774
- int (number)
3775
- tinyInt (number)
3776
- bigInt (number)
3777
- double ()
3778
- float ()
3779
- json ()
3780
- varchar (number)
3781
- char (number)
3782
- longText()
3783
- mediumText()
3784
- tinyText()
3785
- text()
3786
- enum(...n)
3787
- date()
3788
- dateTime()
3789
- timestamp ()
3790
-
3791
- /**
3792
- * To add attributes of the schema to the database
3793
- * @Attrbuites
3794
- *
3795
- */
3796
- unsigned()
3797
- unique()
3798
- null()
3799
- notNull()
3800
- primary()
3801
- default(string)
3802
- defaultTimestamp()
3803
- autoIncrement()
3804
-
3805
- /**
3806
- * To add a foreign key to the column
3807
- * @ForeginKey
3808
- */
3809
- foreign({ references : ${COLUMN} , on : ${TABLE-NAME OR MODEL CLASSES} })
3810
-
3811
- /**
3812
- * To add a index key to the column
3813
- * @indexKey
3814
- */
3815
- index()
3816
- ```
3817
-
3818
- ## Cli
3819
-
3820
- To get started, let's install tspace-mysql
3821
- you may use a basic cli :
3822
-
3823
- ```sh
3824
- npm install tspace-mysql -g
3825
-
3826
- ```
3827
-
3828
- ## Make Model
3829
-
3830
- The command will be placed Model in the specific directory.
3831
-
3832
- ```sh
3833
-
3834
- /**
3835
- *
3836
- * @make Model
3837
- * @options
3838
- * @arg --m => created scheme table for migrate. short cut migration table like Make Migration
3839
- * @arg --dir=directory => created model in directory. default root directory
3840
- * @arg --type=js // extension js. default ts
3841
- */
3842
- tspace-mysql make:model <model name> --m --dir=.... --type=....
3843
-
3844
- tspace-mysql make:model User --m --dir=app/Models
3845
- /**
3846
- *
3847
- * @Ex directory
3848
- */
3849
- - node_modules
3850
- - app
3851
- - Models
3852
- User.ts
3853
- ```
3854
-
3855
- ## Make Migration
3856
-
3857
- The command will be placed Migration in the specific directory.
3858
-
3859
- ```sh
3860
- /**
3861
- *
3862
- * @make Migration Table
3863
- * @options
3864
- * @arg --dir=directory => created scheme table in directory. default root directory
3865
- * @arg --type=js // extension js default ts
3866
- */
3867
- tspace-mysql make:migration <table name> --type=... --dir=....
3868
-
3869
- tspace-mysql make:migration users --dir=app/Models/Migrations
3870
- /**
3871
- *
3872
- * @Ex directory
3873
- */
3874
- - node_modules
3875
- - app
3876
- - Models
3877
- - Migrations
3878
- create_users_table.ts
3879
- User.ts
3880
- ```
3881
-
3882
- ## Migrate
3883
-
3884
- ```sh
3885
- /**
3886
- *
3887
- * @run Migrate table
3888
- * @options
3889
- * @arg --dir=directory => find migrate in directory. default find in root folder
3890
- * @arg --type=js // extension js default ts
3891
- */
3892
- tspace-mysql migrate <folder> --type=<type file js or ts> --dir=<directory for migrate>
3893
-
3894
- tspace-mysql migrate --dir=app/Models/Migrations --type=js
3895
-
3896
- /**
3897
- *
3898
- * @Ex directory
3899
- */
3900
- - node_modules
3901
- - app
3902
- - Models
3903
- - Migrations
3904
- create_users_table.ts
3905
- create_posts_table.ts
3906
- User.ts
3907
- Post.ts
3908
- // => migrate all schemas in folder <Migrations>. created into database
3909
- ```
3910
-
3911
- # Query
3912
-
3913
- The command will execute a query.
3914
-
3915
- ```sh
3916
- tspace-mysql query "SELECT * FROM users"
3917
-
3918
- ```
3919
-
3920
- # Dump
3921
-
3922
- The command will dump the database or table into a file.
3923
-
3924
- ```sh
3925
- tspace-mysql dump:db --dir=<folder for dump> --values // backup with values in the tables
3926
-
3927
- tspace-mysql dump:table "table_name" --dir=<folder for dump> --values // backup with values in the table
3928
-
3929
- ```
3930
-
3931
- # Generate Models
3932
-
3933
- The command will generate models from tables in the database.
3934
-
3935
- ```sh
3936
- tspace-mysql generate:models --dir=<folder for creating>
3937
-
3938
- tspace-mysql generate:models --dir=app/Models --env=development --decorators
3939
-
3940
- ```
3941
-
3942
- # Migration Models
3943
-
3944
- The command will generate migrations based on the schema in your models to a .sql file,
3945
- can also push the migration files to the database.
3946
-
3947
- ```sh
3948
- /**
3949
- *
3950
- * @arg --push will push the migration files to the database
3951
- * @arg --generate will generate the migration files
3952
- */
3953
- tspace-mysql migrations:models --dir=<path-to-migration> --models=<path to your models> --generate
3954
- tspace-mysql migrations:models --dir=<path-to-migration> --push
3955
-
3956
- tspace-mysql migrations:models --models=src/app/models --dir=migrations --generate
3957
- tspace-mysql migrations:models --dir=migrations --push
3958
-
3959
- ```
3960
-
3961
- # Migration DB
3962
-
3963
- The command will generate migrations based on the schema in your database to a .sql file,
3964
- can also push the migration files to the database.
3965
-
3966
- ```sh
3967
- /**
3968
- *
3969
- * @arg --push will push the migration files to the database
3970
- * @arg --generate will generate the migration files
3971
- */
3972
- tspace-mysql migrations:db --dir=<path-to-migration> --generate --env=<YOUR_ENV> -filename=<YOUR_FILENAME>
3973
- tspace-mysql migrations:db --dir=<path-to-migration> --push
3974
-
3975
- tspace-mysql migrations:db --dir=migrations --generate --filename=dump.sql --env=development
3976
- tspace-mysql migrations:db --dir=migrations --push --filename=dump.sql --env=development
3977
-
3978
- ```
58
+ - [Getting Started](https://thanathip41.github.io/tspace-mysql/#/)
59
+ - [Install](https://thanathip41.github.io/tspace-mysql/#/?id=install)
60
+ - [Configuration](https://thanathip41.github.io/tspace-mysql/#/?id=configuration)
61
+ - [SQL Like](https://thanathip41.github.io/tspace-mysql/#/sql-like)
62
+ - [Select Statements](https://thanathip41.github.io/tspace-mysql/#/sql-like?id=select-statements)
63
+ - [Insert Statements](https://thanathip41.github.io/tspace-mysql/#/sql-like?id=insert-statements)
64
+ - [Update Statements](https://thanathip41.github.io/tspace-mysql/#/sql-like?id=update-statements)
65
+ - [Delete Statements](https://thanathip41.github.io/tspace-mysql/#/sql-like?id=delete-statements)
66
+ - [Query Builder](https://thanathip41.github.io/tspace-mysql/#/query-builder)
67
+ - [Table Name & Alias Name](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=table-name--alias-name)
68
+ - [Returning Results](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=returning-results)
69
+ - [Query Statement](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=query-statements)
70
+ - [Select Statements](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=select-statements)
71
+ - [Insert Statements](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=insert-statements)
72
+ - [Update Statements](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=update-statements)
73
+ - [Delete Statements](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=delete-statements)
74
+ - [Raw Expressions](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=raw-expressions)
75
+ - [Ordering, Grouping, Limit and Offset](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=ordering-grouping-limit-and-offset)
76
+ - [Ordering](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=ordering)
77
+ - [Grouping](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=grouping)
78
+ - [Limit and Offset](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=limit-and-offset)
79
+ - [Joins](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=joins)
80
+ - [Inner Join Clause](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=inner-join-clause)
81
+ - [Left Join, Right Join Clause](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=left-join-right-join-clause)
82
+ - [Cross Join Clause](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=cross-join-clause)
83
+ - [Basic Where Clauses](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=basic-where-clauses)
84
+ - [Where Clauses](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=where-clauses)
85
+ - [Or Where Clauses](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=or-where-clauses)
86
+ - [Where cases](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=where-cases)
87
+ - [Where Object Clauses](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=where-object-clauses)
88
+ - [JSON Where Clauses](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=json-where-clauses)
89
+ - [Additional Where Clauses](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=additional-where-clauses)
90
+ - [Logical Grouping](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=logical-grouping)
91
+ - [Advanced Where Clauses](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=advanced-where-clauses)
92
+ - [Where Exists Clauses](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=where-exists-clauses)
93
+ - [Subquery Where Clauses](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=subquery-where-clauses)
94
+ - [Conditional Where Clauses](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=conditional-where-clauses)
95
+ - [GetGroupBy](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=getgroupby)
96
+ - [Paginating](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=paginating)
97
+ - [Hook Statements](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=hook-statements)
98
+ - [Faker Statements](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=faker-statements)
99
+ - [Unset Statements](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=unset-statements)
100
+ - [Common Table Expressions](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=common-table-expressions)
101
+ - [Union](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=union)
102
+ - [More Methods](https://thanathip41.github.io/tspace-mysql/#/query-builder?id=more-methods)
103
+ - [Database Transactions](https://thanathip41.github.io/tspace-mysql/#/database-transactions)
104
+ - [Race Condition](https://thanathip41.github.io/tspace-mysql/#/race-condition)
105
+ - [Connection](https://thanathip41.github.io/tspace-mysql/#/connection)
106
+ - [Backup](https://thanathip41.github.io/tspace-mysql/#/backup)
107
+ - [Injection](https://thanathip41.github.io/tspace-mysql/#/injection)
108
+ - [Model](https://thanathip41.github.io/tspace-mysql/#/model)
109
+ - [Basic Model Setup](https://thanathip41.github.io/tspace-mysql/#/model?id=basic-model-setup)
110
+ - [Table Name](https://thanathip41.github.io/tspace-mysql/#/model?id=table-name)
111
+ - [Pattern](https://thanathip41.github.io/tspace-mysql/#/model?id=pattern)
112
+ - [UUID](https://thanathip41.github.io/tspace-mysql/#/model?id=uuid)
113
+ - [Timestamp](https://thanathip41.github.io/tspace-mysql/#/model?id=timestamp)
114
+ - [Debug](https://thanathip41.github.io/tspace-mysql/#/model?id=debug)
115
+ - [Observer](https://thanathip41.github.io/tspace-mysql/#/model?id=observer)
116
+ - [Logger](https://thanathip41.github.io/tspace-mysql/#/model?id=logger)
117
+ - [Hooks](https://thanathip41.github.io/tspace-mysql/#/model?id=hooks)
118
+ - [Global Scope](https://thanathip41.github.io/tspace-mysql/#/model?id=global-scope)
119
+ - [Schema](https://thanathip41.github.io/tspace-mysql/#/model?id=schema)
120
+ - [Schema Model](https://thanathip41.github.io/tspace-mysql/#/model?id=schema-model)
121
+ - [Virtual Column](https://thanathip41.github.io/tspace-mysql/#/model?id=virtual-column)
122
+ - [Validation](https://thanathip41.github.io/tspace-mysql/#/model?id=validation)
123
+ - [Sync](https://thanathip41.github.io/tspace-mysql/#/model?id=sync)
124
+ - [SoftDelete](https://thanathip41.github.io/tspace-mysql/#/model?id=softdelete)
125
+ - [Joins Model](https://thanathip41.github.io/tspace-mysql/#/model?id=joins-model)
126
+ - [Inner Join Model Clause](https://thanathip41.github.io/tspace-mysql/#/model?id=inner-join-model-clause)
127
+ - [Left Join , Right Join Model Clause](https://thanathip41.github.io/tspace-mysql/#/model?id=left-join-right-join-model-clause)
128
+ - [Cross Join Model Clause](https://thanathip41.github.io/tspace-mysql/#/model?id=cross-join-model-clause)
129
+ - [Relationships](https://thanathip41.github.io/tspace-mysql/#/model?id=relationships)
130
+ - [One To One](https://thanathip41.github.io/tspace-mysql/#/model?id=one-to-one)
131
+ - [One To Many](https://thanathip41.github.io/tspace-mysql/#/model?id=one-to-many)
132
+ - [Belongs To](https://thanathip41.github.io/tspace-mysql/#/model?id=belongs-to)
133
+ - [Many To Many](https://thanathip41.github.io/tspace-mysql/#/model?id=many-to-many)
134
+ - [Relation](https://thanathip41.github.io/tspace-mysql/#/model?id=relation)
135
+ - [Deeply Nested Relations](https://thanathip41.github.io/tspace-mysql/#/model?id=deeply-nested-relations)
136
+ - [Relation Exists](https://thanathip41.github.io/tspace-mysql/#/model?id=relation-exists)
137
+ - [Relation Count](https://thanathip41.github.io/tspace-mysql/#/model?id=relation-count)
138
+ - [Relation Trashed](https://thanathip41.github.io/tspace-mysql/#/model?id=relation-trashed)
139
+ - [Built in Relation Functions](https://thanathip41.github.io/tspace-mysql/#/model?id=built-in-relation-functions)
140
+ - [Cache](https://thanathip41.github.io/tspace-mysql/#/model?id=cache)
141
+ - [Decorator](https://thanathip41.github.io/tspace-mysql/#/model?id=decorator)
142
+ - [Type Safety](https://thanathip41.github.io/tspace-mysql/#/model?id=type-safety)
143
+ - [Select Type Safety](https://thanathip41.github.io/tspace-mysql/#/model?id=select-type-safety-type-safety)
144
+ - [OrderBy Type Safety](https://thanathip41.github.io/tspace-mysql/#/model?id=order-by-type-safety)
145
+ - [GroupBy Type Safety](https://thanathip41.github.io/tspace-mysql/#/model?id=group-by-type-safety)
146
+ - [Where Type Safety](https://thanathip41.github.io/tspace-mysql/#/model?id=where-type-safety)
147
+ - [Insert Type Safety](https://thanathip41.github.io/tspace-mysql/#/model?id=insert-type-safety)
148
+ - [Update Type Safety](https://thanathip41.github.io/tspace-mysql/#/model?id=update-type-safety)
149
+ - [Delete Type Safety](https://thanathip41.github.io/tspace-mysql/#/model?id=delete-type-safety)
150
+ - [Relationships Type Safety](https://thanathip41.github.io/tspace-mysql/#/model?id=relationships-type-safety)
151
+ - [Results Type Safety](https://thanathip41.github.io/tspace-mysql/#/model?id=results-type-safety)
152
+ - [Metadata](https://thanathip41.github.io/tspace-mysql/#/model?id=metadata)
153
+ - [Audit](https://thanathip41.github.io/tspace-mysql/#/model?id=audit)
154
+ - [Repository](https://thanathip41.github.io/tspace-mysql/#/repository)
155
+ - [Select Statements](https://thanathip41.github.io/tspace-mysql/#/repository?id=select-statements)
156
+ - [Insert Statements](https://thanathip41.github.io/tspace-mysql/#/repository?id=insert-statements)
157
+ - [Update Statements](https://thanathip41.github.io/tspace-mysql/#/repository?id=update-statements)
158
+ - [Delete Statements](https://thanathip41.github.io/tspace-mysql/#/repository?id=delete-statements)
159
+ - [Transactions](https://thanathip41.github.io/tspace-mysql/#/repository?id=transactions)
160
+ - [Relations](https://thanathip41.github.io/tspace-mysql/#/repository?id=relations)
161
+ - [View](https://thanathip41.github.io/tspace-mysql/#/view)
162
+ - [Stored Procedure](https://thanathip41.github.io/tspace-mysql/#/stored-procedure)
163
+ - [Blueprint](https://thanathip41.github.io/tspace-mysql/#/blueprint)
164
+ - [Cli](https://thanathip41.github.io/tspace-mysql/#/cli)
165
+ - [Make Model](https://thanathip41.github.io/tspace-mysql/#/cli?id=make-model)
166
+ - [Make Migration](https://thanathip41.github.io/tspace-mysql/#/cli?id=make-migration)
167
+ - [Migrate](https://thanathip41.github.io/tspace-mysql/#/cli?id=migrate)
168
+ - [Query](https://thanathip41.github.io/tspace-mysql/#/cli?id=query)
169
+ - [Dump](https://thanathip41.github.io/tspace-mysql/#/cli?id=dump)
170
+ - [Generate Models](https://thanathip41.github.io/tspace-mysql/#/cli?id=generate-models)
171
+ - [Migration Models](https://thanathip41.github.io/tspace-mysql/#/cli?id=migration-models)
172
+ - [Migration DB](https://thanathip41.github.io/tspace-mysql/#/cli?id=migration-db)