myorm_pg 9.3.0 → 10.0.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
@@ -18,10 +18,21 @@ npm install myorm_pg
18
18
  ```
19
19
 
20
20
  ---
21
+ ## Configuration
21
22
 
22
- ## TypeScript Configuration
23
+ #### Peer Dependencies
23
24
 
24
- Decorators must be enabled in your `tsconfig.json`:
25
+ This ORM relies on the `reflect-metadata` package to enable runtime type reflection used by decorators.
26
+
27
+ Make sure it is installed and imported **once** in your application entry point:
28
+
29
+ ```typescript
30
+ import 'reflect-metadata';
31
+ ```
32
+
33
+ #### Typescript
34
+
35
+ Decorators and metadata emission must be enabled in your `tsconfig.json`:
25
36
 
26
37
  ```json
27
38
  {
@@ -29,6 +40,9 @@ Decorators must be enabled in your `tsconfig.json`:
29
40
  "emitDecoratorMetadata": true
30
41
  }
31
42
  ```
43
+
44
+ These options are required for entity mapping, dependency injection, and relationship metadata to work correctly.
45
+
32
46
  ---
33
47
 
34
48
 
@@ -45,7 +59,10 @@ Defines the database table name associated with the entity.
45
59
 
46
60
  ### @Column
47
61
  Marks a class property as a table column.
48
- An optional parameter allows you to specify a custom column name.
62
+
63
+ You may optionally provide a custom column name as a parameter.
64
+
65
+ If any other column-related decorator is applied to the property, the `@Column` decorator becomes optional — except when you want to explicitly define the column name.
49
66
 
50
67
  ### @PrimaryKey
51
68
  Indicates that the column is the primary key of the table.
@@ -154,8 +171,7 @@ import { Message } from './Message';
154
171
  export class Person
155
172
  {
156
173
  // Primary key with SERIAL (auto-increment)
157
- @PrimaryKey()
158
- @Column()
174
+ @PrimaryKey()
159
175
  @DataType(DBTypes.SERIAL)
160
176
  public Id!: number;
161
177
 
@@ -171,33 +187,27 @@ export class Person
171
187
  @Column()
172
188
  public Age!: number;
173
189
 
174
- // Explicit integer column
175
- @Column()
190
+ // Explicit integer column
176
191
  @DataType(DBTypes.INTEGER)
177
192
  public CEP!: number;
178
193
 
179
- // PostgreSQL TEXT[]
180
- @Column()
194
+ // PostgreSQL TEXT[]
181
195
  @DataType(DBTypes.TEXTARRAY)
182
196
  public PhoneNumbers!: string[];
183
197
 
184
- // PostgreSQL INTEGER[]
185
- @Column()
198
+ // PostgreSQL INTEGER[]
186
199
  @DataType(DBTypes.INTEGERARRAY)
187
200
  public Documents!: number[];
188
201
 
189
- // PostgreSQL DATE
190
- @Column()
202
+ // PostgreSQL DATE
191
203
  @DataType(DBTypes.DATE)
192
204
  public Birth!: Date;
193
205
 
194
- // One person can write many messages
195
- @Column()
206
+ // One person can write many messages
196
207
  @OneToMany(() => Message, "From")
197
208
  public MessagesWriten?: Message[];
198
209
 
199
210
  // Many persons can receive many messages
200
- @Column()
201
211
  @ManyToMany(() => Message, "To")
202
212
  public MessagesReceived?: Message[];
203
213
 
@@ -231,8 +241,7 @@ import { Person } from './Person';
231
241
  export class Message
232
242
  {
233
243
  // Primary key with SERIAL (auto-increment)
234
- @PrimaryKey()
235
- @Column()
244
+ @PrimaryKey()
236
245
  @DataType(DBTypes.SERIAL)
237
246
  public Id : number = -1;
238
247
 
@@ -240,13 +249,11 @@ export class Message
240
249
  @Column()
241
250
  public Message : string;
242
251
 
243
- // One person can write many messages
244
- @Column()
252
+ // One person can write many messages
245
253
  @ManyToOne(()=> Person, "MessagesWriten")
246
254
  public From? : Person;
247
255
 
248
- // Many persons can receive many messages
249
- @Column()
256
+ // Many persons can receive many messages
250
257
  @ManyToMany(()=> Person, "MessagesReceived")
251
258
  public To? : Person[];
252
259
 
@@ -684,6 +691,123 @@ await context.Persons.DeleteAsync(person);
684
691
 
685
692
  ---
686
693
 
694
+
695
+ # Transactions
696
+
697
+ This ORM provides first-class support for database transactions, including **begin**, **commit**, **rollback**, and **savepoints**.
698
+ This allows you to safely group multiple operations and partially rollback changes when needed.
699
+
700
+ ### Basic Usage
701
+
702
+ You can manually control a transaction using the context API:
703
+
704
+ ```typescript
705
+ await context.BeginTransactionAsync();
706
+
707
+ // database operations...
708
+
709
+ await context.CommitAsync();
710
+ ```
711
+ If something goes wrong, you can rollback the entire transaction:
712
+
713
+ ```typescript
714
+ await context.RollBackAsync();
715
+ ```
716
+
717
+
718
+ ### Full Rollback Example
719
+
720
+ In this example, **any error** causes the entire transaction to be rolled back:
721
+
722
+ ```typescript
723
+ await context.BeginTransactionAsync();
724
+
725
+ try
726
+ {
727
+ await context.Persons.AddAsync(person1);
728
+ await context.Persons.AddAsync(person2);
729
+
730
+ await context.Messages.AddAsync(message);
731
+
732
+ await context.CommitAsync();
733
+ }
734
+ catch (error)
735
+ {
736
+ // Reverts all operations executed within the transaction
737
+ await context.RollBackAsync();
738
+ throw error;
739
+ }
740
+ ```
741
+ What happens here:
742
+
743
+ - All operations are executed inside a single transaction
744
+
745
+ - If any step fails, no data is persisted
746
+
747
+ - The transaction is only committed if everything succeeds
748
+
749
+ ## Savepoint with Partial Rollback Example
750
+
751
+ Savepoints allow you to protect a specific section of a transaction.
752
+
753
+
754
+ ```typescript
755
+ await context.BeginTransactionAsync();
756
+
757
+ try
758
+ {
759
+ await context.Persons.AddAsync(person1);
760
+ await context.Persons.AddAsync(person2);
761
+ await context.Persons.AddAsync(person3);
762
+ await context.Persons.AddAsync(person4);
763
+
764
+ // Creates a savepoint after all persons are added
765
+ await context.SavePointAsync("persons");
766
+
767
+ await context.Messages.AddAsync(message);
768
+
769
+ // Something went wrong while saving the message
770
+ throw new Error("Message validation failed");
771
+
772
+ await context.CommitAsync();
773
+ }
774
+ catch (error)
775
+ {
776
+ // Rollback only the operations after the savepoint
777
+ await context.RollBackAsync("persons");
778
+
779
+ // Commit everything that happened before the savepoint
780
+ await context.CommitAsync();
781
+ }
782
+
783
+ ```
784
+ Result:
785
+
786
+ - All Person entities are saved
787
+
788
+ - The Message entity is discarded
789
+
790
+ - The transaction completes successfully
791
+
792
+ ## Recommended Pattern
793
+ ```typescript
794
+ await context.BeginTransactionAsync();
795
+
796
+ try
797
+ {
798
+ // operations
799
+ await context.CommitAsync();
800
+ }
801
+ catch
802
+ {
803
+ await context.RollBackAsync();
804
+ throw;
805
+ }
806
+ ```
807
+ Using `try/catch` with transactions is strongly recommended to guarantee data integrity and predictable behavior.
808
+
809
+ ---
810
+
687
811
  # Fluent query methods
688
812
 
689
813
  ## Where
@@ -743,6 +867,89 @@ let persons = await context.Persons.WhereField("MessagesReceived").IsNull().ToLi
743
867
 
744
868
 
745
869
 
870
+ # GetTypeMapping (Type Mapping Helper)
871
+
872
+ The `PGDBSet<T>.GetTypeMapping()` feature exposes metadata about an entity mapping, allowing you to safely build **dynamic SQL statements** based on entity definitions, column mappings, and relationships — without hardcoding table or column names.
873
+
874
+ This is especially useful for:
875
+ - Dynamic queries
876
+ - Custom SQL generation
877
+ - Debugging mappings
878
+ - Advanced filtering scenarios
879
+
880
+ ### Basic Usage
881
+ ```typescript
882
+
883
+ let helper = context.Persons.GetTypeMapping();
884
+
885
+ ```
886
+ The returned helper provides access to:
887
+
888
+ - Table → mapped table name
889
+
890
+ - Columns → mapped column names
891
+
892
+ - EvaluateStatement() → generates SQL expressions from strongly-typed filters
893
+
894
+
895
+ #### Update example
896
+ ```typescript
897
+
898
+ let helper = context.Persons.GetTypeMapping();
899
+
900
+ let person = await context.Persons.OrderBy("Age").FirstOrDefaultAsync();
901
+
902
+ let update = `update ${helper.Table}
903
+ set ${helper.Columns.Age} = ${helper.Columns.Age} - 1
904
+ where ${helper.Columns.Id} = ${person?.Id}`;
905
+
906
+
907
+ let rowCount = (await context.ExecuteQuery(update)).rowCount;
908
+ ```
909
+
910
+ #### Select using EvaluateStatement()
911
+ ```typescript
912
+ const helper = context.Persons.GetTypeMapping();
913
+
914
+ const whereClause = helper.EvaluateStatement({
915
+ Field: "Age",
916
+ Value: 20
917
+ });
918
+
919
+ const select = `select ${helper.Columns.Name}, ${helper.Columns.Email} from ${helper.Table} where ${whereClause}`;
920
+
921
+ ```
922
+
923
+ #### Querying using relation fields
924
+
925
+ ```typescript
926
+
927
+ const helper = context.Persons.GetTypeMapping();
928
+
929
+ const whereClause = helper.EvaluateStatement({
930
+ Field: "MessagesReceived",
931
+ Kind: Operation.CONTAINS,
932
+ Value: [messageObject]
933
+ });
934
+
935
+ const select = `select ${helper.Columns.Id} from ${helper.Table} where ${whereClause}`;
936
+
937
+ ```
938
+
939
+ `GetTypeMapping()` gives you a low-level but type-aware view of your entity mapping:
940
+
941
+ - No hardcoded table or column names
942
+
943
+ - Safe dynamic SQL generation
944
+
945
+ - Works with scalar fields and relations
946
+
947
+ - Ideal for advanced scenarios where LINQ-like APIs are not enough
948
+
949
+
950
+ ---
951
+
952
+
746
953
  ## Contributing
747
954
 
748
955
  Pull requests are welcome. For major changes, please open an issue first