tspace-mysql 1.8.3 → 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.
- package/README.md +372 -62
- package/build/cli/generate/model.js +3 -3
- package/build/cli/generate/model.js.map +1 -1
- package/build/lib/constants/index.d.ts +7 -1
- package/build/lib/constants/index.js +7 -1
- package/build/lib/constants/index.js.map +1 -1
- package/build/lib/core/Abstracts/AbstractBuilder.d.ts +1 -1
- package/build/lib/core/Abstracts/AbstractBuilder.js.map +1 -1
- package/build/lib/core/Abstracts/AbstractDB.d.ts +1 -1
- package/build/lib/core/Abstracts/AbstractDB.js.map +1 -1
- package/build/lib/core/Abstracts/AbstractView.d.ts +10 -0
- package/build/lib/core/Abstracts/AbstractView.js +9 -0
- package/build/lib/core/Abstracts/AbstractView.js.map +1 -0
- package/build/lib/core/Blueprint.d.ts +24 -4
- package/build/lib/core/Blueprint.js +78 -87
- package/build/lib/core/Blueprint.js.map +1 -1
- package/build/lib/core/Builder.d.ts +13 -4
- package/build/lib/core/Builder.js +12 -40
- package/build/lib/core/Builder.js.map +1 -1
- package/build/lib/core/Cache/DBCache.js +15 -16
- package/build/lib/core/Cache/DBCache.js.map +1 -1
- package/build/lib/core/DB.js +1 -1
- package/build/lib/core/DB.js.map +1 -1
- package/build/lib/core/Decorator.d.ts +1 -1
- package/build/lib/core/Decorator.js.map +1 -1
- package/build/lib/core/Handlers/Relation.d.ts +2 -1
- package/build/lib/core/Handlers/Relation.js +51 -8
- package/build/lib/core/Handlers/Relation.js.map +1 -1
- package/build/lib/core/Handlers/State.d.ts +1 -0
- package/build/lib/core/Handlers/State.js +1 -1
- package/build/lib/core/Handlers/State.js.map +1 -1
- package/build/lib/core/JoinModel.d.ts +1 -1
- package/build/lib/core/JoinModel.js.map +1 -1
- package/build/lib/core/Meta.d.ts +55 -0
- package/build/lib/core/Meta.js +175 -0
- package/build/lib/core/Meta.js.map +1 -0
- package/build/lib/core/Model.d.ts +20 -6
- package/build/lib/core/Model.js +187 -11
- package/build/lib/core/Model.js.map +1 -1
- package/build/lib/core/Repository.js.map +1 -1
- package/build/lib/core/Schema.d.ts +2 -2
- package/build/lib/core/Schema.js +113 -78
- package/build/lib/core/Schema.js.map +1 -1
- package/build/lib/core/SqlLike.js.map +1 -1
- package/build/lib/core/StoredProcedure.d.ts +120 -0
- package/build/lib/core/StoredProcedure.js +161 -0
- package/build/lib/core/StoredProcedure.js.map +1 -0
- package/build/lib/core/UtilityTypes.d.ts +25 -44
- package/build/lib/core/View.d.ts +96 -0
- package/build/lib/core/View.js +141 -0
- package/build/lib/core/View.js.map +1 -0
- package/build/lib/core/index.d.ts +5 -0
- package/build/lib/core/index.js +7 -2
- package/build/lib/core/index.js.map +1 -1
- package/build/lib/types/index.d.ts +4 -0
- package/build/lib/utils/index.js +5 -2
- package/build/lib/utils/index.js.map +1 -1
- package/build/tests/04-Model-pattern.test.js +1 -1
- package/build/tests/04-Model-pattern.test.js.map +1 -1
- package/build/tests/05-View.test.d.ts +1 -0
- package/build/tests/05-View.test.js +83 -0
- package/build/tests/05-View.test.js.map +1 -0
- package/build/tests/06-Meta.test.d.ts +1 -0
- package/build/tests/06-Meta.test.js +103 -0
- package/build/tests/06-Meta.test.js.map +1 -0
- package/build/tests/07-Virtual-column.test.d.ts +1 -0
- package/build/tests/07-Virtual-column.test.js +160 -0
- package/build/tests/07-Virtual-column.test.js.map +1 -0
- package/build/tests/schema-spec.js +25 -25
- package/build/tests/schema-spec.js.map +1 -1
- package/package.json +1 -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,15 +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)
|
|
123
|
-
- [Safety
|
|
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)
|
|
124
127
|
- [Repository](#repository)
|
|
125
128
|
- [Repository Select Statements](#repository-select-statements)
|
|
126
129
|
- [Repository Insert Statements](#repository-insert-statements)
|
|
@@ -128,6 +131,8 @@ npm install tspace-mysql -g
|
|
|
128
131
|
- [Repository Delete Statements](#repository-delete-statements)
|
|
129
132
|
- [Repository Transactions](#repository-transactions)
|
|
130
133
|
- [Repository Relations](#repository-relations)
|
|
134
|
+
- [View](#view)
|
|
135
|
+
- [Stored Procedure](#stored-procedure)
|
|
131
136
|
- [Blueprint](#blueprint)
|
|
132
137
|
- [Cli](#cli)
|
|
133
138
|
- [Make Model](#make-model)
|
|
@@ -2478,7 +2483,7 @@ using the following:
|
|
|
2478
2483
|
#### Schema Model
|
|
2479
2484
|
|
|
2480
2485
|
```js
|
|
2481
|
-
import { Model, Blueprint ,
|
|
2486
|
+
import { Model, Blueprint , type T } from "tspace-mysql";
|
|
2482
2487
|
|
|
2483
2488
|
const schema = {
|
|
2484
2489
|
id: Blueprint.int().notNull().primary().autoIncrement(),
|
|
@@ -2492,7 +2497,7 @@ const schema = {
|
|
|
2492
2497
|
|
|
2493
2498
|
|
|
2494
2499
|
// make type in TS
|
|
2495
|
-
type TS =
|
|
2500
|
+
type TS = T.Schema<typeof Schema>
|
|
2496
2501
|
|
|
2497
2502
|
// the TSchemaUser will be created like that
|
|
2498
2503
|
/**
|
|
@@ -2519,6 +2524,60 @@ class User extends Model<TS> // use the schema for this User model
|
|
|
2519
2524
|
|
|
2520
2525
|
```
|
|
2521
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
|
+
|
|
2522
2581
|
#### Validation
|
|
2523
2582
|
|
|
2524
2583
|
Validate the schema of Model
|
|
@@ -2677,12 +2736,12 @@ const user = await new User().trashed().findMany()
|
|
|
2677
2736
|
```
|
|
2678
2737
|
|
|
2679
2738
|
### Type Safety
|
|
2680
|
-
Type
|
|
2681
|
-
Type
|
|
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:
|
|
2682
2741
|
|
|
2683
2742
|
```js
|
|
2684
2743
|
// in file User.ts
|
|
2685
|
-
import { Model , Blueprint ,
|
|
2744
|
+
import { Model , Blueprint , type T } from 'tspace-mysql'
|
|
2686
2745
|
import Phone from '../Phone'
|
|
2687
2746
|
|
|
2688
2747
|
const schemaUser = {
|
|
@@ -2696,8 +2755,8 @@ const schemaUser = {
|
|
|
2696
2755
|
updatedAt :Blueprint.timestamp().null()
|
|
2697
2756
|
}
|
|
2698
2757
|
|
|
2699
|
-
type TSchemaUser =
|
|
2700
|
-
// TSchemaUser =
|
|
2758
|
+
type TSchemaUser = T.SchemaStatic<typeof schemaUser>
|
|
2759
|
+
// TSchemaUser = T.Schema<typeof schemaUser>
|
|
2701
2760
|
|
|
2702
2761
|
// TSchema allowed to set any new keys without in the schema to results
|
|
2703
2762
|
// TSchemaStatic not allowed to set any new keys without in the schema to results
|
|
@@ -2717,7 +2776,7 @@ export default User
|
|
|
2717
2776
|
+--------------------------------------------------------------------------+
|
|
2718
2777
|
|
|
2719
2778
|
// in file Phone.ts
|
|
2720
|
-
import { Model , Blueprint ,
|
|
2779
|
+
import { Model , Blueprint , type T } from 'tspace-mysql'
|
|
2721
2780
|
import { User } from './User.ts'
|
|
2722
2781
|
const schemaPhone = {
|
|
2723
2782
|
id :Blueprint.int().notNull().primary().autoIncrement(),
|
|
@@ -2728,7 +2787,7 @@ const schemaPhone = {
|
|
|
2728
2787
|
updatedAt :Blueprint.timestamp().null()
|
|
2729
2788
|
}
|
|
2730
2789
|
|
|
2731
|
-
type TSchemaPhone =
|
|
2790
|
+
type TSchemaPhone = T.SchemaStatic<typeof schemaPhone>
|
|
2732
2791
|
|
|
2733
2792
|
class Phone extends Model<TSchemaPhone> {
|
|
2734
2793
|
constructor() {
|
|
@@ -2741,10 +2800,25 @@ class Phone extends Model<TSchemaPhone> {
|
|
|
2741
2800
|
export { Phone }
|
|
2742
2801
|
export default Phone
|
|
2743
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
|
+
|
|
2744
2818
|
+--------------------------------------------------------------------------+
|
|
2745
2819
|
```
|
|
2746
2820
|
|
|
2747
|
-
### Safety Select
|
|
2821
|
+
### Type Safety Select
|
|
2748
2822
|
|
|
2749
2823
|
```js
|
|
2750
2824
|
import { User } from './User.ts'
|
|
@@ -2756,18 +2830,17 @@ const user = await new User().select('idx','username').findOne() ❌
|
|
|
2756
2830
|
const user = await new User().except('id','username').findOne() ✅
|
|
2757
2831
|
const user = await new User().except('idx','username').findOne() ❌
|
|
2758
2832
|
|
|
2759
|
-
//
|
|
2760
|
-
user.withoutSchema = 1 ✅ //
|
|
2761
|
-
user.withoutSchema = 1 ❌ //
|
|
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>
|
|
2762
2836
|
// But can you make like this for cases
|
|
2763
2837
|
const user = await new User().except('idx','username').findOne<{ withoutSchema : number }>()
|
|
2764
2838
|
user.withoutSchema = 1 ✅
|
|
2765
2839
|
```
|
|
2766
2840
|
|
|
2767
|
-
### Safety OrderBy
|
|
2841
|
+
### Type Safety OrderBy
|
|
2768
2842
|
|
|
2769
2843
|
```js
|
|
2770
|
-
|
|
2771
2844
|
import { User } from './User.ts'
|
|
2772
2845
|
import { Phone } from './Phone.ts'
|
|
2773
2846
|
|
|
@@ -2782,7 +2855,7 @@ const users = await new User().oldest('idx').findMany() ❌
|
|
|
2782
2855
|
|
|
2783
2856
|
```
|
|
2784
2857
|
|
|
2785
|
-
### Safety GroupBy
|
|
2858
|
+
### Type Safety GroupBy
|
|
2786
2859
|
|
|
2787
2860
|
```js
|
|
2788
2861
|
import { User } from './User.ts'
|
|
@@ -2793,7 +2866,7 @@ const users = await new User().groupBy('idx').findMany() ❌
|
|
|
2793
2866
|
|
|
2794
2867
|
```
|
|
2795
2868
|
|
|
2796
|
-
### Safety Where
|
|
2869
|
+
### Type Safety Where
|
|
2797
2870
|
|
|
2798
2871
|
```js
|
|
2799
2872
|
import { User } from './User.ts'
|
|
@@ -2831,7 +2904,7 @@ const users = await new User()
|
|
|
2831
2904
|
|
|
2832
2905
|
```
|
|
2833
2906
|
|
|
2834
|
-
### Safety Insert
|
|
2907
|
+
### Type Safety Insert
|
|
2835
2908
|
|
|
2836
2909
|
```js
|
|
2837
2910
|
import { User } from './User.ts'
|
|
@@ -2845,7 +2918,7 @@ const users = await new User().create({ idx : 10 }).save() ❌
|
|
|
2845
2918
|
|
|
2846
2919
|
```
|
|
2847
2920
|
|
|
2848
|
-
### Safety Update
|
|
2921
|
+
### Type Safety Update
|
|
2849
2922
|
|
|
2850
2923
|
```js
|
|
2851
2924
|
import { User } from './User.ts'
|
|
@@ -2858,7 +2931,7 @@ const users = await new User().update({ idx : 10 }).where('idx',1).save() ❌
|
|
|
2858
2931
|
|
|
2859
2932
|
```
|
|
2860
2933
|
|
|
2861
|
-
### Safety Delete
|
|
2934
|
+
### Type Safety Delete
|
|
2862
2935
|
|
|
2863
2936
|
```js
|
|
2864
2937
|
import { User } from './User.ts'
|
|
@@ -2869,10 +2942,10 @@ const users = await new User().where('idx',1).delete() ❌
|
|
|
2869
2942
|
|
|
2870
2943
|
```
|
|
2871
2944
|
|
|
2872
|
-
### Safety Relationships
|
|
2945
|
+
### Type Safety Relationships
|
|
2873
2946
|
|
|
2874
2947
|
```js
|
|
2875
|
-
import {
|
|
2948
|
+
import { type T } from 'tspace-mysql'
|
|
2876
2949
|
import { User } from './User.ts'
|
|
2877
2950
|
import { Phone } from './Phone.ts'
|
|
2878
2951
|
// Case #1 : Relationship with 2 relations 'phone' and 'phones'
|
|
@@ -2903,7 +2976,7 @@ import { Phone } from './Phone.ts'
|
|
|
2903
2976
|
// good 👍👍👍
|
|
2904
2977
|
const users = await new User()
|
|
2905
2978
|
.relations('phone','phones')
|
|
2906
|
-
.findMany<{ phone :
|
|
2979
|
+
.findMany<{ phone : T.SchemaModel<Phone> , phones : T.SchemaModel<Phone>[] }>()
|
|
2907
2980
|
|
|
2908
2981
|
for(const user of users) {
|
|
2909
2982
|
user.phone ✅
|
|
@@ -2921,7 +2994,7 @@ for(const user of users) {
|
|
|
2921
2994
|
.relations('phone','phones')
|
|
2922
2995
|
.relationQuery('phone' , (query : Phone) => query.relations('user'))
|
|
2923
2996
|
.relationQuery('phones' , (query : Phone) => query.relations('user'))
|
|
2924
|
-
.findMany<{ phone :
|
|
2997
|
+
.findMany<{ phone : T.SchemaModel<Phone> , phones : T.SchemaModel<Phone>[] }>()
|
|
2925
2998
|
|
|
2926
2999
|
for(const user of users) {
|
|
2927
3000
|
user.phone.user ❌
|
|
@@ -2949,8 +3022,8 @@ for(const user of users) {
|
|
|
2949
3022
|
.relationQuery('phone' , (query : Phone) => query.relations('user'))
|
|
2950
3023
|
.relationQuery('phones' , (query : Phone) => query.relations('user'))
|
|
2951
3024
|
.findMany<{
|
|
2952
|
-
phone : Partial<
|
|
2953
|
-
phones : (Partial<
|
|
3025
|
+
phone : Partial<T.SchemaModel<Phone>> & { user : T.SchemaModel<User>};
|
|
3026
|
+
phones : (Partial<T.SchemaModel<Phone>> & { user : T.SchemaModel<User>})[];
|
|
2954
3027
|
}>()
|
|
2955
3028
|
|
|
2956
3029
|
for(const user of users) {
|
|
@@ -2965,23 +3038,23 @@ for(const user of users) {
|
|
|
2965
3038
|
+--------------------------------------------------------------------------+
|
|
2966
3039
|
// If you don't want to set types for every returning method such as 'findOne', 'findMany', and so on...
|
|
2967
3040
|
|
|
2968
|
-
import { Model , Blueprint ,
|
|
3041
|
+
import { Model , Blueprint , type T } from 'tspace-mysql'
|
|
2969
3042
|
import { Phone } from '../Phone'
|
|
2970
3043
|
|
|
2971
3044
|
const schemaUser = {
|
|
2972
|
-
id
|
|
2973
|
-
uuid
|
|
2974
|
-
email
|
|
2975
|
-
name
|
|
2976
|
-
username
|
|
2977
|
-
password
|
|
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(),
|
|
2978
3051
|
createdAt :Blueprint.timestamp().null(),
|
|
2979
3052
|
updatedAt :Blueprint.timestamp().null()
|
|
2980
3053
|
}
|
|
2981
3054
|
|
|
2982
|
-
type TSchemaUser =
|
|
3055
|
+
type TSchemaUser = T.SchemaStatic<typeof schemaUser>
|
|
2983
3056
|
|
|
2984
|
-
type TRelationUser =
|
|
3057
|
+
type TRelationUser = T.Relation<{
|
|
2985
3058
|
phones : Phone[]
|
|
2986
3059
|
phone : Phone
|
|
2987
3060
|
}>
|
|
@@ -3003,28 +3076,25 @@ export { User }
|
|
|
3003
3076
|
+--------------------------------------------------------------------------+
|
|
3004
3077
|
|
|
3005
3078
|
// in file Phone.ts
|
|
3006
|
-
import { Model , Blueprint ,
|
|
3079
|
+
import { Model , Blueprint , type T } from 'tspace-mysql'
|
|
3007
3080
|
import { User } from './User.ts'
|
|
3008
3081
|
|
|
3009
3082
|
const schemaPhone = {
|
|
3010
|
-
id
|
|
3011
|
-
uuid
|
|
3012
|
-
userId
|
|
3013
|
-
number
|
|
3083
|
+
id :Blueprint.int().notNull().primary().autoIncrement(),
|
|
3084
|
+
uuid :Blueprint.varchar(50).null(),
|
|
3085
|
+
userId :Blueprint.int().notNull(),
|
|
3086
|
+
number :Blueprint.varchar(50).notNull(),
|
|
3014
3087
|
createdAt :Blueprint.timestamp().null(),
|
|
3015
3088
|
updatedAt :Blueprint.timestamp().null()
|
|
3016
3089
|
}
|
|
3017
3090
|
|
|
3018
|
-
type TSchemaPhone =
|
|
3091
|
+
type TSchemaPhone = T.Schema<typeof schemaPhone>
|
|
3019
3092
|
|
|
3020
|
-
type TRelationPhone =
|
|
3093
|
+
type TRelationPhone = T.Relation<{
|
|
3021
3094
|
user : User[]
|
|
3022
3095
|
}>
|
|
3023
3096
|
|
|
3024
|
-
class Phone extends Model<
|
|
3025
|
-
TSchemaPhone,
|
|
3026
|
-
TRelationPhone
|
|
3027
|
-
> {
|
|
3097
|
+
class Phone extends Model<TSchemaPhone,TRelationPhone> {
|
|
3028
3098
|
constructor() {
|
|
3029
3099
|
super()
|
|
3030
3100
|
this.useSchema(schemaPhone)
|
|
@@ -3074,11 +3144,11 @@ const users = await new User()
|
|
|
3074
3144
|
|
|
3075
3145
|
```
|
|
3076
3146
|
|
|
3077
|
-
## Safety
|
|
3147
|
+
## Type Safety Results
|
|
3078
3148
|
```js
|
|
3079
|
-
import type
|
|
3149
|
+
import { type T } from 'tspace-mysql'
|
|
3080
3150
|
|
|
3081
|
-
const fError = async () : Promise<
|
|
3151
|
+
const fError = async () : Promise<T.Results<User>[]> => {
|
|
3082
3152
|
|
|
3083
3153
|
const users = [{
|
|
3084
3154
|
id : 1,
|
|
@@ -3089,7 +3159,7 @@ const fError = async () : Promise<TResult<User>[]> => {
|
|
|
3089
3159
|
return users // ❌
|
|
3090
3160
|
}
|
|
3091
3161
|
|
|
3092
|
-
const fCorrect = async () : Promise<
|
|
3162
|
+
const fCorrect = async () : Promise<T.Results<User>[]> => {
|
|
3093
3163
|
|
|
3094
3164
|
const users = await new User().findMany()
|
|
3095
3165
|
|
|
@@ -3098,17 +3168,76 @@ const fCorrect = async () : Promise<TResult<User>[]> => {
|
|
|
3098
3168
|
|
|
3099
3169
|
```
|
|
3100
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
|
+
|
|
3101
3230
|
## Repository
|
|
3102
3231
|
```js
|
|
3103
3232
|
Repository is a mechanism that encapsulates all database operations related to a specific model.
|
|
3104
3233
|
It provides methods for querying, inserting, updating, and deleting records in the database associated with the model.
|
|
3105
3234
|
|
|
3106
|
-
** The Repository check always type
|
|
3235
|
+
** The Repository check always type Type Safety if model is used the type of schema
|
|
3107
3236
|
|
|
3108
3237
|
```
|
|
3109
3238
|
### Repository Select Statements
|
|
3110
3239
|
```js
|
|
3111
|
-
import { Repository
|
|
3240
|
+
import { Repository, OP , type T } from 'tspace-mysql'
|
|
3112
3241
|
import { User } from '../Models/User'
|
|
3113
3242
|
|
|
3114
3243
|
const userRepository = Repository(User)
|
|
@@ -3316,7 +3445,7 @@ try {
|
|
|
3316
3445
|
|
|
3317
3446
|
### Repository Relations
|
|
3318
3447
|
```js
|
|
3319
|
-
import { Repository ,
|
|
3448
|
+
import { Repository , OP } from 'tspace-mysql'
|
|
3320
3449
|
import { User } from '../Models/User'
|
|
3321
3450
|
import { Phone } from '../Models/Phone'
|
|
3322
3451
|
|
|
@@ -3357,6 +3486,187 @@ const phoneBelongUser = await phoneRepository.findOne({
|
|
|
3357
3486
|
|
|
3358
3487
|
```
|
|
3359
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
|
+
```
|
|
3360
3670
|
## Blueprint
|
|
3361
3671
|
|
|
3362
3672
|
Blueprint is a tool used for defining database schemas programmatically.
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const Model = (model, npm, schema) => {
|
|
4
|
-
return `import { Model , Blueprint ,
|
|
4
|
+
return `import { Model , Blueprint , type T } from '${npm}'
|
|
5
5
|
|
|
6
6
|
const schema = ${schema}
|
|
7
7
|
|
|
8
|
-
type TS =
|
|
8
|
+
type TS = T.Schema<typeof schema>
|
|
9
9
|
|
|
10
|
-
type TR =
|
|
10
|
+
type TR = T.Relation<{
|
|
11
11
|
// ... name your relationship
|
|
12
12
|
}>
|
|
13
13
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.js","sourceRoot":"","sources":["../../../src/cli/generate/model.ts"],"names":[],"mappings":";;AAAA,MAAM,KAAK,GAAG,CAAC,KAAa,EAAE,GAAW,EAAE,MAAe,EAAE,EAAE;IAC9D,OAAO,
|
|
1
|
+
{"version":3,"file":"model.js","sourceRoot":"","sources":["../../../src/cli/generate/model.ts"],"names":[],"mappings":";;AAAA,MAAM,KAAK,GAAG,CAAC,KAAa,EAAE,GAAW,EAAE,MAAe,EAAE,EAAE;IAC9D,OAAO,+CAA+C,GAAG;;iBAExC,MAAM;;;;;;;;QAQf,KAAK;;;;;;;;;;;;WAYF,KAAK;iBACC,KAAK;CACrB,CAAA;AACD,CAAC,CAAA;AAED,kBAAe,KAAK,CAAA"}
|