orange-orm 5.0.0-beta.0 → 5.0.0-beta.10
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 +85 -68
- package/dist/index.browser.mjs +38 -7
- package/dist/index.mjs +108 -31
- package/docs/changelog.md +5 -0
- package/other.db +0 -0
- package/package.json +1 -1
- package/src/client/index.js +2 -0
- package/src/emptyFilter.js +13 -1
- package/src/map2.d.ts +14 -7
- package/src/table/column/newColumn.js +2 -2
- package/src/table/column/utils.js +8 -0
- package/src/table/executeQueries/executeQueriesCore.js +7 -2
- package/src/table/joinRelation/getRelatives.js +4 -3
- package/src/table/relation/newOneLeg.js +1 -1
- package/src/table.js +4 -1
- package/src/tedious/outputInsertedSql.js +2 -2
- package/src/tedious/wrapCommand.js +34 -11
- package/src/tedious/wrapQuery.js +36 -13
- package/deno.lock +0 -76
package/README.md
CHANGED
|
@@ -134,7 +134,7 @@ const db = map.sqlite('demo.db');
|
|
|
134
134
|
getRows();
|
|
135
135
|
|
|
136
136
|
async function getRows() {
|
|
137
|
-
const orders = await db.order.
|
|
137
|
+
const orders = await db.order.getMany({
|
|
138
138
|
where: x => x.lines.any(line => line.product.contains('broomstick'))
|
|
139
139
|
.and(x.customer.name.startsWith('Harry')),
|
|
140
140
|
lines: {
|
|
@@ -312,29 +312,8 @@ __Why close ?__
|
|
|
312
312
|
In serverless environments (e.g. AWS Lambda, Vercel, Cloudflare Workers) execution contexts are frequently frozen and resumed. Explicitly closing the client or pool ensures that file handles are released promptly and prevents “database locked” errors between invocations.
|
|
313
313
|
|
|
314
314
|
__SQLite user-defined functions__
|
|
315
|
-
You can register custom SQLite functions
|
|
316
|
-
|
|
317
|
-
```javascript
|
|
318
|
-
import map from './map';
|
|
319
|
-
const db = map.sqlite('demo.db');
|
|
320
|
-
|
|
321
|
-
db.function('add_prefix', (text, prefix) => `${prefix}${text}`);
|
|
322
|
-
|
|
323
|
-
const rows = await db.query(
|
|
324
|
-
"select id, name, add_prefix(name, '[VIP] ') as prefixedName from customer"
|
|
325
|
-
);
|
|
326
|
-
```
|
|
327
|
-
|
|
328
|
-
If you need the function inside a transaction, register it within the transaction callback to ensure it is available on that connection.
|
|
329
|
-
|
|
330
|
-
```javascript
|
|
331
|
-
await db.transaction(async (db) => {
|
|
332
|
-
db.function('add_prefix', (text, prefix) => `${prefix}${text}`);
|
|
333
|
-
return db.query(
|
|
334
|
-
"select id, name, add_prefix(name, '[VIP] ') as prefixedName from customer"
|
|
335
|
-
);
|
|
336
|
-
});
|
|
337
|
-
```
|
|
315
|
+
You can register custom SQLite functions using `db.function(name, fn)`.
|
|
316
|
+
For full behavior, runtime caveats, and examples, see [SQLite user-defined functions](#sqlite-user-defined-functions).
|
|
338
317
|
|
|
339
318
|
__From the browser__
|
|
340
319
|
You can securely use Orange from the browser by utilizing the Express plugin, which serves to safeguard sensitive database credentials from exposure at the client level. This technique bypasses the need to transmit raw SQL queries directly from the client to the server. Instead, it logs method calls initiated by the client, which are later replayed and authenticated on the server. This not only reinforces security by preventing the disclosure of raw SQL queries on the client side but also facilitates a smoother operation. Essentially, this method mirrors a traditional REST API, augmented with advanced TypeScript tooling for enhanced functionality. You can read more about it in the section called [In the browser](#user-content-in-the-browser)
|
|
@@ -445,7 +424,7 @@ export interface Env {
|
|
|
445
424
|
export default {
|
|
446
425
|
async fetch(request, env): Promise<Response> {
|
|
447
426
|
const db = map.d1(env.DB);
|
|
448
|
-
const customers = await db.customer.
|
|
427
|
+
const customers = await db.customer.getMany();
|
|
449
428
|
return Response.json(customers);
|
|
450
429
|
},
|
|
451
430
|
} satisfies ExportedHandler<Env>;
|
|
@@ -613,7 +592,7 @@ const db = map.sqlite('demo.db');
|
|
|
613
592
|
getRows();
|
|
614
593
|
|
|
615
594
|
async function getRows() {
|
|
616
|
-
const orders = await db.order.
|
|
595
|
+
const orders = await db.order.getMany({
|
|
617
596
|
customer: true,
|
|
618
597
|
deliveryAddress: true,
|
|
619
598
|
lines: {
|
|
@@ -632,7 +611,7 @@ const db = map.sqlite('demo.db');
|
|
|
632
611
|
getRows();
|
|
633
612
|
|
|
634
613
|
async function getRows() {
|
|
635
|
-
const orders = await db.order.
|
|
614
|
+
const orders = await db.order.getMany({
|
|
636
615
|
offset: 1,
|
|
637
616
|
orderBy: ['orderDate desc', 'id'],
|
|
638
617
|
limit: 10,
|
|
@@ -664,7 +643,7 @@ const db = map.sqlite('demo.db');
|
|
|
664
643
|
getRows();
|
|
665
644
|
|
|
666
645
|
async function getRows() {
|
|
667
|
-
const orders = await db.order.
|
|
646
|
+
const orders = await db.order.getMany({
|
|
668
647
|
numberOfLines: x => x.count(x => x.lines.id),
|
|
669
648
|
totalAmount: x => x.sum(x => lines.amount),
|
|
670
649
|
balance: x => x.customer.balance
|
|
@@ -681,7 +660,7 @@ const db = map.sqlite('demo.db');
|
|
|
681
660
|
getRows();
|
|
682
661
|
|
|
683
662
|
async function getRows() {
|
|
684
|
-
const orders = await db.order.
|
|
663
|
+
const orders = await db.order.getMany({
|
|
685
664
|
where: x => x.lines.any(line => line.product.contains('i'))
|
|
686
665
|
.and(x.customer.balance.greaterThan(180)),
|
|
687
666
|
customer: true,
|
|
@@ -690,14 +669,13 @@ async function getRows() {
|
|
|
690
669
|
});
|
|
691
670
|
}
|
|
692
671
|
```
|
|
693
|
-
You can also
|
|
694
|
-
It is also possible to combine `where-filter` with the independent filter when using the `getMany` method.
|
|
672
|
+
You can also build the `where` filter separately and pass it in via the `where` clause. This keeps the filter independent of the fetching strategy and easier to reuse.
|
|
695
673
|
```javascript
|
|
696
674
|
async function getRows() {
|
|
697
675
|
const filter = db.order.lines.any(line => line.product.contains('i'))
|
|
698
676
|
.and(db.order.customer.balance.greaterThan(180));
|
|
699
|
-
const orders = await db.order.getMany(
|
|
700
|
-
|
|
677
|
+
const orders = await db.order.getMany({
|
|
678
|
+
where: filter,
|
|
701
679
|
customer: true,
|
|
702
680
|
deliveryAddress: true,
|
|
703
681
|
lines: true
|
|
@@ -714,7 +692,7 @@ const db = map.sqlite('demo.db');
|
|
|
714
692
|
getRows();
|
|
715
693
|
|
|
716
694
|
async function getRows() {
|
|
717
|
-
const order = await db.order.getOne(
|
|
695
|
+
const order = await db.order.getOne({
|
|
718
696
|
where: x => x.customer(customer => customer.isActive.eq(true)
|
|
719
697
|
.and(customer.startsWith('Harr'))),
|
|
720
698
|
customer: true,
|
|
@@ -723,15 +701,16 @@ async function getRows() {
|
|
|
723
701
|
});
|
|
724
702
|
}
|
|
725
703
|
```
|
|
726
|
-
You can
|
|
727
|
-
|
|
704
|
+
You can also build the `where` filter independently and reuse it.
|
|
705
|
+
With `getOne`, you can combine the positional `where` filter with the `where` option to compose filters.
|
|
728
706
|
```javascript
|
|
729
707
|
async function getRows() {
|
|
730
708
|
const filter = db.order.customer(customer => customer.isActive.eq(true)
|
|
731
709
|
.and(customer.startsWith('Harr')));
|
|
732
|
-
//equivalent, but creates
|
|
710
|
+
// equivalent, but creates slightly different SQL:
|
|
733
711
|
// const filter = db.order.customer.isActive.eq(true).and(db.order.customer.startsWith('Harr'));
|
|
734
|
-
const order = await db.order.getOne(
|
|
712
|
+
const order = await db.order.getOne({
|
|
713
|
+
where: filter,
|
|
735
714
|
customer: true,
|
|
736
715
|
deliveryAddress: true,
|
|
737
716
|
lines: true
|
|
@@ -812,7 +791,7 @@ const db = map.sqlite('demo.db');
|
|
|
812
791
|
update();
|
|
813
792
|
|
|
814
793
|
async function update() {
|
|
815
|
-
let orders = await db.order.
|
|
794
|
+
let orders = await db.order.getMany({
|
|
816
795
|
orderBy: 'id',
|
|
817
796
|
lines: true,
|
|
818
797
|
deliveryAddress: true,
|
|
@@ -1045,7 +1024,7 @@ const db = map.sqlite('demo.db');
|
|
|
1045
1024
|
updateInsertDelete();
|
|
1046
1025
|
|
|
1047
1026
|
async function updateInsertDelete() {
|
|
1048
|
-
const orders = await db.order.
|
|
1027
|
+
const orders = await db.order.getMany({
|
|
1049
1028
|
customer: true,
|
|
1050
1029
|
deliveryAddress: true,
|
|
1051
1030
|
lines: true
|
|
@@ -1092,7 +1071,7 @@ const db = map.sqlite('demo.db');
|
|
|
1092
1071
|
deleteRows();
|
|
1093
1072
|
|
|
1094
1073
|
async function deleteRows() {
|
|
1095
|
-
let orders = await db.order.
|
|
1074
|
+
let orders = await db.order.getMany({
|
|
1096
1075
|
where: x => x.customer.name.eq('George')
|
|
1097
1076
|
});
|
|
1098
1077
|
|
|
@@ -1108,7 +1087,7 @@ const db = map.sqlite('demo.db');
|
|
|
1108
1087
|
deleteRows();
|
|
1109
1088
|
|
|
1110
1089
|
async function deleteRows() {
|
|
1111
|
-
let orders = await db.order.
|
|
1090
|
+
let orders = await db.order.getMany({
|
|
1112
1091
|
where: x => x.deliveryAddress.name.eq('George'),
|
|
1113
1092
|
customer: true,
|
|
1114
1093
|
deliveryAddress: true,
|
|
@@ -1193,6 +1172,7 @@ express().disable('x-powered-by')
|
|
|
1193
1172
|
```
|
|
1194
1173
|
|
|
1195
1174
|
<sub>📄 browser.ts</sub>
|
|
1175
|
+
|
|
1196
1176
|
```ts
|
|
1197
1177
|
import map from './map';
|
|
1198
1178
|
|
|
@@ -1201,7 +1181,7 @@ const db = map.http('http://localhost:3000/orange');
|
|
|
1201
1181
|
updateRows();
|
|
1202
1182
|
|
|
1203
1183
|
async function updateRows() {
|
|
1204
|
-
const order = await db.order.getOne(
|
|
1184
|
+
const order = await db.order.getOne({
|
|
1205
1185
|
where: x => x.lines.any(line => line.product.startsWith('Magic wand'))
|
|
1206
1186
|
.and(x.customer.name.startsWith('Harry'),
|
|
1207
1187
|
lines: true
|
|
@@ -1286,7 +1266,7 @@ async function updateRows() {
|
|
|
1286
1266
|
}
|
|
1287
1267
|
);
|
|
1288
1268
|
|
|
1289
|
-
const order = await db.order.getOne(
|
|
1269
|
+
const order = await db.order.getOne({
|
|
1290
1270
|
where: x => x.lines.any(line => line.product.startsWith('Magic wand'))
|
|
1291
1271
|
.and(db.order.customer.name.startsWith('Harry')),
|
|
1292
1272
|
lines: true
|
|
@@ -1419,7 +1399,7 @@ const db = map.sqlite('demo.db');
|
|
|
1419
1399
|
getRows();
|
|
1420
1400
|
|
|
1421
1401
|
async function getRows() {
|
|
1422
|
-
const rows = await db.order.
|
|
1402
|
+
const rows = await db.order.getMany({
|
|
1423
1403
|
deliveryAddress: true
|
|
1424
1404
|
});
|
|
1425
1405
|
}
|
|
@@ -1435,7 +1415,7 @@ const db = map.sqlite('demo.db');
|
|
|
1435
1415
|
getRows();
|
|
1436
1416
|
|
|
1437
1417
|
async function getRows() {
|
|
1438
|
-
const rows = await db.order.
|
|
1418
|
+
const rows = await db.order.getMany({
|
|
1439
1419
|
orderDate: false,
|
|
1440
1420
|
deliveryAddress: {
|
|
1441
1421
|
countryCode: true,
|
|
@@ -1459,7 +1439,7 @@ const db = map.sqlite('demo.db');
|
|
|
1459
1439
|
getRows();
|
|
1460
1440
|
|
|
1461
1441
|
async function getRows() {
|
|
1462
|
-
const rows = await db.customer.
|
|
1442
|
+
const rows = await db.customer.getMany({
|
|
1463
1443
|
where x => x.name.equal('Harry')
|
|
1464
1444
|
});
|
|
1465
1445
|
}
|
|
@@ -1472,7 +1452,7 @@ const db = map.sqlite('demo.db');
|
|
|
1472
1452
|
getRows();
|
|
1473
1453
|
|
|
1474
1454
|
async function getRows() {
|
|
1475
|
-
const rows = await db.customer.
|
|
1455
|
+
const rows = await db.customer.getMany({
|
|
1476
1456
|
where x => x.name.notEqual('Harry')
|
|
1477
1457
|
});
|
|
1478
1458
|
}
|
|
@@ -1485,7 +1465,7 @@ const db = map.sqlite('demo.db');
|
|
|
1485
1465
|
getRows();
|
|
1486
1466
|
|
|
1487
1467
|
async function getRows() {
|
|
1488
|
-
const rows = await db.customer.
|
|
1468
|
+
const rows = await db.customer.getMany({
|
|
1489
1469
|
where: x => x.name.contains('arr')
|
|
1490
1470
|
});
|
|
1491
1471
|
}
|
|
@@ -1500,7 +1480,7 @@ getRows();
|
|
|
1500
1480
|
async function getRows() {
|
|
1501
1481
|
const filter = db.customer.name.startsWith('Harr');
|
|
1502
1482
|
|
|
1503
|
-
const rows = await db.customer.
|
|
1483
|
+
const rows = await db.customer.getMany({
|
|
1504
1484
|
where: x => x.name.startsWith('Harr')
|
|
1505
1485
|
});
|
|
1506
1486
|
}
|
|
@@ -1513,7 +1493,7 @@ const db = map.sqlite('demo.db');
|
|
|
1513
1493
|
getRows();
|
|
1514
1494
|
|
|
1515
1495
|
async function getRows() {
|
|
1516
|
-
const rows = await db.customer.
|
|
1496
|
+
const rows = await db.customer.getMany({
|
|
1517
1497
|
where: x => x.name.endsWith('arry')
|
|
1518
1498
|
});
|
|
1519
1499
|
}
|
|
@@ -1526,7 +1506,7 @@ const db = map.sqlite('demo.db');
|
|
|
1526
1506
|
getRows();
|
|
1527
1507
|
|
|
1528
1508
|
async function getRows() {
|
|
1529
|
-
const rows = await db.order.
|
|
1509
|
+
const rows = await db.order.getMany({
|
|
1530
1510
|
where: x => x.orderDate.greaterThan('2023-07-14T12:00:00')
|
|
1531
1511
|
});
|
|
1532
1512
|
}
|
|
@@ -1539,7 +1519,7 @@ const db = map.sqlite('demo.db');
|
|
|
1539
1519
|
getRows();
|
|
1540
1520
|
|
|
1541
1521
|
async function getRows() {
|
|
1542
|
-
const rows = await db.order.
|
|
1522
|
+
const rows = await db.order.getMany({
|
|
1543
1523
|
where: x => x.orderDate.greaterThanOrEqual('2023-07-14T12:00:00')
|
|
1544
1524
|
});
|
|
1545
1525
|
}
|
|
@@ -1552,7 +1532,7 @@ const db = map.sqlite('demo.db');
|
|
|
1552
1532
|
getRows();
|
|
1553
1533
|
|
|
1554
1534
|
async function getRows() {
|
|
1555
|
-
const rows = await db.order.
|
|
1535
|
+
const rows = await db.order.getMany({
|
|
1556
1536
|
where: x => x.orderDate.lessThan('2023-07-14T12:00:00')
|
|
1557
1537
|
});
|
|
1558
1538
|
}
|
|
@@ -1565,7 +1545,7 @@ const db = map.sqlite('demo.db');
|
|
|
1565
1545
|
getRows();
|
|
1566
1546
|
|
|
1567
1547
|
async function getRows() {
|
|
1568
|
-
const rows = await db.order.
|
|
1548
|
+
const rows = await db.order.getMany({
|
|
1569
1549
|
where: x => x.orderDate.lessThanOrEqual('2023-07-14T12:00:00')
|
|
1570
1550
|
});
|
|
1571
1551
|
}
|
|
@@ -1578,7 +1558,7 @@ const db = map.sqlite('demo.db');
|
|
|
1578
1558
|
getRows();
|
|
1579
1559
|
|
|
1580
1560
|
async function getRows() {
|
|
1581
|
-
const rows = await db.order.
|
|
1561
|
+
const rows = await db.order.getMany({
|
|
1582
1562
|
where: x => x.orderDate.between('2023-07-14T12:00:00', '2024-07-14T12:00:00')
|
|
1583
1563
|
});
|
|
1584
1564
|
}
|
|
@@ -1591,7 +1571,7 @@ const db = map.sqlite('demo.db');
|
|
|
1591
1571
|
getRows();
|
|
1592
1572
|
|
|
1593
1573
|
async function getRows() {
|
|
1594
|
-
const rows = await db.order.
|
|
1574
|
+
const rows = await db.order.getMany({
|
|
1595
1575
|
where: x => x.customer.name.in('George', 'Harry')
|
|
1596
1576
|
});
|
|
1597
1577
|
|
|
@@ -1613,11 +1593,11 @@ async function getRows() {
|
|
|
1613
1593
|
parameters: ['%arry']
|
|
1614
1594
|
};
|
|
1615
1595
|
|
|
1616
|
-
const rowsWithRaw = await db.customer.
|
|
1596
|
+
const rowsWithRaw = await db.customer.getMany({
|
|
1617
1597
|
where: () => rawFilter
|
|
1618
1598
|
});
|
|
1619
1599
|
|
|
1620
|
-
const rowsWithCombined = await db.customer.
|
|
1600
|
+
const rowsWithCombined = await db.customer.getMany({
|
|
1621
1601
|
where: x => x.balance.greaterThan(100).and(rawFilter)
|
|
1622
1602
|
});
|
|
1623
1603
|
}
|
|
@@ -1635,7 +1615,7 @@ const db = map.sqlite('demo.db');
|
|
|
1635
1615
|
getRows();
|
|
1636
1616
|
|
|
1637
1617
|
async function getRows() {
|
|
1638
|
-
const orders = await db.order.
|
|
1618
|
+
const orders = await db.order.getMany({
|
|
1639
1619
|
lines: {
|
|
1640
1620
|
where: x => x.product.contains('broomstick')
|
|
1641
1621
|
},
|
|
@@ -1657,7 +1637,7 @@ const db = map.sqlite('demo.db');
|
|
|
1657
1637
|
getRows();
|
|
1658
1638
|
|
|
1659
1639
|
async function getRows() {
|
|
1660
|
-
const rows = await db.order.
|
|
1640
|
+
const rows = await db.order.getMany({
|
|
1661
1641
|
where: x => x.customer.name.equal('Harry')
|
|
1662
1642
|
.and(x.orderDate.greaterThan('2023-07-14T12:00:00'))
|
|
1663
1643
|
});
|
|
@@ -1672,7 +1652,7 @@ getRows();
|
|
|
1672
1652
|
|
|
1673
1653
|
async function getRows() {
|
|
1674
1654
|
|
|
1675
|
-
const rows = await db.order.
|
|
1655
|
+
const rows = await db.order.getMany({
|
|
1676
1656
|
where: y => y.customer( x => x.name.equal('George')
|
|
1677
1657
|
.or(x.name.equal('Harry')))
|
|
1678
1658
|
});
|
|
@@ -1687,7 +1667,7 @@ getRows();
|
|
|
1687
1667
|
|
|
1688
1668
|
async function getRows() {
|
|
1689
1669
|
//Neither George nor Harry
|
|
1690
|
-
const rows = await db.order.
|
|
1670
|
+
const rows = await db.order.getMany({
|
|
1691
1671
|
where: y => y.customer(x => x.name.equal('George')
|
|
1692
1672
|
.or(x.name.equal('Harry')))
|
|
1693
1673
|
.not()
|
|
@@ -1702,7 +1682,7 @@ const db = map.sqlite('demo.db');
|
|
|
1702
1682
|
getRows();
|
|
1703
1683
|
|
|
1704
1684
|
async function getRows() {
|
|
1705
|
-
const rows = await db.order.
|
|
1685
|
+
const rows = await db.order.getMany({
|
|
1706
1686
|
where: x => x.deliveryAddress.exists()
|
|
1707
1687
|
});
|
|
1708
1688
|
}
|
|
@@ -1723,7 +1703,7 @@ const db = map.sqlite('demo.db');
|
|
|
1723
1703
|
getRows();
|
|
1724
1704
|
|
|
1725
1705
|
async function getRows() {
|
|
1726
|
-
const rows = await db.order.
|
|
1706
|
+
const rows = await db.order.getMany({
|
|
1727
1707
|
where: y => y.lines.any(x => x.product.contains('guitar'))
|
|
1728
1708
|
//equivalent syntax:
|
|
1729
1709
|
//where: x => x.lines.product.contains('guitar')
|
|
@@ -1739,7 +1719,7 @@ const db = map.sqlite('demo.db');
|
|
|
1739
1719
|
getRows();
|
|
1740
1720
|
|
|
1741
1721
|
async function getRows() {
|
|
1742
|
-
const rows = await db.order.
|
|
1722
|
+
const rows = await db.order.getMany({
|
|
1743
1723
|
where: y => y.lines.all(x => x.product.contains('a'))
|
|
1744
1724
|
});
|
|
1745
1725
|
}
|
|
@@ -1753,7 +1733,7 @@ const db = map.sqlite('demo.db');
|
|
|
1753
1733
|
getRows();
|
|
1754
1734
|
|
|
1755
1735
|
async function getRows() {
|
|
1756
|
-
const rows = await db.order.
|
|
1736
|
+
const rows = await db.order.getMany({
|
|
1757
1737
|
where: y => y.lines.none(x => x.product.equal('Magic wand'))
|
|
1758
1738
|
});
|
|
1759
1739
|
}
|
|
@@ -2181,6 +2161,43 @@ async function getRows() {
|
|
|
2181
2161
|
```
|
|
2182
2162
|
</details>
|
|
2183
2163
|
|
|
2164
|
+
<details id="sqlite-user-defined-functions"><summary><strong>SQLite user-defined functions</strong></summary>
|
|
2165
|
+
|
|
2166
|
+
You can register custom SQLite functions on the connection using `db.function(name, fn)`.
|
|
2167
|
+
|
|
2168
|
+
The `fn` argument is your user-defined callback:
|
|
2169
|
+
- It is invoked by SQLite every time the SQL function is called.
|
|
2170
|
+
- Callback arguments are positional and match the SQL call (for example, `my_fn(a, b)` maps to `(a, b)`).
|
|
2171
|
+
- Return a SQLite-compatible scalar value (for example text, number, or `null`).
|
|
2172
|
+
- Throwing inside the callback fails the SQL statement.
|
|
2173
|
+
|
|
2174
|
+
`db.function(...)` is sync-only in Node and Deno, but can be async or sync in Bun.
|
|
2175
|
+
|
|
2176
|
+
```javascript
|
|
2177
|
+
import map from './map';
|
|
2178
|
+
const db = map.sqlite('demo.db');
|
|
2179
|
+
|
|
2180
|
+
await db.function('add_prefix', (text, prefix) => `${prefix}${text}`);
|
|
2181
|
+
|
|
2182
|
+
const rows = await db.query(
|
|
2183
|
+
"select id, name, add_prefix(name, '[VIP] ') as prefixedName from customer"
|
|
2184
|
+
);
|
|
2185
|
+
```
|
|
2186
|
+
|
|
2187
|
+
If you need the function inside a transaction, register it within the transaction callback to ensure it is available on that connection.
|
|
2188
|
+
|
|
2189
|
+
```javascript
|
|
2190
|
+
await db.transaction(async (db) => {
|
|
2191
|
+
await db.function('add_prefix', (text, prefix) => `${prefix}${text}`);
|
|
2192
|
+
return db.query(
|
|
2193
|
+
"select id, name, add_prefix(name, '[VIP] ') as prefixedName from customer"
|
|
2194
|
+
);
|
|
2195
|
+
});
|
|
2196
|
+
```
|
|
2197
|
+
|
|
2198
|
+
`db.function(...)` is available on direct SQLite connections (for example `map.sqlite(...)`) and not through `map.http(...)`.
|
|
2199
|
+
</details>
|
|
2200
|
+
|
|
2184
2201
|
<details id="aggregates"><summary><strong>Aggregate functions</strong></summary>
|
|
2185
2202
|
|
|
2186
2203
|
You can count records and aggregate numerical columns. This can either be done across rows or separately for each row.
|
|
@@ -2202,7 +2219,7 @@ const db = map.sqlite('demo.db');
|
|
|
2202
2219
|
getRows();
|
|
2203
2220
|
|
|
2204
2221
|
async function getRows() {
|
|
2205
|
-
const orders = await db.order.
|
|
2222
|
+
const orders = await db.order.getMany({
|
|
2206
2223
|
numberOfLines: x => x.count(x => x.lines.id),
|
|
2207
2224
|
totalAmount: x => x.sum(x => lines.amount),
|
|
2208
2225
|
balance: x => x.customer.balance
|
package/dist/index.browser.mjs
CHANGED
|
@@ -1076,6 +1076,10 @@ function requireUtils () {
|
|
|
1076
1076
|
};
|
|
1077
1077
|
|
|
1078
1078
|
c.and = function(context, other) {
|
|
1079
|
+
if (other === undefined) {
|
|
1080
|
+
other = context;
|
|
1081
|
+
context = null;
|
|
1082
|
+
}
|
|
1079
1083
|
other = negotiateRawSqlFilter(context, other);
|
|
1080
1084
|
var nextFilter = negotiateNextAndFilter(filter, other);
|
|
1081
1085
|
var next = newBoolean(nextFilter);
|
|
@@ -1086,6 +1090,10 @@ function requireUtils () {
|
|
|
1086
1090
|
};
|
|
1087
1091
|
|
|
1088
1092
|
c.or = function(context, other) {
|
|
1093
|
+
if (other === undefined) {
|
|
1094
|
+
other = context;
|
|
1095
|
+
context = null;
|
|
1096
|
+
}
|
|
1089
1097
|
other = negotiateRawSqlFilter(context, other);
|
|
1090
1098
|
var nextFilter = negotiateNextOrFilter(filter, other);
|
|
1091
1099
|
var next = newBoolean(nextFilter);
|
|
@@ -1197,10 +1205,14 @@ function requireEmptyFilter () {
|
|
|
1197
1205
|
return emptyFilter.and.apply(null, arguments);
|
|
1198
1206
|
}
|
|
1199
1207
|
|
|
1200
|
-
emptyFilter.sql = parameterized.sql;
|
|
1208
|
+
emptyFilter.sql = parameterized.sql.bind(parameterized);
|
|
1201
1209
|
emptyFilter.parameters = parameterized.parameters;
|
|
1202
1210
|
|
|
1203
1211
|
emptyFilter.and = function(context, other) {
|
|
1212
|
+
if (other === undefined) {
|
|
1213
|
+
other = context;
|
|
1214
|
+
context = null;
|
|
1215
|
+
}
|
|
1204
1216
|
other = negotiateRawSqlFilter(context, other);
|
|
1205
1217
|
for (var i = 2; i < arguments.length; i++) {
|
|
1206
1218
|
other = other.and(context, arguments[i]);
|
|
@@ -1209,6 +1221,10 @@ function requireEmptyFilter () {
|
|
|
1209
1221
|
};
|
|
1210
1222
|
|
|
1211
1223
|
emptyFilter.or = function(context, other) {
|
|
1224
|
+
if (other === undefined) {
|
|
1225
|
+
other = context;
|
|
1226
|
+
context = null;
|
|
1227
|
+
}
|
|
1212
1228
|
other = negotiateRawSqlFilter(context, other);
|
|
1213
1229
|
for (var i = 2; i < arguments.length; i++) {
|
|
1214
1230
|
other = other.or(context, arguments[i]);
|
|
@@ -1217,6 +1233,10 @@ function requireEmptyFilter () {
|
|
|
1217
1233
|
};
|
|
1218
1234
|
|
|
1219
1235
|
emptyFilter.not = function(context, other) {
|
|
1236
|
+
if (other === undefined) {
|
|
1237
|
+
other = context;
|
|
1238
|
+
context = null;
|
|
1239
|
+
}
|
|
1220
1240
|
other = negotiateRawSqlFilter(context, other).not(context);
|
|
1221
1241
|
for (var i = 2; i < arguments.length; i++) {
|
|
1222
1242
|
other = other.and(context, arguments[i]);
|
|
@@ -2098,9 +2118,14 @@ function requireExecuteQueriesCore () {
|
|
|
2098
2118
|
|
|
2099
2119
|
function executeQueriesCore(context, queries) {
|
|
2100
2120
|
var promises = [];
|
|
2121
|
+
var chain = Promise.resolve();
|
|
2101
2122
|
for (var i = 0; i < queries.length; i++) {
|
|
2102
|
-
|
|
2123
|
+
// Serialize execution while still returning an array of promises
|
|
2124
|
+
var q = chain.then(function(qi) {
|
|
2125
|
+
return executeQuery(context, qi);
|
|
2126
|
+
}.bind(null, queries[i]));
|
|
2103
2127
|
promises.push(q);
|
|
2128
|
+
chain = q;
|
|
2104
2129
|
}
|
|
2105
2130
|
return promises;
|
|
2106
2131
|
}
|
|
@@ -3958,6 +3983,8 @@ function requireClient () {
|
|
|
3958
3983
|
const handler = {
|
|
3959
3984
|
get(target, prop, receiver) {
|
|
3960
3985
|
const value = Reflect.get(target, prop, receiver);
|
|
3986
|
+
if (value instanceof Date)
|
|
3987
|
+
return value;
|
|
3961
3988
|
if (typeof value === 'object' && value !== null) {
|
|
3962
3989
|
return new Proxy(value, handler);
|
|
3963
3990
|
}
|
|
@@ -4461,7 +4488,7 @@ function requireNewColumn () {
|
|
|
4461
4488
|
alias = extractAlias(alias);
|
|
4462
4489
|
from = c.greaterThanOrEqual(context, from, alias);
|
|
4463
4490
|
to = c.lessThanOrEqual(context, to, alias);
|
|
4464
|
-
return from.and(to);
|
|
4491
|
+
return from.and(context, to);
|
|
4465
4492
|
};
|
|
4466
4493
|
|
|
4467
4494
|
c.in = function(context, arg, alias) {
|
|
@@ -9022,6 +9049,7 @@ function requireGetRelatives$1 () {
|
|
|
9022
9049
|
|
|
9023
9050
|
function getRelatives(context, parent, relation) {
|
|
9024
9051
|
var queryContext = parent.queryContext;
|
|
9052
|
+
var ctx = context === undefined ? null : context;
|
|
9025
9053
|
let strategy = queryContext && queryContext.strategy[relation.leftAlias];
|
|
9026
9054
|
var filter = emptyFilter;
|
|
9027
9055
|
if (relation.columns.length === 1)
|
|
@@ -9042,7 +9070,7 @@ function requireGetRelatives$1 () {
|
|
|
9042
9070
|
}
|
|
9043
9071
|
|
|
9044
9072
|
if (ids.length > 0)
|
|
9045
|
-
filter = relation.childTable._primaryColumns[0].in(
|
|
9073
|
+
filter = relation.childTable._primaryColumns[0].in(ctx, ids);
|
|
9046
9074
|
}
|
|
9047
9075
|
|
|
9048
9076
|
function createCompositeFilter() {
|
|
@@ -9050,7 +9078,7 @@ function requireGetRelatives$1 () {
|
|
|
9050
9078
|
for (var i = 0; i < queryContext.rows.length; i++) {
|
|
9051
9079
|
keyFilter = rowToPrimaryKeyFilter(context, queryContext.rows[i], relation);
|
|
9052
9080
|
if (keyFilter)
|
|
9053
|
-
filter = filter.or(
|
|
9081
|
+
filter = filter.or(ctx, keyFilter);
|
|
9054
9082
|
}
|
|
9055
9083
|
}
|
|
9056
9084
|
|
|
@@ -10074,7 +10102,7 @@ function requireNewOneLeg () {
|
|
|
10074
10102
|
c.expand = relation.expand;
|
|
10075
10103
|
|
|
10076
10104
|
c.accept = function(visitor) {
|
|
10077
|
-
visitor.visitOne(c);
|
|
10105
|
+
return visitor.visitOne(c);
|
|
10078
10106
|
};
|
|
10079
10107
|
|
|
10080
10108
|
return c;
|
|
@@ -12773,7 +12801,10 @@ function requireTable () {
|
|
|
12773
12801
|
row[property] = value;
|
|
12774
12802
|
};
|
|
12775
12803
|
|
|
12776
|
-
table.delete =
|
|
12804
|
+
table.delete = function(context, ...rest) {
|
|
12805
|
+
const args = [context, table, ...rest];
|
|
12806
|
+
return _delete.apply(null, args);
|
|
12807
|
+
};
|
|
12777
12808
|
table.cascadeDelete = function(context, ...rest) {
|
|
12778
12809
|
const args = [context, table, ...rest];
|
|
12779
12810
|
return cascadeDelete.apply(null, args);
|
package/dist/index.mjs
CHANGED
|
@@ -1077,6 +1077,10 @@ function requireUtils () {
|
|
|
1077
1077
|
};
|
|
1078
1078
|
|
|
1079
1079
|
c.and = function(context, other) {
|
|
1080
|
+
if (other === undefined) {
|
|
1081
|
+
other = context;
|
|
1082
|
+
context = null;
|
|
1083
|
+
}
|
|
1080
1084
|
other = negotiateRawSqlFilter(context, other);
|
|
1081
1085
|
var nextFilter = negotiateNextAndFilter(filter, other);
|
|
1082
1086
|
var next = newBoolean(nextFilter);
|
|
@@ -1087,6 +1091,10 @@ function requireUtils () {
|
|
|
1087
1091
|
};
|
|
1088
1092
|
|
|
1089
1093
|
c.or = function(context, other) {
|
|
1094
|
+
if (other === undefined) {
|
|
1095
|
+
other = context;
|
|
1096
|
+
context = null;
|
|
1097
|
+
}
|
|
1090
1098
|
other = negotiateRawSqlFilter(context, other);
|
|
1091
1099
|
var nextFilter = negotiateNextOrFilter(filter, other);
|
|
1092
1100
|
var next = newBoolean(nextFilter);
|
|
@@ -1198,10 +1206,14 @@ function requireEmptyFilter () {
|
|
|
1198
1206
|
return emptyFilter.and.apply(null, arguments);
|
|
1199
1207
|
}
|
|
1200
1208
|
|
|
1201
|
-
emptyFilter.sql = parameterized.sql;
|
|
1209
|
+
emptyFilter.sql = parameterized.sql.bind(parameterized);
|
|
1202
1210
|
emptyFilter.parameters = parameterized.parameters;
|
|
1203
1211
|
|
|
1204
1212
|
emptyFilter.and = function(context, other) {
|
|
1213
|
+
if (other === undefined) {
|
|
1214
|
+
other = context;
|
|
1215
|
+
context = null;
|
|
1216
|
+
}
|
|
1205
1217
|
other = negotiateRawSqlFilter(context, other);
|
|
1206
1218
|
for (var i = 2; i < arguments.length; i++) {
|
|
1207
1219
|
other = other.and(context, arguments[i]);
|
|
@@ -1210,6 +1222,10 @@ function requireEmptyFilter () {
|
|
|
1210
1222
|
};
|
|
1211
1223
|
|
|
1212
1224
|
emptyFilter.or = function(context, other) {
|
|
1225
|
+
if (other === undefined) {
|
|
1226
|
+
other = context;
|
|
1227
|
+
context = null;
|
|
1228
|
+
}
|
|
1213
1229
|
other = negotiateRawSqlFilter(context, other);
|
|
1214
1230
|
for (var i = 2; i < arguments.length; i++) {
|
|
1215
1231
|
other = other.or(context, arguments[i]);
|
|
@@ -1218,6 +1234,10 @@ function requireEmptyFilter () {
|
|
|
1218
1234
|
};
|
|
1219
1235
|
|
|
1220
1236
|
emptyFilter.not = function(context, other) {
|
|
1237
|
+
if (other === undefined) {
|
|
1238
|
+
other = context;
|
|
1239
|
+
context = null;
|
|
1240
|
+
}
|
|
1221
1241
|
other = negotiateRawSqlFilter(context, other).not(context);
|
|
1222
1242
|
for (var i = 2; i < arguments.length; i++) {
|
|
1223
1243
|
other = other.and(context, arguments[i]);
|
|
@@ -2099,9 +2119,14 @@ function requireExecuteQueriesCore () {
|
|
|
2099
2119
|
|
|
2100
2120
|
function executeQueriesCore(context, queries) {
|
|
2101
2121
|
var promises = [];
|
|
2122
|
+
var chain = Promise.resolve();
|
|
2102
2123
|
for (var i = 0; i < queries.length; i++) {
|
|
2103
|
-
|
|
2124
|
+
// Serialize execution while still returning an array of promises
|
|
2125
|
+
var q = chain.then(function(qi) {
|
|
2126
|
+
return executeQuery(context, qi);
|
|
2127
|
+
}.bind(null, queries[i]));
|
|
2104
2128
|
promises.push(q);
|
|
2129
|
+
chain = q;
|
|
2105
2130
|
}
|
|
2106
2131
|
return promises;
|
|
2107
2132
|
}
|
|
@@ -3959,6 +3984,8 @@ function requireClient () {
|
|
|
3959
3984
|
const handler = {
|
|
3960
3985
|
get(target, prop, receiver) {
|
|
3961
3986
|
const value = Reflect.get(target, prop, receiver);
|
|
3987
|
+
if (value instanceof Date)
|
|
3988
|
+
return value;
|
|
3962
3989
|
if (typeof value === 'object' && value !== null) {
|
|
3963
3990
|
return new Proxy(value, handler);
|
|
3964
3991
|
}
|
|
@@ -4462,7 +4489,7 @@ function requireNewColumn () {
|
|
|
4462
4489
|
alias = extractAlias(alias);
|
|
4463
4490
|
from = c.greaterThanOrEqual(context, from, alias);
|
|
4464
4491
|
to = c.lessThanOrEqual(context, to, alias);
|
|
4465
|
-
return from.and(to);
|
|
4492
|
+
return from.and(context, to);
|
|
4466
4493
|
};
|
|
4467
4494
|
|
|
4468
4495
|
c.in = function(context, arg, alias) {
|
|
@@ -9023,6 +9050,7 @@ function requireGetRelatives$1 () {
|
|
|
9023
9050
|
|
|
9024
9051
|
function getRelatives(context, parent, relation) {
|
|
9025
9052
|
var queryContext = parent.queryContext;
|
|
9053
|
+
var ctx = context === undefined ? null : context;
|
|
9026
9054
|
let strategy = queryContext && queryContext.strategy[relation.leftAlias];
|
|
9027
9055
|
var filter = emptyFilter;
|
|
9028
9056
|
if (relation.columns.length === 1)
|
|
@@ -9043,7 +9071,7 @@ function requireGetRelatives$1 () {
|
|
|
9043
9071
|
}
|
|
9044
9072
|
|
|
9045
9073
|
if (ids.length > 0)
|
|
9046
|
-
filter = relation.childTable._primaryColumns[0].in(
|
|
9074
|
+
filter = relation.childTable._primaryColumns[0].in(ctx, ids);
|
|
9047
9075
|
}
|
|
9048
9076
|
|
|
9049
9077
|
function createCompositeFilter() {
|
|
@@ -9051,7 +9079,7 @@ function requireGetRelatives$1 () {
|
|
|
9051
9079
|
for (var i = 0; i < queryContext.rows.length; i++) {
|
|
9052
9080
|
keyFilter = rowToPrimaryKeyFilter(context, queryContext.rows[i], relation);
|
|
9053
9081
|
if (keyFilter)
|
|
9054
|
-
filter = filter.or(
|
|
9082
|
+
filter = filter.or(ctx, keyFilter);
|
|
9055
9083
|
}
|
|
9056
9084
|
}
|
|
9057
9085
|
|
|
@@ -10075,7 +10103,7 @@ function requireNewOneLeg () {
|
|
|
10075
10103
|
c.expand = relation.expand;
|
|
10076
10104
|
|
|
10077
10105
|
c.accept = function(visitor) {
|
|
10078
|
-
visitor.visitOne(c);
|
|
10106
|
+
return visitor.visitOne(c);
|
|
10079
10107
|
};
|
|
10080
10108
|
|
|
10081
10109
|
return c;
|
|
@@ -12774,7 +12802,10 @@ function requireTable () {
|
|
|
12774
12802
|
row[property] = value;
|
|
12775
12803
|
};
|
|
12776
12804
|
|
|
12777
|
-
table.delete =
|
|
12805
|
+
table.delete = function(context, ...rest) {
|
|
12806
|
+
const args = [context, table, ...rest];
|
|
12807
|
+
return _delete.apply(null, args);
|
|
12808
|
+
};
|
|
12778
12809
|
table.cascadeDelete = function(context, ...rest) {
|
|
12779
12810
|
const args = [context, table, ...rest];
|
|
12780
12811
|
return cascadeDelete.apply(null, args);
|
|
@@ -19655,7 +19686,7 @@ function requireOutputInsertedSql () {
|
|
|
19655
19686
|
|
|
19656
19687
|
function formatColumn(column) {
|
|
19657
19688
|
if (column.formatOut)
|
|
19658
|
-
return column.formatOut(context, 'INSERTED')
|
|
19689
|
+
return `${column.formatOut(context, 'INSERTED')} AS [${column._dbName}]`;
|
|
19659
19690
|
else
|
|
19660
19691
|
return `INSERTED.[${column._dbName}]`;
|
|
19661
19692
|
}
|
|
@@ -20236,18 +20267,28 @@ function requireWrapQuery$1 () {
|
|
|
20236
20267
|
return runQuery;
|
|
20237
20268
|
|
|
20238
20269
|
function runQuery(query, onCompleted) {
|
|
20239
|
-
|
|
20240
|
-
|
|
20241
|
-
|
|
20242
|
-
|
|
20243
|
-
|
|
20244
|
-
|
|
20245
|
-
}
|
|
20246
|
-
|
|
20247
|
-
|
|
20248
|
-
|
|
20249
|
-
|
|
20250
|
-
|
|
20270
|
+
enqueue(function(done) {
|
|
20271
|
+
function safeCompleted(err, rows) {
|
|
20272
|
+
try {
|
|
20273
|
+
onCompleted(err, rows);
|
|
20274
|
+
} finally {
|
|
20275
|
+
done();
|
|
20276
|
+
}
|
|
20277
|
+
}
|
|
20278
|
+
|
|
20279
|
+
if (!CachedRequest || !CachedTypes) {
|
|
20280
|
+
import('tedious')
|
|
20281
|
+
.then(({ Request, TYPES }) => {
|
|
20282
|
+
CachedRequest = Request;
|
|
20283
|
+
CachedTypes = TYPES;
|
|
20284
|
+
doQuery(query, safeCompleted);
|
|
20285
|
+
})
|
|
20286
|
+
.catch(err => safeCompleted(extractError(err), []));
|
|
20287
|
+
}
|
|
20288
|
+
else {
|
|
20289
|
+
doQuery(query, safeCompleted);
|
|
20290
|
+
}
|
|
20291
|
+
});
|
|
20251
20292
|
}
|
|
20252
20293
|
|
|
20253
20294
|
function doQuery(query, onCompleted) {
|
|
@@ -20348,6 +20389,19 @@ function requireWrapQuery$1 () {
|
|
|
20348
20389
|
}
|
|
20349
20390
|
}
|
|
20350
20391
|
}
|
|
20392
|
+
|
|
20393
|
+
function enqueue(task) {
|
|
20394
|
+
if (!connection.__orangeOrmQueue)
|
|
20395
|
+
connection.__orangeOrmQueue = Promise.resolve();
|
|
20396
|
+
connection.__orangeOrmQueue = connection.__orangeOrmQueue.then(() => new Promise((resolve) => {
|
|
20397
|
+
try {
|
|
20398
|
+
task(resolve);
|
|
20399
|
+
}
|
|
20400
|
+
catch (_e) {
|
|
20401
|
+
resolve();
|
|
20402
|
+
}
|
|
20403
|
+
})).catch(() => {});
|
|
20404
|
+
}
|
|
20351
20405
|
}
|
|
20352
20406
|
|
|
20353
20407
|
// Helper functions remain the same
|
|
@@ -20427,17 +20481,27 @@ function requireWrapCommand$1 () {
|
|
|
20427
20481
|
return runQuery;
|
|
20428
20482
|
|
|
20429
20483
|
function runQuery(query, onCompleted) {
|
|
20430
|
-
|
|
20431
|
-
|
|
20432
|
-
|
|
20433
|
-
|
|
20434
|
-
|
|
20435
|
-
|
|
20436
|
-
}
|
|
20437
|
-
|
|
20438
|
-
|
|
20439
|
-
|
|
20440
|
-
|
|
20484
|
+
enqueue(function(done) {
|
|
20485
|
+
function safeCompleted(err, result) {
|
|
20486
|
+
try {
|
|
20487
|
+
onCompleted(err, result);
|
|
20488
|
+
} finally {
|
|
20489
|
+
done();
|
|
20490
|
+
}
|
|
20491
|
+
}
|
|
20492
|
+
|
|
20493
|
+
if (!CachedRequest || !CachedTypes) {
|
|
20494
|
+
import('tedious')
|
|
20495
|
+
.then(({ Request, TYPES }) => {
|
|
20496
|
+
CachedRequest = Request;
|
|
20497
|
+
CachedTypes = TYPES;
|
|
20498
|
+
doQuery(query, safeCompleted);
|
|
20499
|
+
})
|
|
20500
|
+
.catch((err) => safeCompleted(extractError(err), { rowsAffected: 0 }));
|
|
20501
|
+
} else {
|
|
20502
|
+
doQuery(query, safeCompleted);
|
|
20503
|
+
}
|
|
20504
|
+
});
|
|
20441
20505
|
}
|
|
20442
20506
|
|
|
20443
20507
|
function doQuery(query, onCompleted) {
|
|
@@ -20490,6 +20554,19 @@ function requireWrapCommand$1 () {
|
|
|
20490
20554
|
return onCompleted(null, { rowsAffected: affectedRows });
|
|
20491
20555
|
}
|
|
20492
20556
|
}
|
|
20557
|
+
|
|
20558
|
+
function enqueue(task) {
|
|
20559
|
+
if (!connection.__orangeOrmQueue)
|
|
20560
|
+
connection.__orangeOrmQueue = Promise.resolve();
|
|
20561
|
+
connection.__orangeOrmQueue = connection.__orangeOrmQueue.then(() => new Promise((resolve) => {
|
|
20562
|
+
try {
|
|
20563
|
+
task(resolve);
|
|
20564
|
+
}
|
|
20565
|
+
catch (_e) {
|
|
20566
|
+
resolve();
|
|
20567
|
+
}
|
|
20568
|
+
})).catch(() => {});
|
|
20569
|
+
}
|
|
20493
20570
|
}
|
|
20494
20571
|
|
|
20495
20572
|
function extractError(e) {
|
package/docs/changelog.md
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
## Changelog
|
|
2
|
+
__5.0.0__
|
|
3
|
+
Breaking: `getAll` was removed. Use `getMany` instead (now with the same signature as the removed `getAll`).
|
|
4
|
+
ExpressJS: Before/after hooks to facilitate row-level security [#135](https://github.com/alfateam/orange-orm/issues/135)
|
|
5
|
+
SQLite: Support for invoking user-defined functions [#145](https://github.com/alfateam/orange-orm/issues/145)
|
|
6
|
+
Support for enums [#100](https://github.com/alfateam/orange-orm/issues/100)
|
|
2
7
|
__4.9.1__
|
|
3
8
|
Fix: Avoid double-quoting aliases in discriminator join SQL [#144](https://github.com/alfateam/orange-orm/issues/144)
|
|
4
9
|
__4.9.0__
|
package/other.db
CHANGED
|
Binary file
|
package/package.json
CHANGED
package/src/client/index.js
CHANGED
|
@@ -1104,6 +1104,8 @@ function onChange(target, onChange) {
|
|
|
1104
1104
|
const handler = {
|
|
1105
1105
|
get(target, prop, receiver) {
|
|
1106
1106
|
const value = Reflect.get(target, prop, receiver);
|
|
1107
|
+
if (value instanceof Date)
|
|
1108
|
+
return value;
|
|
1107
1109
|
if (typeof value === 'object' && value !== null) {
|
|
1108
1110
|
return new Proxy(value, handler);
|
|
1109
1111
|
}
|
package/src/emptyFilter.js
CHANGED
|
@@ -4,10 +4,14 @@ function emptyFilter() {
|
|
|
4
4
|
return emptyFilter.and.apply(null, arguments);
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
emptyFilter.sql = parameterized.sql;
|
|
7
|
+
emptyFilter.sql = parameterized.sql.bind(parameterized);
|
|
8
8
|
emptyFilter.parameters = parameterized.parameters;
|
|
9
9
|
|
|
10
10
|
emptyFilter.and = function(context, other) {
|
|
11
|
+
if (other === undefined) {
|
|
12
|
+
other = context;
|
|
13
|
+
context = null;
|
|
14
|
+
}
|
|
11
15
|
other = negotiateRawSqlFilter(context, other);
|
|
12
16
|
for (var i = 2; i < arguments.length; i++) {
|
|
13
17
|
other = other.and(context, arguments[i]);
|
|
@@ -16,6 +20,10 @@ emptyFilter.and = function(context, other) {
|
|
|
16
20
|
};
|
|
17
21
|
|
|
18
22
|
emptyFilter.or = function(context, other) {
|
|
23
|
+
if (other === undefined) {
|
|
24
|
+
other = context;
|
|
25
|
+
context = null;
|
|
26
|
+
}
|
|
19
27
|
other = negotiateRawSqlFilter(context, other);
|
|
20
28
|
for (var i = 2; i < arguments.length; i++) {
|
|
21
29
|
other = other.or(context, arguments[i]);
|
|
@@ -24,6 +32,10 @@ emptyFilter.or = function(context, other) {
|
|
|
24
32
|
};
|
|
25
33
|
|
|
26
34
|
emptyFilter.not = function(context, other) {
|
|
35
|
+
if (other === undefined) {
|
|
36
|
+
other = context;
|
|
37
|
+
context = null;
|
|
38
|
+
}
|
|
27
39
|
other = negotiateRawSqlFilter(context, other).not(context);
|
|
28
40
|
for (var i = 2; i < arguments.length; i++) {
|
|
29
41
|
other = other.and(context, arguments[i]);
|
package/src/map2.d.ts
CHANGED
|
@@ -166,7 +166,7 @@ type BaseFetchStrategy<M extends Record<string, TableDefinition<M>>, K extends k
|
|
|
166
166
|
orderBy?: OrderBy<M, K>;
|
|
167
167
|
limit?: number;
|
|
168
168
|
offset?: number;
|
|
169
|
-
where?:
|
|
169
|
+
where?: WhereClause<M, K>;
|
|
170
170
|
};
|
|
171
171
|
|
|
172
172
|
export type PrimaryKeyObject<M extends Record<string, TableDefinition<M>>, K extends keyof M> =
|
|
@@ -344,18 +344,25 @@ export type AggregateStrategy<M extends Record<string, TableDefinition<M>>, K ex
|
|
|
344
344
|
BaseAggregateStrategy<M, K>
|
|
345
345
|
| CustomAggregateSelectors<M, K>;
|
|
346
346
|
|
|
347
|
-
type
|
|
347
|
+
type WhereFilter<M extends Record<string, TableDefinition<M>>, K extends keyof M> =
|
|
348
|
+
RawFilter | Array<PrimaryKeyObject<M, K>>;
|
|
349
|
+
|
|
350
|
+
type WhereFunc<M extends Record<string, TableDefinition<M>>, K extends keyof M> =
|
|
351
|
+
(row: RootTableRefs<M, K>) => WhereFilter<M, K>;
|
|
352
|
+
|
|
353
|
+
type WhereClause<M extends Record<string, TableDefinition<M>>, K extends keyof M> =
|
|
354
|
+
WhereFilter<M, K> | WhereFunc<M, K> | (() => WhereFilter<M, K>);
|
|
348
355
|
|
|
349
356
|
type BaseAggregateStrategy<M extends Record<string, TableDefinition<M>>, K extends keyof M> = {
|
|
350
357
|
limit?: number;
|
|
351
358
|
offset?: number;
|
|
352
|
-
where?:
|
|
359
|
+
where?: WhereClause<M, K>;
|
|
353
360
|
};
|
|
354
361
|
|
|
355
362
|
type CustomAggregateSelectors<M extends Record<string, TableDefinition<M>>, K extends keyof M> = {
|
|
356
363
|
[key: string]: (row: RootSelectionRefs<M, K>) => ValidSelectorReturnTypes<M, K>;
|
|
357
364
|
} & {
|
|
358
|
-
where?:
|
|
365
|
+
where?: WhereClause<M, K>;
|
|
359
366
|
} & {
|
|
360
367
|
// Explicitly prevent limit/offset in selectors
|
|
361
368
|
limit?: never;
|
|
@@ -683,7 +690,7 @@ export type TableClient<M extends Record<string, TableDefinition<M>>, K extends
|
|
|
683
690
|
aggregate<strategy extends AggregateStrategy<M, K>>(strategy: strategy): Promise<Array<DeepExpand<AggregateCustomSelectorProperties<M, K, strategy>>>>;
|
|
684
691
|
|
|
685
692
|
// Single item methods - return individual objects with individual active record methods
|
|
686
|
-
getOne<strategy extends FetchStrategy<M, K
|
|
693
|
+
getOne<strategy extends FetchStrategy<M, K>>(
|
|
687
694
|
strategy?: strategy
|
|
688
695
|
): Promise<WithActiveRecord<DeepExpand<Selection<M, K, strategy>>, M, K> | undefined>;
|
|
689
696
|
|
|
@@ -698,12 +705,12 @@ export type TableClient<M extends Record<string, TableDefinition<M>>, K extends
|
|
|
698
705
|
// UPDATED: Bulk update methods with relations support
|
|
699
706
|
update(
|
|
700
707
|
row: UpdateRowWithRelations<M, K>,
|
|
701
|
-
opts: { where:
|
|
708
|
+
opts: { where: WhereClause<M, K> }
|
|
702
709
|
): Promise<void>;
|
|
703
710
|
|
|
704
711
|
update<strategy extends FetchStrategy<M, K>>(
|
|
705
712
|
row: UpdateRowWithRelations<M, K>,
|
|
706
|
-
opts: { where:
|
|
713
|
+
opts: { where: WhereClause<M, K> },
|
|
707
714
|
strategy: strategy
|
|
708
715
|
): Promise<WithArrayActiveRecord<Array<DeepExpand<Selection<M, K, strategy>>>, M, K>>;
|
|
709
716
|
|
|
@@ -55,7 +55,7 @@ module.exports = function(table, name) {
|
|
|
55
55
|
alias = extractAlias(alias);
|
|
56
56
|
from = c.greaterThanOrEqual(context, from, alias);
|
|
57
57
|
to = c.lessThanOrEqual(context, to, alias);
|
|
58
|
-
return from.and(to);
|
|
58
|
+
return from.and(context, to);
|
|
59
59
|
};
|
|
60
60
|
|
|
61
61
|
c.in = function(context, arg, alias) {
|
|
@@ -102,4 +102,4 @@ module.exports = function(table, name) {
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
return c;
|
|
105
|
-
};
|
|
105
|
+
};
|
|
@@ -18,6 +18,10 @@ function newBoolean(filter) {
|
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
c.and = function(context, other) {
|
|
21
|
+
if (other === undefined) {
|
|
22
|
+
other = context;
|
|
23
|
+
context = null;
|
|
24
|
+
}
|
|
21
25
|
other = negotiateRawSqlFilter(context, other);
|
|
22
26
|
var nextFilter = negotiateNextAndFilter(filter, other);
|
|
23
27
|
var next = newBoolean(nextFilter);
|
|
@@ -28,6 +32,10 @@ function newBoolean(filter) {
|
|
|
28
32
|
};
|
|
29
33
|
|
|
30
34
|
c.or = function(context, other) {
|
|
35
|
+
if (other === undefined) {
|
|
36
|
+
other = context;
|
|
37
|
+
context = null;
|
|
38
|
+
}
|
|
31
39
|
other = negotiateRawSqlFilter(context, other);
|
|
32
40
|
var nextFilter = negotiateNextOrFilter(filter, other);
|
|
33
41
|
var next = newBoolean(nextFilter);
|
|
@@ -2,11 +2,16 @@ var executeQuery = require('./executeQuery');
|
|
|
2
2
|
|
|
3
3
|
function executeQueriesCore(context, queries) {
|
|
4
4
|
var promises = [];
|
|
5
|
+
var chain = Promise.resolve();
|
|
5
6
|
for (var i = 0; i < queries.length; i++) {
|
|
6
|
-
|
|
7
|
+
// Serialize execution while still returning an array of promises
|
|
8
|
+
var q = chain.then(function(qi) {
|
|
9
|
+
return executeQuery(context, qi);
|
|
10
|
+
}.bind(null, queries[i]));
|
|
7
11
|
promises.push(q);
|
|
12
|
+
chain = q;
|
|
8
13
|
}
|
|
9
14
|
return promises;
|
|
10
15
|
}
|
|
11
16
|
|
|
12
|
-
module.exports = executeQueriesCore;
|
|
17
|
+
module.exports = executeQueriesCore;
|
|
@@ -4,6 +4,7 @@ var negotiateExpandInverse = require('../negotiateExpandInverse');
|
|
|
4
4
|
|
|
5
5
|
function getRelatives(context, parent, relation) {
|
|
6
6
|
var queryContext = parent.queryContext;
|
|
7
|
+
var ctx = context === undefined ? null : context;
|
|
7
8
|
let strategy = queryContext && queryContext.strategy[relation.leftAlias];
|
|
8
9
|
var filter = emptyFilter;
|
|
9
10
|
if (relation.columns.length === 1)
|
|
@@ -24,7 +25,7 @@ function getRelatives(context, parent, relation) {
|
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
if (ids.length > 0)
|
|
27
|
-
filter = relation.childTable._primaryColumns[0].in(
|
|
28
|
+
filter = relation.childTable._primaryColumns[0].in(ctx, ids);
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
function createCompositeFilter() {
|
|
@@ -32,7 +33,7 @@ function getRelatives(context, parent, relation) {
|
|
|
32
33
|
for (var i = 0; i < queryContext.rows.length; i++) {
|
|
33
34
|
keyFilter = rowToPrimaryKeyFilter(context, queryContext.rows[i], relation);
|
|
34
35
|
if (keyFilter)
|
|
35
|
-
filter = filter.or(
|
|
36
|
+
filter = filter.or(ctx, keyFilter);
|
|
36
37
|
}
|
|
37
38
|
}
|
|
38
39
|
|
|
@@ -61,4 +62,4 @@ function isNullOrUndefined(item) {
|
|
|
61
62
|
return item === null || item === undefined;
|
|
62
63
|
}
|
|
63
64
|
|
|
64
|
-
module.exports = getRelatives;
|
|
65
|
+
module.exports = getRelatives;
|
package/src/table.js
CHANGED
|
@@ -192,7 +192,10 @@ function _new(tableName) {
|
|
|
192
192
|
row[property] = value;
|
|
193
193
|
};
|
|
194
194
|
|
|
195
|
-
table.delete =
|
|
195
|
+
table.delete = function(context, ...rest) {
|
|
196
|
+
const args = [context, table, ...rest];
|
|
197
|
+
return _delete.apply(null, args);
|
|
198
|
+
};
|
|
196
199
|
table.cascadeDelete = function(context, ...rest) {
|
|
197
200
|
const args = [context, table, ...rest];
|
|
198
201
|
return cascadeDelete.apply(null, args);
|
|
@@ -9,7 +9,7 @@ function outputInsertedSql(context, table) {
|
|
|
9
9
|
|
|
10
10
|
function formatColumn(column) {
|
|
11
11
|
if (column.formatOut)
|
|
12
|
-
return column.formatOut(context, 'INSERTED')
|
|
12
|
+
return `${column.formatOut(context, 'INSERTED')} AS [${column._dbName}]`;
|
|
13
13
|
else
|
|
14
14
|
return `INSERTED.[${column._dbName}]`;
|
|
15
15
|
}
|
|
@@ -17,4 +17,4 @@ function outputInsertedSql(context, table) {
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
module.exports = outputInsertedSql;
|
|
20
|
+
module.exports = outputInsertedSql;
|
|
@@ -7,17 +7,27 @@ function wrapCommand(_context, connection) {
|
|
|
7
7
|
return runQuery;
|
|
8
8
|
|
|
9
9
|
function runQuery(query, onCompleted) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
10
|
+
enqueue(function(done) {
|
|
11
|
+
function safeCompleted(err, result) {
|
|
12
|
+
try {
|
|
13
|
+
onCompleted(err, result);
|
|
14
|
+
} finally {
|
|
15
|
+
done();
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (!CachedRequest || !CachedTypes) {
|
|
20
|
+
import('tedious')
|
|
21
|
+
.then(({ Request, TYPES }) => {
|
|
22
|
+
CachedRequest = Request;
|
|
23
|
+
CachedTypes = TYPES;
|
|
24
|
+
doQuery(query, safeCompleted);
|
|
25
|
+
})
|
|
26
|
+
.catch((err) => safeCompleted(extractError(err), { rowsAffected: 0 }));
|
|
27
|
+
} else {
|
|
28
|
+
doQuery(query, safeCompleted);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
21
31
|
}
|
|
22
32
|
|
|
23
33
|
function doQuery(query, onCompleted) {
|
|
@@ -70,6 +80,19 @@ function wrapCommand(_context, connection) {
|
|
|
70
80
|
return onCompleted(null, { rowsAffected: affectedRows });
|
|
71
81
|
}
|
|
72
82
|
}
|
|
83
|
+
|
|
84
|
+
function enqueue(task) {
|
|
85
|
+
if (!connection.__orangeOrmQueue)
|
|
86
|
+
connection.__orangeOrmQueue = Promise.resolve();
|
|
87
|
+
connection.__orangeOrmQueue = connection.__orangeOrmQueue.then(() => new Promise((resolve) => {
|
|
88
|
+
try {
|
|
89
|
+
task(resolve);
|
|
90
|
+
}
|
|
91
|
+
catch (_e) {
|
|
92
|
+
resolve();
|
|
93
|
+
}
|
|
94
|
+
})).catch(() => {});
|
|
95
|
+
}
|
|
73
96
|
}
|
|
74
97
|
|
|
75
98
|
function extractError(e) {
|
package/src/tedious/wrapQuery.js
CHANGED
|
@@ -7,18 +7,28 @@ function wrapQuery(_context, connection) {
|
|
|
7
7
|
return runQuery;
|
|
8
8
|
|
|
9
9
|
function runQuery(query, onCompleted) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
10
|
+
enqueue(function(done) {
|
|
11
|
+
function safeCompleted(err, rows) {
|
|
12
|
+
try {
|
|
13
|
+
onCompleted(err, rows);
|
|
14
|
+
} finally {
|
|
15
|
+
done();
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (!CachedRequest || !CachedTypes) {
|
|
20
|
+
import('tedious')
|
|
21
|
+
.then(({ Request, TYPES }) => {
|
|
22
|
+
CachedRequest = Request;
|
|
23
|
+
CachedTypes = TYPES;
|
|
24
|
+
doQuery(query, safeCompleted);
|
|
25
|
+
})
|
|
26
|
+
.catch(err => safeCompleted(extractError(err), []));
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
doQuery(query, safeCompleted);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
22
32
|
}
|
|
23
33
|
|
|
24
34
|
function doQuery(query, onCompleted) {
|
|
@@ -119,6 +129,19 @@ function wrapQuery(_context, connection) {
|
|
|
119
129
|
}
|
|
120
130
|
}
|
|
121
131
|
}
|
|
132
|
+
|
|
133
|
+
function enqueue(task) {
|
|
134
|
+
if (!connection.__orangeOrmQueue)
|
|
135
|
+
connection.__orangeOrmQueue = Promise.resolve();
|
|
136
|
+
connection.__orangeOrmQueue = connection.__orangeOrmQueue.then(() => new Promise((resolve) => {
|
|
137
|
+
try {
|
|
138
|
+
task(resolve);
|
|
139
|
+
}
|
|
140
|
+
catch (_e) {
|
|
141
|
+
resolve();
|
|
142
|
+
}
|
|
143
|
+
})).catch(() => {});
|
|
144
|
+
}
|
|
122
145
|
}
|
|
123
146
|
|
|
124
147
|
// Helper functions remain the same
|
|
@@ -179,4 +202,4 @@ function addParameters(request, params, TYPES) {
|
|
|
179
202
|
}
|
|
180
203
|
}
|
|
181
204
|
|
|
182
|
-
module.exports = wrapQuery;
|
|
205
|
+
module.exports = wrapQuery;
|
package/deno.lock
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": "5",
|
|
3
|
-
"specifiers": {
|
|
4
|
-
"jsr:@std/assert@*": "1.0.17",
|
|
5
|
-
"jsr:@std/assert@^1.0.17": "1.0.17",
|
|
6
|
-
"jsr:@std/internal@^1.0.12": "1.0.12",
|
|
7
|
-
"jsr:@std/path@*": "1.1.4",
|
|
8
|
-
"jsr:@std/testing@*": "1.0.17"
|
|
9
|
-
},
|
|
10
|
-
"jsr": {
|
|
11
|
-
"@std/assert@1.0.17": {
|
|
12
|
-
"integrity": "df5ebfffe77c03b3fa1401e11c762cc8f603d51021c56c4d15a8c7ab45e90dbe",
|
|
13
|
-
"dependencies": [
|
|
14
|
-
"jsr:@std/internal"
|
|
15
|
-
]
|
|
16
|
-
},
|
|
17
|
-
"@std/internal@1.0.12": {
|
|
18
|
-
"integrity": "972a634fd5bc34b242024402972cd5143eac68d8dffaca5eaa4dba30ce17b027"
|
|
19
|
-
},
|
|
20
|
-
"@std/path@1.1.4": {
|
|
21
|
-
"integrity": "1d2d43f39efb1b42f0b1882a25486647cb851481862dc7313390b2bb044314b5",
|
|
22
|
-
"dependencies": [
|
|
23
|
-
"jsr:@std/internal"
|
|
24
|
-
]
|
|
25
|
-
},
|
|
26
|
-
"@std/testing@1.0.17": {
|
|
27
|
-
"integrity": "87bdc2700fa98249d48a17cd72413352d3d3680dcfbdb64947fd0982d6bbf681",
|
|
28
|
-
"dependencies": [
|
|
29
|
-
"jsr:@std/assert@^1.0.17",
|
|
30
|
-
"jsr:@std/internal"
|
|
31
|
-
]
|
|
32
|
-
}
|
|
33
|
-
},
|
|
34
|
-
"workspace": {
|
|
35
|
-
"packageJson": {
|
|
36
|
-
"dependencies": [
|
|
37
|
-
"npm:@cloudflare/workers-types@^4.20241106.0",
|
|
38
|
-
"npm:@electric-sql/pglite@0.3",
|
|
39
|
-
"npm:@lroal/on-change@^4.0.2",
|
|
40
|
-
"npm:@rollup/plugin-commonjs@^28.0.2",
|
|
41
|
-
"npm:@rollup/plugin-json@^6.1.0",
|
|
42
|
-
"npm:@rollup/plugin-node-resolve@13",
|
|
43
|
-
"npm:@tediousjs/connection-string@~0.4.1",
|
|
44
|
-
"npm:@types/express@^4.17.13",
|
|
45
|
-
"npm:@types/oracledb@^6.0.4",
|
|
46
|
-
"npm:@types/tedious@^4.0.14",
|
|
47
|
-
"npm:@typescript-eslint/eslint-plugin@6",
|
|
48
|
-
"npm:@typescript-eslint/parser@6",
|
|
49
|
-
"npm:@vitest/coverage-v8@^3.2.4",
|
|
50
|
-
"npm:ajv@^8.17.1",
|
|
51
|
-
"npm:axios@^1.6.2",
|
|
52
|
-
"npm:better-sqlite3@^11.8.1",
|
|
53
|
-
"npm:cors@^2.8.5",
|
|
54
|
-
"npm:eslint-plugin-jest@^27.1.7",
|
|
55
|
-
"npm:eslint@^8.57.0",
|
|
56
|
-
"npm:express@^4.18.2",
|
|
57
|
-
"npm:fast-json-patch@^3.1.1",
|
|
58
|
-
"npm:findup-sync@5",
|
|
59
|
-
"npm:glob@^10.3.4 || ^11.0.2",
|
|
60
|
-
"npm:module-definition@4 || 5 || * || 6",
|
|
61
|
-
"npm:msnodesqlv8@^4.1.0",
|
|
62
|
-
"npm:mysql2@^3.9.4",
|
|
63
|
-
"npm:oracledb@^6.3.0",
|
|
64
|
-
"npm:owasp-dependency-check@^0.0.21",
|
|
65
|
-
"npm:pg-query-stream@^3.3.2",
|
|
66
|
-
"npm:pg@^8.5.1",
|
|
67
|
-
"npm:rfdc@^1.2.0",
|
|
68
|
-
"npm:rollup@^2.52.7",
|
|
69
|
-
"npm:tedious@19",
|
|
70
|
-
"npm:typescript@^5.4.5",
|
|
71
|
-
"npm:uuid@^8.3.2 || 9 || 10 || ^11.1.0",
|
|
72
|
-
"npm:vitest@^3.2.4"
|
|
73
|
-
]
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|