meadow-endpoints 4.0.14 → 4.0.16

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.
Files changed (27) hide show
  1. package/dist/indoctrinate_content_staging/Indoctrinate-Catalog-AppData.json +1286 -1065
  2. package/dist/meadow-endpoints.js +253 -164
  3. package/dist/meadow-endpoints.js.map +1 -1
  4. package/dist/meadow-endpoints.min.js +7 -7
  5. package/dist/meadow-endpoints.min.js.map +1 -1
  6. package/docs/_version.json +7 -0
  7. package/docs/css/docuserve.css +277 -23
  8. package/docs/index.html +2 -2
  9. package/docs/retold-catalog.json +13 -1
  10. package/docs/retold-keyword-index.json +1 -1
  11. package/package.json +9 -8
  12. package/source/Meadow-Endpoints-Browser-Shim.js +4 -1
  13. package/source/Meadow-Endpoints.js +6 -6
  14. package/source/controller/Meadow-Endpoints-Controller-Base.js +6 -6
  15. package/source/controller/components/Meadow-Endpoints-Controller-BehaviorInjection.js +11 -11
  16. package/source/controller/components/Meadow-Endpoints-Controller-Error.js +23 -15
  17. package/source/controller/components/Meadow-Endpoints-Controller-Log.js +9 -9
  18. package/source/controller/utility/Meadow-Endpoints-Filter-Parser.js +16 -16
  19. package/source/controller/utility/Meadow-Endpoints-Session-Marshaler.js +42 -42
  20. package/source/controller/utility/Meadow-Endpoints-Stream-RecordArray.js +6 -6
  21. package/source/endpoints/create/Meadow-Operation-Create.js +1 -1
  22. package/source/endpoints/schema/Meadow-Endpoint-Validate.js +1 -1
  23. package/source/endpoints/update/Meadow-Endpoint-BulkUpdate.js +2 -0
  24. package/source/endpoints/update/Meadow-Operation-Update.js +2 -0
  25. package/source/endpoints/upsert/Meadow-Endpoint-BulkUpsert.js +3 -1
  26. package/source/endpoints/upsert/Meadow-Operation-Upsert.js +5 -3
  27. package/test/MeadowEndpoints_basic_tests.js +776 -0
@@ -819,6 +819,45 @@ suite
819
819
  );
820
820
  }
821
821
  );
822
+ test
823
+ (
824
+ 'upsert: update by GUID when passed ID is zero',
825
+ function (fDone)
826
+ {
827
+ // First create a record so we have a known GUID
828
+ _SuperTest
829
+ .post('1.0/Book')
830
+ .send({ Title: 'Zero ID Upsert Test', Genre: 'Test' })
831
+ .end(
832
+ (pError, pResponse) =>
833
+ {
834
+ let tmpCreated = JSON.parse(pResponse.text);
835
+ let tmpRecord = Array.isArray(tmpCreated) ? tmpCreated[0] : tmpCreated;
836
+ let tmpGUID = tmpRecord.GUIDBook;
837
+ let tmpID = tmpRecord.IDBook;
838
+ Expect(tmpID).to.be.above(0);
839
+ Expect(tmpGUID).to.be.a('string');
840
+
841
+ // Now upsert with ID=0 but the same GUID — should
842
+ // find the record by GUID and update it, not fail
843
+ // with "Record IDs do not match".
844
+ _SuperTest
845
+ .put('1.0/Book/Upsert')
846
+ .send({ IDBook: 0, GUIDBook: tmpGUID, Title: 'Zero ID Upsert Updated' })
847
+ .end(
848
+ (pUpsertError, pUpsertResponse) =>
849
+ {
850
+ Expect(pUpsertResponse.status).to.equal(200);
851
+ let tmpResult = JSON.parse(pUpsertResponse.text);
852
+ Expect(tmpResult.IDBook).to.equal(tmpID);
853
+ Expect(tmpResult.Title).to.equal('Zero ID Upsert Updated');
854
+ fDone();
855
+ }
856
+ );
857
+ }
858
+ );
859
+ }
860
+ );
822
861
  }
823
862
  );
824
863
 
@@ -1369,6 +1408,743 @@ suite
1369
1408
  );
1370
1409
  }
1371
1410
  );
1411
+
1412
+ // ==================================================================
1413
+ // New hooks added 2026-04-18 to restore ME2 parity
1414
+ // (Update-Pre, Update-Query) and to extend ME4's bulk-level hooks
1415
+ // to Update/Upsert (UpdateBulk-*, UpsertBulk-*).
1416
+ // ==================================================================
1417
+
1418
+ test
1419
+ (
1420
+ 'setBehavior: Update-PreOperation hook can mutate RecordToModify before DAL update',
1421
+ function (fDone)
1422
+ {
1423
+ _MeadowEndpoints.controller.BehaviorInjection.setBehavior('Update-PreOperation',
1424
+ (pRequest, pRequestState, fCallback) =>
1425
+ {
1426
+ // Hook sees the incoming payload on RecordToModify,
1427
+ // existing loaded row on Record. Mutations to
1428
+ // RecordToModify flow through to the DAL update.
1429
+ Expect(pRequestState.RecordToModify).to.be.an('object');
1430
+ pRequestState.RecordToModify.Genre = 'MutatedByPreOp';
1431
+ return fCallback();
1432
+ });
1433
+
1434
+ _SuperTest
1435
+ .put('1.0/Book')
1436
+ .send({ IDBook: 4, Title: 'Snow Crash (v2)' })
1437
+ .end(
1438
+ (pError, pResponse) =>
1439
+ {
1440
+ let tmpResult = JSON.parse(pResponse.text);
1441
+ Expect(tmpResult.Genre).to.equal('MutatedByPreOp');
1442
+ Expect(tmpResult.Title).to.equal('Snow Crash (v2)');
1443
+
1444
+ delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Update-PreOperation'];
1445
+ fDone();
1446
+ }
1447
+ );
1448
+ }
1449
+ );
1450
+ test
1451
+ (
1452
+ 'setBehavior: Update-PreOperation hook can reject an update',
1453
+ function (fDone)
1454
+ {
1455
+ _MeadowEndpoints.controller.BehaviorInjection.setBehavior('Update-PreOperation',
1456
+ (pRequest, pRequestState, fCallback) =>
1457
+ {
1458
+ if (!pRequestState.RecordToModify.Title)
1459
+ {
1460
+ const tmpError = new Error('Title is required');
1461
+ tmpError.StatusCode = 400;
1462
+ return fCallback(tmpError);
1463
+ }
1464
+ return fCallback();
1465
+ });
1466
+
1467
+ _SuperTest
1468
+ .put('1.0/Book')
1469
+ .send({ IDBook: 3 })
1470
+ .end(
1471
+ (pError, pResponse) =>
1472
+ {
1473
+ const tmpResult = JSON.parse(pResponse.text);
1474
+ Expect(tmpResult).to.have.property('Error');
1475
+
1476
+ delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Update-PreOperation'];
1477
+ fDone();
1478
+ }
1479
+ );
1480
+ }
1481
+ );
1482
+ test
1483
+ (
1484
+ 'setBehavior: Update-QueryConfiguration hook fires after Query.addRecord',
1485
+ function (fDone)
1486
+ {
1487
+ _MeadowEndpoints.controller.BehaviorInjection.setBehavior('Update-QueryConfiguration',
1488
+ (pRequest, pRequestState, fCallback) =>
1489
+ {
1490
+ // Query should exist and have had the record added;
1491
+ // hook can scope the update further.
1492
+ Expect(pRequestState.Query).to.exist;
1493
+ pRequestState.Query.addFilter('Deleted', 0);
1494
+ return fCallback();
1495
+ });
1496
+
1497
+ _SuperTest
1498
+ .put('1.0/Book')
1499
+ .send({ IDBook: 2, Title: 'Dune (updated)' })
1500
+ .end(
1501
+ (pError, pResponse) =>
1502
+ {
1503
+ const tmpResult = JSON.parse(pResponse.text);
1504
+ Expect(tmpResult.Title).to.equal('Dune (updated)');
1505
+
1506
+ delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Update-QueryConfiguration'];
1507
+ fDone();
1508
+ }
1509
+ );
1510
+ }
1511
+ );
1512
+ test
1513
+ (
1514
+ 'setBehavior: UpdateBulk-PreOperation fires once before the batch',
1515
+ function (fDone)
1516
+ {
1517
+ let _CallCount = 0;
1518
+ let _SawBulkRecords = false;
1519
+ _MeadowEndpoints.controller.BehaviorInjection.setBehavior('UpdateBulk-PreOperation',
1520
+ (pRequest, pRequestState, fCallback) =>
1521
+ {
1522
+ _CallCount++;
1523
+ _SawBulkRecords = Array.isArray(pRequestState.BulkRecords);
1524
+ return fCallback();
1525
+ });
1526
+
1527
+ _SuperTest
1528
+ .put('1.0/Books')
1529
+ .send([
1530
+ { IDBook: 1, Title: 'Angels & Demons (batch)' },
1531
+ { IDBook: 2, Title: 'Dune (batch)' },
1532
+ ])
1533
+ .end(
1534
+ (pError, pResponse) =>
1535
+ {
1536
+ Expect(_CallCount).to.equal(1);
1537
+ Expect(_SawBulkRecords).to.equal(true);
1538
+
1539
+ delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['UpdateBulk-PreOperation'];
1540
+ fDone();
1541
+ }
1542
+ );
1543
+ }
1544
+ );
1545
+ test
1546
+ (
1547
+ 'setBehavior: UpdateBulk-PostOperation fires once after the batch',
1548
+ function (fDone)
1549
+ {
1550
+ let _CallCount = 0;
1551
+ let _SawUpdatedRecords = false;
1552
+ _MeadowEndpoints.controller.BehaviorInjection.setBehavior('UpdateBulk-PostOperation',
1553
+ (pRequest, pRequestState, fCallback) =>
1554
+ {
1555
+ _CallCount++;
1556
+ _SawUpdatedRecords = Array.isArray(pRequestState.UpdatedRecords) && pRequestState.UpdatedRecords.length > 0;
1557
+ return fCallback();
1558
+ });
1559
+
1560
+ _SuperTest
1561
+ .put('1.0/Books')
1562
+ .send([
1563
+ { IDBook: 3, Title: 'Neuromancer (batch post)' },
1564
+ ])
1565
+ .end(
1566
+ (pError, pResponse) =>
1567
+ {
1568
+ Expect(_CallCount).to.equal(1);
1569
+ Expect(_SawUpdatedRecords).to.equal(true);
1570
+
1571
+ delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['UpdateBulk-PostOperation'];
1572
+ fDone();
1573
+ }
1574
+ );
1575
+ }
1576
+ );
1577
+ test
1578
+ (
1579
+ 'setBehavior: UpsertBulk-PreOperation fires once before the batch',
1580
+ function (fDone)
1581
+ {
1582
+ let _CallCount = 0;
1583
+ _MeadowEndpoints.controller.BehaviorInjection.setBehavior('UpsertBulk-PreOperation',
1584
+ (pRequest, pRequestState, fCallback) =>
1585
+ {
1586
+ _CallCount++;
1587
+ Expect(Array.isArray(pRequestState.BulkRecords)).to.equal(true);
1588
+ return fCallback();
1589
+ });
1590
+
1591
+ _SuperTest
1592
+ .put('1.0/Book/Upserts')
1593
+ .send([
1594
+ { Title: 'Bulk Upsert New 1' },
1595
+ { Title: 'Bulk Upsert New 2' },
1596
+ ])
1597
+ .end(
1598
+ (pError, pResponse) =>
1599
+ {
1600
+ Expect(_CallCount).to.equal(1);
1601
+
1602
+ delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['UpsertBulk-PreOperation'];
1603
+ fDone();
1604
+ }
1605
+ );
1606
+ }
1607
+ );
1608
+ test
1609
+ (
1610
+ 'setBehavior: UpsertBulk-PostOperation fires once after the batch',
1611
+ function (fDone)
1612
+ {
1613
+ let _CallCount = 0;
1614
+ let _SawUpserted = false;
1615
+ _MeadowEndpoints.controller.BehaviorInjection.setBehavior('UpsertBulk-PostOperation',
1616
+ (pRequest, pRequestState, fCallback) =>
1617
+ {
1618
+ _CallCount++;
1619
+ _SawUpserted = Array.isArray(pRequestState.UpsertedRecords) && pRequestState.UpsertedRecords.length > 0;
1620
+ return fCallback();
1621
+ });
1622
+
1623
+ _SuperTest
1624
+ .put('1.0/Book/Upserts')
1625
+ .send([
1626
+ { Title: 'Bulk Upsert Post 1' },
1627
+ ])
1628
+ .end(
1629
+ (pError, pResponse) =>
1630
+ {
1631
+ Expect(_CallCount).to.equal(1);
1632
+ Expect(_SawUpserted).to.equal(true);
1633
+
1634
+ delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['UpsertBulk-PostOperation'];
1635
+ fDone();
1636
+ }
1637
+ );
1638
+ }
1639
+ );
1640
+
1641
+ // ==================================================================
1642
+ // Coverage backfill for hooks that were present but previously
1643
+ // untested. Each test registers a handler, fires the endpoint,
1644
+ // and asserts the hook observed the expected state. These also
1645
+ // act as stage-semantics documentation for the hook surface.
1646
+ // ==================================================================
1647
+
1648
+ test
1649
+ (
1650
+ 'setBehavior: Create-QueryConfiguration fires after Query.addRecord',
1651
+ function (fDone)
1652
+ {
1653
+ let _Seen = null;
1654
+ _MeadowEndpoints.controller.BehaviorInjection.setBehavior('Create-QueryConfiguration',
1655
+ (pRequest, pRequestState, fCallback) =>
1656
+ {
1657
+ _Seen = {
1658
+ hasQuery: !!pRequestState.Query,
1659
+ hasRecordToCreate: !!pRequestState.RecordToCreate,
1660
+ };
1661
+ return fCallback();
1662
+ });
1663
+
1664
+ _SuperTest
1665
+ .post('1.0/Book')
1666
+ .send({ Title: 'Query-Config hook target' })
1667
+ .end(
1668
+ (pError, pResponse) =>
1669
+ {
1670
+ Expect(_Seen).to.deep.equal({ hasQuery: true, hasRecordToCreate: true });
1671
+
1672
+ delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Create-QueryConfiguration'];
1673
+ fDone();
1674
+ }
1675
+ );
1676
+ }
1677
+ );
1678
+ test
1679
+ (
1680
+ 'setBehavior: Create-PostOperation sees the freshly-inserted Record',
1681
+ function (fDone)
1682
+ {
1683
+ let _SeenIDBook = null;
1684
+ _MeadowEndpoints.controller.BehaviorInjection.setBehavior('Create-PostOperation',
1685
+ (pRequest, pRequestState, fCallback) =>
1686
+ {
1687
+ _SeenIDBook = pRequestState.Record && pRequestState.Record.IDBook;
1688
+ pRequestState.Record.PostOpTag = 'was-here';
1689
+ return fCallback();
1690
+ });
1691
+
1692
+ _SuperTest
1693
+ .post('1.0/Book')
1694
+ .send({ Title: 'Post-op hook target' })
1695
+ .end(
1696
+ (pError, pResponse) =>
1697
+ {
1698
+ const tmpResult = JSON.parse(pResponse.text);
1699
+ Expect(_SeenIDBook).to.be.above(0);
1700
+ Expect(tmpResult.PostOpTag).to.equal('was-here');
1701
+
1702
+ delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Create-PostOperation'];
1703
+ fDone();
1704
+ }
1705
+ );
1706
+ }
1707
+ );
1708
+ test
1709
+ (
1710
+ 'setBehavior: CreateBulk-PreOperation fires once with RecordsToBulkCreate',
1711
+ function (fDone)
1712
+ {
1713
+ let _CallCount = 0;
1714
+ let _SawRecords = false;
1715
+ _MeadowEndpoints.controller.BehaviorInjection.setBehavior('CreateBulk-PreOperation',
1716
+ (pRequest, pRequestState, fCallback) =>
1717
+ {
1718
+ _CallCount++;
1719
+ _SawRecords = Array.isArray(pRequest.RecordsToBulkCreate);
1720
+ return fCallback();
1721
+ });
1722
+
1723
+ _SuperTest
1724
+ .post('1.0/Books')
1725
+ .send([
1726
+ { Title: 'Bulk Create 1' },
1727
+ { Title: 'Bulk Create 2' },
1728
+ ])
1729
+ .end(
1730
+ (pError, pResponse) =>
1731
+ {
1732
+ Expect(_CallCount).to.equal(1);
1733
+ Expect(_SawRecords).to.equal(true);
1734
+
1735
+ delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['CreateBulk-PreOperation'];
1736
+ fDone();
1737
+ }
1738
+ );
1739
+ }
1740
+ );
1741
+ test
1742
+ (
1743
+ 'setBehavior: CreateBulk-PostOperation fires once with CreatedRecords',
1744
+ function (fDone)
1745
+ {
1746
+ let _SawCreated = null;
1747
+ _MeadowEndpoints.controller.BehaviorInjection.setBehavior('CreateBulk-PostOperation',
1748
+ (pRequest, pRequestState, fCallback) =>
1749
+ {
1750
+ _SawCreated = Array.isArray(pRequestState.CreatedRecords) && pRequestState.CreatedRecords.length;
1751
+ return fCallback();
1752
+ });
1753
+
1754
+ _SuperTest
1755
+ .post('1.0/Books')
1756
+ .send([
1757
+ { Title: 'Bulk Create Post 1' },
1758
+ ])
1759
+ .end(
1760
+ (pError, pResponse) =>
1761
+ {
1762
+ Expect(_SawCreated).to.equal(1);
1763
+
1764
+ delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['CreateBulk-PostOperation'];
1765
+ fDone();
1766
+ }
1767
+ );
1768
+ }
1769
+ );
1770
+ test
1771
+ (
1772
+ 'setBehavior: Delete-QueryConfiguration can scope the delete query',
1773
+ function (fDone)
1774
+ {
1775
+ _MeadowEndpoints.controller.BehaviorInjection.setBehavior('Delete-QueryConfiguration',
1776
+ (pRequest, pRequestState, fCallback) =>
1777
+ {
1778
+ Expect(pRequestState.Query).to.exist;
1779
+ return fCallback();
1780
+ });
1781
+
1782
+ // Use a record we don't care about the state of; create one inline.
1783
+ _SuperTest
1784
+ .post('1.0/Book')
1785
+ .send({ Title: 'Delete-Query target' })
1786
+ .end(
1787
+ (pPostErr, pPostRes) =>
1788
+ {
1789
+ const tmpID = JSON.parse(pPostRes.text).IDBook;
1790
+ _SuperTest
1791
+ .delete(`1.0/Book/${tmpID}`)
1792
+ .end(
1793
+ (pDelErr, pDelRes) =>
1794
+ {
1795
+ delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Delete-QueryConfiguration'];
1796
+ fDone();
1797
+ }
1798
+ );
1799
+ }
1800
+ );
1801
+ }
1802
+ );
1803
+ test
1804
+ (
1805
+ 'setBehavior: Delete-PostOperation fires after soft-delete',
1806
+ function (fDone)
1807
+ {
1808
+ let _HookFired = false;
1809
+ _MeadowEndpoints.controller.BehaviorInjection.setBehavior('Delete-PostOperation',
1810
+ (pRequest, pRequestState, fCallback) =>
1811
+ {
1812
+ _HookFired = true;
1813
+ return fCallback();
1814
+ });
1815
+
1816
+ _SuperTest
1817
+ .post('1.0/Book')
1818
+ .send({ Title: 'Delete-Post target' })
1819
+ .end(
1820
+ (pPostErr, pPostRes) =>
1821
+ {
1822
+ const tmpID = JSON.parse(pPostRes.text).IDBook;
1823
+ _SuperTest
1824
+ .delete(`1.0/Book/${tmpID}`)
1825
+ .end(
1826
+ () =>
1827
+ {
1828
+ Expect(_HookFired).to.equal(true);
1829
+ delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Delete-PostOperation'];
1830
+ fDone();
1831
+ }
1832
+ );
1833
+ }
1834
+ );
1835
+ }
1836
+ );
1837
+ test
1838
+ (
1839
+ 'setBehavior: Read-QueryConfiguration runs after filter is applied',
1840
+ function (fDone)
1841
+ {
1842
+ let _SeenCriteria = null;
1843
+ _MeadowEndpoints.controller.BehaviorInjection.setBehavior('Read-QueryConfiguration',
1844
+ (pRequest, pRequestState, fCallback) =>
1845
+ {
1846
+ _SeenCriteria = pRequestState.RecordSearchCriteria;
1847
+ return fCallback();
1848
+ });
1849
+
1850
+ _SuperTest
1851
+ .get('1.0/Book/1')
1852
+ .end(
1853
+ () =>
1854
+ {
1855
+ Expect(_SeenCriteria).to.be.a('string').and.satisfy((pS) => pS.includes('IDBook'));
1856
+ delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Read-QueryConfiguration'];
1857
+ fDone();
1858
+ }
1859
+ );
1860
+ }
1861
+ );
1862
+ test
1863
+ (
1864
+ 'setBehavior: Reads-PostOperation fires after list load',
1865
+ function (fDone)
1866
+ {
1867
+ let _SawRecords = false;
1868
+ _MeadowEndpoints.controller.BehaviorInjection.setBehavior('Reads-PostOperation',
1869
+ (pRequest, pRequestState, fCallback) =>
1870
+ {
1871
+ _SawRecords = Array.isArray(pRequestState.Records) && pRequestState.Records.length > 0;
1872
+ return fCallback();
1873
+ });
1874
+
1875
+ _SuperTest
1876
+ .get('1.0/Books/0/10')
1877
+ .end(
1878
+ () =>
1879
+ {
1880
+ Expect(_SawRecords).to.equal(true);
1881
+ delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Reads-PostOperation'];
1882
+ fDone();
1883
+ }
1884
+ );
1885
+ }
1886
+ );
1887
+ test
1888
+ (
1889
+ 'setBehavior: ReadMax-QueryConfiguration fires with column name',
1890
+ function (fDone)
1891
+ {
1892
+ let _SeenColumn = null;
1893
+ _MeadowEndpoints.controller.BehaviorInjection.setBehavior('ReadMax-QueryConfiguration',
1894
+ (pRequest, pRequestState, fCallback) =>
1895
+ {
1896
+ _SeenColumn = pRequestState.ColumnName;
1897
+ return fCallback();
1898
+ });
1899
+
1900
+ _SuperTest
1901
+ .get('1.0/Book/Max/PublicationYear')
1902
+ .end(
1903
+ () =>
1904
+ {
1905
+ Expect(_SeenColumn).to.equal('PublicationYear');
1906
+ delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['ReadMax-QueryConfiguration'];
1907
+ fDone();
1908
+ }
1909
+ );
1910
+ }
1911
+ );
1912
+ test
1913
+ (
1914
+ 'setBehavior: ReadMax-PostOperation fires after max lookup',
1915
+ function (fDone)
1916
+ {
1917
+ let _HookFired = false;
1918
+ _MeadowEndpoints.controller.BehaviorInjection.setBehavior('ReadMax-PostOperation',
1919
+ (pRequest, pRequestState, fCallback) =>
1920
+ {
1921
+ _HookFired = true;
1922
+ return fCallback();
1923
+ });
1924
+
1925
+ _SuperTest
1926
+ .get('1.0/Book/Max/PublicationYear')
1927
+ .end(
1928
+ () =>
1929
+ {
1930
+ Expect(_HookFired).to.equal(true);
1931
+ delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['ReadMax-PostOperation'];
1932
+ fDone();
1933
+ }
1934
+ );
1935
+ }
1936
+ );
1937
+ test
1938
+ (
1939
+ 'setBehavior: CountBy-QueryConfiguration can modify count-by query',
1940
+ function (fDone)
1941
+ {
1942
+ let _HookFired = false;
1943
+ _MeadowEndpoints.controller.BehaviorInjection.setBehavior('CountBy-QueryConfiguration',
1944
+ (pRequest, pRequestState, fCallback) =>
1945
+ {
1946
+ _HookFired = true;
1947
+ Expect(pRequestState.Query).to.exist;
1948
+ return fCallback();
1949
+ });
1950
+
1951
+ _SuperTest
1952
+ .get('1.0/Books/Count/By/Genre/Thriller')
1953
+ .end(
1954
+ () =>
1955
+ {
1956
+ Expect(_HookFired).to.equal(true);
1957
+ delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['CountBy-QueryConfiguration'];
1958
+ fDone();
1959
+ }
1960
+ );
1961
+ }
1962
+ );
1963
+ test
1964
+ (
1965
+ 'setBehavior: Undelete-PreOperation fires before undelete',
1966
+ function (fDone)
1967
+ {
1968
+ let _HookFired = false;
1969
+ _MeadowEndpoints.controller.BehaviorInjection.setBehavior('Undelete-PreOperation',
1970
+ (pRequest, pRequestState, fCallback) =>
1971
+ {
1972
+ _HookFired = true;
1973
+ return fCallback();
1974
+ });
1975
+
1976
+ // Create, delete, then undelete to hit the hook.
1977
+ _SuperTest
1978
+ .post('1.0/Book')
1979
+ .send({ Title: 'Undelete-Pre target' })
1980
+ .end(
1981
+ (pPostErr, pPostRes) =>
1982
+ {
1983
+ const tmpID = JSON.parse(pPostRes.text).IDBook;
1984
+ _SuperTest
1985
+ .delete(`1.0/Book/${tmpID}`)
1986
+ .end(
1987
+ () =>
1988
+ {
1989
+ _SuperTest
1990
+ .get(`1.0/Book/Undelete/${tmpID}`)
1991
+ .end(
1992
+ () =>
1993
+ {
1994
+ Expect(_HookFired).to.equal(true);
1995
+ delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Undelete-PreOperation'];
1996
+ fDone();
1997
+ }
1998
+ );
1999
+ }
2000
+ );
2001
+ }
2002
+ );
2003
+ }
2004
+ );
2005
+ test
2006
+ (
2007
+ 'setBehavior: Undelete-PostOperation fires after undelete',
2008
+ function (fDone)
2009
+ {
2010
+ let _HookFired = false;
2011
+ _MeadowEndpoints.controller.BehaviorInjection.setBehavior('Undelete-PostOperation',
2012
+ (pRequest, pRequestState, fCallback) =>
2013
+ {
2014
+ _HookFired = true;
2015
+ return fCallback();
2016
+ });
2017
+
2018
+ _SuperTest
2019
+ .post('1.0/Book')
2020
+ .send({ Title: 'Undelete-Post target' })
2021
+ .end(
2022
+ (pPostErr, pPostRes) =>
2023
+ {
2024
+ const tmpID = JSON.parse(pPostRes.text).IDBook;
2025
+ _SuperTest
2026
+ .delete(`1.0/Book/${tmpID}`)
2027
+ .end(
2028
+ () =>
2029
+ {
2030
+ _SuperTest
2031
+ .get(`1.0/Book/Undelete/${tmpID}`)
2032
+ .end(
2033
+ () =>
2034
+ {
2035
+ Expect(_HookFired).to.equal(true);
2036
+ delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Undelete-PostOperation'];
2037
+ fDone();
2038
+ }
2039
+ );
2040
+ }
2041
+ );
2042
+ }
2043
+ );
2044
+ }
2045
+ );
2046
+ test
2047
+ (
2048
+ 'setBehavior: Schema-PreOperation fires before schema render',
2049
+ function (fDone)
2050
+ {
2051
+ let _HookFired = false;
2052
+ _MeadowEndpoints.controller.BehaviorInjection.setBehavior('Schema-PreOperation',
2053
+ (pRequest, pRequestState, fCallback) =>
2054
+ {
2055
+ _HookFired = true;
2056
+ return fCallback();
2057
+ });
2058
+
2059
+ _SuperTest
2060
+ .get('1.0/Book/Schema')
2061
+ .end(
2062
+ () =>
2063
+ {
2064
+ Expect(_HookFired).to.equal(true);
2065
+ delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Schema-PreOperation'];
2066
+ fDone();
2067
+ }
2068
+ );
2069
+ }
2070
+ );
2071
+ test
2072
+ (
2073
+ 'setBehavior: Validate-PreOperation fires before validate',
2074
+ function (fDone)
2075
+ {
2076
+ let _HookFired = false;
2077
+ _MeadowEndpoints.controller.BehaviorInjection.setBehavior('Validate-PreOperation',
2078
+ (pRequest, pRequestState, fCallback) =>
2079
+ {
2080
+ _HookFired = true;
2081
+ return fCallback();
2082
+ });
2083
+
2084
+ _SuperTest
2085
+ .post('1.0/Book/Schema/Validate')
2086
+ .send({ Title: 'Validate target' })
2087
+ .end(
2088
+ () =>
2089
+ {
2090
+ Expect(_HookFired).to.equal(true);
2091
+ delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Validate-PreOperation'];
2092
+ fDone();
2093
+ }
2094
+ );
2095
+ }
2096
+ );
2097
+ test
2098
+ (
2099
+ 'setBehavior: Validate-PostOperation fires after validate',
2100
+ function (fDone)
2101
+ {
2102
+ let _HookFired = false;
2103
+ _MeadowEndpoints.controller.BehaviorInjection.setBehavior('Validate-PostOperation',
2104
+ (pRequest, pRequestState, fCallback) =>
2105
+ {
2106
+ _HookFired = true;
2107
+ return fCallback();
2108
+ });
2109
+
2110
+ _SuperTest
2111
+ .post('1.0/Book/Schema/Validate')
2112
+ .send({ Title: 'Validate target 2' })
2113
+ .end(
2114
+ () =>
2115
+ {
2116
+ Expect(_HookFired).to.equal(true);
2117
+ delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Validate-PostOperation'];
2118
+ fDone();
2119
+ }
2120
+ );
2121
+ }
2122
+ );
2123
+ test
2124
+ (
2125
+ 'setBehavior: New-PreOperation fires before empty record render',
2126
+ function (fDone)
2127
+ {
2128
+ let _HookFired = false;
2129
+ _MeadowEndpoints.controller.BehaviorInjection.setBehavior('New-PreOperation',
2130
+ (pRequest, pRequestState, fCallback) =>
2131
+ {
2132
+ _HookFired = true;
2133
+ return fCallback();
2134
+ });
2135
+
2136
+ _SuperTest
2137
+ .get('1.0/Book/Schema/New')
2138
+ .end(
2139
+ () =>
2140
+ {
2141
+ Expect(_HookFired).to.equal(true);
2142
+ delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['New-PreOperation'];
2143
+ fDone();
2144
+ }
2145
+ );
2146
+ }
2147
+ );
1372
2148
  }
1373
2149
  );
1374
2150