tspace-mysql 1.9.1 → 1.9.3-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 (95) hide show
  1. package/README.md +388 -40
  2. package/dist/lib/core/Abstracts/AbstractBuilder.d.ts +16 -17
  3. package/dist/lib/core/Abstracts/AbstractBuilder.js.map +1 -1
  4. package/dist/lib/core/Abstracts/AbstractDB.d.ts +1 -1
  5. package/dist/lib/core/Abstracts/AbstractModel.d.ts +7 -2
  6. package/dist/lib/core/Abstracts/AbstractModel.js.map +1 -1
  7. package/dist/lib/core/Blueprint.d.ts +56 -23
  8. package/dist/lib/core/Blueprint.js +45 -6
  9. package/dist/lib/core/Blueprint.js.map +1 -1
  10. package/dist/lib/core/Builder.d.ts +57 -39
  11. package/dist/lib/core/Builder.js +91 -56
  12. package/dist/lib/core/Builder.js.map +1 -1
  13. package/dist/lib/core/Cache/MemoryCache.js +9 -4
  14. package/dist/lib/core/Cache/MemoryCache.js.map +1 -1
  15. package/dist/lib/core/Cache/index.js +32 -13
  16. package/dist/lib/core/Cache/index.js.map +1 -1
  17. package/dist/lib/core/Contracts/Audit.d.ts +6 -6
  18. package/dist/lib/core/Contracts/Audit.js.map +1 -1
  19. package/dist/lib/core/Contracts/Logger.d.ts +5 -5
  20. package/dist/lib/core/Contracts/Logger.js.map +1 -1
  21. package/dist/lib/core/DB.d.ts +2 -2
  22. package/dist/lib/core/DB.js +6 -19
  23. package/dist/lib/core/DB.js.map +1 -1
  24. package/dist/lib/core/Driver/index.d.ts +7 -5
  25. package/dist/lib/core/Driver/index.js +4 -2
  26. package/dist/lib/core/Driver/index.js.map +1 -1
  27. package/dist/lib/core/Driver/mariadb/MariadbDriver.js +14 -6
  28. package/dist/lib/core/Driver/mariadb/MariadbDriver.js.map +1 -1
  29. package/dist/lib/core/Driver/mariadb/MariadbQueryBuilder.d.ts +3 -3
  30. package/dist/lib/core/Driver/mariadb/MariadbQueryBuilder.js +24 -7
  31. package/dist/lib/core/Driver/mariadb/MariadbQueryBuilder.js.map +1 -1
  32. package/dist/lib/core/Driver/mongodb/MongodbDriver.js +18 -12
  33. package/dist/lib/core/Driver/mongodb/MongodbDriver.js.map +1 -1
  34. package/dist/lib/core/Driver/mongodb/MongodbQueryBuilder.d.ts +3 -3
  35. package/dist/lib/core/Driver/mongodb/MongodbQueryBuilder.js +9 -1
  36. package/dist/lib/core/Driver/mongodb/MongodbQueryBuilder.js.map +1 -1
  37. package/dist/lib/core/Driver/mysql/MysqlDriver.js +15 -7
  38. package/dist/lib/core/Driver/mysql/MysqlDriver.js.map +1 -1
  39. package/dist/lib/core/Driver/mysql/MysqlQueryBuilder.d.ts +3 -3
  40. package/dist/lib/core/Driver/mysql/MysqlQueryBuilder.js +24 -7
  41. package/dist/lib/core/Driver/mysql/MysqlQueryBuilder.js.map +1 -1
  42. package/dist/lib/core/Driver/postgres/PostgresDriver.js +14 -6
  43. package/dist/lib/core/Driver/postgres/PostgresDriver.js.map +1 -1
  44. package/dist/lib/core/Driver/postgres/PostgresQueryBuilder.d.ts +3 -3
  45. package/dist/lib/core/Driver/postgres/PostgresQueryBuilder.js +22 -7
  46. package/dist/lib/core/Driver/postgres/PostgresQueryBuilder.js.map +1 -1
  47. package/dist/lib/core/Driver/sqlite/SqliteDriver.d.ts +1 -0
  48. package/dist/lib/core/Driver/sqlite/SqliteDriver.js +25 -4
  49. package/dist/lib/core/Driver/sqlite/SqliteDriver.js.map +1 -1
  50. package/dist/lib/core/Driver/sqlite/SqliteQueryBuilder.d.ts +2 -0
  51. package/dist/lib/core/Driver/sqlite/SqliteQueryBuilder.js +27 -21
  52. package/dist/lib/core/Driver/sqlite/SqliteQueryBuilder.js.map +1 -1
  53. package/dist/lib/core/Join.d.ts +63 -5
  54. package/dist/lib/core/Join.js +92 -15
  55. package/dist/lib/core/Join.js.map +1 -1
  56. package/dist/lib/core/JoinModel.d.ts +65 -9
  57. package/dist/lib/core/JoinModel.js +79 -50
  58. package/dist/lib/core/JoinModel.js.map +1 -1
  59. package/dist/lib/core/Meta.d.ts +7 -7
  60. package/dist/lib/core/Meta.js +10 -9
  61. package/dist/lib/core/Meta.js.map +1 -1
  62. package/dist/lib/core/Model.d.ts +377 -69
  63. package/dist/lib/core/Model.js +528 -93
  64. package/dist/lib/core/Model.js.map +1 -1
  65. package/dist/lib/core/{Queue.d.ts → Queue/index.d.ts} +96 -90
  66. package/dist/lib/core/Queue/index.js +282 -0
  67. package/dist/lib/core/Queue/index.js.map +1 -0
  68. package/dist/lib/core/Queue/types.d.ts +31 -0
  69. package/dist/lib/core/Queue/types.js +3 -0
  70. package/dist/lib/core/Queue/types.js.map +1 -0
  71. package/dist/lib/core/Queue/worker.d.ts +102 -0
  72. package/dist/lib/core/{Queue.js → Queue/worker.js} +165 -260
  73. package/dist/lib/core/Queue/worker.js.map +1 -0
  74. package/dist/lib/core/RelationManager.d.ts +4 -4
  75. package/dist/lib/core/RelationManager.js +141 -16
  76. package/dist/lib/core/RelationManager.js.map +1 -1
  77. package/dist/lib/core/Repository.d.ts +41 -21
  78. package/dist/lib/core/Repository.js +40 -15
  79. package/dist/lib/core/Repository.js.map +1 -1
  80. package/dist/lib/core/Schema.d.ts +13 -13
  81. package/dist/lib/core/Schema.js +12 -0
  82. package/dist/lib/core/Schema.js.map +1 -1
  83. package/dist/lib/core/StateManager.d.ts +6 -0
  84. package/dist/lib/core/StateManager.js +1 -0
  85. package/dist/lib/core/StateManager.js.map +1 -1
  86. package/dist/lib/core/UtilityTypes.d.ts +75 -78
  87. package/dist/lib/core/UtilityTypes.js.map +1 -1
  88. package/dist/lib/types/decorator/index.d.ts +3 -0
  89. package/dist/lib/types/index.d.ts +53 -9
  90. package/dist/lib/types/repository/index.d.ts +3 -3
  91. package/dist/lib/utils/index.d.ts +6 -3
  92. package/dist/lib/utils/index.js +42 -3
  93. package/dist/lib/utils/index.js.map +1 -1
  94. package/package.json +1 -1
  95. package/dist/lib/core/Queue.js.map +0 -1
package/README.md CHANGED
@@ -43,7 +43,29 @@ npm install -g tspace-mysql
43
43
 
44
44
  ## Documentation
45
45
 
46
- See the [`docs`](https://thanathip41.github.io/tspace-mysql) directory for full documentation.
46
+ ### For LLMs & AI Assistants
47
+
48
+ 📚 **Complete Skills Documentation** is available in the [`skills/`](./skills) folder. This includes comprehensive, verified guides for:
49
+
50
+ - Model Setup & Blueprint
51
+ - Query Builder & SQL Operations
52
+ - Relationships (hasOne, hasMany, belongsTo, belongsToMany)
53
+ - Repository Pattern
54
+ - Decorators
55
+ - Type Safety (T namespace)
56
+ - Transactions
57
+ - Caching (DB_CACHE, .cache())
58
+ - Queue System
59
+ - CLI Commands
60
+ - Complete Real-World Examples
61
+
62
+ All skills documentation is **100% verified** against the source code.
63
+
64
+ ### Human-Readable Documentation
65
+
66
+ See the [`docs/`](./docs) directory for full documentation with examples.
67
+
68
+ Online: https://thanathip41.github.io/tspace-mysql
47
69
 
48
70
  ## TypeScript
49
71
 
@@ -66,6 +88,8 @@ npm install -D typescript@5.9.3
66
88
  - [MySQL Database](#mysql-database)
67
89
  - [Mariadb Database](#mariadb-database)
68
90
  - [Postgres Database](#postgres-database)
91
+ - [SQLite Database](#sqlite-database)
92
+ - [Mongodb Database](#mongodb-database)
69
93
  - [Cluster Database](#cluster-database)
70
94
  - [SQL Like](#sql-Like)
71
95
  - [Query Builder](#query-builder)
@@ -107,6 +131,7 @@ npm install -D typescript@5.9.3
107
131
  - [More Methods](#more-methods)
108
132
  - [Database Transactions](#database-transactions)
109
133
  - [Race Condition](#race-condition)
134
+ - [Lock Table](#lock-table)
110
135
  - [Connection](#connection)
111
136
  - [Backup](#backup)
112
137
  - [Injection](#injection)
@@ -165,6 +190,8 @@ npm install -D typescript@5.9.3
165
190
  - [Repository Transactions](#repository-transactions)
166
191
  - [Repository Relations](#repository-relations)
167
192
  - [Queue](#queue)
193
+ - [Queue Events](#queue-events)
194
+ - [Queue Type-safe Events and Jobs](#queue-type-safe-events-and-jobs)
168
195
  - [View](#view)
169
196
  - [Stored Procedure](#stored-procedure)
170
197
  - [Blueprint](#blueprint)
@@ -247,6 +274,50 @@ DB_PASSWORD = password
247
274
  DB_DATABASE = database
248
275
  ```
249
276
 
277
+ ### SQLite Database
278
+
279
+ To connect the application to a SQLite database, using the following:
280
+
281
+ ```sh
282
+ npm install better-sqlite3 --save
283
+ ```
284
+
285
+ ```js
286
+ DB_DRIVER = sqlite
287
+ DB_DATABASE = app.db
288
+ ```
289
+ ⚠️ Requirements for better-sqlite3
290
+ Node.js 22 or higher is required
291
+
292
+ ### Mongodb Database
293
+
294
+ To connect the application to a Mongodb database, using the following:
295
+ ```sh
296
+ npm install mongodb --save
297
+ ```
298
+
299
+ ```js
300
+ DB_DRIVER = mongodb
301
+ DB_HOST = localhost
302
+ DB_PORT = 27017
303
+ DB_USERNAME = root
304
+ DB_PASSWORD = password
305
+ DB_DATABASE = database
306
+ ```
307
+ ✅ Supported Features
308
+
309
+ CRUD operations (create, read, update, delete)
310
+ Basic joins & relations (via abstraction layer)
311
+
312
+ ⚠️ Limitations
313
+
314
+ MongoDB support is partially implemented and may not fully match SQL-based drivers like MySQL or PostgreSQL
315
+
316
+ * Advanced ORM features may be limited
317
+ * Complex joins rely on abstraction (not native MongoDB behavior)
318
+ * Some features may behave differently compared to relational databases
319
+ * Transactions / advanced optimizations may be limited
320
+
250
321
  ### Cluster Database
251
322
  If you need strict race condition control, it is required to use multiple nodes for write and read. <br>
252
323
  Avoid using a node load balancer in this case, as it may bypass proper write/read distribution and compromise consistency.<br>
@@ -1251,7 +1322,7 @@ whereNotIn(column , [])
1251
1322
  whereNull(column)
1252
1323
  whereNotNull(column)
1253
1324
  whereBetween (column , [value1 , value2])
1254
- whereQuery(callback)
1325
+ whereQuery(query)
1255
1326
  whereJson(column, { targetKey, value , OP })
1256
1327
  whereRaw(sql)
1257
1328
  whereExists(sql)
@@ -1261,7 +1332,7 @@ orWhere(column , OP , value)
1261
1332
  orWhereRaw(sql)
1262
1333
  orWhereIn(column , [])
1263
1334
  orWhereSubQuery(colmn , rawSQL)
1264
- when(contition , callback)
1335
+ when(contition , query)
1265
1336
  select(column1 ,column2 ,...N)
1266
1337
  distinct()
1267
1338
  selectRaw(column1 ,column2 ,...N)
@@ -1294,7 +1365,7 @@ onlyTrashed()
1294
1365
  connection(options)
1295
1366
  backup({ database , connection })
1296
1367
  backupToFile({ filePath, database , connection })
1297
- hook((result) => ...) // callback result to function
1368
+ hook((result) => ...) // query result to function
1298
1369
  sleep(seconds)
1299
1370
 
1300
1371
  /**
@@ -1322,9 +1393,9 @@ relationsExists(name1 , name2,...nameN) // withExists(name1, name2,...nameN)
1322
1393
  */
1323
1394
  relationsTrashed(name1 , name2,...nameN) // withTrashed(name1, name2,...nameN)
1324
1395
  /**
1325
- * @relation call a name of relation in registry, callback query of data
1396
+ * @relation call a name of relation in registry, query query of data
1326
1397
  */
1327
- relationQuery(name, (callback) ) // withQuery(name1, (callback))
1398
+ relationQuery(name, (query) ) // withQuery(name1, (query))
1328
1399
 
1329
1400
 
1330
1401
  /**
@@ -1603,6 +1674,148 @@ async function simulateRaceConnection(): Promise<void> {
1603
1674
 
1604
1675
  simulateRaceConnection();
1605
1676
 
1677
+ ```
1678
+ ## Lock Table
1679
+
1680
+ Within a lock table, you can utilize the following:
1681
+
1682
+ This approach is not recommended in clustered or load-balance environments,
1683
+ because locks are session-bound and requests may be routed to different database connections.
1684
+
1685
+ READ:
1686
+ - Other sessions can read.
1687
+ - Other sessions must wait before writing.
1688
+ - SELECT: allowed
1689
+ - INSERT: waits
1690
+ - UPDATE: waits
1691
+ - DELETE: waits
1692
+
1693
+ WRITE:
1694
+ - Other sessions must wait before reading or writing.
1695
+ - SELECT: waits
1696
+ - INSERT: waits
1697
+ - UPDATE: waits
1698
+ - DELETE: waits
1699
+
1700
+ The lock is released automatically after the query completes.
1701
+
1702
+ ```js
1703
+ import { Model, Blueprint } from 'tspace-mysql'
1704
+
1705
+ class User extends Model {
1706
+ protected boot() {
1707
+ this.useSchema({
1708
+ id : Blueprint.int().notNull().primary().autoIncrement(),
1709
+ email : Blueprint.varchar(20).notNull()
1710
+ });
1711
+ }
1712
+ }
1713
+
1714
+ async function requestA() {
1715
+
1716
+ try {
1717
+
1718
+ console.log("A: locking table...");
1719
+
1720
+ // READ | WRITE
1721
+ await User.lockTable('WRITE', async (query) => {
1722
+ console.log("A: table LOCKED");
1723
+
1724
+ // Simulate a long-running write transaction.
1725
+ // WRITE operations from other sessions will wait
1726
+ // until the table lock is released.
1727
+ //
1728
+ // READ behavior depends on the selected lock mode:
1729
+ // - READ lock: other readers are allowed
1730
+ // - WRITE lock: readers/writers may be blocked
1731
+ await new Promise((r) => setTimeout(r, 1000 * 10));
1732
+
1733
+ // IMPORTANT:
1734
+ // While the table is locked, all database operations
1735
+ // must use the provided `query` instance.
1736
+ //
1737
+ // This guarantees the operation runs on the same
1738
+ // database session/connection that owns the lock.
1739
+ //
1740
+ // ❌ May fail because it can use a different connection:
1741
+ // await new User().insert({...}).save();
1742
+ //
1743
+ // ✅ Uses the lock owner session:
1744
+ await query.insert({...}).save();
1745
+
1746
+ // In READ mode this write operation will throw,
1747
+ // because writes are not permitted under a READ lock.
1748
+ // In WRITE mode it executes successfully.
1749
+
1750
+ console.log("A: unlocking table...");
1751
+ });
1752
+
1753
+ console.log("A: done");
1754
+
1755
+ } catch (err:any) {
1756
+
1757
+ console.error('❌ SHOULD NOT FAIL:', err.message);
1758
+ }
1759
+ }
1760
+
1761
+ async function requestB(n: number = 1) {
1762
+ console.log(`B(${n}): waiting 1s before query...`);
1763
+ await new Promise((r) => setTimeout(r, 1000));
1764
+
1765
+ console.log(`B(${n}): trying SELECT...`);
1766
+
1767
+ const start = Date.now();
1768
+
1769
+ try {
1770
+
1771
+ const users = await new User().select('id').get();
1772
+ console.log(`B(${n}): result`, users.length);
1773
+
1774
+ console.log(`B(${n}): finished in`, Date.now() - start, "ms");
1775
+ } catch (err:any) {
1776
+ console.error(`B(${n}): ERROR`, err.message);
1777
+ }
1778
+ }
1779
+
1780
+ async function requestC(n: number = 1) {
1781
+ console.log(`C(${n}): waiting 1s before query...`);
1782
+ await new Promise((r) => setTimeout(r, 1000));
1783
+
1784
+ console.log(`C(${n}): trying Insert...Select`);
1785
+
1786
+ const start = Date.now();
1787
+
1788
+ try {
1789
+
1790
+ await new User().faker(1);
1791
+
1792
+ const users = await new User().select('id').get();
1793
+ console.log(`C(${n}): result`, users.length);
1794
+
1795
+ console.log(`C(${n}): finished in`, Date.now() - start, "ms");
1796
+ } catch (err:any) {
1797
+ console.error(`C(${n}): ERROR`, err.message);
1798
+ }
1799
+ }
1800
+
1801
+ (async () => {
1802
+ // Test scenario:
1803
+ //
1804
+ // 1. Request A acquires a table lock.
1805
+ // 2. Requests B perform concurrent reads.
1806
+ // 3. Request C performs a concurrent write.
1807
+ // 4. Observe whether operations are blocked, queued, or rejected
1808
+ // according to the selected lock mode.
1809
+ await Promise.all([
1810
+ requestA(),
1811
+ requestB(1),
1812
+ requestB(2),
1813
+ requestC(3)
1814
+ ])
1815
+ .then(r => process.exit(1))
1816
+
1817
+ })()
1818
+
1606
1819
  ```
1607
1820
 
1608
1821
  ## Connection
@@ -1757,6 +1970,26 @@ class User extends Model {
1757
1970
  * updated_at : Blueprint.timestamp().null(),
1758
1971
  * deleted_at : Blueprint.timestamp().null()
1759
1972
  * }) // auto-generated table when table is not exists and auto-create column when column not exists
1973
+ *
1974
+ * this.useLifecycle('beforeInsert', () => console.log('beforeInsert'))
1975
+ * this.useLifecycle('afterInsert', () => console.log('afterInsert'))
1976
+ * this.useLifecycle('beforeUpdate', () => console.log('beforeUpdate'))
1977
+ * this.useLifecycle('afterUpdate', () => console.log('afterUpdate'))
1978
+ * this.useLifecycle('beforeRemove', () => console.log('beforeRemove'))
1979
+ * this.useLifecycle('afterRemove', () => console.log('afterRemove'))
1980
+ *
1981
+ * this.useTransform({
1982
+ * name : {
1983
+ * to : async (name) => `${name}-> transform@before`,
1984
+ * from : async (name) => `${name}-> transform@after`,
1985
+ * }
1986
+ * })
1987
+ *
1988
+ * this.useHooks([
1989
+ * (r:any) => console.log(r,'hook1'),
1990
+ * (r:any) => console.log(r,'hook2'),
1991
+ * (r:any) => console.log(r,'hook3')
1992
+ * ])
1760
1993
  *
1761
1994
  * // validate input when create or update reference to the schema in 'this.useSchema'
1762
1995
  * this.useValidateSchema({
@@ -2053,7 +2286,8 @@ Let's example a basic relationship:
2053
2286
  A one-to-one relationship is used to define relationships where a single model is the parent to one child models
2054
2287
 
2055
2288
  ```js
2056
- import { Model } from 'tspace-mysql'
2289
+ import { Model , type T } from 'tspace-mysql';
2290
+
2057
2291
  import Phone from '../Phone'
2058
2292
  class User extends Model {
2059
2293
  constructor(){
@@ -2068,12 +2302,15 @@ class User extends Model {
2068
2302
  }
2069
2303
  /**
2070
2304
  * Mark a method for relationship
2071
- * @hasOne Get the phone associated with the user. using function callback
2305
+ * @hasOne Get the phone associated with the user. using function query
2072
2306
  * @function
2073
2307
  */
2074
- phone (callback) {
2075
- return this.hasOneBuilder({ name : 'phone' , model : Phone } , callback)
2308
+ public phone (query ?: T.QueryModifier<Phone>) {
2309
+ return this.hasOneBuilder({ model : Phone } , query)
2076
2310
  }
2311
+
2312
+ // or
2313
+ public phone = this.createRelation(Phone,{ type : 'hasOne'})
2077
2314
  }
2078
2315
  export default User
2079
2316
 
@@ -2091,8 +2328,8 @@ const userUsingFunction = await new User().phone().findOne()
2091
2328
  A one-to-many relationship is used to define relationships where a single model is the parent to one or more child models.
2092
2329
 
2093
2330
  ```js
2094
- import { Model } from 'tspace-mysql'
2095
- import Comment from '../Comment'
2331
+ import { Model, type T } from 'tspace-mysql';
2332
+ import Comment from '../Comment';
2096
2333
  class Post extends Model {
2097
2334
  constructor(){
2098
2335
  super()
@@ -2106,12 +2343,15 @@ class Post extends Model {
2106
2343
  }
2107
2344
  /**
2108
2345
  *
2109
- * @hasManyQuery Get the comments for the post. using function callback
2346
+ * @hasManyQuery Get the comments for the post. using function query
2110
2347
  * @function
2111
2348
  */
2112
- comments (callback) {
2113
- return this.hasManyBuilder({ name : 'comments' , model : Comment } , callback)
2349
+ public comments (query?: T.QueryModifier<Comment>) {
2350
+ return this.hasManyBuilder({ model : Comment } , query)
2114
2351
  }
2352
+
2353
+ // or
2354
+ public comments = this.createRelation(Comment,{ type : 'hasMany'})
2115
2355
  }
2116
2356
  export default Post
2117
2357
 
@@ -2129,7 +2369,7 @@ const postsUsingFunction = await new Post().comments().findOne()
2129
2369
  A belongsto relationship is used to define relationships where a single model is the child to parent models.
2130
2370
 
2131
2371
  ```js
2132
- import { Model } from 'tspace-mysql'
2372
+ import { Model, type T } from 'tspace-mysql'
2133
2373
  import User from '../User'
2134
2374
  class Phone extends Model {
2135
2375
  constructor(){
@@ -2144,12 +2384,15 @@ class Phone extends Model {
2144
2384
  }
2145
2385
  /**
2146
2386
  *
2147
- * @belongsToBuilder Get the user that owns the phone.. using function callback
2387
+ * @belongsToBuilder Get the user that owns the phone.. using function query
2148
2388
  * @function
2149
2389
  */
2150
- user (callback) {
2151
- return this.belongsToBuilder({ name : 'user' , model : User }, callback)
2390
+ public user (query?: T.QueryModifier<user>) {
2391
+ return this.belongsToBuilder({ model : User }, query)
2152
2392
  }
2393
+
2394
+ // or
2395
+ public user = this.createRelation(User,{ type : 'belognsTo'})
2153
2396
  }
2154
2397
  export default Phone
2155
2398
 
@@ -2167,7 +2410,7 @@ const phoneUsingFunction = await new Phone().user().findOne()
2167
2410
  Many-to-many relations are slightly more complicated than hasOne and hasMany relationships.
2168
2411
 
2169
2412
  ```js
2170
- import { Model } from 'tspace-mysql'
2413
+ import { Model, type T } from 'tspace-mysql'
2171
2414
  import Role from '../Role'
2172
2415
  class User extends Model {
2173
2416
  constructor(){
@@ -2181,12 +2424,15 @@ class User extends Model {
2181
2424
  this.belognsToMany({ name : 'roles' , model : Role })
2182
2425
  }
2183
2426
  /**
2184
- * @belongsToBuilder Get the user that owns the phone.. using function callback
2427
+ * @belongsToBuilder Get the user that owns the phone.. using function query
2185
2428
  * @function
2186
2429
  */
2187
- roles (callback) {
2188
- return this.belognsToManyBuilder({ model : Role } , callback)
2430
+ public roles (query?: T.QueryModifier<Role>) {
2431
+ return this.belognsToManyBuilder({ model : Role } , query)
2189
2432
  }
2433
+
2434
+ // or
2435
+ public roles = this.createRelation(Role, { type : 'belognsToMany'})
2190
2436
  }
2191
2437
  export default User
2192
2438
 
@@ -2700,7 +2946,7 @@ Cache can be used in a Model.
2700
2946
  Let's illustrate this with an example of a cache:
2701
2947
 
2702
2948
  ```js
2703
- // support memory db and redis
2949
+ // support memory , db , redis
2704
2950
  // set cache in file config .env , .env.development ... etc
2705
2951
  DB_CACHE = memory // by default
2706
2952
 
@@ -2708,6 +2954,7 @@ DB_CACHE = memory // by default
2708
2954
  DB_CACHE = db
2709
2955
 
2710
2956
  // for redis
2957
+ // npm install redis@5.6.0
2711
2958
  DB_CACHE = redis://username:password@server:6379
2712
2959
 
2713
2960
  const users = await new User()
@@ -2743,22 +2990,27 @@ import { PostUser } from './PostUser'
2743
2990
 
2744
2991
  class UserObserve {
2745
2992
 
2746
- public selected(results) {
2747
- console.log({ results , selected : true })
2748
- }
2993
+ public selected(results) {
2994
+ console.log({ results , selected : true })
2995
+ }
2749
2996
 
2750
- public created(results) {
2751
- console.log({ results , created : true })
2752
- }
2997
+ public created(results) {
2998
+ console.log({ results , created : true })
2999
+ }
2753
3000
 
2754
- public updated(results) {
2755
- console.log({ results , updated : true })
2756
- }
3001
+ public updated(results) {
3002
+ console.log({ results , updated : true })
3003
+ }
2757
3004
 
2758
- public deleted(results) {
2759
- console.log({ results , deleted : true })
2760
- }
3005
+ public deleted(results) {
3006
+ console.log({ results , deleted : true })
2761
3007
  }
3008
+ }
3009
+
3010
+ enum UserRole {
3011
+ Admin = 'admin',
3012
+ User = 'user',
3013
+ }
2762
3014
 
2763
3015
  @Pattern('camelCase')
2764
3016
  @Observer(UserObserve)
@@ -2794,6 +3046,9 @@ class User extends Model {
2794
3046
  @Column(() => Blueprint.varchar(50).null())
2795
3047
  public password !: string
2796
3048
 
3049
+ @Column(() => Blueprint.enum(UserRole).default(UserRole.Admin))
3050
+ public role !: `${UserRole}`
3051
+
2797
3052
  @Column(() => Blueprint.timestamp().null())
2798
3053
  public createdAt!: Date
2799
3054
 
@@ -3939,9 +4194,14 @@ const fakeSendEmail = async (job: Job) => {
3939
4194
 
3940
4195
  // start the Queue
3941
4196
  await Queue.start({
3942
- inspect : true,
3943
- flush : false, // flush = true -> remove all jobs
3944
- hostname: 'pod1'
4197
+ inspect : true, // @default false, enable queue workflow inspection
4198
+ flush : false, // @default false, true -> remove all jobs
4199
+ hostname : 'pod1', // @default null, worker hostname
4200
+ maxIdleRetries : 8, // @default 5, maximum retries when no jobs are available
4201
+ poll : {
4202
+ enabled : true, // @default false, enable periodic job checking
4203
+ timeout : 10_000 // @default 60_000, polling interval
4204
+ };
3945
4205
  });
3946
4206
 
3947
4207
  const worker = 20;
@@ -3981,6 +4241,83 @@ for(let j = 1; j <= worker * 500; j++) {
3981
4241
  // if you want to end the Queue
3982
4242
  // await Queue.end()
3983
4243
 
4244
+ ```
4245
+ ### Queue Events
4246
+
4247
+ Queue also supports an event-based publish/subscribe pattern.
4248
+
4249
+ One event can have multiple subscribers.
4250
+ Use Queue.subscribe() to subscribe a job handler to an event
4251
+ ```js
4252
+ // user.created
4253
+ // │
4254
+ // ├── email
4255
+ // ├── notify
4256
+ // └── analytics
4257
+
4258
+ Queue.subscribe(
4259
+ 'user.created',
4260
+ 'email',
4261
+ async (job) => {
4262
+ await new Promise(r => setTimeout(r, 1000));
4263
+ console.log('Send e-mail : ' + job.payload.email)
4264
+ return 'Done!';
4265
+ },
4266
+ { concurrency: 2 }
4267
+ );
4268
+
4269
+ Queue.subscribe(
4270
+ 'user.created',
4271
+ 'notify',
4272
+ async (job) => {
4273
+ await new Promise(r => setTimeout(r, 1000));
4274
+ console.log('notify : ' + job.payload.email)
4275
+ return 'Done!';
4276
+ },
4277
+ { concurrency: 3 }
4278
+ );
4279
+ ```
4280
+ Use Queue.publish() to publish an event.
4281
+ ```js
4282
+ for (let i = 1; i <= 5; i++) {
4283
+ // will send to jobs ['email','notify'];
4284
+ Queue.publish(
4285
+ 'user.created',
4286
+ { id : i , email : `user${i}@gmail.com` },
4287
+ {
4288
+ priority: i
4289
+ }
4290
+ );
4291
+ }
4292
+
4293
+ ```
4294
+ ### Queue Type-safe Events and Jobs
4295
+ Queue optionally supports type-safe event and job names through `QueueContract`.
4296
+
4297
+ The feature is optional.
4298
+
4299
+ If the application does not define a contract, the Queue API can continue to accept normal string names.
4300
+
4301
+ Create a `types.d.ts` file in your application:
4302
+ ```js
4303
+ import { QueueContract } from 'tspace-mysql';
4304
+
4305
+ declare module 'tspace-mysql' {
4306
+ interface QueueContract {
4307
+ events: {
4308
+ 'user.created': [
4309
+ 'email',
4310
+ 'notify',
4311
+ ];
4312
+ };
4313
+
4314
+ jobs: [
4315
+ 'resize-video',
4316
+ 'cleanup',
4317
+ ];
4318
+ }
4319
+ }
4320
+
3984
4321
  ```
3985
4322
 
3986
4323
  ## View
@@ -4170,7 +4507,13 @@ Blueprint is a tool used for defining database schemas programmatically.
4170
4507
  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:
4171
4508
 
4172
4509
  ```js
4173
- import { Schema , Blueprint , DB } from 'tspace-mysql'
4510
+ import { Schema , Blueprint , DB } from 'tspace-mysql';
4511
+
4512
+ enum UserRole {
4513
+ Admin = 'admin',
4514
+ User = 'user',
4515
+ }
4516
+
4174
4517
  (async () => {
4175
4518
  await new Schema().table('users', {
4176
4519
  id : Blueprint.int().notNull().primary().autoIncrement(),
@@ -4181,6 +4524,7 @@ import { Schema , Blueprint , DB } from 'tspace-mysql'
4181
4524
  email_verify : Blueprint.tinyInt(),
4182
4525
  password : Blueprint.varchar(255),
4183
4526
  json : Blueprint.json(),
4527
+ role : Blueprint.enum(UserRole).default(UserRole.Admin)
4184
4528
  created_at : Blueprint.null().timestamp(),
4185
4529
  updated_at : Blueprint.null().timestamp(),
4186
4530
  deleted_at : Blueprint.null().timestamp()
@@ -4213,6 +4557,10 @@ enum(...n)
4213
4557
  date()
4214
4558
  dateTime()
4215
4559
  timestamp ()
4560
+ raw({
4561
+ type : 'DECIMAL(10, 2)',
4562
+ attribute : 'DEFAULT(1)'
4563
+ })
4216
4564
 
4217
4565
  /**
4218
4566
  * To add attributes of the schema to the database