orange-orm 5.3.6 → 5.4.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
@@ -33,8 +33,10 @@ The ultimate Object Relational Mapper for Node.js, Bun and Deno, offering seamle
33
33
  | SQLite | ✅ | ✅ | ✅ | |
34
34
  | Cloudflare D1 | | | | ✅|
35
35
 
36
- ## Sponsorship <span style="font-size: larger; color: darkred;">♡</span>
37
- If you value the hard work behind Orange and wish to see it evolve further, consider [sponsoring](https://github.com/sponsors/lroal). Your support fuels the journey of refining and expanding this tool for our developer community.
36
+ ## Sponsorship ❤️
37
+ Orange ORM is free and open source, maintained in my spare time.
38
+ If Orange saves you or your company time, sponsorship helps fund ongoing development, bug fixes, documentation, and long-term maintenance.
39
+ 👉 [Sponsor Orange ORM on GitHub](https://github.com/sponsors/lroal)
38
40
 
39
41
  ## MCP (Model Context Protocol)
40
42
  Orange ORM is available as an MCP resource on Context7. Use it with AI-powered tools like GitHub Copilot, Cursor, or Claude to get up-to-date documentation and code examples directly in your IDE.
@@ -754,14 +756,14 @@ const db = map.sqlite('demo.db');
754
756
  getRows();
755
757
 
756
758
  async function getRows() {
757
- const orders = await db.order.getMany([
759
+ const orders = await db.order.getMany({
760
+ where: () => [
758
761
  {id: 1},
759
762
  {id: 2}
760
- ],
761
- {
762
- customer: true,
763
- deliveryAddress: true,
764
- lines: true
763
+ ],
764
+ customer: true,
765
+ deliveryAddress: true,
766
+ lines: true
765
767
  });
766
768
  }
767
769
  ```
@@ -845,6 +847,50 @@ async function update() {
845
847
  const orders = await db.order.update(propsToBeModified, { where: x => x.id.eq(1) }, strategy);
846
848
  }
847
849
  ```
850
+ __Row locks with forUpdate and skipLocked__
851
+ Use `forUpdate: true` in a fetching strategy to lock selected rows for update until the current transaction completes. Add `skipLocked: true` when concurrent workers should skip rows that are already locked instead of waiting for them. This is useful for queue-like workloads where several workers pick the next available rows.
852
+
853
+ `forUpdate` and `skipLocked` should be used inside a transaction. They are supported by PostgreSQL/PGlite, MySQL, MariaDB, Oracle, and MS SQL. SQLite and SAP ASE throw an error because row locking with `SELECT FOR UPDATE` is not supported there.
854
+
855
+ ```javascript
856
+ import map from './map';
857
+ const db = map.postgres('postgres://postgres:postgres@postgres/postgres');
858
+
859
+ async function claimNextOrders() {
860
+ return await db.transaction(async tx => {
861
+ const orders = await tx.order.getMany({
862
+ where: x => x.orderDate.lessThan(new Date()),
863
+ orderBy: 'id',
864
+ limit: 10,
865
+ forUpdate: true,
866
+ skipLocked: true,
867
+ lines: {
868
+ forUpdate: true
869
+ }
870
+ });
871
+
872
+ for (const order of orders) {
873
+ order.orderDate = new Date();
874
+ }
875
+
876
+ await orders.saveChanges();
877
+ return orders;
878
+ });
879
+ }
880
+ ```
881
+
882
+ The same lock strategy can be passed to write helpers that return affected rows:
883
+
884
+ ```javascript
885
+ const updated = await db.transaction(async tx => {
886
+ return await tx.customer.update(
887
+ { name: 'Updated' },
888
+ { where: x => x.id.eq(customerId) },
889
+ { forUpdate: true, skipLocked: true }
890
+ );
891
+ });
892
+ ```
893
+
848
894
  __Replacing a row from JSON__
849
895
  The replace method is suitable when a complete overwrite is required from a JSON object - typically in a REST API. However, it's important to consider that this method replaces the entire row and it's children, which might not always be desirable in a multi-user environment.
850
896