myorm_pg 9.1.1 → 9.2.0

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 CHANGED
@@ -1,31 +1,288 @@
1
1
  # myorm_pg
2
2
 
3
- myorm_pg is a ORM writen with TypeScript with sintax similar with MyORMForPostgreSQL of .NET
3
+ **myorm_pg** is a lightweight ORM written in **TypeScript** for **PostgreSQL**.
4
4
 
5
- ## Installation
5
+ It focuses on:
6
+ - Strongly typed entities
7
+ - Decorator-based mapping
8
+ - Fluent and expressive queries
9
+ - Automatic relationship handling
10
+ - Simple database lifecycle management
6
11
 
12
+ ---
7
13
 
14
+ ## Installation
8
15
 
9
16
  ```bash
10
17
  npm install myorm_pg
11
18
  ```
12
- Enable decorators on tsconfig.json
19
+
20
+ ---
21
+
22
+ ## TypeScript Configuration
23
+
24
+ Decorators must be enabled in your `tsconfig.json`:
25
+
13
26
  ```json
14
- "experimentalDecorators": true,
15
- "emitDecoratorMetadata": true,
27
+ {
28
+ "experimentalDecorators": true,
29
+ "emitDecoratorMetadata": true
30
+ }
31
+ ```
32
+ ---
33
+
34
+
35
+
36
+ # Entities
37
+
38
+ Entities represent database tables and are defined using TypeScript classes combined with decorators.
39
+ Decorators are responsible for mapping classes, properties, and relationships directly to PostgreSQL structures.
40
+
41
+ ## Decorator Overview
42
+
43
+ ### @Table
44
+ Defines the database table name associated with the entity.
45
+
46
+ ### @Column
47
+ Marks a class property as a table column.
48
+ An optional parameter allows you to specify a custom column name.
49
+
50
+ ### @PrimaryKey
51
+ Indicates that the column is the primary key of the table.
52
+
53
+ ### @DataType
54
+ Explicitly defines the PostgreSQL data type for the column using DBTypes.
55
+
56
+ ## Relationship decorators
57
+ Define how entities relate to each other and how foreign keys and junction tables are generated:
58
+
59
+
60
+
61
+ ### @OneToMany
62
+ - Defines a one-to-many relationship. One entity instance is related to many instances of another entity
63
+
64
+ - Does NOT create a foreign key by itself
65
+
66
+ - Must always be paired with a corresponding **@ManyToOne** on the other side
67
+
68
+ - The foreign key is created on the many side
69
+ #### Example
70
+
71
+ ```typescript
72
+ // Person.ts
73
+ @OneToMany(() => Message, "From")
74
+ public MessagesWriten?: Message[];
75
+ ```
76
+ ```typescript
77
+ // Message.ts
78
+ @ManyToOne(() => Person, "MessagesWriten")
79
+ public From?: Person;
80
+ ```
81
+
82
+
83
+
84
+ ### @ManyToOne
85
+ - Defines the owning side of a one-to-many relationship.
86
+
87
+ - Many records point to one record
88
+
89
+ - This is the side responsible for persisting the relationship
90
+
91
+ #### Example
92
+
93
+ ```typescript
94
+ // Message.ts
95
+ @ManyToOne(() => Person, "MessagesWriten")
96
+ public From?: Person;
97
+ ```
98
+
99
+
100
+ ### @ManyToMany
101
+
102
+ - Defines a many-to-many relationship.
103
+
104
+ - Many records relate to many records
105
+
106
+ - You do not need to define the junction entity manually
107
+
108
+ #### Example:
109
+
110
+ ```typescript
111
+ // Person.ts
112
+ @ManyToMany(() => Message, "To")
113
+ public MessagesReceived?: Message[];
114
+ ```
115
+ ```typescript
116
+ // Message.ts
117
+ @ManyToMany(() => Person, "MessagesReceived")
118
+ public To?: Person[];
119
+ ```
120
+
121
+ ### @OneToOne
122
+
123
+ - Defines a one-to-one relationship.
124
+
125
+ - One record is associated with exactly one record
126
+
127
+
128
+
129
+ #### Example:
130
+
131
+ ```typescript
132
+ // Person.ts
133
+ @OneToOne(() => Profile, "Person")
134
+ public Profile?: Profile;
135
+ ```
136
+ ```typescript
137
+ // Profile.ts
138
+ @OneToOne(() => Person, "Profile")
139
+ public Person?: Person;
140
+ ```
141
+
142
+
143
+
144
+ ## Example of entities
145
+
146
+
147
+ ### Person.ts
148
+
149
+ ```typescript
150
+ import { Table, Column, PrimaryKey, DataType, OneToMany, OneToOne, ManyToMany, DBTypes} from 'myorm_pg';
151
+ import { Message } from './Message';
152
+
153
+ @Table("person_tb")
154
+ export class Person
155
+ {
156
+ // Primary key with SERIAL (auto-increment)
157
+ @PrimaryKey()
158
+ @Column()
159
+ @DataType(DBTypes.SERIAL)
160
+ public Id!: number;
161
+
162
+ // Simple text column
163
+ @Column()
164
+ public Name!: string;
165
+
166
+ // Column with custom database name
167
+ @Column("email_address")
168
+ public Email!: string;
169
+
170
+ // Numeric column
171
+ @Column()
172
+ public Age!: number;
173
+
174
+ // Explicit integer column
175
+ @Column()
176
+ @DataType(DBTypes.INTEGER)
177
+ public CEP!: number;
178
+
179
+ // PostgreSQL TEXT[]
180
+ @Column()
181
+ @DataType(DBTypes.TEXTARRAY)
182
+ public PhoneNumbers!: string[];
183
+
184
+ // PostgreSQL INTEGER[]
185
+ @Column()
186
+ @DataType(DBTypes.INTEGERARRAY)
187
+ public Documents!: number[];
188
+
189
+ // PostgreSQL DATE
190
+ @Column()
191
+ @DataType(DBTypes.DATE)
192
+ public Birth!: Date;
193
+
194
+ // One person can write many messages
195
+ @Column()
196
+ @OneToMany(() => Message, "From")
197
+ public MessagesWriten?: Message[];
198
+
199
+ // Many persons can receive many messages
200
+ @Column()
201
+ @ManyToMany(() => Message, "To")
202
+ public MessagesReceived?: Message[];
203
+
204
+
205
+ constructor(name : string = "", email : string = "", age : number = 1)
206
+ {
207
+ this.Id = -1;
208
+ this.Name = name;
209
+ this.Email = email;
210
+ this.Age = age;
211
+ this.CEP = -1;
212
+ this.PhoneNumbers = [];
213
+ this.Birth = new Date(1992,4,23);
214
+ this.Documents = [];
215
+ this.MessagesReceived = [];
216
+ this.MessagesWriten = [];
217
+
218
+ }
219
+
220
+
221
+ }
222
+ ```
223
+
224
+ ### Message.ts
225
+
226
+ ```typescript
227
+ import { Table, Column, PrimaryKey, DataType, ManyToOne, ManyToMany, DBTypes} from 'myorm_pg';
228
+ import { Person } from './Person';
229
+
230
+ @Table("message_tb")
231
+ export class Message
232
+ {
233
+ // Primary key with SERIAL (auto-increment)
234
+ @PrimaryKey()
235
+ @Column()
236
+ @DataType(DBTypes.SERIAL)
237
+ public Id : number = -1;
238
+
239
+ // Text column
240
+ @Column()
241
+ public Message : string;
242
+
243
+ // One person can write many messages
244
+ @Column()
245
+ @ManyToOne(()=> Person, "MessagesWriten")
246
+ public From? : Person;
247
+
248
+ // Many persons can receive many messages
249
+ @Column()
250
+ @ManyToMany(()=> Person, "MessagesReceived")
251
+ public To? : Person[];
252
+
253
+
254
+ constructor(message : string, from? : Person, to? : Person[])
255
+ {
256
+ this.Message = message;
257
+ this.From = from;
258
+ this.To = to;
259
+ }
260
+
261
+
262
+ }
16
263
  ```
17
264
 
265
+ ---
266
+
267
+ # Database Context
268
+
269
+ The database context is the central access point to the database.
270
+ It manages:
271
+
272
+ - The database connection
273
+
274
+ - Entity sets (PGDBSet<T>)
18
275
 
19
- # Usage
20
- This ORM is based on https://www.nuget.org/packages/Adr.MyORMForPostgreSQL for .NET. The usage is similar.
276
+ - Schema synchronization
21
277
 
278
+ - Query execution
22
279
 
23
- ### Context.ts
280
+ Each entity must be registered in the context to be tracked and queried by the ORM.
24
281
 
25
282
  ```typescript
26
283
  import { PGDBManager, PGDBContext, PGDBSet} from 'myorm_pg';
27
- import { Message } from './entities/Message';
28
- import { Person } from './entities/Person';
284
+ import { Message } from './Message';
285
+ import { Person } from './Person';
29
286
 
30
287
 
31
288
  export default class Context extends PGDBContext
@@ -43,14 +300,10 @@ export default class Context extends PGDBContext
43
300
  ```
44
301
 
45
302
  # Create a instance of context and update or creare database
46
- ### Create with explicts parameters
303
+
47
304
 
48
305
  ```typescript
49
-
50
- var context = new Context(PGDBManager.Build("localhost", 5432, "test_db", "username", "password"));
51
-
52
- await context.UpdateDatabaseAsync();
53
-
306
+ const context = new Context(PGDBManager.Build("localhost", 5432, "test_db", "username", "password"));
54
307
  ```
55
308
 
56
309
  ### Create with enviroment variables
@@ -60,21 +313,42 @@ this method will try get values from __process.env__ keys. The ORM will search f
60
313
 
61
314
 
62
315
  ```typescript
316
+ const context = new Context(PGDBManager.BuildFromEnviroment());
317
+ ```
63
318
 
64
- var context = new Context(PGDBManager.BuildFromEnviroment());
319
+ After creating the context, the database schema can be created or updated automatically based on the entity metadata.
65
320
 
321
+ ```typescript
66
322
  await context.UpdateDatabaseAsync();
323
+ ```
324
+
325
+ This process:
326
+
327
+ - Creates tables if they do not exist
328
+
329
+ - Updates columns and data types
330
+
331
+ - Creates foreign keys and junction tables
332
+
333
+ - Keeps the database schema synchronized with the code
334
+ ### Create with explicts parameters
335
+
336
+ ```typescript
67
337
 
338
+ var context = new Context(PGDBManager.Build("localhost", 5432, "test_db", "username", "password"));
339
+
340
+ await context.UpdateDatabaseAsync();
68
341
 
69
342
  ```
343
+ ---
70
344
 
71
345
 
72
346
 
73
- ## Insert entities
347
+ # Insert entities
74
348
 
75
349
  ```typescript
76
350
 
77
- let person = new Person();
351
+ const person = new Person();
78
352
  person.Name = "Adriano";
79
353
  person.Email = "adriano@test.com";
80
354
  person.Birth = new Date(1970,01,01);
@@ -84,9 +358,9 @@ person.PhoneNumbers = ['+55(55)1234-5678'];
84
358
  await context.Persons.AddAsync(person);
85
359
 
86
360
  ```
361
+ ---
87
362
 
88
-
89
- ## Insert entities with relation
363
+ # Insert entities with relation
90
364
  In this case, all persons will be saved automatically. All persons of __Message.To__ property will have a reference to this message on property
91
365
  __Person.MessagesReceived__ and the person of __Message.From__ will have a reference to this message on __Person.MessagesWriten__ property
92
366
 
@@ -103,7 +377,10 @@ await context.Messages.AddAsync(msg);
103
377
 
104
378
  ```
105
379
 
106
- # where
380
+ ---
381
+ # Query
382
+
383
+ ## where
107
384
 
108
385
 
109
386
  ```typescript
@@ -116,7 +393,7 @@ let persons = await context.Persons.Where({
116
393
 
117
394
  ```
118
395
 
119
- # And
396
+ ## And
120
397
 
121
398
 
122
399
  ```typescript
@@ -134,7 +411,7 @@ let persons = await context.Persons.Where({
134
411
  ```
135
412
 
136
413
 
137
- # Or
414
+ ## Or
138
415
 
139
416
 
140
417
  ```typescript
@@ -151,10 +428,11 @@ let persons = await context.Persons.Where({
151
428
 
152
429
  ```
153
430
 
431
+ ---
154
432
 
155
433
  # Operations
156
434
 
157
- ### Equals
435
+ ## Equals
158
436
 
159
437
  ```typescript
160
438
 
@@ -167,7 +445,7 @@ let persons = await context.Persons.Where({
167
445
  ```
168
446
 
169
447
 
170
- ### Not equals
448
+ ## Not equals
171
449
 
172
450
  ```typescript
173
451
 
@@ -180,7 +458,7 @@ let persons = await context.Persons.Where({
180
458
 
181
459
  ```
182
460
 
183
- ### Contains
461
+ ## Contains
184
462
 
185
463
  ```typescript
186
464
 
@@ -193,7 +471,7 @@ let persons = await context.Persons.Where({
193
471
  ```
194
472
 
195
473
 
196
- ### Starts with
474
+ ## Starts with
197
475
 
198
476
  ```typescript
199
477
 
@@ -206,7 +484,7 @@ let persons = await context.Persons.Where({
206
484
  ```
207
485
 
208
486
 
209
- ### Ends with
487
+ ## Ends with
210
488
 
211
489
  ```typescript
212
490
 
@@ -218,7 +496,7 @@ let persons = await context.Persons.Where({
218
496
  .ToListAsync();
219
497
  ```
220
498
 
221
- ### Greater
499
+ ## Greater
222
500
 
223
501
  ```typescript
224
502
 
@@ -230,7 +508,7 @@ let persons = await context.Persons.Where({
230
508
  .ToListAsync();
231
509
  ```
232
510
 
233
- ### Smaller
511
+ ## Smaller
234
512
 
235
513
  ```typescript
236
514
 
@@ -242,9 +520,9 @@ let persons = await context.Persons.Where({
242
520
  .ToListAsync();
243
521
 
244
522
  ```
523
+ ---
524
+ # Load related entities
245
525
 
246
- # Load
247
- We can load all related entities
248
526
  ```typescript
249
527
 
250
528
  let persons = await context.Persons.Where({
@@ -271,6 +549,8 @@ await context.Messages.ReloadCachedRealitionsAsync(messages, ["To"]); //will loa
271
549
  This query will load/reload the "TO" property of all messages with Person objects
272
550
 
273
551
 
552
+ ---
553
+
274
554
  # Joins
275
555
  We can create complex Joins
276
556
 
@@ -294,6 +574,22 @@ We can create complex Joins
294
574
  This query will retrieve from database all messages sent to a person with name "camila" and that are sent this year.
295
575
 
296
576
 
577
+ ### Left join
578
+ ```typescript
579
+ let msgs = await context.From(Person)
580
+ .LeftJoin(Message)
581
+ .On(Person, "Id", Message, "To")
582
+ .Where(Message, {
583
+ Field : "Id",
584
+ Value : undefined
585
+ })
586
+ .Select(Person).ToListAsync();
587
+ ```
588
+
589
+ This query will retrieve from database all persos who have no one message received.
590
+
591
+
592
+
297
593
  ## Order by
298
594
 
299
595
  ```typescript
@@ -302,6 +598,9 @@ let all = await context.Persons
302
598
  .ToListAsync();
303
599
  ```
304
600
 
601
+
602
+ ---
603
+ # Ordering and Limit
305
604
  ## Order by descending
306
605
 
307
606
  ```typescript
@@ -310,7 +609,7 @@ let all = await context.Persons
310
609
  .ToListAsync();
311
610
  ```
312
611
 
313
-
612
+ ---
314
613
  ## Limit
315
614
 
316
615
  ```typescript
@@ -331,7 +630,9 @@ let person = await context.Persons.Where({
331
630
  ```
332
631
 
333
632
 
334
- ## Update person
633
+
634
+ ---
635
+ # Update
335
636
 
336
637
  ```typescript
337
638
  let person = await context.Persons.Where({
@@ -345,10 +646,10 @@ await context.Persons.UpdateAsync(person);
345
646
 
346
647
  ```
347
648
 
649
+ ---
348
650
 
349
651
 
350
-
351
- ## Delete
652
+ # Delete
352
653
 
353
654
  ```typescript
354
655
  let person = await context.Persons.Where({
@@ -359,7 +660,9 @@ let person = await context.Persons.Where({
359
660
  await context.Persons.DeleteAsync(person);
360
661
  ```
361
662
 
663
+
362
664
  # Delete or update many registers
665
+
363
666
  ## DeleteSelectionAsync
364
667
  ```typescript
365
668
  await context.Persons.Where({
@@ -376,25 +679,10 @@ await context.Persons.DeleteAsync(person);
376
679
  Field : 'Age',
377
680
  Value : 20
378
681
  })
379
- .DeleteSelectionAsync();
682
+ .UpdateSelectionAsync();
380
683
  ```
381
684
 
382
-
383
- # Inner and Left Join
384
- We can execute complex join operation
385
-
386
- ```typescript
387
- let messagesToCamila = await context.From(Person)
388
- .InnerJoin(Message)
389
- .On(Person, "Id", Message, "To")
390
- .Where(Person,
391
- {
392
- Field : "Name",
393
- Kind : Operation.CONSTAINS,
394
- Value : "camila"
395
- })
396
- .Select(Message).Load("To").ToListAsync();
397
- ```
685
+ ---
398
686
 
399
687
  # Fluent query methods
400
688
 
@@ -439,11 +727,11 @@ let persons = await context.Persons.Where({Field : 'Age', Value : 1})
439
727
  let persons = await context.Persons.WhereField("MessagesReceived").IsNull().ToListAsync();
440
728
  ```
441
729
 
730
+ ---
442
731
  # Free hand query
443
732
 
444
733
  ```typescript
445
734
  let persons = await context.Persons.WhereAsString(`age > 30 or name ilike '%adriano%'`).ToListAsync();
446
-
447
735
  ```
448
736
 
449
737
 
@@ -451,119 +739,9 @@ let persons = await context.Persons.WhereField("MessagesReceived").IsNull().ToLi
451
739
 
452
740
  ```typescript
453
741
  let pg_result = await context.ExecuteQuery("select now()");
454
-
455
- ```
456
-
457
-
458
- # Entities used in this example
459
-
460
-
461
- ### ./entities/Person.ts
462
-
463
- ```typescript
464
- import { Table, Column, PrimaryKey, DataType, OneToMany, OneToOne, ManyToMany, DBTypes} from 'myorm_pg';
465
- import { Message } from './Message';
466
-
467
- @Table("person_tb")
468
- export class Person
469
- {
470
- @PrimaryKey()
471
- @Column()
472
- @DataType(DBTypes.SERIAL)
473
- public Id : number;
474
-
475
- @Column()
476
- public Name : string;
477
-
478
- @Column("email_address")
479
- public Email : string;
480
-
481
- @Column()
482
- public Age : number;
483
-
484
-
485
- @Column()
486
- @DataType(DBTypes.INTEGER)
487
- public CEP : number;
488
-
489
-
490
- @Column()
491
- @DataType(DBTypes.TEXTARRAY)
492
- public PhoneNumbers : string[];
493
-
494
- @Column()
495
- @DataType(DBTypes.INTEGERARRAY)
496
- public Documents : number[];
497
-
498
- @Column()
499
- @DataType(DBTypes.DATE)
500
- public Birth : Date;
501
-
502
-
503
- @Column()
504
- @OneToMany(()=> Message, "From")
505
- public MessagesWriten? : Message[];
506
-
507
- @Column()
508
- @ManyToMany(()=> Message, "To")
509
- public MessagesReceived? : Message[];
510
-
511
-
512
- constructor(name : string = "", email : string = "", age : number = 1)
513
- {
514
- this.Id = -1;
515
- this.Name = name;
516
- this.Email = email;
517
- this.Age = age;
518
- this.CEP = -1;
519
- this.PhoneNumbers = [];
520
- this.Birth = new Date(1992,4,23);
521
- this.Documents = [];
522
- this.MessagesReceived = [];
523
- this.MessagesWriten = [];
524
-
525
- }
526
-
527
-
528
- }
529
742
  ```
530
743
 
531
- ### ./entities/Message.ts
532
-
533
- ```typescript
534
- import { Table, Column, PrimaryKey, DataType, ManyToOne, ManyToMany, DBTypes} from 'myorm_pg';
535
- import { Person } from './Person';
536
744
 
537
- @Table("message_tb")
538
- export class Message
539
- {
540
- @PrimaryKey()
541
- @Column()
542
- @DataType(DBTypes.SERIAL)
543
- public Id : number = -1;
544
-
545
- @Column()
546
- public Message : string;
547
-
548
- @Column()
549
- @ManyToOne(()=> Person, "MessagesWriten")
550
- public From? : Person;
551
-
552
- @Column()
553
- @ManyToMany(()=> Person, "MessagesReceived")
554
- public To? : Person[];
555
-
556
-
557
- constructor(message : string, from? : Person, to? : Person[])
558
- {
559
- this.Message = message;
560
- this.From = from;
561
- this.To = to;
562
- }
563
-
564
-
565
- }
566
- ```
567
745
 
568
746
  ## Contributing
569
747