tspace-mysql 1.8.2 → 1.8.4

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 (83) hide show
  1. package/README.md +443 -68
  2. package/build/cli/generate/model.js +3 -3
  3. package/build/cli/generate/model.js.map +1 -1
  4. package/build/lib/constants/index.d.ts +7 -1
  5. package/build/lib/constants/index.js +7 -1
  6. package/build/lib/constants/index.js.map +1 -1
  7. package/build/lib/core/Abstracts/AbstractBuilder.d.ts +1 -1
  8. package/build/lib/core/Abstracts/AbstractBuilder.js.map +1 -1
  9. package/build/lib/core/Abstracts/AbstractDB.d.ts +2 -2
  10. package/build/lib/core/Abstracts/AbstractDB.js.map +1 -1
  11. package/build/lib/core/Abstracts/AbstractView.d.ts +10 -0
  12. package/build/lib/core/Abstracts/AbstractView.js +9 -0
  13. package/build/lib/core/Abstracts/AbstractView.js.map +1 -0
  14. package/build/lib/core/Blueprint.d.ts +24 -4
  15. package/build/lib/core/Blueprint.js +78 -87
  16. package/build/lib/core/Blueprint.js.map +1 -1
  17. package/build/lib/core/Builder.d.ts +39 -30
  18. package/build/lib/core/Builder.js +1094 -1044
  19. package/build/lib/core/Builder.js.map +1 -1
  20. package/build/lib/core/Cache/DBCache.js +15 -16
  21. package/build/lib/core/Cache/DBCache.js.map +1 -1
  22. package/build/lib/core/DB.d.ts +38 -38
  23. package/build/lib/core/DB.js +119 -115
  24. package/build/lib/core/DB.js.map +1 -1
  25. package/build/lib/core/Decorator.d.ts +1 -1
  26. package/build/lib/core/Decorator.js.map +1 -1
  27. package/build/lib/core/Handlers/Relation.d.ts +2 -1
  28. package/build/lib/core/Handlers/Relation.js +60 -15
  29. package/build/lib/core/Handlers/Relation.js.map +1 -1
  30. package/build/lib/core/Handlers/State.d.ts +1 -0
  31. package/build/lib/core/Handlers/State.js +1 -1
  32. package/build/lib/core/Handlers/State.js.map +1 -1
  33. package/build/lib/core/JoinModel.d.ts +1 -1
  34. package/build/lib/core/JoinModel.js.map +1 -1
  35. package/build/lib/core/Meta.d.ts +55 -0
  36. package/build/lib/core/Meta.js +175 -0
  37. package/build/lib/core/Meta.js.map +1 -0
  38. package/build/lib/core/Model.d.ts +158 -94
  39. package/build/lib/core/Model.js +1586 -1203
  40. package/build/lib/core/Model.js.map +1 -1
  41. package/build/lib/core/Nest/index.d.ts +3 -1
  42. package/build/lib/core/Nest/index.js +4 -2
  43. package/build/lib/core/Nest/index.js.map +1 -1
  44. package/build/lib/{connection/index.d.ts → core/Pool.d.ts} +2 -1
  45. package/build/lib/{connection/index.js → core/Pool.js} +74 -6
  46. package/build/lib/core/Pool.js.map +1 -0
  47. package/build/lib/core/Repository.d.ts +16 -16
  48. package/build/lib/core/Repository.js +73 -45
  49. package/build/lib/core/Repository.js.map +1 -1
  50. package/build/lib/core/Schema.d.ts +2 -2
  51. package/build/lib/core/Schema.js +113 -78
  52. package/build/lib/core/Schema.js.map +1 -1
  53. package/build/lib/core/SqlLike.js.map +1 -1
  54. package/build/lib/core/StoredProcedure.d.ts +120 -0
  55. package/build/lib/core/StoredProcedure.js +161 -0
  56. package/build/lib/core/StoredProcedure.js.map +1 -0
  57. package/build/lib/core/UtilityTypes.d.ts +25 -44
  58. package/build/lib/core/View.d.ts +96 -0
  59. package/build/lib/core/View.js +141 -0
  60. package/build/lib/core/View.js.map +1 -0
  61. package/build/lib/core/index.d.ts +17 -12
  62. package/build/lib/core/index.js +9 -4
  63. package/build/lib/core/index.js.map +1 -1
  64. package/build/lib/types/index.d.ts +23 -3
  65. package/build/lib/utils/index.js +5 -2
  66. package/build/lib/utils/index.js.map +1 -1
  67. package/build/tests/01-Pool.test.js +0 -10
  68. package/build/tests/01-Pool.test.js.map +1 -1
  69. package/build/tests/04-Model-pattern.test.js +1 -1
  70. package/build/tests/04-Model-pattern.test.js.map +1 -1
  71. package/build/tests/05-View.test.d.ts +1 -0
  72. package/build/tests/05-View.test.js +83 -0
  73. package/build/tests/05-View.test.js.map +1 -0
  74. package/build/tests/06-Meta.test.d.ts +1 -0
  75. package/build/tests/06-Meta.test.js +103 -0
  76. package/build/tests/06-Meta.test.js.map +1 -0
  77. package/build/tests/07-Virtual-column.test.d.ts +1 -0
  78. package/build/tests/07-Virtual-column.test.js +160 -0
  79. package/build/tests/07-Virtual-column.test.js.map +1 -0
  80. package/build/tests/schema-spec.js +25 -25
  81. package/build/tests/schema-spec.js.map +1 -1
  82. package/package.json +1 -1
  83. package/build/lib/connection/index.js.map +0 -1
package/README.md CHANGED
@@ -18,6 +18,7 @@ tspace-mysql is an Object-Relational Mapping (ORM) tool designed to run seamless
18
18
  | **Soft Deletes** | Marks records as deleted without removing them from the database. This allows for recovery and auditing later. |
19
19
  | **Relationships** | Set up connections between models, such as one-to-one, one-to-many, belongs-to, and many-to-many. Supports nested relationships and checks. |
20
20
  | **Type Safety** | Ensures that queries are safer by checking the types of statements like `SELECT`, `ORDER BY`, `GROUP BY`, and `WHERE`. |
21
+ | **Metadata** | Get the metadata of a Model. |
21
22
  | **Repository** | Follows a pattern for managing database operations like `SELECT`, `INSERT`, `UPDATE`, and `DELETE`. It helps keep the code organized. |
22
23
  | **Decorators** | Use decorators to add extra functionality or information to model classes and methods, making the code easier to read. |
23
24
  | **Caching** | Improves performance by storing frequently requested data. Supports in-memory caching (like memory DB) and Redis for distributed caching. |
@@ -91,6 +92,7 @@ npm install tspace-mysql -g
91
92
  - [Global Scope](#global-scope)
92
93
  - [Schema](#schema)
93
94
  - [Schema Model](#schema-model)
95
+ - [Virtual Column](#virtual-column)
94
96
  - [Validation](#validation)
95
97
  - [Sync](#sync)
96
98
  - [SoftDelete](#softdelete)
@@ -112,14 +114,16 @@ npm install tspace-mysql -g
112
114
  - [Cache](#cache)
113
115
  - [Decorator](#decorator)
114
116
  - [Type Safety](#type-safety)
115
- - [Safety Select](#safety-select)
116
- - [Safety OrderBy](#safety-order-by)
117
- - [Safety GroupBy](#safety-group-by)
118
- - [Safety Where](#safety-where)
119
- - [Safety Insert](#safety-insert)
120
- - [Safety Update](#safety-update)
121
- - [Safety Delete](#safety-delete)
122
- - [Safety Relationships](#safety-relationships)
117
+ - [Type Safety Select](#type-safety-select)
118
+ - [Type Safety OrderBy](#type-safety-order-by)
119
+ - [Type Safety GroupBy](#type-safety-group-by)
120
+ - [Type Safety Where](#type-safety-where)
121
+ - [Type Safety Insert](#type-safety-insert)
122
+ - [Type Safety Update](#type-safety-update)
123
+ - [Type Safety Delete](#type-safety-delete)
124
+ - [Type Safety Relationships](#type-safety-relationships)
125
+ - [Type Safety Results](#type-safety-results)
126
+ - [Metadata](#metadata)
123
127
  - [Repository](#repository)
124
128
  - [Repository Select Statements](#repository-select-statements)
125
129
  - [Repository Insert Statements](#repository-insert-statements)
@@ -127,6 +131,8 @@ npm install tspace-mysql -g
127
131
  - [Repository Delete Statements](#repository-delete-statements)
128
132
  - [Repository Transactions](#repository-transactions)
129
133
  - [Repository Relations](#repository-relations)
134
+ - [View](#view)
135
+ - [Stored Procedure](#stored-procedure)
130
136
  - [Blueprint](#blueprint)
131
137
  - [Cli](#cli)
132
138
  - [Make Model](#make-model)
@@ -1229,7 +1235,35 @@ try {
1229
1235
  *
1230
1236
  * @commit commit transaction to database
1231
1237
  */
1238
+ // After your use commit if use same connection for actions this transction will auto commit
1232
1239
  await connection.commit();
1240
+
1241
+ // If you need to start a new transaction again, just use wait connection.startTransaction();
1242
+
1243
+ const postsAfterCommited = await new Post()
1244
+ .createMultiple([
1245
+ {
1246
+ user_id: user.id,
1247
+ title: `tspace-post1`,
1248
+ },
1249
+ {
1250
+ user_id: user.id,
1251
+ title: `tspace-post2`,
1252
+ },
1253
+ {
1254
+ user_id: user.id,
1255
+ title: `tspace-post3`,
1256
+ },
1257
+ ])
1258
+ // Using this connection now will auto-commit to the database.
1259
+ .bind(connection) // If you need to perform additional operations, use await connection.startTransaction(); again.
1260
+ .save();
1261
+
1262
+
1263
+ // Do not perform any operations with this connection.
1264
+ // The transaction has already been committed, and the connection is closed.
1265
+ // Just ensure everything is handled at the end of the transaction.
1266
+ await connection.end();
1233
1267
 
1234
1268
  } catch (err) {
1235
1269
  /**
@@ -2449,7 +2483,7 @@ using the following:
2449
2483
  #### Schema Model
2450
2484
 
2451
2485
  ```js
2452
- import { Model, Blueprint , TSchema } from "tspace-mysql";
2486
+ import { Model, Blueprint , type T } from "tspace-mysql";
2453
2487
 
2454
2488
  const schema = {
2455
2489
  id: Blueprint.int().notNull().primary().autoIncrement(),
@@ -2463,7 +2497,7 @@ const schema = {
2463
2497
 
2464
2498
 
2465
2499
  // make type in TS
2466
- type TS = TSchema<typeof Schema>
2500
+ type TS = T.Schema<typeof Schema>
2467
2501
 
2468
2502
  // the TSchemaUser will be created like that
2469
2503
  /**
@@ -2490,6 +2524,60 @@ class User extends Model<TS> // use the schema for this User model
2490
2524
 
2491
2525
  ```
2492
2526
 
2527
+ #### Virtual Column
2528
+ ```js
2529
+
2530
+ import { Model, Blueprint , type T } from "tspace-mysql";
2531
+
2532
+ const schema = {
2533
+ id: Blueprint.int().notNull().primary().autoIncrement(),
2534
+ uuid: Blueprint.varchar(50).null().index(),
2535
+ firstName: Blueprint.varchar(191).notNull(),
2536
+ lastName : Blueprint.varchar(191).notNull(),
2537
+ email: Blueprint.varchar(191).notNull(),
2538
+ createdAt: Blueprint.timestamp().null(),
2539
+ updatedAt: Blueprint.timestamp().null(),
2540
+ deletedAt: Blueprint.timestamp().null(),
2541
+
2542
+ // Define you virtual column to schema
2543
+ fullName : new Blueprint().virtual(`CONCAT(firstName,' ', lastName)`),
2544
+ countPosts : new Blueprint().virtual(`(SELECT COUNT(*) FROM posts WHERE posts.userid = users.id)`)
2545
+
2546
+ // if you need to custom the virtual column for some method.
2547
+ // fullName : new Blueprint().virtual({
2548
+ // select : `CONCAT(firstName,' ', lastName)`,
2549
+ // where : `CONCAT(firstName,' ', lastName)`,
2550
+ // orderBy : `CONCAT(firstName,' ', lastName)`,
2551
+ // groupBy : `CONCAT(firstName,' ', lastName)`,
2552
+ // }),
2553
+ }
2554
+
2555
+ type TS = T.Schema<typeof Schema>
2556
+
2557
+ class User extends Model<TS> {
2558
+ constructor() {
2559
+ super();
2560
+ this.useSchema(schema)
2561
+ }
2562
+ }
2563
+ const users = await new User()
2564
+ .select('id','firstName','lastName','fullName','countPosts')
2565
+ .where('fullName','LIKE',`%tspace-mysql%`)
2566
+ .orderBy('fullName','desc')
2567
+ .groupBy('fullName')
2568
+ .findMany()
2569
+
2570
+ // SELECT
2571
+ // `users`.`id`, `users`.`firstName`, `users`.`lastName`,
2572
+ // CONCAT(firstName,' ', lastName) AS fullName ,
2573
+ // (SELECT COUNT(*) FROM posts WHERE posts.userid = users.id) AS countPosts
2574
+ // FROM `users`
2575
+ // WHERE CONCAT(firstName,' ', lastName) LIKE '%tspace-mysql%'
2576
+ // GROUP BY CONCAT(firstName,' ', lastName)
2577
+ // ORDER BY CONCAT(firstName,' ', lastName) DESC
2578
+
2579
+ ```
2580
+
2493
2581
  #### Validation
2494
2582
 
2495
2583
  Validate the schema of Model
@@ -2648,12 +2736,12 @@ const user = await new User().trashed().findMany()
2648
2736
  ```
2649
2737
 
2650
2738
  ### Type Safety
2651
- Type safety in TypeScript refers to the ability of the language to detect and prevent type errors during compile-time.
2652
- Type safety still works when you add additional types to your model, using the following:
2739
+ Type Type Safety in TypeScript refers to the ability of the language to detect and prevent type errors during compile-time.
2740
+ Type Type Safety still works when you add additional types to your model, using the following:
2653
2741
 
2654
2742
  ```js
2655
2743
  // in file User.ts
2656
- import { Model , Blueprint , TSchema , TSchemaStatic } from 'tspace-mysql'
2744
+ import { Model , Blueprint , type T } from 'tspace-mysql'
2657
2745
  import Phone from '../Phone'
2658
2746
 
2659
2747
  const schemaUser = {
@@ -2667,8 +2755,8 @@ const schemaUser = {
2667
2755
  updatedAt :Blueprint.timestamp().null()
2668
2756
  }
2669
2757
 
2670
- type TSchemaUser = TSchemaStatic<typeof schemaUser>
2671
- // TSchemaUser = TSchema<typeof schemaUser>
2758
+ type TSchemaUser = T.SchemaStatic<typeof schemaUser>
2759
+ // TSchemaUser = T.Schema<typeof schemaUser>
2672
2760
 
2673
2761
  // TSchema allowed to set any new keys without in the schema to results
2674
2762
  // TSchemaStatic not allowed to set any new keys without in the schema to results
@@ -2688,7 +2776,7 @@ export default User
2688
2776
  +--------------------------------------------------------------------------+
2689
2777
 
2690
2778
  // in file Phone.ts
2691
- import { Model , Blueprint , TSchema , TSchemaStatic } from 'tspace-mysql'
2779
+ import { Model , Blueprint , type T } from 'tspace-mysql'
2692
2780
  import { User } from './User.ts'
2693
2781
  const schemaPhone = {
2694
2782
  id :Blueprint.int().notNull().primary().autoIncrement(),
@@ -2699,7 +2787,7 @@ const schemaPhone = {
2699
2787
  updatedAt :Blueprint.timestamp().null()
2700
2788
  }
2701
2789
 
2702
- type TSchemaPhone = TSchemaStatic<typeof schemaPhone>
2790
+ type TSchemaPhone = T.SchemaStatic<typeof schemaPhone>
2703
2791
 
2704
2792
  class Phone extends Model<TSchemaPhone> {
2705
2793
  constructor() {
@@ -2712,10 +2800,25 @@ class Phone extends Model<TSchemaPhone> {
2712
2800
  export { Phone }
2713
2801
  export default Phone
2714
2802
 
2803
+ // example basic
2804
+ type TS = T.Schema<typeof TSchemaUser>
2805
+ type TR = T.Relation<{ phone : Phone }>
2806
+
2807
+ type TSM = T.SchemaModel<User>
2808
+ type TRM = T.RelationModel<User>
2809
+
2810
+ type TColumn = T.Column<User>
2811
+
2812
+ type TResults = T.Results<User>
2813
+ type TPaginateResults = T.Results<User, { paginate : true }>
2814
+
2815
+ type TRepository = T.Repository<User>
2816
+ type TRepositoryTypeOf = T.RepositoryTypeOf<User>
2817
+
2715
2818
  +--------------------------------------------------------------------------+
2716
2819
  ```
2717
2820
 
2718
- ### Safety Select
2821
+ ### Type Safety Select
2719
2822
 
2720
2823
  ```js
2721
2824
  import { User } from './User.ts'
@@ -2727,18 +2830,17 @@ const user = await new User().select('idx','username').findOne() ❌
2727
2830
  const user = await new User().except('id','username').findOne() ✅
2728
2831
  const user = await new User().except('idx','username').findOne() ❌
2729
2832
 
2730
- // TSchemaStatic not allowed to set any new keys without in the schema to results
2731
- user.withoutSchema = 1 ✅ // TSchema<User>
2732
- user.withoutSchema = 1 ❌ // TSchemaStatic<User>
2833
+ // T.SchemaStatic not allowed to set any new keys without in the schema to results
2834
+ user.withoutSchema = 1 ✅ // T.Schema<User>
2835
+ user.withoutSchema = 1 ❌ // T.SchemaStatic<User>
2733
2836
  // But can you make like this for cases
2734
2837
  const user = await new User().except('idx','username').findOne<{ withoutSchema : number }>()
2735
2838
  user.withoutSchema = 1 ✅
2736
2839
  ```
2737
2840
 
2738
- ### Safety OrderBy
2841
+ ### Type Safety OrderBy
2739
2842
 
2740
2843
  ```js
2741
-
2742
2844
  import { User } from './User.ts'
2743
2845
  import { Phone } from './Phone.ts'
2744
2846
 
@@ -2753,7 +2855,7 @@ const users = await new User().oldest('idx').findMany() ❌
2753
2855
 
2754
2856
  ```
2755
2857
 
2756
- ### Safety GroupBy
2858
+ ### Type Safety GroupBy
2757
2859
 
2758
2860
  ```js
2759
2861
  import { User } from './User.ts'
@@ -2764,7 +2866,7 @@ const users = await new User().groupBy('idx').findMany() ❌
2764
2866
 
2765
2867
  ```
2766
2868
 
2767
- ### Safety Where
2869
+ ### Type Safety Where
2768
2870
 
2769
2871
  ```js
2770
2872
  import { User } from './User.ts'
@@ -2802,7 +2904,7 @@ const users = await new User()
2802
2904
 
2803
2905
  ```
2804
2906
 
2805
- ### Safety Insert
2907
+ ### Type Safety Insert
2806
2908
 
2807
2909
  ```js
2808
2910
  import { User } from './User.ts'
@@ -2816,7 +2918,7 @@ const users = await new User().create({ idx : 10 }).save() ❌
2816
2918
 
2817
2919
  ```
2818
2920
 
2819
- ### Safety Update
2921
+ ### Type Safety Update
2820
2922
 
2821
2923
  ```js
2822
2924
  import { User } from './User.ts'
@@ -2829,7 +2931,7 @@ const users = await new User().update({ idx : 10 }).where('idx',1).save() ❌
2829
2931
 
2830
2932
  ```
2831
2933
 
2832
- ### Safety Delete
2934
+ ### Type Safety Delete
2833
2935
 
2834
2936
  ```js
2835
2937
  import { User } from './User.ts'
@@ -2840,10 +2942,10 @@ const users = await new User().where('idx',1).delete() ❌
2840
2942
 
2841
2943
  ```
2842
2944
 
2843
- ### Safety Relationships
2945
+ ### Type Safety Relationships
2844
2946
 
2845
2947
  ```js
2846
- import { TSchemaModel } from 'tspace-mysql'
2948
+ import { type T } from 'tspace-mysql'
2847
2949
  import { User } from './User.ts'
2848
2950
  import { Phone } from './Phone.ts'
2849
2951
  // Case #1 : Relationship with 2 relations 'phone' and 'phones'
@@ -2874,7 +2976,7 @@ import { Phone } from './Phone.ts'
2874
2976
  // good 👍👍👍
2875
2977
  const users = await new User()
2876
2978
  .relations('phone','phones')
2877
- .findMany<{ phone : TSchemaModel<Phone> , phones : TSchemaModel<Phone>[] }>()
2979
+ .findMany<{ phone : T.SchemaModel<Phone> , phones : T.SchemaModel<Phone>[] }>()
2878
2980
 
2879
2981
  for(const user of users) {
2880
2982
  user.phone ✅
@@ -2892,7 +2994,7 @@ for(const user of users) {
2892
2994
  .relations('phone','phones')
2893
2995
  .relationQuery('phone' , (query : Phone) => query.relations('user'))
2894
2996
  .relationQuery('phones' , (query : Phone) => query.relations('user'))
2895
- .findMany<{ phone : TSchemaModel<Phone> , phones : TSchemaModel<Phone>[] }>()
2997
+ .findMany<{ phone : T.SchemaModel<Phone> , phones : T.SchemaModel<Phone>[] }>()
2896
2998
 
2897
2999
  for(const user of users) {
2898
3000
  user.phone.user ❌
@@ -2920,8 +3022,8 @@ for(const user of users) {
2920
3022
  .relationQuery('phone' , (query : Phone) => query.relations('user'))
2921
3023
  .relationQuery('phones' , (query : Phone) => query.relations('user'))
2922
3024
  .findMany<{
2923
- phone : Partial<TSchemaModel<Phone>> & { user : TSchemaModel<User>};
2924
- phones : (Partial<TSchemaModel<Phone>> & { user : TSchemaModel<User>})[];
3025
+ phone : Partial<T.SchemaModel<Phone>> & { user : T.SchemaModel<User>};
3026
+ phones : (Partial<T.SchemaModel<Phone>> & { user : T.SchemaModel<User>})[];
2925
3027
  }>()
2926
3028
 
2927
3029
  for(const user of users) {
@@ -2936,23 +3038,23 @@ for(const user of users) {
2936
3038
  +--------------------------------------------------------------------------+
2937
3039
  // If you don't want to set types for every returning method such as 'findOne', 'findMany', and so on...
2938
3040
 
2939
- import { Model , Blueprint , TSchema , TSchemaStatic , TRelation } from 'tspace-mysql'
3041
+ import { Model , Blueprint , type T } from 'tspace-mysql'
2940
3042
  import { Phone } from '../Phone'
2941
3043
 
2942
3044
  const schemaUser = {
2943
- id :Blueprint.int().notNull().primary().autoIncrement(),
2944
- uuid :Blueprint.varchar(50).null(),
2945
- email :Blueprint.varchar(50).null(),
2946
- name :Blueprint.varchar(255).null(),
2947
- username : Blueprint.varchar(255).null(),
2948
- password : Blueprint.varchar(255).null(),
3045
+ id :Blueprint.int().notNull().primary().autoIncrement(),
3046
+ uuid :Blueprint.varchar(50).null(),
3047
+ email :Blueprint.varchar(50).null(),
3048
+ name :Blueprint.varchar(255).null(),
3049
+ username :Blueprint.varchar(255).null(),
3050
+ password :Blueprint.varchar(255).null(),
2949
3051
  createdAt :Blueprint.timestamp().null(),
2950
3052
  updatedAt :Blueprint.timestamp().null()
2951
3053
  }
2952
3054
 
2953
- type TSchemaUser = TSchemaStatic<typeof schemaUser>
3055
+ type TSchemaUser = T.SchemaStatic<typeof schemaUser>
2954
3056
 
2955
- type TRelationUser = TRelation<{
3057
+ type TRelationUser = T.Relation<{
2956
3058
  phones : Phone[]
2957
3059
  phone : Phone
2958
3060
  }>
@@ -2974,28 +3076,25 @@ export { User }
2974
3076
  +--------------------------------------------------------------------------+
2975
3077
 
2976
3078
  // in file Phone.ts
2977
- import { Model , Blueprint , TSchema , TRelation } from 'tspace-mysql'
3079
+ import { Model , Blueprint , type T } from 'tspace-mysql'
2978
3080
  import { User } from './User.ts'
2979
3081
 
2980
3082
  const schemaPhone = {
2981
- id :Blueprint.int().notNull().primary().autoIncrement(),
2982
- uuid :Blueprint.varchar(50).null(),
2983
- userId : Blueprint.int().notNull(),
2984
- number :Blueprint.varchar(50).notNull(),
3083
+ id :Blueprint.int().notNull().primary().autoIncrement(),
3084
+ uuid :Blueprint.varchar(50).null(),
3085
+ userId :Blueprint.int().notNull(),
3086
+ number :Blueprint.varchar(50).notNull(),
2985
3087
  createdAt :Blueprint.timestamp().null(),
2986
3088
  updatedAt :Blueprint.timestamp().null()
2987
3089
  }
2988
3090
 
2989
- type TSchemaPhone = TSchema<typeof schemaPhone>
3091
+ type TSchemaPhone = T.Schema<typeof schemaPhone>
2990
3092
 
2991
- type TRelationPhone = TRelation<{
3093
+ type TRelationPhone = T.Relation<{
2992
3094
  user : User[]
2993
3095
  }>
2994
3096
 
2995
- class Phone extends Model<
2996
- TSchemaPhone,
2997
- TRelationPhone
2998
- > {
3097
+ class Phone extends Model<TSchemaPhone,TRelationPhone> {
2999
3098
  constructor() {
3000
3099
  super()
3001
3100
  this.useSchema(schemaPhone)
@@ -3045,17 +3144,100 @@ const users = await new User()
3045
3144
 
3046
3145
  ```
3047
3146
 
3147
+ ## Type Safety Results
3148
+ ```js
3149
+ import { type T } from 'tspace-mysql'
3150
+
3151
+ const fError = async () : Promise<T.Results<User>[]> => {
3152
+
3153
+ const users = [{
3154
+ id : 1,
3155
+ uuid: "12d4f08a-a20d-4f41-abac-81391e135d60",
3156
+ email: "tspace@example.com"
3157
+ }]
3158
+
3159
+ return users // ❌
3160
+ }
3161
+
3162
+ const fCorrect = async () : Promise<T.Results<User>[]> => {
3163
+
3164
+ const users = await new User().findMany()
3165
+
3166
+ return users // ✅
3167
+ }
3168
+
3169
+ ```
3170
+
3171
+ ## Metadata
3172
+ Get the metadata of a Model works only when a schema is added to the Model.
3173
+
3174
+ ```js
3175
+ import { Meta, Model , Blueprint , type T } from 'tspace-mysql';
3176
+
3177
+ const schema = {
3178
+ id : Blueprint.int().notNull().primary().autoIncrement(),
3179
+ uuid : Blueprint.varchar(50).null(),
3180
+ email : Blueprint.varchar(255).notNull().index('users.email@index'),
3181
+ name : Blueprint.varchar(255).null(),
3182
+ username : Blueprint.varchar(255).notNull(),
3183
+ password : Blueprint.varchar(255).notNull(),
3184
+ status : Blueprint.tinyInt().notNull().default(0),
3185
+ createdAt : Blueprint.timestamp().null(),
3186
+ updatedAt : Blueprint.timestamp().null()
3187
+ }
3188
+
3189
+ type TS = T.Schema<typeof schema>
3190
+
3191
+ class User extends Model<TS> {
3192
+ constructor() {
3193
+ super()
3194
+ this.useSchema(schema)
3195
+ this.useUUID()
3196
+ this.useTimestamp()
3197
+ }
3198
+ }
3199
+
3200
+ const meta = Meta(User)
3201
+
3202
+ const table = meta.table() // 'users'
3203
+ const column = meta.column('id') // 'id'
3204
+ const columnRef = meta.columnReference('id') // `users`.`id`
3205
+ const columnTypeOf = meta.columnTypeOf('id') // number
3206
+ const columnType = meta.columnType('id') // Int
3207
+ const columns = meta.columns() // ['id','uuid',...'updatedAt']
3208
+ const hasColumn = meta.hasColumn('idx') // false
3209
+ const primaryKey = meta.primaryKey() // 'id'
3210
+ const indexes = meta.indexes() // ['users.email@index']
3211
+ const nullable = meta.nullable() // ['uuid','name','createdAt','updatedAt']
3212
+ const defaults = meta.defaults() // { status : 0 }
3213
+
3214
+ console.log({
3215
+ table,
3216
+ column,
3217
+ columnRef,
3218
+ columnTypeOf,
3219
+ columnType,
3220
+ columns,
3221
+ hasColumn,
3222
+ primaryKey,
3223
+ indexes,
3224
+ nullable,
3225
+ defaults
3226
+ })
3227
+
3228
+ ```
3229
+
3048
3230
  ## Repository
3049
3231
  ```js
3050
3232
  Repository is a mechanism that encapsulates all database operations related to a specific model.
3051
3233
  It provides methods for querying, inserting, updating, and deleting records in the database associated with the model.
3052
3234
 
3053
- ** The Repository check always type safety if model is used the type of schema
3235
+ ** The Repository check always type Type Safety if model is used the type of schema
3054
3236
 
3055
3237
  ```
3056
3238
  ### Repository Select Statements
3057
3239
  ```js
3058
- import { Repository , TRepository , OP } from 'tspace-mysql'
3240
+ import { Repository, OP , type T } from 'tspace-mysql'
3059
3241
  import { User } from '../Models/User'
3060
3242
 
3061
3243
  const userRepository = Repository(User)
@@ -3248,8 +3430,12 @@ try {
3248
3430
  transaction
3249
3431
  })
3250
3432
 
3433
+ // after your use commit if use same transction for actions this transction will auto commit
3251
3434
  await transaction.commit()
3252
3435
 
3436
+ // ensure the nothing with transction just use end of transction
3437
+ await transaction.end();
3438
+
3253
3439
  } catch (err) {
3254
3440
 
3255
3441
  await transaction.rollback()
@@ -3259,39 +3445,228 @@ try {
3259
3445
 
3260
3446
  ### Repository Relations
3261
3447
  ```js
3262
- import { Repository , TRepository , OP } from 'tspace-mysql'
3448
+ import { Repository , OP } from 'tspace-mysql'
3263
3449
  import { User } from '../Models/User'
3264
3450
  import { Phone } from '../Models/Phone'
3265
3451
 
3266
3452
  const userRepository = Repository(User)
3267
3453
 
3268
3454
  const userHasPhones = await userRepository.findOne({
3269
- select : ['*'],
3455
+ select : {
3456
+ id : true,
3457
+ name : true,
3458
+ username : true,
3459
+ phone : {
3460
+ id : true,
3461
+ user_id : true,
3462
+ name: true
3463
+ }
3464
+ },
3270
3465
  where : {
3271
3466
  id: 1
3272
3467
  },
3273
- relations : ['phone'],
3274
- relationQuery:{
3275
- name : 'phone',
3276
- callback: () : TRepository<Phone> => ({ // add type for the callback know to check type of the model
3277
- select: ['id', 'userId', 'name'],
3278
- relations : ['user']
3279
- })
3468
+ relations: {
3469
+ phone: {
3470
+ user : true
3471
+ }
3280
3472
  }
3281
- })
3473
+ });
3282
3474
 
3283
3475
  const phoneRepository = Repository(Phone)
3284
3476
 
3285
3477
  const phoneBelongUser = await phoneRepository.findOne({
3286
- select : ['*'],
3478
+ select : '*',
3287
3479
  where : {
3288
3480
  id: 1
3289
3481
  },
3290
- relations : ['user']
3482
+ relations : {
3483
+ user : true
3484
+ }
3291
3485
  })
3292
3486
 
3293
3487
  ```
3294
3488
 
3489
+ ## View
3490
+
3491
+ Your database schema can also use views. These views are represented by classes that behave similarly to models,
3492
+ but they are based on stored SQL queries instead of actual tables.
3493
+ Let's look at a basic view class example:
3494
+ ```js
3495
+
3496
+ import { type T, Blueprint, Model , View , Meta } from 'tspace-mysql'
3497
+
3498
+ const schemaUser = {
3499
+ id: Blueprint.int().notNull().primary().autoIncrement(),
3500
+ uuid: Blueprint.varchar(50).null().index(),
3501
+ name: Blueprint.varchar(191).notNull(),
3502
+ email: Blueprint.varchar(191).notNull()
3503
+ }
3504
+
3505
+ type TUser = T.Schema<typeof schemaUser>
3506
+
3507
+ class User extends Model<TUser> {
3508
+ protected boot(): void {
3509
+ this.useSchema(schemaUser)
3510
+ }
3511
+ }
3512
+
3513
+ const schemaPost = {
3514
+ id: Blueprint.int().notNull().primary().autoIncrement(),
3515
+ uuid: Blueprint.varchar(50).null().index(),
3516
+ user_id :Blueprint.int().notnull(),
3517
+ title: Blueprint.varchar(191).notNull(),
3518
+ content: Blueprint.varchar(191).notNull()
3519
+ }
3520
+
3521
+ type TPost = T.Schema<typeof schemaPost>
3522
+
3523
+ class Post extends Model<TPost> {
3524
+ protected boot(): void {
3525
+ this.useSchema(schemaPost)
3526
+ }
3527
+ }
3528
+
3529
+ const schemaUserPostCountView = {
3530
+ id :Blueprint.int().notNull().primary().autoIncrement(),
3531
+ user_id :Blueprint.int().notnull(),
3532
+ name :Blueprint.varchar(255).null(),
3533
+ post_count : Blueprint.int().notnull()
3534
+ }
3535
+
3536
+ type TSUserPostCountView = T.Schema<typeof schemaUserPostCountView>
3537
+ type TRUserPostCountView = T.Relation<{
3538
+ user: User
3539
+ }>
3540
+
3541
+ class UserPostCountView extends View<TSUserPostCountView,TRUserPostCountView> {
3542
+
3543
+ protected boot(): void {
3544
+ this.useSchema(schemaUserPostCountView)
3545
+ const metaUser = Meta(User)
3546
+ const metaPost = Meta(Post)
3547
+
3548
+ this.createView({
3549
+ synchronize: true,
3550
+ expression : new User()
3551
+ .selectRaw(`ROW_NUMBER() OVER (ORDER BY ${metaUser.columnRef('id')}) AS id`)
3552
+ .selectRaw(`${metaUser.columnRef('id')} AS user_id`)
3553
+ .selectRaw(metaUser.columnRef('name'))
3554
+ .select(metaUser.columnRef('email'))
3555
+ .selectRaw(`COUNT(${metaPost.columnRef('id')}) AS post_count`)
3556
+ .leftJoin(metaUser.columnRef('id'),metaPost.columnRef('user_id'))
3557
+ .groupBy(metaUser.columnRef('id'))
3558
+ .groupBy(metaUser.columnRef('name'))
3559
+ .toString()
3560
+
3561
+ // Look like this
3562
+ // expression :
3563
+ // SELECT
3564
+ // ROW_NUMBER() OVER (ORDER BY `users`.`id`) AS id,
3565
+ // `users`.`id` AS user_id, `users`.`name`, `users`.`email`,
3566
+ // COUNT(`posts`.`id`) AS post_count
3567
+ // FROM `users`
3568
+ // LEFT JOIN `posts` ON `users`.`id` = `posts`.`user_id`
3569
+ // GROUP BY `users`.`id`, `users`.`name`
3570
+ })
3571
+
3572
+ this.belongsTo({ name : 'user' , model : User })
3573
+ }
3574
+ }
3575
+
3576
+ new UserPostCountView()
3577
+ .with('user')
3578
+ .get()
3579
+ .then( v=> {
3580
+ console.log(v)
3581
+ })
3582
+
3583
+ ```
3584
+
3585
+ ## Stored Procedure
3586
+ StoredProcedure is a predefined set of SQL statements stored in the database that you can call (execute) by name.
3587
+ ```js
3588
+
3589
+ import { StoredProcedure } from 'tspace-mysql'
3590
+
3591
+ type T = {
3592
+ AddUser: {
3593
+ params: {
3594
+ name : string;
3595
+ email: string;
3596
+ } | [string,string];
3597
+ result: {
3598
+ fieldCount: number;
3599
+ affectedRows: number;
3600
+ insertId: number;
3601
+ info: string;
3602
+ serverStatus: number;
3603
+ warningStatus: number;
3604
+ changedRows: number;
3605
+ }
3606
+ };
3607
+ GetUser: {
3608
+ params: [number];
3609
+ result: any[]
3610
+ },
3611
+ GetUsers: {
3612
+ params: [];
3613
+ result: any[]
3614
+ }
3615
+ };
3616
+
3617
+ class MyStoreProcedure extends StoredProcedure<T> {
3618
+ protected boot(): void {
3619
+
3620
+ this.createProcedure({
3621
+ name: 'AddUser',
3622
+ expression: `
3623
+ CREATE PROCEDURE AddUser(IN name VARCHAR(255), IN email VARCHAR(255))
3624
+ BEGIN
3625
+ INSERT INTO users (name, email) VALUES (name, email);
3626
+ END;
3627
+ `,
3628
+ synchronize: true
3629
+ });
3630
+
3631
+ this.createProcedure({
3632
+ name: 'GetUsers',
3633
+ expression: `
3634
+ CREATE PROCEDURE GetUsers()
3635
+ BEGIN
3636
+ SELECT * FROM users LIMIT 5;
3637
+ END;
3638
+ `,
3639
+ synchronize: true
3640
+ });
3641
+
3642
+ this.createProcedure({
3643
+ name: 'GetUser',
3644
+ expression: `
3645
+ CREATE PROCEDURE GetUser(IN userId INT)
3646
+ BEGIN
3647
+ SELECT * FROM users WHERE id = userId LIMIT 1;
3648
+ END;
3649
+ `,
3650
+ synchronize: true
3651
+ })
3652
+ }
3653
+ }
3654
+
3655
+ const storeProcedure = new MyStoreProcedure()
3656
+
3657
+ storeProcedure.call('AddUser', { name : 'tspace-mysql' , email : 'tspace-mysql@example.com'})
3658
+ .then(r => console.log(r))
3659
+ .catch(e => console.log(e))
3660
+
3661
+ storeProcedure.call('GetUser',[1])
3662
+ .then(r => console.log(r))
3663
+ .catch(e => console.log(e))
3664
+
3665
+ storeProcedure.call('GetUsers',[])
3666
+ .then(r => console.log(r))
3667
+ .catch(e => console.log(e))
3668
+
3669
+ ```
3295
3670
  ## Blueprint
3296
3671
 
3297
3672
  Blueprint is a tool used for defining database schemas programmatically.