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.
- package/README.md +443 -68
- 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 +2 -2
- 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 +39 -30
- package/build/lib/core/Builder.js +1094 -1044
- 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.d.ts +38 -38
- package/build/lib/core/DB.js +119 -115
- 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 +60 -15
- 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 +158 -94
- package/build/lib/core/Model.js +1586 -1203
- package/build/lib/core/Model.js.map +1 -1
- package/build/lib/core/Nest/index.d.ts +3 -1
- package/build/lib/core/Nest/index.js +4 -2
- package/build/lib/core/Nest/index.js.map +1 -1
- package/build/lib/{connection/index.d.ts → core/Pool.d.ts} +2 -1
- package/build/lib/{connection/index.js → core/Pool.js} +74 -6
- package/build/lib/core/Pool.js.map +1 -0
- package/build/lib/core/Repository.d.ts +16 -16
- package/build/lib/core/Repository.js +73 -45
- 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 +17 -12
- package/build/lib/core/index.js +9 -4
- package/build/lib/core/index.js.map +1 -1
- package/build/lib/types/index.d.ts +23 -3
- package/build/lib/utils/index.js +5 -2
- package/build/lib/utils/index.js.map +1 -1
- package/build/tests/01-Pool.test.js +0 -10
- package/build/tests/01-Pool.test.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/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 ,
|
|
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 =
|
|
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
|
|
2652
|
-
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:
|
|
2653
2741
|
|
|
2654
2742
|
```js
|
|
2655
2743
|
// in file User.ts
|
|
2656
|
-
import { Model , Blueprint ,
|
|
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 =
|
|
2671
|
-
// TSchemaUser =
|
|
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 ,
|
|
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 =
|
|
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
|
-
//
|
|
2731
|
-
user.withoutSchema = 1 ✅ //
|
|
2732
|
-
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>
|
|
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 {
|
|
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 :
|
|
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 :
|
|
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<
|
|
2924
|
-
phones : (Partial<
|
|
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 ,
|
|
3041
|
+
import { Model , Blueprint , type T } from 'tspace-mysql'
|
|
2940
3042
|
import { Phone } from '../Phone'
|
|
2941
3043
|
|
|
2942
3044
|
const schemaUser = {
|
|
2943
|
-
id
|
|
2944
|
-
uuid
|
|
2945
|
-
email
|
|
2946
|
-
name
|
|
2947
|
-
username
|
|
2948
|
-
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(),
|
|
2949
3051
|
createdAt :Blueprint.timestamp().null(),
|
|
2950
3052
|
updatedAt :Blueprint.timestamp().null()
|
|
2951
3053
|
}
|
|
2952
3054
|
|
|
2953
|
-
type TSchemaUser =
|
|
3055
|
+
type TSchemaUser = T.SchemaStatic<typeof schemaUser>
|
|
2954
3056
|
|
|
2955
|
-
type TRelationUser =
|
|
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 ,
|
|
3079
|
+
import { Model , Blueprint , type T } from 'tspace-mysql'
|
|
2978
3080
|
import { User } from './User.ts'
|
|
2979
3081
|
|
|
2980
3082
|
const schemaPhone = {
|
|
2981
|
-
id
|
|
2982
|
-
uuid
|
|
2983
|
-
userId
|
|
2984
|
-
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(),
|
|
2985
3087
|
createdAt :Blueprint.timestamp().null(),
|
|
2986
3088
|
updatedAt :Blueprint.timestamp().null()
|
|
2987
3089
|
}
|
|
2988
3090
|
|
|
2989
|
-
type TSchemaPhone =
|
|
3091
|
+
type TSchemaPhone = T.Schema<typeof schemaPhone>
|
|
2990
3092
|
|
|
2991
|
-
type TRelationPhone =
|
|
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
|
|
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
|
|
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 ,
|
|
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
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
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 :
|
|
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.
|