@rentman/rm-core 0.0.0-RM4-44763

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 (201) hide show
  1. package/dist/rm-core.js +2 -0
  2. package/dist/rm-core.js.map +1 -0
  3. package/dist/types/src/classes/ApiFormatter.d.ts +66 -0
  4. package/dist/types/src/classes/ApiRequestService.d.ts +18 -0
  5. package/dist/types/src/classes/ApiResponseProcessor.d.ts +31 -0
  6. package/dist/types/src/classes/BusinessLogicManager/AantalBusinessLogicRuleBase.d.ts +36 -0
  7. package/dist/types/src/classes/BusinessLogicManager/AantaltotaalBusinessLogicRuleBase.d.ts +60 -0
  8. package/dist/types/src/classes/BusinessLogicManager/Afspraak/AfspraakRecureindBusinessLogicRule.d.ts +5 -0
  9. package/dist/types/src/classes/BusinessLogicManager/Beschikbaarheid/BeschikbaarheidRecureindBusinessLogicRule.d.ts +5 -0
  10. package/dist/types/src/classes/BusinessLogicManager/BusinessLogicManager.d.ts +66 -0
  11. package/dist/types/src/classes/BusinessLogicManager/BusinessLogicRule.d.ts +81 -0
  12. package/dist/types/src/classes/BusinessLogicManager/BusinessLogicRuleApplyContext.d.ts +32 -0
  13. package/dist/types/src/classes/BusinessLogicManager/BusinessLogicRuleConditionContext.d.ts +41 -0
  14. package/dist/types/src/classes/BusinessLogicManager/BusinessLogicRuleContextBase.d.ts +58 -0
  15. package/dist/types/src/classes/BusinessLogicManager/Contact/ContactAddressBusinessLogicRule.d.ts +22 -0
  16. package/dist/types/src/classes/BusinessLogicManager/Customfield/CustomFieldLinkedItemTypeBusinessLogicRule.d.ts +18 -0
  17. package/dist/types/src/classes/BusinessLogicManager/Customfield/CustomFieldTypeBusinessLogicRule.d.ts +18 -0
  18. package/dist/types/src/classes/BusinessLogicManager/DefaultContactPersonUpdateBusinessLogicRule.d.ts +30 -0
  19. package/dist/types/src/classes/BusinessLogicManager/Documents/DocumentTemplateBusinessLogicRule.d.ts +20 -0
  20. package/dist/types/src/classes/BusinessLogicManager/Exemplaar/ExemplaarAanschafdatumBusinessLogicRule.d.ts +14 -0
  21. package/dist/types/src/classes/BusinessLogicManager/Exemplaar/ExemplaarBarcodeDeleteBusinessLogicRule.d.ts +14 -0
  22. package/dist/types/src/classes/BusinessLogicManager/Factuur/FactuurBetalingsconditieBusinessLogicRule.d.ts +21 -0
  23. package/dist/types/src/classes/BusinessLogicManager/Factuur/FactuurDatumBusinessLogicRule.d.ts +23 -0
  24. package/dist/types/src/classes/BusinessLogicManager/Factuur/FactuurNumberseriesBusinessLogicRule.d.ts +14 -0
  25. package/dist/types/src/classes/BusinessLogicManager/Files/FilesNameExtensionBusinessLogicRule.d.ts +20 -0
  26. package/dist/types/src/classes/BusinessLogicManager/Functie/FunctieNaaminternBusinessLogicRule.d.ts +18 -0
  27. package/dist/types/src/classes/BusinessLogicManager/Functie/FunctieRecureindBusinessLogicRule.d.ts +5 -0
  28. package/dist/types/src/classes/BusinessLogicManager/Functie/FunctieTwowayBusinessLogicRule.d.ts +14 -0
  29. package/dist/types/src/classes/BusinessLogicManager/Functiegroep/FunctiegroepSubprojectBusinessLogicRule.d.ts +17 -0
  30. package/dist/types/src/classes/BusinessLogicManager/Inhuurmateriaal/InhuurmateriaalAantalBusinessLogicRule.d.ts +4 -0
  31. package/dist/types/src/classes/BusinessLogicManager/Inhuurmateriaal/InhuurmateriaalAantaltotaalBusinessLogicRule.d.ts +9 -0
  32. package/dist/types/src/classes/BusinessLogicManager/Materiaal/MateriaalBulkToSerialBusinessLogicRule.d.ts +17 -0
  33. package/dist/types/src/classes/BusinessLogicManager/Materiaal/MateriaalIsCombinationBusinessLogicRule.d.ts +20 -0
  34. package/dist/types/src/classes/BusinessLogicManager/Materiaal/MateriaalIsPhysicalCombinationBulkBusinessLogicRule.d.ts +19 -0
  35. package/dist/types/src/classes/BusinessLogicManager/Materiaal/MateriaalSerialToBulkBusinessLogicRule.d.ts +16 -0
  36. package/dist/types/src/classes/BusinessLogicManager/Materiaal/MateriaalToPhysicalBusinessLogicRule.d.ts +18 -0
  37. package/dist/types/src/classes/BusinessLogicManager/Materiaal/MateriaalToVirtualBusinessLogicRule.d.ts +22 -0
  38. package/dist/types/src/classes/BusinessLogicManager/Materiaal/MateriaalTypePropertiesBusinessLogicRule.d.ts +19 -0
  39. package/dist/types/src/classes/BusinessLogicManager/Materiaal/MateriaalVerhuurBusinessLogicRule.d.ts +19 -0
  40. package/dist/types/src/classes/BusinessLogicManager/Materiaal/SurfaceArticleSizeBusinessLogicRule.d.ts +23 -0
  41. package/dist/types/src/classes/BusinessLogicManager/MateriaalCatFunctieFunctiegroep/LinkedTimeItemBusinessLogicRuleBase.d.ts +46 -0
  42. package/dist/types/src/classes/BusinessLogicManager/MateriaalCatFunctieFunctiegroep/LinkedTimeItemDurationBusinessLogicRule.d.ts +17 -0
  43. package/dist/types/src/classes/BusinessLogicManager/MateriaalCatFunctieFunctiegroep/LinkedTimeItemMateriaalCatBusinessLogicRule.d.ts +25 -0
  44. package/dist/types/src/classes/BusinessLogicManager/MateriaalCatFunctieFunctiegroep/LinkedTimeItemSubprojectBusinessLogicRule.d.ts +48 -0
  45. package/dist/types/src/classes/BusinessLogicManager/MateriaalCatFunctieFunctiegroep/LinkedTimeItemTimeSchemeBusinessLogicRule.d.ts +27 -0
  46. package/dist/types/src/classes/BusinessLogicManager/MateriaalCatFunctieFunctiegroep/LinkedTimeItemTimeSchemeStartBusinessLogicRule.d.ts +18 -0
  47. package/dist/types/src/classes/BusinessLogicManager/MateriaalCatFunctieFunctiegroep/LinkedTimeItemTimeValueStartBusinessLogicRule.d.ts +20 -0
  48. package/dist/types/src/classes/BusinessLogicManager/MateriaalCatFunctieFunctiegroep/TimeColumnUtil.d.ts +132 -0
  49. package/dist/types/src/classes/BusinessLogicManager/OfferteContract/OfferteContractDatumBusinessLogicRule.d.ts +21 -0
  50. package/dist/types/src/classes/BusinessLogicManager/PlanningPersoneelTransport/PlanningPersoneelTransportBusinessLogicRule.d.ts +24 -0
  51. package/dist/types/src/classes/BusinessLogicManager/Planningmateriaal/PlanningmateriaalAantalBusinessLogicRule.d.ts +4 -0
  52. package/dist/types/src/classes/BusinessLogicManager/Planningmateriaal/PlanningmateriaalAantaltotaalBusinessLogicRule.d.ts +9 -0
  53. package/dist/types/src/classes/BusinessLogicManager/Planningmateriaal/PlanningmateriaalOptieBusinessLogicRule.d.ts +26 -0
  54. package/dist/types/src/classes/BusinessLogicManager/Planningmateriaal/PlanningmateriaalParentBusinessLogicRule.d.ts +17 -0
  55. package/dist/types/src/classes/BusinessLogicManager/Planningmateriaal/PlanningmateriaalStaysAtLocationBusinessLogicRule.d.ts +32 -0
  56. package/dist/types/src/classes/BusinessLogicManager/Project/ProjectClientChangedBusinessLogicRule.d.ts +31 -0
  57. package/dist/types/src/classes/BusinessLogicManager/Project/ProjectContactProjectNoteBusinessLogicRule.d.ts +25 -0
  58. package/dist/types/src/classes/BusinessLogicManager/Project/ProjectOneSubLocationAlignBusinessRule.d.ts +26 -0
  59. package/dist/types/src/classes/BusinessLogicManager/ProjectSubproject/ProjectSubprojectDefaultTimeBusinessLogicRule.d.ts +26 -0
  60. package/dist/types/src/classes/BusinessLogicManager/PurchaseOrder/PurchaseOrderApprovalStatusBusinessLogicRule.d.ts +19 -0
  61. package/dist/types/src/classes/BusinessLogicManager/PurchaseOrder/PurchaseOrderOwnerBusinessLogicRule.d.ts +16 -0
  62. package/dist/types/src/classes/BusinessLogicManager/Rate/RateUpdatedBusinessLogicRule.d.ts +14 -0
  63. package/dist/types/src/classes/BusinessLogicManager/RecurrentItem/RecurrentItemRecureindBusinessLogicRule.d.ts +28 -0
  64. package/dist/types/src/classes/BusinessLogicManager/Reparatie/ReparatieExemplaarAantalBusinessLogicRule.d.ts +14 -0
  65. package/dist/types/src/classes/BusinessLogicManager/Reparatie/ReparatieLostItemExemplaarLocationBusinessLogicRule.d.ts +21 -0
  66. package/dist/types/src/classes/BusinessLogicManager/Rol/RolEditOwnDataBusinessLogicRule.d.ts +20 -0
  67. package/dist/types/src/classes/BusinessLogicManager/Rol/RolFileAccessBusinessLogicRule.d.ts +19 -0
  68. package/dist/types/src/classes/BusinessLogicManager/Rol/RolPersoneelsplannerToegangBusinessLogicRule.d.ts +20 -0
  69. package/dist/types/src/classes/BusinessLogicManager/Rol/RolProjectenBewerkenBusinessLogicRule.d.ts +20 -0
  70. package/dist/types/src/classes/BusinessLogicManager/Rol/RolProjectenToegangBusinessLogicRule.d.ts +21 -0
  71. package/dist/types/src/classes/BusinessLogicManager/Rol/RolPurchaseOrderAttachPlanningBusinessLogicRule.d.ts +19 -0
  72. package/dist/types/src/classes/BusinessLogicManager/Rol/RolVisibilityFinancialsBusinessLogicRule.d.ts +35 -0
  73. package/dist/types/src/classes/BusinessLogicManager/Rol/RolWarehosueTrackingLogAccessBusinessLogicRule.d.ts +20 -0
  74. package/dist/types/src/classes/BusinessLogicManager/Setinhoud/SetinhoudCreateFixedBusinessLogicRule.d.ts +21 -0
  75. package/dist/types/src/classes/BusinessLogicManager/Setinhoud/SetinhoudUpdateFixedBusinessLogicRule.d.ts +26 -0
  76. package/dist/types/src/classes/BusinessLogicManager/Subproject/SubprojectInPlanningBusinessLogicRule.d.ts +14 -0
  77. package/dist/types/src/classes/BusinessLogicManager/Subproject/SubprojectOneSubLocationAlignBusinessRule.d.ts +27 -0
  78. package/dist/types/src/classes/BusinessLogicManager/Subproject/SubprojectOneSubNameAlignBusinessRule.d.ts +22 -0
  79. package/dist/types/src/classes/BusinessLogicManager/Tijd/TijdNameChangedBusinessLogicRule.d.ts +21 -0
  80. package/dist/types/src/classes/BusinessLogicManager/Tijd/TijdSubprojectChangedBusinessLogicRule.d.ts +17 -0
  81. package/dist/types/src/classes/BusinessLogicManager/Uren/HoursTypeBusinessLogicRuleBase.d.ts +10 -0
  82. package/dist/types/src/classes/BusinessLogicManager/Uren/UrenCalculatedDurationBusinessLogicRule.d.ts +13 -0
  83. package/dist/types/src/classes/BusinessLogicManager/Uren/UrenCanHaveActivitiesBusinessLogicRule.d.ts +13 -0
  84. package/dist/types/src/classes/BusinessLogicManager/businessLogicRule.decorator.d.ts +13 -0
  85. package/dist/types/src/classes/BusinessLogicManager/registeredBusinessLogicRules.d.ts +66 -0
  86. package/dist/types/src/classes/ChangesCompilation.d.ts +26 -0
  87. package/dist/types/src/classes/ChangesDelta.d.ts +81 -0
  88. package/dist/types/src/classes/ChangesDeltaBase.d.ts +85 -0
  89. package/dist/types/src/classes/ChangesProcessor.d.ts +35 -0
  90. package/dist/types/src/classes/ChildChangesDelta.d.ts +38 -0
  91. package/dist/types/src/classes/ColumnCache.d.ts +22 -0
  92. package/dist/types/src/classes/ColumnExpansion.d.ts +18 -0
  93. package/dist/types/src/classes/ColumnHandler.d.ts +16 -0
  94. package/dist/types/src/classes/ColumnInfo.d.ts +16 -0
  95. package/dist/types/src/classes/ColumnSet.d.ts +79 -0
  96. package/dist/types/src/classes/ColumnUtil.d.ts +97 -0
  97. package/dist/types/src/classes/ConversionMapService.d.ts +23 -0
  98. package/dist/types/src/classes/CreateRequest.d.ts +16 -0
  99. package/dist/types/src/classes/CreatedChangesDelta.d.ts +22 -0
  100. package/dist/types/src/classes/ItemCache.d.ts +26 -0
  101. package/dist/types/src/classes/ItemCreateService.d.ts +14 -0
  102. package/dist/types/src/classes/ItemEntryService.d.ts +29 -0
  103. package/dist/types/src/classes/KeyService.d.ts +10 -0
  104. package/dist/types/src/classes/LockService.d.ts +28 -0
  105. package/dist/types/src/classes/ModuleChangesCompilation.d.ts +20 -0
  106. package/dist/types/src/classes/ParentChangesDelta.d.ts +42 -0
  107. package/dist/types/src/classes/QueryColumnExtractor.d.ts +16 -0
  108. package/dist/types/src/classes/QueryContainsLocalIdParser.d.ts +14 -0
  109. package/dist/types/src/classes/QueryParser.d.ts +18 -0
  110. package/dist/types/src/classes/QueryParserBase.d.ts +32 -0
  111. package/dist/types/src/classes/QueryParserIdUpdater.d.ts +16 -0
  112. package/dist/types/src/classes/QueryService.d.ts +10 -0
  113. package/dist/types/src/classes/RequestBuffer/RequestBuffer.d.ts +13 -0
  114. package/dist/types/src/classes/RequestBuffer/RequestBufferBase.d.ts +37 -0
  115. package/dist/types/src/classes/RequestBuffer/RequestBufferManager.d.ts +24 -0
  116. package/dist/types/src/classes/RequestBuffer/SingleQueryRequestBuffer.d.ts +18 -0
  117. package/dist/types/src/classes/RequestColumnExpansion.d.ts +11 -0
  118. package/dist/types/src/classes/RequestColumnsOperationsCache.d.ts +45 -0
  119. package/dist/types/src/classes/SocketMessageHandler.d.ts +28 -0
  120. package/dist/types/src/classes/TemplateCache.d.ts +61 -0
  121. package/dist/types/src/classes/Util.d.ts +36 -0
  122. package/dist/types/src/classes/cache/AbstractCache.d.ts +86 -0
  123. package/dist/types/src/classes/cache/CachedQueryHandlerBase.d.ts +145 -0
  124. package/dist/types/src/classes/cache/ItemHandlerBase.d.ts +97 -0
  125. package/dist/types/src/classes/cache/ItemMatcherBase.d.ts +90 -0
  126. package/dist/types/src/classes/cache/server/ServerCache.d.ts +83 -0
  127. package/dist/types/src/classes/cache/server/ServerCachedQueryHandler.d.ts +29 -0
  128. package/dist/types/src/classes/cache/server/ServerItemHandler.d.ts +35 -0
  129. package/dist/types/src/classes/cache/transaction/TransactionCache.d.ts +342 -0
  130. package/dist/types/src/classes/cache/transaction/TransactionCachedQueryHandler.d.ts +111 -0
  131. package/dist/types/src/classes/cache/transaction/TransactionEventHandler.d.ts +17 -0
  132. package/dist/types/src/classes/cache/transaction/TransactionItemHandler.d.ts +121 -0
  133. package/dist/types/src/classes/cache/transaction/TransactionValidator.d.ts +25 -0
  134. package/dist/types/src/classes/cache/transaction/TransactionValidatorBase.d.ts +19 -0
  135. package/dist/types/src/classes/cache/transaction/TransactionValidatorWithDependencies.d.ts +15 -0
  136. package/dist/types/src/classes/changes/CollectionItemChangesListenerContext.d.ts +22 -0
  137. package/dist/types/src/classes/changes/ItemChangesListenerContext.d.ts +7 -0
  138. package/dist/types/src/classes/changes/ItemChangesListenerContextBase.d.ts +44 -0
  139. package/dist/types/src/classes/matcher/CompatorQueryNode.d.ts +24 -0
  140. package/dist/types/src/classes/matcher/CustomQueryNode.d.ts +8 -0
  141. package/dist/types/src/classes/matcher/GraphQueryParser.d.ts +34 -0
  142. package/dist/types/src/classes/matcher/IsComparatorQueryNode.d.ts +13 -0
  143. package/dist/types/src/classes/matcher/LinkedToQueryNode.d.ts +9 -0
  144. package/dist/types/src/classes/matcher/NonMatchableQueryNode.d.ts +9 -0
  145. package/dist/types/src/classes/matcher/NotIsComparatorQueryNode.d.ts +14 -0
  146. package/dist/types/src/classes/matcher/QueryNode.d.ts +49 -0
  147. package/dist/types/src/classes/matcher/RootQueryNode.d.ts +14 -0
  148. package/dist/types/src/classes/matcher/SearchQueryNode.d.ts +8 -0
  149. package/dist/types/src/classes/matcher/SubQueryNode.d.ts +8 -0
  150. package/dist/types/src/classes/matcher/ValueTransformers.d.ts +41 -0
  151. package/dist/types/src/classes/matcher/ValuelessEdgeQueryNode.d.ts +11 -0
  152. package/dist/types/src/classes/matcher/greater-smaller-than-comparator-query.node.d.ts +25 -0
  153. package/dist/types/src/constants.d.ts +2 -0
  154. package/dist/types/src/core.d.ts +63 -0
  155. package/dist/types/src/exceptions/CriticalBusinessLogicRuleException.d.ts +4 -0
  156. package/dist/types/src/exceptions/ItemAlreadyExistsException.d.ts +4 -0
  157. package/dist/types/src/exceptions/ItemLockedException.d.ts +2 -0
  158. package/dist/types/src/exceptions/ItemNotFoundException.d.ts +5 -0
  159. package/dist/types/src/exceptions/MissingColumnException.d.ts +6 -0
  160. package/dist/types/src/exceptions/SavingInProgressException.d.ts +2 -0
  161. package/dist/types/src/exceptions/TransactionPendingException.d.ts +2 -0
  162. package/dist/types/src/factories/ApiResponseProcessorFactory.d.ts +5 -0
  163. package/dist/types/src/factories/ChangesCompilationFactory.d.ts +5 -0
  164. package/dist/types/src/factories/ChangesDeltaFactory.d.ts +13 -0
  165. package/dist/types/src/factories/CollectionResourceFactory.d.ts +20 -0
  166. package/dist/types/src/factories/ColumnExpansionFactory.d.ts +7 -0
  167. package/dist/types/src/factories/ColumnInfoFactory.d.ts +7 -0
  168. package/dist/types/src/factories/ColumnSetFactory.d.ts +15 -0
  169. package/dist/types/src/factories/GraphQueryParserFactory.d.ts +10 -0
  170. package/dist/types/src/factories/ItemCacheFactory.d.ts +7 -0
  171. package/dist/types/src/factories/ItemResourceFactory.d.ts +7 -0
  172. package/dist/types/src/factories/ModuleChangesCompilationFactory.d.ts +6 -0
  173. package/dist/types/src/factories/RequestColumnExpansionFactory.d.ts +4 -0
  174. package/dist/types/src/factories/RequestColumnsOperationsCacheFactory.d.ts +7 -0
  175. package/dist/types/src/factories/TransactionCacheFactory.d.ts +12 -0
  176. package/dist/types/src/index.d.ts +11 -0
  177. package/dist/types/src/interfaces/AbstractCacheDependencyInterface.d.ts +46 -0
  178. package/dist/types/src/interfaces/ApiRequestServiceInterface.d.ts +14 -0
  179. package/dist/types/src/interfaces/ErrorHandlerInterface.d.ts +6 -0
  180. package/dist/types/src/interfaces/LinkTreeServiceInterface.d.ts +6 -0
  181. package/dist/types/src/interfaces/ServerCacheDependencyInterface.d.ts +6 -0
  182. package/dist/types/src/interfaces/SocketMessageInterface.d.ts +3 -0
  183. package/dist/types/src/interfaces/TransactionCollectionHandlerDependencyInterface.d.ts +15 -0
  184. package/dist/types/src/interfaces/TransactionItemHandlerDependencyInterface.d.ts +16 -0
  185. package/dist/types/src/internal.d.ts +110 -0
  186. package/dist/types/src/models/CachedQueryItem.d.ts +33 -0
  187. package/dist/types/src/models/CollectionEntry.d.ts +16 -0
  188. package/dist/types/src/models/CollectionOptions.d.ts +111 -0
  189. package/dist/types/src/models/CollectionResource.d.ts +175 -0
  190. package/dist/types/src/models/ItemEntry.d.ts +23 -0
  191. package/dist/types/src/models/ItemOptions.d.ts +25 -0
  192. package/dist/types/src/models/ItemResource.d.ts +135 -0
  193. package/dist/types/src/models/LimitedCollectionResource.d.ts +26 -0
  194. package/dist/types/src/models/OrderedCollectionResource.d.ts +19 -0
  195. package/dist/types/src/models/Template.d.ts +17 -0
  196. package/dist/types/src/services/rm-holidays.service.d.ts +31 -0
  197. package/dist/types/src/types/AggregatedChangesListener.d.ts +99 -0
  198. package/dist/types/src/types/ApiQuery.d.ts +95 -0
  199. package/dist/types/src/types/ItemTypesCollection.d.ts +416 -0
  200. package/package.json +56 -0
  201. package/readme.md +42 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rm-core.js","mappings":"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","sources":["webpack://RmCore/webpack/universalModuleDefinition","webpack://RmCore/external umd \"@angular/core\"","webpack://RmCore/external umd \"@rentman/backend-types\"","webpack://RmCore/external umd \"moment\"","webpack://RmCore/webpack/bootstrap","webpack://RmCore/webpack/runtime/compat get default export","webpack://RmCore/webpack/runtime/define property getters","webpack://RmCore/webpack/runtime/hasOwnProperty shorthand","webpack://RmCore/webpack/runtime/make namespace object","webpack://RmCore/./src/constants.ts","webpack://RmCore/./src/types/ItemTypesCollection.ts","webpack://RmCore/./src/models/ItemEntry.ts","webpack://RmCore/./src/models/ItemResource.ts","webpack://RmCore/./src/models/CachedQueryItem.ts","webpack://RmCore/./src/models/CollectionEntry.ts","webpack://RmCore/./src/exceptions/ItemNotFoundException.ts","webpack://RmCore/./src/models/CollectionResource.ts","webpack://RmCore/./src/models/OrderedCollectionResource.ts","webpack://RmCore/./src/models/LimitedCollectionResource.ts","webpack://RmCore/./src/models/Template.ts","webpack://RmCore/./src/classes/Util.ts","webpack://RmCore/./src/classes/ApiFormatter.ts","webpack://RmCore/./src/classes/ApiRequestService.ts","webpack://RmCore/./src/classes/ApiResponseProcessor.ts","webpack://RmCore/./src/classes/ChangesCompilation.ts","webpack://RmCore/./src/classes/ChangesProcessor.ts","webpack://RmCore/./src/classes/ColumnCache.ts","webpack://RmCore/./src/classes/ColumnExpansion.ts","webpack://RmCore/./src/classes/ColumnHandler.ts","webpack://RmCore/./src/classes/ColumnInfo.ts","webpack://RmCore/./src/classes/ColumnSet.ts","webpack://RmCore/./src/classes/RequestColumnsOperationsCache.ts","webpack://RmCore/./src/classes/ColumnUtil.ts","webpack://RmCore/./src/classes/ConversionMapService.ts","webpack://RmCore/./src/classes/CreateRequest.ts","webpack://RmCore/./src/classes/ItemCache.ts","webpack://RmCore/./src/classes/ItemEntryService.ts","webpack://RmCore/./src/classes/KeyService.ts","webpack://RmCore/./src/classes/cache/transaction/TransactionEventHandler.ts","webpack://RmCore/./src/classes/LockService.ts","webpack://RmCore/./src/classes/ModuleChangesCompilation.ts","webpack://RmCore/./src/classes/QueryParserBase.ts","webpack://RmCore/./src/classes/matcher/QueryNode.ts","webpack://RmCore/./src/classes/matcher/ValuelessEdgeQueryNode.ts","webpack://RmCore/./src/classes/matcher/NonMatchableQueryNode.ts","webpack://RmCore/./src/classes/matcher/CustomQueryNode.ts","webpack://RmCore/./src/classes/matcher/ValueTransformers.ts","webpack://RmCore/./src/classes/matcher/CompatorQueryNode.ts","webpack://RmCore/./src/classes/matcher/greater-smaller-than-comparator-query.node.ts","webpack://RmCore/./src/classes/matcher/IsComparatorQueryNode.ts","webpack://RmCore/./src/classes/matcher/LinkedToQueryNode.ts","webpack://RmCore/./src/classes/matcher/NotIsComparatorQueryNode.ts","webpack://RmCore/./src/classes/matcher/RootQueryNode.ts","webpack://RmCore/./src/classes/matcher/SearchQueryNode.ts","webpack://RmCore/./src/classes/matcher/SubQueryNode.ts","webpack://RmCore/./src/classes/matcher/GraphQueryParser.ts","webpack://RmCore/./src/classes/QueryColumnExtractor.ts","webpack://RmCore/./src/classes/QueryContainsLocalIdParser.ts","webpack://RmCore/./src/classes/QueryParser.ts","webpack://RmCore/./src/classes/QueryParserIdUpdater.ts","webpack://RmCore/./src/classes/QueryService.ts","webpack://RmCore/./src/classes/RequestColumnExpansion.ts","webpack://RmCore/./src/classes/SocketMessageHandler.ts","webpack://RmCore/./src/classes/cache/AbstractCache.ts","webpack://RmCore/./src/classes/cache/server/ServerCache.ts","webpack://RmCore/./src/classes/cache/ItemMatcherBase.ts","webpack://RmCore/./src/classes/cache/ItemHandlerBase.ts","webpack://RmCore/./src/classes/cache/server/ServerItemHandler.ts","webpack://RmCore/./src/classes/cache/CachedQueryHandlerBase.ts","webpack://RmCore/./src/classes/cache/server/ServerCachedQueryHandler.ts","webpack://RmCore/./src/exceptions/TransactionPendingException.ts","webpack://RmCore/./src/classes/cache/transaction/TransactionCache.ts","webpack://RmCore/./src/classes/cache/transaction/TransactionItemHandler.ts","webpack://RmCore/./src/classes/cache/transaction/TransactionCachedQueryHandler.ts","webpack://RmCore/./src/classes/cache/transaction/TransactionValidatorBase.ts","webpack://RmCore/./src/classes/cache/transaction/TransactionValidator.ts","webpack://RmCore/./src/classes/cache/transaction/TransactionValidatorWithDependencies.ts","webpack://RmCore/./src/classes/ChangesDeltaBase.ts","webpack://RmCore/./src/exceptions/MissingColumnException.ts","webpack://RmCore/./src/classes/ChangesDelta.ts","webpack://RmCore/./src/classes/ChildChangesDelta.ts","webpack://RmCore/./src/classes/ParentChangesDelta.ts","webpack://RmCore/./src/classes/RequestBuffer/RequestBufferBase.ts","webpack://RmCore/./src/classes/RequestBuffer/RequestBuffer.ts","webpack://RmCore/./src/classes/RequestBuffer/SingleQueryRequestBuffer.ts","webpack://RmCore/./src/classes/RequestBuffer/RequestBufferManager.ts","webpack://RmCore/./src/classes/ItemCreateService.ts","webpack://RmCore/./src/classes/CreatedChangesDelta.ts","webpack://RmCore/./src/classes/TemplateCache.ts","webpack://RmCore/./src/classes/changes/ItemChangesListenerContextBase.ts","webpack://RmCore/./src/classes/changes/ItemChangesListenerContext.ts","webpack://RmCore/./src/classes/changes/CollectionItemChangesListenerContext.ts","webpack://RmCore/./src/classes/BusinessLogicManager/BusinessLogicRuleContextBase.ts","webpack://RmCore/./src/classes/BusinessLogicManager/BusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/BusinessLogicRuleConditionContext.ts","webpack://RmCore/./src/classes/BusinessLogicManager/BusinessLogicRuleApplyContext.ts","webpack://RmCore/./src/classes/BusinessLogicManager/businessLogicRule.decorator.ts","webpack://RmCore/./node_modules/tslib/tslib.es6.js","webpack://RmCore/./src/classes/BusinessLogicManager/RecurrentItem/RecurrentItemRecureindBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Afspraak/AfspraakRecureindBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Beschikbaarheid/BeschikbaarheidRecureindBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Contact/ContactAddressBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Customfield/CustomFieldLinkedItemTypeBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Customfield/CustomFieldTypeBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/DefaultContactPersonUpdateBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Documents/DocumentTemplateBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Exemplaar/ExemplaarAanschafdatumBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Exemplaar/ExemplaarBarcodeDeleteBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Factuur/FactuurBetalingsconditieBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Factuur/FactuurDatumBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Factuur/FactuurNumberseriesBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Files/FilesNameExtensionBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Functie/FunctieNaaminternBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Functie/FunctieRecureindBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Functie/FunctieTwowayBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Functiegroep/FunctiegroepSubprojectBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/AantalBusinessLogicRuleBase.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Inhuurmateriaal/InhuurmateriaalAantalBusinessLogicRule.ts","webpack://RmCore/./src/exceptions/CriticalBusinessLogicRuleException.ts","webpack://RmCore/./src/classes/BusinessLogicManager/AantaltotaalBusinessLogicRuleBase.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Inhuurmateriaal/InhuurmateriaalAantaltotaalBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Materiaal/MateriaalBulkToSerialBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Materiaal/MateriaalIsCombinationBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Materiaal/MateriaalIsPhysicalCombinationBulkBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Materiaal/MateriaalSerialToBulkBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Materiaal/MateriaalToPhysicalBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Materiaal/MateriaalToVirtualBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Materiaal/MateriaalTypePropertiesBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Materiaal/MateriaalVerhuurBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Materiaal/SurfaceArticleSizeBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/MateriaalCatFunctieFunctiegroep/TimeColumnUtil.ts","webpack://RmCore/./src/classes/BusinessLogicManager/MateriaalCatFunctieFunctiegroep/LinkedTimeItemBusinessLogicRuleBase.ts","webpack://RmCore/./src/classes/BusinessLogicManager/MateriaalCatFunctieFunctiegroep/LinkedTimeItemDurationBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/MateriaalCatFunctieFunctiegroep/LinkedTimeItemMateriaalCatBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/MateriaalCatFunctieFunctiegroep/LinkedTimeItemSubprojectBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/MateriaalCatFunctieFunctiegroep/LinkedTimeItemTimeSchemeBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/MateriaalCatFunctieFunctiegroep/LinkedTimeItemTimeSchemeStartBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/MateriaalCatFunctieFunctiegroep/LinkedTimeItemTimeValueStartBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/OfferteContract/OfferteContractDatumBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Planningmateriaal/PlanningmateriaalAantalBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Planningmateriaal/PlanningmateriaalAantaltotaalBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Planningmateriaal/PlanningmateriaalOptieBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Planningmateriaal/PlanningmateriaalParentBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Planningmateriaal/PlanningmateriaalStaysAtLocationBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/PlanningPersoneelTransport/PlanningPersoneelTransportBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Project/ProjectClientChangedBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Project/ProjectContactProjectNoteBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Project/ProjectOneSubLocationAlignBusinessRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/ProjectSubproject/ProjectSubprojectDefaultTimeBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/PurchaseOrder/PurchaseOrderApprovalStatusBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/PurchaseOrder/PurchaseOrderOwnerBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Rate/RateUpdatedBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Reparatie/ReparatieExemplaarAantalBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Reparatie/ReparatieLostItemExemplaarLocationBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Rol/RolEditOwnDataBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Rol/RolFileAccessBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Rol/RolPersoneelsplannerToegangBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Rol/RolProjectenBewerkenBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Rol/RolProjectenToegangBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Rol/RolPurchaseOrderAttachPlanningBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Rol/RolVisibilityFinancialsBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Rol/RolWarehosueTrackingLogAccessBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Setinhoud/SetinhoudCreateFixedBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Setinhoud/SetinhoudUpdateFixedBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Subproject/SubprojectInPlanningBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Subproject/SubprojectOneSubLocationAlignBusinessRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Subproject/SubprojectOneSubNameAlignBusinessRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Tijd/TijdNameChangedBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/Tijd/TijdSubprojectChangedBusinessLogicRule.ts","webpack://RmCore/./src/classes/BusinessLogicManager/registeredBusinessLogicRules.ts","webpack://RmCore/./src/classes/BusinessLogicManager/BusinessLogicManager.ts","webpack://RmCore/./src/factories/ApiResponseProcessorFactory.ts","webpack://RmCore/./src/factories/ChangesCompilationFactory.ts","webpack://RmCore/./src/factories/CollectionResourceFactory.ts","webpack://RmCore/./src/factories/ColumnExpansionFactory.ts","webpack://RmCore/./src/factories/ColumnInfoFactory.ts","webpack://RmCore/./src/factories/ColumnSetFactory.ts","webpack://RmCore/./src/factories/RequestColumnsOperationsCacheFactory.ts","webpack://RmCore/./src/factories/ItemCacheFactory.ts","webpack://RmCore/./src/factories/ItemResourceFactory.ts","webpack://RmCore/./src/factories/TransactionCacheFactory.ts","webpack://RmCore/./src/factories/ModuleChangesCompilationFactory.ts","webpack://RmCore/./src/factories/RequestColumnExpansionFactory.ts","webpack://RmCore/./src/factories/ChangesDeltaFactory.ts","webpack://RmCore/./src/exceptions/ItemAlreadyExistsException.ts","webpack://RmCore/./src/exceptions/ItemLockedException.ts","webpack://RmCore/./src/exceptions/SavingInProgressException.ts","webpack://RmCore/./src/factories/GraphQueryParserFactory.ts","webpack://RmCore/./src/core.ts","webpack://RmCore/./src/services/rm-holidays.service.ts"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"@rentman/backend-types\"), require(\"@angular/core\"), require(\"moment\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([\"@rentman/backend-types\", \"@angular/core\", \"moment\"], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"RmCore\"] = factory(require(\"@rentman/backend-types\"), require(\"@angular/core\"), require(\"moment\"));\n\telse\n\t\troot[\"RmCore\"] = factory(root[\"@rentman/backend-types\"], root[\"@angular/core\"], root[\"moment\"]);\n})(self, (__WEBPACK_EXTERNAL_MODULE__174__, __WEBPACK_EXTERNAL_MODULE__860__, __WEBPACK_EXTERNAL_MODULE__416__) => {\nreturn ","module.exports = __WEBPACK_EXTERNAL_MODULE__860__;","module.exports = __WEBPACK_EXTERNAL_MODULE__174__;","module.exports = __WEBPACK_EXTERNAL_MODULE__416__;","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","export const ALL_PERMISSIONS = 7;\n\nexport const COLUMN_SEPERATOR = '>';\n","import { Signal } from '@angular/core';\nimport { ApiEnumApiType, ApiFields, ApiItemType, GetColumnType, ItemId, RequestParameters as BackendTypesRequestParameters, ResponseColumnItem, RmLoginInfoFlag } from '@rentman/backend-types';\nimport { UnknownResponseColumn } from '@rentman/backend-types/dist/manual/api-response-column';\nimport moment from 'moment';\nimport { ApiQuery, ChangesDeltaItemUpdateMode, ItemEntry, ItemResource, RequestColumnExpansion } from '../internal';\n\nexport type DerivedStringToRequestColumnPath<StringType extends string> = StringType extends `${infer Head}>${infer Tail}`\n\t? readonly [Head, ...DerivedStringToRequestColumnPath<Tail>]\n\t: readonly [StringType];\n\nexport type ResolveDerivedValue<\n\tItemTypeType extends ApiItemType,\n\tColumnPath extends readonly string[],\n> =\n\tColumnPath extends readonly [infer Last]\n\t\t? Last extends ItemTypeColumnId<ItemTypeType>\n\t\t\t? GetFieldValueType<ItemTypeType, Last>\n\t\t\t: never\n\t\t: ColumnPath extends readonly [infer First, ...infer Rest]\n\t\t\t? First extends ItemTypeColumnId<ItemTypeType>\n\t\t\t\t? Rest extends readonly string[]\n\t\t\t\t\t? ResolveDerivedValue<ExtractApiItemType<GetColumnType<ItemTypeType, First>>, Rest>\n\t\t\t\t\t: never\n\t\t\t\t: never\n\t\t\t: never;\n\nexport type ResolveDerivedValues<\n\tItemTypeType extends ApiItemType,\n\tColumnPath extends readonly string[]\n> =\n\tColumnPath extends readonly [infer Last]\n\t\t? Last extends ItemTypeColumnId<ItemTypeType>\n\t\t\t? FieldMap<ExtractApiItemType<GetColumnType<ItemTypeType, Last>>>\n\t\t\t: never\n\t\t: ColumnPath extends readonly [infer First, ...infer Rest]\n\t\t\t? First extends ItemTypeColumnId<ItemTypeType>\n\t\t\t\t? Rest extends readonly string[]\n\t\t\t\t\t? ResolveDerivedValues<ExtractApiItemType<GetColumnType<ItemTypeType, First>>, Rest>\n\t\t\t\t\t: never\n\t\t\t\t: never\n\t\t\t: never;\n\nexport type ApiEnumApiTypeToTsTypeMap = {\n\t[ApiEnumApiType.TYPE_TOKEN]: string,\n\t[ApiEnumApiType.TYPE_ID]: number,\n\t[ApiEnumApiType.TYPE_ORDER]: number,\n\t[ApiEnumApiType.TYPE_PARENTID]: number,\n\t[ApiEnumApiType.TYPE_PARENTTYPE]: ApiItemType,\n\t[ApiEnumApiType.TYPE_ITEMID]: number,\n\t[ApiEnumApiType.TYPE_ITEMTYPE]: ApiItemType,\n\t[ApiEnumApiType.TYPE_PASSWORD]: string,\n\t[ApiEnumApiType.TYPE_IP]: string,\n\t[ApiEnumApiType.TYPE_COORDINATE]: number,\n\t[ApiEnumApiType.TYPE_BLOB]: string,\n\t[ApiEnumApiType.TYPE_BITFLAG]: number,\n\t[ApiEnumApiType.TYPE_NUMBER]: number,\n\t[ApiEnumApiType.TYPE_VOLUME]: number,\n\t[ApiEnumApiType.TYPE_WEIGHT]: number,\n\t[ApiEnumApiType.TYPE_DISTANCE]: number,\n\t[ApiEnumApiType.TYPE_DIMENSION]: number,\n\t[ApiEnumApiType.TYPE_QUANTITY]: number,\n\t[ApiEnumApiType.TYPE_POWER]: number,\n\t[ApiEnumApiType.TYPE_CURRENT]: number,\n\n\t[ApiEnumApiType.TYPE_DOUBLE]: number,\n\t[ApiEnumApiType.TYPE_PRICE]: number,\n\t[ApiEnumApiType.TYPE_BOOL]: boolean,\n\t[ApiEnumApiType.TYPE_INT]: number,\n\t[ApiEnumApiType.TYPE_EMAIL]: string,\n\t[ApiEnumApiType.TYPE_PHONE]: string,\n\t[ApiEnumApiType.TYPE_URL]: string,\n\t[ApiEnumApiType.TYPE_PERCENTAGE]: number,\n\t[ApiEnumApiType.TYPE_TEXT]: string,\n\t[ApiEnumApiType.TYPE_LONGTEXT]: string,\n\t[ApiEnumApiType.TYPE_HTML]: string,\n\t[ApiEnumApiType.TYPE_DATE]: moment.Moment,\n\t[ApiEnumApiType.TYPE_DATETIME]: moment.Moment,\n\t[ApiEnumApiType.TYPE_DURATION]: moment.Duration,\n\t[ApiEnumApiType.TYPE_ITEM]: number,\n\t[ApiEnumApiType.TYPE_LINK]: number,\n\t[ApiEnumApiType.TYPE_CHILD]: number,\n\t[ApiEnumApiType.TYPE_SIBLING]: number,\n\t[ApiEnumApiType.TYPE_JSON]: any,\n\t[ApiEnumApiType.TYPE_ENUM]: string,\n\t[ApiEnumApiType.TYPE_COUNTRY]: string,\n\t[ApiEnumApiType.TYPE_COLOR]: string,\n\t[ApiEnumApiType.TYPE_TEXTREPLACE]: string,\n\t[ApiEnumApiType.TYPE_FILESIZE]: number,\n\t[ApiEnumApiType.TYPE_ICON]: string,\n\t[ApiEnumApiType.TYPE_NUMERIC_EXTERNALID]: number,\n\t[ApiEnumApiType.TYPE_ALPHANUMERIC_EXTERNALID]: string,\n\t[ApiEnumApiType.TYPE_TIME]: string,\n\t[ApiEnumApiType.TYPE_TIMESTAMP]: moment.Moment,\n\t[ApiEnumApiType.TYPE_TIMESTAMP_MS]: moment.Moment,\n};\n\nexport type ParentIdMap<T> = {\n\t[parentId: string]: T,\n};\n\nexport type EntryParent<ItemTypeType extends ApiItemType = any> = {\n\treadonly itemType: ItemTypeType,\n\treadonly itemId: ItemId,\n};\n\nexport type EntryParentNull<ItemTypeType extends ApiItemType = ApiItemType> = EntryParent<ItemTypeType> | null;\n\nexport type ItemTypeColumnId<ItemTypeType extends ApiItemType> = keyof ApiFields[ItemTypeType];\nexport type ItemTypeColumnIds<ItemTypeType extends ApiItemType> = readonly ItemTypeColumnId<ItemTypeType>[];\n\n// eslint-disable-next-line max-len\nexport type FieldMap<ItemTypeType extends ApiItemType = ApiItemType, ColumnIds extends ItemTypeColumnIds<ItemTypeType> = ItemTypeColumnIds<ItemTypeType>> = {\n\t[ColumnId in ColumnIds[number]]: GetFieldValueType<ItemTypeType, ColumnId>\n};\n\n// eslint-disable-next-line max-len\nexport type SignalFieldMap<ItemTypeType extends ApiItemType = ApiItemType, ColumnIds extends ItemTypeColumnIds<ItemTypeType> = ItemTypeColumnIds<ItemTypeType>> = {\n\t[ColumnId in ColumnIds[number]]: Signal<GetFieldValueType<ItemTypeType, ColumnId>>\n};\n\nexport type ExtractApiType<T> = T extends {type: any,} ? T['type'] : never;\nexport type ExtractApiEnum<T> = T extends {enum: any,} ? T['enum'] : never;\nexport type ExtractApiItemType<T> = T extends {itemType: any,} ? T['itemType'] : never;\nexport type ExtractApiNullable<T> = T extends {nullable: any,} ? T['nullable'] : never;\n\nexport type ExtractApiFieldType<T> = T extends {type: keyof ApiEnumApiTypeToTsTypeMap,}\n\t? ApiEnumApiTypeToTsTypeMap[T['type']]\n\t: never;\n\nexport type GetFieldValueType<ItemTypeType extends ApiItemType, ColumnId extends keyof ApiFields[ItemTypeType]> =\n// If the type is an enum, allow the keys of the enum\n\tExtractApiType<ApiFields[ItemTypeType][ColumnId]> extends ApiEnumApiType.TYPE_ENUM\n\t\t? keyof ExtractApiEnum<ApiFields[ItemTypeType][ColumnId]>\n\t\t// Otherwise check if it's nullable\n\t\t: GetNullableValueType<ItemTypeType, ColumnId>;\n\ntype GetNullableValueType<ItemTypeType extends ApiItemType, ColumnId extends keyof ApiFields[ItemTypeType]> =\n// If it's not nullable\n\tExtractApiNullable<ApiFields[ItemTypeType][ColumnId]> extends false\n\t\t// Just allow the value\n\t\t? ExtractApiFieldType<ApiFields[ItemTypeType][ColumnId]>\n\t\t// If it's a datetime, date or duration, only allow moment.invalid, not null\n\t\t// eslint-disable-next-line max-len\n\t\t: ExtractApiType<ApiFields[ItemTypeType][ColumnId]> extends ApiEnumApiType.TYPE_DATETIME | ApiEnumApiType.TYPE_DATE | ApiEnumApiType.TYPE_TIMESTAMP | ApiEnumApiType.TYPE_TIMESTAMP_MS | ApiEnumApiType.TYPE_DURATION\n\t\t\t? ExtractApiFieldType<ApiFields[ItemTypeType][ColumnId]>\n\t\t\t// If it's not any of those types, allow null or the original type\n\t\t\t: null | ExtractApiFieldType<ApiFields[ItemTypeType][ColumnId]>;\n\nexport interface SocketMessageBase {\n\theader: {\n\t\tdomain: string,\n\t\taccount: string,\n\t\tsender: {\n\t\t\tdisplayname: string,\n\t\t\titemType: 'Medewerker',\n\t\t\titemId: ItemId,\n\t\t\tauthorized: boolean,\n\t\t\tsession: string,\n\t\t},\n\t\tmessageId: {\n\t\t\tId: string,\n\t\t\tsequence: number,\n\t\t\tbatch: number,\n\t\t\trequest: number,\n\t\t},\n\t\tsent: string,\n\t\tforceEvaluate: boolean,\n\t},\n\tmessageType: string,\n\tinResponse: boolean,\n}\n\nexport interface SocketMessageCreate<ItemTypeType extends ApiItemType>\n\textends SocketMessageBase {\n\tmessageType: 'event',\n\tbody: {\n\t\titemType: ItemTypeType,\n\t\teventType: 'create',\n\t\titems: Pick<SocketUpdatedItems, ItemTypeType>,\n\t},\n}\n\nexport interface SocketMessageUpdate<ItemTypeType extends ApiItemType>\n\textends SocketMessageBase {\n\tmessageType: 'event',\n\tbody: {\n\t\titemType: ItemTypeType,\n\t\teventType: 'update',\n\t\titems: Pick<SocketUpdatedItems, ItemTypeType>,\n\t},\n}\n\nexport interface SocketMessageDelete\n\textends SocketMessageBase {\n\tmessageType: 'event',\n\tbody: {\n\t\titemType: ApiItemType,\n\t\teventType: 'delete',\n\t\titems: ItemId[],\n\t},\n}\n\nexport interface SocketMessageLinkTo<ItemTypeType extends ApiItemType>\n\textends SocketMessageBase {\n\tmessageType: 'event',\n\tbody: {\n\t\titemType: ItemTypeType,\n\t\teventType: 'linkTo',\n\t\titems: Pick<SocketUpdatedItems, ItemTypeType>,\n\t},\n}\n\ntype SocketUpdatedItems = {\n\t[ItemType in ApiItemType]: {\n\t\t[itemId: string]: SocketMessageValuesTuple<ItemType, ItemTypeColumnIds<ItemType>>,\n\t}\n};\n\nexport type SocketMessageValuesTuple<ItemTypeType extends ApiItemType, ColumnIds extends ItemTypeColumnIds<ItemTypeType>> = {\n\tparent: EntryParent | null,\n\tvalues: FieldMap<ItemTypeType, ColumnIds>,\n};\n\nexport type SocketMessage<ItemTypeType extends ApiItemType> = SocketMessageCreate<ItemTypeType>\n\t| SocketMessageUpdate<ItemTypeType>\n\t| SocketMessageLinkTo<ItemTypeType>\n\t| SocketMessageDelete;\n\n// ===================================================== Item resource\n\nexport type ItemResourcesItemTypeMap = {\n\t[ItemTypeType in ApiItemType]?: ItemResource<ItemTypeType>[]\n};\n\n// ===================================================== Item Entry\n\nexport type ItemMap<T> = {\n\t[itemType: string]: {\n\t\t[itemId: string]: T,\n\t},\n};\n\nexport type ParentItemMap<T> = {\n\t[parentId: number]: {\n\t\t[itemType: string]: T,\n\t},\n};\n\nexport type ItemEntryMap<ItemTypeType extends ApiItemType = any> = ItemMap<ItemEntry<ItemTypeType>>;\n\nexport type ItemEntryParentIdMap<ItemTypeType extends ApiItemType> = ParentIdMap<ItemEntry<ItemTypeType>[]>;\n\nexport type ConversionMap = {\n\t[itemId: number]: number,\n};\n\nexport type ItemIdConversionMap = {\n\t[itemType: string]: ConversionMap,\n};\n\nexport type CreateRequestParameterMap<T = any> = ItemMap<T>;\n\nexport type ItemError = {message: string,};\n\n// ===================================================== Collection Entry\n\nexport type CollectionQuery<ItemTypeType extends ApiItemType, IsLocallyMatchable extends boolean = boolean> = {\n\tobject: ApiQuery<ItemTypeType>,\n\tstring: string,\n\tisLocallyMatchable: IsLocallyMatchable,\n};\n\n// ===================================================== Columns\n\n// eslint-disable-next-line max-len\nexport type ResponseColumnMap<ItemTypeType extends ApiItemType = ApiItemType, ColumnIds extends ItemTypeColumnIds<ItemTypeType> = ItemTypeColumnIds<ItemTypeType>> = {\n\t[ColumnId in ColumnIds[number]]: GetColumnType<ItemTypeType, ColumnId>\n};\n\nexport type ResponseColumnItemTypeMap = {\n\t[ItemTypeType in ApiItemType]: ResponseColumnMap<ItemTypeType, ItemTypeColumnIds<ItemTypeType>>\n};\n\nexport type RootColumnMap<ItemTypeType extends ApiItemType = any, ColumnIds extends ItemTypeColumnIds<ItemTypeType> = any> = {\n\t[ColumnId in ColumnIds[number]]: {\n\t\tapiColumn: GetColumnType<ItemTypeType, ColumnId>,\n\t\tchildren: RootColumnMap,\n\t}\n};\n\n// ===================================================== Api reference\n\nexport type ApiResponse<ItemTypeType extends ApiItemType = any> = {\n\tcolumns: ItemTypeMap<UnknownResponseColumn[]>,\n\titemType: ItemTypeType,\n\titems: ItemTypeMap<{\n\t\t[itemId: string]: {\n\t\t\tdata: unknown[],\n\t\t\tlinks: Record<ApiItemType, ItemId[]>,\n\t\t},\n\t}>,\n\tlinks: Record<ApiItemType, ItemId[]>,\n\tcacheable?: boolean,\n} & Record<string, unknown>; // TODO\n\n// ===================================================== Api template response\nexport type TemplateItemResourceMap<T extends ItemResource<any>> = {\n\tmain: T,\n\tlinked: ItemResourcesItemTypeMap,\n};\n\nexport type ItemTypeMap<T = any> = {\n\t[itemType: string]: T,\n};\n\n// ===================================================== Api request\n\nexport type ApiRequestItemValues = {\n\tvalues?: any,\n\tlinks?: {\n\t\t[itemType: string]: ItemId[],\n\t},\n};\n\nexport type ApiRequestItemMap = {\n\t[itemType: string]: {\n\t\t[itemId: number]: ApiRequestItemValues,\n\t},\n};\n\nexport type OnlyNonNever<T> = {\n\t[P in keyof T]: T[P] extends never ? never : P;\n}[keyof T];\n\nexport type GetColumnIdsOfType<ItemTypeType extends ApiItemType, ApiType extends ApiEnumApiType> = OnlyNonNever<{\n\t[ColumnId in keyof ApiFields[ItemTypeType]]: ExtractApiType<ApiFields[ItemTypeType][ColumnId]> extends ApiType\n\t\t? true : never;\n}>;\n\nexport type GetDerivedColumnIds<ItemTypeType extends ApiItemType> = OnlyNonNever<{\n\t[ColumnId in keyof ApiFields[ItemTypeType]]: GetColumnType<ItemTypeType, ColumnId> extends ResponseColumnItem ? true\n\t\t: never;\n}>;\n\nexport type DerivedRequestColumnObject<ItemTypeType extends ApiItemType = any> = {\n\t[ColumnId in GetDerivedColumnIds<ItemTypeType>]?: ApiRequestColumnArray<ExtractApiItemType<GetColumnType<ItemTypeType, ColumnId>>>;\n};\n\nexport type ApiRequestColumn<ItemTypeType extends ApiItemType = any> =\n\tItemTypeColumnId<ItemTypeType>\n\t| DerivedRequestColumnObject<ItemTypeType>;\n\nexport type ApiRequestColumnArray<ItemTypeType extends ApiItemType = any> = readonly ApiRequestColumn<ItemTypeType>[];\n\nexport type ApiRequestColumns<ItemTypeType extends ApiItemType = any> = ApiRequestColumnArray<ItemTypeType> | true;\n\nexport type MutableApiRequestColumnArray<ItemTypeType extends ApiItemType = any> = ApiRequestColumn<ItemTypeType>[];\n\n/**\n * Both the array and string representation are read-only, because whenever the object changes, the string representation\n * should change too.\n */\nexport type RequestColumnsTuple<ItemTypeType extends ApiItemType = any> = {\n\t\treadonly object: true,\n\t\treadonly string: 'true',\n\t}\n\t| {\n\treadonly object: ApiRequestColumns<ItemTypeType>,\n\treadonly string: string,\n};\n\n// We intentionally don't type this because the itemTypes are too large for the TS compiler\nexport type ApiRequestColumnMap = {\n\t[itemType: string]: ApiRequestColumns,\n};\n\nexport type ApiRequestColumnArrayMap = {\n\t[itemType in ApiItemType]?: ApiRequestColumnArray\n};\n\nexport type ApiRequestLimit<ItemTypeType extends ApiItemType = any> = {\n\tfield: ItemTypeColumnId<ItemTypeType>,\n\t// 'desc' is default\n\torder?: 'desc' | 'asc',\n\tlimit: number,\n};\n\n// ===================================================== Create request\n\nexport type CreateRequestEntry<ItemTypeType extends ApiItemType> = {\n\trequest: {\n\t\trequestType: 'create',\n\t\titemType?: ItemTypeType,\n\t\tparentType?: ApiItemType,\n\t\tparentId?: {\n\t\t\t[itemId: string]: ItemId,\n\t\t},\n\t\titems: ApiRequestItemMap,\n\t\tcolumns: ApiRequestColumnMap,\n\t\tuniqueTransactionId?: string,\n\t},\n\tcolumns: RequestColumnExpansion,\n\titems: ItemEntryMap<ItemTypeType>,\n};\n\n// ===============================================\n\nexport enum ApiLinkTreeType {\n\tITEMTABLE = 'itemtable',\n\tDIRECT = 'direct'\n}\n\nexport type ApiLinkTreeEntryItemTable = {\n\ttype: ApiLinkTreeType.ITEMTABLE,\n};\n\nexport type ApiLinkTreeEntryDirect<ItemTypeType extends ApiItemType = any> = {\n\ttype: ApiLinkTreeType.DIRECT,\n\tfield: ItemTypeColumnId<ItemTypeType>,\n};\n\nexport type ApiLinkTreeEntry<ItemTypeType extends ApiItemType = any> =\n\tApiLinkTreeEntryItemTable\n\t| ApiLinkTreeEntryDirect<ItemTypeType>;\n\nexport type ApiLinkTree = {\n\t[itemType: string]: {\n\t\t[childType: string]: ApiLinkTreeEntry,\n\t},\n};\n\n/**\n * @description\n * Callback to determine if an item should be included in the create delta, return `false` to exclude the item\n */\n// eslint-disable-next-line max-len\nexport type FilterItemEntryCallback<ItemTypeType extends ApiItemType = any, ColumnIds extends ItemTypeColumnIds<ItemTypeType> = ItemTypeColumnIds<ItemTypeType>> = (\n\titemType: ItemTypeType,\n\tfields: FieldMap<ItemTypeType, ColumnIds>,\n) => boolean;\n\n// eslint-disable-next-line max-len\nexport type ModifyFieldsCallback<ItemTypeType extends ApiItemType = any, ColumnIds extends ItemTypeColumnIds<ItemTypeType> = ItemTypeColumnIds<ItemTypeType>> = (\n\titemType: ItemTypeType,\n\tfields: FieldMap<ItemTypeType, ColumnIds>,\n\titemIdConversionMap?: ItemIdConversionMap,\n) => void;\n\nexport type DeregFunction = () => void;\n\nexport type ResponseItemUpdateModeMap = ItemTypeMap<{\n\t[itemId: string]: ChangesDeltaItemUpdateMode,\n}>;\n\n/**\n * Converts a set of request columns to a set of columns of the item type by extracting the derived object key.\n * Example:\n * ```typescript\n * const requestColumns = [\n * 'serienummer',\n * {\n * materiaal: [\n * 'displayname',\n * {\n * creator: [\n * \t\t\t\t\t 'displayname',\n * ],\n * }\n * ],\n * },\n * ];\n * ```\n * Will turn into\n * ```typescript\n * [\n * 'serienummer',\n * 'materiaal',\n * ]\n * ```\n */\nexport type ConvertRequestToItemTypeColumnsIds<U extends ApiItemType, T extends ApiRequestColumnArray<U>> = {\n\t-readonly [K in keyof T]: T[K] extends Record<string, unknown>\n\t\t? keyof T[K] extends ItemTypeColumnId<U>\n\t\t\t? keyof T[K]\n\t\t\t: never\n\t\t: T[K] extends ItemTypeColumnId<U>\n\t\t\t? T[K]\n\t\t\t: never\n};\n\n/**\n * Transforms a set of request columns (which can contain derived column objects) to columns of the item\n * by extracting the derived object key.\n *\n * This should *only* be used when you're transforming a set of columns to something that can *only* contain the item's\n * columns such as a FieldMap or a ResponseColumnObject. If you use this in other situations you lose the derived column information\n */\nexport type RequestToItemColumns<U extends ApiItemType, T extends ApiRequestColumns<U>> =\n\tT extends ApiRequestColumnArray<U>\n\t\t? ConvertRequestToItemTypeColumnsIds<U, T> extends ItemTypeColumnIds<U>\n\t\t\t? ConvertRequestToItemTypeColumnsIds<U, T>\n\t\t\t: never\n\t\t: ItemTypeColumnIds<U>;\n\n// eslint-disable-next-line max-len\nexport type RequestColumnsFieldMap<ItemTypeType extends ApiItemType, Columns extends ApiRequestColumns<ItemTypeType>> = FieldMap<ItemTypeType, RequestToItemColumns<ItemTypeType, Columns>>;\n\n// eslint-disable-next-line max-len\nexport type RequestColumnsSignalFieldMap<ItemTypeType extends ApiItemType, Columns extends ApiRequestColumns<ItemTypeType>> = SignalFieldMap<ItemTypeType, RequestToItemColumns<ItemTypeType, Columns>>;\n\nexport type HasFlagFn = (\n\tflag: RmLoginInfoFlag,\n) => boolean;\n\ntype JoinPath<Prefix extends string, Suffix extends string> = Prefix extends '' ? Suffix : `${Prefix}>${Suffix}`;\n\n// We need to have a max depth so that we don't recurse infinitely.\n// @formatter:off\ntype Add1<T extends number> = T extends 0 ? 1 : T extends 1 ? 2 : T extends 2 ? 3 : T extends 3 ? 4 : T extends 4 ? 5 : never;\n\n/**\n * Turns a set of request columns into a union of all possible string paths, excluding the root level.\n * Example:\n * ```typescript\n * const requestColumns = [\n * 'serienummer',\n * {\n * materiaal: [\n * 'displayname',\n * {\n * creator: [\n *\t\t\t\t\t 'displayname',\n * ],\n * }\n * ],\n * },\n * ];\n * ```\n * Will turn into\n * ```typescript\n * 'materiaal>displayname' | 'materiaal>creator' | 'materiaal>creator>displayname'\n * ```\n */\nexport type RequestColumnsToDerivedStringPaths<T, Prefix extends string = '', Depth extends number = 0> =\n\tDepth extends 5\n\t\t? any\n\t\t: T extends readonly (infer U)[]\n\t\t\t? RequestColumnsToDerivedStringPaths<U, Prefix>\n\t\t\t: T extends string\n\t\t\t\t// Exclude root node. We don't want a direct field to be able to be called from `getDerivedValue`. Use `fields` instead\n\t\t\t\t? Prefix extends ''\n\t\t\t\t\t? never\n\t\t\t\t\t: JoinPath<Prefix, T>\n\t\t\t\t: T extends Record<string, any>\n\t\t\t\t\t? {\n\t\t\t\t\t\t[K in keyof T]:\n\t\t\t\t\t\t// Exclude root node. We don't want a direct field to be able to be called from `getDerivedValue`. Use `fields` instead\n\t\t\t\t\t\t| (Prefix extends '' ? never : JoinPath<Prefix, K & string>)\n\t\t\t\t\t\t| RequestColumnsToDerivedStringPaths<T[K], JoinPath<Prefix, K & string>, Add1<Depth>>\n\t\t\t\t\t}[keyof T]\n\t\t\t\t\t: never;\n\n/**\n * Turns a set of request columns into a union of all possible path arrays, excluding the root level.\n * Example:\n * ```typescript\n * const requestColumns = [\n * 'serienummer',\n * {\n * materiaal: [\n * 'displayname',\n * {\n * creator: [\n *\t\t\t\t\t 'displayname',\n * ],\n * }\n * ],\n * },\n * ];\n * ```\n * Will turn into\n * ```typescript\n * ['materiaal', 'displayname'] | ['materiaal', 'creator'] | ['materiaal', 'creator', 'displayname']\n * ```\n */\nexport type RequestColumnsToDerivedArrayPaths<T, Prefix extends readonly string[] = [], Depth extends number = 0> =\n\tDepth extends 5\n\t\t? any\n\t\t: T extends readonly (infer U)[]\n\t\t\t? (\n\t\t\tPrefix extends [] ? never\n\t\t\t\t// Exclude root node. We don't want a direct field to be able to be called from `getDerivedValue`. Use `fields` instead\n\t\t\t\t: Prefix['length'] extends 1\n\t\t\t\t\t? never\n\t\t\t\t\t: Prefix\n\t\t\t) | RequestColumnsToDerivedArrayPaths<U, Prefix, Depth>\n\t\t\t: T extends string\n\t\t\t\t? Prefix extends []\n\t\t\t\t\t? never\n\t\t\t\t\t: readonly [...Prefix, T]\n\t\t\t\t: T extends Record<string, any>\n\t\t\t\t\t? (\n\t\t\t\t\t// Exclude root node. We don't want a direct field to be able to be called from `getDerivedValue`. Use `fields` instead\n\t\t\t\t\tPrefix extends []\n\t\t\t\t\t\t? never\n\t\t\t\t\t\t: Prefix['length'] extends 1\n\t\t\t\t\t\t\t? never\n\t\t\t\t\t\t\t: Prefix\n\t\t\t\t\t) | {\n\t\t\t\t\t[K in keyof T]: RequestColumnsToDerivedArrayPaths<T[K], [...Prefix, K & string], Add1<Depth>>\n\t\t\t\t}[keyof T]\n\t\t\t\t\t: never;\n\nexport type RequestParameters<ItemTypeType extends keyof BackendTypesRequestParameters> = {\n\t[key in keyof BackendTypesRequestParameters[ItemTypeType]]: RequestParameterTypeToTsType<\n\t\tBackendTypesRequestParameters[ItemTypeType][key]\n\t>\n};\n\ntype RequestParameterTypeToTsType<RequestParameter> = (\n\tRequestParameter extends {\n\t\ttype: 'enum',\n\t\tenum: string[],\n\t}\n\t\t? RequestParameter['enum'][number]\n\t\t: RequestParameter extends {\n\t\t\ttype: keyof ApiEnumApiTypeToTsTypeMap,\n\t\t}\n\t\t\t? ApiEnumApiTypeToTsTypeMap[RequestParameter['type']]\n\t\t\t: never\n) | (\n\tRequestParameter extends {\n\t\tnullable: true,\n\t}\n\t\t? null\n\t\t: never\n);","import { signal } from '@angular/core';\nimport { ApiItemType, ItemId } from '@rentman/backend-types';\nimport { ColumnSet, KeyService } from '../internal';\n\nexport class ItemEntry<ItemTypeType extends ApiItemType = any> {\n\n\t// We don't want other people to mess with this, but we need a global counter to\n\t// give each entry a unique id within this RmCore.\n\tprivate static currentId: number = 0;\n\n\tpublic id: number = ++ItemEntry.currentId;\n\n\tpublic isLockableSignal = signal<boolean>(\n\t\tthis.isLockable(),\n\t);\n\n\tpublic isLocalSignal = signal<boolean>(\n\t\tthis.isLocal(),\n\t);\n\n\tprivate outdated: boolean = false;\n\n\tpublic constructor (\n\t\tpublic itemType: ItemTypeType,\n\t\tpublic itemId: ItemId,\n\t\tpublic columns: ColumnSet<ItemTypeType>,\n\t) {\n\t}\n\n\tpublic updateId (\n\t\tnewItemId: number,\n\t): void {\n\t\tthis.itemId = newItemId;\n\n\t\tthis.isLockableSignal.set(\n\t\t\tthis.isLockable(),\n\t\t);\n\n\t\tthis.isLocalSignal.set(\n\t\t\tthis.isLocal(),\n\t\t);\n\t}\n\n\tpublic isOutdated (): boolean {\n\t\treturn this.outdated;\n\t}\n\n\tpublic markOutdated (): void {\n\t\tthis.outdated = true;\n\t}\n\n\tpublic markUpToDate (): void {\n\t\tthis.outdated = false;\n\t}\n\n\tpublic isLocal (): boolean {\n\t\treturn KeyService.isLocalId(\n\t\t\tthis.itemId,\n\t\t);\n\t}\n\n\tpublic isLockable (): boolean {\n\t\tif (this.isLocal()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tswitch (this.itemType) {\n\t\t\tcase 'Project':\n\t\t\tcase 'Materiaal':\n\t\t\tcase 'Contact':\n\t\t\tcase 'Medewerker':\n\t\t\tcase 'Voertuig':\n\t\t\tcase 'Template':\n\t\t\tcase 'Inhuur':\n\t\t\t\treturn true;\n\t\t\tdefault:\n\t\t\t\treturn false;\n\t\t}\n\t}\n\n\tpublic toJSON () {\n\t\treturn {\n\t\t\tid: this.id,\n\t\t\tcolumns: this.columns,\n\t\t};\n\t}\n\n}\n","import { computed, Signal } from '@angular/core';\nimport { ApiItemType, ItemId, ResponseColumn } from '@rentman/backend-types';\nimport { UnknownResponseColumn } from '@rentman/backend-types/dist/manual/api-response-column';\nimport { AggregatedChangesListenerFunction, ApiFormatter, ApiRequestColumns, COLUMN_SEPERATOR, ColumnUtil, createPath, DeregFunction, DerivedStringToRequestColumnPath, EntryParentNull, FieldMap, ItemAggregatedChangesListener, ItemEntry, ItemResourceFactory, ItemTypeColumnIds, RequestColumnsFieldMap, RequestColumnsSignalFieldMap, RequestColumnsToDerivedArrayPaths, RequestColumnsToDerivedStringPaths, RequestParameters, RequestToItemColumns, ResolveDerivedValue, ResolveDerivedValues, ResponseColumnMap, TransactionCache } from '../internal';\n\n/**\n * This type is used to constrain the `Children` type parameter of item resources and collection resources. We don't\n * specify the whole collection resource here to prevent creating a circular type.\n */\nexport type ChildCollectionResources = {\n\t[ChildItemType in ApiItemType]?: {\n\t\titemType: ChildItemType,\n\t\titems: any[],\n\t}\n};\n\nexport type ItemResourceComputedSignalFunction<\n\tItemTypeType extends ApiItemType,\n\tRequestColumns extends ApiRequestColumns<ItemTypeType>,\n\tReturnValue = unknown,\n> = (\n\titemResource: {\n\t\ttransaction: TransactionCache,\n\t\tentry: ItemEntry<ItemTypeType>,\n\t\tfieldSignals: Readonly<RequestColumnsSignalFieldMap<ItemTypeType, RequestColumns>>,\n\t\tgetDerivedSignal: <GetDerivedSignalPath extends readonly string[] | string, DefaultValue = unknown> (\n\t\t\tpathInput: GetDerivedSignalPath,\n\t\t\tdefaultValue?: DefaultValue,\n\t\t) => Signal<MaybeDefaultValue<ResolveDerivedValue<ItemTypeType, GetDerivedSignalPath extends string\n\t\t\t? DerivedStringToRequestColumnPath<GetDerivedSignalPath> : GetDerivedSignalPath>, DefaultValue>>,\n\t},\n) => ReturnValue;\n\n// If there's no default value we only give back T, in case it is set it can also be the type of the default value\ntype MaybeDefaultValue<T, DefaultValue> = DefaultValue extends number | bigint | string | boolean | null | object\n\t? DefaultValue | T\n\t: T;\n\nexport class ItemResource<\n\t// TODO: We'd probably want to remove the default value here.\n\tItemTypeType extends ApiItemType = ApiItemType,\n\tRequestColumns extends ApiRequestColumns<ItemTypeType> = ItemTypeColumnIds<ItemTypeType>,\n\tChildren extends ChildCollectionResources | undefined = undefined\n> {\n\n\tpublic columns: ResponseColumnMap<ItemTypeType, RequestToItemColumns<ItemTypeType, RequestColumns>>;\n\tpublic fields: Readonly<RequestColumnsFieldMap<ItemTypeType, RequestColumns>>;\n\tpublic initial: Readonly<RequestColumnsFieldMap<ItemTypeType, RequestColumns>>;\n\n\tpublic fieldSignals: Readonly<RequestColumnsSignalFieldMap<ItemTypeType, RequestColumns>>;\n\n\t// We have the `itemType` both here and on `entry` because if you check `ItemResource.itemType` Typescript\n\t// will properly infer the ItemResource as being that itemType. If you do `ItemResource.entry.itemType` it will not\n\t// infer ItemResource as being that itemType\n\tpublic itemType: ItemTypeType;\n\n\tpublic children: Children;\n\n\t/**\n\t * We type this loosely to prevent TypeScript inferring a complex type when comparing item resources.\n\t */\n\tprivate readonly aggregatedChangesListeners: AggregatedChangesListenerFunction<any, any>[] = [];\n\n\t// We cache the derived field signals here instead of on the transaction because the paths are usually highly specific, and caching\n\t// them on the transaction would often keep them alive longer than necessary.\n\t// The downside is that requesting the same derived field signal on multiple ItemResources for the same item entry will create multiple signals, but this\n\t// is negligible in practice.\n\tprivate derivedFieldSignals: {\n\t\t[columnPath: string]: Signal<any>,\n\t} = {};\n\n\tprivate __computedFunctions: WeakMap<\n\t\tItemResourceComputedSignalFunction<ItemTypeType, RequestColumns>,\n\t\tSignal<any>\n\t> = new WeakMap();\n\n\tpublic constructor (\n\t\tprotected readonly factory: ItemResourceFactory,\n\t\tpublic readonly entry: ItemEntry<ItemTypeType>,\n\t\t// `transaction` is exposed for the app because they work with multiple logged-in users, and it's not always clear which\n\t\t// transaction belongs to whom. This way you can just do `resource.transaction.save()`\n\t\tpublic readonly transaction: TransactionCache,\n\t\tprivate readonly _isNew: boolean,\n\t\tabortSignal: AbortSignal | null = null,\n\t) {\n\t\t// eslint-disable-next-line max-len\n\t\tthis.columns = entry.columns.response[entry.columns.itemType] as ResponseColumnMap<ItemTypeType, RequestToItemColumns<ItemTypeType, RequestColumns>>;\n\t\tthis.itemType = this.entry.itemType;\n\n\t\tthis.initial = transaction.itemHandler.constructInitialProxy(\n\t\t\tentry,\n\t\t) as Readonly<RequestColumnsFieldMap<ItemTypeType, RequestColumns>>;\n\n\t\tthis.fields = transaction.itemHandler.constructFieldsProxy(\n\t\t\tentry,\n\t\t) as Readonly<RequestColumnsFieldMap<ItemTypeType, RequestColumns>>;\n\n\t\tthis.fieldSignals = transaction.itemHandler.constructSignalFieldsProxy(\n\t\t\tentry,\n\t\t) as Readonly<RequestColumnsSignalFieldMap<ItemTypeType, RequestColumns>>;\n\n\t\tthis.onConstruct();\n\n\t\tif (\n\t\t\tabortSignal !== null\n\t\t\t&& !abortSignal.aborted\n\t\t) {\n\t\t\tabortSignal.addEventListener(\n\t\t\t\t'abort',\n\t\t\t\t() => this.clearResource(),\n\t\t\t);\n\t\t}\n\t}\n\n\t// Used for resource clearing tests\n\tpublic onConstruct (): void {\n\n\t}\n\n\tpublic computedSignal<FunctionReference extends ItemResourceComputedSignalFunction<ItemTypeType, RequestColumns>> (\n\t\tfunctionReference: FunctionReference,\n\t): Signal<ReturnType<FunctionReference>> {\n\t\tif (\n\t\t\tthis.__computedFunctions.has(\n\t\t\t\tfunctionReference,\n\t\t\t)\n\t\t) {\n\t\t\treturn this.__computedFunctions.get(\n\t\t\t\tfunctionReference,\n\t\t\t)!;\n\t\t}\n\n\t\tconst computedSignal = computed<ReturnType<FunctionReference>>(\n\t\t\t() => functionReference(\n\t\t\t\tthis,\n\t\t\t) as ReturnType<FunctionReference>,\n\t\t);\n\n\t\tthis.__computedFunctions.set(\n\t\t\tfunctionReference,\n\t\t\tcomputedSignal,\n\t\t);\n\n\t\treturn computedSignal;\n\t}\n\n\t/**\n\t * We type this loosely to prevent TypeScript inferring a complex type when comparing item resources.\n\t * @internal\n\t */\n\tpublic getAggregatedChangesListeners<ChangesListeners extends Set<AggregatedChangesListenerFunction<any, any>>> (\n\t\taccumulator: ChangesListeners = new Set() as ChangesListeners,\n\t): ChangesListeners {\n\t\tfor (const listener of this.aggregatedChangesListeners) {\n\t\t\taccumulator.add(\n\t\t\t\tlistener,\n\t\t\t);\n\t\t}\n\n\t\treturn accumulator;\n\t}\n\n\tpublic clearResource (): void {\n\t\tthis.clearChildCollections();\n\n\t\tthis.transaction.itemHandler.clearItemResource(\n\t\t\tthis,\n\t\t);\n\t}\n\n\tpublic deregisterChangesListener (\n\t\tlistener: ItemAggregatedChangesListener<ItemResource<ItemTypeType, RequestColumns, Children>>,\n\t): void {\n\t\tconst index = this.aggregatedChangesListeners.indexOf(\n\t\t\tlistener,\n\t\t);\n\n\t\tif (index !== -1) {\n\t\t\tthis.aggregatedChangesListeners.splice(\n\t\t\t\tindex,\n\t\t\t\t1,\n\t\t\t);\n\t\t}\n\t}\n\n\tpublic registerChangesListener (\n\t\tlistener: ItemAggregatedChangesListener<ItemResource<ItemTypeType, RequestColumns, Children>>,\n\t): DeregFunction {\n\t\tthis.aggregatedChangesListeners.push(\n\t\t\tlistener,\n\t\t);\n\n\t\treturn () => {\n\t\t\tthis.deregisterChangesListener(\n\t\t\t\tlistener,\n\t\t\t);\n\t\t};\n\t}\n\n\tpublic setChildCollectionResources (\n\t\tchildren: Children,\n\t): void {\n\t\tif (children === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.children = children;\n\n\t\tfor (const itemType in children) {\n\t\t\tconst childCollectionResource = children[itemType as string];\n\n\t\t\tchildCollectionResource.setParentItem(\n\t\t\t\tthis,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Collects all the fields from this item, useful while debugging when you want to look at the complete fieldset\n\t * (because this.fields is now a proxy class)\n\t */\n\tpublic collectFields (): RequestColumnsFieldMap<ItemTypeType, RequestColumns> {\n\t\treturn this.transaction.itemHandler.collectFields(\n\t\t\tthis.entry,\n\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Updates the fields of the item and calls onChange, when updating many fields of many items it's better to create a {@link ChangesDelta ChangesDelta} yourself so all changes can be applied at once\n\t */\n\tpublic setFields (\n\t\tvalues: Partial<FieldMap<ItemTypeType>>,\n\t): Promise<this> {\n\t\tconst columns = this.columns;\n\n\t\tfor (const columnId in values) {\n\t\t\tconst column = columns[columnId as string];\n\n\t\t\tif (column === undefined) {\n\t\t\t\tthis.factory.errorHandler.logWarning(\n\t\t\t\t\t`setFields: no column found for ${columnId}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst changesDelta = this.transaction.createChangesDelta();\n\n\t\tchangesDelta.setItemUpdated(\n\t\t\tthis.entry,\n\t\t\tvalues,\n\t\t);\n\n\t\treturn this.transaction\n\t\t\t.applyChangesDelta(\n\t\t\t\tchangesDelta,\n\t\t\t)\n\t\t\t.then(\n\t\t\t\t() => this,\n\t\t\t);\n\t}\n\n\t/**\n\t * Copies the fields of the item resource to `destination`.\n\t * Note: When you want to create lots of copies, there are some straightforward optimizations that can be done here.\n\t * @param destination - For the resulting type to be correct, the columns of the destination should be known. Existing\n\t * properties will be preserved.\n\t * @param columnIds - The columns that should be copied. Only fields specified in the item resource type can be set here.\n\t * Will copy all available columns by default. (Note: may include columns not specified in the type.)\n\t * @returns The `destination` object.\n\t */\n\tpublic copyFields<\n\t\tDestinationColumnIds extends ItemTypeColumnIds<ItemTypeType> = [],\n\t\tColumnIds extends readonly RequestToItemColumns<ItemTypeType, RequestColumns>[number][] =\n\t\t\tRequestToItemColumns<ItemTypeType, RequestColumns>[number][],\n\t> (\n\t\tdestination: FieldMap<ItemTypeType, DestinationColumnIds> = {} as FieldMap<ItemTypeType, DestinationColumnIds>,\n\t\tcolumnIds?: ColumnIds,\n\t): FieldMap<ItemTypeType, DestinationColumnIds | ColumnIds> {\n\t\tfor (const column of this.entry.columns.main) {\n\t\t\tconst columnId = column.id;\n\n\t\t\tif (\n\t\t\t\tdestination[columnId] !== undefined\n\t\t\t\t|| (\n\t\t\t\t\tcolumnIds !== undefined\n\t\t\t\t\t&& !columnIds.includes(\n\t\t\t\t\t\tcolumnId,\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tdestination[columnId] = ApiFormatter.clone(\n\t\t\t\tcolumn.apiColumn.type,\n\t\t\t\tthis.transaction.itemHandler.lookUpItemField(\n\t\t\t\t\tthis.entry,\n\t\t\t\t\tcolumnId,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\treturn destination;\n\t}\n\n\t/**\n\t * Fetches the ItemResource's parent with the current fields\n\t *\n\t * ----------------\n\t *\n\t * @remark\n\t * Use this if you need to get the parent after an item has been deleted\n\t */\n\tpublic getParent (\n\t\tfromInitial?: boolean,\n\t): EntryParentNull {\n\t\treturn this.transaction.getParent(\n\t\t\tthis.entry,\n\t\t\tfromInitial,\n\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Utility function to easily check if a field is changed.\n\t * Will return `false` if the field is changed\n\t *\n\t * @example\n\t * onChange: (\n\t * itemResource,\n\t * previous,\n\t * compareItemField\n\t * ) {\n\t * if (!compareItemField('columnId')) {\n\t * processItem(itemResource);\n\t * }\n\t * }\n\t */\n\tpublic compareItemField (\n\t\tcolumnId: RequestToItemColumns<ItemTypeType, RequestColumns>[number],\n\t\tprevious: RequestColumnsFieldMap<ItemTypeType, RequestColumns>,\n\t): boolean {\n\t\tconst column = this.columns[columnId] as ResponseColumn<ItemTypeType>;\n\n\t\tif (column === undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t'Missing column in ItemResource.compareItemField',\n\t\t\t);\n\t\t}\n\n\t\treturn ApiFormatter.compareFields(\n\t\t\tcolumn.type,\n\t\t\tthis.fields[columnId],\n\t\t\tprevious[columnId],\n\t\t);\n\t}\n\n\tpublic hasChanges (): boolean {\n\t\treturn this\n\t\t\t.transaction\n\t\t\t.itemHandler\n\t\t\t.detectEntryChanges(\n\t\t\t\tthis.entry.id,\n\t\t\t);\n\t}\n\n\tpublic setTransactionParameters (\n\t\tparameters: Partial<RequestParameters<ItemTypeType>>,\n\t): void {\n\t\tcreatePath(\n\t\t\tthis.transaction.tabRequestParameters,\n\t\t\t[\n\t\t\t\tthis.entry.itemType,\n\t\t\t\tthis.entry.itemId,\n\t\t\t],\n\t\t\t[\n\t\t\t\t{},\n\t\t\t\tparameters,\n\t\t\t],\n\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * 'isNew' means that the {@link ItemEntry ItemEntry} is a local item and that this resource was created when the {@link ItemEntry ItemEntry} was first created\n\t */\n\tpublic isNew (): boolean {\n\t\treturn this._isNew;\n\t}\n\n\tpublic isLocal (): boolean {\n\t\treturn this.entry.isLocal();\n\t}\n\n\tpublic toJSON () {\n\t\tconst columnIds: string[] = [];\n\n\t\tfor (const columnId in this.columns) {\n\t\t\tcolumnIds.push(\n\t\t\t\tcolumnId,\n\t\t\t);\n\t\t}\n\n\t\treturn {\n\t\t\tcolumns: columnIds,\n\t\t\tfields: this.fields,\n\t\t\tentry: this.entry,\n\t\t};\n\t}\n\n\tpublic getDerivedSignal<const T extends RequestColumnsToDerivedStringPaths<RequestColumns>, DefaultValue = unknown> (\n\t\tpathInput: T,\n\t\tdefaultValue?: DefaultValue,\n\t): Signal<MaybeDefaultValue<ResolveDerivedValue<ItemTypeType, DerivedStringToRequestColumnPath<T>>, DefaultValue>>;\n\n\tpublic getDerivedSignal<const T extends RequestColumnsToDerivedArrayPaths<RequestColumns>, DefaultValue = unknown> (\n\t\tpathInput: T,\n\t\tdefaultValue?: DefaultValue,\n\t): Signal<MaybeDefaultValue<ResolveDerivedValue<ItemTypeType, T>, DefaultValue>>;\n\n\t// Derived signals are handled by using a `Computed` signal, which will automatically update when the underlying item changes.\n\t// This way, if any signal along the path changes, the derived signal will automatically update without us having to do any extra work.\n\tpublic getDerivedSignal<T extends readonly string[] | string, DefaultValue = unknown> (\n\t\tpathInput: T,\n\t\tdefaultValue?: DefaultValue,\n\t): Signal<MaybeDefaultValue<ResolveDerivedValue<ItemTypeType, T extends string ? DerivedStringToRequestColumnPath<T>\n\t\t: T>, DefaultValue>> {\n\t\tlet joinedPath: string;\n\t\tlet pathArray: readonly string[];\n\n\t\tif (typeof pathInput === 'string') {\n\t\t\tpathArray = pathInput.split(\n\t\t\t\tCOLUMN_SEPERATOR,\n\t\t\t);\n\t\t\tjoinedPath = pathInput;\n\t\t} else {\n\t\t\tpathArray = pathInput;\n\t\t\tjoinedPath = pathInput.join(\n\t\t\t\tCOLUMN_SEPERATOR,\n\t\t\t);\n\t\t}\n\n\t\tif (this.derivedFieldSignals[joinedPath] !== undefined) {\n\t\t\treturn this.derivedFieldSignals[joinedPath];\n\t\t}\n\n\t\tconst derivedComputed = this.derivedFieldSignals[joinedPath] = computed(\n\t\t\t() => {\n\t\t\t\tlet itemEntry: ItemEntry<any> = this.entry;\n\n\t\t\t\tfor (let i = 0; i < pathArray.length; i++) {\n\t\t\t\t\tconst columnId = pathArray[i] as any;\n\n\t\t\t\t\tif (i === pathArray.length - 1) {\n\t\t\t\t\t\tconst resultValueSignal = this.transaction.itemHandler.getItemFieldSignal(\n\t\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\t\tcolumnId,\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// We want to return the value of the signal, not the signal itself\n\t\t\t\t\t\treturn resultValueSignal();\n\t\t\t\t\t}\n\n\t\t\t\t\tconst column = this.transaction.core.columnCache.getColumn(\n\t\t\t\t\t\titemEntry.itemType,\n\t\t\t\t\t\tcolumnId,\n\t\t\t\t\t) as UnknownResponseColumn | undefined;\n\n\t\t\t\t\tif (column === undefined) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t`getDerivedSignal: column ${columnId} not found for itemtype ${itemEntry.itemType}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (\n\t\t\t\t\t\t!ColumnUtil.isItemColumn(\n\t\t\t\t\t\t\tcolumn,\n\t\t\t\t\t\t)\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t`getDerivedSignal: column ${columnId} for itemtype ${itemEntry.itemType} is not an item type`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst itemIdSignal = this.transaction.itemHandler.getItemFieldSignal(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\tcolumnId,\n\t\t\t\t\t);\n\n\t\t\t\t\tconst itemId = itemIdSignal() as ItemId | null;\n\n\t\t\t\t\tif (itemId === null) {\n\t\t\t\t\t\treturn defaultValue;\n\t\t\t\t\t}\n\n\t\t\t\t\titemEntry = this.transaction.getLocalItemEntryByItemId(\n\t\t\t\t\t\tcolumn.itemType,\n\t\t\t\t\t\titemId,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`getDerivedSignal: could not traverse path ${joinedPath} for itemtype ${itemEntry.itemType}`,\n\t\t\t\t);\n\t\t\t},\n\t\t);\n\n\t\treturn derivedComputed;\n\t}\n\n\t/**\n\t * @description\n\t * Returns the value of the columnPath, or undefined when the path couldn't be traversed\n\t *\n\t * @param columnPath Can either be an array of columnIds (['column', 'column2']) or a config column string ('column>column2')\n\t */\n\tpublic getDerivedValue<const T extends RequestColumnsToDerivedStringPaths<RequestColumns>, DefaultValue = unknown> (\n\t\tcolumnPath: T,\n\t\tdefaultValue?: DefaultValue,\n\t): MaybeDefaultValue<ResolveDerivedValue<ItemTypeType, DerivedStringToRequestColumnPath<T>>, DefaultValue>;\n\n\tpublic getDerivedValue<const T extends RequestColumnsToDerivedArrayPaths<RequestColumns>, DefaultValue = unknown> (\n\t\tcolumnPath: T,\n\t\tdefaultValue?: DefaultValue,\n\t): MaybeDefaultValue<ResolveDerivedValue<ItemTypeType, T>, DefaultValue>;\n\n\tpublic getDerivedValue<T extends readonly string[] | string, DefaultValue = unknown> (\n\t\tcolumnPath: readonly string[] | string,\n\t\tdefaultValue?: DefaultValue,\n\t): MaybeDefaultValue<ResolveDerivedValue<ItemTypeType,\n\t\tT extends string\n\t\t\t? DerivedStringToRequestColumnPath<T>\n\t\t\t: T>, DefaultValue> {\n\t\treturn this.transaction.itemHandler.getDerivedValue(\n\t\t\tthis.entry,\n\t\t\tcolumnPath as any,\n\t\t\tdefaultValue,\n\t\t) as any;\n\t}\n\n\t/**\n\t * @description\n\t * Traverses the column path and returns the fields of the derived item, returns undefined if the item isn't found\n\t *\n\t * ---------------------\n\t *\n\t * @remark\n\t * Assumes the derived item's values are already cached\n\t */\n\n\tpublic getDerivedValues<const T extends readonly string[]> (\n\t\tcolumnPath: T,\n\t): ResolveDerivedValues<ItemTypeType, T> | undefined {\n\t\treturn this.transaction.itemHandler.getDerivedValues(\n\t\t\tthis.entry,\n\t\t\tcolumnPath,\n\t\t) as any;\n\t}\n\n\t/**\n\t * @description\n\t * Clears all the child CollectionResource attached to an itemResource\n\t */\n\tpublic clearChildCollections (): void {\n\t\tif (this.children === null) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const itemType in this.children) {\n\t\t\tthis.children[itemType as string].clearResource();\n\t\t}\n\t}\n\n}\n","import { ApiItemType } from '@rentman/backend-types';\nimport { RootQueryNode } from '../classes/matcher/RootQueryNode';\nimport { CollectionQuery, Deferred, ItemEntry, promiseCreateDeferred, RequestColumnsTuple } from '../internal';\n\nexport class CachedQueryItem<ItemTypeType extends ApiItemType = any> {\n\n\tpublic promise: Promise<this>;\n\n\tpublic creation: Date = new Date();\n\n\tprivate deferred: Deferred<this> | null;\n\tprivate outdated: boolean = false;\n\n\tpublic constructor (\n\t\tpublic readonly itemType: ItemTypeType,\n\t\t// Collection query object is read-only because it is used as leaf node in the query graph.\n\t\tpublic readonly query: CollectionQuery<ItemTypeType>,\n\t\t// When using child collections, the query graph could already be a graph that matches multiple cached queries.\n\t\tpublic readonly queryGraph: RootQueryNode<ItemTypeType>,\n\t\tpublic items: ItemEntry<ItemTypeType>[],\n\t\t// todo: we should make sure that the queryColumns and linkedTo field are in the request columns, this is currently handled by 'expandColumnsWithQueryColumns'\n\t\tpublic requestColumnsTuple: RequestColumnsTuple<ItemTypeType>,\n\t) {\n\t\tthis.deferred = promiseCreateDeferred<this>();\n\t\tthis.promise = this.deferred.promise;\n\t}\n\n\tpublic isOutdated (): boolean {\n\t\treturn this.outdated;\n\t}\n\n\tpublic markOutdated (): void {\n\t\tthis.outdated = true;\n\t}\n\n\tpublic markUpToDate (): void {\n\t\tthis.outdated = false;\n\t}\n\n\tpublic itemsResolved (): boolean {\n\t\treturn this.deferred === null;\n\t}\n\n\t/**\n\t * Resolve can be called on items that are already resolved. The request buffer might or might not combine\n\t * requests together.\n\t */\n\tpublic resolve (): void {\n\t\tif (this.deferred === null) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.deferred.resolve(\n\t\t\tthis,\n\t\t);\n\n\t\tthis.deferred = null;\n\t}\n\n\tpublic reject (\n\t\treason: any,\n\t): void {\n\t\tif (this.deferred === null) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.deferred.reject(\n\t\t\treason,\n\t\t);\n\n\t\tthis.deferred = null;\n\t}\n\n\t/**\n\t * Updates the items in the collection resource, given the results of a query matching cycle.\n\t *\n\t * Note: In order to reduce back-end requests for non-locally matchable queries, `fittingItemEntries` may contain item\n\t * entries that are already present in the collection, and `nonFittingItemEntries` may contain item entries that\n\t * are not present in the collection.\n\t */\n\tpublic handleMatchedItemEntries (\n\t\tfittingItemEntries: Iterable<ItemEntry<ItemTypeType>>,\n\t\tnonFittingItemEntries: Set<ItemEntry<ItemTypeType>> | undefined,\n\t): void {\n\t\tconst fittingItemEntriesCopy = new Set(\n\t\t\tfittingItemEntries,\n\t\t);\n\n\t\tif (fittingItemEntriesCopy.size > 0) {\n\t\t\tfor (const itemEntry of this.items) {\n\t\t\t\tfittingItemEntriesCopy.delete(\n\t\t\t\t\titemEntry,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tfor (const fittingItemEntry of fittingItemEntriesCopy) {\n\t\t\t\tthis.items.push(\n\t\t\t\t\tfittingItemEntry,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (nonFittingItemEntries === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst newItemEntries: ItemEntry<ItemTypeType>[] = [];\n\n\t\tfor (const itemEntry of this.items) {\n\t\t\tif (\n\t\t\t\t!nonFittingItemEntries.has(\n\t\t\t\t\titemEntry,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tnewItemEntries.push(\n\t\t\t\t\titemEntry,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tthis.items = newItemEntries;\n\t}\n\n}\n","import { ApiItemType } from '@rentman/backend-types';\nimport { ApiRequestColumns, CollectionQuery, ColumnExpansion, ColumnSet, EntryParentNull, KeyService, QueryService, RootCollectionOptionsBase } from '../internal';\n\nexport class CollectionEntry<ItemTypeType extends ApiItemType> {\n\n\t// We don't want other people to mess with this, but we need a global counter to\n\t// give each collection a unique id within this RmCore.\n\tprivate static currentId: number = 0;\n\n\tpublic id: number = CollectionEntry.currentId++;\n\tpublic itemType: ItemTypeType;\n\tpublic parent: EntryParentNull = null;\n\tpublic promise: Promise<this>;\n\n\tpublic constructor (\n\t\tprivate queryService: QueryService,\n\t\tpublic options: Readonly<RootCollectionOptionsBase<ItemTypeType>>,\n\t\t// Collection query object is read-only because it is used as leaf node in the query graph.\n\t\tpublic readonly query: CollectionQuery<ItemTypeType>,\n\t\tpublic columns: ColumnSet<ItemTypeType>,\n\t) {\n\t\tthis.itemType = columns.itemType;\n\t\tthis.parent = options.parent ?? null;\n\t}\n\n\tpublic isLocal (): boolean {\n\t\tconst parent = this.parent;\n\n\t\tif (parent === null) {\n\t\t\treturn this.queryService.containsLocalId(\n\t\t\t\tthis.query.object,\n\t\t\t);\n\t\t}\n\n\t\treturn KeyService.isLocalId(\n\t\t\tparent.itemId,\n\t\t);\n\t}\n\n\tpublic expandColumns (\n\t\tcolumnExpansion: ColumnExpansion<ItemTypeType>,\n\t): void {\n\t\tthis.columns = columnExpansion.run(\n\t\t\tthis.columns,\n\t\t).merged;\n\t\t(this.options.columns as ApiRequestColumns) = this.columns.request;\n\t}\n\n}\n","import { ApiItemType, ItemId } from '@rentman/backend-types';\n\nexport class ItemNotFoundException\n\textends Error {\n\n\tpublic constructor (\n\t\tentryId: number,\n\t\titemId?: undefined,\n\t);\n\n\tpublic constructor (\n\t\titemType: ApiItemType,\n\t\titemId: ItemId,\n\t);\n\n\tpublic constructor (\n\t\titemTypeOrEntryId: ApiItemType | number,\n\t\titemId?: ItemId,\n\t) {\n\t\tsuper(\n\t\t\ttypeof itemTypeOrEntryId === 'number'\n\t\t\t\t? `Item with item entry ID ${itemTypeOrEntryId} does not exist`\n\t\t\t\t: `Item with type '${itemTypeOrEntryId}' and item ID ${itemId} does not exist`,\n\t\t);\n\t}\n\n}","import { signal, WritableSignal } from '@angular/core';\nimport { ApiItemType, ItemId } from '@rentman/backend-types';\nimport { RootQueryNode } from '../classes/matcher/RootQueryNode';\nimport { ItemNotFoundException } from '../exceptions/ItemNotFoundException';\nimport { AbstractCache, AggregatedChangesByListener, AggregatedChangesListener, AggregatedChangesListenerFunction, ApiRequestColumnArray, CachedQueryItem, CachedQueryItemsItemTypeTuple, ChangesDeltaResult, ChildCollectionResources, CollectionChangesListenerContext, CollectionEntry, CollectionItemChangesListenerContext, CollectionOptions, CollectionQuery, CollectionResourceFactory, ColumnSet, DeregFunction, FieldMap, ItemEntry, ItemIdConversionMap, ItemResource, ItemTypeColumnIds, ParentCachedQueryItemTuple, ParentChangesDelta, ParentIdMap, RequestColumnsFieldMap, ResponseColumnItemTypeMap, RootCollectionOptionsBase, TransactionCache } from '../internal';\n\nexport type CollectionToItemResource<\n\tCollectionResourceType extends {\n\t\titems: any[],\n\t}\n> = CollectionResourceType['items'][number];\n\nexport interface AddedRemovedItemResources<ItemResourceType> {\n\taddedItems: ItemResourceType[],\n\tremovedItems: ItemResourceType[],\n}\n\n/**\n * Stores added, removed, and changed items for a collection resource. All properties are represented as item resources.\n */\nexport interface CollectionItemResourceChanges<\n\tCollectionResourceType extends {\n\t\titems: any[],\n\t}\n>\n\textends AddedRemovedItemResources<CollectionToItemResource<CollectionResourceType>> {\n\n\tchangedItems: CollectionToItemResource<CollectionResourceType>[],\n\tcollectionResource: CollectionResourceType,\n}\n\n/**\n * Collection changes listeners have a single `CollectionResourceType` type variable (instead of separate item type /\n * request columns / children variables) because there are multiple types of collection resources\n * ({@link OrderedCollectionResource}, {@link LimitedCollectionResource}).\n */\nexport type CollectionItemChangesListener<CollectionResourceType extends CollectionResource<any, any, any>> = (\n\tcontext: CollectionItemChangesListenerContext<CollectionResourceType>,\n) => void;\n\nexport type OnAddCallback<CollectionResourceType extends CollectionResource<any, any, any>> = (\n\targs: {\n\t\titemResources: CollectionToItemResource<CollectionResourceType>[],\n\t\tcollectionResource: CollectionResourceType,\n\t\tisInitialCall: boolean,\n\t\tisCalledAfterSocketUpdate: boolean,\n\t},\n) => void;\n\nexport type OnRemoveCallback<CollectionResourceType extends CollectionResource<any, any, any>> = (\n\targs: {\n\t\titemResources: CollectionToItemResource<CollectionResourceType>[],\n\t\titemEntries: CollectionToItemResource<CollectionResourceType>['entry'][],\n\t\tcollectionResource: CollectionResourceType,\n\t\tisCalledAfterSocketUpdate: boolean,\n\t},\n) => void;\n\nexport class CollectionResource<\n\tItemTypeType extends ApiItemType,\n\tRequestColumns extends ApiRequestColumnArray<ItemTypeType> = ItemTypeColumnIds<ItemTypeType>,\n\tChildren extends ChildCollectionResources | undefined = undefined\n> {\n\n\tpublic readonly itemType: ItemTypeType;\n\tpublic readonly entry: CollectionEntry<ItemTypeType>;\n\tpublic readonly columns: ResponseColumnItemTypeMap;\n\n\tpublic items: ItemResource<ItemTypeType, RequestColumns, Children>[] = [];\n\n\t// eslint-disable-next-line max-len\n\tpublic readonly itemsSignal: WritableSignal<ItemResource<ItemTypeType, RequestColumns, Children>[]> = signal<ItemResource<ItemTypeType, RequestColumns, Children>[]>(\n\t\tthis.items,\n\t);\n\n\tpublic parentItem: ItemResource<any, any, any> | null;\n\n\tprotected itemEntryIdMap: {\n\t\t[itemEntryId: number]: ItemResource<ItemTypeType, RequestColumns, Children>,\n\t} = {};\n\n\tprivate onChangeCallbacks: CollectionItemChangesListener<CollectionResource<ItemTypeType, RequestColumns, Children>>[] = [];\n\tprivate onAddCallbacks: OnAddCallback<CollectionResource<ItemTypeType, RequestColumns, Children>>[] = [];\n\tprivate onRemoveCallbacks: OnRemoveCallback<CollectionResource<ItemTypeType, RequestColumns, Children>>[] = [];\n\n\t/**\n\t * We type this loosely to prevent TypeScript inferring a complex type when comparing collection resources.\n\t */\n\tprivate aggregatedChangesListeners: AggregatedChangesListenerFunction<any, any>[] = [];\n\n\tpublic constructor (\n\t\tprotected readonly factory: CollectionResourceFactory,\n\t\t// TODO: Specify columns / children.\n\t\tpublic readonly options: Readonly<RootCollectionOptionsBase<ItemTypeType>>,\n\t\tpublic readonly transaction: TransactionCache,\n\t\tpublic readonly queryGraph: RootQueryNode<ItemTypeType>,\n\t\tquery: CollectionQuery<ItemTypeType>,\n\t\tcolumnSet: ColumnSet<ItemTypeType>,\n\t\tpublic parentCollection: CollectionResource<any, any, any> | null,\n\t) {\n\t\tthis.columns = columnSet.response;\n\t\tthis.itemType = columnSet.itemType;\n\t\tthis.entry = new CollectionEntry(\n\t\t\tthis.factory.queryService,\n\t\t\toptions,\n\t\t\tquery,\n\t\t\tcolumnSet,\n\t\t);\n\n\t\tthis.registerOptionsChangesListeners();\n\t\tthis.onConstruct();\n\n\t\tconst abortSignal = this.options.abortSignal;\n\n\t\tif (\n\t\t\tabortSignal !== undefined\n\t\t\t&& !abortSignal.aborted\n\t\t) {\n\t\t\tabortSignal.addEventListener(\n\t\t\t\t'abort',\n\t\t\t\t() => this.clearResource(),\n\t\t\t);\n\t\t}\n\t}\n\n\tpublic setParentItem (\n\t\tparentItem: ItemResource<any, any, any>,\n\t): void {\n\t\tthis.parentItem = parentItem;\n\t}\n\n\tpublic initializeItems (\n\t\tinitialItemEntries: ItemEntry<ItemTypeType>[],\n\t\tchildCollectionResourceMap: ParentIdMap<Children>,\n\t): void {\n\t\tconst itemResources = this.addItemResources(\n\t\t\tinitialItemEntries,\n\t\t\tchildCollectionResourceMap,\n\t\t);\n\n\t\tif (this.options.callOnAddWithInitialItems === true) {\n\t\t\tthis.triggerCollectionChangesListeners(\n\t\t\t\t{\n\t\t\t\t\taddedItems: itemResources,\n\t\t\t\t\tremovedItems: [],\n\t\t\t\t},\n\t\t\t\tnull,\n\t\t\t\tundefined,\n\t\t\t\tfalse,\n\t\t\t\ttrue,\n\t\t\t\tnull,\n\t\t\t);\n\t\t}\n\t}\n\n\t// Used for resource clearing tests\n\tpublic onConstruct (): void {\n\n\t}\n\n\t/**\n\t * @internal\n\t */\n\tpublic clearCachedQueryOnTransaction (\n\t\ttransaction: AbstractCache,\n\t): void {\n\t\tconst cachedQuery = transaction.cachedQueryHandler.getCachedQueryItem(\n\t\t\tthis.entry.itemType,\n\t\t\tthis.entry.query.string,\n\t\t);\n\n\t\tcachedQuery?.markOutdated();\n\n\t\tif (this.options.children === null) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const itemResource of this.items) {\n\t\t\tfor (const childItemType in itemResource.children) {\n\t\t\t\t(itemResource.children[childItemType as ApiItemType] as CollectionResource<any>).clearCachedQueryOnTransaction(\n\t\t\t\t\ttransaction,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * @description\n\t * Removes the query (if it's cached) from the TransactionCachedQueryHandler and redoes the query\n\t *\n\t * Fixme: This function does not work properly for other collections using the same query.\n\t * While adds and updates are properly processed by the query matcher after we fetch the new data,\n\t * the absense of items in the response is not handled as deletes. We've fixed that in the collection\n\t * you call `refresh` on by manually comparing the items, but this doesn't remove it from other collections.\n\t */\n\tpublic async refresh (): Promise<CachedQueryItem<ItemTypeType>> {\n\t\tconst transactionChain = this.transaction.getTransactionChain(\n\t\t\ttrue,\n\t\t);\n\n\t\tfor (const transaction of transactionChain) {\n\t\t\tthis.clearCachedQueryOnTransaction(\n\t\t\t\ttransaction,\n\t\t\t);\n\t\t}\n\n\t\tconst cachedQueryItem = await this.fetchCachedQuery();\n\t\tconst itemEntriesToBeRemovedSet: Set<ItemEntry<ItemTypeType>> = new Set();\n\n\t\tfor (const itemResource of this.items) {\n\t\t\tconst foundItem = cachedQueryItem.items.find(\n\t\t\t\titemEntry => itemEntry.itemId === itemResource.entry.itemId,\n\t\t\t);\n\n\t\t\t// These items are in the collection, but not in the cached query, so should be removed\n\t\t\tif (foundItem === undefined) {\n\t\t\t\titemEntriesToBeRemovedSet.add(\n\t\t\t\t\titemResource.entry,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst addedRemovedItemResources = await this.updateItemsProperty(\n\t\t\t[],\n\t\t\titemEntriesToBeRemovedSet,\n\t\t\ttrue,\n\t\t);\n\n\t\tthis.itemsSignal.set(\n\t\t\t[\n\t\t\t\t...this.items,\n\t\t\t],\n\t\t);\n\n\t\tthis.triggerCollectionChangesListeners(\n\t\t\taddedRemovedItemResources,\n\t\t\tnull,\n\t\t\tundefined,\n\t\t\tfalse,\n\t\t\tfalse,\n\t\t\tnull,\n\t\t);\n\n\t\treturn cachedQueryItem;\n\t}\n\n\tpublic deregisterChangesListener (\n\t\tlistener: AggregatedChangesListenerFunction<any, any>,\n\t): void {\n\t\tconst index = this.aggregatedChangesListeners.indexOf(\n\t\t\tlistener,\n\t\t);\n\n\t\tif (index !== -1) {\n\t\t\tthis.aggregatedChangesListeners.splice(\n\t\t\t\tindex,\n\t\t\t\t1,\n\t\t\t);\n\t\t}\n\t}\n\n\tpublic registerChangesListener (\n\t\t/*\n\t\t * We're using the `this` type here to ensure the `collectionResource` property has the correct value\n\t\t * for limited collection resources.\n\t\t */\n\t\tlistener: AggregatedChangesListener<this, any>,\n\t): DeregFunction {\n\t\tthis.aggregatedChangesListeners.push(\n\t\t\tlistener,\n\t\t);\n\n\t\treturn () => {\n\t\t\tthis.deregisterChangesListener(\n\t\t\t\tlistener,\n\t\t\t);\n\t\t};\n\t}\n\n\t/**\n\t * @deprecated\n\t */\n\tpublic onAdd (\n\t\tcallback: OnAddCallback<this>,\n\t): DeregFunction {\n\t\treturn this.__registerCallback(\n\t\t\tthis.onAddCallbacks,\n\t\t\tcallback,\n\t\t);\n\t}\n\n\t/**\n\t * @deprecated\n\t */\n\tpublic onChange (\n\t\tcallback: CollectionItemChangesListener<this>,\n\t): DeregFunction {\n\t\treturn this.__registerCallback(\n\t\t\tthis.onChangeCallbacks,\n\t\t\tcallback,\n\t\t);\n\t}\n\n\t/**\n\t * @deprecated\n\t */\n\tpublic onRemove (\n\t\tcallback: OnRemoveCallback<this>,\n\t): DeregFunction {\n\t\treturn this.__registerCallback(\n\t\t\tthis.onRemoveCallbacks,\n\t\t\tcallback,\n\t\t);\n\t}\n\n\tpublic removeItems (\n\t\tidArray: ItemId[],\n\t): Promise<ChangesDeltaResult> {\n\t\tconst changesDelta = this.transaction.createChangesDelta();\n\t\tconst removedItemEntries: ItemEntry[] = [];\n\n\t\tfor (const itemResource of this.items) {\n\t\t\tconst itemEntry = itemResource.entry;\n\n\t\t\tif (!idArray.includes(\n\t\t\t\titemEntry.itemId,\n\t\t\t)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tremovedItemEntries.push(\n\t\t\t\titemEntry,\n\t\t\t);\n\t\t}\n\n\t\tchangesDelta.setItemsDeleted(\n\t\t\tremovedItemEntries,\n\t\t);\n\n\t\treturn this.transaction.applyChangesDelta(\n\t\t\tchangesDelta,\n\t\t);\n\t}\n\n\tpublic removeItem (\n\t\titemId: ItemId,\n\t): Promise<ChangesDeltaResult> {\n\t\treturn this.removeItems(\n\t\t\t[\n\t\t\t\titemId,\n\t\t\t],\n\t\t);\n\t}\n\n\tpublic addItems (\n\t\tvaluesArray: Partial<RequestColumnsFieldMap<ItemTypeType, RequestColumns>>[],\n\t): Promise<ChangesDeltaResult> {\n\t\tconst changesDelta = this.transaction.createChangesDelta();\n\n\t\tif (this.entry.parent !== null) {\n\t\t\tconst parentFields = this.factory.itemEntryService.getLinkFieldsByParent(\n\t\t\t\tthis.entry.parent,\n\t\t\t\tthis.entry.itemType,\n\t\t\t);\n\n\t\t\tfor (const values of valuesArray) {\n\t\t\t\tfor (const columnId in parentFields) {\n\t\t\t\t\tvalues[columnId as string] = parentFields[columnId];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn changesDelta\n\t\t\t.setItemsCreated(\n\t\t\t\tthis.entry.itemType,\n\t\t\t\tvaluesArray,\n\t\t\t)\n\t\t\t.then(\n\t\t\t\t() => this.transaction.applyChangesDelta(\n\t\t\t\t\tchangesDelta,\n\t\t\t\t),\n\t\t\t);\n\t}\n\n\tpublic addItem (\n\t\tvalues: Partial<FieldMap<ItemTypeType>>,\n\t): Promise<ChangesDeltaResult> {\n\t\treturn this.addItems(\n\t\t\t[\n\t\t\t\tvalues,\n\t\t\t],\n\t\t);\n\t}\n\n\tpublic getIdArray (): ItemId[] {\n\t\treturn this.items.map(\n\t\t\titemResource => itemResource.entry.itemId,\n\t\t);\n\t}\n\n\t// todo[type] Items can be undefined, but this gives a lot of errors frontend\n\tpublic getItemById (\n\t\titemId: ItemId,\n\t): ItemResource<ItemTypeType, RequestColumns, Children> {\n\t\ttry {\n\t\t\tconst itemEntry = this.transaction.getLocalItemEntryByItemId(\n\t\t\t\tthis.itemType,\n\t\t\t\titemId,\n\t\t\t);\n\n\t\t\treturn this.itemEntryIdMap[itemEntry.id];\n\t\t} catch (exception) {\n\t\t\t// This method is also used to test whether an item is included in the collection. It could also be it is\n\t\t\t// not cached at all.\n\t\t\tif (exception instanceof ItemNotFoundException) {\n\t\t\t\t// @ts-ignore\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\tthrow exception;\n\t\t}\n\t}\n\n\tpublic triggerCollectionChangesListeners (\n\t\tchangedItemResources: AddedRemovedItemResources<ItemResource<ItemTypeType, RequestColumns, Children>> & {\n\t\t\tchangedItems?: undefined,\n\t\t},\n\t\tsourceChangesDelta: null,\n\t\titemIdConversionMap: ItemIdConversionMap | undefined,\n\t\tisCalledAfterSocketUpdate: boolean,\n\t\tisInitialCall: boolean,\n\t\tcollectionChangesAccumulator: AggregatedChangesByListener | null,\n\t): void;\n\n\tpublic triggerCollectionChangesListeners (\n\t\tchangedItemResources: AddedRemovedItemResources<ItemResource<ItemTypeType, RequestColumns, Children>> & {\n\t\t\tchangedItems: ItemResource<ItemTypeType, RequestColumns, Children>[],\n\t\t},\n\t\tsourceChangesDelta: ParentChangesDelta,\n\t\titemIdConversionMap: ItemIdConversionMap | undefined,\n\t\tisCalledAfterSocketUpdate: boolean,\n\t\tisInitialCall: boolean,\n\t\tcollectionChangesAccumulator: AggregatedChangesByListener | null,\n\t): void;\n\n\t/**\n\t * Handles the deprecated `onAdd`, `onRemove` and `onChange` callbacks, as well as collection changes listeners.\n\t *\n\t * @param sourceChangesDelta -`previous` is read from this changes delta when constructing a changes listener context.\n\t * Can be `null` when there are no changed items.\n\t * @param aggregatedListenerChangesAccumulator - Stores collection changes in order for aggregated collection changes\n\t * listeners to be called at a later moment in time. When `null`, aggregated collection changes listeners are\n\t * called immediately.\n\t */\n\tpublic triggerCollectionChangesListeners (\n\t\t{\n\t\t\taddedItems,\n\t\t\tchangedItems,\n\t\t\tremovedItems,\n\t\t}: AddedRemovedItemResources<ItemResource<ItemTypeType, RequestColumns, Children>> & {\n\t\t\tchangedItems?: ItemResource<ItemTypeType, RequestColumns, Children>[],\n\t\t},\n\t\tsourceChangesDelta: ParentChangesDelta | null,\n\t\titemIdConversionMap: ItemIdConversionMap | undefined,\n\t\tisCalledAfterSocketUpdate: boolean,\n\t\tisInitialCall: boolean,\n\t\taggregatedListenerChangesAccumulator: AggregatedChangesByListener | null,\n\t): void {\n\t\tif (\n\t\t\tthis.onAddCallbacks.length > 0\n\t\t\t&& addedItems.length > 0\n\t\t) {\n\t\t\ttry {\n\t\t\t\tfor (const callback of this.onAddCallbacks) {\n\t\t\t\t\tcallback(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\titemResources: addedItems,\n\t\t\t\t\t\t\tcollectionResource: this,\n\t\t\t\t\t\t\tisInitialCall,\n\t\t\t\t\t\t\tisCalledAfterSocketUpdate,\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis.factory.errorHandler.logError(\n\t\t\t\t\terror,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (\n\t\t\tthis.onRemoveCallbacks.length > 0\n\t\t\t&& removedItems.length > 0\n\t\t) {\n\t\t\tconst itemEntries = removedItems.map(\n\t\t\t\titemResource => itemResource.entry,\n\t\t\t);\n\n\t\t\ttry {\n\t\t\t\tfor (const callback of this.onRemoveCallbacks) {\n\t\t\t\t\tcallback(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\titemEntries,\n\t\t\t\t\t\t\titemResources: removedItems,\n\t\t\t\t\t\t\tcollectionResource: this,\n\t\t\t\t\t\t\tisCalledAfterSocketUpdate,\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis.factory.errorHandler.logError(\n\t\t\t\t\terror,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst aggregatedChangesListeners = this.getAggregatedChangesListeners();\n\t\tconst itemChangesListenerContexts: CollectionItemChangesListenerContext<this>[] = [];\n\n\t\tif (\n\t\t\t(\n\t\t\t\tthis.onChangeCallbacks.length > 0\n\t\t\t\t|| aggregatedChangesListeners.size > 0\n\t\t\t)\n\t\t\t&& changedItems !== undefined\n\t\t\t&& changedItems.length > 0\n\t\t) {\n\t\t\tfor (const changedItem of changedItems) {\n\t\t\t\tconst itemEntryId = changedItem.entry.id;\n\n\t\t\t\t// In some instances, the collection can already contain items that appear in 'created' changes. These\n\t\t\t\t// will be interpreted as changed items initially. This happens when a cached query is copied from a\n\t\t\t\t// parent transaction before the changes originating from the back-end request are propagated to the\n\t\t\t\t// transaction on which the collection was requested.\n\t\t\t\t// TODO: A solution to this would be to only copy a cached query from a parent transaction when it would\n\t\t\t\t// differ from the one on the child transaction.\n\t\t\t\tif (sourceChangesDelta!.created[itemEntryId] !== undefined) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst previous = sourceChangesDelta!.updated[itemEntryId].previous as Partial<FieldMap<ItemTypeType>> | null;\n\n\t\t\t\t// `previous` can be `null` when there are no changes on the current transaction. There\n\t\t\t\t// might be changes on the parent transaction, or an empty might have been used to add items to\n\t\t\t\t// newly created cached queries on the server cache.\n\t\t\t\tif (previous === null) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\titemChangesListenerContexts.push(\n\t\t\t\t\tnew CollectionItemChangesListenerContext(\n\t\t\t\t\t\tthis,\n\t\t\t\t\t\tchangedItem,\n\t\t\t\t\t\tisCalledAfterSocketUpdate,\n\t\t\t\t\t\tprevious,\n\t\t\t\t\t\titemIdConversionMap,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tfor (const callback of this.onChangeCallbacks) {\n\t\t\t\t\tfor (const itemChangesListenerContext of itemChangesListenerContexts) {\n\t\t\t\t\t\tcallback(\n\t\t\t\t\t\t\titemChangesListenerContext,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis.factory.errorHandler.logError(\n\t\t\t\t\terror,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (\n\t\t\taggregatedChangesListeners.size === 0\n\t\t\t// This could occur when no previous values are available for changed items (see comment above), or,\n\t\t\t// for limited collection resources, when an item matches the query but falls outside the limit.\n\t\t\t|| (\n\t\t\t\taddedItems.length === 0\n\t\t\t\t&& removedItems.length === 0\n\t\t\t\t&& itemChangesListenerContexts.length === 0\n\t\t\t)\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst changesListenerContext: CollectionChangesListenerContext<this> = {\n\t\t\taddedItems,\n\t\t\tchangedItems: itemChangesListenerContexts,\n\t\t\tremovedItems,\n\t\t\tcollectionResource: this,\n\t\t};\n\n\t\tif (aggregatedListenerChangesAccumulator === null) {\n\t\t\tfor (const aggregatedChangesListener of aggregatedChangesListeners) {\n\t\t\t\taggregatedChangesListener(\n\t\t\t\t\t{\n\t\t\t\t\t\t[this.itemType]: [\n\t\t\t\t\t\t\tchangesListenerContext,\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t\t{},\n\t\t\t\t\tisCalledAfterSocketUpdate,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const aggregatedChangesListener of aggregatedChangesListeners) {\n\t\t\tlet aggregatedChanges = aggregatedListenerChangesAccumulator.get(\n\t\t\t\taggregatedChangesListener,\n\t\t\t);\n\n\t\t\tif (aggregatedChanges === undefined) {\n\t\t\t\taggregatedListenerChangesAccumulator.set(\n\t\t\t\t\taggregatedChangesListener,\n\t\t\t\t\taggregatedChanges = {\n\t\t\t\t\t\titem: {},\n\t\t\t\t\t\tcollection: {},\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t(aggregatedChanges.collection[this.itemType] as CollectionChangesListenerContext<this>[]) ??= [];\n\n\t\t\t(aggregatedChanges.collection[this.itemType] as CollectionChangesListenerContext<this>[]).push(\n\t\t\t\tchangesListenerContext,\n\t\t\t);\n\t\t}\n\t}\n\n\tpublic forEach (\n\t\tcallback: (itemResource: ItemResource<ItemTypeType, RequestColumns, Children>) => void,\n\t): void {\n\t\tconst itemResources = this.items;\n\n\t\tfor (const itemResource of itemResources) {\n\t\t\tcallback(\n\t\t\t\titemResource,\n\t\t\t);\n\t\t}\n\t}\n\n\tpublic filter (\n\t\tcallback: (itemResource: ItemResource<ItemTypeType, RequestColumns, Children>) => boolean,\n\t): ItemResource<ItemTypeType, RequestColumns, Children>[] {\n\t\tconst itemResources = this.items;\n\t\tconst result: ItemResource<ItemTypeType, RequestColumns, Children>[] = [];\n\n\t\tfor (const itemResource of itemResources) {\n\t\t\tif (callback(\n\t\t\t\titemResource,\n\t\t\t)) {\n\t\t\t\tresult.push(\n\t\t\t\t\titemResource,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic first (\n\t\tcallback: (itemResource: ItemResource<ItemTypeType, RequestColumns, Children>) => boolean,\n\t): ItemResource<ItemTypeType, RequestColumns, Children> | null {\n\t\tconst itemResources = this.items;\n\n\t\tfor (const itemResource of itemResources) {\n\t\t\tif (callback(\n\t\t\t\titemResource,\n\t\t\t)) {\n\t\t\t\treturn itemResource;\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tpublic some (\n\t\tcallback: (itemResource: ItemResource<ItemTypeType, RequestColumns, Children>) => boolean,\n\t): boolean {\n\t\treturn this.first(\n\t\t\tcallback,\n\t\t) !== null;\n\t}\n\n\tpublic groupBy (\n\t\targument: string | ((itemResource: ItemResource<ItemTypeType, RequestColumns, Children>) => string | null),\n\t): {\n\t\t[key: string]: ItemResource<ItemTypeType, RequestColumns, Children>[],\n\t} {\n\t\tconst itemsResources = this.items;\n\t\tconst result: {[key: string]: ItemResource<ItemTypeType, RequestColumns, Children>[],} = {};\n\n\t\tif (typeof argument === 'string') {\n\t\t\tfor (const itemResource of itemsResources) {\n\t\t\t\tif (itemResource.entry.columns.response[this.entry.itemType][argument] === undefined) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Trying to group on a column not in one of the items in this collection! (column '${argument}', item ${itemResource.entry.itemType}:${itemResource.entry.itemId})`,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tconst value = itemResource.fields[argument];\n\n\t\t\t\tif (result[value] === undefined) {\n\t\t\t\t\tresult[value] = [];\n\t\t\t\t}\n\n\t\t\t\tresult[value].push(\n\t\t\t\t\titemResource,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (typeof argument === 'function') {\n\t\t\tfor (const itemResource of itemsResources) {\n\t\t\t\tconst value = argument(\n\t\t\t\t\titemResource,\n\t\t\t\t);\n\n\t\t\t\tif (value === null) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (result[value] === undefined) {\n\t\t\t\t\tresult[value] = [];\n\t\t\t\t}\n\n\t\t\t\tresult[value].push(\n\t\t\t\t\titemResource,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic map<U> (\n\t\targument: string | ((itemResource: ItemResource<ItemTypeType, RequestColumns, Children>) => U),\n\t): U[] {\n\t\tconst itemResources = this.items;\n\t\tconst length = itemResources.length;\n\t\tconst result = new Array(\n\t\t\tlength,\n\t\t);\n\n\t\tif (typeof argument === 'string') {\n\t\t\tfor (let i = 0; i < length; i++) {\n\t\t\t\tresult[i] = itemResources[i].fields[argument];\n\t\t\t}\n\t\t}\n\n\t\tif (typeof argument === 'function') {\n\t\t\tfor (let i = 0; i < length; i++) {\n\t\t\t\tresult[i] = argument(\n\t\t\t\t\titemResources[i],\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic reduce<U> (\n\t\tcallback: (\n\t\t\titemResource: ItemResource<ItemTypeType, RequestColumns, Children>,\n\t\t\tvalue: U,\n\t\t) => U,\n\t\tvalue: U,\n\t): U {\n\t\tconst itemResources = this.items;\n\n\t\tfor (const itemResource of itemResources) {\n\t\t\tvalue = callback(\n\t\t\t\titemResource,\n\t\t\t\tvalue,\n\t\t\t);\n\t\t}\n\n\t\treturn value;\n\t}\n\n\t/**\n\t * @description\n\t * Removes the {@link CollectionResource CollectionResource} from the transaction, preventing the\n\t * {@link CollectionResource.options.onAdd onAdd} and {@link CollectionResource.options.onRemove onRemove} callbacks\n\t * from being called. You should call this function when the resource is no longer needed.\n\t *\n\t * @remark\n\t * - Does not remove cached queries;\n\t * - Does not revert changes on the items themselves.\n\t */\n\tpublic clearResource (): void {\n\t\tthis.aggregatedChangesListeners = [];\n\t\tthis.onAddCallbacks = [];\n\t\tthis.onRemoveCallbacks = [];\n\t\tthis.onChangeCallbacks = [];\n\n\t\tif (this.options.children !== null) {\n\t\t\tfor (const itemResource of this.items) {\n\t\t\t\titemResource.clearChildCollections();\n\t\t\t}\n\t\t}\n\n\t\tthis.transaction.cachedQueryHandler.clearCollectionResource(\n\t\t\tthis,\n\t\t);\n\t}\n\n\t/**\n\t * Updates the items in the collection resource, given the results of a query matching cycle.\n\t *\n\t * Note: In order to reduce back-end requests for non-locally matchable queries, `fittingItemEntries` may contain item\n\t * entries that are already present in the collection, and `nonFittingItemEntries` may contain item entries that\n\t * are not present in the collection.\n\t *\n\t * @returns A {@link CollectionResourceChanges} object, which can be used to trigger collection changes listeners.\n\t */\n\tpublic async handleMatchedItemEntries (\n\t\tfittingItemEntries: Iterable<ItemEntry<ItemTypeType>>,\n\t\tnonFittingItemEntries: Set<ItemEntry<ItemTypeType>> | undefined,\n\t\tclearChildCollectionResources: boolean,\n\t): Promise<CollectionItemResourceChanges<CollectionResource<ItemTypeType, RequestColumns, Children>>> {\n\t\tconst {\n\t\t\titemEntriesToBeAdded,\n\t\t\titemEntriesToBeRemovedSet,\n\t\t\tchangedItemResources,\n\t\t} = this.getCollectionItemEntryChanges(\n\t\t\tfittingItemEntries,\n\t\t\tnonFittingItemEntries,\n\t\t);\n\n\t\tconst addedRemovedItemResources = await this.updateItemsProperty(\n\t\t\titemEntriesToBeAdded,\n\t\t\titemEntriesToBeRemovedSet,\n\t\t\tclearChildCollectionResources,\n\t\t);\n\n\t\treturn {\n\t\t\tcollectionResource: this,\n\t\t\taddedItems: addedRemovedItemResources.addedItems,\n\t\t\tremovedItems: addedRemovedItemResources.removedItems,\n\t\t\tchangedItems: changedItemResources,\n\t\t};\n\t}\n\n\t/**\n\t * We type this loosely to prevent TypeScript inferring a complex type when comparing collection resources.\n\t * @internal\n\t */\n\tpublic getAggregatedChangesListeners<ChangesListeners extends Set<AggregatedChangesListenerFunction<any, any>>> (\n\t\taccumulator: ChangesListeners = new Set() as ChangesListeners,\n\t): ChangesListeners {\n\t\t// We're using a set here to prevent issues when a listener has (erroneously) been declared on a parent as well\n\t\t// as a child collection.\n\t\tfor (const listener of this.aggregatedChangesListeners) {\n\t\t\taccumulator.add(\n\t\t\t\tlistener,\n\t\t\t);\n\t\t}\n\n\t\tthis.parentCollection?.getAggregatedChangesListeners(\n\t\t\taccumulator,\n\t\t);\n\n\t\tthis.parentItem?.getAggregatedChangesListeners(\n\t\t\taccumulator,\n\t\t);\n\n\t\treturn accumulator;\n\t}\n\n\tprotected getCollectionItemEntryChanges (\n\t\tfittingItemEntries: Iterable<ItemEntry<ItemTypeType>>,\n\t\tnonFittingItemEntries: Set<ItemEntry<ItemTypeType>> | undefined,\n\t): {\n\t\titemEntriesToBeAdded: ItemEntry<ItemTypeType>[],\n\t\titemEntriesToBeRemovedSet: Set<ItemEntry<ItemTypeType>>,\n\t\tchangedItemResources: ItemResource<ItemTypeType, RequestColumns, Children>[],\n\t} {\n\t\tconst itemEntriesToBeAdded: ItemEntry<ItemTypeType>[] = [];\n\t\tconst itemEntriesToBeRemovedSet: Set<ItemEntry<ItemTypeType>> = new Set();\n\t\tconst changedItemResources: ItemResource<ItemTypeType, RequestColumns, Children>[] = [];\n\n\t\tfor (const fittingItemEntry of fittingItemEntries) {\n\t\t\tconst itemResource = this.itemEntryIdMap[fittingItemEntry.id];\n\n\t\t\tif (itemResource === undefined) {\n\t\t\t\titemEntriesToBeAdded.push(\n\t\t\t\t\tfittingItemEntry,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tchangedItemResources.push(\n\t\t\t\t\titemResource,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (nonFittingItemEntries !== undefined) {\n\t\t\tfor (const nonFittingItemEntry of nonFittingItemEntries) {\n\t\t\t\tif (this.itemEntryIdMap[nonFittingItemEntry.id] !== undefined) {\n\t\t\t\t\titemEntriesToBeRemovedSet.add(\n\t\t\t\t\t\tnonFittingItemEntry,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\titemEntriesToBeAdded,\n\t\t\titemEntriesToBeRemovedSet,\n\t\t\tchangedItemResources,\n\t\t};\n\t}\n\n\t/**\n\t * Removes the item resources associated with the passed item entries from the `items` array, while keeping the\n\t * reference intact.\n\t *\n\t * Note: This method does not call any listeners, nor does it re-order the items.\n\t *\n\t * @param itemEntriesToBeRemovedSet May also contain item entries that are not included in the collection at all.\n\t * @returns The {@link ItemResource ItemResources} that were removed from the {@link CollectionResource collection}.\n\t */\n\tprotected removeItemResources (\n\t\titemEntriesToBeRemovedSet: Set<ItemEntry<ItemTypeType>>,\n\t\tclearChildCollectionResources: boolean,\n\t): ItemResource<ItemTypeType, RequestColumns, Children>[] {\n\t\tif (itemEntriesToBeRemovedSet.size === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst filteredItemResources: ItemResource<ItemTypeType, RequestColumns, Children>[] = [];\n\t\tconst removedItemResources: ItemResource<ItemTypeType, RequestColumns, Children>[] = [];\n\n\t\tfor (const itemResource of this.items) {\n\t\t\tconst itemEntry = itemResource.entry;\n\n\t\t\tif (\n\t\t\t\t!itemEntriesToBeRemovedSet.has(\n\t\t\t\t\titemEntry,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tfilteredItemResources.push(\n\t\t\t\t\titemResource,\n\t\t\t\t);\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tremovedItemResources.push(\n\t\t\t\titemResource,\n\t\t\t);\n\n\t\t\tdelete this.itemEntryIdMap[itemEntry.id];\n\n\t\t\tif (clearChildCollectionResources) {\n\t\t\t\titemResource.clearChildCollections();\n\t\t\t}\n\t\t}\n\n\t\tthis.items.length = filteredItemResources.length;\n\n\t\tfor (let i = 0; i < filteredItemResources.length; i++) {\n\t\t\tthis.items[i] = filteredItemResources[i];\n\t\t}\n\n\t\treturn removedItemResources;\n\t}\n\n\t/**\n\t * Updates the `items` property of the collection resource, consisting of item resources representing the items in\n\t * the collection.\n\t *\n\t * Note that for some added item entries, no item resource might be returned, as some of the items might already\n\t * have been added while the child collections where requested.\n\t */\n\tprotected async updateItemsProperty (\n\t\titemEntriesToBeAdded: ItemEntry<ItemTypeType>[],\n\t\titemEntriesToBeRemovedSet: Set<ItemEntry<ItemTypeType>>,\n\t\tclearChildCollectionResources: boolean,\n\t): Promise<AddedRemovedItemResources<ItemResource<ItemTypeType, RequestColumns, Children>>> {\n\t\tif (\n\t\t\tthis.options.children === undefined\n\t\t\t|| itemEntriesToBeAdded.length === 0\n\t\t) {\n\t\t\treturn {\n\t\t\t\taddedItems: this.addItemResources(\n\t\t\t\t\titemEntriesToBeAdded,\n\t\t\t\t\t{},\n\t\t\t\t),\n\t\t\t\tremovedItems: this.removeItemResources(\n\t\t\t\t\titemEntriesToBeRemovedSet,\n\t\t\t\t\tclearChildCollectionResources,\n\t\t\t\t),\n\t\t\t};\n\t\t}\n\n\t\tconst cachedQueryItemTuples = await this.transaction.cachedQueryHandler.__fetchChildCachedQueryItems(\n\t\t\tthis.entry.itemType,\n\t\t\titemEntriesToBeAdded.map(\n\t\t\t\titemEntry => itemEntry.itemId,\n\t\t\t),\n\t\t\tthis.options.children,\n\t\t);\n\n\t\t// While the child collections were being fetched the items could have been added already.\n\t\tconst nonIncludedItemEntriesMap: Map<ItemId, ItemEntry<ItemTypeType>> = new Map();\n\n\t\tfor (const itemEntry of itemEntriesToBeAdded) {\n\t\t\tif (this.itemEntryIdMap[itemEntry.id] === undefined) {\n\t\t\t\tnonIncludedItemEntriesMap.set(\n\t\t\t\t\titemEntry.itemId,\n\t\t\t\t\titemEntry,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tlet filteredCachedQueryItemTypeTuples: CachedQueryItemsItemTypeTuple<ApiItemType>[];\n\n\t\tif (nonIncludedItemEntriesMap.size === itemEntriesToBeAdded.length) {\n\t\t\tfilteredCachedQueryItemTypeTuples = cachedQueryItemTuples;\n\t\t} else {\n\t\t\t// We're also filtering the cached query items to ensure no child collection resources are created\n\t\t\t// for items that will not be added to the collection.\n\t\t\tfilteredCachedQueryItemTypeTuples = [];\n\n\t\t\tfor (const cachedQueryItemTypeTuple of cachedQueryItemTuples) {\n\t\t\t\tconst filteredCachedQueryItemTuples: ParentCachedQueryItemTuple<ApiItemType>[] = [];\n\n\t\t\t\tfor (const cachedQueryItemTuple of cachedQueryItemTypeTuple.cachedQueryItemTuples) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tnonIncludedItemEntriesMap.has(\n\t\t\t\t\t\t\tcachedQueryItemTuple.options.parent!.itemId,\n\t\t\t\t\t\t)\n\t\t\t\t\t) {\n\t\t\t\t\t\tfilteredCachedQueryItemTuples.push(\n\t\t\t\t\t\t\tcachedQueryItemTuple,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfilteredCachedQueryItemTypeTuples.push(\n\t\t\t\t\t{\n\t\t\t\t\t\titemType: cachedQueryItemTypeTuple.itemType,\n\t\t\t\t\t\tcachedQueryItemTuples: filteredCachedQueryItemTuples,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// `addItemResources` and `removeItemResources` should be called synchronously, as we rely on\n\t\t// `itemEntryMap` to figure out if items have been added while waiting for child cached queries to resolve.\n\t\treturn {\n\t\t\taddedItems: this.addItemResources(\n\t\t\t\t[\n\t\t\t\t\t...nonIncludedItemEntriesMap.values(),\n\t\t\t\t],\n\t\t\t\tthis.factory.constructChildCollectionResources(\n\t\t\t\t\tfilteredCachedQueryItemTypeTuples,\n\t\t\t\t\tthis,\n\t\t\t\t\tthis.transaction,\n\t\t\t\t),\n\t\t\t),\n\t\t\tremovedItems: this.removeItemResources(\n\t\t\t\titemEntriesToBeRemovedSet,\n\t\t\t\tclearChildCollectionResources,\n\t\t\t),\n\t\t};\n\t}\n\n\t/**\n\t * Creates item resources and adds them to the `items` array. This function is also called when the collection\n\t * resource is constructed.\n\t *\n\t * Note: This method does not call any listeners.\n\t *\n\t * @param itemEntriesToBeAdded - The item entries are assumed not to be in the collection yet.\n\t */\n\tprotected addItemResources (\n\t\titemEntriesToBeAdded: Iterable<ItemEntry<ItemTypeType>>,\n\t\tchildCollections: ParentIdMap<Children>,\n\t): ItemResource<ItemTypeType, RequestColumns, Children>[] {\n\t\tconst itemResourcesToBeAdded = this.transaction.createItemResources<ItemTypeType, RequestColumns, Children>(\n\t\t\titemEntriesToBeAdded,\n\t\t\tchildCollections,\n\t\t\t// We don't want to pass the onChange down, as that would make a collection changes listener also listen to individual\n\t\t\t// item changes, which we already handle in `handleMatchedItemEntries`.\n\t\t\tundefined,\n\t\t\tthis.options.abortSignal,\n\t\t);\n\n\t\tfor (const itemResource of itemResourcesToBeAdded) {\n\t\t\tthis.items.push(\n\t\t\t\titemResource,\n\t\t\t);\n\t\t\tthis.itemEntryIdMap[itemResource.entry.id] = itemResource;\n\t\t}\n\n\t\treturn itemResourcesToBeAdded;\n\t}\n\n\tprotected async fetchCachedQuery (\n\t\toptions: CollectionOptions<ItemTypeType> = this.options,\n\t): Promise<CachedQueryItem<ItemTypeType>> {\n\t\tconst cachedQueryHandler = this.transaction.cachedQueryHandler;\n\n\t\t// We're calling `__fetchParentItemEntriesByQueryData` directly here because at this point the collection options\n\t\t// have already been processed. Processing collections options constructs a query, which should happen only once.\n\t\tconst parentCachedQueryItemTuple = await cachedQueryHandler.__fetchParentItemEntriesByQueryData(\n\t\t\tthis.itemType,\n\t\t\toptions,\n\t\t\tthis.factory.requestColumnsOperationsCacheFactory.construct(\n\t\t\t\tthis.itemType,\n\t\t\t\tthis.options.columns,\n\t\t\t),\n\t\t\tthis.entry.query,\n\t\t);\n\n\t\treturn parentCachedQueryItemTuple.cachedQueryItem;\n\t}\n\n\tprivate registerOptionsChangesListeners (): void {\n\t\tconst {\n\t\t\tonAdd,\n\t\t\tonRemove,\n\t\t\tonChange,\n\t\t\tchangesListener,\n\t\t} = this.options;\n\n\t\tif (onAdd !== undefined) {\n\t\t\tthis.onAddCallbacks.push(\n\t\t\t\targs => {\n\t\t\t\t\tonAdd(\n\t\t\t\t\t\targs.itemResources,\n\t\t\t\t\t\targs.collectionResource,\n\t\t\t\t\t\targs.isInitialCall,\n\t\t\t\t\t\targs.isCalledAfterSocketUpdate,\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\tif (onRemove !== undefined) {\n\t\t\tthis.onRemoveCallbacks.push(\n\t\t\t\targs => {\n\t\t\t\t\tonRemove(\n\t\t\t\t\t\targs.itemEntries,\n\t\t\t\t\t\targs.collectionResource,\n\t\t\t\t\t\targs.isCalledAfterSocketUpdate,\n\t\t\t\t\t\targs.itemResources,\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\tif (onChange !== undefined) {\n\t\t\tthis.onChangeCallbacks.push(\n\t\t\t\tonChange,\n\t\t\t);\n\t\t}\n\n\t\tif (changesListener !== undefined) {\n\t\t\tthis.aggregatedChangesListeners.push(\n\t\t\t\tchangesListener,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate __registerCallback<T> (\n\t\tarr: T[],\n\t\tcallback: T,\n\t): DeregFunction {\n\t\tarr.push(\n\t\t\tcallback,\n\t\t);\n\n\t\treturn () => {\n\t\t\tconst index = arr.indexOf(\n\t\t\t\tcallback,\n\t\t\t);\n\n\t\t\tif (index > -1) {\n\t\t\t\tarr.splice(\n\t\t\t\t\tindex,\n\t\t\t\t\t1,\n\t\t\t\t);\n\t\t\t}\n\t\t};\n\t}\n\n}\n","import { ApiEnumApiType, ApiItemType } from '@rentman/backend-types';\nimport { AddedRemovedItemResources, ApiRequestColumnArray, ChildCollectionResources, CollectionResource, ItemEntry, ItemResource, ParentIdMap, RootCollectionOptionsWithOrder } from '../internal';\n\ntype CompareFunction<ValueType> = (\n\tvalue1: ValueType,\n\tvalue2: ValueType,\n) => number;\n\nconst compareNumberFn: CompareFunction<unknown> = (\n\tvalue1,\n\tvalue2,\n) => Number(\n\tvalue1,\n) - Number(\n\tvalue2,\n);\n\nconst compareStringFn: CompareFunction<string> = (\n\tvalue1,\n\tvalue2,\n): number => value1.localeCompare(\n\tvalue2,\n);\n\nfunction getSortCompareFunction (\n\tapiType: ApiEnumApiType,\n): CompareFunction<any> {\n\tswitch (apiType) {\n\t\tcase ApiEnumApiType.TYPE_NUMBER:\n\t\tcase ApiEnumApiType.TYPE_DATETIME:\n\t\tcase ApiEnumApiType.TYPE_TIMESTAMP:\n\t\tcase ApiEnumApiType.TYPE_TIMESTAMP_MS:\n\t\tcase ApiEnumApiType.TYPE_DATE:\n\t\tcase ApiEnumApiType.TYPE_DURATION:\n\t\tcase ApiEnumApiType.TYPE_VOLUME:\n\t\tcase ApiEnumApiType.TYPE_WEIGHT:\n\t\tcase ApiEnumApiType.TYPE_DIMENSION:\n\t\tcase ApiEnumApiType.TYPE_PRICE:\n\t\tcase ApiEnumApiType.TYPE_DOUBLE:\n\t\tcase ApiEnumApiType.TYPE_INT:\n\t\tcase ApiEnumApiType.TYPE_CURRENT:\n\t\tcase ApiEnumApiType.TYPE_POWER:\n\t\tcase ApiEnumApiType.TYPE_DISTANCE:\n\t\tcase ApiEnumApiType.TYPE_ORDER:\n\t\t\treturn compareNumberFn;\n\t\tcase ApiEnumApiType.TYPE_TEXT:\n\t\tcase ApiEnumApiType.TYPE_LONGTEXT:\n\t\tcase ApiEnumApiType.TYPE_HTML:\n\t\tcase ApiEnumApiType.TYPE_TIME:\n\t\t\treturn compareStringFn;\n\t\tdefault:\n\t\t\tthrow new Error(\n\t\t\t\t`ApiType ${apiType} does not have a sort function`,\n\t\t\t);\n\t}\n}\n\nexport class OrderedCollectionResource<\n\tItemTypeType extends ApiItemType,\n\tRequestColumns extends ApiRequestColumnArray<ItemTypeType>,\n\tChildren extends ChildCollectionResources | undefined = undefined\n>\n\textends CollectionResource<ItemTypeType, RequestColumns, Children> {\n\n\tpublic declare options: RootCollectionOptionsWithOrder<ItemTypeType>;\n\n\tpublic override initializeItems (\n\t\tinitialItemEntries: ItemEntry<ItemTypeType>[],\n\t\tchildCollectionResourceMap: ParentIdMap<Children>,\n\t): void {\n\t\tconst itemResources = this.addItemResources(\n\t\t\tinitialItemEntries,\n\t\t\tchildCollectionResourceMap,\n\t\t);\n\n\t\t// We ensure the items are sorted before calling the change listeners\n\t\tthis.sortItemResources();\n\n\t\tif (this.options.callOnAddWithInitialItems === true) {\n\t\t\tthis.triggerCollectionChangesListeners(\n\t\t\t\t{\n\t\t\t\t\taddedItems: itemResources,\n\t\t\t\t\tremovedItems: [],\n\t\t\t\t},\n\t\t\t\tnull,\n\t\t\t\tundefined,\n\t\t\t\tfalse,\n\t\t\t\ttrue,\n\t\t\t\tnull,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Note that `updateItemsProperty` is called whenever items are updated, so there's no reason to register a listener\n\t * as well.\n\t */\n\tprotected override async updateItemsProperty (\n\t\titemEntriesToBeAdded: ItemEntry<ItemTypeType>[],\n\t\titemEntriesToBeRemovedSet: Set<ItemEntry<ItemTypeType>>,\n\t\tclearChildCollectionResources: boolean,\n\t): Promise<AddedRemovedItemResources<ItemResource<ItemTypeType, RequestColumns, Children>>> {\n\t\tconst addedRemovedItemResources = await super.updateItemsProperty(\n\t\t\titemEntriesToBeAdded,\n\t\t\titemEntriesToBeRemovedSet,\n\t\t\tclearChildCollectionResources,\n\t\t);\n\n\t\tthis.sortItemResources();\n\n\t\treturn addedRemovedItemResources;\n\t}\n\n\tprotected getSortCompareTuple (): {\n\t\tcompareFunction: CompareFunction<unknown>,\n\t\tisDescending: boolean,\n\t} {\n\t\tconst orderOption = this.options.order;\n\n\t\treturn {\n\t\t\tcompareFunction: getSortCompareFunction(\n\t\t\t\tthis.columns[this.itemType][orderOption.field as ApiItemType].type,\n\t\t\t),\n\t\t\tisDescending: orderOption.order === undefined\n\t\t\t\t|| orderOption.order === 'desc',\n\t\t};\n\t}\n\n\tprotected sortItemResources (): void {\n\t\tconst {\n\t\t\tcompareFunction,\n\t\t\tisDescending,\n\t\t} = this.getSortCompareTuple();\n\n\t\tconst field = this.options.order.field;\n\n\t\tthis.items.sort(\n\t\t\t(\n\t\t\t\titemResourceA: ItemResource<any, any, any>,\n\t\t\t\titemResourceB: ItemResource<any, any, any>,\n\t\t\t) => {\n\t\t\t\tlet compareResult = compareFunction(\n\t\t\t\t\titemResourceA.fields[field],\n\t\t\t\t\titemResourceB.fields[field],\n\t\t\t\t);\n\n\t\t\t\tif (compareResult === 0) {\n\t\t\t\t\tcompareResult = itemResourceA.fields.id - itemResourceB.fields.id;\n\t\t\t\t}\n\n\t\t\t\treturn isDescending\n\t\t\t\t\t? -compareResult\n\t\t\t\t\t: compareResult;\n\t\t\t},\n\t\t);\n\t}\n\n\tprotected sortItemEntries (\n\t\titemEntries: ItemEntry<ItemTypeType>[],\n\t): ItemEntry<ItemTypeType>[] {\n\t\tconst {\n\t\t\tcompareFunction,\n\t\t\tisDescending,\n\t\t} = this.getSortCompareTuple();\n\n\t\tconst field = this.options.order.field;\n\t\tconst itemHandler = this.transaction.itemHandler;\n\n\t\treturn itemEntries.sort(\n\t\t\t(\n\t\t\t\titemEntryA,\n\t\t\t\titemEntryB,\n\t\t\t) => {\n\t\t\t\tlet compareResult = compareFunction(\n\t\t\t\t\titemHandler.lookUpItemField(\n\t\t\t\t\t\titemEntryA,\n\t\t\t\t\t\tfield,\n\t\t\t\t\t),\n\t\t\t\t\titemHandler.lookUpItemField(\n\t\t\t\t\t\titemEntryB,\n\t\t\t\t\t\tfield,\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\tif (compareResult === 0) {\n\t\t\t\t\tcompareResult = itemEntryA.itemId - itemEntryB.itemId;\n\t\t\t\t}\n\n\t\t\t\treturn isDescending\n\t\t\t\t\t? -compareResult\n\t\t\t\t\t: compareResult;\n\t\t\t},\n\t\t);\n\t}\n\n}\n","import { ApiItemType } from '@rentman/backend-types';\nimport { ApiRequestColumnArray, ChildCollectionResources, CollectionItemResourceChanges, CollectionResource, ItemEntry, OrderedCollectionResource, RootCollectionOptionsWithLimit } from '../internal';\n\nexport class LimitedCollectionResource<\n\tItemTypeType extends ApiItemType,\n\tRequestColumns extends ApiRequestColumnArray<ItemTypeType>,\n\tChildren extends ChildCollectionResources | undefined = undefined\n>\n\textends OrderedCollectionResource<ItemTypeType, RequestColumns, Children> {\n\n\tpublic declare options: RootCollectionOptionsWithLimit<ItemTypeType>;\n\n\tpublic async setLimit (\n\t\tnewLimit: number,\n\t): Promise<void> {\n\t\tconst previousLimit = this.options.order.limit;\n\n\t\tthis.options.order.limit = newLimit;\n\n\t\tlet itemEntriesToBeAdded: ItemEntry<ItemTypeType>[] = [];\n\t\tlet itemEntriesToBeRemovedSet: Set<ItemEntry<ItemTypeType>> = new Set();\n\n\t\tif (newLimit > previousLimit) {\n\t\t\titemEntriesToBeAdded = await this.increaseItemEntriesToBeAdded(\n\t\t\t\titemEntriesToBeAdded,\n\t\t\t\titemEntriesToBeRemovedSet,\n\t\t\t\tpreviousLimit,\n\t\t\t);\n\t\t} else {\n\t\t\t(\n\t\t\t\t{\n\t\t\t\t\titemEntriesToBeAdded,\n\t\t\t\t\titemEntriesToBeRemovedSet,\n\t\t\t\t} = this.limitItemEntriesToBeAdded(\n\t\t\t\t\titemEntriesToBeAdded,\n\t\t\t\t\titemEntriesToBeRemovedSet,\n\t\t\t\t)\n\t\t\t);\n\t\t}\n\n\t\tconst addedRemovedItemResources = await this.updateItemsProperty(\n\t\t\titemEntriesToBeAdded,\n\t\t\titemEntriesToBeRemovedSet,\n\t\t\ttrue,\n\t\t);\n\n\t\tthis.itemsSignal.set(\n\t\t\t[\n\t\t\t\t...this.items,\n\t\t\t],\n\t\t);\n\n\t\tthis.triggerCollectionChangesListeners(\n\t\t\taddedRemovedItemResources,\n\t\t\tnull,\n\t\t\tundefined,\n\t\t\tfalse,\n\t\t\tfalse,\n\t\t\tnull,\n\t\t);\n\t}\n\n\tpublic override async handleMatchedItemEntries (\n\t\tfittingItemEntries: Iterable<ItemEntry<ItemTypeType>>,\n\t\tnonFittingItemEntries: Set<ItemEntry<ItemTypeType>> | undefined,\n\t\tclearChildCollectionResources: boolean,\n\t): Promise<CollectionItemResourceChanges<CollectionResource<ItemTypeType, RequestColumns, Children>>> {\n\t\tconst itemEntryChanges = this.getCollectionItemEntryChanges(\n\t\t\tfittingItemEntries,\n\t\t\tnonFittingItemEntries,\n\t\t);\n\n\t\tlet {\n\t\t\titemEntriesToBeAdded,\n\t\t\titemEntriesToBeRemovedSet,\n\t\t} = itemEntryChanges;\n\n\t\t// Both `limitCollectionChanges` and `resolveChildCollections` can alter the item entries to be added and removed.\n\t\t(\n\t\t\t{\n\t\t\t\titemEntriesToBeAdded,\n\t\t\t\titemEntriesToBeRemovedSet,\n\t\t\t} = this.limitItemEntriesToBeAdded(\n\t\t\t\titemEntriesToBeAdded,\n\t\t\t\titemEntriesToBeRemovedSet,\n\t\t\t)\n\t\t);\n\n\t\titemEntriesToBeAdded = await this.increaseItemEntriesToBeAdded(\n\t\t\titemEntriesToBeAdded,\n\t\t\titemEntriesToBeRemovedSet,\n\t\t);\n\n\t\tconst addedRemovedItemResources = await this.updateItemsProperty(\n\t\t\titemEntriesToBeAdded,\n\t\t\titemEntriesToBeRemovedSet,\n\t\t\tclearChildCollectionResources,\n\t\t);\n\n\t\treturn {\n\t\t\tcollectionResource: this,\n\t\t\taddedItems: addedRemovedItemResources.addedItems,\n\t\t\tremovedItems: addedRemovedItemResources.removedItems,\n\t\t\tchangedItems: itemEntryChanges.changedItemResources,\n\t\t};\n\t}\n\n\t/**\n\t * @returns A *sorted* array of item entries representing `baseItemEntries` with `itemEntriesToBeAdded` and\n\t * `itemEntriesToBeRemovedSet` applied.\n\t */\n\tprivate applyAddedRemovedItemEntries (\n\t\tbaseItemEntries: ItemEntry<ItemTypeType>[],\n\t\titemEntriesToBeAdded: ItemEntry<ItemTypeType>[],\n\t\titemEntriesToBeRemovedSet: Set<ItemEntry<ItemTypeType>>,\n\t): ItemEntry<ItemTypeType>[] {\n\t\tconst updatedItemEntries: ItemEntry<ItemTypeType>[] = itemEntriesToBeAdded.slice();\n\n\t\tfor (const itemEntry of baseItemEntries) {\n\t\t\tif (\n\t\t\t\titemEntriesToBeRemovedSet.has(\n\t\t\t\t\titemEntry,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tupdatedItemEntries.push(\n\t\t\t\titemEntry,\n\t\t\t);\n\t\t}\n\n\t\treturn this.sortItemEntries(\n\t\t\tupdatedItemEntries,\n\t\t);\n\t}\n\n\t/**\n\t * When adding items to or removing items from a collection having a `limit` property set, we want to express the\n\t * limit in the items that will be added / removed, instead of basing it on items currently present in the\n\t * collection. This way, when a changes listener is registered, we ensure that:\n\t *\n\t * - The changes listener is called only once;\n\t * - The changes listener is called with item resources representing the final added / removed items.\n\t */\n\tprivate limitItemEntriesToBeAdded (\n\t\titemEntriesToBeAdded: ItemEntry<ItemTypeType>[],\n\t\titemEntriesToBeRemovedSet: Set<ItemEntry<ItemTypeType>>,\n\t): {\n\t\titemEntriesToBeAdded: ItemEntry<ItemTypeType>[],\n\t\titemEntriesToBeRemovedSet: Set<ItemEntry<ItemTypeType>>,\n\t} {\n\t\tconst newAmount = this.items.length + (itemEntriesToBeAdded.length - itemEntriesToBeRemovedSet.size);\n\t\tconst limit = this.options.order.limit;\n\n\t\tif (newAmount <= limit) {\n\t\t\treturn {\n\t\t\t\titemEntriesToBeAdded,\n\t\t\t\titemEntriesToBeRemovedSet,\n\t\t\t};\n\t\t}\n\n\t\tconst excessItemEntries = this\n\t\t\t.applyAddedRemovedItemEntries(\n\t\t\t\tthis.items.map(\n\t\t\t\t\titemResource => itemResource.entry,\n\t\t\t\t),\n\t\t\t\titemEntriesToBeAdded,\n\t\t\t\titemEntriesToBeRemovedSet,\n\t\t\t)\n\t\t\t.slice(\n\t\t\t\tlimit,\n\t\t\t);\n\n\t\tconst itemEntriesToBeAddedCopy: ItemEntry<ItemTypeType>[] = itemEntriesToBeAdded.slice();\n\t\tconst itemEntriesToBeRemovedCopy: Set<ItemEntry<ItemTypeType>> = new Set(\n\t\t\t[\n\t\t\t\t...itemEntriesToBeRemovedSet,\n\t\t\t],\n\t\t);\n\n\t\tfor (const itemEntry of excessItemEntries) {\n\t\t\tconst itemEntriesToBeAddedIndex = itemEntriesToBeAddedCopy.indexOf(\n\t\t\t\titemEntry,\n\t\t\t);\n\n\t\t\tif (itemEntriesToBeAddedIndex === -1) {\n\t\t\t\titemEntriesToBeRemovedCopy.add(\n\t\t\t\t\titemEntry,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\titemEntriesToBeAddedCopy.splice(\n\t\t\t\t\titemEntriesToBeAddedIndex,\n\t\t\t\t\t1,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\titemEntriesToBeAdded: itemEntriesToBeAddedCopy,\n\t\t\titemEntriesToBeRemovedSet: itemEntriesToBeRemovedCopy,\n\t\t};\n\t}\n\n\t/**\n\t * When were removing items from the collection, we want to add additional items as well, such that we still\n\t * adhere to the limit. See: {@link limitItemEntriesToBeAdded}.\n\t */\n\tprivate async increaseItemEntriesToBeAdded (\n\t\titemEntriesToBeAdded: ItemEntry<ItemTypeType>[],\n\t\titemEntriesToBeRemovedSet: Set<ItemEntry<ItemTypeType>>,\n\t\tpreviousLimit: number = this.options.order.limit,\n\t): Promise<ItemEntry<ItemTypeType>[]> {\n\t\tconst newAmount = this.items.length + (itemEntriesToBeAdded.length - itemEntriesToBeRemovedSet.size);\n\t\tconst limit = this.options.order.limit;\n\n\t\tif (\n\t\t\tnewAmount >= limit\n\t\t\t// We only need to increase the amount of items when we know additional items might be available. This\n\t\t\t// is the case when we were at the limit previously.\n\t\t\t|| this.items.length < previousLimit\n\t\t) {\n\t\t\treturn itemEntriesToBeAdded;\n\t\t}\n\n\t\tconst itemHandler = this.transaction.itemHandler;\n\t\tconst orderOption = this.options.order;\n\n\t\t// TODO: Calling this method will result in another changes delta being applied, which be cause\n\t\t// {@link handleMatchedItemEntries} to be called. No item entries will be added to this collection, because at\n\t\t// that point, no items have been removed yet. Ideally, we should process the item entries of the resulting\n\t\t// cached query without matching them to collections.\n\t\tconst cachedQueryItem = await this.fetchCachedQuery(\n\t\t\t{\n\t\t\t\t...this.options,\n\t\t\t\torder: {\n\t\t\t\t\torder: orderOption.order,\n\t\t\t\t\tfield: orderOption.field,\n\t\t\t\t\t// To simplify this operation, we add a margin to the amount of items we're going to request.\n\t\t\t\t\t// As long as we have enough items left after we remove the items that have been removed,\n\t\t\t\t\t// and the ones we're going to remove, we're good. (Taking `itemEntriesToBeAdded` into\n\t\t\t\t\t// account here would make this unnecessarily complex as these could include items removed\n\t\t\t\t\t// in the past.)\n\t\t\t\t\tlimit: limit + itemEntriesToBeRemovedSet.size + itemHandler.getDeletedItemsAmount(\n\t\t\t\t\t\tthis.itemType,\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\t\tconst sortedItemEntries = this.applyAddedRemovedItemEntries(\n\t\t\tcachedQueryItem.items,\n\t\t\titemEntriesToBeAdded,\n\t\t\titemEntriesToBeRemovedSet,\n\t\t);\n\t\tconst newItemEntriesToBeAdded: ItemEntry<ItemTypeType>[] = [];\n\t\t// We're not taking `itemEntriesToBeAdded` into account here, as these should already be present in\n\t\t// `sortedItemEntries`. This way, we're ensuring that added item entries that would be located after the limit\n\t\t// will not be included.\n\t\tconst numAdditionalItemsRequired = limit - (this.items.length - itemEntriesToBeRemovedSet.size);\n\n\t\tfor (\n\t\t\tlet i = 0;\n\t\t\ti < sortedItemEntries.length\n\t\t\t&& newItemEntriesToBeAdded.length < numAdditionalItemsRequired;\n\t\t\ti++\n\t\t) {\n\t\t\tconst itemEntry = sortedItemEntries[i];\n\n\t\t\tif (\n\t\t\t\t// If the item is already present...\n\t\t\t\tthis.itemEntryIdMap[itemEntry.id] !== undefined\n\t\t\t\t// Or it has been removed in the past (and we're not re-adding it), we can continue.\n\t\t\t\t// (Item entries to be removed are already handled in `applyAddedRemovedItemEntries`).\n\t\t\t\t|| (\n\t\t\t\t\titemHandler.itemIsDeleted(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t)\n\t\t\t\t\t&& !itemEntriesToBeAdded.includes(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tnewItemEntriesToBeAdded.push(\n\t\t\t\titemEntry,\n\t\t\t);\n\t\t}\n\n\t\treturn newItemEntriesToBeAdded;\n\t}\n\n}\n","import { ApiItemType, ItemId } from '@rentman/backend-types';\nimport { ApiFormatter, ApiResponseProcessor, ColumnSet, ColumnSetFactory, ColumnUtil, FieldMap, ItemEntryService, ResponseColumnItemTypeMap } from '../internal';\nimport { UnknownResponseColumn } from '@rentman/backend-types/dist/manual/api-response-column';\n\nexport class Template<ItemTypeType extends ApiItemType> {\n\n\t/**\n\t * Also contains the additional response columns.\n\t */\n\tprivate readonly responseColumns: ResponseColumnItemTypeMap;\n\n\tpublic constructor (\n\t\tpublic readonly itemType: ItemTypeType,\n\t\tpublic readonly response: ApiResponseProcessor<ItemTypeType>,\n\t\tprivate readonly columnSetFactory: ColumnSetFactory,\n\t\tprivate readonly itemEntryService: ItemEntryService,\n\t\tprivate readonly additionalResponseColumns: ResponseColumnItemTypeMap,\n\t) {\n\t\tthis.responseColumns = ColumnUtil\n\t\t\t.mergeResponseColumns(\n\t\t\t\tresponse.fetchColumnsObject(),\n\t\t\t\tadditionalResponseColumns,\n\t\t\t)\n\t\t\t.merged;\n\t}\n\n\tpublic getFields<FieldsItemType extends ApiItemType = ItemTypeType> (\n\t\titemType: FieldsItemType = this.itemType as unknown as FieldsItemType,\n\t\titemId: ItemId<FieldsItemType> = this.response.links[itemType][0],\n\t): FieldMap<FieldsItemType> {\n\t\tconst fields = this.response.fetchObject<FieldsItemType>(\n\t\t\titemType,\n\t\t\titemId,\n\t\t);\n\n\t\tif (fields === undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t`Template.getFields: itemType ${itemType} with itemId ${itemId} not found in ApiResponseProcessor.`,\n\t\t\t);\n\t\t}\n\n\t\tconst itemTypeColumns = this.additionalResponseColumns[this.itemType];\n\n\t\tfor (const columnId in itemTypeColumns) {\n\t\t\tconst column = this.additionalResponseColumns[this.itemType][columnId] as UnknownResponseColumn;\n\n\t\t\tif (fields[column.id] !== undefined) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tApiFormatter.isExpensiveFormat(\n\t\t\t\t\tcolumn.type,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tApiResponseProcessor.addLazyFormattingFunction(\n\t\t\t\t\tcolumn.id as keyof FieldMap<FieldsItemType>,\n\t\t\t\t\tcolumn.type,\n\t\t\t\t\tcolumn.default,\n\t\t\t\t\tfields,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tfields[column.id] = ApiFormatter.formatResponseValue(\n\t\t\t\t\tcolumn.type,\n\t\t\t\t\tcolumn.default,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\t...fields,\n\t\t\t...this.itemEntryService.getLocalDefaultValues(),\n\t\t};\n\t}\n\n\tpublic getMainColumnSet (): ColumnSet<ItemTypeType> {\n\t\treturn this.getColumnSet(\n\t\t\tthis.itemType,\n\t\t);\n\t}\n\n\tpublic getColumnSet<ColumnSetItemType extends ApiItemType> (\n\t\titemType: ColumnSetItemType,\n\t): ColumnSet<ColumnSetItemType> {\n\t\t// Because we're not sure which columns are in the response template, we're calling `constructFromResponse`\n\t\t// always.\n\t\treturn this.columnSetFactory.constructFromResponse(\n\t\t\titemType,\n\t\t\tfalse,\n\t\t\tthis.responseColumns,\n\t\t);\n\t}\n\n}\n","export function findIndex<T> (\n\thaystack: T[],\n\tcallback: (item: T) => boolean,\n): number {\n\tfor (let i = 0; i < haystack.length; i++) {\n\t\tif (callback(\n\t\t\thaystack[i],\n\t\t)) {\n\t\t\treturn i;\n\t\t}\n\t}\n\n\treturn -1;\n}\n\nexport function shallowMerge (\n\tobject,\n\tdefaults,\n) {\n\tif (object === undefined) {\n\t\treturn defaults;\n\t}\n\n\tconst result = {};\n\n\tfor (const key in defaults) {\n\t\tresult[key] = object[key] === undefined\n\t\t\t? defaults[key] : object[key];\n\t}\n\n\treturn result;\n}\n\nexport function hasProperties (\n\tobject,\n) {\n\t// @ts-ignore\n\tfor (const key in object) {\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nexport function getFirstProperty<T = string> (\n\tobject,\n): T | null {\n\tif (typeof object !== 'object') {\n\t\treturn null;\n\t}\n\n\tfor (const key in object) {\n\t\treturn key as unknown as T;\n\t}\n\n\treturn null;\n}\n\nexport function inArray (\n\tneedle,\n\thaystack,\n) {\n\tfor (const hay of haystack) {\n\t\t// eslint-disable-next-line eqeqeq\n\t\tif (needle == hay) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\nexport function pathExists (\n\tsource,\n\tpath: string[],\n): boolean {\n\tif (typeof source === 'undefined') {\n\t\treturn false;\n\t}\n\n\tfor (const p of path) {\n\t\tif (typeof source[p] === 'undefined') {\n\t\t\treturn false;\n\t\t}\n\n\t\tsource = source[p];\n\t}\n\n\treturn true;\n}\n\nexport function createPath<T> (\n\tobject: any,\n\tpath: (number | string)[],\n\tdefaults: any[],\n\toverwriteDestination: boolean = false,\n): T {\n\tfor (let i = 0; i < path.length; i++) {\n\t\tconst value = path[i];\n\n\t\tif (\n\t\t\tobject[value] === undefined\n\t\t\t|| (\n\t\t\t\toverwriteDestination\n\t\t\t\t&& i === path.length - 1\n\t\t\t)\n\t\t) {\n\t\t\tobject[value] = defaults[i];\n\t\t}\n\n\t\tobject = object[value];\n\t}\n\n\treturn object;\n}\n\nexport function getPath (\n\tobject: Record<string, any>,\n\tpath: (number | string)[],\n\tcreate: boolean = false,\n): any {\n\tif (object === undefined) {\n\t\treturn undefined;\n\t}\n\n\tfor (const p of path) {\n\t\t// won't alter the caller's var\n\t\tobject = object[p];\n\n\t\tif (object === undefined && !create) {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\treturn object;\n}\n\n// Taken from AngularJS, added comments to ignore TypeScript errors\nfunction baseExtend (\n\tdst,\n\tobjs,\n\tdeep,\n) {\n\tfor (let i = 0, ii = objs.length; i < ii; ++i) {\n\t\tconst obj = objs[i];\n\n\t\tif (!isObject(\n\t\t\tobj,\n\t\t) && !isFunction(\n\t\t\tobj,\n\t\t)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst keys = Object.keys(\n\t\t\tobj,\n\t\t);\n\n\t\tfor (let j = 0, jj = keys.length; j < jj; j++) {\n\t\t\tconst key = keys[j];\n\t\t\tconst src = obj[key];\n\n\t\t\tif (deep && isObject(\n\t\t\t\tsrc,\n\t\t\t)) {\n\t\t\t\tif (isDate(\n\t\t\t\t\tsrc,\n\t\t\t\t)) {\n\t\t\t\t\tdst[key] = new Date(\n\t\t\t\t\t\tsrc.valueOf(),\n\t\t\t\t\t);\n\t\t\t\t} else if (isRegExp(\n\t\t\t\t\tsrc,\n\t\t\t\t)) {\n\t\t\t\t\tdst[key] = new RegExp(\n\t\t\t\t\t\tsrc,\n\t\t\t\t\t);\n\t\t\t\t} else if (src.nodeName) {\n\t\t\t\t\tdst[key] = src.cloneNode(\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t);\n\t\t\t\t} else if (isElement(\n\t\t\t\t\tsrc,\n\t\t\t\t)) {\n\t\t\t\t\tdst[key] = src.clone();\n\t\t\t\t} else {\n\t\t\t\t\tif (!isObject(\n\t\t\t\t\t\tdst[key],\n\t\t\t\t\t)) {\n\t\t\t\t\t\tdst[key] = isArray(\n\t\t\t\t\t\t\tsrc,\n\t\t\t\t\t\t) ? [] : {};\n\t\t\t\t\t}\n\n\t\t\t\t\tbaseExtend(\n\t\t\t\t\t\tdst[key],\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\tsrc,\n\t\t\t\t\t\t],\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tdst[key] = src;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn dst;\n}\n\nexport function extend (\n\tdst,\n\t...args\n) {\n\treturn baseExtend(\n\t\tdst,\n\t\targs,\n\t\tfalse,\n\t);\n}\n\nexport function merge (\n\tdst,\n\t...args\n) {\n\treturn baseExtend(\n\t\tdst,\n\t\targs,\n\t\ttrue,\n\t);\n}\n\nexport function isObject (\n\tvalue,\n) {\n\t// http://jsperf.com/isobject4\n\treturn value !== null && typeof value === 'object';\n}\n\nexport function isBlankObject (\n\tvalue,\n) {\n\treturn value !== null && typeof value === 'object' && !Object.getPrototypeOf(\n\t\tvalue,\n\t);\n}\n\nexport function isString (\n\tvalue,\n) {\n\treturn typeof value === 'string';\n}\n\nexport function isNumber (\n\tvalue,\n) {\n\treturn typeof value === 'number';\n}\n\nexport function isDate (\n\tvalue,\n) {\n\treturn toString.call(\n\t\tvalue,\n\t) === '[object Date]';\n}\n\nexport const isArray = Array.isArray;\n\nexport function isFunction<T> (\n\tvalue: any,\n): value is T {\n\treturn typeof value === 'function';\n}\n\nexport function isPromiseLike<T = any> (\n\tobj: any,\n): obj is Promise<T> {\n\treturn obj && isFunction(\n\t\tobj.then,\n\t);\n}\n\ntype ResolvedPromiseObject<ObjectType extends Record<string, any>> = {\n\t[K in keyof ObjectType]: ObjectType[K] extends Promise<infer PromiseType> ? PromiseType : ObjectType[K]\n};\n\nexport function promiseAllObject<ObjectType extends Record<string, any>> (\n\tpromiseObject: ObjectType,\n): Promise<ResolvedPromiseObject<ObjectType>> {\n\tconst keys: string[] = [];\n\tconst promises: Promise<ObjectType[keyof ObjectType]>[] = [];\n\n\tfor (const key in promiseObject) {\n\t\tkeys.push(\n\t\t\tkey,\n\t\t);\n\t\tpromises.push(\n\t\t\tpromiseObject[key],\n\t\t);\n\t}\n\n\treturn Promise\n\t\t.all(\n\t\t\tpromises,\n\t\t)\n\t\t.then(\n\t\t\tresolved => {\n\t\t\t\tconst result = {};\n\n\t\t\t\tfor (let i: number = 0; i < keys.length; i++) {\n\t\t\t\t\tresult[keys[i]] = resolved[i];\n\t\t\t\t}\n\n\t\t\t\treturn result as ResolvedPromiseObject<ObjectType>;\n\t\t\t},\n\t\t);\n}\n\nexport interface Deferred<T> {\n\tpromise: Promise<T>,\n\n\tresolve (value?: T | PromiseLike<T>): void,\n\n\treject (reason?: any): void,\n}\n\nexport function promiseCreateDeferred<T> (): Deferred<T> {\n\tconst result: Partial<Deferred<T>> = {};\n\n\tresult.promise = new Promise(\n\t\t(\n\t\t\tresolve,\n\t\t\treject,\n\t\t) => {\n\t\t\tresult.resolve = resolve;\n\t\t\tresult.reject = reject;\n\t\t},\n\t);\n\n\treturn result as Deferred<T>;\n}\n\nexport function isRegExp (\n\tvalue,\n) {\n\treturn toString.call(\n\t\tvalue,\n\t) === '[object RegExp]';\n}\n\nexport function isBoolean (\n\tvalue,\n) {\n\treturn typeof value === 'boolean';\n}\n\nexport function isElement (\n\tnode,\n) {\n\treturn !!(node\n\t\t&& (\n\t\t\tnode.nodeName // We are a direct element.\n\t\t\t|| (node.prop && node.attr && node.find)\n\t\t)\n\t); // We have an on and find method part of jQuery API.\n}\n\nexport function isWindow (\n\tobj,\n) {\n\treturn obj && obj.window === obj;\n}\n\nexport function isDefined (\n\tvalue,\n) {\n\treturn typeof value !== 'undefined';\n}\n\nexport function equals (\n\to1,\n\to2,\n) {\n\tif (o1 === o2) {\n\t\treturn true;\n\t}\n\n\tif (o1 === null || o2 === null) {\n\t\treturn false;\n\t}\n\n\t// eslint-disable-next-line no-self-compare\n\tif (o1 !== o1 && o2 !== o2) {\n\t\treturn true;\n\t} // NaN === NaN\n\n\tconst t1 = typeof o1;\n\tconst t2 = typeof o2;\n\n\tlet length;\n\tlet key;\n\tlet keySet;\n\n\tif (t1 === t2 && t1 === 'object') {\n\t\tif (isArray(\n\t\t\to1,\n\t\t)) {\n\t\t\tif (!isArray(\n\t\t\t\to2,\n\t\t\t)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tlength = o1.length;\n\n\t\t\tif (o1.length === o2.length) {\n\t\t\t\tfor (key = 0; key < length; key++) {\n\t\t\t\t\tif (!equals(\n\t\t\t\t\t\to1[key],\n\t\t\t\t\t\to2[key],\n\t\t\t\t\t)) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\t\t\t}\n\t\t} else if (isDate(\n\t\t\to1,\n\t\t)) {\n\t\t\tif (!isDate(\n\t\t\t\to2,\n\t\t\t)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn simpleCompare(\n\t\t\t\to1.getTime(),\n\t\t\t\to2.getTime(),\n\t\t\t);\n\t\t} else if (isRegExp(\n\t\t\to1,\n\t\t)) {\n\t\t\tif (!isRegExp(\n\t\t\t\to2,\n\t\t\t)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn o1.toString() === o2.toString();\n\t\t} else {\n\t\t\tif (isWindow(\n\t\t\t\to1,\n\t\t\t) || isWindow(\n\t\t\t\to2,\n\t\t\t) || isArray(\n\t\t\t\to2,\n\t\t\t) || isDate(\n\t\t\t\to2,\n\t\t\t) || isRegExp(\n\t\t\t\to2,\n\t\t\t)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tkeySet = createMap();\n\n\t\t\tfor (key in o1) {\n\t\t\t\tif (isFunction(\n\t\t\t\t\to1[key],\n\t\t\t\t)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (!equals(\n\t\t\t\t\to1[key],\n\t\t\t\t\to2[key],\n\t\t\t\t)) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tkeySet[key] = true;\n\t\t\t}\n\n\t\t\tfor (key in o2) {\n\t\t\t\tif (!(key in keySet) && isDefined(\n\t\t\t\t\to2[key],\n\t\t\t\t) && !isFunction(\n\t\t\t\t\to2[key],\n\t\t\t\t)) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\nfunction createMap () {\n\treturn Object.create(\n\t\tnull,\n\t);\n}\n\n// eslint-disable-next-line no-self-compare\nfunction simpleCompare (\n\ta,\n\tb,\n) {\n\treturn a === b || (a !== a && b !== b);\n}\n\nfunction isValidObjectMaxDepth (\n\tmaxDepth,\n) {\n\treturn isNumber(\n\t\tmaxDepth,\n\t) && maxDepth > 0;\n}\n\nexport function copy (\n\tsource: Record<string, any>,\n\tdestination?: Record<string, any>,\n\tmaxDepth?,\n) {\n\tconst stackSource: Record<string, any>[] = [];\n\tconst stackDest: Record<string, any>[] = [];\n\n\tmaxDepth = isValidObjectMaxDepth(\n\t\tmaxDepth,\n\t) ? maxDepth : NaN;\n\n\tif (destination) {\n\t\tif (source === destination) {\n\t\t\tthrow new Error(\n\t\t\t\t'Can\\'t copy! Source and destination are identical.',\n\t\t\t);\n\t\t}\n\n\t\t// Empty the destination object\n\t\tif (isArray(\n\t\t\tdestination,\n\t\t)) {\n\t\t\tdestination.length = 0;\n\t\t} else {\n\t\t\tfor (const key in destination) {\n\t\t\t\tdelete destination[key];\n\t\t\t}\n\t\t}\n\n\t\tstackSource.push(\n\t\t\tsource,\n\t\t);\n\t\tstackDest.push(\n\t\t\tdestination,\n\t\t);\n\n\t\treturn copyRecurse(\n\t\t\tsource,\n\t\t\tdestination,\n\t\t\tmaxDepth,\n\t\t);\n\t}\n\n\treturn copyElement(\n\t\tsource,\n\t\tmaxDepth,\n\t);\n\n\tfunction copyRecurse (\n\t\t_source,\n\t\t_destination,\n\t\t_maxDepth,\n\t) {\n\t\t_maxDepth--;\n\n\t\tif (_maxDepth < 0) {\n\t\t\treturn '...';\n\t\t}\n\n\t\tif (isArray(\n\t\t\t_source,\n\t\t)) {\n\t\t\tfor (let i = 0, ii = _source.length; i < ii; i++) {\n\t\t\t\t_destination.push(\n\t\t\t\t\tcopyElement(\n\t\t\t\t\t\t_source[i],\n\t\t\t\t\t\t_maxDepth,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t} else if (isBlankObject(\n\t\t\t_source,\n\t\t)) {\n\t\t\t// createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty\n\t\t\tfor (const key in _source) {\n\t\t\t\t_destination[key] = copyElement(\n\t\t\t\t\t_source[key],\n\t\t\t\t\t_maxDepth,\n\t\t\t\t);\n\t\t\t}\n\t\t} else if (_source && typeof _source.hasOwnProperty === 'function') {\n\t\t\t// Slow path, which must rely on hasOwnProperty\n\t\t\tfor (const key in _source) {\n\t\t\t\tif (Object.prototype.hasOwnProperty.call(\n\t\t\t\t\t_source,\n\t\t\t\t\tkey,\n\t\t\t\t)) {\n\t\t\t\t\t_destination[key] = copyElement(\n\t\t\t\t\t\t_source[key],\n\t\t\t\t\t\t_maxDepth,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// Slowest path --- hasOwnProperty can't be called as a method\n\t\t\tfor (const key in _source) {\n\t\t\t\tif (Object.prototype.hasOwnProperty.call(\n\t\t\t\t\t_source,\n\t\t\t\t\tkey,\n\t\t\t\t)) {\n\t\t\t\t\t_destination[key] = copyElement(\n\t\t\t\t\t\t_source[key],\n\t\t\t\t\t\t_maxDepth,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn _destination;\n\t}\n\n\tfunction copyElement (\n\t\t_source,\n\t\t_maxDepth = 5,\n\t) {\n\t\t// Simple values\n\t\tif (!isObject(\n\t\t\t_source,\n\t\t)) {\n\t\t\treturn _source;\n\t\t}\n\n\t\t// Already copied values\n\t\tconst index = stackSource.indexOf(\n\t\t\t_source,\n\t\t);\n\n\t\tif (index !== -1) {\n\t\t\treturn stackDest[index];\n\t\t}\n\n\t\tif (isWindow(\n\t\t\t_source,\n\t\t)) {\n\t\t\tthrow new Error(\n\t\t\t\t'Can\\'t copy! Making copies of Window instances is not supported.',\n\t\t\t);\n\t\t}\n\n\t\tlet needsRecurse = false;\n\t\tlet _destination = copyType(\n\t\t\t_source,\n\t\t);\n\n\t\tif (_destination === undefined) {\n\t\t\t_destination = isArray(\n\t\t\t\t_source,\n\t\t\t) ? [] : Object.create(\n\t\t\t\tObject.getPrototypeOf(\n\t\t\t\t\t_source,\n\t\t\t\t),\n\t\t\t);\n\t\t\tneedsRecurse = true;\n\t\t}\n\n\t\tstackSource.push(\n\t\t\t_source,\n\t\t);\n\t\tstackDest.push(\n\t\t\t_destination,\n\t\t);\n\n\t\treturn needsRecurse\n\t\t\t? copyRecurse(\n\t\t\t\t_source,\n\t\t\t\t_destination,\n\t\t\t\t_maxDepth,\n\t\t\t)\n\t\t\t: _destination;\n\t}\n\n\tfunction copyType (\n\t\t_source,\n\t) {\n\t\tswitch (toString.call(\n\t\t\t_source,\n\t\t)) {\n\t\t\tcase '[object Int8Array]':\n\t\t\tcase '[object Int16Array]':\n\t\t\tcase '[object Int32Array]':\n\t\t\tcase '[object Float32Array]':\n\t\t\tcase '[object Float64Array]':\n\t\t\tcase '[object Uint8Array]':\n\t\t\tcase '[object Uint8ClampedArray]':\n\t\t\tcase '[object Uint16Array]':\n\t\t\tcase '[object Uint32Array]':\n\t\t\t\treturn new _source.constructor(\n\t\t\t\t\tcopyElement(\n\t\t\t\t\t\t_source.buffer,\n\t\t\t\t\t),\n\t\t\t\t\t_source.byteOffset,\n\t\t\t\t\t_source.length,\n\t\t\t\t);\n\n\t\t\tcase '[object ArrayBuffer]':\n\t\t\t\t// Support: IE10\n\t\t\t\tif (!_source.slice) {\n\t\t\t\t\t// If we're in this case we know the environment supports ArrayBuffer\n\t\t\t\t\t/* eslint-disable no-undef */\n\t\t\t\t\tconst copied = new ArrayBuffer(\n\t\t\t\t\t\t_source.byteLength,\n\t\t\t\t\t);\n\n\t\t\t\t\tnew Uint8Array(\n\t\t\t\t\t\tcopied,\n\t\t\t\t\t)\n\t\t\t\t\t\t.set(\n\t\t\t\t\t\t\tnew Uint8Array(\n\t\t\t\t\t\t\t\t_source,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t/* eslint-enable */\n\t\t\t\t\treturn copied;\n\t\t\t\t}\n\n\t\t\t\treturn _source.slice(\n\t\t\t\t\t0,\n\t\t\t\t);\n\n\t\t\tcase '[object Boolean]':\n\t\t\tcase '[object Number]':\n\t\t\tcase '[object String]':\n\t\t\tcase '[object Date]':\n\t\t\t\treturn new _source.constructor(\n\t\t\t\t\t_source.valueOf(),\n\t\t\t\t);\n\n\t\t\tcase '[object RegExp]': {\n\t\t\t\tconst re = new RegExp(\n\t\t\t\t\t_source._source,\n\t\t\t\t\t_source.toString()\n\t\t\t\t\t\t.match(\n\t\t\t\t\t\t\t/[^/]*$/,\n\t\t\t\t\t\t)[0],\n\t\t\t\t);\n\n\t\t\t\tre.lastIndex = _source.lastIndex;\n\n\t\t\t\treturn re;\n\t\t\t}\n\t\t\t\n\t\t\tcase '[object Blob]':\n\t\t\t\treturn new _source.constructor(\n\t\t\t\t\t[\n\t\t\t\t\t\t_source,\n\t\t\t\t\t],\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: _source.type,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t}\n\n\t\tif (isFunction(\n\t\t\t_source.cloneNode,\n\t\t)) {\n\t\t\treturn _source.cloneNode(\n\t\t\t\ttrue,\n\t\t\t);\n\t\t}\n\t}\n}\n","import { ApiEnumApiType, ApiItemType } from '@rentman/backend-types';\nimport { UnknownResponseColumn } from '@rentman/backend-types/dist/manual/api-response-column';\nimport moment from 'moment';\nimport { ApiEnumApiTypeToTsTypeMap, FieldMap, ItemTypeColumnId, ItemTypeColumnIds, ResponseColumnMap } from '../types/ItemTypesCollection';\nimport { ColumnInfo } from './ColumnInfo';\nimport { copy, equals } from './Util';\n\n/**\n * @description\n * A service which provides functions to transform data that comes from/goes to the API\n *\n * @warning\n * The code in these functions can be *very hot* on large databases, therefore performance must be kept in mind.\n * This is also the reason why all column types are written out instead of using the enum\n */\nexport abstract class ApiFormatter {\n\n\tpublic static readonly SERVER_DATETIME_FORMAT: string = 'YYYY-MM-DD[T]HH:mm:ssZ';\n\tpublic static readonly SERVER_DATE_FORMAT: string = 'YYYY-MM-DD';\n\n\t/**\n\t * @description\n\t * Returns if a column type is an 'expensive' type, meaning that the action to format the field takes significant CPU time\n\t *\n\t * ----\n\t * @remarks\n\t * Currently only used for Moment objects\n\t */\n\tpublic static isExpensiveFormat (\n\t\tcolumnType: ApiEnumApiType,\n\t): boolean {\n\t\tswitch (columnType) {\n\t\t\t// case ApiEnumApiType.TYPE_DATE:\n\t\t\tcase 'date':\n\t\t\t// case ApiEnumApiType.TYPE_DATETIME:\n\t\t\tcase 'datetime':\n\t\t\t// case ApiEnumApiType.TYPE_DURATION:\n\t\t\tcase 'duration':\n\t\t\t// case ApiEnumApiType.TYPE_TIMESTAMP:\n\t\t\tcase 'timestamp':\n\t\t\t// case ApiEnumApiType.TYPE_TIMESTAMP_MS:\n\t\t\tcase 'timestamp_ms':\n\t\t\t\treturn true;\n\t\t\tdefault:\n\t\t\t\treturn false;\n\t\t}\n\t}\n\n\tpublic static formatRequestLocal<ItemTypeType extends ApiItemType> (\n\t\tfields: FieldMap<ItemTypeType>,\n\t\tcolumns: ColumnInfo<ItemTypeType>[],\n\t): {[columnId: string]: any,} {\n\t\tconst result: {[columnId: string]: any,} = {};\n\n\t\tfor (const column of columns) {\n\t\t\tconst columnId = column.id;\n\t\t\tconst apiColumn = column.apiColumn;\n\n\t\t\tif (\n\t\t\t\tapiColumn.readOnly\n\t\t\t\t|| fields[columnId] === undefined\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tresult[columnId] = this.formatRequestValue(\n\t\t\t\tapiColumn.type,\n\t\t\t\tfields[columnId],\n\t\t\t);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * TODO: Since we're never writing to fields directly, we could consider replacing `copyFields` by\n\t * {@link shallowCopyFields}.\n\t */\n\tpublic static copyFields<ItemTypeType extends ApiItemType = any, ColumnIds extends ItemTypeColumnIds<ItemTypeType> = any> (\n\t\tsource: Partial<FieldMap<ItemTypeType, ColumnIds>>,\n\t\tdestination: Partial<FieldMap<ItemTypeType>>,\n\t\tcolumns: ColumnInfo<ItemTypeType, ColumnIds[number]>[],\n\t): FieldMap<ItemTypeType, ColumnIds> {\n\t\tfor (const column of columns) {\n\t\t\tconst columnPath = column.path;\n\n\t\t\tif (\n\t\t\t\t!Object.prototype.hasOwnProperty.call(\n\t\t\t\t\tsource,\n\t\t\t\t\tcolumnPath,\n\t\t\t\t)\n\t\t\t\t|| (\n\t\t\t\t\t// prevent triggering getter for expensive formats\n\t\t\t\t\t!this.isExpensiveFormat(\n\t\t\t\t\t\t(column.apiColumn as UnknownResponseColumn).type,\n\t\t\t\t\t)\n\t\t\t\t\t&& source[columnPath] === undefined\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tdestination[columnPath as ColumnIds[number]] = this.clone(\n\t\t\t\t(column.apiColumn as UnknownResponseColumn).type,\n\t\t\t\tsource[columnPath],\n\t\t\t);\n\t\t}\n\n\t\treturn destination as FieldMap<ItemTypeType, ColumnIds>;\n\t}\n\n\t/**\n\t * Iterates over source properties, doesn't clone complex objects. Overwrites properties already in `destination`.\n\t *\n\t * Note: we iterate over the keys of `source` here because this method is typically called when we want to make a\n\t * copy of changed fields in a changes delta.\n\t */\n\tpublic static shallowCopyFields<ItemTypeType extends ApiItemType, ColumnIds extends ItemTypeColumnIds<ItemTypeType> = any> (\n\t\tsource: Partial<FieldMap<ItemTypeType, ColumnIds>>,\n\t\tdestination: Partial<FieldMap<ItemTypeType>>,\n\t\tresponseColumns: ResponseColumnMap<ItemTypeType>,\n\t\tonMissingColumn?: (columnId: ItemTypeColumnId<ItemTypeType>) => void,\n\t): Partial<FieldMap<ItemTypeType, ColumnIds>> {\n\t\tfor (const columnId in source) {\n\t\t\tconst column = responseColumns[columnId];\n\n\t\t\tif (column === undefined) {\n\t\t\t\tonMissingColumn?.(\n\t\t\t\t\tcolumnId as ItemTypeColumnId<ItemTypeType>,\n\t\t\t\t);\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tthis.isExpensiveFormat(\n\t\t\t\t\tcolumn.type,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tconst desc = Object.getOwnPropertyDescriptor(\n\t\t\t\t\tsource,\n\t\t\t\t\tcolumnId,\n\t\t\t\t);\n\n\t\t\t\tif (\n\t\t\t\t\tdesc !== undefined\n\t\t\t\t\t&& desc.get !== undefined\n\t\t\t\t) {\n\t\t\t\t\tObject.defineProperty(\n\t\t\t\t\t\tdestination,\n\t\t\t\t\t\tcolumnId,\n\t\t\t\t\t\tdesc,\n\t\t\t\t\t);\n\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdestination[columnId] = source[columnId];\n\t\t}\n\n\t\treturn destination as FieldMap<ItemTypeType, ColumnIds>;\n\t}\n\n\tpublic static setDefaultValues<ItemTypeType extends ApiItemType = any> (\n\t\tdestination: Partial<FieldMap<ItemTypeType>>,\n\t\tcolumns: ColumnInfo<ItemTypeType>[],\n\t): FieldMap<ItemTypeType> {\n\t\tfor (const column of columns) {\n\t\t\tdestination[column.id] = ApiFormatter.formatResponseValue(\n\t\t\t\tcolumn.apiColumn.type,\n\t\t\t\tcolumn.apiColumn.default,\n\t\t\t);\n\t\t}\n\n\t\treturn destination as FieldMap<ItemTypeType>;\n\t}\n\n\t/**\n\t * @description\n\t * Compares the given fields, returns `true` when the fields are equal\n\t */\n\tpublic static compareFields<ColumnType extends ApiEnumApiType> (\n\t\tcolumnType: ColumnType,\n\t\tfirst?: ApiEnumApiTypeToTsTypeMap[ColumnType],\n\t\tsecond?: ApiEnumApiTypeToTsTypeMap[ColumnType],\n\t): boolean {\n\t\tif (first === undefined) {\n\t\t\treturn second === undefined;\n\t\t}\n\n\t\tif (second === undefined) {\n\t\t\treturn false;\n\t\t}\n\n\t\tswitch (columnType) {\n\t\t\t// case ApiEnumApiType.TYPE_DATE:\n\t\t\tcase 'date':\n\t\t\t// case ApiEnumApiType.TYPE_DATETIME:\n\t\t\tcase 'datetime':\n\t\t\t// case ApiEnumApiType.TYPE_TIMESTAMP:\n\t\t\tcase 'timestamp':\n\t\t\t// case ApiEnumApiType.TYPE_TIMESTAMP_MS:\n\t\t\tcase 'timestamp_ms':\n\t\t\t\treturn this.compareMomentObjects(\n\t\t\t\t\tfirst,\n\t\t\t\t\tsecond,\n\t\t\t\t);\n\t\t\t// case ApiEnumApiType.TYPE_DURATION:\n\t\t\tcase 'duration':\n\t\t\t\treturn this.compareDurations(\n\t\t\t\t\tfirst,\n\t\t\t\t\tsecond,\n\t\t\t\t);\n\t\t\t// case ApiEnumApiType.TYPE_ID: // id types\n\t\t\tcase 'id': // id types\n\t\t\t// case ApiEnumApiType.TYPE_ITEM:\n\t\t\tcase 'item':\n\t\t\t// case ApiEnumApiType.TYPE_LINK:\n\t\t\tcase 'link':\n\t\t\t// case ApiEnumApiType.TYPE_CHILD:\n\t\t\tcase 'child':\n\t\t\t// case ApiEnumApiType.TYPE_SIBLING:\n\t\t\tcase 'sibling':\n\t\t\t// case ApiEnumApiType.TYPE_NUMERIC_EXTERNALID:\n\t\t\tcase 'numeric_externalid':\n\t\t\t// case ApiEnumApiType.TYPE_ALPHANUMERIC_EXTERNALID:\n\t\t\tcase 'alphanumeric_externalid':\n\t\t\t\t// use non-strict comparison\n\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\treturn first == second;\n\t\t\t// case ApiEnumApiType.TYPE_CURRENT:\n\t\t\tcase 'current':\n\t\t\t// case ApiEnumApiType.TYPE_DIMENSION:\n\t\t\tcase 'dimension':\n\t\t\t// case ApiEnumApiType.TYPE_DISTANCE:\n\t\t\tcase 'distance':\n\t\t\t// floating point types\n\t\t\t// case ApiEnumApiType.TYPE_DOUBLE:\n\t\t\tcase 'double':\n\t\t\t// case ApiEnumApiType.TYPE_POWER:\n\t\t\tcase 'power':\n\t\t\t// case ApiEnumApiType.TYPE_VOLUME:\n\t\t\tcase 'volume':\n\t\t\t// case ApiEnumApiType.TYPE_WEIGHT:\n\t\t\tcase 'weight':\n\t\t\t// case ApiEnumApiType.TYPE_COORDINATE:\n\t\t\tcase 'coordinate':\n\t\t\t// case ApiEnumApiType.TYPE_PRICE:\n\t\t\tcase 'price':\n\t\t\t// case ApiEnumApiType.TYPE_PERCENTAGE:\n\t\t\tcase 'percentage':\n\t\t\t\treturn this.compareFloats(\n\t\t\t\t\tfirst,\n\t\t\t\t\tsecond,\n\t\t\t\t);\n\t\t\t// case ApiEnumApiType.TYPE_QUANTITY:\n\t\t\tcase 'quantity':\n\t\t\t// case ApiEnumApiType.TYPE_NUMBER:\n\t\t\tcase 'number':\n\t\t\t// case ApiEnumApiType.TYPE_FILESIZE:\n\t\t\tcase 'filesize':\n\t\t\t// case ApiEnumApiType.TYPE_INT:\n\t\t\tcase 'int':\n\t\t\t// case ApiEnumApiType.TYPE_BOOL:\n\t\t\tcase 'bool':\n\t\t\t// case ApiEnumApiType.TYPE_ENUM:\n\t\t\tcase 'enum':\n\t\t\t// case ApiEnumApiType.TYPE_EMAIL:\n\t\t\tcase 'email':\n\t\t\t// case ApiEnumApiType.TYPE_PHONE:\n\t\t\tcase 'phone':\n\t\t\t// case ApiEnumApiType.TYPE_URL:\n\t\t\tcase 'url':\n\t\t\t// case ApiEnumApiType.TYPE_TEXT:\n\t\t\tcase 'text':\n\t\t\t// case ApiEnumApiType.TYPE_LONGTEXT:\n\t\t\tcase 'longtext':\n\t\t\t// case ApiEnumApiType.TYPE_COLOR:\n\t\t\tcase 'color':\n\t\t\t// case ApiEnumApiType.TYPE_ORDER:\n\t\t\tcase 'order':\n\t\t\t// case ApiEnumApiType.TYPE_TIME:\n\t\t\tcase 'time':\n\t\t\t\treturn first === second;\n\t\t\tdefault:\n\t\t\t\treturn equals(\n\t\t\t\t\tfirst,\n\t\t\t\t\tsecond,\n\t\t\t\t);\n\t\t}\n\t}\n\n\tpublic static compareFloats (\n\t\ta: number,\n\t\tb: number,\n\t): boolean {\n\t\tconst absA = Math.abs(\n\t\t\ta,\n\t\t);\n\t\tconst absB = Math.abs(\n\t\t\tb,\n\t\t);\n\t\tconst diff = Math.abs(\n\t\t\ta - b,\n\t\t);\n\n\t\tconst EPSILON = 1.19e-07;\n\n\t\t// shortcut, handles infinities\n\t\tif (a === b) {\n\t\t\treturn true;\n\t\t} else if (a === 0 || b === 0 || diff < Number.MIN_VALUE) {\n\t\t\t// a or b is zero or both are extremely close to it\n\t\t\t// relative error is less meaningful here\n\t\t\treturn diff < (EPSILON * Number.MIN_VALUE);\n\t\t} else {\n\t\t\t// use relative error\n\t\t\treturn diff / Math.min(\n\t\t\t\t(absA + absB),\n\t\t\t\tNumber.MAX_VALUE,\n\t\t\t) < EPSILON;\n\t\t}\n\t}\n\n\tpublic static compareMomentObjects (\n\t\tfirst: moment.Moment,\n\t\tsecond: moment.Moment,\n\t): boolean {\n\t\tif (!first.isValid()) {\n\t\t\treturn !second.isValid();\n\t\t}\n\n\t\t// first IS valid\n\t\tif (!second.isValid()) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn first.isSame(\n\t\t\tsecond,\n\t\t);\n\t}\n\n\tpublic static compareDurations (\n\t\tfirst: moment.Duration,\n\t\tsecond: moment.Duration,\n\t): boolean {\n\t\treturn first.asMilliseconds() === second.asMilliseconds();\n\t}\n\n\tpublic static formatResponseValue (\n\t\tcolumnType: string,\n\t\tvalue: any,\n\t) {\n\t\tswitch (columnType) {\n\t\t\tcase 'datetime':\n\t\t\tcase 'date':\n\t\t\t// case ApiEnumApiType.TYPE_TIMESTAMP:\n\t\t\tcase 'timestamp':\n\t\t\t// case ApiEnumApiType.TYPE_TIMESTAMP_MS:\n\t\t\tcase 'timestamp_ms':\n\t\t\t\treturn this.formatResponseDate(\n\t\t\t\t\tvalue,\n\t\t\t\t);\n\t\t\tcase 'color':\n\t\t\t\treturn this.formatResponseColor(\n\t\t\t\t\tvalue,\n\t\t\t\t);\n\t\t\tcase 'duration':\n\t\t\t\treturn this.formatResponseDuration(\n\t\t\t\t\tvalue,\n\t\t\t\t);\n\t\t\tcase 'json':\n\t\t\t\treturn typeof value === 'string' && value !== '' ? JSON.parse(\n\t\t\t\t\tvalue,\n\t\t\t\t) : value;\n\t\t\tcase 'number':\n\t\t\t\treturn value === 0 ? null : value;\n\t\t\tcase 'filesize':\n\t\t\t\treturn value / 1000000;\n\t\t\tdefault:\n\t\t\t\treturn value;\n\t\t}\n\t}\n\n\tpublic static formatRequestValue (\n\t\tcolumnType: string,\n\t\tvalue: any,\n\t) {\n\t\tswitch (columnType) {\n\t\t\tcase 'datetime':\n\t\t\t\treturn this.formatRequestDateTime(\n\t\t\t\t\tvalue,\n\t\t\t\t);\n\t\t\tcase 'date':\n\t\t\t\treturn this.formatRequestDate(\n\t\t\t\t\tvalue,\n\t\t\t\t);\n\t\t\tcase 'color':\n\t\t\t\treturn this.formatRequestColor(\n\t\t\t\t\tvalue,\n\t\t\t\t);\n\t\t\tcase 'duration':\n\t\t\t\treturn this.formatRequestDuration(\n\t\t\t\t\tvalue,\n\t\t\t\t);\n\t\t\tcase 'number':\n\t\t\t\treturn value === 0 ? null : value;\n\t\t\tdefault:\n\t\t\t\treturn value;\n\t\t}\n\t}\n\n\tpublic static formatResponseDate (\n\t\t// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents\n\t\tvalue: null | any,\n\t): moment.Moment {\n\t\treturn value === null ? moment.invalid() : moment(\n\t\t\tvalue,\n\t\t\tmoment.ISO_8601,\n\t\t);\n\t}\n\n\tpublic static formatResponseDuration (\n\t\tvalue: null | number,\n\t): moment.Duration {\n\t\treturn moment.duration(\n\t\t\tvalue === null ? 0 : value,\n\t\t\t'seconds',\n\t\t);\n\t}\n\n\tpublic static formatResponseColor (\n\t\tvalue: string | null,\n\t): string | null {\n\t\tif (value === null) {\n\t\t\treturn value;\n\t\t}\n\n\t\treturn value.startsWith(\n\t\t\t'#',\n\t\t) ? value : '#' + value;\n\t}\n\n\tpublic static formatRequestDateTime (\n\t\tvalue: moment.Moment,\n\t): string | null {\n\t\treturn value.isValid() ? value.format(\n\t\t\tthis.SERVER_DATETIME_FORMAT,\n\t\t) : null;\n\t}\n\n\tpublic static formatRequestDate (\n\t\tvalue: moment.Moment,\n\t): string | null {\n\t\treturn value.isValid() ? value.format(\n\t\t\tthis.SERVER_DATE_FORMAT,\n\t\t) : null;\n\t}\n\n\tpublic static formatRequestDuration (\n\t\tvalue: moment.Duration,\n\t): number {\n\t\treturn value.asSeconds();\n\t}\n\n\tpublic static formatRequestColor (\n\t\tvalue: string | null,\n\t): string | null {\n\t\tif (value === null) {\n\t\t\treturn value;\n\t\t}\n\n\t\treturn value.startsWith(\n\t\t\t'#',\n\t\t) ? value.substring(\n\t\t\t1,\n\t\t) : value;\n\t}\n\n\tpublic static getDefaultValue (\n\t\tcolumnType: ApiEnumApiType,\n\t): any {\n\t\tswitch (columnType) {\n\t\t\t// case ApiEnumApiType.TYPE_INT:\n\t\t\tcase 'int':\n\t\t\t// case ApiEnumApiType.TYPE_DOUBLE:\n\t\t\tcase 'double':\n\t\t\t// case ApiEnumApiType.TYPE_PERCENTAGE:\n\t\t\tcase 'percentage':\n\t\t\t// case ApiEnumApiType.TYPE_PRICE:\n\t\t\tcase 'price':\n\t\t\t// case ApiEnumApiType.TYPE_ORDER:\n\t\t\tcase 'order':\n\t\t\t\treturn 0;\n\t\t\t// case ApiEnumApiType.TYPE_ITEM:\n\t\t\tcase 'item':\n\t\t\t// case ApiEnumApiType.TYPE_LINK:\n\t\t\tcase 'link':\n\t\t\t// case ApiEnumApiType.TYPE_CHILD:\n\t\t\tcase 'child':\n\t\t\t// case ApiEnumApiType.TYPE_SIBLING:\n\t\t\tcase 'sibling':\n\t\t\t\treturn null;\n\t\t\t// case ApiEnumApiType.TYPE_BOOL:\n\t\t\tcase 'bool':\n\t\t\t\treturn false;\n\t\t\t// case ApiEnumApiType.TYPE_ENUM:\n\t\t\tcase 'enum':\n\t\t\t\treturn '0';\n\t\t\t// case ApiEnumApiType.TYPE_DATE:\n\t\t\tcase 'date':\n\t\t\t// case ApiEnumApiType.TYPE_DATETIME:\n\t\t\tcase 'datetime':\n\t\t\t// case ApiEnumApiType.TYPE_TIMESTAMP:\n\t\t\tcase 'timestamp':\n\t\t\t// case ApiEnumApiType.TYPE_TIMESTAMP_MS:\n\t\t\tcase 'timestamp_ms':\n\t\t\t\treturn moment.invalid();\n\t\t\t// case ApiEnumApiType.TYPE_DURATION:\n\t\t\tcase 'duration':\n\t\t\t\treturn moment.duration();\n\t\t\t// case ApiEnumApiType.TYPE_TEXT:\n\t\t\tcase 'text':\n\t\t\t// case ApiEnumApiType.TYPE_LONGTEXT:\n\t\t\tcase 'longtext':\n\t\t\t\treturn '';\n\t\t\tcase 'time':\n\t\t\t\treturn '00:00';\n\t\t\t// case ApiEnumApiType.TYPE_COLOR:\n\t\t\tcase 'color':\n\t\t\t\treturn '#000000';\n\t\t\tdefault:\n\t\t\t\treturn '';\n\t\t\t// \t\t\t\t\temail\n\t\t\t// \t\t\t\t\turl\n\t\t\t// \t\t\t\t\thtml\n\t\t\t// \t\t\t\t\tjson\n\t\t\t// \t\t\t\t\tdata\n\t\t}\n\t}\n\n\tpublic static hasValue (\n\t\tcolumnType: ApiEnumApiType,\n\t\tvalue: any,\n\t): boolean {\n\t\tif (\n\t\t\tvalue === undefined\n\t\t\t|| value === null\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\tswitch (columnType) {\n\t\t\t// case ApiEnumApiType.TYPE_INT:\n\t\t\tcase 'int':\n\t\t\t// case ApiEnumApiType.TYPE_DOUBLE:\n\t\t\tcase 'double':\n\t\t\t// case ApiEnumApiType.TYPE_PERCENTAGE:\n\t\t\tcase 'percentage':\n\t\t\t// case ApiEnumApiType.TYPE_PRICE:\n\t\t\tcase 'price':\n\t\t\t// case ApiEnumApiType.TYPE_ORDER:\n\t\t\tcase 'order':\n\t\t\t\treturn !isNaN(\n\t\t\t\t\tvalue,\n\t\t\t\t);\n\t\t\t// case ApiEnumApiType.TYPE_ITEM:\n\t\t\tcase 'item':\n\t\t\t// case ApiEnumApiType.TYPE_LINK:\n\t\t\tcase 'link':\n\t\t\t// case ApiEnumApiType.TYPE_CHILD:\n\t\t\tcase 'child':\n\t\t\t// case ApiEnumApiType.TYPE_SIBLING:\n\t\t\tcase 'sibling':\n\t\t\t\treturn value !== null;\n\t\t\t// case ApiEnumApiType.TYPE_BOOL:\n\t\t\tcase 'bool':\n\t\t\t\treturn true;\n\t\t\t// case ApiEnumApiType.TYPE_ENUM:\n\t\t\tcase 'enum':\n\t\t\t\treturn value !== null;\n\t\t\t// case ApiEnumApiType.TYPE_DATE:\n\t\t\tcase 'date':\n\t\t\t// case ApiEnumApiType.TYPE_DATETIME:\n\t\t\tcase 'datetime':\n\t\t\t// case ApiEnumApiType.TYPE_TIMESTAMP:\n\t\t\tcase 'timestamp':\n\t\t\t// case ApiEnumApiType.TYPE_TIMESTAMP_MS:\n\t\t\tcase 'timestamp_ms':\n\t\t\t\treturn moment.isMoment(\n\t\t\t\t\tvalue,\n\t\t\t\t) && value.isValid();\n\t\t\t// case ApiEnumApiType.TYPE_DURATION:\n\t\t\tcase 'duration':\n\t\t\t\treturn moment.isDuration(\n\t\t\t\t\tvalue,\n\t\t\t\t) && value.asMilliseconds() > 0;\n\t\t\t// case ApiEnumApiType.TYPE_TEXT:\n\t\t\tcase 'text':\n\t\t\t// case ApiEnumApiType.TYPE_LONGTEXT:\n\t\t\tcase 'longtext':\n\t\t\t\treturn value !== '';\n\t\t\t// case ApiEnumApiType.TYPE_COLOR:\n\t\t\tcase 'color':\n\t\t\t\treturn value !== '#';\n\t\t\tdefault:\n\t\t\t\treturn !!value;\n\t\t\t// \t\t\t\t\temail\n\t\t\t// \t\t\t\t\turl\n\t\t\t// \t\t\t\t\thtml\n\t\t\t// \t\t\t\t\tjson\n\t\t\t// \t\t\t\t\tdata\n\t\t\t// time\n\t\t}\n\t}\n\n\tpublic static isDefaultValue (\n\t\tcolumnType: ApiEnumApiType,\n\t\tvalue: any,\n\t): boolean {\n\t\treturn this.compareFields(\n\t\t\tcolumnType,\n\t\t\tvalue,\n\t\t\tthis.getDefaultValue(\n\t\t\t\tcolumnType,\n\t\t\t),\n\t\t);\n\t}\n\n\tpublic static clone (\n\t\tcolumnType: string,\n\t\tvalue: any,\n\t): any {\n\t\tswitch (columnType) {\n\t\t\t// case ApiEnumApiType.TYPE_DURATION:\n\t\t\tcase 'duration':\n\t\t\t\treturn this.cloneDuration(\n\t\t\t\t\tvalue,\n\t\t\t\t);\n\t\t\t// case ApiEnumApiType.TYPE_DATE:\n\t\t\tcase 'date':\n\t\t\t// case ApiEnumApiType.TYPE_DATETIME:\n\t\t\tcase 'datetime':\n\t\t\t// case ApiEnumApiType.TYPE_TIMESTAMP:\n\t\t\tcase 'timestamp':\n\t\t\t// case ApiEnumApiType.TYPE_TIMESTAMP_MS:\n\t\t\tcase 'timestamp_ms':\n\t\t\t\treturn moment(\n\t\t\t\t\tvalue,\n\t\t\t\t);\n\t\t\t// case ApiEnumApiType.TYPE_JSON:\n\t\t\tcase 'json':\n\t\t\t\treturn copy(\n\t\t\t\t\tvalue,\n\t\t\t\t);\n\t\t\tdefault:\n\t\t\t\treturn value;\n\t\t}\n\t}\n\n\tpublic static getCloneFunction (\n\t\tcolumnType: string,\n\t) {\n\t\tswitch (columnType) {\n\t\t\t// case ApiEnumApiType.TYPE_DURATION:\n\t\t\tcase 'duration':\n\t\t\t\treturn this.cloneDuration;\n\t\t\t// case ApiEnumApiType.TYPE_DATE:\n\t\t\tcase 'date':\n\t\t\t// case ApiEnumApiType.TYPE_DATETIME:\n\t\t\tcase 'datetime':\n\t\t\t// case ApiEnumApiType.TYPE_TIMESTAMP:\n\t\t\tcase 'timestamp':\n\t\t\t// case ApiEnumApiType.TYPE_TIMESTAMP_MS:\n\t\t\tcase 'timestamp_ms':\n\t\t\t\treturn this.cloneDate;\n\t\t\tdefault:\n\t\t\t\treturn this.identity;\n\t\t}\n\t}\n\n\tpublic static cloneDuration (\n\t\tduration: moment.Duration,\n\t): moment.Duration {\n\t\treturn moment.duration(\n\t\t\tduration,\n\t\t);\n\t}\n\n\tpublic static cloneDate (\n\t\tdate: moment.Moment,\n\t): moment.Moment {\n\t\treturn date.clone();\n\t}\n\n\tpublic static identity<T> (\n\t\tinput: T,\n\t): T {\n\t\treturn input;\n\t}\n\n}\n","import { ApiItemType, BackendApiQuery, ItemId } from '@rentman/backend-types';\nimport { ApiRequestColumnMap, ApiRequestColumns, ApiRequestItemMap, ApiRequestLimit, ApiRequestServiceInterface, ApiResponseProcessor, ApiResponseProcessorFactory, FieldMap, RequestParameters } from '../internal';\n\nexport class ApiRequestService {\n\n\tpublic constructor (\n\t\tprivate externalApiRequestService: ApiRequestServiceInterface,\n\t\tprivate apiResponseProcessorFactory: ApiResponseProcessorFactory,\n\t) {\n\n\t}\n\n\tpublic template<ItemTypeType extends ApiItemType = any> (\n\t\titemType: ItemTypeType,\n\t\tparams?: Partial<RequestParameters<ItemTypeType>>,\n\t): Promise<ApiResponseProcessor> {\n\t\treturn this.processResponse(\n\t\t\tthis.externalApiRequestService.template(\n\t\t\t\titemType,\n\t\t\t\tparams,\n\t\t\t),\n\t\t);\n\t}\n\n\tpublic create<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\titemId: ItemId,\n\t\tvalues: Partial<FieldMap<ItemTypeType>>,\n\t\tcolumns: ApiRequestColumnMap,\n\t\tparentType?: ApiItemType,\n\t\tparentId?: ItemId,\n\t\tuniqueTransactionId?: string,\n\t): Promise<ApiResponseProcessor> {\n\t\treturn this.processResponse(\n\t\t\tthis.externalApiRequestService.create(\n\t\t\t\titemType,\n\t\t\t\titemId,\n\t\t\t\tvalues,\n\t\t\t\tcolumns,\n\t\t\t\tparentType,\n\t\t\t\tparentId,\n\t\t\t\tuniqueTransactionId,\n\t\t\t),\n\t\t);\n\t}\n\n\tpublic delete<ItemTypeType extends ApiItemType> (\n\t\titemType: ApiItemType,\n\t\titemIds: ItemId[],\n\t\tuniqueTransactionId?: string,\n\t): Promise<ApiResponseProcessor<ItemTypeType>> {\n\t\treturn this.processResponse(\n\t\t\tthis.externalApiRequestService.delete(\n\t\t\t\titemType,\n\t\t\t\titemIds,\n\t\t\t\tuniqueTransactionId,\n\t\t\t),\n\t\t);\n\t}\n\n\tpublic updateItems<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\titems: ApiRequestItemMap,\n\t\tcolumns: ApiRequestColumnMap,\n\t\tuniqueTransactionId?: string,\n\t): Promise<ApiResponseProcessor<ItemTypeType>> {\n\t\treturn this.processResponse(\n\t\t\tthis.externalApiRequestService.updateItems(\n\t\t\t\titemType,\n\t\t\t\titems,\n\t\t\t\tcolumns,\n\t\t\t\tuniqueTransactionId,\n\t\t\t),\n\t\t);\n\t}\n\n\tpublic requestSkeleton<ItemTypeType extends ApiItemType = ApiItemType> (\n\t\tparams: any,\n\t\trequestCanceler?: Promise<any>,\n\t): Promise<ApiResponseProcessor<ItemTypeType>> {\n\t\treturn this.processResponse(\n\t\t\tthis.externalApiRequestService.requestSkeleton(\n\t\t\t\tparams,\n\t\t\t\trequestCanceler,\n\t\t\t),\n\t\t);\n\t}\n\n\tpublic columns<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tcolumns: {\n\t\t\t[itemType: string]: ApiRequestColumns | true,\n\t\t},\n\t\tparams?: any,\n\t): Promise<ApiResponseProcessor<ItemTypeType>> {\n\t\treturn this.processResponse(\n\t\t\tthis.externalApiRequestService.columns(\n\t\t\t\titemType,\n\t\t\t\tcolumns,\n\t\t\t\tparams,\n\t\t\t),\n\t\t);\n\t}\n\n\tpublic query<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tquery: BackendApiQuery<ItemTypeType>,\n\t\tcolumns: ApiRequestColumnMap,\n\t\tlimit?: ApiRequestLimit<ItemTypeType>,\n\t): Promise<ApiResponseProcessor<ItemTypeType>> {\n\t\treturn this.processResponse(\n\t\t\tthis.externalApiRequestService.query(\n\t\t\t\titemType,\n\t\t\t\tquery,\n\t\t\t\tcolumns,\n\t\t\t\tlimit,\n\t\t\t),\n\t\t);\n\t}\n\n\tpublic module<ResponseType = unknown> (\n\t\tmodule: string,\n\t\tmethod: string,\n\t\tparams: Record<string, unknown>,\n\t): Promise<ResponseType> {\n\t\treturn this.externalApiRequestService._module(\n\t\t\tmodule,\n\t\t\tmethod,\n\t\t\tparams,\n\t\t);\n\t}\n\n\tpublic processResponse<ItemTypeType extends ApiItemType = ApiItemType> (\n\t\trequest: any,\n\t): Promise<ApiResponseProcessor<ItemTypeType>> {\n\t\treturn request.then(\n\t\t\t(\n\t\t\t\tresponse: any,\n\t\t\t) => this.apiResponseProcessorFactory.construct(\n\t\t\t\tresponse,\n\t\t\t),\n\t\t);\n\t}\n\n}\n","import { ApiItemType, ItemId, ResponseColumn, TempItemTypeWithoutFixedIds, UnknownResponseColumn } from '@rentman/backend-types';\nimport { ApiFormatter, ApiResponse, COLUMN_SEPERATOR, ColumnInfo, ColumnUtil, DerivedStringToRequestColumnPath, FieldMap, ItemTypeMap, KeyService, ResolveDerivedValue, ResponseColumnItemTypeMap, ResponseColumnMap } from '../internal';\n\n// todo[cache] extend base class per request (delete has different structure)\nexport class ApiResponseProcessor<RequestItemType extends ApiItemType = any> {\n\n\tpublic itemType: RequestItemType;\n\n\tpublic columns: ItemTypeMap<UnknownResponseColumn[]>;\n\tpublic links: ApiResponse<RequestItemType>['links'];\n\tpublic cacheable: boolean;\n\tpublic map: any;\n\tpublic items: ApiResponse<RequestItemType>['items'];\n\n\tpublic columnIndexMap: {\n\t\t[itemType: string]: {\n\t\t\t[columnId: string]: number,\n\t\t},\n\t} = {};\n\n\tpublic columnMap: ResponseColumnItemTypeMap = {} as ResponseColumnItemTypeMap;\n\n\tpublic constructor (\n\t\tpublic response: ApiResponse<RequestItemType>,\n\t) {\n\t\tthis.columns = response.columns;\n\t\tthis.items = response.items;\n\t\tthis.links = response.links;\n\t\tthis.cacheable = response.cacheable ?? false;\n\t\tthis.map = response.map;\n\t\tthis.itemType = response.itemType;\n\n\t\tthis.createColumnMaps();\n\t\tthis.replaceTempItemTypeIdsWithLocalIds();\n\t}\n\n\tpublic static addLazyFormattingFunction<Fields extends FieldMap<any>, ColumnId extends keyof Fields> (\n\t\tcolumnId: ColumnId,\n\t\tcolumnType: string,\n\t\tinitialValue: any,\n\t\tdestination: Fields,\n\t): void {\n\t\tObject.defineProperty(\n\t\t\tdestination,\n\t\t\tcolumnId,\n\t\t\t{\n\t\t\t\tenumerable: true,\n\t\t\t\tconfigurable: true,\n\t\t\t\tset:\n\t\t\t\t\tvalue => {\n\t\t\t\t\t\tdelete destination[columnId];\n\n\t\t\t\t\t\tdestination[columnId] = value;\n\t\t\t\t\t},\n\t\t\t\tget: () => {\n\t\t\t\t\tdelete destination[columnId];\n\n\t\t\t\t\treturn destination[columnId] = ApiFormatter.formatResponseValue(\n\t\t\t\t\t\tcolumnType,\n\t\t\t\t\t\tinitialValue,\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic fetchColumnObject (\n\t\titemType: ApiItemType,\n\t): ResponseColumnMap {\n\t\treturn this.columnMap[itemType];\n\t}\n\n\tpublic fetchDerivedValue<T extends string, DefaultValue = undefined> (\n\t\tinitialItemId: ItemId,\n\t\tcolumnPath: T,\n\t\tdefaultValue?: DefaultValue,\n\t): ResolveDerivedValue<RequestItemType, DerivedStringToRequestColumnPath<T>>;\n\n\tpublic fetchDerivedValue<T extends readonly string[], DefaultValue = undefined> (\n\t\tinitialItemId: ItemId,\n\t\tcolumnPath: T,\n\t\tdefaultValue?: DefaultValue,\n\t): ResolveDerivedValue<RequestItemType, T>;\n\n\tpublic fetchDerivedValue<DefaultValue = undefined> (\n\t\tinitialItemId: ItemId,\n\t\tpath: string[] | string,\n\t\tdefaultValue?: DefaultValue,\n\t\t// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents\n\t): any | DefaultValue {\n\t\tif (typeof path === 'string') {\n\t\t\tpath = path.split(\n\t\t\t\tCOLUMN_SEPERATOR,\n\t\t\t);\n\t\t}\n\n\t\tlet itemId = initialItemId;\n\t\tlet itemType = this.itemType;\n\n\t\tfor (let i = 0; i < path.length - 1; i++) {\n\t\t\tconst columnId = path[i];\n\n\t\t\tconst column = this.columnMap[itemType][columnId];\n\n\t\t\tif (column === undefined) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Column '${columnId}' not found in ApiResponseProcessor.fetchDerivedValue`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\t!ColumnUtil.isItemColumn(\n\t\t\t\t\tcolumn,\n\t\t\t\t)\n\t\t\t\t|| column.itemType === null\n\t\t\t) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Column '${columnId}' doesn't have children in ApiResponseProcessor.fetchDerivedValue`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\titemId = this.fetchValue(\n\t\t\t\titemType,\n\t\t\t\titemId,\n\t\t\t\tcolumnId,\n\t\t\t);\n\n\t\t\titemType = column.itemType;\n\n\t\t\tif (itemId === null) {\n\t\t\t\treturn defaultValue;\n\t\t\t}\n\t\t}\n\n\t\treturn this.fetchValue(\n\t\t\titemType,\n\t\t\titemId,\n\t\t\tpath[path.length - 1],\n\t\t) ?? defaultValue;\n\t}\n\n\tpublic fetchValue (\n\t\titemType: ApiItemType,\n\t\titemId: ItemId,\n\t\tcolumnId: string,\n\t) {\n\t\tif (this.items[itemType][itemId] === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst column = this.columnMap[itemType][columnId];\n\t\tconst index = this.columnIndexMap[itemType][columnId];\n\n\t\treturn ApiFormatter.formatResponseValue(\n\t\t\tcolumn.type,\n\t\t\tthis.items[itemType][itemId].data[index],\n\t\t);\n\t}\n\n\tpublic fetchColumnArray<const ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t): ResponseColumn<ItemTypeType>[] {\n\t\tconst result: ReturnType<ApiResponseProcessor['fetchColumnArray']> = [];\n\n\t\tfor (const apiColumn of this.columns[itemType]) {\n\t\t\tresult.push(\n\t\t\t\tapiColumn,\n\t\t\t);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic fetchDerivedObject (\n\t\titemType: ApiItemType,\n\t\titemId: ItemId,\n\t\trootColumns: ColumnInfo[],\n\t) {\n\t\tconst result = {};\n\n\t\tfor (const column of rootColumns) {\n\t\t\tthis.fetchDerivedValues(\n\t\t\t\tthis.fetchValue(\n\t\t\t\t\titemType,\n\t\t\t\t\titemId,\n\t\t\t\t\tcolumn.id,\n\t\t\t\t),\n\t\t\t\tcolumn,\n\t\t\t\tresult,\n\t\t\t);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic fetchDerivedValues (\n\t\tvalue: any,\n\t\tcolumn: ColumnInfo,\n\t\tdestination: any,\n\t): void {\n\t\tfor (const childColumn of column.children) {\n\t\t\tlet childValue;\n\n\t\t\tif (value === null) {\n\t\t\t\tchildValue = null;\n\t\t\t\tdestination[childColumn.path] = ApiFormatter.formatResponseValue(\n\t\t\t\t\tchildColumn.apiColumn.type,\n\t\t\t\t\tchildColumn.apiColumn.default,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tchildValue = this.fetchValue(\n\t\t\t\t\tcolumn.itemType,\n\t\t\t\t\tvalue,\n\t\t\t\t\tchildColumn.id,\n\t\t\t\t);\n\t\t\t\tdestination[childColumn.path] = childValue;\n\t\t\t}\n\n\t\t\tif (childColumn.isLeaf) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tthis.fetchDerivedValues(\n\t\t\t\tchildValue,\n\t\t\t\tchildColumn,\n\t\t\t\tdestination,\n\t\t\t);\n\t\t}\n\t}\n\n\t// Todo[types]: if we know the request column array we can improve this\n\tpublic fetchObject<const ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\titemId: string | ItemId,\n\t): FieldMap<ItemTypeType> | undefined {\n\t\tif (this.items[itemType] === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst item = this.items[itemType][itemId];\n\n\t\tif (item === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst data = this.items[itemType][itemId].data;\n\t\tconst result: FieldMap<ItemTypeType> = {} as FieldMap<ItemTypeType>;\n\n\t\tfor (let i = 0; i < data.length; i++) {\n\t\t\tconst column: UnknownResponseColumn = this.columns[itemType][i];\n\n\t\t\tif (\n\t\t\t\tApiFormatter.isExpensiveFormat(\n\t\t\t\t\tcolumn.type,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tApiResponseProcessor.addLazyFormattingFunction(\n\t\t\t\t\tcolumn.id as keyof FieldMap<ItemTypeType>,\n\t\t\t\t\tcolumn.type,\n\t\t\t\t\tdata[i],\n\t\t\t\t\tresult,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tresult[column.id] = ApiFormatter.formatResponseValue(\n\t\t\t\t\tcolumn.type,\n\t\t\t\t\tdata[i],\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic fetchObjectArray<const ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tidArray?: ItemId[] | null,\n\t): FieldMap<ItemTypeType>[] {\n\t\tconst result: any[] = [];\n\n\t\tif (idArray === null) {\n\t\t\tfor (const itemId in this.items[itemType]) {\n\t\t\t\tresult.push(\n\t\t\t\t\tthis.fetchObject(\n\t\t\t\t\t\titemType,\n\t\t\t\t\t\titemId,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\tif (idArray === undefined) {\n\t\t\tidArray = this.links[itemType];\n\t\t}\n\n\t\tfor (const itemId of idArray) {\n\t\t\tresult.push(\n\t\t\t\tthis.fetchObject(\n\t\t\t\t\titemType,\n\t\t\t\t\titemId,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic fetchColumnsObject (): ResponseColumnItemTypeMap {\n\t\treturn this.columnMap;\n\t}\n\n\tprivate createColumnMaps (): void {\n\t\tfor (const itemType in this.columns) {\n\t\t\tthis.columnIndexMap[itemType] = {};\n\t\t\tthis.columnMap[itemType] = {};\n\n\t\t\tfor (let i = 0; i < this.columns[itemType].length; i++) {\n\t\t\t\tconst column = this.columns[itemType][i];\n\n\t\t\t\tthis.columnIndexMap[itemType][column.id] = i;\n\t\t\t\tthis.columnMap[itemType][column.id] = column;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate replaceTempItemTypeIdsWithLocalIds (): void {\n\t\tfor (const itemType in this.links) {\n\t\t\tconst isTempItemType = TempItemTypeWithoutFixedIds.includes(\n\t\t\t\titemType as ApiItemType,\n\t\t\t);\n\n\t\t\tif (!isTempItemType) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst newLocalIds: ItemId[] = [];\n\n\t\t\tfor (const itemId of this.links[itemType]) {\n\t\t\t\tconst newLocalItemId = KeyService.getLocalId();\n\n\t\t\t\tnewLocalIds.push(\n\t\t\t\t\tnewLocalItemId,\n\t\t\t\t);\n\n\t\t\t\tconst values = this.items[itemType][itemId];\n\n\t\t\t\tvalues.data[this.columnIndexMap[itemType].id] = newLocalItemId;\n\n\t\t\t\tthis.items[itemType][newLocalItemId] = values;\n\t\t\t\tdelete this.items[itemType][itemId];\n\t\t\t}\n\n\t\t\tthis.links[itemType] = newLocalIds;\n\t\t}\n\t}\n\n}\n","import { ApiItemType } from '@rentman/backend-types';\nimport { ChildChangesDeltaItemCreateDelta, createPath, EntryParent, ItemEntry, ItemEntryMap, ItemMap, TransactionCache } from '../internal';\n\nexport type CreateRequestCompilationParent = ApiItemType | 'Void';\n\nexport type CreateCompilation = {\n\t[parentType: string]: {\n\t\t[parentId: number]: ItemMap<ChildChangesDeltaItemCreateDelta>,\n\t},\n};\n\nexport type DeleteCompilation = {\n\t[itemType: string]: ItemEntry[],\n};\n\nexport type UpdateCompilation = ItemEntryMap;\n\nexport class ChangesCompilation {\n\n\tpublic compilation: {\n\t\tcreate: CreateCompilation,\n\t\tdelete: DeleteCompilation,\n\t\tupdate: UpdateCompilation,\n\t} = {\n\t\tcreate: {},\n\t\tdelete: {},\n\t\tupdate: {},\n\t};\n\n\tpublic constructor (\n\t\tprivate transaction: TransactionCache,\n\t) {\n\t\tthis.processDelta();\n\t}\n\n\tprivate processDelta (): void {\n\t\tconst changesDelta = this.transaction.getDelta();\n\n\t\tfor (const deleteTuple of changesDelta.getDeleteTuplesIterator()) {\n\t\t\tif (\n\t\t\t\tdeleteTuple.entry.isLocal()\n\t\t\t\t// Cascading deletes will delete itself when processing the delete response items\n\t\t\t\t|| deleteTuple.isCascaded\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tthis.addDeleteEntry(\n\t\t\t\tdeleteTuple.entry,\n\t\t\t);\n\t\t}\n\n\t\tfor (const itemEntryId in changesDelta.created) {\n\t\t\tconst tuple = changesDelta.created[itemEntryId];\n\n\t\t\tthis.addCreateEntry(\n\t\t\t\ttuple,\n\t\t\t);\n\t\t}\n\n\t\tfor (const itemEntryId in changesDelta.updated) {\n\t\t\tconst tuple = changesDelta.updated[itemEntryId];\n\n\t\t\tthis.addUpdateEntry(\n\t\t\t\ttuple.entry,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate getDefaultParent (): EntryParent {\n\t\treturn {\n\t\t\titemType: 'Void',\n\t\t\titemId: 0,\n\t\t};\n\t}\n\n\tprivate addDeleteEntry (\n\t\titemEntry: ItemEntry,\n\t): void {\n\t\tcreatePath<ItemEntry[]>(\n\t\t\tthis.compilation.delete,\n\t\t\t[\n\t\t\t\titemEntry.itemType,\n\t\t\t],\n\t\t\t[\n\t\t\t\t[],\n\t\t\t],\n\t\t)\n\t\t\t.push(\n\t\t\t\titemEntry,\n\t\t\t);\n\t}\n\n\tprivate addUpdateEntry (\n\t\titemEntry: ItemEntry,\n\t): void {\n\t\tcreatePath(\n\t\t\tthis.compilation.update,\n\t\t\t[\n\t\t\t\titemEntry.itemType,\n\t\t\t\titemEntry.itemId,\n\t\t\t],\n\t\t\t[\n\t\t\t\t{},\n\t\t\t\titemEntry,\n\t\t\t],\n\t\t);\n\t}\n\n\tprivate addCreateEntry (\n\t\tcreateDelta: ChildChangesDeltaItemCreateDelta,\n\t): void {\n\t\tlet parent = this.transaction.getParent(\n\t\t\tcreateDelta.entry,\n\t\t);\n\n\t\tif (parent === null) {\n\t\t\tparent = this.getDefaultParent();\n\t\t}\n\n\t\tcreatePath(\n\t\t\tthis.compilation.create,\n\t\t\t[\n\t\t\t\tparent.itemType,\n\t\t\t\tparent.itemId,\n\t\t\t\tcreateDelta.entry.itemType,\n\t\t\t\tcreateDelta.entry.itemId,\n\t\t\t],\n\t\t\t[\n\t\t\t\t{},\n\t\t\t\t{},\n\t\t\t\t{},\n\t\t\t\tcreateDelta,\n\t\t\t],\n\t\t);\n\t}\n\n}\n","import { ApiItemType, ItemId } from '@rentman/backend-types';\nimport { ApiRequestService, ChangesCompilation, ChangesCompilationFactory, ChangesDeltaFactory, ChangesDeltaResult, CreateRequest, CreateRequestEntry, DeleteCompilation, ErrorHandlerInterface, getPath, hasProperties, inArray, ItemEntry, ItemIdConversionMap, RequestBufferManager, RequestColumnExpansionFactory, ResponseItemUpdateModeMap, ServerCache, TransactionCache, UpdateCompilation } from '../internal';\n\nexport type OnAfterCreateCallback = (conversionMap: ItemIdConversionMap) => void;\n\n/**\n * @description\n * Executes the changes from a specific {@link TransactionCache transaction} and returns a {@link ChangesDelta ChangesDelta}\n */\nexport class ChangesProcessor {\n\n\tprivate itemIdConversionMap: ItemIdConversionMap = {};\n\tprivate serverCache: ServerCache;\n\n\tpublic constructor (\n\t\tprivate apiRequestService: ApiRequestService,\n\t\tprivate changesCompilationFactory: ChangesCompilationFactory,\n\t\tprivate changesDeltaFactory: ChangesDeltaFactory,\n\t\tprivate errorHandler: ErrorHandlerInterface,\n\t\tprivate requestBufferManager: RequestBufferManager,\n\t\tprivate requestColumnExpansionFactory: RequestColumnExpansionFactory,\n\t\tprivate transaction: TransactionCache,\n\t\tprivate breakUpByParent?: boolean,\n\t\tprivate onAfterCreateCallback?: OnAfterCreateCallback,\n\t) {\n\t\tthis.serverCache = this.transaction.getServerCache();\n\t}\n\n\t/**\n\t * @description\n\t * Executes the requests in the order of:\n\t * 1. create\n\t * 2. update\n\t * 3. delete\n\t */\n\tpublic execute (): Promise<ItemIdConversionMap> {\n\t\tconst changesCompilation = this.changesCompilationFactory.construct(\n\t\t\tthis.transaction,\n\t\t);\n\n\t\tconst compilation = changesCompilation.compilation;\n\n\t\t// We're suspending query requests here to prevent the following situations:\n\t\t// - A newly created item being returned in a query while waiting for a create response. In this case, we could\n\t\t// end up caching the item twice, as we don't know the item in the query response is the item we sent the\n\t\t// create request for until the create response arrives.\n\t\t// - A deleted item being returned in a query while waiting for create / delete responses.\n\t\tthis.requestBufferManager.suspendRequests();\n\n\t\tconst uniqueTransactionId: string = self.crypto.randomUUID();\n\n\t\treturn this\n\t\t\t.executeCreateRequests(\n\t\t\t\tchangesCompilation,\n\t\t\t\tuniqueTransactionId,\n\t\t\t)\n\t\t\t.then(\n\t\t\t\t() => this.executeUpdateRequests(\n\t\t\t\t\tcompilation.update,\n\t\t\t\t\tuniqueTransactionId,\n\t\t\t\t),\n\t\t\t)\n\t\t\t.then(\n\t\t\t\t() => this.executeDeleteRequests(\n\t\t\t\t\tcompilation.delete,\n\t\t\t\t\tuniqueTransactionId,\n\t\t\t\t),\n\t\t\t)\n\t\t\t.then(\n\t\t\t\t() => this.itemIdConversionMap,\n\t\t\t)\n\t\t\t.finally(\n\t\t\t\t() => this.requestBufferManager.continueRequests(),\n\t\t\t);\n\t}\n\n\tprivate getMapValue (\n\t\titemType: ApiItemType,\n\t\titemId: ItemId,\n\t\tmap: ItemIdConversionMap = this.itemIdConversionMap,\n\t): ItemId | undefined {\n\t\tif (map === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (map[itemType] === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn map[itemType][itemId];\n\t}\n\n\tprivate executeCreateRequests (\n\t\tchangesCompilation: ChangesCompilation,\n\t\tuniqueTransactionId?: string,\n\t): Promise<ChangesDeltaResult[]> {\n\t\tconst requests = new CreateRequest(\n\t\t\tthis.requestColumnExpansionFactory,\n\t\t\tchangesCompilation.compilation.create,\n\t\t\tthis.transaction,\n\t\t\tthis.breakUpByParent,\n\t\t\tuniqueTransactionId,\n\t\t)\n\t\t\t.run();\n\n\t\tconst responses: Promise<any>[] = [];\n\n\t\tfor (const request of requests) {\n\t\t\tresponses.push(\n\t\t\t\tthis\n\t\t\t\t\t.executeCreateRequest(\n\t\t\t\t\t\trequest,\n\t\t\t\t\t)\n\t\t\t\t\t.then(\n\t\t\t\t\t\tresult => {\n\t\t\t\t\t\t\tif (this.onAfterCreateCallback !== undefined) {\n\t\t\t\t\t\t\t\tthis.onAfterCreateCallback(\n\t\t\t\t\t\t\t\t\tthis.itemIdConversionMap,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn result;\n\t\t\t\t\t\t},\n\t\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\treturn Promise.all(\n\t\t\tresponses,\n\t\t);\n\t}\n\n\tprivate executeCreateRequest (\n\t\trequestResource: CreateRequestEntry<any>,\n\t): Promise<ChangesDeltaResult> {\n\t\treturn this.apiRequestService\n\t\t\t.requestSkeleton(\n\t\t\t\trequestResource.request,\n\t\t\t)\n\t\t\t.then(\n\t\t\t\tresponse => {\n\t\t\t\t\tconst changesDelta = this.changesDeltaFactory.construct(\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t);\n\t\t\t\t\tconst itemEntries = requestResource.items;\n\t\t\t\t\tconst directRequestItemsMap: ResponseItemUpdateModeMap = {};\n\n\t\t\t\t\tfor (const itemType in itemEntries) {\n\t\t\t\t\t\tfor (const itemId in itemEntries[itemType]) {\n\t\t\t\t\t\t\tconst itemEntry = itemEntries[itemType][itemId];\n\t\t\t\t\t\t\tconst newItemId = this.getMapValue(\n\t\t\t\t\t\t\t\titemType as ApiItemType,\n\t\t\t\t\t\t\t\tparseInt(\n\t\t\t\t\t\t\t\t\titemId,\n\t\t\t\t\t\t\t\t\t10,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tresponse.map,\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t// If an entry is not returned in the response, this means that the item wasn't created on purpose by the backend\n\t\t\t\t\t\t\t// If a create would actually fail, the whole request would fail\n\t\t\t\t\t\t\tif (newItemId === undefined) {\n\t\t\t\t\t\t\t\tchangesDelta.setItemDeleted(\n\t\t\t\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// we're sure the entry exists, because otherwise you couldn't save it in the first place\n\t\t\t\t\t\t\tconst localItemEntry = this.transaction.itemHandler.entries.get(\n\t\t\t\t\t\t\t\titemType as ApiItemType,\n\t\t\t\t\t\t\t\titemId,\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t// eslint-disable-next-line max-len\n\t\t\t\t\t\t\tthis.serverCache.itemHandler.itemChanges[localItemEntry.id] = this.serverCache.itemHandler.copyTransactionItemEntryChanges(\n\t\t\t\t\t\t\t\tthis.transaction.itemHandler.itemChanges[localItemEntry.id],\n\t\t\t\t\t\t\t\tlocalItemEntry,\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\tthis.serverCache.itemHandler.entries.add(\n\t\t\t\t\t\t\t\tlocalItemEntry,\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\tthis.transaction.itemHandler.entries.clearByItemId(\n\t\t\t\t\t\t\t\titemType as ApiItemType,\n\t\t\t\t\t\t\t\tNumber(\n\t\t\t\t\t\t\t\t\titemId,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\tif (directRequestItemsMap[itemType] === undefined) {\n\t\t\t\t\t\t\t\tdirectRequestItemsMap[itemType] = {};\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tdirectRequestItemsMap[itemType][newItemId] = 'CLEAR_ALWAYS';\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// extend conversion map\n\t\t\t\t\tfor (const itemType in response.map) {\n\t\t\t\t\t\tif (this.itemIdConversionMap[itemType] === undefined) {\n\t\t\t\t\t\t\tthis.itemIdConversionMap[itemType] = {};\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tfor (const itemId in response.map[itemType]) {\n\t\t\t\t\t\t\tthis.itemIdConversionMap[itemType][itemId] = response.map[itemType][itemId];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// We want to pass the itemIdConversionMap containing only the conversion from this response\n\t\t\t\t\t// to the processResponse instead of the full this.itemIdConversionMap. Because if you pass the full\n\t\t\t\t\t// this.itemIdConversionMap it will process an item from an earlier create request multiple times.\n\t\t\t\t\tthis.serverCache.processResponse(\n\t\t\t\t\t\tresponse,\n\t\t\t\t\t\trequestResource.request.columns,\n\t\t\t\t\t\tchangesDelta,\n\t\t\t\t\t\tdirectRequestItemsMap,\n\t\t\t\t\t\tresponse.map,\n\t\t\t\t\t);\n\n\t\t\t\t\treturn this.serverCache.applyChangesDelta(\n\t\t\t\t\t\tchangesDelta,\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t\tresponse.map,\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t);\n\t}\n\n\tprivate async executeUpdateRequests (\n\t\tcompilation: UpdateCompilation,\n\t\tuniqueTransactionId: string,\n\t): Promise<void> {\n\t\tfor (const itemType in compilation) {\n\t\t\tawait this.executeUpdateRequest(\n\t\t\t\titemType,\n\t\t\t\tcompilation[itemType],\n\t\t\t\tuniqueTransactionId,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate async executeUpdateRequest<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\titemEntries: {\n\t\t\t[itemId: number]: ItemEntry<ItemTypeType>,\n\t\t},\n\t\tuniqueTransactionId: string,\n\t): Promise<void> {\n\t\tconst request: {\n\t\t\t[itemType: string]: {\n\t\t\t\t[itemId: string]: {\n\t\t\t\t\t[columnId: string]: any,\n\t\t\t\t},\n\t\t\t},\n\t\t} = {};\n\n\t\tconst requestColumns = this.requestColumnExpansionFactory.construct();\n\n\t\trequest[itemType] = {};\n\n\t\t// we need to do the formatRequest call here (fields might have been updated)\n\t\tfor (const itemId in itemEntries) {\n\t\t\tconst itemEntry = itemEntries[itemId];\n\t\t\tconst formattedValues = this.transaction.itemHandler.formatRequest(\n\t\t\t\titemEntry,\n\t\t\t);\n\n\t\t\tif (\n\t\t\t\t!hasProperties(\n\t\t\t\t\tformattedValues,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst itemRequest: any = request[itemType][itemId] = {};\n\t\t\tconst parameters = getPath(\n\t\t\t\tthis.transaction.tabRequestParameters,\n\t\t\t\t[\n\t\t\t\t\titemType,\n\t\t\t\t\titemId,\n\t\t\t\t],\n\t\t\t);\n\n\t\t\titemRequest.values = formattedValues;\n\n\t\t\tif (parameters !== undefined) {\n\t\t\t\titemRequest.parameters = parameters;\n\t\t\t}\n\n\t\t\t// We can assume that if an itemEntry fits a collection it already has a superset of the collection's columns\n\t\t\t// todo: verify if this is actually true\n\t\t\trequestColumns.expandWithColumnSet(\n\t\t\t\titemEntry.columns,\n\t\t\t);\n\t\t}\n\n\t\tif (\n\t\t\t// It can happen that when only parent fields are changed a LinkTo is done which then causes there to be no more changes on the item so\n\t\t\t// an empty update request is done. We can remove this check when we can do Update requests instead of LinkTo requests\n\t\t\t!hasProperties(\n\t\t\t\trequest[itemType],\n\t\t\t)\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst apiRequestColumns = requestColumns.get();\n\n\t\tconst response = await this.apiRequestService.updateItems(\n\t\t\titemType,\n\t\t\trequest,\n\t\t\tapiRequestColumns,\n\t\t\tuniqueTransactionId,\n\t\t);\n\n\t\tconst directRequestItemsMap: ResponseItemUpdateModeMap = {};\n\n\t\tfor (const requestItemType in request) {\n\t\t\tif (directRequestItemsMap[requestItemType] === undefined) {\n\t\t\t\tdirectRequestItemsMap[requestItemType] = {};\n\t\t\t}\n\n\t\t\tfor (const itemId in request[requestItemType]) {\n\t\t\t\tdirectRequestItemsMap[requestItemType][itemId] = 'CLEAR_ALWAYS';\n\t\t\t}\n\t\t}\n\n\t\tconst changesDelta = this.changesDeltaFactory.construct(\n\t\t\tfalse,\n\t\t\t[\n\t\t\t\titemType,\n\t\t\t],\n\t\t);\n\n\t\tawait this.serverCache.applyChangesDelta(\n\t\t\tthis.serverCache.processResponse(\n\t\t\t\tresponse,\n\t\t\t\tapiRequestColumns,\n\t\t\t\tchangesDelta,\n\t\t\t\tdirectRequestItemsMap,\n\t\t\t),\n\t\t);\n\t}\n\n\tprivate executeDeleteRequests (\n\t\tcompilation: DeleteCompilation,\n\t\tuniqueTransactionId: string,\n\t): Promise<void[]> {\n\t\tconst requests: Promise<void>[] = [];\n\n\t\t// clearing not necessary\n\t\tfor (const itemType in compilation) {\n\t\t\trequests.push(\n\t\t\t\tthis.executeDeleteRequest(\n\t\t\t\t\titemType as ApiItemType,\n\t\t\t\t\tcompilation[itemType],\n\t\t\t\t\tuniqueTransactionId,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\treturn Promise.all(\n\t\t\trequests,\n\t\t);\n\t}\n\n\tprivate executeDeleteRequest<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\titemEntries: ItemEntry<ItemTypeType>[],\n\t\tuniqueTransactionId: string,\n\t): Promise<void> {\n\t\treturn this.apiRequestService\n\t\t\t.delete(\n\t\t\t\titemType,\n\t\t\t\titemEntries.map(\n\t\t\t\t\tentry => entry.itemId,\n\t\t\t\t),\n\t\t\t\tuniqueTransactionId,\n\t\t\t)\n\t\t\t.then(\n\t\t\t\tresponse => {\n\t\t\t\t\tconst changesDelta = this.changesDeltaFactory.constructParentDelta();\n\t\t\t\t\tconst responseIdArray = response.items;\n\n\t\t\t\t\tfor (const itemEntry of itemEntries) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t!inArray(\n\t\t\t\t\t\t\t\titemEntry.itemId,\n\t\t\t\t\t\t\t\tresponseIdArray,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tthis.errorHandler.logWarning(\n\t\t\t\t\t\t\t\t'Delete failed!',\n\t\t\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tchangesDelta.setItemDeleted(\n\t\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn this.serverCache.applyChangesFromParent(\n\t\t\t\t\t\tchangesDelta,\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t);\n\t}\n\n}\n","import { ApiItemType, GetColumnType, ResponseColumn, ResponseColumnItem, UnknownResponseColumn } from '@rentman/backend-types';\nimport { ApiRequestColumn, ApiRequestColumnArray, ApiRequestColumns, ApiResponseProcessor, ColumnUtil, DerivedRequestColumnObject, ItemTypeColumnId, MutableApiRequestColumnArray, ResponseColumnItemTypeMap } from '../internal';\n\nexport class ColumnCache {\n\n\tprivate cache: Partial<ResponseColumnItemTypeMap> = {};\n\n\tprivate pendingCache: {\n\t\t[itemType: string]: {\n\t\t\t[columnId: string]: Promise<ApiResponseProcessor>,\n\t\t},\n\t} = {};\n\n\tprivate allColumns: {\n\t\t[itemType: string]: boolean,\n\t} = {};\n\n\tpublic setColumn<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tresponseColumn: ResponseColumn<ItemTypeType>,\n\t): ResponseColumn<ItemTypeType> {\n\t\tconst cache = this.cache;\n\n\t\tif (cache[itemType] === undefined) {\n\t\t\tcache[itemType] = {} as ResponseColumnItemTypeMap[ItemTypeType];\n\t\t}\n\n\t\tconst entry = cache[itemType]!;\n\t\tconst columnId = responseColumn.id as string;\n\n\t\tif (entry[columnId] === undefined) {\n\t\t\tentry[columnId] = responseColumn as UnknownResponseColumn;\n\t\t}\n\n\t\treturn entry[columnId] as ResponseColumn<ItemTypeType>;\n\t}\n\n\tpublic setColumns<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\trequestColumns: ApiRequestColumns<ItemTypeType>,\n\t\tresponseColumns: ResponseColumnItemTypeMap,\n\t\tcolumnFilter: string | false,\n\t): ResponseColumnItemTypeMap {\n\t\tconst result: ResponseColumnItemTypeMap = {} as ResponseColumnItemTypeMap;\n\n\t\tfor (const responseType in responseColumns) {\n\t\t\tconst columns = responseColumns[responseType];\n\n\t\t\tresult[responseType] = {};\n\n\t\t\tfor (const columnId in columns) {\n\t\t\t\tresult[responseType][columnId] = this.setColumn(\n\t\t\t\t\tresponseType as ApiItemType,\n\t\t\t\t\tcolumns[columnId],\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (requestColumns === true && columnFilter === false) {\n\t\t\tthis.allColumns[itemType] = true;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic setPendingColumn<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tcolumnId: ItemTypeColumnId<ItemTypeType>,\n\t\tpromise: Promise<ApiResponseProcessor>,\n\t): void {\n\t\tconst cache = this.pendingCache;\n\n\t\tif (cache[itemType] === undefined) {\n\t\t\tcache[itemType] = {};\n\t\t}\n\n\t\tconst entry = cache[itemType];\n\n\t\tif (entry[columnId as string] === undefined) {\n\t\t\tentry[columnId as string] = promise;\n\t\t}\n\t}\n\n\tpublic clearPendingColumns<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\trequestColumns: ApiRequestColumnArray<ItemTypeType>,\n\t): void {\n\t\tfor (const columnIdOrDerivedObject of requestColumns) {\n\t\t\tconst parsedRequestColumn = ColumnUtil.parseRequestColumn(\n\t\t\t\tcolumnIdOrDerivedObject,\n\t\t\t);\n\n\t\t\tdelete this.pendingCache[itemType]?.[parsedRequestColumn.id as string];\n\t\t}\n\t}\n\n\tpublic setPendingColumns<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\trequestColumns: ApiRequestColumnArray<ItemTypeType>,\n\t\tpromise: Promise<ApiResponseProcessor>,\n\t): void {\n\t\tfor (const columnIdOrDerivedObject of requestColumns) {\n\t\t\t// Derived columns are not supported and can not either due to it being in a type\n\t\t\tconst parsedRequestColumn = ColumnUtil.parseRequestColumn(\n\t\t\t\tcolumnIdOrDerivedObject,\n\t\t\t);\n\n\t\t\tthis.setPendingColumn(\n\t\t\t\titemType,\n\t\t\t\tparsedRequestColumn.id,\n\t\t\t\tpromise,\n\t\t\t);\n\t\t}\n\t}\n\n\tpublic retrieve<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\trequestColumns: ApiRequestColumns<ItemTypeType>,\n\t): {\n\t\tcached: Partial<ResponseColumnItemTypeMap>,\n\t\tmissing: ApiRequestColumns<ItemTypeType>,\n\t\tpending: Promise<ApiRequestColumns<ItemTypeType>> | null,\n\t} {\n\t\tif (requestColumns === true) {\n\t\t\tif (\n\t\t\t\tthis.containsAll(\n\t\t\t\t\titemType,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\treturn {\n\t\t\t\t\tcached: this.getColumns(\n\t\t\t\t\t\titemType,\n\t\t\t\t\t),\n\t\t\t\t\tmissing: [],\n\t\t\t\t\tpending: null,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tcached: {},\n\t\t\t\tmissing: true,\n\t\t\t\tpending: null,\n\t\t\t};\n\t\t}\n\n\t\tconst responseAccumulator: ResponseColumnItemTypeMap = {} as ResponseColumnItemTypeMap;\n\t\tconst requestAccumulator: MutableApiRequestColumnArray<ItemTypeType> = [];\n\t\tconst pendingAccumulator: Promise<any>[] = [];\n\n\t\tthis.retrieveColumns(\n\t\t\titemType,\n\t\t\trequestColumns,\n\t\t\trequestAccumulator,\n\t\t\tresponseAccumulator,\n\t\t\tpendingAccumulator,\n\t\t);\n\n\t\treturn {\n\t\t\tcached: responseAccumulator,\n\t\t\tmissing: requestAccumulator,\n\t\t\tpending: pendingAccumulator.length > 0\n\t\t\t\t? Promise.all(\n\t\t\t\t\tpendingAccumulator,\n\t\t\t\t)\n\t\t\t\t: null,\n\t\t};\n\t}\n\n\tpublic containsAll (\n\t\titemType: ApiItemType,\n\t): boolean {\n\t\treturn this.allColumns[itemType] === true;\n\t}\n\n\tpublic getColumns (\n\t\titemType: ApiItemType,\n\t): ResponseColumnItemTypeMap {\n\t\tconst cache = this.cache;\n\n\t\treturn {\n\t\t\t[itemType]: cache[itemType] === undefined\n\t\t\t\t? {}\n\t\t\t\t: cache[itemType],\n\t\t} as ResponseColumnItemTypeMap;\n\t}\n\n\tpublic getColumn<ItemTypeType extends ApiItemType, ColumnId extends ItemTypeColumnId<ItemTypeType>> (\n\t\titemType: ItemTypeType,\n\t\tcolumnId: ColumnId,\n\t): GetColumnType<ItemTypeType, ColumnId> | undefined {\n\t\tconst cache = this.cache[itemType];\n\n\t\tif (cache === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn cache[columnId as string];\n\t}\n\n\tprivate retrieveColumns<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\trequestColumns: ApiRequestColumnArray<ItemTypeType>,\n\t\trequestAccumulator: MutableApiRequestColumnArray<ItemTypeType>,\n\t\tresponseAccumulator: Partial<ResponseColumnItemTypeMap>,\n\t\tpendingAccumulator: Promise<ApiResponseProcessor>[],\n\t): void {\n\t\t// always retrieve the id column\n\t\tthis.retrieveColumn(\n\t\t\titemType,\n\t\t\t'id',\n\t\t\trequestAccumulator,\n\t\t\tresponseAccumulator,\n\t\t\tpendingAccumulator,\n\t\t);\n\n\t\tfor (const requestColumn of requestColumns) {\n\t\t\tthis.retrieveColumn(\n\t\t\t\titemType,\n\t\t\t\trequestColumn,\n\t\t\t\trequestAccumulator,\n\t\t\t\tresponseAccumulator,\n\t\t\t\tpendingAccumulator,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate retrieveColumn<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\trequestColumn: ApiRequestColumn<ItemTypeType>,\n\t\trequestAccumulator: MutableApiRequestColumnArray<ItemTypeType>,\n\t\tresponseAccumulator: Partial<ResponseColumnItemTypeMap>,\n\t\tpendingAccumulator: Promise<ApiResponseProcessor>[],\n\t): void {\n\t\tconst column = ColumnUtil.parseRequestColumn(\n\t\t\trequestColumn,\n\t\t);\n\t\tconst responseColumn = this.getColumn(\n\t\t\titemType,\n\t\t\tcolumn.id,\n\t\t);\n\n\t\t// If the column is not in the response yet\n\t\tif (responseColumn === undefined) {\n\t\t\tconst pendingColumnPromise = this.pendingCache[itemType]?.[column.id as string];\n\n\t\t\t// And it is also not pending, it is a requested column\n\t\t\tif (pendingColumnPromise === undefined) {\n\t\t\t\trequestAccumulator.push(\n\t\t\t\t\trequestColumn,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\t// Otherwise the column request is pending\n\t\t\t\tpendingAccumulator.push(\n\t\t\t\t\tpendingColumnPromise,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (responseAccumulator[itemType] === undefined) {\n\t\t\tresponseAccumulator[itemType] = {} as ResponseColumnItemTypeMap[ItemTypeType];\n\t\t}\n\n\t\tresponseAccumulator[itemType]![column.id as string] = responseColumn;\n\n\t\tif (column.children.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst missingDerived: MutableApiRequestColumnArray<ItemTypeType> = [];\n\n\t\tthis.retrieveColumns(\n\t\t\t(responseColumn as ResponseColumnItem).itemType,\n\t\t\tcolumn.children as ApiRequestColumnArray<ItemTypeType>,\n\t\t\tmissingDerived,\n\t\t\tresponseAccumulator,\n\t\t\tpendingAccumulator,\n\t\t);\n\n\t\tif (missingDerived.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\trequestAccumulator.push(\n\t\t\t{\n\t\t\t\t[column.id]: missingDerived,\n\t\t\t} as unknown as DerivedRequestColumnObject<ItemTypeType>,\n\t\t);\n\t}\n\n}\n","import { ApiItemType } from '@rentman/backend-types';\nimport { ApiRequestColumnArray, ApiRequestColumns, ColumnExpansionResult, ColumnInfo, ColumnInfoFactory, ColumnSet, MutableApiRequestColumnArray, ResponseColumnItemTypeMap, RootColumnMap } from '../internal';\n\n/**\n * @description\n * A ColumnExpansion is used to make sure {@link ItemEntry ItemEntries} that have the same {@link ColumnSet ColumnSet} (matched on {@link ColumnSet.id ColumnSet.id}) will all get the same new expanded ColumnSet\n */\nexport class ColumnExpansion<ItemTypeType extends ApiItemType> {\n\n\tprivate expansionMap: {\n\t\t[columnSetId: string]: ColumnExpansionResult<ItemTypeType> | undefined,\n\t} = {};\n\n\tprivate requestColumnsTrue: boolean;\n\tprivate requestColumns: ApiRequestColumnArray<ItemTypeType>;\n\n\tpublic constructor (\n\t\tprivate columnInfoFactory: ColumnInfoFactory,\n\t\tpublic itemType: ItemTypeType,\n\t\trequestColumns: ApiRequestColumns<ItemTypeType>,\n\t\tpublic responseColumns: ResponseColumnItemTypeMap,\n\t) {\n\t\tif (requestColumns === true) {\n\t\t\t// requestColumns should always be an array, when it is true derived column information will be lost\n\t\t\tthis.requestColumnsTrue = true;\n\n\t\t\tconst requestColumnArray: MutableApiRequestColumnArray = [];\n\n\t\t\tfor (const columnId in responseColumns[itemType]) {\n\t\t\t\trequestColumnArray.push(\n\t\t\t\t\tcolumnId,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.requestColumns = requestColumnArray as ApiRequestColumnArray<ItemTypeType>;\n\t\t} else {\n\t\t\tthis.requestColumnsTrue = false;\n\t\t\tthis.requestColumns = requestColumns;\n\t\t}\n\t}\n\n\tpublic run (\n\t\tcolumnSet: ColumnSet<ItemTypeType>,\n\t): ColumnExpansionResult<ItemTypeType> {\n\t\tconst expansionMap = this.expansionMap;\n\t\tconst columnSetId = columnSet.id;\n\n\t\tif (expansionMap[columnSetId] !== undefined) {\n\t\t\treturn expansionMap[columnSetId];\n\t\t}\n\n\t\treturn expansionMap[columnSetId] = columnSet.expand(\n\t\t\tthis.requestColumns,\n\t\t\tthis.requestColumnsTrue,\n\t\t\tthis.responseColumns,\n\t\t);\n\t}\n\n\tpublic aggregateRootColumns (): ColumnInfo<ItemTypeType>[] {\n\t\tconst expansionMap = this.expansionMap;\n\n\t\tconst rootColumnMap: RootColumnMap = {};\n\n\t\tfor (const columnSetId in expansionMap) {\n\t\t\tconst difference = expansionMap[columnSetId]!.difference;\n\n\t\t\tif (difference === null) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tthis.expandRootColumnMap(\n\t\t\t\tdifference.root,\n\t\t\t\trootColumnMap,\n\t\t\t);\n\t\t}\n\n\t\treturn this.columnInfoFactory.constructFromRootMap(\n\t\t\trootColumnMap,\n\t\t);\n\t}\n\n\tprivate expandRootColumnMap<ColumnItemType extends ApiItemType> (\n\t\tcolumns: ColumnInfo<ColumnItemType>[],\n\t\tdestination: RootColumnMap,\n\t): void {\n\t\tfor (const column of columns) {\n\t\t\tconst columnId = column.id;\n\n\t\t\tif (destination[columnId] === undefined) {\n\t\t\t\tdestination[columnId] = {\n\t\t\t\t\tapiColumn: column.apiColumn,\n\t\t\t\t\tchildren: {},\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tthis.expandRootColumnMap(\n\t\t\t\tcolumn.children,\n\t\t\t\tdestination[columnId].children,\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ApiItemType, ResponseColumn, ResponseColumnCustom } from '@rentman/backend-types';\nimport { UnknownResponseColumn } from '@rentman/backend-types/dist/manual/api-response-column';\nimport { API_COLUMN_LOCATION, ApiRequestColumns, ApiRequestService, ColumnCache, ColumnUtil, ResponseColumnItemTypeMap } from '../internal';\n\nexport class ColumnHandler {\n\n\tpublic constructor (\n\t\tprivate apiRequestService: ApiRequestService,\n\t\tprivate cache: ColumnCache,\n\t) {\n\t}\n\n\tpublic setColumn<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tresponseColumn: ResponseColumn<ItemTypeType>,\n\t): ResponseColumn<ItemTypeType> {\n\t\treturn this.cache.setColumn(\n\t\t\titemType,\n\t\t\tresponseColumn,\n\t\t);\n\t}\n\n\tpublic setColumns<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\trequestColumns: ApiRequestColumns<ItemTypeType>,\n\t\tresponseColumns: ResponseColumnItemTypeMap,\n\t\tfilter: string | false = false,\n\t): ResponseColumnItemTypeMap {\n\t\treturn this.cache.setColumns(\n\t\t\titemType,\n\t\t\trequestColumns,\n\t\t\tresponseColumns,\n\t\t\tfilter,\n\t\t);\n\t}\n\n\tpublic fetchItemTypeTranslations (\n\t\titemTypes: ApiItemType[],\n\t): Promise<{[itemType: string]: string,}> {\n\t\treturn Promise\n\t\t\t.all(\n\t\t\t\titemTypes.map(\n\t\t\t\t\titemType => this.fetch(\n\t\t\t\t\t\titemType,\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t'id',\n\t\t\t\t\t\t],\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t)\n\t\t\t.then(\n\t\t\t\tresponseColumnArray => responseColumnArray.reduce(\n\t\t\t\t\t(\n\t\t\t\t\t\taccumulator,\n\t\t\t\t\t\tresponseColumns,\n\t\t\t\t\t\tindex,\n\t\t\t\t\t) => {\n\t\t\t\t\t\tconst itemType = itemTypes[index];\n\n\t\t\t\t\t\taccumulator[itemType] = responseColumns[itemType].id.name;\n\n\t\t\t\t\t\treturn accumulator;\n\t\t\t\t\t},\n\t\t\t\t\t{} as {[itemType: string]: string,},\n\t\t\t\t),\n\t\t\t);\n\t}\n\n\tpublic fetch<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\trequestColumns: ApiRequestColumns<ItemTypeType>,\n\t\tparams?: any,\n\t): Promise<ResponseColumnItemTypeMap> {\n\t\tconst columnResource = this.cache.retrieve(\n\t\t\titemType,\n\t\t\trequestColumns,\n\t\t);\n\n\t\t// We are not missing any columns and there are currently no columns requests in flight\n\t\t// so we can just return everything from the cache\n\t\tif (\n\t\t\tcolumnResource.missing !== true\n\t\t\t&& columnResource.missing.length === 0\n\t\t\t&& columnResource.pending === null\n\t\t) {\n\t\t\treturn Promise.resolve(\n\t\t\t\tcolumnResource.cached as ResponseColumnItemTypeMap,\n\t\t\t);\n\t\t}\n\n\t\t// We are not missing any columns but there are still requests in flight so we just return that one\n\t\t// otherwise it would do the same request again\n\t\tif (\n\t\t\tcolumnResource.missing !== true\n\t\t\t&& columnResource.missing.length === 0\n\t\t\t&& columnResource.pending !== null\n\t\t) {\n\t\t\treturn columnResource.pending.then(\n\t\t\t\t() => {\n\t\t\t\t\t// The pending columns are not all columns we need, so we retrieve the full set from the cache\n\t\t\t\t\treturn this.cache.retrieve(\n\t\t\t\t\t\titemType,\n\t\t\t\t\t\trequestColumns,\n\t\t\t\t\t).cached as ResponseColumnItemTypeMap;\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\t// We are missing columns and there are also column requests in flight\n\t\tif (\n\t\t\tcolumnResource.missing !== true\n\t\t\t&& columnResource.missing.length > 0\n\t\t\t&& columnResource.pending !== null\n\t\t) {\n\t\t\treturn Promise\n\t\t\t\t.all(\n\t\t\t\t\t[\n\t\t\t\t\t\tthis.request(\n\t\t\t\t\t\t\titemType,\n\t\t\t\t\t\t\tcolumnResource.missing,\n\t\t\t\t\t\t\tparams,\n\t\t\t\t\t\t),\n\t\t\t\t\t\tcolumnResource.pending,\n\t\t\t\t\t],\n\t\t\t\t)\n\t\t\t\t.then(\n\t\t\t\t\t() => {\n\t\t\t\t\t\t// The pending columns are not all columns we need, so we retrieve the full set from the cache\n\t\t\t\t\t\treturn this.cache.retrieve(\n\t\t\t\t\t\t\titemType,\n\t\t\t\t\t\t\trequestColumns,\n\t\t\t\t\t\t).cached as ResponseColumnItemTypeMap;\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t}\n\n\t\t// We are missing columns and there are no column requests in flight\n\t\treturn this\n\t\t\t.request(\n\t\t\t\titemType,\n\t\t\t\tcolumnResource.missing,\n\t\t\t\tparams,\n\t\t\t)\n\t\t\t.then(\n\t\t\t\tresponseColumns => {\n\t\t\t\t\treturn ColumnUtil.mergeResponseColumns(\n\t\t\t\t\t\tresponseColumns,\n\t\t\t\t\t\tcolumnResource.cached as ResponseColumnItemTypeMap,\n\t\t\t\t\t).merged;\n\t\t\t\t},\n\t\t\t);\n\t}\n\n\tpublic fetchAll (\n\t\titemType: ApiItemType,\n\t): Promise<ResponseColumnItemTypeMap> {\n\t\tif (this.cache.containsAll(\n\t\t\titemType,\n\t\t)) {\n\t\t\treturn Promise.resolve(\n\t\t\t\tthis.cache.getColumns(\n\t\t\t\t\titemType,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\treturn this.request(\n\t\t\titemType,\n\t\t\ttrue,\n\t\t);\n\t}\n\n\tpublic async fetchEditableCustomColumns<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t): Promise<ResponseColumnCustom[]> {\n\t\tconst columns = await this.fetchAll(\n\t\t\titemType,\n\t\t);\n\n\t\tconst result: ResponseColumnCustom[] = [];\n\n\t\tfor (const columnId in columns[itemType]) {\n\t\t\tconst responseColumn = columns[itemType][columnId] as ResponseColumn<ItemTypeType>;\n\n\t\t\tif (\n\t\t\t\tColumnUtil.isCustomColumn(\n\t\t\t\t\tresponseColumn,\n\t\t\t\t)\n\t\t\t\t&& ColumnUtil.hasLocationProperty(\n\t\t\t\t\tresponseColumn as UnknownResponseColumn,\n\t\t\t\t\tAPI_COLUMN_LOCATION.EDIT,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tresult.push(\n\t\t\t\t\tresponseColumn,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate request<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tcolumns: ApiRequestColumns<ItemTypeType>,\n\t\tparams: {filter: string | false,} = {\n\t\t\tfilter: false,\n\t\t},\n\t): Promise<ResponseColumnItemTypeMap> {\n\t\tconst promise = this.apiRequestService.columns(\n\t\t\titemType,\n\t\t\t{\n\t\t\t\t[itemType]: columns,\n\t\t\t},\n\t\t\tparams,\n\t\t);\n\n\t\t// We don't support caching pending columns for columns true or filters\n\t\tif (\n\t\t\tcolumns !== true\n\t\t\t&& params.filter === false\n\t\t) {\n\t\t\tthis.cache.setPendingColumns(\n\t\t\t\titemType,\n\t\t\t\tcolumns,\n\t\t\t\tpromise,\n\t\t\t);\n\t\t}\n\n\t\treturn promise.then(\n\t\t\tcolumnResource => {\n\t\t\t\tif (\n\t\t\t\t\tcolumns !== true\n\t\t\t\t\t&& params.filter === false\n\t\t\t\t) {\n\t\t\t\t\tthis.cache.clearPendingColumns(\n\t\t\t\t\t\titemType,\n\t\t\t\t\t\tcolumns,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn this.cache.setColumns(\n\t\t\t\t\titemType,\n\t\t\t\t\tcolumns,\n\t\t\t\t\tcolumnResource.fetchColumnsObject(),\n\t\t\t\t\tparams.filter,\n\t\t\t\t);\n\t\t\t},\n\t\t);\n\t}\n\n}\n","import { ApiItemType, GetColumnType } from '@rentman/backend-types';\nimport { UnknownResponseColumn } from '@rentman/backend-types/dist/manual/api-response-column';\nimport { ApiRequestColumnArray, ItemTypeColumnId } from '..';\nimport { COLUMN_SEPERATOR } from '../constants';\n\nexport class ColumnInfo<ItemTypeType extends ApiItemType = any, ColumnId extends ItemTypeColumnId<ItemTypeType> = any> {\n\n\tpublic id: ColumnId;\n\tpublic level: number;\n\tpublic path: string;\n\tpublic tailPath: string;\n\tpublic itemType: ItemTypeType | null = null;\n\t// The item type of the child columns is not the same as the item type of the parent column.\n\tpublic children: ColumnInfo<ApiItemType>[] = [];\n\tpublic isLeaf: boolean = true;\n\n\tpublic constructor (\n\t\tpublic readonly apiColumn: GetColumnType<ItemTypeType, ColumnId>,\n\t\tpublic readonly parent: ColumnInfo | null = null,\n\t) {\n\t\tconst columnId = (apiColumn as UnknownResponseColumn).id;\n\n\t\tthis.id = columnId as ColumnId;\n\n\t\tif (parent === null) {\n\t\t\tthis.level = 0;\n\t\t\tthis.path = columnId;\n\t\t\tthis.tailPath = '';\n\t\t} else {\n\t\t\tthis.level = parent.level + 1;\n\t\t\tthis.path = parent.path + COLUMN_SEPERATOR + columnId;\n\n\t\t\tthis.tailPath = parent.level === 0\n\t\t\t\t? columnId\n\t\t\t\t: parent.tailPath + COLUMN_SEPERATOR + columnId;\n\t\t}\n\t}\n\n\tpublic toRequestColumns (): ApiRequestColumnArray<ItemTypeType> {\n\t\tif (this.children.length === 0) {\n\t\t\treturn [\n\t\t\t\tthis.id,\n\t\t\t];\n\t\t}\n\n\t\treturn [\n\t\t\t{\n\t\t\t\t[this.id]: this.children.flatMap(\n\t\t\t\t\tc => c.toRequestColumns(),\n\t\t\t\t),\n\t\t\t},\n\t\t] as any;\n\t}\n\n\tpublic setChildren (\n\t\titemType: ItemTypeType,\n\t\tchildren: ColumnInfo<ApiItemType>[],\n\t): this {\n\t\tthis.itemType = itemType;\n\t\tthis.children = children;\n\t\tthis.isLeaf = false;\n\n\t\treturn this;\n\t}\n\n}\n","import { ApiEnumApiType, ApiItemType } from '@rentman/backend-types';\nimport { ApiRequestColumnArray, ApiRequestColumns, ColumnInfo, ColumnSetFactory, ColumnUtil, RequestColumnMergeResult, ResponseColumnItemTypeMap } from '../internal';\n\nexport type ColumnExpansionResult<ItemTypeType extends ApiItemType> = {\n\tmerged: ColumnSet<ItemTypeType>,\n\tdifference: ColumnSet<ItemTypeType> | null,\n};\n\nlet currentId = 0;\n\nexport class ColumnSet<ItemTypeType extends ApiItemType> {\n\n\tpublic readonly id: number = ++currentId;\n\n\tpublic link: ColumnInfo<ItemTypeType> | null = null;\n\n\t/**\n\t * The item's own columns\n\t */\n\tpublic readonly main: ColumnInfo<ItemTypeType>[] = [];\n\n\t/**\n\t * Columns which contain children, can be used to determine which derived values need to be refreshed when the root value changes.\n\t *\n\t * @example\n\t * columns: [\n\t * {\n\t * // 'exemplaar' is the root\n\t * exemplaar: [\n\t * 'displayname',\n\t * ],\n\t * },\n\t * ]\n\t */\n\tpublic readonly root: ColumnInfo<ItemTypeType>[] = [];\n\n\t/**\n\t * Columns which should be searchable in the frontend (mainly used for grids)\n\t */\n\tpublic readonly searchable: {\n\t\tmain: ColumnInfo<ItemTypeType>[],\n\t\tderived: ColumnInfo<ItemTypeType>[],\n\t} = {\n\t\tmain: [],\n\t\tderived: [],\n\t};\n\n\t/**\n\t * Custom columns fetched for this set\n\t */\n\tpublic readonly custom: {\n\t\tmain: ColumnInfo<ItemTypeType>[],\n\t\tderived: ColumnInfo<ItemTypeType>[],\n\t} = {\n\t\tmain: [],\n\t\tderived: [],\n\t};\n\n\t/**\n\t * Columns which reference another item\n\t */\n\tpublic readonly item: {\n\t\tmain: ColumnInfo<ItemTypeType>[],\n\t\tderived: ColumnInfo<ItemTypeType>[],\n\t} = {\n\t\tmain: [],\n\t\tderived: [],\n\t};\n\n\t/**\n\t * Warning: Contains both main and derived columns!\n\t */\n\tpublic readonly leaf: {\n\t\tmain: ColumnInfo<ItemTypeType>[],\n\t\tderived: ColumnInfo<ItemTypeType>[],\n\t} = {\n\t\tmain: [],\n\t\tderived: [],\n\t};\n\n\t/**\n\t * Warning: Contains both main and derived columns!\n\t */\n\tpublic readonly filtered: {\n\t\tmain: ColumnInfo<ItemTypeType>[],\n\t\tderived: ColumnInfo<ItemTypeType>[],\n\t} = {\n\t\tmain: [],\n\t\tderived: [],\n\t};\n\n\tpublic constructor (\n\t\tprivate columnSetFactory: ColumnSetFactory,\n\t\tpublic readonly itemType: ItemTypeType,\n\t\tpublic readonly request: ApiRequestColumnArray<ItemTypeType>,\n\t\tpublic readonly requestColumnsTrue: boolean,\n\t\tpublic readonly response: ResponseColumnItemTypeMap,\n\t) {\n\t}\n\n\tpublic groupColumnInfo (\n\t\tcolumnInfo: ColumnInfo,\n\t): void {\n\t\tconst responseColumn = columnInfo.apiColumn;\n\t\tconst isDerived = columnInfo.parent !== null;\n\t\tconst targetProp = isDerived ? 'derived' : 'main';\n\n\t\tif (!isDerived) {\n\t\t\tif (responseColumn.type === ApiEnumApiType.TYPE_LINK) {\n\t\t\t\tthis.link = columnInfo;\n\t\t\t}\n\n\t\t\tthis.main.push(\n\t\t\t\tcolumnInfo,\n\t\t\t);\n\t\t}\n\n\t\tif (columnInfo.isLeaf) {\n\t\t\tthis.leaf[targetProp].push(\n\t\t\t\tcolumnInfo,\n\t\t\t);\n\t\t} else if (!isDerived) {\n\t\t\t// Only main root columns should be stored\n\t\t\tthis.root.push(\n\t\t\t\tcolumnInfo,\n\t\t\t);\n\t\t}\n\n\t\tif (\n\t\t\tColumnUtil.isFilteredColumn(\n\t\t\t\tresponseColumn,\n\t\t\t)\n\t\t) {\n\t\t\tthis.filtered[targetProp].push(\n\t\t\t\tcolumnInfo,\n\t\t\t);\n\t\t}\n\n\t\tif (\n\t\t\tColumnUtil.isSearchableColumn(\n\t\t\t\tresponseColumn,\n\t\t\t)\n\t\t) {\n\t\t\tthis.searchable[targetProp].push(\n\t\t\t\tcolumnInfo,\n\t\t\t);\n\t\t}\n\n\t\tif (\n\t\t\tColumnUtil.isCustomColumn(\n\t\t\t\tresponseColumn,\n\t\t\t)\n\t\t) {\n\t\t\tthis.custom[targetProp].push(\n\t\t\t\tcolumnInfo,\n\t\t\t);\n\t\t}\n\n\t\tif (\n\t\t\tColumnUtil.isItemColumn(\n\t\t\t\tresponseColumn,\n\t\t\t)\n\t\t) {\n\t\t\tthis.item[targetProp].push(\n\t\t\t\tcolumnInfo,\n\t\t\t);\n\t\t}\n\t}\n\n\tpublic toJSON () {\n\t\tconst parseColumns = (\n\t\t\tcolumns: ColumnInfo[],\n\t\t) => columns.map(\n\t\t\tc => c.id,\n\t\t);\n\n\t\treturn parseColumns(\n\t\t\tthis.main,\n\t\t);\n\t}\n\n\t/**\n\t * @param columnsToCompare\n\t * @param columnsToCompareTrue - Set this to true if you know `columnsToCompare` contains all request columns.\n\t */\n\tpublic isSupersetOf (\n\t\tcolumnsToCompare: ApiRequestColumns<ItemTypeType>,\n\t\tcolumnsToCompareTrue?: boolean,\n\t): boolean {\n\t\tif (columnsToCompare === true) {\n\t\t\treturn this.requestColumnsTrue;\n\t\t}\n\n\t\t// If we've got all columns (true), we still need to check for derived columns below.\n\t\tif (\n\t\t\tcolumnsToCompareTrue === true\n\t\t\t&& !this.requestColumnsTrue\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\tfor (const column of columnsToCompare) {\n\t\t\tif (\n\t\t\t\t!ColumnUtil.containsColumn(\n\t\t\t\t\tcolumn,\n\t\t\t\t\tthis.request,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tpublic mergeRequestColumns (\n\t\trequestColumns: ApiRequestColumns<ItemTypeType>,\n\t): RequestColumnMergeResult {\n\t\treturn ColumnUtil.mergeRequestColumns(\n\t\t\tthis.request,\n\t\t\trequestColumns,\n\t\t);\n\t}\n\n\tpublic mergeResponseColumns (\n\t\tresponseColumns: ResponseColumnItemTypeMap,\n\t): ResponseColumnItemTypeMap {\n\t\treturn ColumnUtil.mergeResponseColumns(\n\t\t\tthis.response,\n\t\t\tresponseColumns,\n\t\t).merged;\n\t}\n\n\tpublic expand (\n\t\trequestColumns: ApiRequestColumnArray<ItemTypeType>,\n\t\trequestColumnsTrue: boolean,\n\t\tresponseColumns: ResponseColumnItemTypeMap,\n\t): ColumnExpansionResult<ItemTypeType> {\n\t\tconst mergedRequestColumns = ColumnUtil.mergeRequestColumns(\n\t\t\tthis.request,\n\t\t\trequestColumns,\n\t\t);\n\n\t\t// We know both this.requestColumns and requestColumns are arrays, so we can just check the length of `difference`.\n\t\tif (mergedRequestColumns.difference.length === 0) {\n\t\t\treturn {\n\t\t\t\tmerged: this,\n\t\t\t\tdifference: null,\n\t\t\t};\n\t\t}\n\n\t\tconst mergedResponseColumns = this.mergeResponseColumns(\n\t\t\tresponseColumns,\n\t\t);\n\n\t\treturn {\n\t\t\tmerged: this.columnSetFactory.constructFromRequest(\n\t\t\t\tthis.itemType,\n\t\t\t\tmergedRequestColumns.merged,\n\t\t\t\tthis.requestColumnsTrue || requestColumnsTrue,\n\t\t\t\tmergedResponseColumns,\n\t\t\t\tfalse,\n\t\t\t\tfalse,\n\t\t\t),\n\t\t\tdifference: this.columnSetFactory.constructFromRequest(\n\t\t\t\tthis.itemType,\n\t\t\t\tmergedRequestColumns.difference,\n\t\t\t\tfalse,\n\t\t\t\t// We need to be able to look up the parent of derived columns.\n\t\t\t\tmergedResponseColumns,\n\t\t\t\tfalse,\n\t\t\t\tfalse,\n\t\t\t),\n\t\t};\n\t}\n\n}\n","import { ApiItemType, ResponseColumnItem, UnknownResponseColumn } from '@rentman/backend-types';\nimport { AbstractCache, ApiRequestColumn, ApiRequestColumnArray, ApiRequestColumns, ColumnCache, ColumnSet, ColumnUtil, MutableApiRequestColumnArray, RequestColumnsTuple, ServerCache } from '../internal';\n\ntype RequestColumnSetMergeResult<ItemTypeType extends ApiItemType = any> = {\n\tmerged: RequestColumnsTuple<ItemTypeType>,\n\tdifference: RequestColumnsTuple<ItemTypeType>,\n};\n\ntype AggregateColumnsTuple<ItemTypeType extends ApiItemType = any> = {\n\treadonly object: ApiRequestColumnArray<ItemTypeType>,\n\treadonly string: string,\n};\n\n/**\n * @description This class caches the results of frequently performed operations on request columns:\n * - Merging;\n * - Testing whether all columns of one column set are present in another (which is mainly done by merging and checking\n * the difference);\n * - Creating hashes (IDs) for sets of request columns.\n */\nexport class RequestColumnsOperationsCache<ItemTypeType extends ApiItemType> {\n\n\t// It is critical that the columns are immutable, otherwise we can not rely on the cached results of the operations.\n\tprivate readonly requestColumnsTuple: RequestColumnsTuple<ItemTypeType>;\n\n\tprivate aggregateColumnsTuple?: AggregateColumnsTuple<ItemTypeType>;\n\n\tprivate expandedRequestColumnsTuple?: RequestColumnsTuple<ItemTypeType>;\n\n\tprivate columnsMergedWithTupleMap: {\n\t\t[requestColumnSetId: string]: RequestColumnSetMergeResult | undefined,\n\t} = {};\n\n\tprivate expandedColumnsMergedWithTupleMap: {\n\t\t[requestColumnSetId: string]: RequestColumnSetMergeResult | undefined,\n\t} = {};\n\n\t// TODO: these can be removed once we add request column set IDs to the column set class.\n\tprivate setContainsAllColumnsMap: {\n\t\t[columnSetId: number]: boolean | undefined,\n\t} = {};\n\n\tprivate setContainsAllExpandedColumnsMap: {\n\t\t[columnSetId: number]: boolean | undefined,\n\t} = {};\n\n\tpublic constructor (\n\t\tpublic readonly itemType: ItemTypeType,\n\t\tprivate columnCache: ColumnCache,\n\t\trequestColumns: ApiRequestColumns<ItemTypeType>,\n\t) {\n\t\tthis.requestColumnsTuple = this.createRequestColumnsTuple(\n\t\t\tColumnUtil.copyRequestColumns(\n\t\t\t\trequestColumns,\n\t\t\t),\n\t\t);\n\t}\n\n\tpublic getRequestColumnsTuple (\n\t\ttransactionCache: AbstractCache,\n\t): RequestColumnsTuple<ItemTypeType> {\n\t\tif (!(transactionCache instanceof ServerCache)) {\n\t\t\treturn this.requestColumnsTuple;\n\t\t}\n\n\t\tif (this.expandedRequestColumnsTuple !== undefined) {\n\t\t\treturn this.expandedRequestColumnsTuple;\n\t\t}\n\n\t\treturn this.expandedRequestColumnsTuple = this.createRequestColumnsTuple(\n\t\t\ttransactionCache.expandColumnsWithRequiredColumns(\n\t\t\t\tthis.itemType,\n\t\t\t\tthis.requestColumnsTuple.object,\n\t\t\t),\n\t\t);\n\t}\n\n\tpublic getAggregateColumns (): AggregateColumnsTuple {\n\t\tif (this.aggregateColumnsTuple !== undefined) {\n\t\t\treturn this.aggregateColumnsTuple;\n\t\t}\n\n\t\treturn this.aggregateColumnsTuple = this.createRequestColumnsTuple(\n\t\t\tthis.extractAggregateColumns(\n\t\t\t\tthis.requestColumnsTuple.object,\n\t\t\t\tthis.itemType,\n\t\t\t),\n\t\t) as AggregateColumnsTuple;\n\t}\n\n\tpublic hasAggregateColumns (): boolean {\n\t\treturn this.getAggregateColumns().object.length > 0;\n\t}\n\n\t/**\n\t *\n\t * @param requestColumnsTuple\n\t * @param transactionCache - When in the server cache, we'll include the columns required for delete\n\t * relations and the query matcher in the operation.\n\t */\n\tpublic getColumnsMergedWithTuple (\n\t\trequestColumnsTuple: RequestColumnsTuple<ItemTypeType>,\n\t\ttransactionCache: AbstractCache,\n\t): RequestColumnSetMergeResult<ItemTypeType> {\n\t\tconst requestColumnSetId = requestColumnsTuple.string;\n\n\t\tconst columnsMergedWithTupleMap = transactionCache instanceof ServerCache\n\t\t\t? this.expandedColumnsMergedWithTupleMap\n\t\t\t: this.columnsMergedWithTupleMap;\n\n\t\tif (columnsMergedWithTupleMap[requestColumnSetId] !== undefined) {\n\t\t\treturn columnsMergedWithTupleMap[requestColumnSetId];\n\t\t}\n\n\t\treturn columnsMergedWithTupleMap[requestColumnSetId] = this.mergeColumnsWithTuple(\n\t\t\trequestColumnsTuple,\n\t\t\ttransactionCache,\n\t\t);\n\t}\n\n\tpublic tupleContainsAllColumns (\n\t\trequestColumnsTuple: RequestColumnsTuple<ItemTypeType>,\n\t\ttransactionCache: AbstractCache,\n\t): boolean {\n\t\tconst difference = this.getColumnsMergedWithTuple(\n\t\t\trequestColumnsTuple,\n\t\t\ttransactionCache,\n\t\t).difference.object;\n\n\t\treturn difference !== true\n\t\t\t&& difference.length === 0;\n\t}\n\n\tpublic setContainsAllColumns (\n\t\tcolumnSet: ColumnSet<ItemTypeType>,\n\t\ttransactionCache: AbstractCache,\n\t): boolean {\n\t\tconst columnSetId = columnSet.id;\n\n\t\tconst setContainsAllColumnsMap = transactionCache instanceof ServerCache\n\t\t\t? this.setContainsAllExpandedColumnsMap\n\t\t\t: this.setContainsAllColumnsMap;\n\n\t\tif (setContainsAllColumnsMap[columnSetId] !== undefined) {\n\t\t\treturn setContainsAllColumnsMap[columnSetId];\n\t\t}\n\n\t\treturn setContainsAllColumnsMap[columnSetId] = columnSet.isSupersetOf(\n\t\t\tthis.getRequestColumnsTuple(\n\t\t\t\ttransactionCache,\n\t\t\t).object,\n\t\t);\n\t}\n\n\tprivate mergeColumnsWithTuple (\n\t\trequestColumnsTuple: RequestColumnsTuple<ItemTypeType>,\n\t\ttransactionCache: AbstractCache,\n\t): RequestColumnSetMergeResult<ItemTypeType> {\n\t\tconst innerRequestColumnsTuple = this.getRequestColumnsTuple(\n\t\t\ttransactionCache,\n\t\t);\n\n\t\tif (innerRequestColumnsTuple.string === requestColumnsTuple.string) {\n\t\t\treturn {\n\t\t\t\tmerged: innerRequestColumnsTuple,\n\t\t\t\tdifference: this.createRequestColumnsTuple(\n\t\t\t\t\t[],\n\t\t\t\t),\n\t\t\t};\n\t\t}\n\n\t\t// The difference we want here are the columns that are in this.requestColumns, but not in the passed request\n\t\t// columns tuple.\n\t\tconst mergedColumns = ColumnUtil.mergeRequestColumns(\n\t\t\trequestColumnsTuple.object,\n\t\t\tinnerRequestColumnsTuple.object,\n\t\t);\n\n\t\treturn {\n\t\t\tmerged: this.createRequestColumnsTuple(\n\t\t\t\tmergedColumns.merged as ApiRequestColumns<ItemTypeType>,\n\t\t\t),\n\t\t\tdifference: this.createRequestColumnsTuple(\n\t\t\t\tmergedColumns.difference as ApiRequestColumns<ItemTypeType>,\n\t\t\t),\n\t\t};\n\t}\n\n\tprivate extractAggregateColumns<ExtractItemTypeType extends ApiItemType> (\n\t\trequestColumns: ApiRequestColumns<ExtractItemTypeType>,\n\t\titemType: ExtractItemTypeType,\n\t): ApiRequestColumnArray<ExtractItemTypeType> {\n\t\tif (requestColumns === true) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst result: MutableApiRequestColumnArray<ExtractItemTypeType> = [];\n\n\t\tfor (const requestColumn of requestColumns) {\n\t\t\tconst parsedColumn = ColumnUtil.parseRequestColumn<ExtractItemTypeType>(\n\t\t\t\trequestColumn,\n\t\t\t);\n\n\t\t\tconst responseColumn = this.columnCache.getColumn(\n\t\t\t\titemType,\n\t\t\t\tparsedColumn.id,\n\t\t\t);\n\n\t\t\tif (responseColumn === undefined) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tColumnUtil.isAggregateColumn(\n\t\t\t\t\tresponseColumn as UnknownResponseColumn,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tresult.push(\n\t\t\t\t\tparsedColumn.id as ApiRequestColumn<ExtractItemTypeType>,\n\t\t\t\t);\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (parsedColumn.children.length === 0) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst childAggregateColumns = this.extractAggregateColumns(\n\t\t\t\tparsedColumn.children,\n\t\t\t\t(responseColumn as ResponseColumnItem).itemType,\n\t\t\t);\n\n\t\t\tif (childAggregateColumns.length > 0) {\n\t\t\t\tresult.push(\n\t\t\t\t\t{\n\t\t\t\t\t\t[parsedColumn.id]: childAggregateColumns,\n\t\t\t\t\t} as ApiRequestColumn<ExtractItemTypeType>,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate createRequestColumnsTuple (\n\t\trequestColumns: ApiRequestColumns<ItemTypeType>,\n\t): RequestColumnsTuple<ItemTypeType> {\n\t\treturn {\n\t\t\tobject: requestColumns,\n\t\t\tstring: ColumnUtil.createRequestColumnSetId(\n\t\t\t\trequestColumns,\n\t\t\t),\n\t\t};\n\t}\n\n}\n","import { ApiEnumApiType, ApiItemType, ResponseColumn, ResponseColumnCustom, ResponseColumnItem } from '@rentman/backend-types';\nimport { UnknownResponseColumn } from '@rentman/backend-types/dist/manual/api-response-column';\n\nimport { ApiRequestColumn, ApiRequestColumnArray, ApiRequestColumns, DerivedRequestColumnObject, ItemTypeColumnId, MutableApiRequestColumnArray, RequestColumnsTuple, ResponseColumnItemTypeMap, ResponseColumnMap } from '../internal';\n\nimport { getFirstProperty, isDefined } from './Util';\n\nexport type RequestColumnMergeResult<T extends ApiRequestColumns = ApiRequestColumns,\n\tU extends ApiRequestColumns = ApiRequestColumns> = {merged: T, difference: U,};\n\nexport enum API_COLUMN_LOCATION {\n\tNO = 0,\n\tIMPORT = 1,\n\tEXPORT = 2,\n\tGRID = 4,\n\tTEMPLATE = 8,\n\tEDIT = 16,\n\tAPI = 20,\n\tSOCKET = 32,\n\tALL = 63,\n\tGRID_SELECTABLE = 32768,\n\tLOCATION_LABELS = 524288,\n}\n\n/**\n * @description\n * A service which provides functions to help on {@link ResponseColumn ResponseColumns}\n *\n * @warning\n * The code in these functions can be *very hot* on large databases, therefore performance must be kept in mind.\n * This is also the reason why all column types are written out instead of using the enum\n */\nexport abstract class ColumnUtil {\n\n\tpublic static isStringColumn (\n\t\tcolumn: UnknownResponseColumn,\n\t): boolean {\n\t\tswitch (column.type) {\n\t\t\t// case ApiEnumApiType.TYPE_EMAIL:\n\t\t\tcase 'email':\n\t\t\t// case ApiEnumApiType.TYPE_PHONE:\n\t\t\tcase 'phone':\n\t\t\t// case ApiEnumApiType.TYPE_URL:\n\t\t\tcase 'url':\n\t\t\t// case ApiEnumApiType.TYPE_TEXT:\n\t\t\tcase 'text':\n\t\t\t// case ApiEnumApiType.TYPE_LONGTEXT:\n\t\t\tcase 'longtext':\n\t\t\t// case ApiEnumApiType.TYPE_TEXTREPLACE:\n\t\t\tcase 'textreplace':\n\t\t\t// case ApiEnumApiType.TYPE_TIME:\n\t\t\tcase 'time':\n\t\t\t\t// case 'html': // TODO: sort on filtered value\n\t\t\t\t// case 'enum':\n\t\t\t\treturn true;\n\t\t\tdefault:\n\t\t\t\treturn false;\n\t\t}\n\t}\n\n\tpublic static isFloatColumn (\n\t\tcolumn: UnknownResponseColumn,\n\t): boolean {\n\t\tswitch (column.type) {\n\t\t\t// floating point types\n\t\t\t// case ApiEnumApiType.TYPE_DOUBLE:\n\t\t\tcase 'double':\n\t\t\t// case ApiEnumApiType.TYPE_VOLUME:\n\t\t\tcase 'volume':\n\t\t\t// case ApiEnumApiType.TYPE_WEIGHT:\n\t\t\tcase 'weight':\n\t\t\t// case ApiEnumApiType.TYPE_DISTANCE:\n\t\t\tcase 'distance':\n\t\t\t// case ApiEnumApiType.TYPE_DIMENSION:\n\t\t\tcase 'dimension':\n\t\t\t// case ApiEnumApiType.TYPE_POWER:\n\t\t\tcase 'power':\n\t\t\t// case ApiEnumApiType.TYPE_CURRENT:\n\t\t\tcase 'current':\n\t\t\t// case ApiEnumApiType.TYPE_PRICE:\n\t\t\tcase 'price':\n\t\t\t// case ApiEnumApiType.TYPE_PERCENTAGE:\n\t\t\tcase 'percentage':\n\t\t\t\treturn true;\n\t\t\tdefault:\n\t\t\t\treturn false;\n\t\t}\n\t}\n\n\tpublic static isIntColumn (\n\t\tcolumn: UnknownResponseColumn,\n\t): boolean {\n\t\tswitch (column.type) {\n\t\t\t// case ApiEnumApiType.TYPE_INT:\n\t\t\tcase 'int':\n\t\t\t// case ApiEnumApiType.TYPE_NUMBER:\n\t\t\tcase 'number':\n\t\t\t// case ApiEnumApiType.TYPE_QUANTITY:\n\t\t\tcase 'quantity':\n\t\t\t\treturn true;\n\t\t\tdefault:\n\t\t\t\treturn false;\n\t\t}\n\t}\n\n\tpublic static isNumberColumn (\n\t\tcolumn: UnknownResponseColumn,\n\t): boolean {\n\t\treturn this.isFloatColumn(\n\t\t\tcolumn,\n\t\t) || this.isIntColumn(\n\t\t\tcolumn,\n\t\t);\n\t}\n\n\tpublic static isCustomColumn<ItemTypeType extends ApiItemType> (\n\t\tcolumn: ResponseColumn<ItemTypeType>,\n\t): column is ResponseColumnCustom<ItemTypeType> {\n\t\treturn column.fieldtype === 'customfield';\n\t}\n\n\tpublic static isAggregateColumn (\n\t\tcolumn: UnknownResponseColumn,\n\t): boolean {\n\t\treturn column.fieldtype === 'aggregate';\n\t}\n\n\tpublic static isItemColumn<ItemTypeType extends ApiItemType> (\n\t\tcolumn: UnknownResponseColumn | ResponseColumn<ItemTypeType>,\n\t\tincludeId: boolean = true,\n\t): column is ResponseColumnItem<ItemTypeType> {\n\t\tswitch (column.type) {\n\t\t\t// case ApiEnumApiType.TYPE_ID:\n\t\t\tcase 'id':\n\t\t\t\treturn includeId;\n\t\t\t// case ApiEnumApiType.TYPE_ITEM:\n\t\t\tcase 'item':\n\t\t\t// case ApiEnumApiType.TYPE_CHILD:\n\t\t\tcase 'child':\n\t\t\t// case ApiEnumApiType.TYPE_SIBLING:\n\t\t\tcase 'sibling':\n\t\t\t// case ApiEnumApiType.TYPE_LINK:\n\t\t\tcase 'link':\n\t\t\t\treturn true;\n\t\t\tdefault:\n\t\t\t\treturn false;\n\t\t}\n\t}\n\n\tpublic static isDateColumn (\n\t\tcolumn: UnknownResponseColumn,\n\t): boolean {\n\t\tswitch (column.type) {\n\t\t\tcase 'datetime':\n\t\t\tcase 'date':\n\t\t\t\treturn true;\n\t\t\tdefault:\n\t\t\t\treturn false;\n\t\t}\n\t}\n\n\tpublic static isRenderedColumn (\n\t\tcolumn: UnknownResponseColumn,\n\t): boolean {\n\t\tswitch (column.type) {\n\t\t\t// case ApiEnumApiType.TYPE_DATETIME:\n\t\t\tcase 'datetime':\n\t\t\t// case ApiEnumApiType.TYPE_DATE:\n\t\t\tcase 'date':\n\t\t\t// case ApiEnumApiType.TYPE_TIMESTAMP:\n\t\t\tcase 'timestamp':\n\t\t\t// case ApiEnumApiType.TYPE_TIMESTAMP_MS:\n\t\t\tcase 'timestamp_ms':\n\t\t\t// case ApiEnumApiType.TYPE_DURATION:\n\t\t\tcase 'duration':\n\t\t\t\treturn true;\n\t\t\tdefault:\n\t\t\t\treturn false;\n\t\t}\n\t}\n\n\tpublic static isFilteredColumn (\n\t\tcolumn: UnknownResponseColumn,\n\t): boolean {\n\t\t// ugly hack :-(\n\t\t// @ts-ignore\n\t\tif (column.id === 'staffel') {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (column.generator !== undefined) {\n\t\t\treturn true;\n\t\t}\n\n\t\tswitch (column.type) {\n\t\t\t// case ApiEnumApiType.TYPE_CURRENT:\n\t\t\tcase 'current':\n\t\t\t// case ApiEnumApiType.TYPE_PRICE:\n\t\t\tcase 'price':\n\t\t\t// case ApiEnumApiType.TYPE_BOOL:\n\t\t\tcase 'bool':\n\t\t\t// case ApiEnumApiType.TYPE_ENUM:\n\t\t\tcase 'enum':\n\t\t\t// case ApiEnumApiType.TYPE_COUNTRY:\n\t\t\tcase 'country':\n\t\t\t// case ApiEnumApiType.TYPE_VOLUME:\n\t\t\tcase 'volume':\n\t\t\t// case ApiEnumApiType.TYPE_WEIGHT:\n\t\t\tcase 'weight':\n\t\t\t// case ApiEnumApiType.TYPE_DISTANCE:\n\t\t\tcase 'distance':\n\t\t\t// case ApiEnumApiType.TYPE_DIMENSION:\n\t\t\tcase 'dimension':\n\t\t\t// case ApiEnumApiType.TYPE_QUANTITY:\n\t\t\tcase 'quantity':\n\t\t\t// case ApiEnumApiType.TYPE_EMAIL:\n\t\t\tcase 'email':\n\t\t\t// case ApiEnumApiType.TYPE_URL:\n\t\t\tcase 'url':\n\t\t\t// case ApiEnumApiType.TYPE_DATETIME:\n\t\t\tcase 'datetime':\n\t\t\t// case ApiEnumApiType.TYPE_DATE:\n\t\t\tcase 'date':\n\t\t\t// case ApiEnumApiType.TYPE_TIMESTAMP:\n\t\t\tcase 'timestamp':\n\t\t\t// case ApiEnumApiType.TYPE_TIMESTAMP_MS:\n\t\t\tcase 'timestamp_ms':\n\t\t\t// case ApiEnumApiType.TYPE_DURATION:\n\t\t\tcase 'duration':\n\t\t\t// case ApiEnumApiType.TYPE_HTML:\n\t\t\tcase 'html':\n\t\t\t// case ApiEnumApiType.TYPE_TEXTREPLACE:\n\t\t\tcase 'textreplace':\n\t\t\t// case ApiEnumApiType.TYPE_LONGTEXT:\n\t\t\tcase 'longtext':\n\t\t\t// case ApiEnumApiType.TYPE_PERCENTAGE:\n\t\t\tcase 'percentage':\n\t\t\t// case ApiEnumApiType.TYPE_TIME:\n\t\t\tcase 'time':\n\t\t\t\treturn true;\n\t\t\tdefault:\n\t\t\t\treturn false;\n\t\t}\n\t}\n\n\tpublic static hasLocationProperty (\n\t\tcolumn: UnknownResponseColumn,\n\t\tlocation: API_COLUMN_LOCATION,\n\t): boolean {\n\t\t// eslint-disable-next-line no-bitwise\n\t\treturn (location & column.location) !== 0;\n\t}\n\n\tpublic static isEditableColumn (\n\t\tcolumn: UnknownResponseColumn,\n\t): boolean {\n\t\tif (column.readOnly) {\n\t\t\treturn false;\n\t\t}\n\n\t\tswitch (column.type) {\n\t\t\t// case ApiEnumApiType.TYPE_DATE:\n\t\t\tcase 'date':\n\t\t\t// case ApiEnumApiType.TYPE_DATETIME:\n\t\t\tcase 'datetime':\n\t\t\t// case ApiEnumApiType.TYPE_TIMESTAMP:\n\t\t\tcase 'timestamp':\n\t\t\t// case ApiEnumApiType.TYPE_TIMESTAMP_MS:\n\t\t\tcase 'timestamp_ms':\n\t\t\t// case ApiEnumApiType.TYPE_DURATION:\n\t\t\tcase 'duration':\n\t\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tpublic static isSearchableColumn (\n\t\tcolumn: UnknownResponseColumn,\n\t): boolean {\n\t\tswitch (column.type) {\n\t\t\t// case ApiEnumApiType.TYPE_EMAIL:\n\t\t\tcase 'email':\n\t\t\t// case ApiEnumApiType.TYPE_PHONE:\n\t\t\tcase 'phone':\n\t\t\t// case ApiEnumApiType.TYPE_TEXT:\n\t\t\tcase 'text':\n\t\t\t// case ApiEnumApiType.TYPE_LONGTEXT:\n\t\t\tcase 'longtext':\n\t\t\t// case ApiEnumApiType.TYPE_HTML:\n\t\t\tcase 'html':\n\t\t\t\treturn true;\n\t\t\tdefault:\n\t\t\t\treturn false;\n\t\t}\n\t}\n\n\tpublic static getComparators (\n\t\tcolumn: UnknownResponseColumn & {\n\t\t\ttype: ApiEnumApiType.TYPE_DIMENSION | ApiEnumApiType.TYPE_WEIGHT | ApiEnumApiType.TYPE_PRICE,\n\t\t},\n\t): ['=', '>', '<'];\n\tpublic static getComparators (\n\t\tcolumn: UnknownResponseColumn & {\n\t\t\t// eslint-disable-next-line max-len\n\t\t\ttype: ApiEnumApiType.TYPE_DATE | ApiEnumApiType.TYPE_DATETIME | ApiEnumApiType.TYPE_DURATION | ApiEnumApiType.TYPE_TIMESTAMP | ApiEnumApiType.TYPE_TIMESTAMP_MS,\n\t\t},\n\t): ['>', '<'];\n\tpublic static getComparators (\n\t\tcolumn: UnknownResponseColumn & {\n\t\t\ttype: ApiEnumApiType.TYPE_TIME,\n\t\t},\n\t): ['>', '<', '=', '!='];\n\tpublic static getComparators (\n\t\tcolumn: UnknownResponseColumn,\n\t): ['=', '!='];\n\tpublic static getComparators (\n\t\tcolumn: UnknownResponseColumn,\n\t): string[] {\n\t\tswitch (column.type) {\n\t\t\t// case ApiEnumApiType.TYPE_DIMENSION:\n\t\t\tcase 'dimension':\n\t\t\t// case ApiEnumApiType.TYPE_WEIGHT:\n\t\t\tcase 'weight':\n\t\t\t// case ApiEnumApiType.TYPE_PRICE:\n\t\t\tcase 'price':\n\t\t\t\treturn [\n\t\t\t\t\t'=',\n\t\t\t\t\t'>',\n\t\t\t\t\t'<',\n\t\t\t\t];\n\t\t\t// case ApiEnumApiType.TYPE_DATE:\n\t\t\tcase 'date':\n\t\t\t// case ApiEnumApiType.TYPE_DATETIME:\n\t\t\tcase 'datetime':\n\t\t\t// case ApiEnumApiType.TYPE_TIMESTAMP:\n\t\t\tcase 'timestamp':\n\t\t\t// case ApiEnumApiType.TYPE_TIMESTAMP_MS:\n\t\t\tcase 'timestamp_ms':\n\t\t\t// case ApiEnumApiType.TYPE_DURATION:\n\t\t\tcase 'duration':\n\t\t\t\treturn [\n\t\t\t\t\t'>',\n\t\t\t\t\t'<',\n\t\t\t\t];\n\t\t\t// case ApiEnumApiType.TYPE_TIME:\n\t\t\tcase 'time':\n\t\t\t\treturn [\n\t\t\t\t\t'>',\n\t\t\t\t\t'<',\n\t\t\t\t\t'=',\n\t\t\t\t\t'!=',\n\t\t\t\t];\n\t\t\tdefault:\n\t\t\t\treturn [\n\t\t\t\t\t'=',\n\t\t\t\t\t'!=',\n\t\t\t\t];\n\t\t}\n\t}\n\n\tpublic static containsColumn<ItemTypeType extends ApiItemType = ApiItemType> (\n\t\trequestColumn: ApiRequestColumn<ItemTypeType>,\n\t\tdestination: ApiRequestColumnArray<ItemTypeType>,\n\t): boolean {\n\t\tconst column = this.parseRequestColumn<ItemTypeType>(\n\t\t\trequestColumn,\n\t\t);\n\t\tconst columnIndex = this.findRequestColumn(\n\t\t\tcolumn.id as any,\n\t\t\tdestination,\n\t\t);\n\n\t\tif (columnIndex === -1) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (column.children.length === 0) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (typeof destination[columnIndex] === 'string') {\n\t\t\treturn false;\n\t\t}\n\n\t\tfor (const childColumn of column.children) {\n\t\t\tif (\n\t\t\t\t!this.containsColumn(\n\t\t\t\t\tchildColumn,\n\t\t\t\t\tdestination[columnIndex][column.id as string],\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tpublic static containsDerivedColumns (\n\t\trequestColumns: ApiRequestColumnArray,\n\t): boolean {\n\t\tfor (const column of requestColumns) {\n\t\t\tif (\n\t\t\t\tthis.parseRequestColumn(\n\t\t\t\t\tcolumn,\n\t\t\t\t).children.length > 0\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tpublic static responseColumnsAvailable (\n\t\titemType: ApiItemType,\n\t\trequestColumns: ApiRequestColumnArray,\n\t\tresponseColumnMap: ResponseColumnItemTypeMap,\n\t): boolean {\n\t\tfor (const requestColumn of requestColumns) {\n\t\t\tconst parsedColumn = this.parseRequestColumn(\n\t\t\t\trequestColumn,\n\t\t\t);\n\t\t\tconst children = parsedColumn.children;\n\t\t\tconst responseColumns = responseColumnMap[itemType];\n\n\t\t\tif (responseColumns === undefined) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tconst responseColumn = responseColumns[parsedColumn.id];\n\n\t\t\tif (responseColumn === undefined) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tchildren.length > 0\n\t\t\t\t&& !this.responseColumnsAvailable(\n\t\t\t\t\tresponseColumn.itemType,\n\t\t\t\t\tchildren,\n\t\t\t\t\tresponseColumnMap,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t// [RM4-38080]- Error suppressed after TS 5.5 upgrade\n\t// eslint-disable-next-line @typescript-eslint/no-unused-vars\n\tpublic static copyRequestColumns<ItemTypeType extends ApiItemType> (columns: true): true;\n\tpublic static copyRequestColumns<ItemTypeType extends ApiItemType> (columns: ApiRequestColumns<ItemTypeType>):\n\t\tApiRequestColumns<ItemTypeType>;\n\tpublic static copyRequestColumns<ItemTypeType extends ApiItemType> (\n\t\tcolumns: ApiRequestColumns<ItemTypeType>,\n\t): ApiRequestColumns {\n\t\tif (columns === true) {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst result: MutableApiRequestColumnArray = [];\n\n\t\tfor (const column of columns) {\n\t\t\tresult.push(\n\t\t\t\tthis.copyRequestColumn(\n\t\t\t\t\tcolumn,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic static copyRequestColumn (\n\t\trequestColumn: ApiRequestColumn,\n\t): ApiRequestColumn {\n\t\tconst column = this.parseRequestColumn(\n\t\t\trequestColumn,\n\t\t);\n\n\t\tif (column.children.length === 0) {\n\t\t\treturn column.id;\n\t\t}\n\n\t\tconst children: ApiRequestColumn[] = [];\n\n\t\tfor (const childColumn of column.children) {\n\t\t\tchildren.push(\n\t\t\t\tthis.copyRequestColumn(\n\t\t\t\t\tchildColumn,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\treturn {\n\t\t\t[column.id]: children,\n\t\t};\n\t}\n\n\tpublic static mergeRequestColumns<T extends true, U extends ApiRequestColumns> (\n\t\tfirst: T,\n\t\tsecond: U,\n\t): RequestColumnMergeResult<true, []>;\n\n\tpublic static mergeRequestColumns<T extends ApiRequestColumnArray, U extends true> (\n\t\tfirst: T,\n\t\tsecond: U,\n\t): RequestColumnMergeResult<true, true>;\n\n\tpublic static mergeRequestColumns<T extends ApiRequestColumnArray, U extends ApiRequestColumnArray> (\n\t\tfirst: T,\n\t\tsecond: U,\n\t): RequestColumnMergeResult<[...T, ...U], ApiRequestColumnArray>;\n\n\tpublic static mergeRequestColumns<T extends ApiRequestColumns, U extends ApiRequestColumns> (\n\t\tfirst: T,\n\t\tsecond: U,\n\t): RequestColumnMergeResult<ApiRequestColumns, ApiRequestColumns>;\n\n\t/**\n\t * @description\n\t * Merges the passed columns and returns the merged set and the difference.\n\t *\n\t * @returns\n\t * - Merged: The merged set of columns\n\t * - Difference: Columns that are in second, but not in first\n\t */\n\tpublic static mergeRequestColumns<ItemTypeType extends ApiItemType> (\n\t\tfirst: ApiRequestColumns<ItemTypeType>,\n\t\tsecond: ApiRequestColumns<ItemTypeType>,\n\t): RequestColumnMergeResult {\n\t\t// === operator needed here\n\t\tif (first === true) {\n\t\t\treturn {\n\t\t\t\tmerged: true,\n\t\t\t\tdifference: [],\n\t\t\t};\n\t\t}\n\n\t\tif (second === true) {\n\t\t\treturn {\n\t\t\t\tmerged: true,\n\t\t\t\tdifference: true,\n\t\t\t};\n\t\t}\n\n\t\tconst merged = this.copyRequestColumns(\n\t\t\tfirst,\n\t\t) as MutableApiRequestColumnArray;\n\t\tconst difference: MutableApiRequestColumnArray = [];\n\n\t\tfor (const column of second) {\n\t\t\tconst addedColumn = this.mergeRequestColumn(\n\t\t\t\tcolumn,\n\t\t\t\tmerged,\n\t\t\t);\n\n\t\t\tif (addedColumn !== null) {\n\t\t\t\tdifference.push(\n\t\t\t\t\taddedColumn,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tmerged: merged,\n\t\t\tdifference: difference,\n\t\t};\n\t}\n\n\tpublic static mergeRequestColumn<ItemTypeType extends ApiItemType> (\n\t\trequestColumn: ApiRequestColumn<ItemTypeType>,\n\t\tdestination: MutableApiRequestColumnArray<ItemTypeType>,\n\t): ApiRequestColumn | null {\n\t\tconst column = this.parseRequestColumn(\n\t\t\trequestColumn,\n\t\t);\n\t\tconst columnIndex = this.findRequestColumn(\n\t\t\tcolumn.id as string,\n\t\t\tdestination,\n\t\t);\n\n\t\tif (columnIndex === -1) {\n\t\t\tdestination.push(\n\t\t\t\trequestColumn,\n\t\t\t);\n\n\t\t\treturn requestColumn;\n\t\t}\n\n\t\tif (column.children.length === 0) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (typeof destination[columnIndex] === 'string') {\n\t\t\tdestination[columnIndex] = {\n\t\t\t\t[column.id]: [],\n\t\t\t} as DerivedRequestColumnObject;\n\t\t}\n\n\t\tconst addedColumns: MutableApiRequestColumnArray = [];\n\n\t\tfor (const childColumn of column.children) {\n\t\t\tconst addedColumn = this.mergeRequestColumn(\n\t\t\t\tchildColumn,\n\t\t\t\tdestination[columnIndex][column.id as string],\n\t\t\t);\n\n\t\t\tif (addedColumn !== null) {\n\t\t\t\taddedColumns.push(\n\t\t\t\t\taddedColumn,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (addedColumns.length === 0) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn {\n\t\t\t[column.id]: addedColumns,\n\t\t};\n\t}\n\n\tpublic static createRequestColumnSetId (\n\t\trequestColumns: ApiRequestColumns,\n\t): RequestColumnsTuple['string'] {\n\t\tif (requestColumns === true) {\n\t\t\treturn 'true';\n\t\t}\n\n\t\tif (requestColumns.length === 0) {\n\t\t\treturn '{}';\n\t\t}\n\n\t\tlet result = this.createRequestColumnId(\n\t\t\trequestColumns[0],\n\t\t);\n\n\t\tfor (let i = 1; i < requestColumns.length; i++) {\n\t\t\tresult += ','\n\t\t\t\t+ this.createRequestColumnId(\n\t\t\t\t\trequestColumns[i],\n\t\t\t\t);\n\t\t}\n\n\t\treturn '{'\n\t\t\t+ result\n\t\t\t+ '}';\n\t}\n\n\tpublic static getRequestColumnId (\n\t\trequestColumn: ApiRequestColumn,\n\t): string {\n\t\tif (typeof requestColumn === 'string') {\n\t\t\treturn requestColumn;\n\t\t}\n\n\t\t// @ts-ignore\n\t\tfor (const columnId in requestColumn) {\n\t\t\treturn columnId;\n\t\t}\n\n\t\tthrow new Error(\n\t\t\t'Tried to get request column from empty derived object',\n\t\t);\n\t}\n\n\tpublic static parseRequestColumn<ItemTypeType extends ApiItemType> (\n\t\trequestColumn: ApiRequestColumn<ItemTypeType>,\n\t): {\n\t\tid: ItemTypeColumnId<ItemTypeType>,\n\t\tchildren: ApiRequestColumnArray,\n\t} {\n\t\tif (typeof requestColumn === 'string') {\n\t\t\treturn {\n\t\t\t\tid: requestColumn as ItemTypeColumnId<ItemTypeType>,\n\t\t\t\tchildren: [],\n\t\t\t};\n\t\t}\n\n\t\tconst columnId = getFirstProperty<ItemTypeColumnId<ItemTypeType>>(\n\t\t\trequestColumn,\n\t\t)!;\n\n\t\treturn {\n\t\t\tid: columnId,\n\t\t\tchildren: requestColumn[columnId as string],\n\t\t};\n\t}\n\n\t/**\n\t * @description\n\t * Merges two sets of {@link ResponseColumnItemTypeMap ResponseColumnItemTypeMaps}.\n\t *\n\t * @returns\n\t * - Merged: The merged set of columns\n\t * - Difference: Columns that are in second, but not in first\n\t */\n\tpublic static mergeResponseColumns (\n\t\tfirst: Partial<ResponseColumnItemTypeMap>,\n\t\tsecond: Partial<ResponseColumnItemTypeMap>,\n\t): {\n\t\tmerged: ResponseColumnItemTypeMap,\n\t\tdifference: ResponseColumnItemTypeMap,\n\t} {\n\t\tconst merged: ResponseColumnItemTypeMap = {} as ResponseColumnItemTypeMap;\n\t\tconst difference: ResponseColumnItemTypeMap = {} as ResponseColumnItemTypeMap;\n\n\t\tfor (const itemType in first) {\n\t\t\tif (second[itemType] === undefined) {\n\t\t\t\tmerged[itemType] = first[itemType];\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst mergeResult = this.mergeResponseColumnMap(\n\t\t\t\tfirst[itemType],\n\t\t\t\tsecond[itemType],\n\t\t\t);\n\n\t\t\tmerged[itemType] = mergeResult.merged;\n\t\t\tdifference[itemType] = mergeResult.difference;\n\t\t}\n\n\t\tfor (const itemType in second) {\n\t\t\tif (first[itemType] === undefined) {\n\t\t\t\tmerged[itemType] = second[itemType];\n\t\t\t\tdifference[itemType] = second[itemType];\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tmerged: merged,\n\t\t\tdifference: difference,\n\t\t};\n\t}\n\n\t/**\n\t * @description\n\t * Merges two sets of {@link ResponseColumnMap response columns}.\n\t *\n\t * @returns\n\t * - Merged: The merged set of columns\n\t * - Difference: Columns that are in second, but not in first\n\t */\n\tpublic static mergeResponseColumnMap<ItemTypeType extends ApiItemType> (\n\t\tfirst: ResponseColumnMap<ItemTypeType>,\n\t\tsecond: ResponseColumnMap<ItemTypeType>,\n\t): {\n\t\tmerged: ResponseColumnMap<ItemTypeType>,\n\t\tdifference: ResponseColumnMap<ItemTypeType>,\n\t} {\n\t\tconst merged: ResponseColumnMap<ItemTypeType> = {} as ResponseColumnMap<ItemTypeType>;\n\t\tconst difference: ResponseColumnMap<ItemTypeType> = {} as ResponseColumnMap<ItemTypeType>;\n\n\t\tfor (const columnId in first) {\n\t\t\tmerged[columnId] = first[columnId];\n\t\t}\n\n\t\tfor (const columnId in second) {\n\t\t\tif (isDefined(\n\t\t\t\tfirst[columnId],\n\t\t\t)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tmerged[columnId] = second[columnId];\n\t\t\tdifference[columnId] = second[columnId];\n\t\t}\n\n\t\treturn {\n\t\t\tmerged: merged,\n\t\t\tdifference: difference,\n\t\t};\n\t}\n\n\tpublic static findRequestColumn (\n\t\tcolumnId: string,\n\t\trequestColumns: ApiRequestColumnArray,\n\t): number {\n\t\tfor (let i = 0; i < requestColumns.length; i++) {\n\t\t\tconst column = requestColumns[i];\n\n\t\t\tif (\n\t\t\t\tthis.getRequestColumnId(\n\t\t\t\t\tcolumn,\n\t\t\t\t) === columnId\n\t\t\t) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\n\t\treturn -1;\n\t}\n\n\tpublic static requestColumnToPath (\n\t\trequestColumn: ApiRequestColumn,\n\t): string[] {\n\t\tif (typeof requestColumn === 'string') {\n\t\t\treturn [\n\t\t\t\trequestColumn,\n\t\t\t];\n\t\t}\n\n\t\tfor (const columnId in requestColumn as DerivedRequestColumnObject) {\n\t\t\treturn [\n\t\t\t\tcolumnId,\n\t\t\t\t...this.requestColumnToPath(\n\t\t\t\t\trequestColumn[columnId][0],\n\t\t\t\t),\n\t\t\t];\n\t\t}\n\n\t\treturn [];\n\t}\n\n\tprivate static createRequestColumnId (\n\t\trequestColumn: ApiRequestColumn,\n\t): string {\n\t\tconst parsedColumn = this.parseRequestColumn(\n\t\t\trequestColumn,\n\t\t);\n\n\t\tif (parsedColumn.children.length === 0) {\n\t\t\treturn parsedColumn.id as string;\n\t\t}\n\n\t\tconst childRequestColumnSetId = this.createRequestColumnSetId(\n\t\t\tparsedColumn.children,\n\t\t);\n\n\t\treturn (parsedColumn.id as string)\n\t\t\t+ '>'\n\t\t\t+ childRequestColumnSetId;\n\t}\n\n}\n","import { ApiEnumApiType, ApiItemType, ItemId } from '@rentman/backend-types';\nimport { ApiResponseProcessor, ColumnInfo, EntryParentNull, FieldMap, ItemEntry, ItemIdConversionMap, KeyService } from '../internal';\n\n/**\n * @description A 'ConversionMap' is used to update a set of item IDs to another. This happens when processing back-end\n * responses (create / template) or cloning items in the front-end. A conversion map is grouped by item type, as item\n * ID's are not unique across types.\n *\n * TODO: In the future, we should create a class and a 'ConversionMapFactory'.\n */\nexport class ConversionMapService {\n\n\tpublic createLocalConversionMap<ItemTypeType extends ApiItemType> (\n\t\trootItemType: ItemTypeType,\n\t\trootLocalItemId: ItemId,\n\t\tapiResponse: ApiResponseProcessor<ItemTypeType>,\n\t): ItemIdConversionMap {\n\t\tconst result: ItemIdConversionMap = {};\n\n\t\tfor (const linkItemType in apiResponse.links) {\n\t\t\tthis.expandLocalConversionMap(\n\t\t\t\tlinkItemType as ApiItemType,\n\t\t\t\tapiResponse.links[linkItemType],\n\t\t\t\tapiResponse,\n\t\t\t\tresult,\n\t\t\t\t// Only consider the root item type at the top level.\n\t\t\t\tlinkItemType === rootItemType\n\t\t\t\t\t? rootLocalItemId\n\t\t\t\t\t: undefined,\n\t\t\t);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic expandConversionMap (\n\t\titemType: ApiItemType,\n\t\titemId: ItemId,\n\t\tconversionMap: ItemIdConversionMap,\n\t\tnewItemId?: ItemId,\n\t): ItemId {\n\t\tconversionMap[itemType] ??= {};\n\t\tconst conversionMapEntry = conversionMap[itemType];\n\n\t\tif (conversionMapEntry[itemId] !== undefined) {\n\t\t\treturn conversionMapEntry[itemId];\n\t\t}\n\n\t\tnewItemId ??= KeyService.getLocalId();\n\n\t\treturn conversionMapEntry[itemId] = newItemId;\n\t}\n\n\tpublic batchExpandConversionMap (\n\t\titemEntries: ItemEntry<any>[],\n\t\tconversionMap: ItemIdConversionMap,\n\t): ItemIdConversionMap {\n\t\tfor (const itemEntry of itemEntries) {\n\t\t\tthis.expandConversionMap(\n\t\t\t\titemEntry.itemType,\n\t\t\t\titemEntry.itemId,\n\t\t\t\tconversionMap,\n\t\t\t);\n\t\t}\n\n\t\treturn conversionMap;\n\t}\n\n\tpublic getConversionValue (\n\t\titemType: ApiItemType,\n\t\titemId: ItemId,\n\t\tmap: ItemIdConversionMap,\n\t): ItemId | undefined {\n\t\tif (map[itemType] === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn map[itemType][itemId];\n\t}\n\n\t/**\n\t * @description\n\t * Updates the columns in `fields` using the `parent` and `conversionMap`.\n\t *\n\t * @param parent - When retrieving an item the 'link' column is not present in the template response, and is added at a later stage. The value for this column can be read from this parameter.\n\t */\n\tpublic updateItemValues<ItemTypeType extends ApiItemType> (\n\t\tsource: FieldMap<ItemTypeType>,\n\t\tdestination: FieldMap<ItemTypeType>,\n\t\titemColumns: ColumnInfo<ItemTypeType>[],\n\t\tconversionMap: ItemIdConversionMap,\n\t\tparent: EntryParentNull = null,\n\t): void {\n\t\tfor (const column of itemColumns) {\n\t\t\tconst columnId = column.id;\n\t\t\tconst apiColumn = column.apiColumn;\n\n\t\t\t// TODO: we can reconsider this once all columns are respected for local items [RM4-10378]\n\t\t\tlet newValue;\n\n\t\t\tif (apiColumn.type === ApiEnumApiType.TYPE_LINK && source[columnId] === undefined) {\n\t\t\t\tif (parent !== null) {\n\t\t\t\t\tnewValue = parent.itemId;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tnewValue = this.getConversionValue(\n\t\t\t\t\tapiColumn.itemType,\n\t\t\t\t\tsource[columnId],\n\t\t\t\t\tconversionMap,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (newValue !== undefined) {\n\t\t\t\tdestination[columnId] = newValue;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate expandLocalConversionMap (\n\t\titemType: ApiItemType,\n\t\tapiItemIds: ItemId[],\n\t\tapiResponse: ApiResponseProcessor,\n\t\tconversionMap: ItemIdConversionMap,\n\t\tfirstLocalItemId: number | null = KeyService.getLocalId(),\n\t): void {\n\t\tif (conversionMap[itemType] === undefined) {\n\t\t\tconversionMap[itemType] = {};\n\t\t}\n\n\t\tfor (let i: number = 0; i < apiItemIds.length; i++) {\n\t\t\tconst apiItemId = apiItemIds[i];\n\n\t\t\t// In test environments we want to keep control over the IDs so that we can do assertions on them.\n\t\t\tif (window.IS_IN_TEST === true) {\n\t\t\t\tconversionMap[itemType][apiItemId] = i === 0 && firstLocalItemId !== null\n\t\t\t\t\t? firstLocalItemId\n\t\t\t\t\t: apiItemId;\n\t\t\t} else {\n\t\t\t\tconversionMap[itemType][apiItemId] = i === 0 && firstLocalItemId !== null\n\t\t\t\t\t? firstLocalItemId\n\t\t\t\t\t: KeyService.getLocalId();\n\t\t\t}\n\n\t\t\tconst links = apiResponse.items[itemType][apiItemId].links;\n\n\t\t\tfor (const linkItemType in links) {\n\t\t\t\tthis.expandLocalConversionMap(\n\t\t\t\t\tlinkItemType as ApiItemType,\n\t\t\t\t\tlinks[linkItemType],\n\t\t\t\t\tapiResponse,\n\t\t\t\t\tconversionMap,\n\t\t\t\t\tnull,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n}\n","import { ApiItemType, ItemId } from '@rentman/backend-types';\nimport { ApiFormatter, ChildChangesDeltaItemCreateDelta, CreateCompilation, CreateRequestCompilationParent, CreateRequestEntry, getPath, ItemMap, KeyService, RequestColumnExpansionFactory, TransactionCache } from '../internal';\n\nexport class CreateRequest<ItemTypeType extends ApiItemType> {\n\n\tpublic requests: CreateRequestEntry<ItemTypeType>[] = [];\n\n\tpublic constructor (\n\t\tprivate requestColumnExpansionFactory: RequestColumnExpansionFactory,\n\t\tprivate compilation: CreateCompilation,\n\t\tprivate transaction: TransactionCache,\n\t\tprivate breakupByParent: boolean = false,\n\t\tprivate uniqueTransactionId?: string,\n\t) {\n\t}\n\n\tpublic finalizeRequest (\n\t\trequestResource: CreateRequestEntry<ItemTypeType>,\n\t) {\n\t\tconst columnExpansion = requestResource.columns;\n\n\t\t// We can assume that if an itemEntry fits a collection it already has a superset of the collection's columns\n\t\t// todo: verify if this is actually true\n\t\trequestResource.request.columns = columnExpansion.get();\n\n\t\tconst itemType: ItemTypeType = requestResource.request.itemType!;\n\n\t\trequestResource.request.columns[itemType] = this\n\t\t\t.transaction\n\t\t\t.getServerCache()\n\t\t\t.expandColumnsWithRequiredColumns(\n\t\t\t\titemType,\n\t\t\t\trequestResource.request.columns[itemType],\n\t\t\t);\n\n\t\treturn requestResource;\n\t}\n\n\tpublic setRequestParent (\n\t\tparentType: CreateRequestCompilationParent,\n\t\trequestEntry: CreateRequestEntry<ItemTypeType>,\n\t): boolean {\n\t\tconst request = requestEntry.request;\n\n\t\tif (parentType === 'Void') {\n\t\t\treturn false;\n\t\t}\n\n\t\trequest.parentType = parentType;\n\t\trequest.parentId = {};\n\n\t\treturn true;\n\t}\n\n\tpublic run () {\n\t\tconst compilation = this.compilation;\n\n\t\tif (this.breakupByParent) {\n\t\t\tfor (const parentType in compilation) {\n\t\t\t\tconst parentMap = compilation[parentType];\n\n\t\t\t\tfor (const parentId in parentMap) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tKeyService.isLocalId(\n\t\t\t\t\t\t\tparentId,\n\t\t\t\t\t\t)\n\t\t\t\t\t) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst requestResource = this.initializeRequest();\n\n\t\t\t\t\tthis.extendRequest(\n\t\t\t\t\t\tparentMap[parentId],\n\t\t\t\t\t\tthis.setRequestParent(\n\t\t\t\t\t\t\tparentType as CreateRequestCompilationParent,\n\t\t\t\t\t\t\trequestResource,\n\t\t\t\t\t\t) ? +parentId : null,\n\t\t\t\t\t\trequestResource,\n\t\t\t\t\t);\n\n\t\t\t\t\tthis.requests.push(\n\t\t\t\t\t\tthis.finalizeRequest(\n\t\t\t\t\t\t\trequestResource,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tfor (const parentType in compilation) {\n\t\t\t\tconst parentMap = compilation[parentType];\n\t\t\t\tconst requestResource = this.initializeRequest();\n\t\t\t\tconst hasParent = this.setRequestParent(\n\t\t\t\t\tparentType as CreateRequestCompilationParent,\n\t\t\t\t\trequestResource,\n\t\t\t\t);\n\n\t\t\t\tlet validRequest = false;\n\n\t\t\t\tfor (const parentId in parentMap) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tKeyService.isLocalId(\n\t\t\t\t\t\t\tparentId,\n\t\t\t\t\t\t)\n\t\t\t\t\t) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.extendRequest(\n\t\t\t\t\t\tparentMap[parentId],\n\t\t\t\t\t\thasParent ? +parentId : null,\n\t\t\t\t\t\trequestResource,\n\t\t\t\t\t);\n\n\t\t\t\t\tvalidRequest = true;\n\t\t\t\t}\n\n\t\t\t\tif (validRequest) {\n\t\t\t\t\tthis.requests.push(\n\t\t\t\t\t\tthis.finalizeRequest(\n\t\t\t\t\t\t\trequestResource,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this.requests;\n\t}\n\n\tpublic initializeRequest (): CreateRequestEntry<ItemTypeType> {\n\t\treturn {\n\t\t\trequest: {\n\t\t\t\trequestType: 'create',\n\t\t\t\titems: {},\n\t\t\t\tcolumns: {},\n\t\t\t\tuniqueTransactionId: this.uniqueTransactionId,\n\t\t\t},\n\t\t\tcolumns: this.requestColumnExpansionFactory.construct(),\n\t\t\titems: {},\n\t\t};\n\t}\n\n\tprivate extendRequest (\n\t\titemValues: ItemMap<ChildChangesDeltaItemCreateDelta>,\n\t\trequestParentId: ItemId | null,\n\t\tdestination: CreateRequestEntry<ItemTypeType>,\n\t) {\n\t\tconst request = destination.request;\n\t\tconst itemEntryMap = destination.items;\n\n\t\tfor (const itemType in itemValues) {\n\t\t\tif (request.itemType === undefined) {\n\t\t\t\trequest.itemType = itemType as ItemTypeType;\n\t\t\t}\n\n\t\t\tif (itemEntryMap[itemType] === undefined) {\n\t\t\t\titemEntryMap[itemType] = {};\n\t\t\t\trequest.items[itemType] = {};\n\t\t\t}\n\n\t\t\tfor (const itemId in itemValues[itemType]) {\n\t\t\t\tconst internalCreateDelta: ChildChangesDeltaItemCreateDelta = itemValues[itemType][itemId];\n\t\t\t\tconst itemEntry = internalCreateDelta.entry;\n\n\t\t\t\tconst childEntries = getPath(\n\t\t\t\t\tthis.compilation,\n\t\t\t\t\t[\n\t\t\t\t\t\titemType,\n\t\t\t\t\t\titemEntry.itemId,\n\t\t\t\t\t],\n\t\t\t\t);\n\t\t\t\tconst itemRequest: any = request.items[itemType][itemEntry.itemId] = {};\n\t\t\t\tconst parameters = getPath(\n\t\t\t\t\tthis.transaction.tabRequestParameters,\n\t\t\t\t\t[\n\t\t\t\t\t\titemType,\n\t\t\t\t\t\titemEntry.itemId,\n\t\t\t\t\t],\n\t\t\t\t);\n\n\t\t\t\tif (requestParentId !== null) {\n\t\t\t\t\t(request.parentId as {[itemId: string]: ItemId,})[itemEntry.itemId] = requestParentId;\n\t\t\t\t}\n\n\t\t\t\tdestination.columns.expandWithColumnSet(\n\t\t\t\t\titemEntry.columns,\n\t\t\t\t);\n\n\t\t\t\titemEntryMap[itemType][itemId] = itemEntry;\n\n\t\t\t\titemRequest.values = ApiFormatter.formatRequestLocal(\n\t\t\t\t\tinternalCreateDelta.fields,\n\t\t\t\t\titemEntry.columns.main,\n\t\t\t\t);\n\n\t\t\t\titemRequest.parameters = parameters;\n\n\t\t\t\tif (childEntries === undefined) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst links: {[itemType: string]: ItemId[],} = itemRequest.links = {};\n\n\t\t\t\tfor (const childType in childEntries) {\n\t\t\t\t\tlinks[childType] = [];\n\n\t\t\t\t\tfor (const childId in childEntries[childType]) {\n\t\t\t\t\t\tlinks[childType].push(\n\t\t\t\t\t\t\tparseInt(\n\t\t\t\t\t\t\t\tchildId,\n\t\t\t\t\t\t\t\t10,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tthis.extendRequest(\n\t\t\t\t\tchildEntries,\n\t\t\t\t\tnull,\n\t\t\t\t\tdestination,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n}\n","import { ApiItemType, ItemId } from '@rentman/backend-types';\nimport { GraphQueryParserFactory } from '../factories/GraphQueryParserFactory';\nimport { AbstractCache, ApiQuery, ItemEntry, ItemEntryMap, ItemNotFoundException } from '../internal';\n\nexport class ItemCache {\n\n\tprivate entries: ItemEntryMap = {};\n\n\tprivate entriesByEntryId: {\n\t\t[itemEntryId: number]: ItemEntry,\n\t} = {};\n\n\tpublic constructor (\n\t\tprivate graphQueryParserFactory: GraphQueryParserFactory,\n\t\tprivate transaction: AbstractCache,\n\t) {\n\t}\n\n\tpublic getByEntryId (\n\t\titemEntryId: ItemEntry['id'],\n\t): ItemEntry {\n\t\tif (this.entriesByEntryId[itemEntryId] === undefined) {\n\t\t\tthrow new ItemNotFoundException(\n\t\t\t\titemEntryId,\n\t\t\t);\n\t\t}\n\n\t\treturn this.entriesByEntryId[itemEntryId];\n\t}\n\n\tpublic containsByEntryId (\n\t\titemEntryId: ItemEntry['id'],\n\t): boolean {\n\t\treturn this.entriesByEntryId[itemEntryId] !== undefined;\n\t}\n\n\tpublic some (\n\t\tcallback: (itemEntry: ItemEntry) => boolean,\n\t): boolean {\n\t\tconst entries = this.entries;\n\n\t\tfor (const itemType in entries) {\n\t\t\tfor (const itemId in entries[itemType]) {\n\t\t\t\tif (callback(\n\t\t\t\t\tentries[itemType][itemId],\n\t\t\t\t)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tpublic getByItemType<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t): ItemEntry<ItemTypeType>[] {\n\t\tconst entries = this.entries[itemType];\n\t\tconst result: ItemEntry<ItemTypeType>[] = [];\n\n\t\tif (entries === undefined) {\n\t\t\treturn result;\n\t\t}\n\n\t\tfor (const itemId in entries) {\n\t\t\tresult.push(\n\t\t\t\tentries[itemId],\n\t\t\t);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic getByQuery<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tquery: ApiQuery<ItemTypeType>,\n\t): ItemEntry<ItemTypeType>[] {\n\t\tconst itemEntries = this.getByItemType(\n\t\t\titemType,\n\t\t);\n\n\t\tif (itemEntries.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst leafNode = {\n\t\t\tstring: '',\n\t\t};\n\n\t\tconst matchesAccumulatorTuple = this.transaction.itemHandler.matchItemsToQueryGraph(\n\t\t\tthis.graphQueryParserFactory\n\t\t\t\t.construct(\n\t\t\t\t\titemType,\n\t\t\t\t\tleafNode,\n\t\t\t\t)\n\t\t\t\t.run(\n\t\t\t\t\tquery,\n\t\t\t\t),\n\t\t\tleafNode,\n\t\t\titemEntries,\n\t\t);\n\n\t\treturn Array.from(\n\t\t\tmatchesAccumulatorTuple.true,\n\t\t);\n\t}\n\n\tpublic getLocalByQuery<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tquery: ApiQuery<ItemTypeType>,\n\t): ItemEntry<ItemTypeType>[] {\n\t\tconst itemEntries = this.entries[itemType];\n\n\t\tif (itemEntries === undefined) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst localItemEntries: ItemEntry<ItemTypeType>[] = [];\n\n\t\tfor (const itemId in itemEntries) {\n\t\t\tconst itemEntry = itemEntries[itemId];\n\n\t\t\tif (itemEntry.isLocal()) {\n\t\t\t\tlocalItemEntries.push(\n\t\t\t\t\titemEntry,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (localItemEntries.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst leafNode = {\n\t\t\tstring: '',\n\t\t};\n\n\t\tconst matchesAccumulatorTuple = this.transaction.itemHandler.matchItemsToQueryGraph(\n\t\t\tthis.graphQueryParserFactory\n\t\t\t\t.construct(\n\t\t\t\t\titemType,\n\t\t\t\t\tleafNode,\n\t\t\t\t)\n\t\t\t\t.run(\n\t\t\t\t\tquery,\n\t\t\t\t),\n\t\t\tleafNode,\n\t\t\tlocalItemEntries,\n\t\t);\n\n\t\treturn Array.from(\n\t\t\tmatchesAccumulatorTuple.true,\n\t\t);\n\t}\n\n\tpublic getByParent<ItemTypeType extends ApiItemType> (\n\t\tparentType: ApiItemType,\n\t\tparentId: ItemId,\n\t\titemType: ItemTypeType,\n\t): ItemEntry<ItemTypeType>[] {\n\t\tconst entries = this.entries[itemType];\n\t\tconst result: ItemEntry<ItemTypeType>[] = [];\n\n\t\tif (entries === undefined) {\n\t\t\treturn result;\n\t\t}\n\n\t\tfor (const itemId in entries) {\n\t\t\tconst itemEntry = entries[itemId];\n\t\t\tconst parent = this.transaction.getParent(\n\t\t\t\titemEntry,\n\t\t\t);\n\n\t\t\tif (parent === null) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\tif (parent.itemType === parentType && parent.itemId == parentId) {\n\t\t\t\tresult.push(\n\t\t\t\t\titemEntry,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic forEach (\n\t\tcallback: (\n\t\t\titemEntry: ItemEntry,\n\t\t) => void,\n\t): void {\n\t\tconst entries = this.entries;\n\n\t\tfor (const itemType in entries) {\n\t\t\tfor (const itemId in entries[itemType]) {\n\t\t\t\tcallback(\n\t\t\t\t\tentries[itemType][itemId],\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic *[Symbol.iterator] (): Iterator<ItemEntry> {\n\t\tconst entries = this.entries;\n\n\t\tfor (const itemType in entries) {\n\t\t\tfor (const itemId in entries[itemType]) {\n\t\t\t\tyield entries[itemType][itemId];\n\t\t\t}\n\t\t}\n\t}\n\n\t/*\tfilter (callback: (itemEntry: ItemEntry) => boolean): void {\n\t const entries = this.entries;\n\t const filteredEntries: ItemEntryMap = {};\n\n\t for (const itemType in entries) {\n\t filteredEntries[itemType] = {};\n\n\t for (const itemId in entries[itemType]) {\n\t const itemEntry = entries[itemType][itemId];\n\n\t if (callback(itemEntry))\n\t filteredEntries[itemType][itemId] = itemEntry;\n\t }\n\t }\n\n\t this.entries = filteredEntries;\n\t }\n\t */\n\tpublic toArray (): ItemEntry[] {\n\t\tconst entries = this.entries;\n\t\tconst result: ItemEntry[] = [];\n\n\t\tfor (const itemType in entries) {\n\t\t\tfor (const itemId in entries[itemType]) {\n\t\t\t\tresult.push(\n\t\t\t\t\tentries[itemType][itemId],\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic add<ItemTypeType extends ApiItemType> (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t): ItemEntry<ItemTypeType> {\n\t\tconst entries = this.entries;\n\t\tconst itemType = itemEntry.itemType;\n\n\t\tif (entries[itemType] === undefined) {\n\t\t\tentries[itemType] = {};\n\t\t}\n\n\t\tthis.entriesByEntryId[itemEntry.id] = itemEntry;\n\n\t\treturn entries[itemType][itemEntry.itemId] = itemEntry;\n\t}\n\n\tpublic get<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\titemId: string | ItemId,\n\t): ItemEntry<ItemTypeType> {\n\t\tif (\n\t\t\tthis.entries[itemType] === undefined\n\t\t\t|| this.entries[itemType][itemId] === undefined\n\t\t) {\n\t\t\tthrow new ItemNotFoundException(\n\t\t\t\titemType,\n\t\t\t\titemId as number,\n\t\t\t);\n\t\t}\n\n\t\treturn this.entries[itemType][itemId];\n\t}\n\n\t// should be fast\n\tpublic contains (\n\t\titemType: ApiItemType,\n\t\titemId: string | ItemId,\n\t): boolean {\n\t\treturn this.entries[itemType] !== undefined && this.entries[itemType][itemId] !== undefined;\n\t}\n\n\tpublic updateItemId<T extends ItemEntry<any>> (\n\t\titemEntry: T,\n\t\toldItemId: string | ItemId,\n\t): T {\n\t\tconst entryMap = this.entries[itemEntry.itemType];\n\n\t\tif (entryMap === undefined || entryMap[oldItemId] === undefined) {\n\t\t\treturn itemEntry;\n\t\t}\n\n\t\tdelete entryMap[oldItemId];\n\n\t\treturn entryMap[itemEntry.itemId] = itemEntry;\n\t}\n\n\tpublic clear (\n\t\titemEntry?: ItemEntry<any>,\n\t): boolean {\n\t\tif (itemEntry === undefined) {\n\t\t\tthis.entries = {};\n\t\t\tthis.entriesByEntryId = {};\n\n\t\t\treturn true;\n\t\t}\n\n\t\treturn this.clearByItemId(\n\t\t\titemEntry.itemType,\n\t\t\titemEntry.itemId,\n\t\t);\n\t}\n\n\tpublic clearByItemId (\n\t\titemType: ApiItemType,\n\t\titemId: ItemId,\n\t): boolean {\n\t\tconst entries = this.entries[itemType];\n\n\t\tif (entries === undefined) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (\n\t\t\t!Object.prototype.hasOwnProperty.call(\n\t\t\t\tentries,\n\t\t\t\titemId,\n\t\t\t)\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\tdelete this.entriesByEntryId[entries[itemId].id];\n\n\t\treturn delete entries[itemId];\n\t}\n\n}\n","import { ApiEnumApiType, ApiItemType, ItemId } from '@rentman/backend-types';\nimport moment from 'moment';\nimport { ALL_PERMISSIONS, ApiLinkTreeType, EntryParent, EntryParentNull, FieldMap, GetColumnIdsOfType, ItemEntry, LinkTreeServiceInterface } from '../internal';\n\ntype TextColumn<ItemTypeType extends ApiItemType> = GetColumnIdsOfType<ItemTypeType, ApiEnumApiType.TYPE_TEXT>;\n\nexport class ItemEntryService {\n\n\tpublic constructor (\n\t\tprivate userId: ItemId,\n\t\tprivate linkTreeService: LinkTreeServiceInterface,\n\t) {\n\t}\n\n\tpublic matchParent (\n\t\toldParent: EntryParentNull,\n\t\tnewParent: EntryParentNull,\n\t): boolean {\n\t\tif (oldParent === null && newParent === null) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (\n\t\t\t(oldParent === null && newParent !== null)\n\t\t\t|| (oldParent !== null && newParent === null)\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// todo[cache] they can't be null anymore here right ?\n\t\treturn (\n\t\t\toldParent!.itemType === newParent!.itemType\n\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t&& oldParent!.itemId == newParent!.itemId\n\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Gets the fields required to set the parent\n\t *\n\t * @remark\n\t * Opposite of {@link ItemEntryService.getParentByFields ItemEntryService.getParentByFields}\n\t */\n\tpublic getLinkFieldsByParent<ParentItemType extends ApiItemType, ItemTypeType extends ApiItemType> (\n\t\tparent: EntryParent<ParentItemType>,\n\t\titemType: ItemTypeType,\n\t): Partial<FieldMap<ItemTypeType>> {\n\t\tconst linkTree = this.linkTreeService.get();\n\n\t\tif (!(itemType in linkTree[parent.itemType])) {\n\t\t\tthrow new Error(\n\t\t\t\t`Non existing link between '${parent.itemType}'->'${itemType}'`,\n\t\t\t);\n\t\t}\n\n\t\tconst linkTreeEntry = linkTree[parent.itemType][itemType];\n\n\t\tconst result: Partial<FieldMap<ItemTypeType>> = {};\n\n\t\tif (linkTreeEntry.type === 'direct') {\n\t\t\tresult[linkTreeEntry.field] = parent.itemId;\n\t\t} else {\n\t\t\t// @ts-ignore we can assume that if link is 'itemtable' that the 'itemtype' and 'item' fields are there\n\t\t\tresult.itemtype = parent.itemType;\n\t\t\t// @ts-ignore we can assume that if link is 'itemtable' that the 'itemtype' and 'item' fields are there\n\t\t\tresult.item = parent.itemId;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * @description\n\t * Gets an {@link EntryParent EntryParent} object from the fields\n\t *\n\t * @remark\n\t * Opposite of {@link ItemEntryService.getLinkFieldsByParent ItemEntryService.getLinkFieldsByParent}\n\t */\n\tpublic getParentByFields<ItemTypeType extends ApiItemType> (\n\t\tparentType: ApiItemType,\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t\tfields: FieldMap<ItemTypeType>,\n\t): EntryParent {\n\t\tconst linkTree = this.linkTreeService.get();\n\t\tconst linkTreeEntry = linkTree[parentType][itemEntry.itemType];\n\n\t\tif (linkTreeEntry === undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t`Non existing link between '${parentType}'->'${itemEntry.itemType}'`,\n\t\t\t);\n\t\t}\n\n\t\tif (linkTreeEntry.type === ApiLinkTreeType.DIRECT) {\n\t\t\treturn {\n\t\t\t\titemType: parentType,\n\t\t\t\titemId: fields[linkTreeEntry.field],\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\t// todo[cache] we already know the parentType?\n\t\t\t// @ts-ignore we can assume that if link is 'itemtable' that the 'itemtype' and 'item' fields are there\n\t\t\titemType: fields.itemtype,\n\t\t\t// @ts-ignore we can assume that if link is 'itemtable' that the 'itemtype' and 'item' fields are there\n\t\t\titemId: fields.item,\n\t\t};\n\t}\n\n\tpublic getFullName (\n\t\tfirstName: string,\n\t\tinfix: string,\n\t\tlastName: string,\n\t): string {\n\t\treturn [\n\t\t\tfirstName,\n\t\t\tinfix,\n\t\t\tlastName,\n\t\t]\n\t\t\t.map(\n\t\t\t\tnamePart =>\n\t\t\t\t\t(\n\t\t\t\t\t\tnamePart ?? ''\n\t\t\t\t\t)\n\t\t\t\t\t\t.trim(),\n\t\t\t)\n\t\t\t.filter(\n\t\t\t\tnamePart =>\n\t\t\t\t\tnamePart !== '',\n\t\t\t)\n\t\t\t.join(\n\t\t\t\t' ',\n\t\t\t);\n\t}\n\n\tpublic getTitleField<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t): TextColumn<ItemTypeType> {\n\t\tswitch (itemType) {\n\t\t\tcase 'Exemplaar':\n\t\t\t\treturn 'merk' satisfies TextColumn<'Exemplaar'> as TextColumn<ItemTypeType>;\n\t\t\tcase 'Factuur':\n\t\t\t\treturn 'nummer' satisfies TextColumn<'Factuur'> as TextColumn<ItemTypeType>;\n\t\t\tcase 'Files':\n\t\t\t\treturn 'friendlyname' satisfies TextColumn<'Files'> as TextColumn<ItemTypeType>;\n\t\t\tcase 'Functie':\n\t\t\tcase 'Standaardfunctie':\n\t\t\t\treturn 'naamintern' satisfies TextColumn<'Standaardfunctie'> as TextColumn<ItemTypeType>;\n\t\t\tcase 'Voorraadmutatie':\n\t\t\t\treturn 'omschrijving' satisfies TextColumn<'Voorraadmutatie'> as TextColumn<ItemTypeType>;\n\t\t\tcase 'Barcode':\n\t\t\t\treturn 'code' satisfies TextColumn<'Barcode'> as TextColumn<ItemTypeType>;\n\t\t\tcase 'Afspraak':\n\t\t\tcase 'Betaalmiddel':\n\t\t\tcase 'Betalingsconditie':\n\t\t\tcase 'Briefpapier':\n\t\t\tcase 'Condition':\n\t\t\tcase 'CustomfieldGroup':\n\t\t\tcase 'Factuurmoment':\n\t\t\tcase 'Functiegroep':\n\t\t\tcase 'Grootboek':\n\t\t\tcase 'Inhuur':\n\t\t\tcase 'Inhuurgroep':\n\t\t\tcase 'Inhuurmateriaal':\n\t\t\tcase 'Materiaal':\n\t\t\tcase 'MateriaalCat':\n\t\t\tcase 'Medewerkertarief':\n\t\t\tcase 'Notitie':\n\t\t\tcase 'Planningmateriaal':\n\t\t\tcase 'Project':\n\t\t\tcase 'Rol':\n\t\t\tcase 'Staffelgroep':\n\t\t\tcase 'Subproject':\n\t\t\tcase 'Taak':\n\t\t\tcase 'Tag':\n\t\t\tcase 'TaxClass':\n\t\t\tcase 'TaxSchema':\n\t\t\tcase 'Template':\n\t\t\tcase 'Tijd':\n\t\t\tcase 'Titel':\n\t\t\tcase 'Type':\n\t\t\tcase 'Voertuig':\n\t\t\t\treturn 'naam' satisfies TextColumn<'Afspraak'> as TextColumn<ItemTypeType>;\n\t\t\t// case 'Contact':\n\t\t\t// case 'Medewerker':\n\t\t\t// case 'Person':\n\t\t\tdefault:\n\t\t\t\t// only use displayname for items that dont't have a simple, writable name field\n\t\t\t\t// this function is also used for templated items\n\t\t\t\treturn 'displayname' as TextColumn<ItemTypeType>;\n\t\t}\n\t}\n\n\t// TODO: we can remove these once all columns are respected for local items [RM4-10378]\n\tpublic getLocalDefaultValues<ItemTypeType extends ApiItemType> (): FieldMap<ItemTypeType, ['permissions', 'creator', 'created']> {\n\t\treturn {\n\t\t\tpermissions: ALL_PERMISSIONS,\n\t\t\tcreator: this.userId,\n\t\t\tcreated: moment(),\n\t\t} as FieldMap<ItemTypeType, ['permissions', 'creator', 'created']>;\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\n\nexport abstract class KeyService {\n\n\tprivate static readonly NEW_PREFIX = '-1' as const;\n\n\tprivate static idCounter: number = 0;\n\n\tpublic static getCssKey (\n\t\t...args: (string | number)[]\n\t): string {\n\t\treturn args.join(\n\t\t\t'_',\n\t\t);\n\t}\n\n\tpublic static getLocalId (): ItemId {\n\t\treturn +(this.NEW_PREFIX + this.incrementIdCounter());\n\t}\n\n\t// note: the changes compiler uses this\n\t// might be called with undefined (itemHandler.createRequest)\n\tpublic static isLocalId (\n\t\titemId: any,\n\t): boolean {\n\t\treturn itemId !== undefined\n\t\t\t&& this.isNewId(\n\t\t\t\titemId,\n\t\t\t);\n\t}\n\n\tpublic static isNewId (\n\t\titemId: any,\n\t): boolean {\n\t\treturn ('' + itemId).startsWith(\n\t\t\tthis.NEW_PREFIX,\n\t\t);\n\t}\n\n\tprivate static incrementIdCounter (): string {\n\t\treturn (++this.idCounter).toString();\n\t}\n\n}\n","import { ErrorHandlerInterface, ItemIdConversionMap, TransactionCache } from '../../../internal';\n\nexport type TransactionCacheCallbackCondition = 'always' | 'onClose' | 'skipOnClose';\n\nexport type TransactionCacheCallbackType = {\n\tonBeforeSave: (transaction: TransactionCache) => any,\n\tonSaveSuccess: (\n\t\ttransaction: TransactionCache,\n\t\tconversionMap: ItemIdConversionMap,\n\t) => any,\n\tonRootItemDelete: () => any,\n};\n\ntype CallbackMap<T extends keyof TransactionCacheCallbackType> = {\n\t[key: string]: {\n\t\tcallback: TransactionCacheCallbackType[T],\n\t\tcondition: TransactionCacheCallbackCondition,\n\t},\n};\n\nconst DEFAULT_PRIORITY = 100;\n\nexport class TransactionEventHandler {\n\n\tprivate callbacks: {\n\t\t[T in keyof TransactionCacheCallbackType]: [\n\t\t\tnumber,\n\t\t\tCallbackMap<T>\n\t\t][]\n\t} = {\n\t\tonBeforeSave: [],\n\t\tonSaveSuccess: [],\n\t\tonRootItemDelete: [],\n\t};\n\n\tpublic constructor (\n\t\tprivate errorHandler: ErrorHandlerInterface,\n\t) {\n\t}\n\n\tpublic clear (): void {\n\t\tthis.callbacks = {\n\t\t\tonBeforeSave: [],\n\t\t\tonSaveSuccess: [],\n\t\t\tonRootItemDelete: [],\n\t\t};\n\t}\n\n\tpublic registerCallback<T extends keyof TransactionCacheCallbackType> (\n\t\ttype: T,\n\t\tkey: string,\n\t\tcallback: TransactionCacheCallbackType[T],\n\t\tcondition: TransactionCacheCallbackCondition = 'always',\n\t\tpriority: number = DEFAULT_PRIORITY,\n\t): () => void {\n\t\tthis.getPriorityLevel(\n\t\t\ttype,\n\t\t\tpriority,\n\t\t)[key] = {\n\t\t\tcallback,\n\t\t\tcondition,\n\t\t};\n\n\t\treturn () => {\n\t\t\tdelete this.getPriorityLevel(\n\t\t\t\ttype,\n\t\t\t\tpriority,\n\t\t\t)[key];\n\t\t};\n\t}\n\n\tpublic executeCallbacks<T extends keyof TransactionCacheCallbackType> (\n\t\ttype: T,\n\t\texecute: (callback: TransactionCacheCallbackType[T]) => any,\n\t\tcloseTab: boolean,\n\t): Promise<any> {\n\t\tconst priorityLevels = this.callbacks[type];\n\t\tconst condition: TransactionCacheCallbackCondition = closeTab ? 'onClose' : 'skipOnClose';\n\n\t\tlet chain = Promise.resolve();\n\n\t\tfor (const priorityLevel of priorityLevels) {\n\t\t\tchain = chain.then(\n\t\t\t\tthis.executeCallbacksPriorityLevel(\n\t\t\t\t\tpriorityLevel[1],\n\t\t\t\t\tcondition,\n\t\t\t\t\texecute,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\treturn chain;\n\t}\n\n\tprivate getPriorityLevel<T extends keyof TransactionCacheCallbackType> (\n\t\ttype: T,\n\t\tdestinationPriority: number,\n\t): CallbackMap<T> {\n\t\tconst priorityLevels = this.callbacks[type];\n\t\tlet newPriorityLevel;\n\n\t\tfor (let i = 0; i < priorityLevels.length; i++) {\n\t\t\tconst priorityLevel = priorityLevels[i];\n\n\t\t\tif (priorityLevel[0] < destinationPriority) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (priorityLevel[0] === destinationPriority) {\n\t\t\t\treturn priorityLevel[1];\n\t\t\t}\n\n\t\t\tnewPriorityLevel = {};\n\n\t\t\tpriorityLevels.splice(\n\t\t\t\ti,\n\t\t\t\t0,\n\t\t\t\t[\n\t\t\t\t\tdestinationPriority,\n\t\t\t\t\tnewPriorityLevel,\n\t\t\t\t],\n\t\t\t);\n\n\t\t\treturn newPriorityLevel;\n\t\t}\n\n\t\tnewPriorityLevel = {};\n\n\t\tpriorityLevels.push(\n\t\t\t[\n\t\t\t\tdestinationPriority,\n\t\t\t\tnewPriorityLevel,\n\t\t\t],\n\t\t);\n\n\t\treturn newPriorityLevel;\n\t}\n\n\tprivate executeCallbacksPriorityLevel<T extends keyof TransactionCacheCallbackType> (\n\t\tcallbacks: CallbackMap<T>,\n\t\tcondition: TransactionCacheCallbackCondition,\n\t\texecute: (callback: TransactionCacheCallbackType[T]) => any,\n\t): () => Promise<any> {\n\t\treturn () => {\n\t\t\tconst promises: any[] = [];\n\n\t\t\tfor (const key in callbacks) {\n\t\t\t\tconst callbackEntry = callbacks[key];\n\n\t\t\t\tif (\n\t\t\t\t\tcallbackEntry.condition !== condition\n\t\t\t\t\t&& callbackEntry.condition !== 'always'\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tpromises.push(\n\t\t\t\t\t\texecute(\n\t\t\t\t\t\t\tcallbackEntry.callback,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t} catch (e) {\n\t\t\t\t\tthis.errorHandler.logError(\n\t\t\t\t\t\te,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// See comment in RM4-28127 for explanation why we use Promise.all here\n\t\t\treturn Promise.all(\n\t\t\t\tpromises,\n\t\t\t);\n\t\t};\n\t}\n\n}\n","import { Signal, signal, untracked, WritableSignal } from '@angular/core';\nimport { ItemId } from '@rentman/backend-types';\nimport { ApiRequestService, FieldMap, ItemEntry, ItemMap, KeyService } from '../internal';\n\ntype LockTokenError = {\n\tisForeign: true,\n\tmessage: string,\n};\n\nexport type LockToken = FieldMap<'Locktoken', ['token', 'id']> | LockTokenError;\n\nexport class LockService {\n\n\tprivate lockItems: WritableSignal<ItemMap<LockToken>> = signal(\n\t\t{},\n\t);\n\n\tprivate promises: ItemMap<Promise<LockToken>> = {};\n\n\tpublic constructor (\n\t\tprivate apiRequestService: ApiRequestService,\n\t) {\n\n\t}\n\n\tpublic getLocksSignal (): Signal<ItemMap<LockToken>> {\n\t\treturn this\n\t\t\t.lockItems\n\t\t\t.asReadonly();\n\t}\n\n\tpublic getLocks (): ItemMap<LockToken> {\n\t\treturn untracked(\n\t\t\t() => this.lockItems(),\n\t\t);\n\t}\n\n\tpublic hasLock (\n\t\tlockTokenId: ItemId,\n\t): boolean {\n\t\tconst lockItems = this.lockItems();\n\n\t\tfor (const itemType in lockItems) {\n\t\t\tfor (const itemId in lockItems[itemType]) {\n\t\t\t\tconst lockItem = lockItems[itemType][itemId];\n\n\t\t\t\tif (\n\t\t\t\t\t!this.isRemoteLock(\n\t\t\t\t\t\tlockItem,\n\t\t\t\t\t)\n\t\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\t\t&& lockItem.id == lockTokenId\n\t\t\t\t) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t// should be fast (watched)\n\tpublic isLocked (\n\t\titemEntry: ItemEntry,\n\t): boolean {\n\t\tconst lockItem = this.getValue(\n\t\t\titemEntry,\n\t\t\tthis.lockItems(),\n\t\t);\n\n\t\tif (lockItem === undefined) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn this.isRemoteLock(\n\t\t\tlockItem,\n\t\t);\n\t}\n\n\tpublic getMessage (\n\t\titemEntry: ItemEntry,\n\t): undefined | string {\n\t\tconst lockItem = this.getValue(\n\t\t\titemEntry,\n\t\t\tthis.lockItems(),\n\t\t);\n\n\t\tif (lockItem === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (\n\t\t\t!this.isRemoteLock(\n\t\t\t\tlockItem,\n\t\t\t)\n\t\t) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn lockItem.message;\n\t}\n\n\tpublic fetchLock (\n\t\titemEntry: ItemEntry,\n\t): Promise<LockToken> {\n\t\tconst lock = this.getValue(\n\t\t\titemEntry,\n\t\t\tthis.lockItems(),\n\t\t);\n\n\t\tif (lock !== undefined) {\n\t\t\treturn Promise.resolve(\n\t\t\t\tlock,\n\t\t\t);\n\t\t}\n\n\t\tconst promise = this.getValue(\n\t\t\titemEntry,\n\t\t\tthis.promises,\n\t\t);\n\n\t\tif (promise !== undefined) {\n\t\t\treturn promise;\n\t\t}\n\n\t\t// The code above should be synchronous. This function can be called multiple times in quick succession.\n\t\treturn this.requestLock(\n\t\t\titemEntry,\n\t\t);\n\t}\n\n\tpublic deleteLock (\n\t\titemEntry: ItemEntry,\n\t): Promise<void> {\n\t\t// I defined this as an inline function for the following reasons:\n\t\t// - To enforce the passed lock token is associated with the item entry above;\n\t\t// - To avoid wrapping the cached lock in a promise.\n\t\tconst doDeleteLock: (\n\t\t\tcachedLock: LockToken,\n\t\t) => Promise<void> = cachedLock => {\n\t\t\tif (\n\t\t\t\tthis.isRemoteLock(\n\t\t\t\t\tcachedLock,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tthis.clearLock(\n\t\t\t\t\titemEntry,\n\t\t\t\t);\n\n\t\t\t\treturn Promise.resolve();\n\t\t\t}\n\n\t\t\treturn this.apiRequestService\n\t\t\t\t.delete(\n\t\t\t\t\t'Locktoken',\n\t\t\t\t\t[\n\t\t\t\t\t\tcachedLock.id,\n\t\t\t\t\t],\n\t\t\t\t)\n\t\t\t\t.then(\n\t\t\t\t\t() => {\n\t\t\t\t\t\tthis.clearLock(\n\t\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\t);\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t};\n\n\t\tconst lock = this.getValue(\n\t\t\titemEntry,\n\t\t\tthis.lockItems(),\n\t\t);\n\n\t\tif (lock !== undefined) {\n\t\t\treturn doDeleteLock(\n\t\t\t\tlock,\n\t\t\t);\n\t\t}\n\n\t\tconst promise = this.getValue(\n\t\t\titemEntry,\n\t\t\tthis.promises,\n\t\t);\n\n\t\tif (promise === undefined) {\n\t\t\treturn Promise.resolve();\n\t\t}\n\n\t\treturn promise.then(\n\t\t\tresolvedLock => doDeleteLock(\n\t\t\t\tresolvedLock,\n\t\t\t),\n\t\t);\n\t}\n\n\tpublic isRemoteLock (\n\t\ttoken: LockToken,\n\t): token is LockTokenError {\n\t\treturn 'isForeign' in token;\n\t}\n\n\tprivate clearLock (\n\t\titemEntry: ItemEntry,\n\t): boolean {\n\t\tconst lockItems = this.lockItems();\n\n\t\tif (lockItems[itemEntry.itemType]?.[itemEntry.itemId] === undefined) {\n\t\t\treturn false;\n\t\t}\n\n\t\tdelete lockItems[itemEntry.itemType][itemEntry.itemId];\n\n\t\tthis.lockItems.set(\n\t\t\t{\n\t\t\t\t...lockItems,\n\t\t\t},\n\t\t);\n\n\t\treturn true;\n\t}\n\n\tprivate requestLock (\n\t\titemEntry: ItemEntry,\n\t): Promise<LockToken> {\n\t\tconst {\n\t\t\titemType,\n\t\t\titemId,\n\t\t} = itemEntry;\n\n\t\tconst promise = this.apiRequestService\n\t\t\t.create(\n\t\t\t\t'Locktoken',\n\t\t\t\tKeyService.getLocalId(),\n\t\t\t\t{\n\t\t\t\t\titemtype: itemType,\n\t\t\t\t\titem: itemId,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tLocktoken: [\n\t\t\t\t\t\t'id',\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t)\n\t\t\t.then(\n\t\t\t\tresponse => {\n\t\t\t\t\tdelete this.promises[itemType][itemId];\n\n\t\t\t\t\tconst fields = response.fetchObject(\n\t\t\t\t\t\t'Locktoken',\n\t\t\t\t\t\tresponse.links.Locktoken[0],\n\t\t\t\t\t)!;\n\n\t\t\t\t\treturn this.setToken(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\tfields,\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t\terror => {\n\t\t\t\t\tdelete this.promises[itemType][itemId];\n\n\t\t\t\t\tif (error.code === 301) {\n\t\t\t\t\t\treturn this.setToken(\n\t\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tisForeign: true,\n\t\t\t\t\t\t\t\tmessage: error.message,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tthrow error;\n\t\t\t\t},\n\t\t\t);\n\n\t\treturn this.setPromise(\n\t\t\titemEntry,\n\t\t\tpromise,\n\t\t);\n\t}\n\n\tprivate getValue<T> (\n\t\titemEntry: ItemEntry,\n\t\tmap: ItemMap<T>,\n\t): undefined | T {\n\t\tconst itemType = itemEntry.itemType;\n\n\t\tif (map[itemType] === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn map[itemType][itemEntry.itemId];\n\t}\n\n\tprivate setPromise<T extends Promise<LockToken>> (\n\t\titemEntry: ItemEntry,\n\t\tpromise: T,\n\t): T {\n\t\tthis.promises[itemEntry.itemType] ??= {};\n\t\tthis.promises[itemEntry.itemType][itemEntry.itemId] = promise;\n\n\t\treturn promise;\n\t}\n\n\tprivate setToken<T extends LockToken> (\n\t\titemEntry: ItemEntry,\n\t\tvalue: T,\n\t): T {\n\t\tconst lockItems = this.lockItems();\n\n\t\tlockItems[itemEntry.itemType] ??= {};\n\t\tlockItems[itemEntry.itemType][itemEntry.itemId] = value;\n\n\t\tthis.lockItems.set(\n\t\t\t{\n\t\t\t\t...lockItems,\n\t\t\t},\n\t\t);\n\n\t\treturn value;\n\t}\n\n}\n","import { ApiItemType, ItemId } from '@rentman/backend-types';\nimport { AbstractCache, ApiRequestItemMap, FieldMap, ItemEntry, ItemTypeMap, LinkTreeServiceInterface, TransactionCache, TransactionDeletedItem } from '../internal';\n\nimport { hasProperties } from './Util';\n\nconst EMPTY_ENTRY = {};\n\nexport type ModuleChangesCompilationResult = {\n\titemType: ApiItemType,\n\titemId: ItemId,\n\titems: ApiRequestItemMap,\n};\n\nexport class ModuleChangesCompilation {\n\n\tpublic destination: ApiRequestItemMap = {};\n\n\tprivate itemsMappedOnParent: {\n\t\t[parentType: string]: {\n\t\t\t[parentId: string]: {\n\t\t\t\t[childItemType: string]: ItemEntry[],\n\t\t\t},\n\t\t},\n\t} = {};\n\n\tprivate transactionChain: AbstractCache[];\n\n\tpublic constructor (\n\t\tprivate linkTreeService: LinkTreeServiceInterface,\n\t\tprivate transaction: TransactionCache,\n\t) {\n\t\tthis.transactionChain = this.transaction.getTransactionChain();\n\t}\n\n\tpublic process (): ModuleChangesCompilationResult {\n\t\tif (this.transaction.rootItem === undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t'A TransactionCache rootItem is required for ModuleChangesCompilation',\n\t\t\t);\n\t\t}\n\n\t\tthis.itemsMappedOnParent = {};\n\n\t\tthis.constructChildItemMap(\n\t\t\tthis.transaction.rootItem.itemType,\n\t\t);\n\n\t\tthis.processItems(\n\t\t\tthis.transaction.rootItem.itemType,\n\t\t\t[\n\t\t\t\tthis.transaction.rootItem,\n\t\t\t],\n\t\t\t{},\n\t\t);\n\n\t\treturn {\n\t\t\titemType: this.transaction.rootItem.itemType,\n\t\t\titemId: this.transaction.rootItem.itemId,\n\t\t\titems: this.destination,\n\t\t};\n\t}\n\n\tprivate constructChildItemMap (\n\t\tparentType: ApiItemType,\n\t): void {\n\t\tconst linkTree = this.linkTreeService.get();\n\t\tconst linkTreeNode = linkTree[parentType];\n\n\t\tif (linkTreeNode === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const childItemType in linkTreeNode) {\n\t\t\tthis.constructChildItemMap(\n\t\t\t\tchildItemType as ApiItemType,\n\t\t\t);\n\n\t\t\tconst deletedEntries: Set<TransactionDeletedItem['entry']['id']> = new Set();\n\n\t\t\tfor (const transaction of this.transactionChain) {\n\t\t\t\tif (transaction instanceof TransactionCache) {\n\t\t\t\t\tconst deletedItemsIterator = transaction.itemHandler.getDeletedItemsIterator(\n\t\t\t\t\t\tchildItemType as ApiItemType,\n\t\t\t\t\t);\n\n\t\t\t\t\tfor (const deletedItemEntry of deletedItemsIterator) {\n\t\t\t\t\t\tdeletedEntries.add(\n\t\t\t\t\t\t\tdeletedItemEntry.id,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const transaction of this.transactionChain) {\n\t\t\t\tconst childItemEntries = transaction.itemHandler.entries.getByItemType(\n\t\t\t\t\tchildItemType as ApiItemType,\n\t\t\t\t);\n\n\t\t\t\tfor (const childItemEntry of childItemEntries) {\n\t\t\t\t\tif (\n\t\t\t\t\t\t// todo/fixme: I think we can assume you can never delete an item on a parent transaction while it's still somehow\n\t\t\t\t\t\t// on a child transaction. In that case we don't have to keep track of the deletedEntries set\n\t\t\t\t\t\tdeletedEntries.has(\n\t\t\t\t\t\t\tchildItemEntry.id,\n\t\t\t\t\t\t)\n\t\t\t\t\t) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst parent = transaction.getParent(\n\t\t\t\t\t\tchildItemEntry,\n\t\t\t\t\t);\n\n\t\t\t\t\tif (parent === null) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.itemsMappedOnParent[parent.itemType] ??= {};\n\t\t\t\t\tthis.itemsMappedOnParent[parent.itemType][parent.itemId] ??= {};\n\t\t\t\t\tthis.itemsMappedOnParent[parent.itemType][parent.itemId][childItemEntry.itemType] ??= [];\n\n\t\t\t\t\tthis.itemsMappedOnParent[parent.itemType][parent.itemId][childItemEntry.itemType].push(\n\t\t\t\t\t\tchildItemEntry,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate processItems<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\titemEntries: ItemEntry<ItemTypeType>[],\n\t\tlinkAccumulator: {[itemType: string]: ItemId[],},\n\t): void {\n\t\tif (this.destination[itemType] === undefined) {\n\t\t\tthis.destination[itemType] = {};\n\t\t}\n\n\t\tif (linkAccumulator[itemType] === undefined) {\n\t\t\tlinkAccumulator[itemType] = [];\n\t\t}\n\n\t\tfor (const itemEntry of itemEntries) {\n\t\t\tconst itemId = itemEntry.itemId;\n\n\t\t\t// each item only has a single parent, so we can safely do this\n\t\t\tif (this.destination[itemType][itemId] !== undefined) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlinkAccumulator[itemType].push(\n\t\t\t\titemId,\n\t\t\t);\n\n\t\t\tthis.destination[itemType][itemId] = this.processItem(\n\t\t\t\titemEntry,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate processItem<ItemTypeType extends ApiItemType> (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t): {\n\t\tvalues?: {\n\t\t\t[columnId: string]: Partial<FieldMap<ItemTypeType>>,\n\t\t},\n\t\tlinks?: {\n\t\t\t[itemType: string]: ItemId[],\n\t\t},\n\t} {\n\t\tconst childItems = this.getItemsByParent(\n\t\t\titemEntry.itemType,\n\t\t\titemEntry.itemId,\n\t\t);\n\n\t\tconst values = this.transaction.itemHandler.formatRequest(\n\t\t\titemEntry,\n\t\t);\n\t\tconst links = {};\n\n\t\tfor (const childType in childItems) {\n\t\t\tthis.processItems(\n\t\t\t\tchildType as ApiItemType,\n\t\t\t\tchildItems[childType],\n\t\t\t\tlinks,\n\t\t\t);\n\t\t}\n\n\t\tconst hasValues = hasProperties(\n\t\t\tvalues,\n\t\t);\n\t\tconst hasLinks = hasProperties(\n\t\t\tlinks,\n\t\t);\n\n\t\tif (hasValues && hasLinks) {\n\t\t\treturn {\n\t\t\t\tvalues: values,\n\t\t\t\tlinks: links,\n\t\t\t};\n\t\t}\n\n\t\tif (hasValues) {\n\t\t\treturn {\n\t\t\t\tvalues: values,\n\t\t\t};\n\t\t}\n\n\t\tif (hasLinks) {\n\t\t\treturn {\n\t\t\t\tlinks: links,\n\t\t\t};\n\t\t}\n\n\t\treturn EMPTY_ENTRY;\n\t}\n\n\tprivate getItemsByParent (\n\t\tparentType: ApiItemType,\n\t\tparentId: ItemId,\n\t): ItemTypeMap<ItemEntry[]> {\n\t\treturn this.itemsMappedOnParent[parentType]?.[parentId] ?? {};\n\t}\n\n}\n","import { ApiFields, ApiItemType, ApiQueryComparator, ApiQueryConditionCustom, ApiQueryConditionSearch, ApiQueryOperator, ItemApiFields } from '@rentman/backend-types';\nimport { ApiQuery, ApiQueryConditionComparator, ApiQueryConditionComparatorShort, ApiQueryConditionExtendedSubQuery, ApiQueryConditionIn, ApiQueryConditionLinkedTo, ApiQueryWithConditions, getFirstProperty } from '../internal';\n\nconst OPPOSITE_COMPARATOR_MAP: {\n\t[key in ApiQueryComparator]: ApiQueryComparator\n} = {\n\t'=': '!=',\n\t'!=': '=',\n\t'>': '<=',\n\t'<': '>=',\n\t'<=': '>',\n\t'>=': '<',\n} as const;\n\n/**\n * When extending this class, note that:\n * - It already provides default values (`not` for `IN` queries, `operator` for `conditions` queries, `field` for\n * sub queries, etc.).\n * - It normalizes comparators (`not` `=` becomes `!=`, etc.).\n */\nexport abstract class QueryParserBase<ReturnType, ParseReturnType = ReturnType> {\n\n\tprivate static normalizeOperator (\n\t\toperator: ApiQueryOperator | undefined,\n\t): Extract<ApiQueryOperator, 'AND' | 'OR'> {\n\t\tswitch (operator) {\n\t\t\tcase undefined:\n\t\t\tcase 'AND':\n\t\t\tcase 'and':\n\t\t\t\treturn 'AND';\n\t\t\tcase 'OR':\n\t\t\tcase 'or':\n\t\t\t\treturn 'OR';\n\t\t\tdefault:\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`QueryParserBase: unknown operator: ${operator}`,\n\t\t\t\t);\n\t\t}\n\t}\n\n\tprivate static isLinkedToQuery<ItemTypeType extends ApiItemType> (\n\t\tquery: unknown,\n\t): query is ApiQueryConditionLinkedTo<ItemTypeType> {\n\t\treturn (query as ApiQueryConditionLinkedTo<ItemTypeType>).linkedTo !== undefined;\n\t}\n\n\tprivate static isCustomQuery<ItemTypeType extends ApiItemType> (\n\t\tquery: unknown,\n\t): query is ApiQueryConditionCustom<ItemTypeType> {\n\t\treturn (query as ApiQueryConditionCustom<ItemTypeType>).custom !== undefined;\n\t}\n\n\tprivate static isSearchQuery (\n\t\tquery: unknown,\n\t): query is ApiQueryConditionSearch {\n\t\treturn (query as ApiQueryConditionSearch).search !== undefined;\n\t}\n\n\tprivate static isQueryWithConditions<ItemTypeType extends ApiItemType> (\n\t\tquery: unknown,\n\t): query is ApiQueryWithConditions<ItemTypeType> {\n\t\treturn (query as ApiQueryWithConditions<ItemTypeType>).conditions !== undefined;\n\t}\n\n\tprivate static isSubQuery<MainItemType extends ApiItemType> (\n\t\tquery: unknown,\n\t): query is ApiQueryConditionExtendedSubQuery<MainItemType, keyof ItemApiFields<MainItemType>, ApiItemType> {\n\t\treturn (query as ApiQueryConditionExtendedSubQuery<MainItemType, keyof ItemApiFields<MainItemType>, ApiItemType>).query !== undefined;\n\t}\n\n\t// We need to have a single entry point, so we can return the 'root' node when returning a graph.\n\tpublic run<ItemTypeType extends ApiItemType> (\n\t\tquery: ApiQuery<ItemTypeType>,\n\t): ReturnType {\n\t\treturn this.parseQuery(\n\t\t\tquery,\n\t\t\t0,\n\t\t) as unknown as ReturnType;\n\t}\n\n\t/**\n\t * @param subQueryDepth As the query language supports nested queries, this parameter denotes how deeply we're\n\t * nested. `subQueryDepth` should increase whenever this method is called from {@link parseSubQuery} or\n\t * {@link parseLinkedToQuery}.\n\t */\n\tprotected parseQuery<ItemTypeType extends ApiItemType> (\n\t\t// Because type narrowing creates increasingly complex types, we're not using the `ApiQuery` type here.\n\t\tquery: unknown,\n\t\tsubQueryDepth: number,\n\t): ParseReturnType {\n\t\tif (\n\t\t\tQueryParserBase.isLinkedToQuery(\n\t\t\t\tquery,\n\t\t\t)\n\t\t) {\n\t\t\treturn this.parseLinkedToQuery(\n\t\t\t\tquery.linkedTo,\n\t\t\t\tquery.query ?? {},\n\t\t\t\tquery.reverse ?? false,\n\t\t\t\tquery.not ?? false,\n\t\t\t\tsubQueryDepth,\n\t\t\t);\n\t\t}\n\n\t\tif (\n\t\t\tQueryParserBase.isCustomQuery(\n\t\t\t\tquery,\n\t\t\t)\n\t\t) {\n\t\t\treturn this.parseCustomQuery(\n\t\t\t\tquery.custom,\n\t\t\t\tquery.parameters,\n\t\t\t\tquery.not ?? false,\n\t\t\t);\n\t\t}\n\n\t\tif (\n\t\t\tQueryParserBase.isSearchQuery(\n\t\t\t\tquery,\n\t\t\t)\n\t\t) {\n\t\t\treturn this.parseSearchQuery(\n\t\t\t\tquery.search,\n\t\t\t\tquery.not ?? false,\n\t\t\t);\n\t\t}\n\n\t\tif (\n\t\t\tQueryParserBase.isQueryWithConditions(\n\t\t\t\tquery,\n\t\t\t)\n\t\t) {\n\t\t\treturn this.parseComplexQuery(\n\t\t\t\tquery.conditions,\n\t\t\t\tQueryParserBase.normalizeOperator(\n\t\t\t\t\tquery.operator,\n\t\t\t\t),\n\t\t\t\tquery.not ?? false,\n\t\t\t\tsubQueryDepth,\n\t\t\t);\n\t\t}\n\n\t\tif (\n\t\t\tQueryParserBase.isSubQuery(\n\t\t\t\tquery,\n\t\t\t)\n\t\t) {\n\t\t\tif (query.key === undefined) {\n\t\t\t\t// Exception is also thrown in the back-end.\n\t\t\t\tthrow new Error(\n\t\t\t\t\t'QueryParserBase: missing \\'key\\' parameter for subquery',\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn this.parseSubQuery(\n\t\t\t\tquery.key,\n\t\t\t\t// The default value for `itemType` is the item type of the column, which we don't have when parsing the query.\n\t\t\t\tquery.itemType,\n\t\t\t\tquery.field ?? 'id',\n\t\t\t\tquery.query,\n\t\t\t\tquery.not ?? false,\n\t\t\t\tsubQueryDepth,\n\t\t\t);\n\t\t}\n\n\t\tconst queryConditionComparator = query as ApiQueryConditionComparator<ItemTypeType, keyof ApiFields[ItemTypeType]>;\n\n\t\tif (queryConditionComparator.key !== undefined) {\n\t\t\treturn this._parseSimpleQuery(\n\t\t\t\tqueryConditionComparator.key,\n\t\t\t\tqueryConditionComparator.value,\n\t\t\t\tqueryConditionComparator,\n\t\t\t);\n\t\t}\n\n\t\tconst key = getFirstProperty(\n\t\t\tquery,\n\t\t);\n\n\t\tif (key === null) {\n\t\t\treturn this.parseEmptyQuery();\n\t\t}\n\n\t\treturn this._parseSimpleQuery(\n\t\t\tkey as keyof ApiFields[ItemTypeType],\n\t\t\t(query as ApiQueryConditionComparatorShort<ItemTypeType, keyof ApiFields[ItemTypeType]>)[key],\n\t\t\t(query as ApiQueryConditionComparatorShort<ItemTypeType, keyof ApiFields[ItemTypeType]>),\n\t\t);\n\t}\n\n\tprotected abstract parseEmptyQuery (): ParseReturnType;\n\n\tprotected abstract parseSubQuery<\n\t\tMainItemType extends ApiItemType,\n\t\tSubItemType extends ApiItemType,\n\t> (\n\t\tkey: keyof ItemApiFields<MainItemType>,\n\t\titemType: SubItemType,\n\t\tfield: keyof ItemApiFields<SubItemType>,\n\t\tquery: ApiQuery<SubItemType>,\n\t\t// We're excluding `undefined` here.\n\t\tnot: boolean,\n\t\tsubQueryDepth: number,\n\t): ParseReturnType;\n\n\tprotected abstract parseSearchQuery (\n\t\tvalue: ApiQueryConditionSearch['search'],\n\t\t// We're excluding `undefined` here.\n\t\tnot: boolean,\n\t): ParseReturnType;\n\n\tprotected abstract parseCustomQuery<\n\t\tItemTypeType extends ApiItemType,\n\t\t// We're specifying a separate type variable for the query here because for custom queries, the type of the\n\t\t// parameters has to match the name of the query. (Unless we're calling `parseCustomQuery` with a specific\n\t\t// custom query, though, it should not really matter.)\n\t\tQueryType extends ApiQueryConditionCustom<ItemTypeType>\n\t> (\n\t\tcustom: QueryType['custom'],\n\t\tparameters: QueryType['parameters'],\n\t\tnot: boolean,\n\t): ParseReturnType;\n\n\t// This method is called with a normalized comparator, so there's no need for a `not` parameter.\n\tprotected abstract parseComparatorQuery<ItemTypeType extends ApiItemType, ColumnId extends keyof ApiFields[ItemTypeType]> (\n\t\tkey: ApiQueryConditionComparator<ItemTypeType, ColumnId>['key'],\n\t\tvalue: ApiQueryConditionComparator<ItemTypeType, ColumnId>['value'],\n\t\tcomparator: ApiQueryConditionComparator<ItemTypeType, ColumnId>['comparator'],\n\t\tquery: ApiQueryConditionComparator<ItemTypeType, ColumnId>,\n\t): ParseReturnType;\n\n\tprotected abstract parseInQuery<ItemTypeType extends ApiItemType, ColumnId extends keyof ApiFields[ItemTypeType]> (\n\t\tkey: ApiQueryConditionIn<ItemTypeType, ColumnId>['key'],\n\t\tvalue: ApiQueryConditionIn<ItemTypeType, ColumnId>['value'],\n\t\tnot: boolean,\n\t): ParseReturnType;\n\n\tprotected abstract parseLinkedToQuery<SubItemType extends ApiItemType> (\n\t\tlinkedTo: ApiQueryConditionLinkedTo<SubItemType>['linkedTo'],\n\t\tquery: Exclude<ApiQueryConditionLinkedTo<SubItemType>['query'], undefined>,\n\t\t// We exclude `undefined` values here.\n\t\treverse: boolean,\n\t\tnot: boolean,\n\t\tsubQueryDepth: number,\n\t): ParseReturnType;\n\n\tprotected abstract parseComplexQuery<ItemTypeType extends ApiItemType> (\n\t\tconditions: ApiQueryWithConditions<ItemTypeType>['conditions'],\n\t\toperator: Extract<ApiQueryOperator, 'AND' | 'OR'>,\n\t\tnot: boolean,\n\t\tsubQueryDepth: number,\n\t): ParseReturnType;\n\n\tprivate _parseSimpleQuery<ItemTypeType extends ApiItemType, ColumnId extends keyof ApiFields[ItemTypeType]> (\n\t\tkey: ColumnId,\n\t\tvalue: ApiQueryConditionIn<ItemTypeType, ColumnId>['value']\n\t\t\t| ApiQueryConditionComparator<ItemTypeType, ColumnId>['value'],\n\t\tquery: ApiQueryConditionIn<ItemTypeType, ColumnId>\n\t\t\t| ApiQueryConditionComparator<ItemTypeType, ColumnId>\n\t\t\t| ApiQueryConditionComparatorShort<ItemTypeType, ColumnId>,\n\t): ParseReturnType {\n\t\tconst comparator = query.comparator;\n\t\tconst not = query.not === true;\n\n\t\tswitch (comparator) {\n\t\t\tcase undefined:\n\t\t\t\tif (\n\t\t\t\t\tArray.isArray(\n\t\t\t\t\t\tvalue,\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\treturn this.parseInQuery(\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tvalue,\n\t\t\t\t\t\tnot,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn this.parseComparatorQuery(\n\t\t\t\t\tkey,\n\t\t\t\t\tvalue,\n\t\t\t\t\tnot\n\t\t\t\t\t\t? '!='\n\t\t\t\t\t\t: '=',\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n\t\t\t\t\tquery as ApiQueryConditionComparator<ItemTypeType, ColumnId>,\n\t\t\t\t);\n\t\t\tcase '=':\n\t\t\tcase '!=':\n\t\t\tcase '>':\n\t\t\tcase '<':\n\t\t\tcase '>=':\n\t\t\tcase '<=':\n\t\t\t\treturn this.parseComparatorQuery(\n\t\t\t\t\tkey,\n\t\t\t\t\tvalue,\n\t\t\t\t\tnot\n\t\t\t\t\t\t? OPPOSITE_COMPARATOR_MAP[comparator]\n\t\t\t\t\t\t: comparator,\n\t\t\t\t\tquery as ApiQueryConditionComparator<ItemTypeType, ColumnId>,\n\t\t\t\t);\n\t\t\tcase 'in':\n\t\t\tcase 'IN':\n\t\t\t\treturn this.parseInQuery(\n\t\t\t\t\tkey,\n\t\t\t\t\tvalue as ApiQueryConditionIn<ItemTypeType, ColumnId>['value'],\n\t\t\t\t\tnot,\n\t\t\t\t);\n\t\t\tdefault:\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`QueryParserBase: unknown comparator: ${comparator}`,\n\t\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ApiItemType } from '@rentman/backend-types';\nimport { GetFieldValueType, ItemIdConversionMap, ItemTypeColumnId } from '../../types/ItemTypesCollection';\n\n// TODO: Add item type parameter.\n/**\n * There are multiple reason we're not using the string representation of the query as a leaf node:\n * - When item IDs are updated after a save, the string representation of a query might change, yet we don't want to\n * replace all leaf nodes.\n */\nexport type LeafQueryNode = {\n\tstring: string,\n};\n\n/**\n * A map consisting of (branching) query nodes as a value and the query node token as a key.\n */\nexport type BranchNodeMap = Map<string, QueryNode>;\n\nexport type QueryNodeTuple = {\n\tleafNodes: LeafQueryNode[],\n\t// We'll have lots of edges connecting to just a leaf node. No need to construct a Map for every one of them.\n\tbranchNodeMap: BranchNodeMap | null,\n};\n\nexport type PositiveMatchingResult = true | 'maybe';\n\nexport interface MatchesAccumulatorTuple<MatchKeyType> {\n\ttrue: Set<MatchKeyType>,\n\tmaybe?: Set<MatchKeyType>,\n}\n\nexport type MatchesAccumulator<MatchKeyType> = Map<string, MatchesAccumulatorTuple<MatchKeyType>>;\n\nexport type GetField<ItemTypeType extends ApiItemType> = <ColumnId extends ItemTypeColumnId<ItemTypeType>> (\n\tcolumnId: ColumnId,\n) => GetFieldValueType<ItemTypeType, ColumnId> | undefined;\n\n/**\n * Function that allows us to modify a node tuple (consisting of leaf and branching nodes) of the destination query\n * graph whenever the corresponding node tuple of the source query graph is a leaf node tuple (it has no branching nodes\n * attached).\n *\n * It can be used to expand the resulting (destination) query graph when cloning.\n */\nexport type ModifyLeafNodeTupleFunction = (leafNodeTuple: QueryNodeTuple) => void;\n\nexport abstract class QueryNode<ItemTypeType extends ApiItemType = ApiItemType> {\n\n\tprotected constructor (\n\t\tpublic readonly TOKEN: string,\n\t) {\n\t}\n\n\tpublic static addBranchNode (\n\t\tdestinationQueryNodeTuple: QueryNodeTuple,\n\t\tnode: QueryNode,\n\t): void {\n\t\tlet branchNodeMap = destinationQueryNodeTuple.branchNodeMap;\n\n\t\tif (branchNodeMap === null) {\n\t\t\tbranchNodeMap = destinationQueryNodeTuple.branchNodeMap = new Map();\n\t\t\tbranchNodeMap.set(\n\t\t\t\tnode.TOKEN,\n\t\t\t\tnode,\n\t\t\t);\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst existingNode = branchNodeMap.get(\n\t\t\tnode.TOKEN,\n\t\t);\n\n\t\tif (existingNode === undefined) {\n\t\t\tbranchNodeMap.set(\n\t\t\t\tnode.TOKEN,\n\t\t\t\tnode,\n\t\t\t);\n\t\t} else {\n\t\t\texistingNode.copyEdgesFrom(\n\t\t\t\tnode,\n\t\t\t\tundefined,\n\t\t\t);\n\t\t}\n\t}\n\n\tprotected static matchQueryNodes<ItemTypeType extends ApiItemType, MatchKeyType> (\n\t\tqueryNodeTuple: QueryNodeTuple,\n\t\tmatchKey: MatchKeyType,\n\t\tgetField: GetField<ItemTypeType>,\n\t\tparentMatch: PositiveMatchingResult,\n\t\tmatchesAccumulator: MatchesAccumulator<MatchKeyType>,\n\t): MatchesAccumulator<MatchKeyType> {\n\t\tfor (const leafNode of queryNodeTuple.leafNodes) {\n\t\t\tlet matchesAccumulatorTuple = matchesAccumulator.get(\n\t\t\t\tleafNode.string,\n\t\t\t);\n\n\t\t\tif (matchesAccumulatorTuple === undefined) {\n\t\t\t\tmatchesAccumulator.set(\n\t\t\t\t\tleafNode.string,\n\t\t\t\t\tmatchesAccumulatorTuple = {\n\t\t\t\t\t\ttrue: new Set(),\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (parentMatch === true) {\n\t\t\t\tmatchesAccumulatorTuple.maybe?.delete(\n\t\t\t\t\tmatchKey,\n\t\t\t\t);\n\t\t\t\tmatchesAccumulatorTuple.true.add(\n\t\t\t\t\tmatchKey,\n\t\t\t\t);\n\n\t\t\t\t// We're dealing with a 'maybe' match.\n\t\t\t} else if (\n\t\t\t\t!matchesAccumulatorTuple.true.has(\n\t\t\t\t\tmatchKey,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tmatchesAccumulatorTuple.maybe ??= new Set();\n\t\t\t\tmatchesAccumulatorTuple.maybe.add(\n\t\t\t\t\tmatchKey,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst branchNodeMap = queryNodeTuple.branchNodeMap;\n\n\t\tif (branchNodeMap === null) {\n\t\t\treturn matchesAccumulator;\n\t\t}\n\n\t\tfor (const child of branchNodeMap.values()) {\n\t\t\tchild.match(\n\t\t\t\tmatchKey,\n\t\t\t\tgetField,\n\t\t\t\tparentMatch,\n\t\t\t\tmatchesAccumulator,\n\t\t\t);\n\t\t}\n\n\t\treturn matchesAccumulator;\n\t}\n\n\t/**\n\t * This method will be called when graph merging, which is what we should optimize for.\n\t * @param sourceQueryNodeTuple - We enforce unique tokens by passing a branch node map here. Objects will be cloned.\n\t **/\n\tprotected static cloneQueryNodesInto (\n\t\tdestinationQueryNodeTuple: QueryNodeTuple,\n\t\tsourceQueryNodeTuple: QueryNodeTuple,\n\t\tmodifyLeafNodeTuple: ModifyLeafNodeTupleFunction | undefined,\n\t): void {\n\t\tconst sourceBranchNodeMap = sourceQueryNodeTuple.branchNodeMap;\n\n\t\tif (\n\t\t\tmodifyLeafNodeTuple !== undefined\n\t\t\t&& sourceBranchNodeMap === null\n\t\t) {\n\t\t\tmodifyLeafNodeTuple(\n\t\t\t\tdestinationQueryNodeTuple,\n\t\t\t);\n\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const leafNode of sourceQueryNodeTuple.leafNodes) {\n\t\t\tdestinationQueryNodeTuple.leafNodes.push(\n\t\t\t\tleafNode,\n\t\t\t);\n\t\t}\n\n\t\tif (sourceBranchNodeMap === null) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet destinationBranchNodeMap = destinationQueryNodeTuple.branchNodeMap;\n\n\t\tif (destinationBranchNodeMap === null) {\n\t\t\tdestinationBranchNodeMap = destinationQueryNodeTuple.branchNodeMap = new Map();\n\n\t\t\tfor (const node of sourceBranchNodeMap.values()) {\n\t\t\t\tdestinationBranchNodeMap.set(\n\t\t\t\t\tnode.TOKEN,\n\t\t\t\t\tnode.clone(\n\t\t\t\t\t\tmodifyLeafNodeTuple,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const node of sourceBranchNodeMap.values()) {\n\t\t\tconst existingNode = destinationBranchNodeMap.get(\n\t\t\t\tnode.TOKEN,\n\t\t\t);\n\n\t\t\tif (existingNode === undefined) {\n\t\t\t\tdestinationBranchNodeMap.set(\n\t\t\t\t\tnode.TOKEN,\n\t\t\t\t\tnode.clone(\n\t\t\t\t\t\tmodifyLeafNodeTuple,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\texistingNode.copyEdgesFrom(\n\t\t\t\t\tnode,\n\t\t\t\t\tmodifyLeafNodeTuple,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Starts with an underscore to avoid confusion with the non-static function.\n\tprotected static _updateLocalItemIdReferences (\n\t\tbranchNodeMap: BranchNodeMap | null,\n\t\titemIdConversionMap: ItemIdConversionMap,\n\t): boolean {\n\t\tif (branchNodeMap === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\tlet result: boolean = false;\n\n\t\tfor (const branchNode of branchNodeMap.values()) {\n\t\t\tif (\n\t\t\t\tbranchNode.updateLocalItemIdReferences(\n\t\t\t\t\titemIdConversionMap,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tresult = true;\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic abstract match<MatchKey> (\n\t\tmatchKey: MatchKey,\n\t\tgetField: GetField<ItemTypeType>,\n\t\tparentMatch: PositiveMatchingResult,\n\t\tmatchesAccumulator: MatchesAccumulator<MatchKey>,\n\t): MatchesAccumulator<MatchKey>;\n\n\tpublic abstract clone (\n\t\tmodifyLeafNodeTuple: ModifyLeafNodeTupleFunction | undefined,\n\t): QueryNode<ItemTypeType>;\n\n\tpublic abstract updateLocalItemIdReferences (\n\t\titemIdConversionMap: ItemIdConversionMap,\n\t): boolean;\n\n\tpublic abstract copyEdgesFrom (\n\t\tsourceNode: QueryNode<ItemTypeType>,\n\t\tmodifyLeafNodeTuple: ModifyLeafNodeTupleFunction | undefined,\n\t): this;\n\n}\n","import { ApiItemType } from '@rentman/backend-types';\nimport { ItemIdConversionMap } from '../../types/ItemTypesCollection';\nimport { LeafQueryNode, ModifyLeafNodeTupleFunction, QueryNode, QueryNodeTuple } from './QueryNode';\n\nexport abstract class ValuelessEdgeQueryNode<ItemTypeType extends ApiItemType>\n\textends QueryNode<ItemTypeType> {\n\n\tpublic constructor (\n\t\ttoken: string,\n\t\tpublic readonly connectedNodesTuple: QueryNodeTuple = {\n\t\t\tleafNodes: [],\n\t\t\tbranchNodeMap: null,\n\t\t},\n\t) {\n\t\tsuper(\n\t\t\ttoken,\n\t\t);\n\t}\n\n\tpublic connectLeafNode (\n\t\tnodeToConnect: LeafQueryNode,\n\t): this {\n\t\tthis.connectedNodesTuple.leafNodes.push(\n\t\t\tnodeToConnect,\n\t\t);\n\n\t\treturn this;\n\t}\n\n\tpublic connectBranchNode (\n\t\tnodeToConnect: QueryNode<ItemTypeType>,\n\t): this {\n\t\tQueryNode.addBranchNode(\n\t\t\tthis.connectedNodesTuple,\n\t\t\tnodeToConnect as QueryNode<ApiItemType>,\n\t\t);\n\n\t\treturn this;\n\t}\n\n\tpublic override updateLocalItemIdReferences (\n\t\titemIdConversionMap: ItemIdConversionMap,\n\t): boolean {\n\t\treturn QueryNode._updateLocalItemIdReferences(\n\t\t\tthis.connectedNodesTuple.branchNodeMap,\n\t\t\titemIdConversionMap,\n\t\t);\n\t}\n\n\tpublic override copyEdgesFrom (\n\t\tsourceNode: ValuelessEdgeQueryNode<ItemTypeType>,\n\t\tmodifyLeafNodeTuple: ModifyLeafNodeTupleFunction | undefined,\n\t): this {\n\t\tQueryNode.cloneQueryNodesInto(\n\t\t\tthis.connectedNodesTuple,\n\t\t\tsourceNode.connectedNodesTuple,\n\t\t\tmodifyLeafNodeTuple,\n\t\t);\n\n\t\treturn this;\n\t}\n\n}\n","import { ApiItemType } from '@rentman/backend-types';\nimport { ApiQuery } from '../../internal';\nimport { GetField, MatchesAccumulator, PositiveMatchingResult, QueryNode } from './QueryNode';\nimport { ValuelessEdgeQueryNode } from './ValuelessEdgeQueryNode';\n\nexport abstract class NonMatchableQueryNode<ItemTypeType extends ApiItemType>\n\textends ValuelessEdgeQueryNode<ItemTypeType> {\n\n\tpublic constructor (\n\t\ttoken: string,\n\t\tpublic readonly apiQuery: ApiQuery<ItemTypeType>,\n\t) {\n\t\tsuper(\n\t\t\ttoken,\n\t\t);\n\t}\n\n\tpublic override match<MatchKeyType> (\n\t\tmatchKey: MatchKeyType,\n\t\tgetField: GetField<ItemTypeType>,\n\t\t_parentMatch: PositiveMatchingResult,\n\t\tmatchesAccumulator: MatchesAccumulator<MatchKeyType>,\n\t): MatchesAccumulator<MatchKeyType> {\n\t\treturn QueryNode.matchQueryNodes(\n\t\t\tthis.connectedNodesTuple,\n\t\t\tmatchKey,\n\t\t\tgetField,\n\t\t\t// true && 'maybe' should always result in 'maybe'.\n\t\t\t'maybe',\n\t\t\tmatchesAccumulator,\n\t\t);\n\t}\n\n}\n","import { ApiItemType, ApiQueryConditionCustom } from '@rentman/backend-types';\nimport { NonMatchableQueryNode } from './NonMatchableQueryNode';\nimport { ModifyLeafNodeTupleFunction } from './QueryNode';\n\nexport class CustomQueryNode<ItemTypeType extends ApiItemType>\n\textends NonMatchableQueryNode<ItemTypeType> {\n\n\tpublic constructor (\n\t\tapiQuery: ApiQueryConditionCustom<ItemTypeType>,\n\t) {\n\t\tsuper(\n\t\t\t// TODO: Temporary token.\n\t\t\t'CUSTOM:',\n\t\t\tapiQuery,\n\t\t);\n\t}\n\n\tpublic clone (\n\t\tmodifyLeafNodeTuple: ModifyLeafNodeTupleFunction | undefined,\n\t): CustomQueryNode<ItemTypeType> {\n\t\treturn new CustomQueryNode<ItemTypeType>(\n\t\t\tthis.apiQuery,\n\t\t)\n\t\t\t.copyEdgesFrom(\n\t\t\t\tthis,\n\t\t\t\tmodifyLeafNodeTuple,\n\t\t\t);\n\t}\n\n\tpublic declare apiQuery: ApiQueryConditionCustom<ItemTypeType>;\n\n}\n","import moment from 'moment';\n\nexport const unsupportedQueryValue = Symbol(\n\t'Unsupported query value',\n);\n\nexport type ExtractEdgeValueType<ValueTransformerType extends ValueTransformer<any, any>> =\n\tValueTransformerType extends ValueTransformer<any, infer EdgeValueType> ? EdgeValueType : never;\n\n/**\n * Each of our comparator query nodes represent an operation ({@link IsComparatorQueryNode},\n * {@link NotIsComparatorQueryNode}, {@link GreaterSmallerThanComparatorQueryNode}). To prevent having to create\n * a separate class for each supported data type (number, string, date, etc.), we introduce value transformers.\n */\nexport interface ValueTransformer<FieldValueType, EdgeValueType, EdgeCompareValueType = EdgeValueType> {\n\t/**\n\t * Converts a value used in a query to a value stored with a query graph edge. Used when converting a query to a\n\t * graph. Might return a {@link unsupportedQueryValue} symbol.\n\t */\n\treadonly queryToEdgeValue: (\n\t\tqueryValue: any,\n\t) => EdgeValueType | typeof unsupportedQueryValue,\n\t/**\n\t * Converts an item field value to a value stored with a query graph edge. Used during the matching process.\n\t */\n\treadonly fieldToEdgeValue: (\n\t\tfieldValue: FieldValueType,\n\t) => EdgeCompareValueType,\n}\n\n/**\n * An edge value transformer is used for the {@link GreaterSmallerThanComparatorQueryNode} exclusively. It adds a\n * `edgeToEdgeCompareValue` method, which is used to facilitate the 'NOW' value for date queries. When using the\n * 'NOW' value, we're storing the 'NOW' string literal with the edge, while comparing with the current time.\n */\nexport interface EdgeValueTransformer<FieldValueType, EdgeValueType, EdgeCompareValueType>\n\textends ValueTransformer<FieldValueType, EdgeValueType, EdgeCompareValueType> {\n\n\treadonly edgeToEdgeCompareValue: (\n\t\tedgeValue: EdgeValueType,\n\t) => EdgeCompareValueType,\n}\n\nexport const numberValueTransformer: EdgeValueTransformer<number, number, number> = {\n\tqueryToEdgeValue: queryValue => typeof queryValue === 'number'\n\t\t? queryValue\n\t\t: unsupportedQueryValue,\n\tfieldToEdgeValue: fieldValue => fieldValue,\n\tedgeToEdgeCompareValue: edgeValue => edgeValue,\n};\n\n/**\n * String comparisons are always case-insensitive because the backend also does this because the MySQL collation we use\n * is case-insensitive.\n */\nexport const stringNullValueTransformer: ValueTransformer<string | null, string | null> = {\n\tqueryToEdgeValue: queryValue => {\n\t\tif (queryValue === null) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (typeof queryValue === 'string') {\n\t\t\treturn queryValue.toLowerCase();\n\t\t}\n\n\t\treturn unsupportedQueryValue;\n\t},\n\tfieldToEdgeValue: fieldValue => fieldValue === null\n\t\t? fieldValue\n\t\t: fieldValue.toLowerCase(),\n};\n\n/**\n * Since `number`, `boolean` and `null` types don't require any special treatment, we can use a single value transformer\n * for these types.\n */\nexport const numberBooleanNullValueTransformer: ValueTransformer<number | boolean | null, number | boolean | null> = {\n\tqueryToEdgeValue: queryValue => (\n\t\tqueryValue === null\n\t\t|| typeof queryValue === 'number'\n\t\t|| typeof queryValue === 'boolean'\n\t)\n\t\t? queryValue\n\t\t: unsupportedQueryValue,\n\tfieldToEdgeValue: fieldValue => fieldValue,\n};\n\nexport const dateNowValueTransformer: EdgeValueTransformer<moment.Moment, number | 'NOW', number> = {\n\tqueryToEdgeValue: queryValue => {\n\t\tif (queryValue === 'NOW') {\n\t\t\treturn 'NOW';\n\t\t}\n\n\t\tif (\n\t\t\tmoment.isMoment(\n\t\t\t\tqueryValue,\n\t\t\t)\n\t\t\t&& queryValue.isValid()\n\t\t) {\n\t\t\treturn queryValue.valueOf();\n\t\t}\n\n\t\treturn unsupportedQueryValue;\n\t},\n\tfieldToEdgeValue: fieldValue => fieldValue.valueOf(),\n\tedgeToEdgeCompareValue: edgeValue => edgeValue !== 'NOW'\n\t\t? edgeValue\n\t\t: moment.now(),\n};\n\nexport const dateNullValueTransformer: ValueTransformer<moment.Moment, number | null> = {\n\t// `null` field values are represented by invalid moment objects.\n\tqueryToEdgeValue: queryValue => {\n\t\tif (\n\t\t\t!moment.isMoment(\n\t\t\t\tqueryValue,\n\t\t\t)\n\t\t) {\n\t\t\treturn unsupportedQueryValue;\n\t\t}\n\n\t\tif (queryValue.isValid()) {\n\t\t\treturn queryValue.valueOf();\n\t\t}\n\n\t\treturn null;\n\t},\n\tfieldToEdgeValue: fieldValue => fieldValue.isValid()\n\t\t// If it's a valid moment we convert it to a timestamp since every moment is its own object reference.\n\t\t? fieldValue.valueOf()\n\t\t// If it's an invalid moment we convert it to `null`.\n\t\t: null,\n};\n\nexport const durationValueTransformer: EdgeValueTransformer<moment.Duration, number, number> = {\n\t// `null` field values are represented by zero-length durations.\n\tqueryToEdgeValue: queryValue => moment.isDuration(\n\t\tqueryValue,\n\t)\n\t\t? queryValue.valueOf() as number\n\t\t: unsupportedQueryValue,\n\t// We'll just use zero as an edge value.\n\tfieldToEdgeValue: fieldValue => fieldValue.valueOf() as number,\n\tedgeToEdgeCompareValue: edgeValue => edgeValue,\n};\n","import { ApiItemType } from '@rentman/backend-types';\nimport { ErrorHandlerInterface } from '../../interfaces/ErrorHandlerInterface';\nimport { ItemIdConversionMap, ItemTypeColumnId } from '../../types/ItemTypesCollection';\nimport { GetField, LeafQueryNode, MatchesAccumulator, ModifyLeafNodeTupleFunction, QueryNode, QueryNodeTuple } from './QueryNode';\nimport { ExtractEdgeValueType, numberBooleanNullValueTransformer, stringNullValueTransformer, unsupportedQueryValue, ValueTransformer } from './ValueTransformers';\n\nexport abstract class ComparatorQueryNode<ItemTypeType extends ApiItemType, ValueTransformerType extends ValueTransformer<any, any>>\n\textends QueryNode<ItemTypeType> {\n\n\t// Can connect with nodes of another item type.\n\tpublic readonly edgeMap: Map<ExtractEdgeValueType<ValueTransformerType>, QueryNodeTuple> = new Map();\n\n\tprotected constructor (\n\t\ttoken: string,\n\t\tprotected readonly columnId: ItemTypeColumnId<ItemTypeType>,\n\t\tpublic readonly valueTransformer: ValueTransformerType,\n\t\tprotected readonly errorHandler: ErrorHandlerInterface,\n\t) {\n\t\tsuper(\n\t\t\ttoken,\n\t\t);\n\t}\n\n\tprotected static findValueTransformer<ValueTransformerType extends ValueTransformer<any, any>> (\n\t\tqueryValue: any,\n\t\tvalueTransformers: ValueTransformerType[],\n\t): ValueTransformerType | null {\n\t\tfor (const valueTransformer of valueTransformers) {\n\t\t\tif (\n\t\t\t\tvalueTransformer.queryToEdgeValue(\n\t\t\t\t\tqueryValue,\n\t\t\t\t) !== unsupportedQueryValue\n\t\t\t) {\n\t\t\t\treturn valueTransformer;\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tpublic connectLeafNode (\n\t\tqueryValue: any,\n\t\tnode: LeafQueryNode,\n\t): this {\n\t\tlet transformedValue = this.valueTransformer.queryToEdgeValue(\n\t\t\tqueryValue,\n\t\t);\n\n\t\tif (transformedValue === unsupportedQueryValue) {\n\t\t\tthis.errorHandler.logError(\n\t\t\t\tnew Error(\n\t\t\t\t\t`Unsupported query value '${queryValue}' passed to 'connectLeafNode'`,\n\t\t\t\t),\n\t\t\t);\n\n\t\t\ttransformedValue = queryValue;\n\t\t}\n\n\t\tthis.getQueryNodeTuple(\n\t\t\ttransformedValue,\n\t\t)\n\t\t\t.leafNodes\n\t\t\t.push(\n\t\t\t\tnode,\n\t\t\t);\n\n\t\treturn this;\n\t}\n\n\tpublic connectBranchNode (\n\t\tqueryValue: any,\n\t\tnodeToConnect: QueryNode<ItemTypeType>,\n\t): this {\n\t\tlet transformedValue = this.valueTransformer.queryToEdgeValue(\n\t\t\tqueryValue,\n\t\t);\n\n\t\tif (transformedValue === unsupportedQueryValue) {\n\t\t\tthis.errorHandler.logError(\n\t\t\t\tnew Error(\n\t\t\t\t\t`Unsupported query value '${queryValue}' passed to 'connectBranchNode'`,\n\t\t\t\t),\n\t\t\t);\n\n\t\t\ttransformedValue = queryValue;\n\t\t}\n\n\t\tQueryNode.addBranchNode(\n\t\t\tthis.getQueryNodeTuple(\n\t\t\t\ttransformedValue,\n\t\t\t),\n\t\t\tnodeToConnect as QueryNode<ApiItemType>,\n\t\t);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Copies edges from source `sourceNode` into the node itself. The column ID and type should be equal.\n\t */\n\tpublic override copyEdgesFrom (\n\t\tsourceNode: ComparatorQueryNode<ItemTypeType, ValueTransformerType>,\n\t\tmodifyLeafNodeTuple: ModifyLeafNodeTupleFunction | undefined,\n\t): this {\n\t\t// When determining what value transformer to use, the query parser looks at the value used in the query.\n\t\t// However, since the `null` value can be used for both string and number columns, when encountering a query\n\t\t// with a `null` comparison on a string column, the {@link numberBooleanNullValueTransformer} will be selected\n\t\t// erroneously. However, this should be very rare, as there are very few nullable string columns.\n\t\tif (\n\t\t\tthis.valueTransformer === numberBooleanNullValueTransformer\n\t\t\t&& sourceNode.valueTransformer === stringNullValueTransformer\n\t\t) {\n\t\t\t(this.valueTransformer as ValueTransformer<any, any>) = stringNullValueTransformer;\n\t\t}\n\n\t\tfor (const sourceEdge of sourceNode.edgeMap.entries()) {\n\t\t\tComparatorQueryNode.cloneQueryNodesInto(\n\t\t\t\tthis.getQueryNodeTuple(\n\t\t\t\t\tsourceEdge[0],\n\t\t\t\t),\n\t\t\t\tsourceEdge[1],\n\t\t\t\tmodifyLeafNodeTuple,\n\t\t\t);\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tpublic override updateLocalItemIdReferences (\n\t\titemIdConversionMap: ItemIdConversionMap,\n\t): boolean {\n\t\tlet result: boolean = false;\n\n\t\t// TODO: Instead of testing every value in the map, we could be a little more robust here, for instance\n\t\t// by adding a response column parameter to this function and checking whether we're dealing with an ID\n\t\t// column.\n\t\tfor (const itemType in itemIdConversionMap) {\n\t\t\tfor (const oldValueString in itemIdConversionMap[itemType]) {\n\t\t\t\tconst oldValue = Number(\n\t\t\t\t\toldValueString,\n\t\t\t\t) as ExtractEdgeValueType<ValueTransformerType>;\n\n\t\t\t\tconst edge = this.edgeMap.get(\n\t\t\t\t\toldValue,\n\t\t\t\t);\n\n\t\t\t\tif (edge === undefined) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// We're being extremely careful here. We could also assume that an edge with the new ID should\n\t\t\t\t// never exist and call `this.edgeMap.set()`.\n\t\t\t\tComparatorQueryNode.cloneQueryNodesInto(\n\t\t\t\t\tthis.getQueryNodeTuple(\n\t\t\t\t\t\titemIdConversionMap[itemType][oldValueString] as ExtractEdgeValueType<ValueTransformerType>,\n\t\t\t\t\t),\n\t\t\t\t\tedge,\n\t\t\t\t\tundefined,\n\t\t\t\t);\n\n\t\t\t\tthis.edgeMap.delete(\n\t\t\t\t\toldValue,\n\t\t\t\t);\n\n\t\t\t\tresult = true;\n\t\t\t}\n\t\t}\n\n\t\tfor (const queryNodeTuple of this.edgeMap.values()) {\n\t\t\tif (\n\t\t\t\tQueryNode._updateLocalItemIdReferences(\n\t\t\t\t\tqueryNodeTuple.branchNodeMap,\n\t\t\t\t\titemIdConversionMap,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tresult = true;\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic abstract clone (\n\t\tmodifyLeafNodeTuple: ModifyLeafNodeTupleFunction | undefined,\n\t): ComparatorQueryNode<ItemTypeType, ValueTransformerType>;\n\n\tpublic getValues (): ExtractEdgeValueType<ValueTransformerType>[] {\n\t\treturn Array.from(\n\t\t\tthis.edgeMap.keys(),\n\t\t);\n\t}\n\n\tprotected matchUndefinedValue<MatchKeyType> (\n\t\tmatchKey: MatchKeyType,\n\t\tgetField: GetField<ItemTypeType>,\n\t\tmatchesAccumulator: MatchesAccumulator<MatchKeyType>,\n\t): MatchesAccumulator<MatchKeyType> {\n\t\tfor (const queryNodeTuple of this.edgeMap.values()) {\n\t\t\tQueryNode.matchQueryNodes(\n\t\t\t\tqueryNodeTuple,\n\t\t\t\tmatchKey,\n\t\t\t\tgetField,\n\t\t\t\t'maybe',\n\t\t\t\tmatchesAccumulator,\n\t\t\t);\n\t\t}\n\n\t\treturn matchesAccumulator;\n\t}\n\n\tprivate getQueryNodeTuple (\n\t\tvalue: ExtractEdgeValueType<ValueTransformerType>,\n\t): QueryNodeTuple {\n\t\tlet queryNodeTuple = this.edgeMap.get(\n\t\t\tvalue,\n\t\t);\n\n\t\tif (queryNodeTuple === undefined) {\n\t\t\tthis.edgeMap.set(\n\t\t\t\tvalue,\n\t\t\t\tqueryNodeTuple = {\n\t\t\t\t\tleafNodes: [],\n\t\t\t\t\tbranchNodeMap: null,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\treturn queryNodeTuple;\n\t}\n\n}\n","import { ApiFields, ApiItemType, ApiQueryComparator } from '@rentman/backend-types';\nimport { ApiQueryConditionComparator, ErrorHandlerInterface } from '../../internal';\nimport { ItemTypeColumnId } from '../../types/ItemTypesCollection';\nimport { ComparatorQueryNode } from './CompatorQueryNode';\nimport { GetField, MatchesAccumulator, ModifyLeafNodeTupleFunction, PositiveMatchingResult, QueryNode } from './QueryNode';\nimport { dateNowValueTransformer, durationValueTransformer, EdgeValueTransformer, numberValueTransformer } from './ValueTransformers';\n\ntype GreaterSmallerThanCompareFunction = (\n\tfieldValue: number,\n\tedgeValue: number,\n) => boolean;\n\nexport type GreaterSmallerThanComparator = Exclude<ApiQueryComparator, '=' | '!='>;\n\nconst valueTransformers = [\n\tnumberValueTransformer,\n\tdateNowValueTransformer,\n\tdurationValueTransformer,\n] as const satisfies EdgeValueTransformer<any, any, any>[];\n\n/**\n * The `Map` implementation we're using for the edges lends itself well for equality testing, which is what we're\n * optimizing for. All other comparators function in the same way, as we need to test each key in the map individually.\n * We could create a subclass for each comparator in the future.\n */\nexport class GreaterSmallerThanComparatorQueryNode<ItemTypeType extends ApiItemType>\n\textends ComparatorQueryNode<ItemTypeType, typeof valueTransformers[number]> {\n\n\tprotected compareValue: GreaterSmallerThanCompareFunction;\n\n\tprotected constructor (\n\t\tcolumnId: ItemTypeColumnId<ItemTypeType>,\n\t\tprotected readonly comparator: GreaterSmallerThanComparator,\n\t\tvalueTransformer: typeof valueTransformers[number],\n\t\terrorHandler: ErrorHandlerInterface,\n\t) {\n\t\tsuper(\n\t\t\t`${comparator}:${columnId as string}`,\n\t\t\tcolumnId,\n\t\t\tvalueTransformer,\n\t\t\terrorHandler,\n\t\t);\n\n\t\tthis.compareValue = GreaterSmallerThanComparatorQueryNode.getCompareFunction(\n\t\t\tthis.comparator,\n\t\t);\n\t}\n\n\tpublic static construct<ItemTypeType extends ApiItemType, ColumnId extends keyof ApiFields[ItemTypeType]> (\n\t\tkey: ApiQueryConditionComparator<ItemTypeType, ColumnId>['key'],\n\t\tvalue: ApiQueryConditionComparator<ItemTypeType, ColumnId>['value'],\n\t\tcomparator: ApiQueryConditionComparator<ItemTypeType, ColumnId>['comparator'],\n\t\terrorHandler: ErrorHandlerInterface,\n\t): GreaterSmallerThanComparatorQueryNode<ItemTypeType> | null {\n\t\tif (\n\t\t\t!GreaterSmallerThanComparatorQueryNode.isSupportedComparator(\n\t\t\t\tcomparator,\n\t\t\t)\n\t\t) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst valueTransformer = ComparatorQueryNode.findValueTransformer(\n\t\t\tvalue,\n\t\t\tvalueTransformers,\n\t\t);\n\n\t\tif (valueTransformer === null) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn new GreaterSmallerThanComparatorQueryNode(\n\t\t\tkey as ItemTypeColumnId<ItemTypeType>,\n\t\t\tcomparator,\n\t\t\tvalueTransformer,\n\t\t\terrorHandler,\n\t\t);\n\t}\n\n\tprotected static isSupportedComparator (\n\t\tcomparator: ApiQueryComparator,\n\t): comparator is GreaterSmallerThanComparator {\n\t\tswitch (comparator) {\n\t\t\tcase '<':\n\t\t\tcase '<=':\n\t\t\tcase '>':\n\t\t\tcase '>=':\n\t\t\t\treturn true;\n\t\t\tdefault:\n\t\t\t\treturn false;\n\t\t}\n\t}\n\n\tpublic override match<MatchKeyType> (\n\t\tmatchKey: MatchKeyType,\n\t\tgetField: GetField<ItemTypeType>,\n\t\tparentMatch: PositiveMatchingResult,\n\t\tmatchesAccumulator: MatchesAccumulator<MatchKeyType>,\n\t): MatchesAccumulator<MatchKeyType> {\n\t\tconst fieldValue = getField(\n\t\t\tthis.columnId,\n\t\t);\n\n\t\tif (fieldValue === undefined) {\n\t\t\treturn this.matchUndefinedValue(\n\t\t\t\tmatchKey,\n\t\t\t\tgetField,\n\t\t\t\tmatchesAccumulator,\n\t\t\t);\n\t\t}\n\n\t\tif (fieldValue === null) {\n\t\t\tthrow new Error(\n\t\t\t\t`Encountered null-value in greater / smaller then comparator node ${this.TOKEN}`,\n\t\t\t);\n\t\t}\n\n\t\tconst transformedFieldValue = (this.valueTransformer as EdgeValueTransformer<any, any, any>).fieldToEdgeValue(\n\t\t\tfieldValue,\n\t\t);\n\n\t\tfor (const entry of this.edgeMap.entries()) {\n\t\t\tif (\n\t\t\t\t!this.compareValue(\n\t\t\t\t\ttransformedFieldValue,\n\t\t\t\t\t(this.valueTransformer as EdgeValueTransformer<any, any, any>).edgeToEdgeCompareValue(\n\t\t\t\t\t\tentry[0],\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tQueryNode.matchQueryNodes(\n\t\t\t\tentry[1],\n\t\t\t\tmatchKey,\n\t\t\t\tgetField,\n\t\t\t\tparentMatch,\n\t\t\t\tmatchesAccumulator,\n\t\t\t);\n\t\t}\n\n\t\treturn matchesAccumulator;\n\t}\n\n\tprotected static getCompareFunction (\n\t\tcomparator: GreaterSmallerThanComparator,\n\t): GreaterSmallerThanCompareFunction {\n\t\tswitch (comparator) {\n\t\t\tcase '>':\n\t\t\t\treturn (\n\t\t\t\t\t(\n\t\t\t\t\t\tfieldValue,\n\t\t\t\t\t\tedgeValue,\n\t\t\t\t\t) => fieldValue > edgeValue\n\t\t\t\t);\n\t\t\tcase '<':\n\t\t\t\treturn (\n\t\t\t\t\t(\n\t\t\t\t\t\tfieldValue,\n\t\t\t\t\t\tedgeValue,\n\t\t\t\t\t) => fieldValue < edgeValue\n\t\t\t\t);\n\t\t\tcase '>=':\n\t\t\t\treturn (\n\t\t\t\t\t(\n\t\t\t\t\t\tfieldValue,\n\t\t\t\t\t\tedgeValue,\n\t\t\t\t\t) => fieldValue >= edgeValue\n\t\t\t\t);\n\t\t\tcase '<=':\n\t\t\t\treturn (\n\t\t\t\t\t(\n\t\t\t\t\t\tfieldValue,\n\t\t\t\t\t\tedgeValue,\n\t\t\t\t\t) => fieldValue <= edgeValue\n\t\t\t\t);\n\t\t}\n\t}\n\n\tpublic override clone (\n\t\tmodifyLeafNodeTuple: ModifyLeafNodeTupleFunction | undefined,\n\t): GreaterSmallerThanComparatorQueryNode<ItemTypeType> {\n\t\treturn new GreaterSmallerThanComparatorQueryNode(\n\t\t\tthis.columnId,\n\t\t\tthis.comparator,\n\t\t\tthis.valueTransformer,\n\t\t\tthis.errorHandler,\n\t\t)\n\t\t\t.copyEdgesFrom(\n\t\t\t\tthis,\n\t\t\t\tmodifyLeafNodeTuple,\n\t\t\t);\n\t}\n\n}\n","import { ApiFields, ApiItemType } from '@rentman/backend-types';\nimport { ApiQueryConditionComparator, ErrorHandlerInterface } from '../../internal';\nimport { ItemTypeColumnId } from '../../types/ItemTypesCollection';\nimport { ComparatorQueryNode } from './CompatorQueryNode';\nimport { GetField, MatchesAccumulator, ModifyLeafNodeTupleFunction, PositiveMatchingResult, QueryNode } from './QueryNode';\nimport { dateNullValueTransformer, durationValueTransformer, numberBooleanNullValueTransformer, stringNullValueTransformer, ValueTransformer } from './ValueTransformers';\n\nexport const isComparatorQueryNodeValueTransformers = [\n\tnumberBooleanNullValueTransformer,\n\tstringNullValueTransformer,\n\tdateNullValueTransformer,\n\tdurationValueTransformer,\n] as const satisfies ValueTransformer<any, any>[];\n\nexport class IsComparatorQueryNode<ItemTypeType extends ApiItemType>\n\textends ComparatorQueryNode<ItemTypeType, typeof isComparatorQueryNodeValueTransformers[number]> {\n\n\tpublic constructor (\n\t\tcolumnId: ItemTypeColumnId<ItemTypeType>,\n\t\tvalueTransformer: typeof isComparatorQueryNodeValueTransformers[number],\n\t\terrorHandler: ErrorHandlerInterface,\n\t) {\n\t\tsuper(\n\t\t\t`IS:${columnId as string}`,\n\t\t\tcolumnId,\n\t\t\tvalueTransformer,\n\t\t\terrorHandler,\n\t\t);\n\t}\n\n\tpublic static construct<ItemTypeType extends ApiItemType, ColumnId extends keyof ApiFields[ItemTypeType]> (\n\t\tkey: ApiQueryConditionComparator<ItemTypeType, ColumnId>['key'],\n\t\tvalue: ApiQueryConditionComparator<ItemTypeType, ColumnId>['value'],\n\t\tcomparator: ApiQueryConditionComparator<ItemTypeType, ColumnId>['comparator'],\n\t\terrorHandler: ErrorHandlerInterface,\n\t): IsComparatorQueryNode<ItemTypeType> | null {\n\t\tif (comparator !== '=') {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst valueTransformer = ComparatorQueryNode.findValueTransformer(\n\t\t\t\tvalue,\n\t\t\tisComparatorQueryNodeValueTransformers,\n\t\t);\n\n\t\tif (valueTransformer === null) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn new IsComparatorQueryNode(\n\t\t\tkey as ItemTypeColumnId<ItemTypeType>,\n\t\t\tvalueTransformer,\n\t\t\terrorHandler,\n\t\t);\n\t}\n\n\tpublic override match<MatchKeyType> (\n\t\tmatchKey: MatchKeyType,\n\t\tgetField: GetField<ItemTypeType>,\n\t\tparentMatch: PositiveMatchingResult,\n\t\tmatchesAccumulator: MatchesAccumulator<MatchKeyType>,\n\t): MatchesAccumulator<MatchKeyType> {\n\t\tconst fieldValue = getField(\n\t\t\tthis.columnId,\n\t\t);\n\n\t\tif (fieldValue === undefined) {\n\t\t\treturn this.matchUndefinedValue(\n\t\t\t\tmatchKey,\n\t\t\t\tgetField,\n\t\t\t\tmatchesAccumulator,\n\t\t\t);\n\t\t}\n\n\t\tconst queryNodeTuple = this.edgeMap.get(\n\t\t\t(this.valueTransformer as ValueTransformer<any, any>).fieldToEdgeValue(\n\t\t\t\tfieldValue,\n\t\t\t),\n\t\t);\n\n\t\tif (queryNodeTuple === undefined) {\n\t\t\treturn matchesAccumulator;\n\t\t}\n\n\t\treturn QueryNode.matchQueryNodes(\n\t\t\tqueryNodeTuple,\n\t\t\tmatchKey,\n\t\t\tgetField,\n\t\t\tparentMatch,\n\t\t\tmatchesAccumulator,\n\t\t);\n\t}\n\n\tpublic override clone (\n\t\tmodifyLeafNodeTuple: ModifyLeafNodeTupleFunction | undefined,\n\t): IsComparatorQueryNode<ItemTypeType> {\n\t\treturn new IsComparatorQueryNode(\n\t\t\tthis.columnId,\n\t\t\tthis.valueTransformer,\n\t\t\tthis.errorHandler,\n\t\t)\n\t\t\t.copyEdgesFrom(\n\t\t\t\tthis,\n\t\t\t\tmodifyLeafNodeTuple,\n\t\t\t);\n\t}\n\n}\n","import { ApiItemType } from '@rentman/backend-types';\nimport { ApiQuery, ApiQueryConditionLinkedTo } from '../../internal';\nimport { NonMatchableQueryNode } from './NonMatchableQueryNode';\nimport { ModifyLeafNodeTupleFunction } from './QueryNode';\n\nexport class LinkedToQueryNode<ItemTypeType extends ApiItemType>\n\textends NonMatchableQueryNode<ItemTypeType> {\n\n\tpublic declare apiQuery: ApiQueryConditionLinkedTo<any>;\n\n\tpublic override clone (\n\t\tmodifyLeafNodeTuple: ModifyLeafNodeTupleFunction | undefined,\n\t): LinkedToQueryNode<ItemTypeType> {\n\t\treturn new LinkedToQueryNode<ItemTypeType>(\n\t\t\tthis.apiQuery,\n\t\t)\n\t\t\t.copyEdgesFrom(\n\t\t\t\tthis,\n\t\t\t\tmodifyLeafNodeTuple,\n\t\t\t);\n\t}\n\n\tpublic constructor (\n\t\tapiQuery: ApiQueryConditionLinkedTo<any>,\n\t) {\n\t\tsuper(\n\t\t\t// TODO: Temporary token.\n\t\t\t'LI',\n\t\t\tapiQuery as ApiQuery<ItemTypeType>,\n\t\t);\n\t}\n\n}","import { ApiFields, ApiItemType } from '@rentman/backend-types';\nimport { ApiQueryConditionComparator, ErrorHandlerInterface } from '../../internal';\nimport { ItemTypeColumnId } from '../../types/ItemTypesCollection';\nimport { ComparatorQueryNode } from './CompatorQueryNode';\nimport { GetField, MatchesAccumulator, ModifyLeafNodeTupleFunction, PositiveMatchingResult, QueryNode } from './QueryNode';\nimport { dateNullValueTransformer, durationValueTransformer, numberBooleanNullValueTransformer, stringNullValueTransformer, ValueTransformer } from './ValueTransformers';\n\nconst valueTransformers = [\n\tnumberBooleanNullValueTransformer,\n\tstringNullValueTransformer,\n\tdateNullValueTransformer,\n\tdurationValueTransformer,\n] as const satisfies ValueTransformer<any, any>[];\n\nexport class NotIsComparatorQueryNode<ItemTypeType extends ApiItemType>\n\textends ComparatorQueryNode<ItemTypeType, typeof valueTransformers[number]> {\n\n\tpublic constructor (\n\t\tcolumnId: ItemTypeColumnId<ItemTypeType>,\n\t\tvalueTransformer: typeof valueTransformers[number],\n\t\terrorHandler: ErrorHandlerInterface,\n\t) {\n\t\tsuper(\n\t\t\t`!IS:${columnId as string}`,\n\t\t\tcolumnId,\n\t\t\tvalueTransformer,\n\t\t\terrorHandler,\n\t\t);\n\t}\n\n\tpublic static construct<ItemTypeType extends ApiItemType, ColumnId extends keyof ApiFields[ItemTypeType]> (\n\t\tkey: ApiQueryConditionComparator<ItemTypeType, ColumnId>['key'],\n\t\tvalue: ApiQueryConditionComparator<ItemTypeType, ColumnId>['value'],\n\t\tcomparator: ApiQueryConditionComparator<ItemTypeType, ColumnId>['comparator'],\n\t\terrorHandler: ErrorHandlerInterface,\n\t): NotIsComparatorQueryNode<ItemTypeType> | null {\n\t\tif (comparator !== '!=') {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst valueTransformer = ComparatorQueryNode.findValueTransformer(\n\t\t\tvalue,\n\t\t\tvalueTransformers,\n\t\t);\n\n\t\tif (valueTransformer === null) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn new NotIsComparatorQueryNode(\n\t\t\tkey as ItemTypeColumnId<ItemTypeType>,\n\t\t\tvalueTransformer,\n\t\t\terrorHandler,\n\t\t);\n\t}\n\n\tpublic override match<MatchKeyType> (\n\t\tmatchKey: MatchKeyType,\n\t\tgetField: GetField<ItemTypeType>,\n\t\tparentMatch: PositiveMatchingResult,\n\t\tmatchesAccumulator: MatchesAccumulator<MatchKeyType>,\n\t): MatchesAccumulator<MatchKeyType> {\n\t\tconst fieldValue = getField(\n\t\t\tthis.columnId,\n\t\t);\n\n\t\tif (fieldValue === undefined) {\n\t\t\treturn this.matchUndefinedValue(\n\t\t\t\tmatchKey,\n\t\t\t\tgetField,\n\t\t\t\tmatchesAccumulator,\n\t\t\t);\n\t\t}\n\n\t\tfor (const entry of this.edgeMap.entries()) {\n\t\t\tif (\n\t\t\t\t(this.valueTransformer as ValueTransformer<any, any>).fieldToEdgeValue(\n\t\t\t\t\tfieldValue,\n\t\t\t\t) === entry[0]\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tQueryNode.matchQueryNodes(\n\t\t\t\tentry[1],\n\t\t\t\tmatchKey,\n\t\t\t\tgetField,\n\t\t\t\tparentMatch,\n\t\t\t\tmatchesAccumulator,\n\t\t\t);\n\t\t}\n\n\t\treturn matchesAccumulator;\n\t}\n\n\tpublic override clone (\n\t\tmodifyLeafNodeTuple: ModifyLeafNodeTupleFunction | undefined,\n\t): NotIsComparatorQueryNode<ItemTypeType> {\n\t\treturn new NotIsComparatorQueryNode(\n\t\t\tthis.columnId,\n\t\t\tthis.valueTransformer,\n\t\t\tthis.errorHandler,\n\t\t)\n\t\t\t.copyEdgesFrom(\n\t\t\t\tthis,\n\t\t\t\tmodifyLeafNodeTuple,\n\t\t\t);\n\t}\n\n}\n","import { ApiItemType } from '@rentman/backend-types';\nimport { GetField, MatchesAccumulator, ModifyLeafNodeTupleFunction, QueryNode, QueryNodeTuple } from './QueryNode';\nimport { ValuelessEdgeQueryNode } from './ValuelessEdgeQueryNode';\n\nexport class RootQueryNode<ItemTypeType extends ApiItemType>\n\textends ValuelessEdgeQueryNode<ItemTypeType> {\n\n\tpublic constructor (\n\t\tconnectionNodesTuple?: QueryNodeTuple,\n\t) {\n\t\tsuper(\n\t\t\t'R',\n\t\t\tconnectionNodesTuple,\n\t\t);\n\t}\n\n\tpublic override clone (\n\t\tmodifyLeafNodeTuple: ModifyLeafNodeTupleFunction | undefined,\n\t): RootQueryNode<ItemTypeType> {\n\t\treturn new RootQueryNode<ItemTypeType>()\n\t\t\t.copyEdgesFrom(\n\t\t\t\tthis,\n\t\t\t\tmodifyLeafNodeTuple,\n\t\t\t);\n\t}\n\n\tpublic override match<MatchKeyType> (\n\t\tmatchKey: MatchKeyType,\n\t\tgetField: GetField<ItemTypeType>,\n\t\tparentMatch: true,\n\t\tmatchesAccumulator: MatchesAccumulator<MatchKeyType>,\n\t): MatchesAccumulator<MatchKeyType> {\n\t\treturn QueryNode.matchQueryNodes(\n\t\t\tthis.connectedNodesTuple,\n\t\t\tmatchKey,\n\t\t\tgetField,\n\t\t\tparentMatch,\n\t\t\tmatchesAccumulator,\n\t\t);\n\t}\n\n\t/**\n\t * Convenience method that sets a default value for `matchesAccumulator`.\n\t * @param matchKey - The value that is added to the `true` or `maybe` sets in `matchesAccumulator` when a match is\n\t * found.\n\t */\n\tpublic doMatch<MatchKeyType> (\n\t\tmatchKey: MatchKeyType,\n\t\tgetField: GetField<ItemTypeType>,\n\t\tmatchesAccumulator: MatchesAccumulator<MatchKeyType> = new Map(),\n\t): MatchesAccumulator<MatchKeyType> {\n\t\treturn QueryNode.matchQueryNodes(\n\t\t\tthis.connectedNodesTuple,\n\t\t\tmatchKey,\n\t\t\tgetField,\n\t\t\ttrue,\n\t\t\tmatchesAccumulator,\n\t\t);\n\t}\n\n}","import { ApiItemType, ApiQueryConditionSearch } from '@rentman/backend-types';\nimport { NonMatchableQueryNode } from './NonMatchableQueryNode';\nimport { ModifyLeafNodeTupleFunction } from './QueryNode';\n\nexport class SearchQueryNode<ItemTypeType extends ApiItemType>\n\textends NonMatchableQueryNode<ItemTypeType> {\n\n\tpublic constructor (\n\t\tapiQuery: ApiQueryConditionSearch,\n\t) {\n\t\tsuper(\n\t\t\t`SEARCH:${apiQuery.search}`,\n\t\t\tapiQuery,\n\t\t);\n\t}\n\n\tpublic declare apiQuery: ApiQueryConditionSearch;\n\n\tpublic override clone (\n\t\tmodifyLeafNodeTuple: ModifyLeafNodeTupleFunction | undefined,\n\t): SearchQueryNode<ItemTypeType> {\n\t\treturn new SearchQueryNode<ItemTypeType>(\n\t\t\tthis.apiQuery,\n\t\t)\n\t\t\t.copyEdgesFrom(\n\t\t\t\tthis,\n\t\t\t\tmodifyLeafNodeTuple,\n\t\t\t);\n\t}\n\n}","import { ApiItemType } from '@rentman/backend-types';\nimport { ApiQuery } from '../../types/ApiQuery';\nimport { NonMatchableQueryNode } from './NonMatchableQueryNode';\nimport { ModifyLeafNodeTupleFunction } from './QueryNode';\n\nexport class SubQueryNode<ItemTypeType extends ApiItemType>\n\textends NonMatchableQueryNode<ItemTypeType> {\n\n\tpublic constructor (\n\t\tapiQuery: ApiQuery<ItemTypeType>,\n\t) {\n\t\tsuper(\n\t\t\t// TODO: Temporary token.\n\t\t\t'SUB',\n\t\t\tapiQuery,\n\t\t);\n\t}\n\n\tpublic override clone (\n\t\tmodifyLeafNodeTuple: ModifyLeafNodeTupleFunction | undefined,\n\t): SubQueryNode<ItemTypeType> {\n\t\treturn new SubQueryNode(\n\t\t\tthis.apiQuery,\n\t\t)\n\t\t\t.copyEdgesFrom(\n\t\t\t\tthis,\n\t\t\t\tmodifyLeafNodeTuple,\n\t\t\t);\n\t}\n\n}","import { ApiFields, ApiItemType, ApiQueryConditionCustom, ApiQueryConditionSearch, ApiQueryOperator, ItemApiFields, ItemId } from '@rentman/backend-types';\nimport { LinkTreeServiceInterface } from '../../interfaces/LinkTreeServiceInterface';\nimport { ApiLinkTreeType, ApiQuery, ApiQueryConditionComparator, ApiQueryConditionIn, ApiQueryConditionLinkedTo, ApiQueryWithConditions, ErrorHandlerInterface, ItemTypeColumnId } from '../../internal';\nimport { QueryParserBase } from '../QueryParserBase';\nimport { ComparatorQueryNode } from './CompatorQueryNode';\nimport { CustomQueryNode } from './CustomQueryNode';\nimport { GreaterSmallerThanComparatorQueryNode } from './greater-smaller-than-comparator-query.node';\nimport { IsComparatorQueryNode, isComparatorQueryNodeValueTransformers } from './IsComparatorQueryNode';\nimport { LinkedToQueryNode } from './LinkedToQueryNode';\nimport { NotIsComparatorQueryNode } from './NotIsComparatorQueryNode';\nimport { LeafQueryNode, ModifyLeafNodeTupleFunction, QueryNode } from './QueryNode';\nimport { RootQueryNode } from './RootQueryNode';\nimport { SearchQueryNode } from './SearchQueryNode';\nimport { SubQueryNode } from './SubQueryNode';\nimport { numberBooleanNullValueTransformer, stringNullValueTransformer, unsupportedQueryValue } from './ValueTransformers';\n\n// Ordered by most common operator\nconst comparatorNodeClasses = [\n\tIsComparatorQueryNode,\n\tNotIsComparatorQueryNode,\n\tGreaterSmallerThanComparatorQueryNode,\n];\n\nexport class GraphQueryParser<ItemTypeType extends ApiItemType, QueryId extends LeafQueryNode>\n\textends QueryParserBase<RootQueryNode<ItemTypeType>, QueryNode<any>[] | QueryId | null> {\n\n\tpublic constructor (\n\t\tprivate itemType: ItemTypeType,\n\t\tprivate queryId: QueryId,\n\t\tprivate linkTreeService: LinkTreeServiceInterface,\n\t\tprivate errorHandler: ErrorHandlerInterface,\n\t) {\n\t\tsuper();\n\t}\n\n\t// We cannot use the global `ItemTypeType` generic here.\n\tpublic override run<QueryItemType extends ApiItemType> (\n\t\tquery: ApiQuery<QueryItemType>,\n\t): RootQueryNode<ItemTypeType> {\n\t\tconst rootNode = new RootQueryNode<ItemTypeType>();\n\t\tconst parsedQuery = this.parseQuery(\n\t\t\tquery,\n\t\t\t0,\n\t\t);\n\n\t\tif (parsedQuery === null) {\n\t\t\treturn rootNode;\n\t\t}\n\n\t\tif (parsedQuery === this.queryId) {\n\t\t\treturn rootNode.connectLeafNode(\n\t\t\t\tparsedQuery,\n\t\t\t);\n\t\t}\n\n\t\tfor (const node of (parsedQuery as QueryNode<ItemTypeType>[])) {\n\t\t\trootNode.connectBranchNode(\n\t\t\t\tnode,\n\t\t\t);\n\t\t}\n\n\t\treturn rootNode;\n\t}\n\n\tprotected override parseEmptyQuery (): QueryId {\n\t\treturn this.queryId;\n\t}\n\n\tpublic static createLinkedToComparatorQueryNode<MainItemType extends ApiItemType, SubItemType extends ApiItemType> (\n\t\tmainItemType: MainItemType,\n\t\tlinkedToItemType: SubItemType,\n\t\tleafNodeTuples: {\n\t\t\tvalue: ItemId,\n\t\t\tnode: LeafQueryNode,\n\t\t}[],\n\t\tlinkTreeService: LinkTreeServiceInterface,\n\t\terrorHandler: ErrorHandlerInterface,\n\t): ComparatorQueryNode<MainItemType, any> {\n\t\tconst linkTreeEntry = linkTreeService.get()[linkedToItemType][mainItemType];\n\n\t\tswitch (linkTreeEntry.type) {\n\t\t\tcase ApiLinkTreeType.DIRECT: {\n\t\t\t\tconst itemComparatorNode = new IsComparatorQueryNode<MainItemType>(\n\t\t\t\t\tlinkTreeEntry.field as ItemTypeColumnId<ApiItemType>,\n\t\t\t\t\tnumberBooleanNullValueTransformer,\n\t\t\t\t\terrorHandler,\n\t\t\t\t);\n\n\t\t\t\tfor (const leafNodeTuple of leafNodeTuples) {\n\t\t\t\t\titemComparatorNode.connectLeafNode(\n\t\t\t\t\t\tleafNodeTuple.value,\n\t\t\t\t\t\tleafNodeTuple.node,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn itemComparatorNode;\n\t\t\t}\n\n\t\t\tcase ApiLinkTreeType.ITEMTABLE: {\n\t\t\t\tconst itemComparatorNode = new IsComparatorQueryNode<MainItemType>(\n\t\t\t\t\t'item' as ItemTypeColumnId<MainItemType>,\n\t\t\t\t\tnumberBooleanNullValueTransformer,\n\t\t\t\t\terrorHandler,\n\t\t\t\t);\n\n\t\t\t\tfor (const leafNodeTuple of leafNodeTuples) {\n\t\t\t\t\titemComparatorNode.connectLeafNode(\n\t\t\t\t\t\tleafNodeTuple.value,\n\t\t\t\t\t\tleafNodeTuple.node,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn new IsComparatorQueryNode<MainItemType>(\n\t\t\t\t\t'itemtype' as ItemTypeColumnId<MainItemType>,\n\t\t\t\t\tstringNullValueTransformer,\n\t\t\t\t\terrorHandler,\n\n\t\t\t\t)\n\t\t\t\t\t.connectBranchNode(\n\t\t\t\t\t\tlinkedToItemType,\n\t\t\t\t\t\titemComparatorNode,\n\t\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected override parseComparatorQuery<SubItemType extends ApiItemType, ColumnId extends keyof ApiFields[SubItemType]> (\n\t\tkey: ApiQueryConditionComparator<SubItemType, ColumnId>['key'],\n\t\tvalue: ApiQueryConditionComparator<SubItemType, ColumnId>['value'],\n\t\tcomparator: ApiQueryConditionComparator<SubItemType, ColumnId>['comparator'],\n\t): [ComparatorQueryNode<SubItemType, any>] {\n\t\tlet queryNode: ComparatorQueryNode<SubItemType, any> | null = null;\n\n\t\tfor (const comparatorNodeClass of comparatorNodeClasses) {\n\t\t\tqueryNode = comparatorNodeClass.construct(\n\t\t\t\tkey,\n\t\t\t\tvalue,\n\t\t\t\tcomparator,\n\t\t\t\tthis.errorHandler,\n\t\t\t);\n\n\t\t\tif (queryNode !== null) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (queryNode === null) {\n\t\t\tthrow new Error(\n\t\t\t\t`Could not find supported comparator node: ${key as string}${comparator}${value} `,\n\t\t\t);\n\t\t}\n\n\t\treturn [\n\t\t\tqueryNode.connectLeafNode(\n\t\t\t\tvalue,\n\t\t\t\tthis.queryId,\n\t\t\t),\n\t\t];\n\t}\n\n\tprotected override parseInQuery<SubItemType extends ApiItemType, ColumnId extends keyof ApiFields[SubItemType]> (\n\t\tkey: ApiQueryConditionIn<SubItemType, ColumnId>['key'],\n\t\tvalues: ApiQueryConditionIn<SubItemType, ColumnId>['value'],\n\t\tnot: boolean,\n\t): [IsComparatorQueryNode<SubItemType> | NotIsComparatorQueryNode<SubItemType>] | QueryId | null {\n\t\tif (values.length === 0) {\n\t\t\treturn not\n\t\t\t\t? this.queryId\n\t\t\t\t: null;\n\t\t}\n\n\t\tconst valueTransformer = isComparatorQueryNodeValueTransformers.find(\n\t\t\tvalueTransformerCandidate => values.every(\n\t\t\t\tvalue => valueTransformerCandidate.queryToEdgeValue(\n\t\t\t\t\tvalue,\n\t\t\t\t) !== unsupportedQueryValue,\n\t\t\t),\n\t\t);\n\n\t\tif (valueTransformer === undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t`Could not find supported comparator node: ${key as string} ${values}`,\n\t\t\t);\n\t\t}\n\n\t\tif (!not) {\n\t\t\tconst comparatorQueryNode = new IsComparatorQueryNode<SubItemType>(\n\t\t\t\tkey,\n\t\t\t\tvalueTransformer,\n\t\t\t\tthis.errorHandler,\n\t\t\t);\n\n\t\t\tfor (const value of values) {\n\t\t\t\tcomparatorQueryNode.connectLeafNode(\n\t\t\t\t\tvalue,\n\t\t\t\t\tthis.queryId,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn [\n\t\t\t\tcomparatorQueryNode,\n\t\t\t];\n\t\t}\n\n\t\tconst rootNodeInstance = new NotIsComparatorQueryNode<SubItemType>(\n\t\t\tkey,\n\t\t\tvalueTransformer,\n\t\t\tthis.errorHandler,\n\t\t);\n\n\t\tlet branchNodeInstance: NotIsComparatorQueryNode<SubItemType> = rootNodeInstance;\n\n\t\tfor (let i = 0; i < values.length - 1; i++) {\n\t\t\tbranchNodeInstance.connectBranchNode(\n\t\t\t\tvalues[i],\n\t\t\t\tbranchNodeInstance = new NotIsComparatorQueryNode<SubItemType>(\n\t\t\t\t\tkey as ColumnId,\n\t\t\t\t\tvalueTransformer,\n\t\t\t\t\tthis.errorHandler,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\tbranchNodeInstance.connectLeafNode(\n\t\t\tvalues[values.length - 1],\n\t\t\tthis.queryId,\n\t\t);\n\n\t\treturn [\n\t\t\trootNodeInstance,\n\t\t];\n\t}\n\n\tprotected override parseLinkedToQuery<MainItemType extends ApiItemType, SubItemType extends ApiItemType> (\n\t\tlinkedTo: ApiQueryConditionLinkedTo<SubItemType>['linkedTo'],\n\t\tquery: Exclude<ApiQueryConditionLinkedTo<SubItemType>['query'], undefined>,\n\t\treverse: boolean,\n\t\tnot: boolean,\n\t\tsubQueryDepth: number,\n\t): QueryNode<MainItemType>[] | null {\n\t\tif (\n\t\t\treverse\n\t\t\t|| not\n\t\t) {\n\t\t\treturn [\n\t\t\t\tnew LinkedToQueryNode(\n\t\t\t\t\t{\n\t\t\t\t\t\tlinkedTo,\n\t\t\t\t\t\tquery,\n\t\t\t\t\t\treverse,\n\t\t\t\t\t\tnot,\n\t\t\t\t\t} as ApiQueryConditionLinkedTo<SubItemType>,\n\t\t\t\t)\n\t\t\t\t\t.connectLeafNode(\n\t\t\t\t\t\tthis.queryId,\n\t\t\t\t\t),\n\t\t\t];\n\t\t}\n\n\t\tconst parsedSubQuery = this.parseQuery(\n\t\t\tquery,\n\t\t\tsubQueryDepth + 1,\n\t\t);\n\n\t\tif (parsedSubQuery === null) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (\n\t\t\tparsedSubQuery !== this.queryId\n\t\t\t&& (parsedSubQuery as QueryNode<SubItemType>[]).length === 1\n\t\t\t&& (parsedSubQuery as QueryNode<SubItemType>[])[0].TOKEN === 'IS:id'\n\t\t) {\n\t\t\tconst itemIds = (parsedSubQuery[0] as IsComparatorQueryNode<SubItemType>).getValues() as number[];\n\n\t\t\treturn [\n\t\t\t\tGraphQueryParser.createLinkedToComparatorQueryNode(\n\t\t\t\t\t// TODO: We should add a `depth` parameter here so we now this is the query item type.\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n\t\t\t\t\tthis.itemType as ApiItemType as MainItemType,\n\t\t\t\t\tlinkedTo,\n\t\t\t\t\titemIds.map(\n\t\t\t\t\t\titemId => (\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tvalue: itemId,\n\t\t\t\t\t\t\t\tnode: this.queryId,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t\tthis.linkTreeService,\n\t\t\t\t\tthis.errorHandler,\n\t\t\t\t),\n\t\t\t];\n\t\t}\n\n\t\t// TODO: Implement rewriting to sub queries.\n\t\treturn [\n\t\t\tnew LinkedToQueryNode(\n\t\t\t\t{\n\t\t\t\t\tlinkedTo,\n\t\t\t\t\tquery,\n\t\t\t\t\treverse,\n\t\t\t\t\tnot,\n\t\t\t\t} as ApiQueryConditionLinkedTo<SubItemType>,\n\t\t\t)\n\t\t\t\t.connectLeafNode(\n\t\t\t\t\tthis.queryId,\n\t\t\t\t),\n\t\t];\n\t}\n\n\tprotected override parseSubQuery<\n\t\tMainItemType extends ApiItemType,\n\t\tSubItemType extends ApiItemType,\n\t> (\n\t\tkey: keyof ItemApiFields<MainItemType>,\n\t\titemType: SubItemType,\n\t\tfield: keyof ItemApiFields<SubItemType>,\n\t\tquery: ApiQuery<SubItemType>,\n\t\t// We're excluding `undefined` here.\n\t\tnot: boolean,\n\t): SubQueryNode<MainItemType>[] {\n\t\t// TODO: There are some subqueries we can match locally.\n\t\treturn [\n\t\t\tnew SubQueryNode(\n\t\t\t\t{\n\t\t\t\t\tkey,\n\t\t\t\t\titemType,\n\t\t\t\t\tfield,\n\t\t\t\t\tquery,\n\t\t\t\t\tnot,\n\t\t\t\t} as ApiQuery<MainItemType>,\n\t\t\t)\n\t\t\t\t.connectLeafNode(\n\t\t\t\t\tthis.queryId,\n\t\t\t\t),\n\t\t];\n\t}\n\n\tprotected override parseSearchQuery<SubItemType extends ApiItemType> (\n\t\tsearch: ApiQueryConditionSearch['search'],\n\t\tnot: boolean,\n\t): [SearchQueryNode<SubItemType>] {\n\t\treturn [\n\t\t\tnew SearchQueryNode(\n\t\t\t\t{\n\t\t\t\t\tsearch,\n\t\t\t\t\tnot,\n\t\t\t\t},\n\t\t\t)\n\t\t\t\t.connectLeafNode(\n\t\t\t\t\tthis.queryId,\n\t\t\t\t),\n\t\t];\n\t}\n\n\tprotected override parseCustomQuery<\n\t\tSubItemType extends ApiItemType,\n\t\tQueryType extends ApiQueryConditionCustom<SubItemType>\n\t> (\n\t\tcustom: QueryType['custom'],\n\t\tparameters: QueryType['parameters'],\n\t\tnot: boolean,\n\t): [CustomQueryNode<SubItemType>] {\n\t\treturn [\n\t\t\tnew CustomQueryNode<SubItemType>(\n\t\t\t\t{\n\t\t\t\t\tcustom,\n\t\t\t\t\tparameters,\n\t\t\t\t\tnot,\n\t\t\t\t} as QueryType,\n\t\t\t)\n\t\t\t\t.connectLeafNode(\n\t\t\t\t\tthis.queryId,\n\t\t\t\t),\n\t\t];\n\t}\n\n\tprotected override parseComplexQuery<SubItemType extends ApiItemType> (\n\t\tconditions: ApiQueryWithConditions<SubItemType>['conditions'],\n\t\toperator: Extract<ApiQueryOperator, 'AND' | 'OR'>,\n\t\tnot: boolean,\n\t\tsubQueryDepth: number,\n\t): QueryNode<SubItemType>[] | QueryId | null {\n\t\tif (not) {\n\t\t\t// We *can* implement this using De Morgan's laws, but it will be a lot of work given the current approach.\n\t\t\t// Also, it is currently not being used in the front-end.\n\t\t\tthrow new Error(\n\t\t\t\t'GraphQueryParser: \\'not\\' unsupported for complex queries. Please rewrite your query.',\n\t\t\t);\n\t\t}\n\n\t\tconst parsedConditions = conditions.map(\n\t\t\tcondition => this.parseQuery(\n\t\t\t\tcondition,\n\t\t\t\tsubQueryDepth,\n\t\t\t),\n\t\t);\n\n\t\tswitch (operator) {\n\t\t\tcase 'OR':\n\t\t\t\treturn this.rewriteOrConditions(\n\t\t\t\t\tparsedConditions,\n\t\t\t\t);\n\n\t\t\tcase 'AND': {\n\t\t\t\tconst rewrittenConditions = this.rewriteAndConditions<SubItemType>(\n\t\t\t\t\tparsedConditions,\n\t\t\t\t);\n\n\t\t\t\tif (\n\t\t\t\t\trewrittenConditions === null\n\t\t\t\t\t|| rewrittenConditions === this.queryId\n\t\t\t\t) {\n\t\t\t\t\treturn rewrittenConditions;\n\t\t\t\t}\n\n\t\t\t\t// Each condition can itself be an OR query, represented by an array of query nodes. We need to\n\t\t\t\t// distribute these conditions over the nodes we already have.\n\t\t\t\t// We declare an accumulator (initialized with the first condition). We then connect the nodes of each\n\t\t\t\t// subsequent condition to the ones in the accumulator.\n\t\t\t\tlet accumulator = (rewrittenConditions as QueryNode<SubItemType>[][])[0];\n\n\t\t\t\tfor (let i = 1; i < (rewrittenConditions as QueryNode<SubItemType>[][]).length; i++) {\n\t\t\t\t\tconst newAccumulator: QueryNode<SubItemType>[] = [];\n\n\t\t\t\t\tfor (const conditionNode of (rewrittenConditions as QueryNode<SubItemType>[][])[i]) {\n\t\t\t\t\t\tconst modifyLeafNodeTuple: ModifyLeafNodeTupleFunction = leafNodeTuple => {\n\t\t\t\t\t\t\tQueryNode.addBranchNode(\n\t\t\t\t\t\t\t\tleafNodeTuple,\n\t\t\t\t\t\t\t\tconditionNode.clone(\n\t\t\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\t\t) as QueryNode,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\t// We connect each node in the accumulator with the node in the parsed condition by replacing\n\t\t\t\t\t\t// the leaf node.\n\t\t\t\t\t\tfor (const accumulatorNode of accumulator) {\n\t\t\t\t\t\t\tnewAccumulator.push(\n\t\t\t\t\t\t\t\taccumulatorNode.clone(\n\t\t\t\t\t\t\t\t\tmodifyLeafNodeTuple,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\taccumulator = newAccumulator;\n\t\t\t\t}\n\n\t\t\t\treturn accumulator;\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected rewriteOrConditions<SubItemType extends ApiItemType> (\n\t\tparsedConditions: (QueryNode<SubItemType>[] | QueryId | null)[],\n\t): null | QueryId | QueryNode<SubItemType>[] {\n\t\t// Conditions that never match have no effect on the result of the query, we can safely filter them out.\n\t\tconst filteredConditions = parsedConditions.filter(\n\t\t\tparsedCondition => parsedCondition !== null,\n\t\t);\n\n\t\t// Empty OR queries never match.\n\t\tif (filteredConditions.length === 0) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// If we have a condition that always matches, the query will always match.\n\t\tif (\n\t\t\tfilteredConditions.some(\n\t\t\t\tparsedCondition => parsedCondition === this.queryId,\n\t\t\t)\n\t\t) {\n\t\t\treturn this.parseEmptyQuery();\n\t\t}\n\n\t\t// When a parsing method returns multiple query nodes, we can assume it is a disjunction, so we can safely call `flat()` here.\n\t\t// (A \\/ B) \\/ (C \\/ D) === A \\/ B \\/ C \\/ D\n\t\treturn (filteredConditions as QueryNode<SubItemType>[][]).flat();\n\t}\n\n\tprotected rewriteAndConditions<SubItemType extends ApiItemType> (\n\t\tparsedConditions: (QueryNode<SubItemType>[] | QueryId | null)[],\n\t): null | QueryId | QueryNode<SubItemType>[][] {\n\t\t// If we have a condition that never matches, the query will never match.\n\t\tif (\n\t\t\tparsedConditions.some(\n\t\t\t\tparsedCondition => parsedCondition === null,\n\t\t\t)\n\t\t) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Conditions that always match have no effect on the result of the query, we can safely filter them out.\n\t\tconst filteredConditions = (parsedConditions as (QueryNode<SubItemType>[] | QueryId)[]).filter(\n\t\t\tparsedCondition => parsedCondition !== this.queryId,\n\t\t) as QueryNode<SubItemType>[][];\n\n\t\t// Empty AND queries always match.\n\t\tif (filteredConditions.length === 0) {\n\t\t\treturn this.parseEmptyQuery();\n\t\t}\n\n\t\treturn filteredConditions;\n\t}\n\n}\n","import { ApiFields, ApiItemType, ApiQueryOperator, ItemApiFields } from '@rentman/backend-types';\nimport { ApiQuery, ApiQueryConditionComparator, ApiQueryConditionIn, ApiQueryConditionLinkedTo, ApiQueryWithConditions, ApiRequestColumn, ApiRequestColumnArray, LinkTreeServiceInterface, MutableApiRequestColumnArray, QueryParserBase } from '../internal';\n\nexport class QueryColumnExtractor<ItemTypeType extends ApiItemType>\n\t// The methods in this class can return columns of sub item types too.\n\textends QueryParserBase<ApiRequestColumnArray> {\n\n\tpublic constructor (\n\t\tprivate linkTreeService: LinkTreeServiceInterface,\n\t\tprivate itemType: ItemTypeType,\n\t) {\n\t\tsuper();\n\t}\n\n\tprotected override parseEmptyQuery (): ApiRequestColumnArray<ItemTypeType> {\n\t\treturn [];\n\t}\n\n\tprotected override parseSubQuery<\n\t\tMainItemType extends ApiItemType,\n\t\tSubItemType extends ApiItemType,\n\t> (\n\t\tkey: keyof ItemApiFields<MainItemType>,\n\t\titemType: SubItemType,\n\t\tfield: keyof ItemApiFields<SubItemType>,\n\t\tquery: ApiQuery<SubItemType>,\n\t\t_not: boolean,\n\t\tsubQueryDepth: number,\n\t): ApiRequestColumnArray<ItemTypeType> {\n\t\tif (\n\t\t\t// If the queried item type differs from the column item type, we cannot request derived columns.\n\t\t\t// The same applies when we're matching the ID column.\n\t\t\tkey === 'id'\n\t\t\t|| itemType !== undefined\n\t\t) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst subItemColumns = this.parseQuery(\n\t\t\tquery,\n\t\t\tsubQueryDepth + 1,\n\t\t) as ApiRequestColumnArray<SubItemType>;\n\n\t\t// If the column of the queried item type is not the 'id' column, add it.\n\t\tif (field !== 'id') {\n\t\t\t(subItemColumns as MutableApiRequestColumnArray<SubItemType>).push(\n\t\t\t\tfield as ApiRequestColumn<SubItemType>,\n\t\t\t);\n\t\t}\n\n\t\treturn [\n\t\t\t{\n\t\t\t\t[key]: subItemColumns,\n\t\t\t},\n\t\t] as ApiRequestColumnArray as ApiRequestColumnArray<ItemTypeType>;\n\t}\n\n\tprotected override parseSearchQuery (): ApiRequestColumnArray<ItemTypeType> {\n\t\treturn [];\n\t}\n\n\tprotected override parseCustomQuery (): ApiRequestColumnArray<ItemTypeType> {\n\t\treturn [];\n\t}\n\n\tprotected override parseComparatorQuery<QueryItemType extends ApiItemType, ColumnId extends keyof ApiFields[QueryItemType]> (\n\t\tkey: ApiQueryConditionComparator<QueryItemType, ColumnId>['key'],\n\t): ApiRequestColumnArray<QueryItemType> {\n\t\treturn [\n\t\t\tkey as ApiRequestColumn<QueryItemType>,\n\t\t];\n\t}\n\n\tprotected override parseInQuery<QueryItemType extends ApiItemType, ColumnId extends keyof ApiFields[QueryItemType]> (\n\t\tkey: ApiQueryConditionIn<QueryItemType, ColumnId>['key'],\n\t\t// [RM4-38080]- Error suppressed after TS 5.5 upgrade\n\t\t// eslint-disable-next-line @typescript-eslint/no-unused-vars\n\t\t_value: ApiQueryConditionIn<QueryItemType, ColumnId>['value'],\n\t): ApiRequestColumnArray {\n\t\treturn [\n\t\t\tkey,\n\t\t];\n\t}\n\n\tprotected override parseLinkedToQuery<SubItemType extends ApiItemType> (\n\t\tlinkedTo: ApiQueryConditionLinkedTo<SubItemType>['linkedTo'],\n\t\t_query: Exclude<ApiQueryConditionLinkedTo<SubItemType>['query'], undefined>,\n\t\t// We exclude `undefined` values here.\n\t\treverse: boolean,\n\t\t_not: boolean,\n\t\tsubQueryDepth: number,\n\t): ApiRequestColumnArray<ItemTypeType> {\n\t\tif (\n\t\t\t// A reverse link cannot be added to the primary itemType's request columns\n\t\t\treverse\n\t\t\t// If we're inside a nested query, the columns will no longer relate to item type of the global query.\n\t\t\t// In the future, we could pass a 'parent' column / item type here and collect derived columns.\n\t\t\t|| subQueryDepth > 0\n\t\t) {\n\t\t\treturn [];\n\t\t}\n\n\t\treturn this.linkTreeService.getColumnsFromLink(\n\t\t\tlinkedTo,\n\t\t\tthis.itemType,\n\t\t);\n\t}\n\n\tprotected override parseComplexQuery<QueryItemType extends ApiItemType> (\n\t\tconditions: ApiQueryWithConditions<QueryItemType>['conditions'],\n\t\t_operator: Extract<ApiQueryOperator, 'AND' | 'OR'>,\n\t\t_not: boolean,\n\t\tsubQueryDepth: number,\n\t): ApiRequestColumnArray<QueryItemType> {\n\t\treturn this.parseConditions(\n\t\t\tconditions,\n\t\t\tsubQueryDepth,\n\t\t);\n\t}\n\n\tprivate parseConditions<QueryItemType extends ApiItemType> (\n\t\tconditions: ApiQueryWithConditions<QueryItemType>['conditions'],\n\t\tsubQueryDepth: number,\n\t): ApiRequestColumnArray<QueryItemType> {\n\t\treturn conditions.reduce(\n\t\t\t(\n\t\t\t\taccumulator,\n\t\t\t\tcondition,\n\t\t\t) => accumulator.concat(\n\t\t\t\tthis.parseQuery(\n\t\t\t\t\tcondition,\n\t\t\t\t\tsubQueryDepth,\n\t\t\t\t) as ApiRequestColumnArray<QueryItemType>,\n\t\t\t),\n\t\t\t[] as ApiRequestColumnArray<QueryItemType>,\n\t\t);\n\t}\n\n}\n","import { ApiFields, ApiItemType, ApiQueryOperator, ItemApiFields } from '@rentman/backend-types';\nimport { ApiQuery, ApiQueryConditionComparator, ApiQueryConditionIn, ApiQueryConditionLinkedTo, ApiQueryWithConditions, KeyService, QueryParserBase } from '../internal';\n\ntype ReturnType = boolean;\n\nexport class QueryContainsLocalIdParser\n\textends QueryParserBase<ReturnType> {\n\n\tprotected override parseEmptyQuery (): ReturnType {\n\t\treturn false;\n\t}\n\n\tprotected override parseSubQuery<\n\t\tMainItemType extends ApiItemType,\n\t\tSubItemType extends ApiItemType,\n\t> (\n\t\t_key: keyof ItemApiFields<MainItemType>,\n\t\t_itemType: SubItemType,\n\t\t_field: keyof ItemApiFields<SubItemType>,\n\t\tquery: ApiQuery<SubItemType>,\n\t\t// We're excluding `undefined` here.\n\t\t_not: boolean,\n\t\tsubQueryDepth: number,\n\t): ReturnType {\n\t\treturn this.parseQuery(\n\t\t\tquery,\n\t\t\tsubQueryDepth + 1,\n\t\t);\n\t}\n\n\tprotected override parseSearchQuery (): ReturnType {\n\t\treturn false;\n\t}\n\n\tprotected override parseCustomQuery (): ReturnType {\n\t\treturn false;\n\t}\n\n\tprotected override parseComparatorQuery<ItemTypeType extends ApiItemType, ColumnId extends keyof ApiFields[ItemTypeType]> (\n\t\t_key: ApiQueryConditionComparator<ItemTypeType, ColumnId>['key'],\n\t\tvalue: ApiQueryConditionComparator<ItemTypeType, ColumnId>['value'],\n\t): ReturnType {\n\t\treturn KeyService.isLocalId(\n\t\t\tvalue,\n\t\t);\n\t}\n\n\tprotected override parseInQuery<ItemTypeType extends ApiItemType, ColumnId extends keyof ApiFields[ItemTypeType]> (\n\t\t_key: ApiQueryConditionIn<ItemTypeType, ColumnId>['key'],\n\t\tvalue: ApiQueryConditionIn<ItemTypeType, ColumnId>['value'],\n\t): ReturnType {\n\t\treturn value.some(\n\t\t\tval => KeyService.isLocalId(\n\t\t\t\tval,\n\t\t\t),\n\t\t);\n\t}\n\n\tprotected override parseLinkedToQuery<SubItemType extends ApiItemType> (\n\t\t_linkedTo: ApiQueryConditionLinkedTo<SubItemType>['linkedTo'],\n\t\tquery: Exclude<ApiQueryConditionLinkedTo<SubItemType>['query'], undefined>,\n\t\t// We exclude `undefined` values here.\n\t\t_reverse: boolean,\n\t\t_not: boolean,\n\t\tsubQueryDepth: number,\n\t): ReturnType {\n\t\treturn this.parseQuery(\n\t\t\tquery,\n\t\t\tsubQueryDepth + 1,\n\t\t);\n\t}\n\n\tprotected override parseComplexQuery<ItemTypeType extends ApiItemType> (\n\t\tconditions: ApiQueryWithConditions<ItemTypeType>['conditions'],\n\t\t_operator: Extract<ApiQueryOperator, 'AND' | 'OR'>,\n\t\t_not: boolean,\n\t\tsubQueryDepth: number,\n\t): ReturnType {\n\t\treturn conditions.some(\n\t\t\tcondition => this.parseQuery(\n\t\t\t\tcondition,\n\t\t\t\tsubQueryDepth,\n\t\t\t),\n\t\t);\n\t}\n\n}\n","import { ApiFields, ApiItemType, ApiQueryConditionCustom, ApiQueryConditionSearch, ApiQueryOperator, ItemApiFields } from '@rentman/backend-types';\nimport moment from 'moment';\nimport { ApiQuery, ApiQueryConditionComparator, ApiQueryConditionIn, ApiQueryConditionLinkedTo, ApiQueryWithConditions, CollectionQuery, QueryParserBase } from '../internal';\n\nconst SEPARATOR = ':';\n\ntype QueryValueType = number | boolean | string | number[] | boolean[] | string[] | moment.Moment | moment.Duration;\n\nexport class QueryParser\n\textends QueryParserBase<CollectionQuery<any>> {\n\n\tprivate static formatStringParameters (\n\t\t...parameters: (string | boolean)[]\n\t): string {\n\t\treturn '['\n\t\t\t+ parameters.join(\n\t\t\t\tSEPARATOR,\n\t\t\t)\n\t\t\t+ ']';\n\t}\n\n\tprivate static formatValue<T> (\n\t\tvalue: T,\n\t): {\n\t\tobject: T,\n\t\tstring: string,\n\t} {\n\t\tconst processedValue = this.processValue(\n\t\t\tvalue,\n\t\t);\n\n\t\treturn {\n\t\t\tobject: processedValue,\n\t\t\tstring: '' + processedValue,\n\t\t};\n\t}\n\n\tprivate static processValue<T> (value: T[]): T[];\n\n\tprivate static processValue (value: moment.Moment): moment.Moment;\n\n\tprivate static processValue (value: moment.Duration): moment.Duration;\n\n\tprivate static processValue<T> (value: T): T;\n\n\tprivate static processValue (\n\t\tvalue: QueryValueType,\n\t): QueryValueType {\n\t\t// algorithm is not important, as long as all arrays are sorted the same way\n\t\tif (\n\t\t\tArray.isArray(\n\t\t\t\tvalue,\n\t\t\t)\n\t\t) {\n\t\t\treturn value\n\t\t\t\t.slice()\n\t\t\t\t.sort();\n\t\t}\n\n\t\tif (\n\t\t\tmoment.isMoment(\n\t\t\t\tvalue,\n\t\t\t)\n\t\t) {\n\t\t\treturn moment(\n\t\t\t\tvalue,\n\t\t\t);\n\t\t}\n\n\t\tif (\n\t\t\tmoment.isDuration(\n\t\t\t\tvalue,\n\t\t\t)\n\t\t) {\n\t\t\treturn moment.duration(\n\t\t\t\tvalue,\n\t\t\t);\n\t\t}\n\n\t\treturn value;\n\t}\n\n\tprivate static compareParsedQueries<ItemTypeType extends ApiItemType> (\n\t\ta: CollectionQuery<ItemTypeType>,\n\t\tb: CollectionQuery<ItemTypeType>,\n\t): -1 | 0 | 1 {\n\t\tif (a.string === b.string) {\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn a.string > b.string ? 1 : -1;\n\t}\n\n\tprotected override parseEmptyQuery (): CollectionQuery<ApiItemType> {\n\t\treturn {\n\t\t\tobject: {},\n\t\t\tstring: '{}',\n\t\t\tisLocallyMatchable: true,\n\t\t};\n\t}\n\n\tprotected override parseSubQuery<\n\t\tMainItemType extends ApiItemType,\n\t\tSubItemType extends ApiItemType,\n\t> (\n\t\tkey: keyof ItemApiFields<MainItemType>,\n\t\titemType: SubItemType,\n\t\tfield: keyof ItemApiFields<SubItemType>,\n\t\tquery: ApiQuery<SubItemType>,\n\t\t// We're excluding `undefined` here.\n\t\tnot: boolean,\n\t\tsubQueryDepth: number,\n\t): CollectionQuery<MainItemType> {\n\t\tconst parsedQuery = this.parseQuery(\n\t\t\tquery,\n\t\t\tsubQueryDepth + 1,\n\t\t);\n\n\t\treturn {\n\t\t\tobject: {\n\t\t\t\tkey,\n\t\t\t\titemType,\n\t\t\t\tfield,\n\t\t\t\tquery: parsedQuery.object,\n\t\t\t\tnot,\n\t\t\t} as ApiQuery<MainItemType>,\n\t\t\tstring: QueryParser.formatStringParameters(\n\t\t\t\t'subField',\n\t\t\t\tkey as string,\n\t\t\t\titemType ?? '',\n\t\t\t\tfield as string,\n\t\t\t\tparsedQuery.string,\n\t\t\t\tnot,\n\t\t\t),\n\t\t\tisLocallyMatchable: false,\n\t\t};\n\t}\n\n\tprotected override parseSearchQuery<ItemTypeType extends ApiItemType> (\n\t\tvalue: ApiQueryConditionSearch['search'],\n\t\tnot: boolean,\n\t): CollectionQuery<ItemTypeType> {\n\t\tconst formattedValue = QueryParser.formatValue(\n\t\t\tvalue,\n\t\t);\n\n\t\treturn {\n\t\t\tobject: {\n\t\t\t\tsearch: formattedValue.object,\n\t\t\t\tnot,\n\t\t\t},\n\t\t\tstring: QueryParser.formatStringParameters(\n\t\t\t\t'search',\n\t\t\t\tformattedValue.string,\n\t\t\t\tnot,\n\t\t\t),\n\t\t\tisLocallyMatchable: false,\n\t\t};\n\t}\n\n\tprotected override parseCustomQuery<\n\t\tItemTypeType extends ApiItemType,\n\t\tQueryType extends ApiQueryConditionCustom<ItemTypeType>,\n\t> (\n\t\tcustom: QueryType['custom'],\n\t\tparameters: QueryType['parameters'],\n\t\tnot: boolean,\n\t): CollectionQuery<ItemTypeType> {\n\t\tif (parameters === undefined) {\n\t\t\treturn {\n\t\t\t\tobject: {\n\t\t\t\t\tcustom,\n\t\t\t\t\tnot,\n\t\t\t\t} as QueryType,\n\t\t\t\tstring: QueryParser.formatStringParameters(\n\t\t\t\t\tcustom,\n\t\t\t\t\tnot,\n\t\t\t\t),\n\t\t\t\tisLocallyMatchable: false,\n\t\t\t};\n\t\t}\n\n\t\tconst parsedParameters = this.parseCustomParameters(\n\t\t\tparameters,\n\t\t);\n\n\t\treturn {\n\t\t\tobject: {\n\t\t\t\tcustom,\n\t\t\t\tparameters: parsedParameters.object,\n\t\t\t\tnot,\n\t\t\t} as ApiQueryConditionCustom<any> as QueryType,\n\t\t\tstring: QueryParser.formatStringParameters(\n\t\t\t\tcustom,\n\t\t\t\tparsedParameters.string,\n\t\t\t\tnot,\n\t\t\t),\n\t\t\tisLocallyMatchable: false,\n\t\t};\n\t}\n\n\tprotected override parseComparatorQuery<ItemTypeType extends ApiItemType, ColumnId extends keyof ApiFields[ItemTypeType]> (\n\t\tkey: ApiQueryConditionComparator<ItemTypeType, ColumnId>['key'],\n\t\tvalue: ApiQueryConditionComparator<ItemTypeType, ColumnId>['value'],\n\t\tcomparator: ApiQueryConditionComparator<ItemTypeType, ColumnId>['comparator'],\n\t): CollectionQuery<ItemTypeType> {\n\t\tconst formattedValue = QueryParser.formatValue(\n\t\t\tvalue,\n\t\t);\n\n\t\treturn {\n\t\t\tobject: {\n\t\t\t\tkey: key,\n\t\t\t\tvalue: formattedValue.object,\n\t\t\t\tcomparator: comparator,\n\t\t\t} as ApiQueryConditionComparator<ItemTypeType, ColumnId>,\n\t\t\tstring: QueryParser.formatStringParameters(\n\t\t\t\tcomparator,\n\t\t\t\tkey as string,\n\t\t\t\tformattedValue.string,\n\t\t\t),\n\t\t\tisLocallyMatchable: true,\n\t\t};\n\t}\n\n\tprotected override parseInQuery<ItemTypeType extends ApiItemType, ColumnId extends keyof ApiFields[ItemTypeType]> (\n\t\tkey: ApiQueryConditionIn<ItemTypeType, ColumnId>['key'],\n\t\tvalue: ApiQueryConditionIn<ItemTypeType, ColumnId>['value'],\n\t\tnot: boolean,\n\t): CollectionQuery<ItemTypeType> {\n\t\tconst formattedValue = QueryParser.formatValue(\n\t\t\tvalue,\n\t\t);\n\n\t\treturn {\n\t\t\tobject: {\n\t\t\t\tkey,\n\t\t\t\tvalue: formattedValue.object,\n\t\t\t\tcomparator: 'IN',\n\t\t\t\tnot: not,\n\t\t\t} as ApiQueryConditionIn<ItemTypeType, ColumnId>,\n\t\t\tstring: QueryParser.formatStringParameters(\n\t\t\t\t'IN',\n\t\t\t\tkey as string,\n\t\t\t\tformattedValue.string,\n\t\t\t\tnot,\n\t\t\t),\n\t\t\tisLocallyMatchable: true,\n\t\t};\n\t}\n\n\tprotected override parseLinkedToQuery<MainItemType extends ApiItemType, SubItemType extends ApiItemType> (\n\t\tlinkedTo: ApiQueryConditionLinkedTo<SubItemType>['linkedTo'],\n\t\tquery: Exclude<ApiQueryConditionLinkedTo<SubItemType>['query'], undefined>,\n\t\treverse: boolean,\n\t\tnot: boolean,\n\t\tsubQueryDepth: number,\n\t): CollectionQuery<MainItemType> {\n\t\tconst parsedQuery = this.parseQuery(\n\t\t\tquery,\n\t\t\tsubQueryDepth + 1,\n\t\t);\n\n\t\treturn {\n\t\t\tobject: {\n\t\t\t\tlinkedTo: linkedTo,\n\t\t\t\tquery: parsedQuery.object,\n\t\t\t\treverse: reverse,\n\t\t\t\tnot: not,\n\t\t\t} as ApiQuery<MainItemType>,\n\t\t\tstring: QueryParser.formatStringParameters(\n\t\t\t\t'linkedTo',\n\t\t\t\tlinkedTo,\n\t\t\t\tparsedQuery.string,\n\t\t\t\treverse,\n\t\t\t\tnot,\n\t\t\t),\n\t\t\tisLocallyMatchable: !reverse,\n\t\t};\n\t}\n\n\tprotected override parseComplexQuery<ItemTypeType extends ApiItemType> (\n\t\tconditions: ApiQueryWithConditions<ItemTypeType>['conditions'],\n\t\toperator: Extract<ApiQueryOperator, 'AND' | 'OR'>,\n\t\tnot: boolean,\n\t\tsubQueryDepth: number,\n\t): CollectionQuery<ItemTypeType> {\n\t\tconst parsedConditions = this.parseConditions(\n\t\t\tconditions,\n\t\t\tsubQueryDepth,\n\t\t);\n\n\t\treturn {\n\t\t\tobject: {\n\t\t\t\tconditions: parsedConditions.object,\n\t\t\t\toperator,\n\t\t\t\tnot,\n\t\t\t},\n\t\t\tstring: QueryParser.formatStringParameters(\n\t\t\t\toperator,\n\t\t\t\tparsedConditions.string,\n\t\t\t\tnot,\n\t\t\t),\n\t\t\tisLocallyMatchable: parsedConditions.isLocallyMatchable,\n\t\t};\n\t}\n\n\tprivate parseCustomParameters<\n\t\tItemTypeType extends ApiItemType,\n\t\tQueryType extends ApiQueryConditionCustom<ItemTypeType>\n\t> (\n\t\tparameters: QueryType['parameters'],\n\t): {\n\t\tobject: QueryType,\n\t\tstring: string,\n\t} {\n\t\tconst keys = Object\n\t\t\t.keys(\n\t\t\t\tparameters,\n\t\t\t)\n\t\t\t.sort();\n\n\t\tconst query = {};\n\t\tlet string = '';\n\n\t\tfor (let i = 0; i < keys.length; i++) {\n\t\t\tconst key = keys[i];\n\t\t\tconst value = QueryParser.formatValue(\n\t\t\t\tparameters[key],\n\t\t\t);\n\n\t\t\tquery[key] = value.object;\n\n\t\t\tif (i > 0) {\n\t\t\t\tstring += SEPARATOR;\n\t\t\t}\n\n\t\t\tstring += value.string;\n\t\t}\n\n\t\treturn {\n\t\t\tobject: query as QueryType,\n\t\t\tstring,\n\t\t};\n\t}\n\n\tprivate parseConditions<ItemTypeType extends ApiItemType> (\n\t\tconditions: ApiQueryWithConditions<ItemTypeType>['conditions'],\n\t\tsubQueryDepth: number,\n\t): {\n\t\tobject: ApiQuery<ItemTypeType>[],\n\t\tstring: string,\n\t\tisLocallyMatchable: boolean,\n\t} {\n\t\tconst parsedConditions: CollectionQuery<ItemTypeType>[] = [];\n\n\t\tfor (const condition of conditions) {\n\t\t\tparsedConditions.push(\n\t\t\t\tthis.parseQuery(\n\t\t\t\t\tcondition,\n\t\t\t\t\tsubQueryDepth,\n\t\t\t\t) as CollectionQuery<ItemTypeType>,\n\t\t\t);\n\t\t}\n\n\t\tparsedConditions.sort(\n\t\t\t(\n\t\t\t\ta,\n\t\t\t\tb,\n\t\t\t) => QueryParser.compareParsedQueries(\n\t\t\t\ta,\n\t\t\t\tb,\n\t\t\t),\n\t\t);\n\n\t\tconst query: ApiQuery<ItemTypeType>[] = [];\n\t\tlet string: string = '';\n\t\tlet isLocallyMatchable: boolean = true;\n\n\t\tfor (const parsedCondition of parsedConditions) {\n\t\t\tquery.push(\n\t\t\t\tparsedCondition.object,\n\t\t\t);\n\t\t\tstring += parsedCondition.string;\n\t\t\tisLocallyMatchable = isLocallyMatchable\n\t\t\t\t&& parsedCondition.isLocallyMatchable;\n\t\t}\n\n\t\treturn {\n\t\t\tobject: query,\n\t\t\tstring,\n\t\t\tisLocallyMatchable,\n\t\t};\n\t}\n\n}\n","import { ApiFields, ApiItemType, ApiQueryOperator, ItemApiFields } from '@rentman/backend-types';\nimport { ApiQuery, ApiQueryConditionComparator, ApiQueryConditionIn, ApiQueryConditionLinkedTo, ApiQueryWithConditions, ItemIdConversionMap, QueryParserBase } from '../internal';\n\ntype ReturnType = boolean;\n\nexport class QueryParserIdUpdater\n\textends QueryParserBase<ReturnType> {\n\n\tpublic constructor (\n\t\tprivate itemIdConversionMap: ItemIdConversionMap,\n\t) {\n\t\tsuper();\n\t}\n\n\tprotected override parseEmptyQuery (): ReturnType {\n\t\treturn false;\n\t}\n\n\tprotected override parseSubQuery<\n\t\tMainItemType extends ApiItemType,\n\t\tSubItemType extends ApiItemType,\n\t> (\n\t\t_key: keyof ItemApiFields<MainItemType>,\n\t\t_itemType: SubItemType,\n\t\t_field: keyof ItemApiFields<SubItemType>,\n\t\tquery: ApiQuery<SubItemType>,\n\t\t// We're excluding `undefined` here.\n\t\t_not: boolean,\n\t\tsubQueryDepth: number,\n\t): ReturnType {\n\t\treturn this.parseQuery(\n\t\t\tquery as ApiQuery<ApiItemType>,\n\t\t\tsubQueryDepth + 1,\n\t\t);\n\t}\n\n\tprotected override parseSearchQuery (): ReturnType {\n\t\treturn false;\n\t}\n\n\tprotected override parseCustomQuery (): ReturnType {\n\t\treturn false;\n\t}\n\n\tprotected override parseComparatorQuery<ItemTypeType extends ApiItemType, ColumnId extends keyof ApiFields[ItemTypeType]> (\n\t\t_key: ApiQueryConditionComparator<ItemTypeType, ColumnId>['key'],\n\t\tvalue: ApiQueryConditionComparator<ItemTypeType, ColumnId>['value'],\n\t\t_comparator: ApiQueryConditionComparator<ItemTypeType, ColumnId>['comparator'],\n\t\tqueryPart: ApiQueryConditionComparator<ItemTypeType, ColumnId>,\n\t): ReturnType {\n\t\tfor (const itemType in this.itemIdConversionMap) {\n\t\t\t// @ts-ignore\n\t\t\tif (this.itemIdConversionMap[itemType][value] !== undefined) {\n\t\t\t\t// @ts-ignore\n\t\t\t\tqueryPart.value = this.itemIdConversionMap[itemType][value];\n\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tprotected override parseInQuery<ItemTypeType extends ApiItemType, ColumnId extends keyof ApiFields[ItemTypeType]> (\n\t\t_key: ApiQueryConditionIn<ItemTypeType, ColumnId>['key'],\n\t\tvalue: ApiQueryConditionIn<ItemTypeType, ColumnId>['value'],\n\t\t// eslint-disable-next-line @typescript-eslint/no-unused-vars\n\t\t_not: boolean,\n\t): ReturnType {\n\t\tlet result: boolean = false;\n\n\t\t// For an `in` we have to check every element in the array\n\t\tfor (let i = 0; i < value.length; i++) {\n\t\t\tfor (const itemType in this.itemIdConversionMap) {\n\t\t\t\tconst newItemId = this.itemIdConversionMap[itemType][value[i] as number];\n\n\t\t\t\tif (newItemId !== undefined) {\n\t\t\t\t\tvalue[i] = newItemId;\n\n\t\t\t\t\tresult = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprotected override parseLinkedToQuery<SubItemType extends ApiItemType> (\n\t\t_linkedTo: ApiQueryConditionLinkedTo<SubItemType>['linkedTo'],\n\t\tquery: Exclude<ApiQueryConditionLinkedTo<SubItemType>['query'], undefined>,\n\t\t// We exclude `undefined` values here.\n\t\t_reverse: boolean,\n\t\t_not: boolean,\n\t\tsubQueryDepth: number,\n\t): ReturnType {\n\t\treturn this.parseQuery(\n\t\t\tquery,\n\t\t\tsubQueryDepth + 1,\n\t\t);\n\t}\n\n\tprotected override parseComplexQuery<ItemTypeType extends ApiItemType> (\n\t\tconditions: ApiQueryWithConditions<ItemTypeType>['conditions'],\n\t\t_operator: Extract<ApiQueryOperator, 'AND' | 'OR'>,\n\t\t_not: boolean,\n\t\tsubQueryDepth: number,\n\t): ReturnType {\n\t\treturn conditions\n\t\t\t.map(\n\t\t\t\tcondition => this.parseQuery(\n\t\t\t\t\tcondition,\n\t\t\t\t\tsubQueryDepth,\n\t\t\t\t),\n\t\t\t)\n\t\t\t.some(\n\t\t\t\tres => res,\n\t\t\t);\n\t}\n\n}\n","import { ApiItemType, ItemId } from '@rentman/backend-types';\nimport { ApiQuery, ApiQueryConditionIn, EntryParentNull, QueryContainsLocalIdParser } from '../internal';\n\nexport class QueryService {\n\n\tpublic containsLocalId<ItemTypeType extends ApiItemType> (\n\t\tquery: ApiQuery<ItemTypeType>,\n\t): boolean {\n\t\treturn new QueryContainsLocalIdParser()\n\t\t\t.run(\n\t\t\t\tquery,\n\t\t\t);\n\t}\n\n\tpublic addAndCondition<ItemTypeType extends ApiItemType> (\n\t\tquery: ApiQuery<ItemTypeType>,\n\t\tcondition: ApiQuery<ItemTypeType>,\n\t): ApiQuery<ItemTypeType> {\n\t\tif (\n\t\t\tthis.isEmptyQuery(\n\t\t\t\tquery,\n\t\t\t)\n\t\t) {\n\t\t\treturn condition;\n\t\t}\n\n\t\tif (\n\t\t\tthis.isEmptyQuery(\n\t\t\t\tcondition,\n\t\t\t)\n\t\t) {\n\t\t\treturn query;\n\t\t}\n\n\t\tif (!('conditions' in query) || query.operator === 'or') {\n\t\t\treturn {\n\t\t\t\tconditions: [\n\t\t\t\t\tquery,\n\t\t\t\t\tcondition,\n\t\t\t\t],\n\t\t\t};\n\t\t}\n\n\t\t// we have an 'and' condition\n\t\treturn {\n\t\t\tconditions: query.conditions!.concat(\n\t\t\t\tcondition,\n\t\t\t),\n\t\t};\n\t}\n\n\tpublic addOrCondition<ItemTypeType extends ApiItemType> (\n\t\tquery: ApiQuery<ItemTypeType>,\n\t\tcondition: ApiQuery<ItemTypeType>,\n\t): ApiQuery<ItemTypeType> {\n\t\tif (\n\t\t\tthis.isEmptyQuery(\n\t\t\t\tquery,\n\t\t\t)\n\t\t) {\n\t\t\treturn query;\n\t\t}\n\n\t\tif (\n\t\t\tthis.isEmptyQuery(\n\t\t\t\tcondition,\n\t\t\t)\n\t\t) {\n\t\t\treturn condition;\n\t\t}\n\n\t\tif ('conditions' in query && query.operator === 'or') {\n\t\t\treturn {\n\t\t\t\tconditions: query.conditions.concat(\n\t\t\t\t\tcondition,\n\t\t\t\t),\n\t\t\t\toperator: 'or',\n\t\t\t};\n\t\t}\n\n\t\t// we have an 'and' condition\n\t\treturn {\n\t\t\tconditions: [\n\t\t\t\tquery,\n\t\t\t\tcondition,\n\t\t\t],\n\t\t\toperator: 'or',\n\t\t};\n\t}\n\n\tpublic addParentCondition<ItemTypeType extends ApiItemType> (\n\t\tquery: ApiQuery<ItemTypeType>,\n\t\tparent: EntryParentNull,\n\t): ApiQuery<ItemTypeType> {\n\t\tif (parent === null) {\n\t\t\treturn query;\n\t\t}\n\n\t\tconst linkedToQuery = {\n\t\t\tlinkedTo: parent.itemType,\n\t\t\tquery: {\n\t\t\t\tid: parent.itemId,\n\t\t\t},\n\t\t};\n\n\t\treturn query === null\n\t\t\t? linkedToQuery\n\t\t\t: this.addAndCondition(\n\t\t\t\tquery,\n\t\t\t\tlinkedToQuery,\n\t\t\t);\n\t}\n\n\tpublic createNotIn<ItemTypeType extends ApiItemType> (\n\t\tidArray: ItemId[],\n\t): ApiQuery<ItemTypeType> {\n\t\treturn {\n\t\t\tcomparator: 'IN',\n\t\t\tkey: 'id',\n\t\t\tvalue: idArray,\n\t\t\tnot: true,\n\t\t} as ApiQueryConditionIn<ItemTypeType, 'id'>;\n\t}\n\n\tpublic isEmptyQuery<ItemTypeType extends ApiItemType> (\n\t\tquery: ApiQuery<ItemTypeType>,\n\t): boolean {\n\t\tfor (const _key in query) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n}\n","import { ApiItemType } from '@rentman/backend-types';\nimport { ApiRequestColumnMap, ApiRequestColumns, ColumnSet, ColumnUtil, MutableApiRequestColumnArray, RequestColumnsTuple } from '../internal';\n\nexport class RequestColumnExpansion {\n\n\tprivate columns: ApiRequestColumnMap = {};\n\n\tprivate columnSetIdMap: {\n\t\t[columnSetId: number]: true | undefined,\n\t} = {};\n\n\tprivate requestColumnSetIdMap: {\n\t\t[requestColumnSetId: string]: true | undefined,\n\t} = {};\n\n\tpublic expandWithRequestColumnsTuple (\n\t\titemType: ApiItemType,\n\t\trequestColumnsTuple: RequestColumnsTuple,\n\t): void {\n\t\tif (this.requestColumnSetIdMap[requestColumnsTuple.string] === true) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.expandWithRequestColumns(\n\t\t\titemType,\n\t\t\trequestColumnsTuple.object,\n\t\t);\n\n\t\tthis.requestColumnSetIdMap[requestColumnsTuple.string] = true;\n\t}\n\n\tpublic expandWithColumnSet (\n\t\tcolumnSet: ColumnSet<any>,\n\t): void {\n\t\tif (this.columnSetIdMap[columnSet.id] === true) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.expandWithRequestColumns(\n\t\t\tcolumnSet.itemType,\n\t\t\tcolumnSet.request,\n\t\t);\n\n\t\tthis.columnSetIdMap[columnSet.id] = true;\n\t}\n\n\tpublic expandWithRequestColumns<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\trequestColumns: ApiRequestColumns<ItemTypeType>,\n\t): void {\n\t\tconst columns = this.columns;\n\n\t\tif (columns[itemType] === true) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (requestColumns === true) {\n\t\t\t// Don't overwrite the request columns with true if we have derived columns. Columns: true does not\n\t\t\t// return the derived columns that we need in the request so we have to make sure we get all the required\n\t\t\t// columns without using true.\n\t\t\t// FIXME: When a collection has been requested with columns: true before a request for the same item type with\n\t\t\t// derived columns the new item might be missing columns that are needed for the collection that asked for\n\t\t\t// columns: true.\n\t\t\tconst itemTypeColumns = columns[itemType];\n\n\t\t\t// @ts-expect-error Ignored after Typescript 5.5 upgrade\n\t\t\tif (itemTypeColumns === true) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\titemTypeColumns === undefined\n\t\t\t\t|| !ColumnUtil.containsDerivedColumns(\n\t\t\t\t\titemTypeColumns,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\t// @ts-ignore TS is complaining\n\t\t\t\tcolumns[itemType] = true;\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (columns[itemType] === undefined) {\n\t\t\tcolumns[itemType] = [];\n\t\t}\n\n\t\tfor (const column of requestColumns) {\n\t\t\tColumnUtil.mergeRequestColumn(\n\t\t\t\tcolumn,\n\t\t\t\tcolumns[itemType] as MutableApiRequestColumnArray<ItemTypeType>,\n\t\t\t);\n\t\t}\n\t}\n\n\tpublic get (): ApiRequestColumnMap {\n\t\treturn this.columns;\n\t}\n\n}\n","import { ApiItemType, ItemId } from '@rentman/backend-types';\nimport { UnknownResponseColumn } from '@rentman/backend-types/dist/manual/api-response-column';\nimport { ActiveItemEntries, ApiFormatter, ApiRequestService, CachedQueryItem, ChangesDelta, ChangesDeltaFactory, ChangesDeltaItemUpdateMode, ChangesDeltaResult, CollectionResource, ColumnCache, ColumnUtil, ErrorHandlerInterface, FieldMap, ItemEntry, ItemTypeColumnId, ItemTypeColumnIds, RequestBufferManager, RequestBufferResult, RequestColumnExpansion, RequestColumnExpansionFactory, RequestColumnsOperationsCacheFactory, ResponseColumnItemTypeMap, ResponseColumnMap, SocketMessage, SocketMessageDelete, SocketMessageValuesTuple, TransactionCacheFactory } from '../internal';\nimport { MatchesAccumulator } from './matcher/QueryNode';\nimport { RootQueryNode } from './matcher/RootQueryNode';\n\nexport class SocketMessageHandler {\n\n\tprivate readonly logPrefix = '[SocketMessageHandler]:' as const;\n\n\tprivate readonly requestBufferManager: RequestBufferManager;\n\n\tpublic constructor (\n\t\tprivate changesDeltaFactory: ChangesDeltaFactory,\n\t\tprivate columnCache: ColumnCache,\n\t\tprivate errorHandler: ErrorHandlerInterface,\n\t\tprivate requestColumnExpansionFactory: RequestColumnExpansionFactory,\n\t\tprivate transactionCacheFactory: TransactionCacheFactory,\n\t\tapiRequestService: ApiRequestService,\n\t\tprivate requestColumnsOperationsCacheFactory: RequestColumnsOperationsCacheFactory,\n\t) {\n\t\tthis.requestBufferManager = new RequestBufferManager(\n\t\t\tapiRequestService,\n\t\t\trequestColumnExpansionFactory,\n\t\t);\n\t}\n\n\tpublic async onMessagesReceived (\n\t\tmessages: SocketMessage<any>[],\n\t\tflushTimeout?: number,\n\t): Promise<ChangesDeltaResult> {\n\t\tconst changesAccumulator = this.changesDeltaFactory.construct(\n\t\t\tfalse,\n\t\t\t[],\n\t\t);\n\t\tconst requestAccumulator: Promise<RequestBufferResult<any>>[] = [];\n\t\tconst serverCache = this.transactionCacheFactory.getServerCache();\n\t\tconst activeItemEntries = serverCache.getActiveItemEntries();\n\n\t\tfor (const message of messages) {\n\t\t\tconst messageBody = message.body;\n\n\t\t\tif (messageBody.eventType === 'delete') {\n\t\t\t\tthis.handleDelete(\n\t\t\t\t\tmessageBody,\n\t\t\t\t\tchangesAccumulator,\n\t\t\t\t);\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tthis.processMessage(\n\t\t\t\tmessageBody,\n\t\t\t\tchangesAccumulator,\n\t\t\t\trequestAccumulator,\n\t\t\t\tactiveItemEntries,\n\t\t\t\tflushTimeout,\n\t\t\t);\n\t\t}\n\n\t\treturn this.processRequests(\n\t\t\trequestAccumulator,\n\t\t\tchangesAccumulator,\n\t\t);\n\t}\n\n\tpublic async refreshItemsOfType (\n\t\titemType: ApiItemType,\n\t): Promise<void> {\n\t\tconst serverCache = this.transactionCacheFactory.getServerCache();\n\t\tconst allActiveItemEntries = serverCache.getActiveItemEntries();\n\n\t\tconst itemEntriesOfType = serverCache.itemHandler.entries.getByItemType(\n\t\t\titemType,\n\t\t);\n\n\t\tconst activeItemEntries: ItemEntry<ApiItemType>[] = [];\n\t\tlet inactiveItemEntryCount = 0;\n\n\t\tfor (const itemEntry of itemEntriesOfType) {\n\t\t\titemEntry.markOutdated();\n\n\t\t\tif (\n\t\t\t\tallActiveItemEntries.has(\n\t\t\t\t\titemEntry,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tactiveItemEntries.push(\n\t\t\t\t\titemEntry,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tinactiveItemEntryCount++;\n\t\t\t}\n\t\t}\n\n\t\tconst cachedQueries = serverCache.cachedQueryHandler.getCachedQueryItemsByItemType(\n\t\t\titemType,\n\t\t);\n\n\t\tconst activeCachedQueries: CachedQueryItem<ApiItemType>[] = [];\n\t\tlet inactiveCachedQueryCount = 0;\n\n\t\tfor (const cachedQueryItem of cachedQueries) {\n\t\t\tcachedQueryItem.markOutdated();\n\n\t\t\tif (\n\t\t\t\tserverCache.cachedQueryHandler.hasActiveCollectionsForQuery(\n\t\t\t\t\tcachedQueryItem.itemType,\n\t\t\t\t\tcachedQueryItem.query.string,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tactiveCachedQueries.push(\n\t\t\t\t\tcachedQueryItem,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tinactiveCachedQueryCount++;\n\t\t\t}\n\t\t}\n\n\t\tif (\n\t\t\tinactiveItemEntryCount > 0\n\t\t\t|| inactiveCachedQueryCount > 0\n\t\t) {\n\t\t\tthis.errorHandler.logDebug(\n\t\t\t\t`${this.logPrefix} Marked ${inactiveItemEntryCount} items and ${inactiveCachedQueryCount} cached queries as outdated for '${itemType}'`,\n\t\t\t);\n\t\t}\n\n\t\tif (\n\t\t\tactiveItemEntries.length === 0\n\t\t\t&& activeCachedQueries.length === 0\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.errorHandler.logDebug(\n\t\t\t`${this.logPrefix} Immediately re-fetching ${activeItemEntries.length} items and ${activeCachedQueries.length} cached queries for '${itemType}'`,\n\t\t);\n\n\t\tconst columnExpansion = this.requestColumnExpansionFactory.construct();\n\n\t\tfor (const itemEntry of activeItemEntries) {\n\t\t\tcolumnExpansion.expandWithColumnSet(\n\t\t\t\titemEntry.columns,\n\t\t\t);\n\t\t}\n\n\t\tconst requestColumns = serverCache.expandColumnExpansionWithRequiredColumns(\n\t\t\titemType,\n\t\t\tcolumnExpansion,\n\t\t\tactiveCachedQueries,\n\t\t\t[],\n\t\t);\n\n\t\tconst columnsOperationsCache = this.requestColumnsOperationsCacheFactory.construct(\n\t\t\titemType,\n\t\t\trequestColumns,\n\t\t);\n\n\t\tconst requestAccumulator: Promise<RequestBufferResult<any>>[] = [\n\t\t\t// Note: This updates any items that are already cached, but won't check for new items that might fit collections, therefor we also refresh the cached queries.\n\t\t\tthis.requestBufferManager.fetchByIds(\n\t\t\t\titemType,\n\t\t\t\tactiveItemEntries.map(\n\t\t\t\t\titemEntry => itemEntry.itemId,\n\t\t\t\t),\n\t\t\t\trequestColumns,\n\t\t\t),\n\t\t];\n\n\t\tif (activeCachedQueries.length > 0) {\n\t\t\t// Note: This will not re-fetch non-cachable queries, as they are not stored in the cache.\n\t\t\tfor (const cachedQueryItem of activeCachedQueries) {\n\t\t\t\trequestAccumulator.push(\n\t\t\t\t\tthis.requestBufferManager.fetchByQuery(\n\t\t\t\t\t\titemType,\n\t\t\t\t\t\tcachedQueryItem.query,\n\t\t\t\t\t\tcolumnsOperationsCache.getRequestColumnsTuple(\n\t\t\t\t\t\t\tserverCache,\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tawait this.processRequests(\n\t\t\trequestAccumulator,\n\t\t);\n\t}\n\n\tprivate handleDelete (\n\t\tsocketMessageBody: SocketMessageDelete['body'],\n\t\tchangesAccumulator: ChangesDelta,\n\t): void {\n\t\tconst serverCache = this.transactionCacheFactory.getServerCache();\n\t\tconst itemType = socketMessageBody.itemType;\n\n\t\tfor (const itemId of socketMessageBody.items) {\n\t\t\tif (\n\t\t\t\tserverCache.containsLocalItemEntryByItemId(\n\t\t\t\t\titemType,\n\t\t\t\t\titemId,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tchangesAccumulator.setItemDeleted(\n\t\t\t\t\tserverCache.getLocalItemEntryByItemId(\n\t\t\t\t\t\titemType,\n\t\t\t\t\t\titemId,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst removedItemEntries = [\n\t\t\t...changesAccumulator.getDeletedItemEntriesIterator(\n\t\t\t\titemType,\n\t\t\t),\n\t\t];\n\n\t\tif (removedItemEntries.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tchangesAccumulator.addQueryItemType(\n\t\t\titemType,\n\t\t);\n\n\t\tconst itemIdString = removedItemEntries\n\t\t\t.map(\n\t\t\t\titemEntry => itemEntry.itemId,\n\t\t\t)\n\t\t\t.join(\n\t\t\t\t', ',\n\t\t\t);\n\n\t\tthis.errorHandler.logDebug(\n\t\t\t`${this.logPrefix} Removing ${itemType} items: [${itemIdString}]`,\n\t\t);\n\t}\n\n\tprivate logFetchedItems<ItemTypeType extends ApiItemType> (\n\t\tmessageBody: Exclude<SocketMessage<ItemTypeType>, SocketMessageDelete>['body'],\n\t\trequestIds: ItemId<ItemTypeType>[],\n\t): void {\n\t\tconst itemIdString = requestIds.join(\n\t\t\t', ',\n\t\t);\n\n\t\tthis.errorHandler.logDebug(\n\t\t\t`${this.logPrefix} Fetching ${messageBody.itemType} items for ${messageBody.eventType}: [${itemIdString}]`,\n\t\t);\n\t}\n\n\tprivate processSocketMessageValues<ItemTypeType extends ApiItemType, ColumnIds extends ItemTypeColumnIds<ItemTypeType>> (\n\t\titemType: ItemTypeType,\n\t\tsocketMessageValuesTuples: SocketMessageValuesTuple<ItemTypeType, ColumnIds>[],\n\t): {\n\t\tfieldsArray: FieldMap<ItemTypeType, ColumnIds>[],\n\t\tcolumns: {\n\t\t\trequest: ColumnIds,\n\t\t\tresponse: ResponseColumnMap<ItemTypeType, ColumnIds>,\n\t\t},\n\t} {\n\t\tconst columnIds: ItemTypeColumnId<ItemTypeType>[] = [];\n\t\tconst responseColumns = {} as ResponseColumnMap<ItemTypeType, ColumnIds>;\n\n\t\tfor (const columnId in socketMessageValuesTuples[0].values) {\n\t\t\tconst responseColumn = this.columnCache.getColumn(\n\t\t\t\titemType,\n\t\t\t\tcolumnId as ItemTypeColumnId<ItemTypeType>,\n\t\t\t);\n\n\t\t\t// If we don't have the response column cached, we're not interested in the socket message field value.\n\t\t\tif (responseColumn === undefined) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tcolumnIds.push(\n\t\t\t\tcolumnId as ItemTypeColumnId<ItemTypeType>,\n\t\t\t);\n\t\t\tresponseColumns[columnId as ItemTypeColumnId<ItemTypeType>] = responseColumn;\n\t\t}\n\n\t\tconst fieldsArray: FieldMap<ItemTypeType, ColumnIds>[] = [];\n\n\t\tfor (const socketMessageItem of socketMessageValuesTuples) {\n\t\t\tconst fields: Partial<FieldMap<ItemTypeType, ColumnIds>> = {};\n\n\t\t\tfor (const columnId of columnIds) {\n\t\t\t\tfields[columnId] = ApiFormatter.formatResponseValue(\n\t\t\t\t\t(responseColumns[columnId] as UnknownResponseColumn).type,\n\t\t\t\t\tsocketMessageItem.values[columnId],\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tfieldsArray.push(\n\t\t\t\tfields as FieldMap<ItemTypeType, ColumnIds>,\n\t\t\t);\n\t\t}\n\n\t\treturn {\n\t\t\tfieldsArray,\n\t\t\tcolumns: {\n\t\t\t\trequest: columnIds as unknown as ColumnIds,\n\t\t\t\tresponse: responseColumns,\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate aggregateCachedRequestColumns<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tfieldsArray: Iterable<FieldMap<ItemTypeType>>,\n\t): RequestColumnExpansion {\n\t\tconst serverCache = this.transactionCacheFactory.getServerCache();\n\t\tconst columnExpansion = this.requestColumnExpansionFactory.construct();\n\n\t\tfor (const fields of fieldsArray) {\n\t\t\tif (\n\t\t\t\tserverCache.containsLocalItemEntryByItemId(\n\t\t\t\t\titemType,\n\t\t\t\t\tfields.id as ItemId,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tcolumnExpansion.expandWithColumnSet(\n\t\t\t\t\tserverCache\n\t\t\t\t\t\t.getLocalItemEntryByItemId(\n\t\t\t\t\t\t\titemType,\n\t\t\t\t\t\t\tfields.id as ItemId,\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.columns,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn columnExpansion;\n\t}\n\n\tprivate getMergedQueryGraphTuple<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t): {\n\t\tcollectionResourceMap: Map<string, CollectionResource<ItemTypeType>[]>,\n\t\tqueryGraph: RootQueryNode<ItemTypeType>,\n\t} {\n\t\tconst serverCache = this.transactionCacheFactory.getServerCache();\n\t\tconst mergedQueryGraph = serverCache.cachedQueryHandler.getMergedQueryGraph(\n\t\t\titemType,\n\t\t) ?? new RootQueryNode<ItemTypeType>();\n\t\tconst uncachedCollectionsIterator = serverCache.cachedQueryHandler.getUncachedCollectionsOnChildTransactionsIterator(\n\t\t\titemType,\n\t\t);\n\t\tconst uncachedCollectionResourceMap: Map<string, CollectionResource<ItemTypeType>[]> = new Map();\n\n\t\tfor (const collectionResource of uncachedCollectionsIterator) {\n\t\t\tconst queryString = collectionResource.entry.query.string;\n\n\t\t\tlet collectionResources = uncachedCollectionResourceMap.get(\n\t\t\t\tqueryString,\n\t\t\t);\n\n\t\t\tif (collectionResources === undefined) {\n\t\t\t\tuncachedCollectionResourceMap.set(\n\t\t\t\t\tqueryString,\n\t\t\t\t\tcollectionResources = [],\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tcollectionResources.push(\n\t\t\t\tcollectionResource,\n\t\t\t);\n\t\t\tmergedQueryGraph.copyEdgesFrom(\n\t\t\t\tcollectionResource.queryGraph,\n\t\t\t\tundefined,\n\t\t\t);\n\t\t}\n\n\t\treturn {\n\t\t\tcollectionResourceMap: uncachedCollectionResourceMap,\n\t\t\tqueryGraph: mergedQueryGraph,\n\t\t};\n\t}\n\n\tprivate matchSocketMessageItems<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tfieldsToMatch: FieldMap<ItemTypeType>[],\n\t\tisCreate: boolean,\n\t\tactiveItemEntries: ActiveItemEntries,\n\t): {\n\t\tfieldsSet: Set<FieldMap<ItemTypeType>>,\n\t\titemEntries: {\n\t\t\tactive: ItemEntry<ItemTypeType>[],\n\t\t\tinactive: ItemEntry<ItemTypeType>[],\n\t\t},\n\t\tcachedQueryItems: {\n\t\t\tactive: CachedQueryItem<ItemTypeType>[],\n\t\t\tinactive: CachedQueryItem<ItemTypeType>[],\n\t\t},\n\t\tuncachedCollections: CollectionResource<ItemTypeType>[],\n\t} | null {\n\t\tconst serverCache = this.transactionCacheFactory.getServerCache();\n\t\tconst matchedFields: Set<FieldMap<ItemTypeType>> = new Set();\n\t\tconst mergedQueryGraphTuple = this.getMergedQueryGraphTuple(\n\t\t\titemType,\n\t\t);\n\n\t\tconst matchedItemEntries: {\n\t\t\tactive: ItemEntry<ItemTypeType>[],\n\t\t\tinactive: ItemEntry<ItemTypeType>[],\n\t\t} = {\n\t\t\tactive: [],\n\t\t\tinactive: [],\n\t\t};\n\n\t\tconst matchesAccumulator: MatchesAccumulator<FieldMap<ItemTypeType>> = new Map();\n\n\t\tfor (const fields of fieldsToMatch) {\n\t\t\tif (\n\t\t\t\tserverCache.containsLocalItemEntryByItemId(\n\t\t\t\t\titemType,\n\t\t\t\t\tfields.id as ItemId,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\t// If we receive a 'create' message for an item we have already we can assume the cache is up-to-date.\n\t\t\t\tif (isCreate) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst itemId = fields.id as ItemId;\n\n\t\t\t\tconst itemEntry = serverCache.getLocalItemEntryByItemId(\n\t\t\t\t\titemType,\n\t\t\t\t\titemId,\n\t\t\t\t);\n\n\t\t\t\tif (\n\t\t\t\t\tactiveItemEntries.has(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\tmatchedItemEntries.active.push(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tmatchedItemEntries.inactive.push(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tmatchedFields.add(\n\t\t\t\t\tfields,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tmergedQueryGraphTuple.queryGraph.doMatch(\n\t\t\t\tfields,\n\t\t\t\tcolumnId => fields[columnId],\n\t\t\t\tmatchesAccumulator,\n\t\t\t);\n\t\t}\n\n\t\tconst matchedCachedQueryItems: {\n\t\t\tactive: CachedQueryItem<ItemTypeType>[],\n\t\t\tinactive: CachedQueryItem<ItemTypeType>[],\n\t\t} = {\n\t\t\tactive: [],\n\t\t\tinactive: [],\n\t\t};\n\n\t\tconst matchedUncachedCollections: CollectionResource<ItemTypeType>[] = [];\n\n\t\tfor (const matchesAccumulatorEntry of matchesAccumulator.entries()) {\n\t\t\tconst queryString = matchesAccumulatorEntry[0];\n\t\t\t// This is a bit unwieldy, because the matches accumulator uses the string representation as key.\n\t\t\t// We have to find the associated cached queries / collection resources manually.\n\t\t\tconst cachedQueryItem = serverCache.cachedQueryHandler.getCachedQueryItem(\n\t\t\t\titemType,\n\t\t\t\tqueryString,\n\t\t\t);\n\t\t\tconst collectionResources = mergedQueryGraphTuple.collectionResourceMap.get(\n\t\t\t\tqueryString,\n\t\t\t);\n\n\t\t\tif (cachedQueryItem !== undefined) {\n\t\t\t\tif (\n\t\t\t\t\tserverCache.cachedQueryHandler.hasActiveCollectionsForQuery(\n\t\t\t\t\t\tcachedQueryItem.itemType,\n\t\t\t\t\t\tcachedQueryItem.query.string,\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\tmatchedCachedQueryItems.active.push(\n\t\t\t\t\t\tcachedQueryItem,\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tmatchedCachedQueryItems.inactive.push(\n\t\t\t\t\t\tcachedQueryItem,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (collectionResources !== undefined) {\n\t\t\t\tmatchedUncachedCollections.push(\n\t\t\t\t\t...collectionResources,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst matchesAccumulatorTuple = matchesAccumulatorEntry[1];\n\n\t\t\tfor (const fields of matchesAccumulatorTuple.true) {\n\t\t\t\tmatchedFields.add(\n\t\t\t\t\tfields,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (matchesAccumulatorTuple.maybe !== undefined) {\n\t\t\t\tfor (const fields of matchesAccumulatorTuple.maybe) {\n\t\t\t\t\tmatchedFields.add(\n\t\t\t\t\t\tfields,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Didn't match any cached items, queries or collections.\n\t\tif (matchedFields.size === 0) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn {\n\t\t\tfieldsSet: matchedFields,\n\t\t\tcachedQueryItems: matchedCachedQueryItems,\n\t\t\tuncachedCollections: matchedUncachedCollections,\n\t\t\titemEntries: matchedItemEntries,\n\t\t};\n\t}\n\n\t/**\n\t * @description\n\t * When an item is created or updated, we should check if it fits in any of the cached queries (using the values provided by the socket message)\n\t * If we think it fits (or maybe) we should fetch the complete item with the superset of columns (the socket message might not have all values)\n\t */\n\tprivate processMessage<ItemTypeType extends ApiItemType> (\n\t\tbody: Exclude<SocketMessage<ItemTypeType>, SocketMessageDelete>['body'],\n\t\tchangesAccumulator: ChangesDelta,\n\t\trequestAccumulator: Promise<RequestBufferResult<ItemTypeType>>[],\n\t\tactiveItemEntries: ActiveItemEntries,\n\t\tflushTimeout?: number,\n\t): void {\n\t\tconst itemType = body.itemType;\n\t\tconst fieldsArrayTuple = this.processSocketMessageValues(\n\t\t\titemType,\n\t\t\tObject.values(\n\t\t\t\tbody.items[itemType],\n\t\t\t),\n\t\t);\n\t\tconst matchedItems = this.matchSocketMessageItems(\n\t\t\titemType,\n\t\t\tfieldsArrayTuple.fieldsArray,\n\t\t\tbody.eventType === 'create',\n\t\t\tactiveItemEntries,\n\t\t);\n\n\t\tif (matchedItems === null) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst itemUpdateModeMap: {\n\t\t\t[itemId: string]: ChangesDeltaItemUpdateMode,\n\t\t} = {};\n\n\t\tfor (const fields of matchedItems.fieldsSet) {\n\t\t\titemUpdateModeMap[fields.id as ItemId] = 'CLEAR_WHEN_SAME';\n\t\t}\n\n\t\tconst serverCache = this.transactionCacheFactory.getServerCache();\n\n\t\t// This changes delta will contain the fields in the socket message, as well as the fields that are required\n\t\t// to add the item to the matched collections.\n\t\tserverCache.processResponseByItemType(\n\t\t\titemType,\n\t\t\tfieldsArrayTuple.columns.request,\n\t\t\t{\n\t\t\t\t[itemType]: fieldsArrayTuple.columns.response,\n\t\t\t} as ResponseColumnItemTypeMap,\n\t\t\tmatchedItems.fieldsSet,\n\t\t\tchangesAccumulator,\n\t\t\titemUpdateModeMap,\n\t\t);\n\n\t\tconst requestColumns = ColumnUtil.mergeRequestColumns(\n\t\t\tfieldsArrayTuple.columns.request,\n\t\t\tserverCache.expandColumnExpansionWithRequiredColumns(\n\t\t\t\titemType,\n\t\t\t\tthis.aggregateCachedRequestColumns(\n\t\t\t\t\titemType,\n\t\t\t\t\tmatchedItems.fieldsSet,\n\t\t\t\t),\n\t\t\t\t[\n\t\t\t\t\t...matchedItems.cachedQueryItems.active,\n\t\t\t\t\t...matchedItems.cachedQueryItems.inactive,\n\t\t\t\t],\n\t\t\t\tmatchedItems.uncachedCollections,\n\t\t\t),\n\t\t);\n\n\t\t// If we already have all the required fields, there's no need to do a back-end request.\n\t\t// Fixme: Are we sure we want to keep this? Now we rely directly on the socket message values, which might be outdated due to the nature of the queue.\n\t\tif (\n\t\t\trequestColumns.difference !== true\n\t\t\t&& requestColumns.difference.length === 0\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (\n\t\t\t// We only want to invalidate cached queries if we don't have to do a request anyways.\n\t\t\tmatchedItems.cachedQueryItems.active.length === 0\n\t\t\t&& matchedItems.itemEntries.active.length === 0\n\t\t\t&& matchedItems.uncachedCollections.length === 0\n\t\t) {\n\t\t\tthis.errorHandler.logDebug(\n\t\t\t\t`${this.logPrefix} Marked ${body.itemType} items as outdated`,\n\t\t\t);\n\n\t\t\t// We'll refresh these lazily when we need them again.\n\t\t\tfor (const inactiveCachedQueryItem of matchedItems.cachedQueryItems.inactive) {\n\t\t\t\t// CachedQueryItems are stored on all transactions, while ItemEntries are unique globally,\n\t\t\t\t// so for cachedQueryItems we need to iterate over all transactions.\n\t\t\t\tserverCache.cachedQueryHandler.markCachedQueriesOutdatedInAllTransactions(\n\t\t\t\t\tinactiveCachedQueryItem.itemType,\n\t\t\t\t\tinactiveCachedQueryItem.query.string,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tfor (const inactiveItemEntry of matchedItems.itemEntries.inactive) {\n\t\t\t\tinactiveItemEntry.markOutdated();\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst requestIds: ItemId<ItemTypeType>[] = [];\n\n\t\tfor (const fields of matchedItems.fieldsSet) {\n\t\t\trequestIds.push(\n\t\t\t\tfields.id as ItemId<ItemTypeType>,\n\t\t\t);\n\t\t}\n\n\t\tthis.logFetchedItems(\n\t\t\tbody,\n\t\t\trequestIds,\n\t\t);\n\n\t\trequestAccumulator.push(\n\t\t\tthis.requestBufferManager.fetchByIds(\n\t\t\t\titemType,\n\t\t\t\trequestIds,\n\t\t\t\trequestColumns.merged,\n\t\t\t\t{\n\t\t\t\t\tflushTimeout,\n\t\t\t\t},\n\t\t\t),\n\t\t);\n\t}\n\n\tprivate async processRequests (\n\t\trequestAccumulator: Promise<RequestBufferResult<any>>[],\n\t\tchangesAccumulator: ChangesDelta = this.changesDeltaFactory.construct(\n\t\t\tfalse,\n\t\t),\n\t): Promise<ChangesDeltaResult> {\n\t\tconst settledPromises = await Promise.allSettled(\n\t\t\trequestAccumulator,\n\t\t);\n\n\t\tconst serverCache = this.transactionCacheFactory.getServerCache();\n\n\t\tfor (const settledPromise of settledPromises) {\n\t\t\tif (settledPromise.status === 'rejected') {\n\t\t\t\tthis.errorHandler.logError(\n\t\t\t\t\tsettledPromise.reason,\n\t\t\t\t);\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst {\n\t\t\t\trequestColumns,\n\t\t\t\tresponse,\n\t\t\t\tnonLocallyMatchableQueryString,\n\t\t\t} = settledPromise.value;\n\n\t\t\tchangesAccumulator.addQueryItemType(\n\t\t\t\tresponse.itemType,\n\t\t\t);\n\n\t\t\tif (nonLocallyMatchableQueryString !== null) {\n\t\t\t\tchangesAccumulator._setQueryResult(\n\t\t\t\t\tresponse.itemType,\n\t\t\t\t\tnonLocallyMatchableQueryString,\n\t\t\t\t\tresponse.links[response.itemType],\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tserverCache.processResponse(\n\t\t\t\tresponse,\n\t\t\t\trequestColumns,\n\t\t\t\tchangesAccumulator,\n\t\t\t);\n\t\t}\n\n\t\treturn serverCache.applyChangesDelta(\n\t\t\tchangesAccumulator,\n\t\t\ttrue,\n\t\t);\n\t}\n\n}\n","import { ApiFieldsOnDeleteRule, ApiItemType, ItemId } from '@rentman/backend-types';\nimport { RmCore } from '../../core';\nimport { AbstractCacheDependencyInterface, CachedQueryHandlerBase, CachedQueryItem, ChangesDelta, ChangesDeltaItemCreateDelta, ChildChangesDelta, CollectionQuery, ColumnInfo, EntryParentNull, FieldMap, ItemCache, ItemEntry, ItemEntryChangesTuple, ItemHandlerBase, ItemIdConversionMap, OnAfterCreateCallback, ParentChangesDelta, ServerCache, TransactionCache, TransactionValidatorFactory } from '../../internal';\n\nexport type TransactionOptions = {\n\t/**\n\t * @description\n\t * Sets the TransactionCache to 'transparent' mode, whenever {@link AbstractCache.createChild createChild} is called it will actually be called on the parent\n\t */\n\ttransparent: boolean,\n};\n\nexport abstract class AbstractCache {\n\n\tpublic children: TransactionCache[] = [];\n\n\tpublic readonly itemHandler: ItemHandlerBase;\n\tpublic readonly cachedQueryHandler: CachedQueryHandlerBase;\n\n\tpublic parent: AbstractCache | null;\n\n\tprotected constructor (\n\t\tpublic dependencies: AbstractCacheDependencyInterface,\n\t\tpublic core: RmCore,\n\t) {\n\t}\n\n\tpublic* getDescendantsIterator (): IterableIterator<TransactionCache> {\n\t\tfor (const child of this.children) {\n\t\t\tyield child;\n\n\t\t\tyield* child.getDescendantsIterator();\n\t\t}\n\t}\n\n\tpublic abstract createChild (\n\t\tid?: string,\n\t\tvalidatorFactory?: TransactionValidatorFactory,\n\t\toptions?: TransactionOptions,\n\t): TransactionCache;\n\n\tpublic onChildDestroy (\n\t\tcache: TransactionCache,\n\t): void {\n\t\tconst index = this.children.indexOf(\n\t\t\tcache,\n\t\t);\n\n\t\tif (index !== -1) {\n\t\t\tthis.children.splice(\n\t\t\t\tindex,\n\t\t\t\t1,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * @description\n\t * Returns {@link ItemEntry ItemEntries} that fit the collection's query, copies over the collectionChanges on all transactions in the chain.\n\t */\n\tpublic abstract getCollectionChangesRecursively<const ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tparsedQuery: CollectionQuery<ItemTypeType>,\n\t): CachedQueryItem<ItemTypeType> | undefined;\n\n\t/**\n\t * @description\n\t * Returns this transaction and all parents\n\t */\n\n\tpublic getTransactionChain (\n\t\tincludeServerCache: false,\n\t): TransactionCache[];\n\n\tpublic getTransactionChain (\n\t\tincludeServerCache?: true,\n\t): AbstractCache[];\n\n\tpublic getTransactionChain (\n\t\tincludeServerCache: boolean = true,\n\t): AbstractCache[] {\n\t\tconst transactions: AbstractCache[] = [];\n\t\t// eslint-disable-next-line @typescript-eslint/no-this-alias\n\t\tlet transaction: AbstractCache = this;\n\n\t\tdo {\n\t\t\tif (\n\t\t\t\t!includeServerCache\n\t\t\t\t&& transaction.parent === null\n\t\t\t) {\n\t\t\t\treturn transactions;\n\t\t\t}\n\n\t\t\ttransactions.push(\n\t\t\t\ttransaction,\n\t\t\t);\n\n\t\t\t// @ts-ignore while loop will break\n\t\t\ttransaction = transaction.parent;\n\t\t} while (transaction !== null);\n\n\t\treturn transactions;\n\t}\n\n\t/**\n\t * @description\n\t * Returns the {@link TransactionItemHandler.entries ItemCache} of the transaction\n\t */\n\tpublic getCurrentItemEntryCache (): ItemCache {\n\t\treturn this.itemHandler.entries;\n\t}\n\n\tpublic abstract getServerCache (): ServerCache;\n\n\tpublic abstract getLocalItemEntry (itemEntryId: ItemEntry['id']): ItemEntry;\n\n\tpublic abstract getLocalItemEntryByItemId<const ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\titemId: ItemEntry<ItemTypeType>['itemId'],\n\t): ItemEntry<ItemTypeType>;\n\n\tpublic abstract containsLocalItemEntryByItemId (\n\t\titemType: ApiItemType,\n\t\titemId: ItemEntry['itemId'],\n\t): boolean;\n\n\t/**\n\t * @description\n\t * Removes an {@link ItemEntry ItemEntry} from the {@link TransactionCache TransactionCache} which means that\n\t * changes on this entry will no longer be tracked.\n\t *\n\t * @returns The deleted item changes.\n\t */\n\tpublic clearItemEntry<ItemTypeType extends ApiItemType> (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t): FieldMap<ItemTypeType> | undefined {\n\t\tthis.cachedQueryHandler.clearLinkedCachedQueryItems(\n\t\t\titemEntry,\n\t\t);\n\n\t\treturn this.itemHandler.clearItemEntry(\n\t\t\titemEntry,\n\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Gets an already cached {@link ItemEntry ItemEntry} and the changes of this specific transaction for that entry\n\t */\n\tpublic getLocalItemEntryChangesTuple<ItemTypeType extends ApiItemType> (\n\t\titemEntryId: ItemEntry<ItemTypeType>['id'],\n\t): ItemEntryChangesTuple<ItemTypeType> {\n\t\treturn {\n\t\t\tentry: this.getLocalItemEntry(\n\t\t\t\titemEntryId,\n\t\t\t),\n\t\t\tchanges: this.itemHandler.itemChanges[itemEntryId],\n\t\t};\n\t}\n\n\t/**\n\t * @description\n\t * Applies changes from a child transaction to a parent\n\t */\n\tpublic abstract applyChangesFromChild (\n\t\ttransaction: TransactionCache,\n\t\tbreakUpByParent?: boolean,\n\t\tonAfterCreateCallback?: OnAfterCreateCallback,\n\t): Promise<ItemIdConversionMap>;\n\n\t/**\n\t * @description\n\t * Called by a parent transaction, propagates changes downwards to all child caches\n\t *\n\t * @remarks\n\t * - Should only be used by the core\n\t *\n\t * todo[cache] Should we refetch derived values just like in applyChangesDelta ?\n\t *\n\t * @internal\n\t */\n\tpublic abstract applyChangesFromParent (\n\t\tparentChangesDelta: ParentChangesDelta,\n\t\tisCalledAfterSocketUpdate?: boolean,\n\t): Promise<void>;\n\n\t// todo[cache] rename to getItemParent or getParentObject?\n\tpublic getParent (\n\t\titemEntry: ItemEntry<any>,\n\t\tfromInitial: boolean = false,\n\t): EntryParentNull {\n\t\tif (\n\t\t\tfromInitial\n\t\t\t// You cannot call fromInitial on the ServerCache\n\t\t\t&& this.parent !== null\n\t\t\t// a local itemEntry can never have changes on a parent transaction\n\t\t\t&& !this.itemHandler.entries.containsByEntryId(\n\t\t\t\titemEntry.id,\n\t\t\t)\n\t\t) {\n\t\t\treturn this.parent.getParent(\n\t\t\t\titemEntry,\n\t\t\t\tfalse,\n\t\t\t);\n\t\t}\n\n\t\t// todo: should we refactor this to not rely on the response columns?\n\n\t\tlet parentType: ApiItemType | null = null;\n\t\tlet parentId: ItemId | null = null;\n\n\t\tif (itemEntry.columns.link !== null) {\n\t\t\tparentType = itemEntry.columns.link.apiColumn.itemType;\n\t\t\tparentId = this.itemHandler.lookUpItemField(\n\t\t\t\titemEntry,\n\t\t\t\titemEntry.columns.link.id,\n\t\t\t) as ItemId ?? null;\n\t\t} else {\n\t\t\tconst responseColumns = itemEntry.columns.response[itemEntry.itemType];\n\n\t\t\tif (\n\t\t\t\t'itemtype' in responseColumns\n\t\t\t\t&& 'item' in responseColumns\n\t\t\t) {\n\t\t\t\tparentType = this.itemHandler.lookUpItemField(\n\t\t\t\t\titemEntry,\n\t\t\t\t\t// @ts-ignore when it's a linktable we can assume the itemtype and item fields are there\n\t\t\t\t\t'itemtype',\n\t\t\t\t) as ApiItemType ?? null;\n\n\t\t\t\tparentId = this.itemHandler.lookUpItemField(\n\t\t\t\t\titemEntry,\n\t\t\t\t\t// @ts-ignore when it's a linktable we can assume the itemtype and item fields are there\n\t\t\t\t\t'item',\n\t\t\t\t) as ItemId ?? null;\n\t\t\t}\n\t\t}\n\n\t\tif (parentType !== null && parentId !== null) {\n\t\t\treturn {\n\t\t\t\titemType: parentType,\n\t\t\t\titemId: parentId,\n\t\t\t};\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tprotected getParentFromFields<ItemTypeType extends ApiItemType = any> (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t\tfields?: FieldMap<ItemTypeType>,\n\t): EntryParentNull {\n\t\tif (fields === undefined) {\n\t\t\treturn null;\n\t\t}\n\n\t\tlet parentType: ApiItemType | null = null;\n\t\tlet parentId: ItemId | null = null;\n\n\t\tif (itemEntry.columns.link !== null) {\n\t\t\tparentType = itemEntry.columns.link.apiColumn.itemType;\n\t\t\tparentId = fields[itemEntry.columns.link.id];\n\t\t} else {\n\t\t\tconst responseColumns = itemEntry.columns.response[itemEntry.itemType];\n\n\t\t\tif (\n\t\t\t\t'itemtype' in responseColumns\n\t\t\t\t&& 'item' in responseColumns\n\t\t\t) {\n\t\t\t\t// @ts-ignore\n\t\t\t\tparentType = fields.itemtype;\n\t\t\t\t// @ts-ignore\n\t\t\t\tparentId = fields.item;\n\t\t\t}\n\t\t}\n\n\t\tif (parentType !== null && parentId !== null) {\n\t\t\treturn {\n\t\t\t\titemType: parentType,\n\t\t\t\titemId: parentId,\n\t\t\t};\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Processes a created item from a changes delta.\n\t * @returns `null` if the item already exists on this transaction, the created item entry otherwise.\n\t */\n\tprotected processCreatedItem<ItemTypeType extends ApiItemType> (\n\t\ttuple: ChangesDeltaItemCreateDelta<ItemTypeType>,\n\t\tsourceChangesDelta: ChangesDelta,\n\t): ItemEntry<ItemTypeType> | null {\n\t\tif (\n\t\t\t!this.containsLocalItemEntryByItemId(\n\t\t\t\ttuple.columns.itemType,\n\t\t\t\ttuple.itemId,\n\t\t\t)\n\t\t) {\n\t\t\treturn this.itemHandler.createItemEntry(\n\t\t\t\ttuple,\n\t\t\t);\n\t\t}\n\n\t\tconst existingItemEntry = this.getLocalItemEntryByItemId(\n\t\t\ttuple.columns.itemType,\n\t\t\ttuple.itemId,\n\t\t);\n\n\t\t// ItemEntry was already created by a faster promise chain, so we treat this like an update\n\t\tsourceChangesDelta.setItemUpdated(\n\t\t\texistingItemEntry,\n\t\t\ttuple.fields,\n\t\t\tthis.core.columnExpansionFactory.construct(\n\t\t\t\ttuple.columns.itemType,\n\t\t\t\ttuple.columns.requestColumnsTrue\n\t\t\t\t\t? true\n\t\t\t\t\t: tuple.columns.request,\n\t\t\t\ttuple.columns.response,\n\t\t\t),\n\t\t\tnull,\n\t\t\t// We don't want to overwrite any user changes\n\t\t\t'KEEP_WHEN_DIFFERENT',\n\t\t);\n\n\t\tsourceChangesDelta.created.remove(\n\t\t\texistingItemEntry.itemType,\n\t\t\texistingItemEntry.itemId,\n\t\t);\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * @description\n\t * Ensures that for all updated items in the delta the required derived values are present\n\t */\n\tprotected fetchUpdatedDerivedValuesFromDelta (\n\t\tchangesDelta: ChangesDelta | ChildChangesDelta,\n\t\titemIdConversionMap: ItemIdConversionMap | undefined,\n\t): Promise<void[]> {\n\t\tconst derivedPromises: Promise<void>[] = [];\n\n\t\tfor (const itemEntryId in changesDelta.updated) {\n\t\t\tconst tuple = changesDelta.updated[itemEntryId];\n\t\t\tconst changedRootColumns: ColumnInfo[] = [];\n\n\t\t\tfor (const column of tuple.entry.columns.root) {\n\t\t\t\tconst cachedFieldValue = this.itemHandler.lookUpItemField(\n\t\t\t\t\ttuple.entry,\n\t\t\t\t\tcolumn.id,\n\t\t\t\t);\n\n\t\t\t\tif (cachedFieldValue === undefined) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst updatedValue = tuple.changes.fields[column.id];\n\t\t\t\tconst conversionMap = itemIdConversionMap?.[column.itemType];\n\n\t\t\t\tif (\n\t\t\t\t\t// If the root column value changed\n\t\t\t\t\tupdatedValue !== undefined\n\t\t\t\t\t// And it's not the same as the already cached value\n\t\t\t\t\t&& updatedValue !== cachedFieldValue\n\t\t\t\t\t&& (\n\t\t\t\t\t\tconversionMap === undefined\n\t\t\t\t\t\t// And it's not the same (but now created) value as the original value was\n\t\t\t\t\t\t|| conversionMap[cachedFieldValue] !== updatedValue\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\tchangedRootColumns.push(\n\t\t\t\t\t\tcolumn,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (changedRootColumns.length === 0) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tderivedPromises.push(\n\t\t\t\tthis.itemHandler.resolveDerivedValues(\n\t\t\t\t\t[\n\t\t\t\t\t\ttuple.entry,\n\t\t\t\t\t],\n\t\t\t\t\tchangedRootColumns,\n\t\t\t\t\tfalse,\n\t\t\t\t\t// We pass the delta so the new rootColumn's values are read\n\t\t\t\t\tchangesDelta,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\t// We need to ensure the new derived values exist before calling onChange, since the onChange function might use the new values\n\t\treturn Promise.all(\n\t\t\tderivedPromises,\n\t\t);\n\t}\n\n\t// todo: We could put this in a business rule, but we should check how many levels it can recurse then because it will check *every* business rule on every recurse\n\tprotected handleCascadingDeletes (\n\t\tchangesDelta: ChangesDelta | ChildChangesDelta | ParentChangesDelta,\n\t): void {\n\t\tfor (const itemType of changesDelta.getDeletedItemTypesIterator()) {\n\t\t\tconst influencedItemTypes = ApiFieldsOnDeleteRule[itemType]?.foreign ?? {};\n\t\t\tconst deletedItemEntriesIterator = changesDelta.getDeletedItemEntriesIterator(\n\t\t\t\titemType,\n\t\t\t);\n\n\t\t\tfor (const deletedItemEntry of deletedItemEntriesIterator) {\n\t\t\t\tfor (const influencedItemType in influencedItemTypes) {\n\t\t\t\t\tfor (const columnId of influencedItemTypes[influencedItemType]) {\n\t\t\t\t\t\tthis.cascadeDeleteByItemType(\n\t\t\t\t\t\t\tchangesDelta,\n\t\t\t\t\t\t\tinfluencedItemType as ApiItemType,\n\t\t\t\t\t\t\tcolumnId,\n\t\t\t\t\t\t\tdeletedItemEntry.itemId,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate cascadeDeleteByItemType<ItemTypeType extends ApiItemType> (\n\t\tchangesDelta: ChangesDelta | ChildChangesDelta | ParentChangesDelta,\n\t\titemType: ItemTypeType,\n\t\tlinkColumnId: keyof FieldMap<ItemTypeType>,\n\t\tparentItemId: ItemId,\n\t): void {\n\t\t// @ts-ignore it complains about the keyof FieldMap index access\n\t\tconst rule = ApiFieldsOnDeleteRule[itemType]?.own[linkColumnId]?.onDeleteRule;\n\n\t\tif (rule === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet itemEntries: ItemEntry<ItemTypeType>[] = [];\n\n\t\tconst transactions = this.getTransactionChain(\n\t\t\ttrue,\n\t\t);\n\n\t\tfor (const transaction of transactions) {\n\t\t\titemEntries = itemEntries.concat(\n\t\t\t\ttransaction.itemHandler.entries.getByItemType(\n\t\t\t\t\titemType,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\tfor (const itemEntry of itemEntries) {\n\t\t\tlet currentParentItemId: ItemId | undefined = changesDelta.updated[itemEntry.id]?.changes.fields[linkColumnId];\n\n\t\t\tif (currentParentItemId === undefined) {\n\t\t\t\tcurrentParentItemId = this.itemHandler.lookUpItemField(\n\t\t\t\t\titemEntry,\n\t\t\t\t\tlinkColumnId,\n\t\t\t\t) as ItemId | undefined;\n\t\t\t}\n\n\t\t\tif (currentParentItemId !== parentItemId) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (rule === 'restrict') {\n\t\t\t\t// We currently do not handle the 'restrict' case in the core because it should prevent the parent item from being deleted but that is not\n\t\t\t\t// something that ever happens in the frontend currently (the server does properly handle this)\n\t\t\t\t// Since we don't update any fields we also don't need to check child items\n\t\t\t} else if (rule === 'set_null') {\n\t\t\t\tconst fields = {\n\t\t\t\t\t[linkColumnId]: null,\n\t\t\t\t} as Partial<FieldMap<ItemTypeType>>;\n\n\t\t\t\tif (changesDelta instanceof ChangesDelta) {\n\t\t\t\t\tchangesDelta.setItemUpdated(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\tfields,\n\t\t\t\t\t\tnull,\n\t\t\t\t\t\tnull,\n\t\t\t\t\t\t'KEEP_WHEN_DIFFERENT',\n\t\t\t\t\t);\n\t\t\t\t} else if (changesDelta instanceof ParentChangesDelta) {\n\t\t\t\t\tchangesDelta.setItemUpdated(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\tfields,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t[linkColumnId]: parentItemId,\n\t\t\t\t\t\t} as Partial<FieldMap<ItemTypeType>>,\n\t\t\t\t\t\t'KEEP_WHEN_DIFFERENT',\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tchangesDelta.setItemUpdated(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\tfields,\n\t\t\t\t\t\t'KEEP_WHEN_DIFFERENT',\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else if (rule === 'cascade') {\n\t\t\t\tif (changesDelta instanceof ChildChangesDelta) {\n\t\t\t\t\tchangesDelta.setItemDeleted(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tentry: itemEntry,\n\t\t\t\t\t\t\tchanges: this.itemHandler.itemChanges[itemEntry.id],\n\t\t\t\t\t\t\tisCascaded: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t} else if (changesDelta instanceof ParentChangesDelta) {\n\t\t\t\t\tchangesDelta.setItemDeleted(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tchangesDelta.setItemDeletedCascaded(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tconst influencedItemTypes = ApiFieldsOnDeleteRule[itemEntry.itemType]?.foreign ?? {};\n\n\t\t\t\t// Since the item gets deleted, we should cascade the delete\n\t\t\t\tfor (const influencedItemType in influencedItemTypes) {\n\t\t\t\t\tfor (const columnId of influencedItemTypes[influencedItemType]) {\n\t\t\t\t\t\tthis.cascadeDeleteByItemType(\n\t\t\t\t\t\t\tchangesDelta,\n\t\t\t\t\t\t\tinfluencedItemType as ApiItemType,\n\t\t\t\t\t\t\tcolumnId,\n\t\t\t\t\t\t\titemEntry.itemId,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n}\n","import { ApiFieldsOnDeleteRule, ApiItemType, ItemId } from '@rentman/backend-types';\nimport { AbstractCache, ApiLinkTreeType, ApiRequestColumnArray, ApiRequestColumnMap, ApiRequestColumns, ApiResponseProcessor, CachedQueryItem, ChangesDelta, ChangesDeltaBase, ChangesDeltaItemUpdateMode, ChangesDeltaResult, ChangesProcessor, CollectionQuery, CollectionResource, ColumnInfo, ConversionMap, DeregFunction, EntryParent, FieldMap, ItemEntry, ItemIdConversionMap, ItemTypeColumnId, MutableApiRequestColumnArray, OnAfterCreateCallback, ParentChangesDelta, RequestBufferManager, RequestColumnExpansion, ResponseColumnItemTypeMap, ResponseItemUpdateModeMap, RmCore, ServerCacheDependencyInterface, ServerCachedQueryHandler, ServerItemHandler, TransactionCache, TransactionOptions, TransactionValidatorFactory } from '../../../internal';\n\ntype OnDeltaAppliedCallback = (\n\tdelta: ChangesDeltaBase,\n) => unknown;\n\nexport type ActiveItemEntries = Set<ItemEntry>;\n\n/**\n * @description\n * The {@link ServerCache ServerCache} is responsible for keeping track of {@link ItemEntry ItemEntries} and {@link CollectionEntry CollectionEntries}\n * which are saved on the server.\n *\n * It's basically a local representation of the database\n */\nexport class ServerCache\n\textends AbstractCache {\n\n\tpublic readonly requestBufferManager: RequestBufferManager;\n\tpublic readonly itemHandler: ServerItemHandler;\n\tpublic readonly cachedQueryHandler: ServerCachedQueryHandler;\n\n\tpublic onDeltaAppliedCallbacks: OnDeltaAppliedCallback[] = [];\n\n\tpublic parent: null = null;\n\n\tpublic constructor (\n\t\tpublic dependencies: ServerCacheDependencyInterface,\n\t\tprivate apiFieldsOnDeleteRule: typeof ApiFieldsOnDeleteRule,\n\t\tcore: RmCore,\n\t) {\n\t\tsuper(\n\t\t\tdependencies,\n\t\t\tcore,\n\t\t);\n\n\t\tthis.requestBufferManager = new RequestBufferManager(\n\t\t\tdependencies.apiRequestService,\n\t\t\tdependencies.requestColumnExpansionFactory,\n\t\t\t(\n\t\t\t\t{\n\t\t\t\t\trequestColumns,\n\t\t\t\t\tresponse,\n\t\t\t\t\tnonLocallyMatchableQueryString,\n\t\t\t\t},\n\t\t\t) => {\n\t\t\t\tconst changesDelta = this.dependencies.changesDeltaFactory.construct(\n\t\t\t\t\tfalse,\n\t\t\t\t\t[\n\t\t\t\t\t\tresponse.itemType,\n\t\t\t\t\t],\n\t\t\t\t);\n\n\t\t\t\tif (nonLocallyMatchableQueryString !== null) {\n\t\t\t\t\tchangesDelta._setQueryResult(\n\t\t\t\t\t\tresponse.itemType,\n\t\t\t\t\t\tnonLocallyMatchableQueryString,\n\t\t\t\t\t\tresponse.links[response.itemType],\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn this.applyChangesDelta(\n\t\t\t\t\tthis.processResponse(\n\t\t\t\t\t\tresponse,\n\t\t\t\t\t\trequestColumns,\n\t\t\t\t\t\tchangesDelta,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t},\n\t\t);\n\n\t\tthis.itemHandler = new ServerItemHandler(\n\t\t\tdependencies.errorHandler,\n\t\t\tdependencies.columnCache,\n\t\t\tdependencies.itemCacheFactory,\n\t\t\tdependencies.itemEntryService,\n\t\t\tdependencies.requestColumnExpansionFactory,\n\t\t\tdependencies.requestColumnsOperationsCacheFactory,\n\t\t\tthis,\n\t\t);\n\n\t\tthis.cachedQueryHandler = new ServerCachedQueryHandler(\n\t\t\tdependencies,\n\t\t\tthis,\n\t\t);\n\t}\n\n\tpublic onDeltaApplied (\n\t\tcallback: OnDeltaAppliedCallback,\n\t): DeregFunction {\n\t\tthis.onDeltaAppliedCallbacks.push(\n\t\t\tcallback,\n\t\t);\n\n\t\treturn () => {\n\t\t\tconst index = this.onDeltaAppliedCallbacks.indexOf(\n\t\t\t\tcallback,\n\t\t\t);\n\n\t\t\tif (index !== -1) {\n\t\t\t\tthis.onDeltaAppliedCallbacks.splice(\n\t\t\t\t\tindex,\n\t\t\t\t\t1,\n\t\t\t\t);\n\t\t\t}\n\t\t};\n\t}\n\n\tpublic getServerCache (): ServerCache {\n\t\treturn this;\n\t}\n\n\t// WARNING: createChild is not in AbstractCache to prevent a circular dependency between AbstractCache <-> TransactionCache\n\tpublic createChild (\n\t\tid?: string,\n\t\tvalidatorFactory?: TransactionValidatorFactory,\n\t\toptions?: TransactionOptions,\n\t): TransactionCache {\n\t\tconst transaction = new TransactionCache(\n\t\t\tthis.dependencies,\n\t\t\tthis.core,\n\t\t\tthis,\n\t\t\tid,\n\t\t\tvalidatorFactory,\n\t\t\toptions,\n\t\t);\n\n\t\tthis.children.push(\n\t\t\ttransaction,\n\t\t);\n\n\t\treturn transaction;\n\t}\n\n\tpublic getActiveItemEntries (): ActiveItemEntries {\n\t\tconst result: ActiveItemEntries = new Set();\n\n\t\tfor (const transaction of this.getDescendantsIterator()) {\n\t\t\tfor (const activeItemResourceTuple of transaction.itemHandler.itemResourcesPerEntry) {\n\t\t\t\tconst hasActiveResources = activeItemResourceTuple[1].some(\n\t\t\t\t\titemResourceRef => itemResourceRef.deref() !== undefined,\n\t\t\t\t);\n\n\t\t\t\tif (!hasActiveResources) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst itemEntry = activeItemResourceTuple[0];\n\n\t\t\t\tthis.collectActiveItemEntriesBasedOnParentEntry(\n\t\t\t\t\ttransaction,\n\t\t\t\t\titemEntry,\n\t\t\t\t\titemEntry.columns.main,\n\t\t\t\t\tresult,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic processResponseByItemType<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\trequestColumns: ApiRequestColumns<ItemTypeType> | null,\n\t\tresponseColumns: ResponseColumnItemTypeMap,\n\t\tresponseItems: Iterable<FieldMap<ItemTypeType>>,\n\t\tchangesDelta: ChangesDelta,\n\t\titemUpdateModeMap?: {\n\t\t\t[itemId: string]: ChangesDeltaItemUpdateMode,\n\t\t},\n\t\tconversionMap?: ConversionMap,\n\t): ChangesDelta {\n\t\tconst columnSet = requestColumns !== null\n\t\t\t? this.dependencies.columnSetFactory.construct(\n\t\t\t\titemType,\n\t\t\t\trequestColumns,\n\t\t\t\tresponseColumns,\n\t\t\t)\n\t\t\t: this.dependencies.columnSetFactory.constructFromResponse(\n\t\t\t\titemType,\n\t\t\t\tfalse,\n\t\t\t\tresponseColumns,\n\t\t\t);\n\t\tconst columnExpansion = this.dependencies.columnExpansionFactory.construct(\n\t\t\titemType,\n\t\t\tcolumnSet.requestColumnsTrue\n\t\t\t\t? true\n\t\t\t\t: columnSet.request,\n\t\t\tresponseColumns,\n\t\t);\n\n\t\tfor (const fields of responseItems) {\n\t\t\tconst itemId = fields.id as ItemId;\n\n\t\t\tlet oldItemId: ItemId | undefined;\n\n\t\t\tif (conversionMap !== undefined) {\n\t\t\t\tfor (const convertedItemId in conversionMap) {\n\t\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\t\tif (conversionMap[convertedItemId] == itemId) {\n\t\t\t\t\t\toldItemId = Number(\n\t\t\t\t\t\t\tconvertedItemId,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// We should re-check if an entry is not created in the meantime\n\t\t\tif (\n\t\t\t\t!this.itemHandler.entries.contains(\n\t\t\t\t\titemType,\n\t\t\t\t\toldItemId ?? itemId,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tchangesDelta._setItemCreated(\n\t\t\t\t\titemId,\n\t\t\t\t\tfields,\n\t\t\t\t\tcolumnSet,\n\t\t\t\t\tnull,\n\t\t\t\t\tfalse,\n\t\t\t\t\ttrue,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tchangesDelta.setItemUpdated(\n\t\t\t\t\tthis.itemHandler.entries.get(\n\t\t\t\t\t\titemType,\n\t\t\t\t\t\toldItemId ?? itemId,\n\t\t\t\t\t),\n\t\t\t\t\tfields,\n\t\t\t\t\tcolumnExpansion,\n\t\t\t\t\tnull,\n\t\t\t\t\titemUpdateModeMap?.[itemId] ?? 'QUERY',\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn changesDelta;\n\t}\n\n\t/**\n\t *\n\t * @param response\n\t * @param requestColumnMap\n\t * @param isCalledAfterSocketUpdate\n\t * @param changesDelta\n\t * @param conversionMap\n\t * @param itemUpdateModeMap Allows you to overwrite the update mode for specific items, this is useful when you want to process the direct items of an update/create request\n\t */\n\tpublic processResponse (\n\t\tresponse: ApiResponseProcessor,\n\t\trequestColumnMap: ApiRequestColumnMap,\n\t\tchangesDelta: ChangesDelta = this.dependencies.changesDeltaFactory.construct(\n\t\t\tfalse,\n\t\t),\n\t\titemUpdateModeMap?: ResponseItemUpdateModeMap,\n\t\tconversionMap?: ItemIdConversionMap,\n\t): ChangesDelta {\n\t\tconst responseColumnsObject = response.fetchColumnsObject();\n\n\t\tfor (const itemType in responseColumnsObject) {\n\t\t\tthis.dependencies.columnCache.setColumns(\n\t\t\t\titemType as ApiItemType,\n\t\t\t\trequestColumnMap[itemType] as ApiRequestColumns<ApiItemType>,\n\t\t\t\tresponseColumnsObject,\n\t\t\t\t// This indicates that we did not apply a filter to the request columns, filters are only applicable\n\t\t\t\t// when doing a fields request. Because this is a query we want to indicate that we did not apply a\n\t\t\t\t// filter on the requested columns, which would have been the default value `false`. But since this is\n\t\t\t\t// not a fields request we are not guaranteed to get back all the columns when doing `columns: true`. So\n\t\t\t\t// we have to pretent we did filter so the column cache doesn't think we got all columns back.\n\t\t\t\t'not_false',\n\t\t\t);\n\t\t}\n\n\t\tfor (const itemType in response.items) {\n\t\t\tthis.processResponseByItemType(\n\t\t\t\titemType as ApiItemType,\n\t\t\t\titemType === response.itemType\n\t\t\t\t\t? requestColumnMap[itemType]\n\t\t\t\t\t: null,\n\t\t\t\tresponseColumnsObject,\n\t\t\t\tresponse.fetchObjectArray(\n\t\t\t\t\titemType as ApiItemType,\n\t\t\t\t\tnull,\n\t\t\t\t),\n\t\t\t\tchangesDelta,\n\t\t\t\titemUpdateModeMap?.[itemType],\n\t\t\t\tconversionMap?.[itemType],\n\t\t\t);\n\t\t}\n\n\t\treturn changesDelta;\n\t}\n\n\t/**\n\t * @description\n\t * Applies changes to this transaction and its children\n\t * ServerCache.applyChangesFromParent should be used when processing an API update/create/delete\n\t *\n\t * `applyChangesFromParent` assumes that all derived values are already fetched and won't attempt to resolve them\n\t * (which `applyChangesDelta` does)\n\t */\n\t// TODO: This function is called for move and delete requests, but not for create and update requests.\n\tpublic async applyChangesFromParent (\n\t\tchangesDelta: ParentChangesDelta,\n\t\tisCalledAfterSocketUpdate: boolean = false,\n\t): Promise<void> {\n\t\tconst parentChangesDelta = this.dependencies.changesDeltaFactory.constructParentDelta(\n\t\t\tchangesDelta,\n\t\t);\n\n\t\tthis.handleCascadingDeletes(\n\t\t\tchangesDelta,\n\t\t);\n\n\t\tthis.itemHandler.processUpdatesFromDelta(\n\t\t\tchangesDelta.updated,\n\t\t\tparentChangesDelta,\n\t\t);\n\n\t\tfor (const itemEntry of changesDelta.getDeletedItemEntriesIterator()) {\n\t\t\tparentChangesDelta.setItemDeleted(\n\t\t\t\titemEntry,\n\t\t\t);\n\t\t}\n\n\t\tconst matchingResults = await this.cachedQueryHandler.matchItemsToCollectionQueries(\n\t\t\tparentChangesDelta,\n\t\t\tparentChangesDelta._queryItemTypeSet,\n\t\t\tfalse,\n\t\t);\n\n\t\tthis.cachedQueryHandler.applyMatchingResultsToCachedQueries(\n\t\t\tmatchingResults,\n\t\t);\n\n\t\tawait Promise.all(\n\t\t\tthis.children.map(\n\t\t\t\tchildTransaction => childTransaction.applyChangesFromParent(\n\t\t\t\t\tparentChangesDelta,\n\t\t\t\t\tisCalledAfterSocketUpdate,\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\n\t\t// We call this before actually removing the entries from the serverCache so that any callback\n\t\t// can still look up the ItemEntry (to use ItemEntry.id)\n\t\tthis.callOnDeltaAppliedCallbacks(\n\t\t\tparentChangesDelta,\n\t\t);\n\n\t\t// It's important that we only actually remove the values of items\n\t\t// *after* all sub-transactions have been processed and items have been removed from collections.\n\t\t// If we don't do this we will get a bunch of errors in getDerivedValue calls because the template\n\t\t// engine will call this during rerenders\n\t\tfor (const itemEntry of changesDelta.getDeletedItemEntriesIterator()) {\n\t\t\tthis.clearItemEntry(\n\t\t\t\titemEntry,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * @description\n\t * Gets the fields required to set the parent\n\t */\n\tpublic getLinkFieldsByParent<const ItemTypeType extends ApiItemType> (\n\t\tparent: EntryParent,\n\t\titemType: ItemTypeType,\n\t): Partial<FieldMap<ItemTypeType>> {\n\t\tconst linkTree = this.dependencies.linkTreeService.get();\n\t\tconst linkTreeEntry = linkTree[parent.itemType][itemType];\n\t\tconst result: Partial<FieldMap<ItemTypeType>> = {};\n\n\t\tif (linkTreeEntry === undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t`Non existing link between '${parent.itemType}'->'${itemType}'`,\n\t\t\t);\n\t\t}\n\n\t\tif (linkTreeEntry.type === ApiLinkTreeType.DIRECT) {\n\t\t\tresult[linkTreeEntry.field] = parent.itemId;\n\t\t} else {\n\t\t\t// @ts-ignore\n\t\t\tresult.itemtype = parent.itemType;\n\t\t\t// @ts-ignore\n\t\t\tresult.item = parent.itemId;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic getCollectionChangesRecursively<const ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tparsedQuery: CollectionQuery<ItemTypeType>,\n\t): CachedQueryItem<ItemTypeType> | undefined {\n\t\treturn this.cachedQueryHandler.getCachedQueryItem(\n\t\t\titemType,\n\t\t\tparsedQuery.string,\n\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Merges the passed changes from the child Transaction into this Transaction's own changes and then propagates\n\t * them to all child Transactions\n\t */\n\tpublic applyChangesFromChild (\n\t\ttransaction: TransactionCache,\n\t\tbreakUpByParent?: boolean,\n\t\tonAfterCreateCallback?: OnAfterCreateCallback,\n\t): Promise<ItemIdConversionMap> {\n\t\t// todo[cache] shouldn't this do everything from TransactionCache.save ?\n\t\tconst depenencies = this.dependencies;\n\n\t\treturn new ChangesProcessor(\n\t\t\tdepenencies.apiRequestService,\n\t\t\tdepenencies.changesCompilationFactory,\n\t\t\tdepenencies.changesDeltaFactory,\n\t\t\tdepenencies.errorHandler,\n\t\t\tthis.requestBufferManager,\n\t\t\tdepenencies.requestColumnExpansionFactory,\n\t\t\ttransaction,\n\t\t\tbreakUpByParent,\n\t\t\tonAfterCreateCallback,\n\t\t)\n\t\t\t.execute();\n\t}\n\n\t/**\n\t * @description\n\t * Applies changes to this transaction and its children\n\t * ServerCache.applyChangesDelta should be used when processing an API response which should create new entries on the ServerCache (such as a Query)\n\t *\n\t * `applyChangesDelta` also ensures any required derived values are properly fetched\n\t * (which `applyChangesFromParent` doesn't)\n\t */\n\tpublic async applyChangesDelta (\n\t\tchangesDelta: ChangesDelta,\n\t\tisCalledAfterSocketUpdate: boolean = false,\n\t\tconversionMap?: ItemIdConversionMap,\n\t): Promise<ChangesDeltaResult> {\n\t\tif (changesDelta.isEmpty()) {\n\t\t\treturn {\n\t\t\t\tchangesDelta,\n\t\t\t\tcreated: [],\n\t\t\t\tallChildrenDonePromise: Promise.resolve(),\n\t\t\t};\n\t\t}\n\n\t\tthis.handleCascadingDeletes(\n\t\t\tchangesDelta,\n\t\t);\n\n\t\tconst parentChangesDelta = this.dependencies.changesDeltaFactory.constructParentDelta(\n\t\t\tchangesDelta,\n\t\t);\n\t\tconst createdEntries: ItemEntry[] = [];\n\n\t\t// We only create new entries on the direct transaction, not on the children\n\t\tchangesDelta.created.forEach(\n\t\t\ttuple => {\n\t\t\t\tconst itemEntry = this.processCreatedItem(\n\t\t\t\t\ttuple,\n\t\t\t\t\tchangesDelta,\n\t\t\t\t);\n\n\t\t\t\tif (itemEntry === null) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tcreatedEntries.push(\n\t\t\t\t\titemEntry,\n\t\t\t\t);\n\n\t\t\t\tparentChangesDelta.setItemCreated(\n\t\t\t\t\titemEntry,\n\t\t\t\t\tthis.itemHandler.itemChanges[itemEntry.id],\n\t\t\t\t);\n\t\t\t},\n\t\t);\n\n\t\tawait this.fetchUpdatedDerivedValuesFromDelta(\n\t\t\tchangesDelta,\n\t\t\tconversionMap,\n\t\t);\n\n\t\tthis.itemHandler.processUpdatesFromDelta(\n\t\t\tchangesDelta.updated,\n\t\t\tparentChangesDelta,\n\t\t);\n\n\t\tfor (const itemEntry of changesDelta.getDeletedItemEntriesIterator()) {\n\t\t\tparentChangesDelta.setItemDeleted(\n\t\t\t\titemEntry,\n\t\t\t);\n\t\t}\n\n\t\tconst matchingResults = await this.cachedQueryHandler.matchItemsToCollectionQueries(\n\t\t\tparentChangesDelta,\n\t\t\tparentChangesDelta._queryItemTypeSet,\n\t\t\ttrue,\n\t\t);\n\n\t\tthis.cachedQueryHandler.applyMatchingResultsToCachedQueries(\n\t\t\tmatchingResults,\n\t\t);\n\n\t\t// We call this before actually removing the entries from the cache so we're able to access the item in the\n\t\t// callback.\n\t\tthis.callOnDeltaAppliedCallbacks(\n\t\t\tparentChangesDelta,\n\t\t);\n\n\t\treturn {\n\t\t\tchangesDelta,\n\t\t\tcreated: createdEntries,\n\t\t\tallChildrenDonePromise: Promise\n\t\t\t\t.all(\n\t\t\t\t\tthis.children.map(\n\t\t\t\t\t\tchildTransaction => childTransaction.applyChangesFromParent(\n\t\t\t\t\t\t\tparentChangesDelta,\n\t\t\t\t\t\t\tisCalledAfterSocketUpdate,\n\t\t\t\t\t\t\tconversionMap,\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\t.then(\n\t\t\t\t\t() => {\n\t\t\t\t\t\t// It's important that we only actually remove the values of items *after* all sub-transactions have been\n\t\t\t\t\t\t// processed and items have been removed from collections. This is because the query matcher uses the fields\n\t\t\t\t\t\t// to quickly determine what collections an item is in.\n\t\t\t\t\t\tfor (const itemEntry of changesDelta.getDeletedItemEntriesIterator()) {\n\t\t\t\t\t\t\tthis.clearItemEntry(\n\t\t\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t};\n\t}\n\n\tpublic getLocalItemEntry (\n\t\titemEntryId: ItemEntry['id'],\n\t): ItemEntry {\n\t\treturn this.itemHandler.entries.getByEntryId(\n\t\t\titemEntryId,\n\t\t);\n\t}\n\n\tpublic getLocalItemEntryByItemId<const ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\titemId: ItemEntry<ItemTypeType>['itemId'],\n\t): ItemEntry<ItemTypeType> {\n\t\treturn this.itemHandler.entries.get(\n\t\t\titemType,\n\t\t\titemId,\n\t\t);\n\t}\n\n\tpublic containsLocalItemEntryByItemId (\n\t\titemType: ApiItemType,\n\t\titemId: ItemEntry['itemId'],\n\t): boolean {\n\t\treturn this.itemHandler.entries.contains(\n\t\t\titemType,\n\t\t\titemId,\n\t\t);\n\t}\n\n\t/**\n\t * Merged the request columns with columns required for delete relations and the query matcher.\n\t * This method is in the server cache because the queries contain the superset of all columns here.\n\t *\n\t * Please note that this function is usually called in the request columns operation cache.\n\t */\n\tpublic expandColumnsWithRequiredColumns<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\trequestColumns: ApiRequestColumns<ItemTypeType>,\n\t): ApiRequestColumns<ItemTypeType> {\n\t\tconst requestColumnExpansion = this.dependencies.requestColumnExpansionFactory.construct();\n\n\t\trequestColumnExpansion.expandWithRequestColumns(\n\t\t\titemType,\n\t\t\trequestColumns,\n\t\t);\n\n\t\treturn this.expandColumnExpansionWithRequiredColumns<ItemTypeType>(\n\t\t\titemType,\n\t\t\trequestColumnExpansion,\n\t\t\tthis.cachedQueryHandler.getCachedQueryItemsByItemType(\n\t\t\t\titemType,\n\t\t\t),\n\t\t\tthis.cachedQueryHandler.getUncachedCollectionsOnChildTransactionsIterator(\n\t\t\t\titemType,\n\t\t\t),\n\t\t);\n\t}\n\n\tpublic expandColumnExpansionWithRequiredColumns<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\trequestColumnExpansion: RequestColumnExpansion,\n\t\tcachedQueryItems: Iterable<CachedQueryItem<ItemTypeType>>,\n\t\tuncachedCollectionResources: Iterable<CollectionResource<ItemTypeType>>,\n\t): ApiRequestColumns<ItemTypeType> {\n\t\t// We always want to fetch these so they are available in the fields RM4-14711\n\t\trequestColumnExpansion.expandWithRequestColumns(\n\t\t\titemType,\n\t\t\t[\n\t\t\t\t'id',\n\t\t\t\t'permissions',\n\t\t\t\t'modified',\n\t\t\t],\n\t\t);\n\n\t\t// If there's a delete relation we should make sure that we have those columns\n\t\trequestColumnExpansion.expandWithRequestColumns(\n\t\t\titemType,\n\t\t\tthis.getColumnIdsWithRelations(\n\t\t\t\titemType,\n\t\t\t),\n\t\t);\n\n\t\tfor (const cachedQueryItem of cachedQueryItems) {\n\t\t\trequestColumnExpansion.expandWithRequestColumnsTuple(\n\t\t\t\titemType,\n\t\t\t\tcachedQueryItem.requestColumnsTuple,\n\t\t\t);\n\t\t}\n\n\t\tfor (const collectionResource of uncachedCollectionResources) {\n\t\t\trequestColumnExpansion.expandWithColumnSet(\n\t\t\t\tcollectionResource.entry.columns,\n\t\t\t);\n\t\t}\n\n\t\treturn requestColumnExpansion.get()[itemType] as ApiRequestColumns<ItemTypeType>;\n\t}\n\n\tprivate getColumnIdsWithRelations<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t): ApiRequestColumnArray<ItemTypeType> {\n\t\tconst onDeleteColumns = this.apiFieldsOnDeleteRule[itemType]?.own;\n\n\t\tif (onDeleteColumns === undefined) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst result: MutableApiRequestColumnArray<ItemTypeType> = [];\n\n\t\tfor (const columnId in onDeleteColumns) {\n\t\t\t// Since we do not handle the `restrict` case we don't need to include those columns in the request\n\t\t\tif (onDeleteColumns[columnId].onDeleteRule !== 'restrict') {\n\t\t\t\tresult.push(\n\t\t\t\t\tcolumnId as ItemTypeColumnId<ItemTypeType>,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate callOnDeltaAppliedCallbacks (\n\t\tdelta: ChangesDeltaBase,\n\t): void {\n\t\tthis.onDeltaAppliedCallbacks.forEach(\n\t\t\tcallback => callback(\n\t\t\t\tdelta,\n\t\t\t),\n\t\t);\n\t}\n\n\tprivate collectActiveItemEntriesBasedOnParentEntry (\n\t\ttransaction: TransactionCache,\n\t\titemEntry: ItemEntry,\n\t\titemLikeColumns: ColumnInfo[],\n\t\tactiveItemEntryAccumulator: ActiveItemEntries,\n\t): void {\n\t\tif (\n\t\t\tactiveItemEntryAccumulator.has(\n\t\t\t\titemEntry,\n\t\t\t)\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\t// We eagerly mark it as processed, so that we skip it if we encounter the same itemEntry again in a derived loop\n\t\tactiveItemEntryAccumulator.add(\n\t\t\titemEntry,\n\t\t);\n\n\t\t// When an item is active and it uses derived values, we should also mark all these derived items as active,\n\t\t// even if there are no ItemResources directly for those items.\n\t\t// If we don't, then these derived values won't properly be updated after receiving a socket message.\n\t\tfor (const parentColumn of itemLikeColumns) {\n\t\t\tif (parentColumn.children.length === 0) {\n\t\t\t\t// It can be that we request an item like field, but request no derived columns of it\n\t\t\t\t// In that case we don't have an ItemEntry for it, so we just skip it\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst derivedItemId = transaction.itemHandler.lookUpItemField(\n\t\t\t\titemEntry,\n\t\t\t\tparentColumn.id,\n\t\t\t);\n\n\t\t\tif (derivedItemId === null) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlet derivedItemEntry: ItemEntry;\n\n\t\t\ttry {\n\t\t\t\tderivedItemEntry = transaction.getLocalItemEntryByItemId(\n\t\t\t\t\tparentColumn.apiColumn.itemType as ApiItemType,\n\t\t\t\t\tderivedItemId,\n\t\t\t\t);\n\t\t\t} catch (e) {\n\t\t\t\tthis.dependencies.errorHandler.logError(\n\t\t\t\t\te,\n\t\t\t\t);\n\n\t\t\t\t// If for whatever reason we cannot find this entry (which shouldn't happen because of the `children` check above),\n\t\t\t\t// we just skip it instead of erroring.\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// We continue the derived path to mark any entry used by the root item as active\n\t\t\tthis.collectActiveItemEntriesBasedOnParentEntry(\n\t\t\t\ttransaction,\n\t\t\t\tderivedItemEntry,\n\t\t\t\tparentColumn.children,\n\t\t\t\tactiveItemEntryAccumulator,\n\t\t\t);\n\t\t}\n\t}\n\n}\n","// eslint-disable-next-line max-classes-per-file\nimport { ApiItemType } from '@rentman/backend-types';\nimport { ItemEntry } from '../../models/ItemEntry';\nimport { GetFieldValueType, ItemTypeColumnId } from '../../types/ItemTypesCollection';\nimport { GetField, LeafQueryNode, MatchesAccumulator, MatchesAccumulatorTuple } from '../matcher/QueryNode';\nimport { RootQueryNode } from '../matcher/RootQueryNode';\nimport { ParentChangesDelta } from '../ParentChangesDelta';\n\nexport type GetMergedQueryGraph = <ItemTypeType extends ApiItemType> (\n\titemType: ItemTypeType,\n) => RootQueryNode<ItemTypeType> | null;\n\nexport interface MatchingResultsAccumulatorTuple<ItemTypeType extends ApiItemType>\n\textends MatchesAccumulatorTuple<ItemEntry<ItemTypeType>> {\n\n\tfalse?: Set<ItemEntry<ItemTypeType>>,\n}\n\n/**\n * This type is similar to {@link MatchesAccumulator} by design, so we can pass it directly to the match function\n * when matching created items.\n */\ntype MatchingResultsAccumulator<ItemTypeType extends ApiItemType> = Map<\n\tstring,\n\tMatchingResultsAccumulatorTuple<ItemTypeType>\n>;\n\nexport type MatchingResultsAccumulatorMapType = {\n\t[ItemType in ApiItemType]?: MatchingResultsAccumulator<ItemType>;\n};\n\ntype MatchesAccumulatorMapType = {\n\t[ItemType in ApiItemType]?: MatchesAccumulator<ItemEntry<ItemType>>;\n};\n\n/**\n * A convenience class to group matches accumulators by item type.\n */\nexport class MatchesAccumulatorMap<\n\tItemTypeMapType extends {\n\t\t[ItemType in ApiItemType]?: any;\n\t}\n> {\n\n\tprivate entries: ItemTypeMapType = {} as ItemTypeMapType;\n\n\tpublic get<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t): Exclude<ItemTypeMapType[ItemTypeType], undefined> {\n\t\tconst entries = this.entries;\n\n\t\treturn entries[itemType] !== undefined\n\t\t\t? entries[itemType]\n\t\t\t: entries[itemType] = new Map() as Exclude<ItemTypeMapType[ItemTypeType], undefined>;\n\t}\n\n\tpublic* [Symbol.iterator] (): Generator<\n\t\t[\n\t\t\tApiItemType,\n\t\t\tExclude<ItemTypeMapType[ApiItemType], undefined>\n\t\t]\n\t> {\n\t\tfor (const itemType in this.entries) {\n\t\t\tyield [\n\t\t\t\titemType as ApiItemType,\n\t\t\t\tthis.entries[itemType] as Exclude<ItemTypeMapType[ApiItemType], undefined>,\n\t\t\t];\n\t\t}\n\t}\n\n}\n\nexport abstract class ItemMatcherBase {\n\n\t/**\n\t * Convenience method to quickly add items entries to a matching results accumulator tuple. Will create a tuple\n\t * if none exists yet.\n\t *\n\t * The matching results accumulator is a map, so we can't define this on the class itself.\n\t */\n\tprivate static addItemsToMatchingResults<ItemTypeType extends ApiItemType> (\n\t\tmatchingResultsAccumulator: MatchingResultsAccumulator<ItemTypeType>,\n\t\tqueryString: string,\n\t\tisMatchKey: keyof MatchingResultsAccumulatorTuple<any>,\n\t\titemEntries: Iterable<ItemEntry<ItemTypeType>>,\n\t): void {\n\t\tlet matchingResultsTuple = matchingResultsAccumulator.get(\n\t\t\tqueryString,\n\t\t);\n\n\t\tif (matchingResultsTuple === undefined) {\n\t\t\tmatchingResultsAccumulator.set(\n\t\t\t\tqueryString,\n\t\t\t\tmatchingResultsTuple = {\n\t\t\t\t\ttrue: new Set(),\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\tlet itemSet = matchingResultsTuple[isMatchKey];\n\n\t\tif (itemSet === undefined) {\n\t\t\titemSet = matchingResultsTuple[isMatchKey] = new Set();\n\t\t}\n\n\t\tfor (const itemEntry of itemEntries) {\n\t\t\titemSet.add(\n\t\t\t\titemEntry,\n\t\t\t);\n\t\t}\n\t}\n\n\tpublic abstract constructGetField<ItemTypeType extends ApiItemType> (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t): GetField<ItemTypeType>;\n\n\tpublic abstract lookUpItemField<ItemTypeType extends ApiItemType, ColumnId extends ItemTypeColumnId<ItemTypeType>> (\n\t\tentry: ItemEntry<ItemTypeType>,\n\t\tcolumnId: ColumnId,\n\t): GetFieldValueType<ItemTypeType, ColumnId> | undefined;\n\n\t/**\n\t * For deleted items, we're determining the collections the item is currently in by matching using the current\n\t * fields. This means this method should run *before* the fields are removed from the cache.\n\t *\n\t * In order to limit back-end requests, we treat 'maybe' matches as a proper match. This means we might try to\n\t * remove items from collections that don't contain the item.\n\t */\n\tpublic matchItemsInDeletedChangesDelta (\n\t\tchangesDelta: ParentChangesDelta,\n\t\tgetMergedQueryGraph: GetMergedQueryGraph,\n\t\tmatchingResultsAccumulatorMap: MatchesAccumulatorMap<MatchingResultsAccumulatorMapType>,\n\t): void {\n\t\tconst matchesAccumulatorMap = new MatchesAccumulatorMap<MatchesAccumulatorMapType>();\n\n\t\tfor (const itemType of changesDelta.getDeletedItemTypesIterator()) {\n\t\t\tconst mergedQueryGraph = getMergedQueryGraph(\n\t\t\t\titemType,\n\t\t\t);\n\n\t\t\tif (mergedQueryGraph === null) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst deletedItemEntriesIterator = changesDelta.getDeletedItemEntriesIterator(\n\t\t\t\titemType,\n\t\t\t);\n\t\t\tconst matchesAccumulator = matchesAccumulatorMap.get(\n\t\t\t\titemType,\n\t\t\t) as MatchesAccumulator<ItemEntry<any>>;\n\n\t\t\tfor (const itemEntry of deletedItemEntriesIterator) {\n\t\t\t\tmergedQueryGraph.doMatch(\n\t\t\t\t\titemEntry,\n\t\t\t\t\t// We're matching using the current fields to quickly retrieve the collections the item is currently\n\t\t\t\t\t// in. We're using a lookup proxy here because there should be a low amount of field queries.\n\t\t\t\t\tthis.constructGetField(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t),\n\t\t\t\t\tmatchesAccumulator,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// Copy every match from the matches accumulator to the matching results accumulator. `true` and `maybe` both\n\t\t// become `false`, since we're dealing with items that should be removed from collections.\n\t\tfor (const matchesAccumulatorMapEntry of matchesAccumulatorMap) {\n\t\t\tconst matchingResultsAccumulator = matchingResultsAccumulatorMap.get(\n\t\t\t\tmatchesAccumulatorMapEntry[0],\n\t\t\t);\n\n\t\t\tfor (const matchesAccumulatorEntry of matchesAccumulatorMapEntry[1].entries()) {\n\t\t\t\tconst matchesAccumulatorTuple = matchesAccumulatorEntry[1] as MatchesAccumulatorTuple<ItemEntry<any>>;\n\n\t\t\t\tItemMatcherBase.addItemsToMatchingResults(\n\t\t\t\t\tmatchingResultsAccumulator as MatchesAccumulator<any>,\n\t\t\t\t\tmatchesAccumulatorEntry[0],\n\t\t\t\t\t'false',\n\t\t\t\t\tmatchesAccumulatorTuple.maybe === undefined\n\t\t\t\t\t\t? matchesAccumulatorTuple.true\n\t\t\t\t\t\t: [\n\t\t\t\t\t\t\t...matchesAccumulatorTuple.true,\n\t\t\t\t\t\t\t// We treat 'maybe' matches as a proper match.\n\t\t\t\t\t\t\t...matchesAccumulatorTuple.maybe,\n\t\t\t\t\t\t],\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Convenience method to match multiple item entries to a single query graph. If you want to match item entries to\n\t * multiple query graphs, it would be better to merge them first.\n\t */\n\tpublic matchItemsToQueryGraph<ItemTypeType extends ApiItemType> (\n\t\tqueryGraph: RootQueryNode<ItemTypeType>,\n\t\tleafNode: LeafQueryNode,\n\t\titemEntries: ItemEntry<ItemTypeType>[],\n\t\tmatchesAccumulatorTuple: MatchesAccumulatorTuple<ItemEntry<ItemTypeType>> = {\n\t\t\ttrue: new Set(),\n\t\t},\n\t): MatchesAccumulatorTuple<ItemEntry<ItemTypeType>> {\n\t\tconst matchesAccumulator: MatchesAccumulator<ItemEntry<ItemTypeType>> = new Map(\n\t\t\t[\n\t\t\t\t[\n\t\t\t\t\tleafNode.string,\n\t\t\t\t\tmatchesAccumulatorTuple,\n\t\t\t\t],\n\t\t\t],\n\t\t);\n\n\t\tfor (const itemEntry of itemEntries) {\n\t\t\tqueryGraph.doMatch(\n\t\t\t\titemEntry,\n\t\t\t\tthis.constructGetField(\n\t\t\t\t\titemEntry,\n\t\t\t\t),\n\t\t\t\tmatchesAccumulator,\n\t\t\t);\n\t\t}\n\n\t\treturn matchesAccumulatorTuple;\n\t}\n\n\t/**\n\t * Empty updates (where `previous` is `null`) are used:\n\t * - When adding items to newly created cached queries on the server cache;\n\t * - When restoring previously deleted items.\n\t *\n\t * Note that this method:\n\t * - Only adds items (because we technically don't have any changes).\n\t * - Discards 'maybe' matches. (Again, because we technically don't have any changes. When populating a non-locally\n\t * matchable query, the query results should be added to the query graph.)\n\t * - Does not check whether the items are deleted (we don't store deleted items on the server cache and restored\n\t * items are by definition no longer deleted).\n\t */\n\tpublic matchEmptyItemsInUpdatedChangesDelta (\n\t\tupdatedChangesDelta: ParentChangesDelta['updated'],\n\t\tgetMergedQueryGraph: GetMergedQueryGraph,\n\t\tmatchingResultsAccumulatorMap: MatchesAccumulatorMap<MatchingResultsAccumulatorMapType>,\n\t): void {\n\t\tconst matchesAccumulatorMap = new MatchesAccumulatorMap<MatchesAccumulatorMapType>();\n\n\t\t// TODO: We should really group updates by item type.\n\t\tfor (const itemEntryId in updatedChangesDelta) {\n\t\t\tconst tuple = updatedChangesDelta[itemEntryId];\n\n\t\t\tif (tuple.previous !== null) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst itemEntry = tuple.entry;\n\t\t\tconst mergedQueryGraph = getMergedQueryGraph(\n\t\t\t\titemEntry.itemType as ApiItemType,\n\t\t\t);\n\n\t\t\tif (mergedQueryGraph === null) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tmergedQueryGraph.doMatch(\n\t\t\t\titemEntry,\n\t\t\t\tthis.constructGetField(\n\t\t\t\t\titemEntry,\n\t\t\t\t),\n\t\t\t\tmatchingResultsAccumulatorMap.get(\n\t\t\t\t\titemEntry.itemType as ApiItemType,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\tfor (const matchesAccumulatorMapEntry of matchesAccumulatorMap) {\n\t\t\tconst matchingResultsAccumulator = matchingResultsAccumulatorMap.get(\n\t\t\t\tmatchesAccumulatorMapEntry[0],\n\t\t\t) as MatchesAccumulator<ItemEntry<any>>;\n\n\t\t\tfor (const matchesAccumulatorEntry of matchesAccumulatorMapEntry[1].entries()) {\n\t\t\t\tItemMatcherBase.addItemsToMatchingResults(\n\t\t\t\t\tmatchingResultsAccumulator,\n\t\t\t\t\tmatchesAccumulatorEntry[0],\n\t\t\t\t\t'true',\n\t\t\t\t\tmatchesAccumulatorEntry[1].true,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * For updated items, we match using the current fields first, then using the updated fields.\n\t * - When the item matches using the updated fields it will always be added. This is because on the server cache,\n\t * we always want to add the item to possible newly created cached queries, even if there are changes. This means\n\t * that we might add items to collections that already contain the item.\n\t * - When the item matches using the current fields, but does not when using the updated ones, it should be removed.\n\t * - In order to limit back-end requests, we consider 'maybe' only for the updated fields. For the current fields,\n\t * we treat 'maybe' as a proper match. This means we might try to remove items from collections that don't contain\n\t * the item.\n\t *\n\t * This method should be optimized for simple operations on large amounts of items, e.g. moving many Missings from\n\t * an 'origin' to a 'destination' status. In this case:\n\t * - A queries matched for the current and updated fields don't overlap;\n\t * - No `maybe` matches should be involved.\n\t */\n\tpublic matchItemsInUpdatedChangesDelta (\n\t\tupdatedChangesDelta: ParentChangesDelta['updated'],\n\t\tgetMergedQueryGraph: GetMergedQueryGraph,\n\t\tmatchingResultsAccumulatorMap: MatchesAccumulatorMap<MatchingResultsAccumulatorMapType>,\n\t): void {\n\t\tconst matchesAccumulatorMap: {\n\t\t\t[ItemType in ApiItemType]?: {\n\t\t\t\tcurrent: MatchesAccumulator<ItemEntry<ItemType>>,\n\t\t\t\tupdated: MatchesAccumulator<ItemEntry<ItemType>>,\n\t\t\t}\n\t\t} = {};\n\n\t\t// TODO: We should really group updates by item type.\n\t\tfor (const itemEntryId in updatedChangesDelta) {\n\t\t\tconst tuple = updatedChangesDelta[itemEntryId];\n\n\t\t\tif (tuple.previous === null) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst itemEntry = tuple.entry;\n\t\t\tconst itemType = itemEntry.itemType as ApiItemType;\n\t\t\tconst mergedQueryGraph = getMergedQueryGraph(\n\t\t\t\titemType,\n\t\t\t);\n\n\t\t\tif (mergedQueryGraph === null) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlet matchesAccumulatorTuple = matchesAccumulatorMap[itemType];\n\n\t\t\tif (matchesAccumulatorTuple === undefined) {\n\t\t\t\tmatchesAccumulatorTuple = matchesAccumulatorMap[itemType] = {\n\t\t\t\t\tcurrent: new Map(),\n\t\t\t\t\tupdated: new Map(),\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tmergedQueryGraph.doMatch(\n\t\t\t\titemEntry,\n\t\t\t\tcolumnId => {\n\t\t\t\t\tconst previousValue = tuple.previous![columnId];\n\n\t\t\t\t\treturn previousValue !== undefined\n\t\t\t\t\t\t? previousValue\n\t\t\t\t\t\t: this.lookUpItemField(\n\t\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\t\tcolumnId,\n\t\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t\tmatchesAccumulatorTuple.current,\n\t\t\t);\n\n\t\t\tmergedQueryGraph.doMatch(\n\t\t\t\titemEntry,\n\t\t\t\tcolumnId => {\n\t\t\t\t\tconst updatedValue = tuple.changes.fields[columnId];\n\n\t\t\t\t\treturn updatedValue !== undefined\n\t\t\t\t\t\t? updatedValue\n\t\t\t\t\t\t: this.lookUpItemField(\n\t\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\t\tcolumnId,\n\t\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t\tmatchesAccumulatorTuple.updated,\n\t\t\t);\n\t\t}\n\n\t\tfor (const itemType in matchesAccumulatorMap) {\n\t\t\tconst matchesAccumulatorTuple = matchesAccumulatorMap[itemType as ApiItemType]!;\n\t\t\tconst matchingResultsAccumulator = matchingResultsAccumulatorMap.get(\n\t\t\t\titemType as ApiItemType,\n\t\t\t);\n\n\t\t\tfor (const updatedMatchesAccumulatorEntry of matchesAccumulatorTuple.updated) {\n\t\t\t\tconst queryString = updatedMatchesAccumulatorEntry[0];\n\t\t\t\tconst updatedMatchesAccumulatorTuple = updatedMatchesAccumulatorEntry[1];\n\n\t\t\t\tif (updatedMatchesAccumulatorTuple.maybe !== undefined) {\n\t\t\t\t\tItemMatcherBase.addItemsToMatchingResults(\n\t\t\t\t\t\tmatchingResultsAccumulator as MatchingResultsAccumulator<any>,\n\t\t\t\t\t\tqueryString,\n\t\t\t\t\t\t'maybe',\n\t\t\t\t\t\tupdatedMatchesAccumulatorTuple.maybe,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tItemMatcherBase.addItemsToMatchingResults(\n\t\t\t\t\tmatchingResultsAccumulator as MatchingResultsAccumulator<any>,\n\t\t\t\t\tqueryString,\n\t\t\t\t\t'true',\n\t\t\t\t\tupdatedMatchesAccumulatorTuple.true,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tfor (const currentMatchesAccumulatorEntry of matchesAccumulatorTuple.current) {\n\t\t\t\tconst queryString = currentMatchesAccumulatorEntry[0];\n\t\t\t\tconst currentMatchesAccumulatorTuple = currentMatchesAccumulatorEntry[1];\n\t\t\t\tconst updatedMatchesAccumulatorTuple = matchesAccumulatorTuple.updated.get(\n\t\t\t\t\tqueryString,\n\t\t\t\t) as MatchesAccumulatorTuple<ItemEntry<any>>;\n\t\t\t\tconst matchedItemEntries: Iterable<ItemEntry> = currentMatchesAccumulatorTuple.maybe === undefined\n\t\t\t\t\t? currentMatchesAccumulatorTuple.true\n\t\t\t\t\t: [\n\t\t\t\t\t\t...currentMatchesAccumulatorTuple.true,\n\t\t\t\t\t\t// We treat 'maybe' matches using the current values as a proper match.\n\t\t\t\t\t\t...currentMatchesAccumulatorTuple.maybe,\n\t\t\t\t\t];\n\n\t\t\t\tif (updatedMatchesAccumulatorTuple === undefined) {\n\t\t\t\t\tItemMatcherBase.addItemsToMatchingResults(\n\t\t\t\t\t\tmatchingResultsAccumulator,\n\t\t\t\t\t\tqueryString,\n\t\t\t\t\t\t'false',\n\t\t\t\t\t\tmatchedItemEntries,\n\t\t\t\t\t);\n\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst nonFittingItemEntries: ItemEntry<any>[] = [];\n\n\t\t\t\tfor (const itemEntry of matchedItemEntries) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tupdatedMatchesAccumulatorTuple.true.has(\n\t\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\t)\n\t\t\t\t\t\t|| (\n\t\t\t\t\t\t\tupdatedMatchesAccumulatorTuple.maybe !== undefined\n\t\t\t\t\t\t\t&& updatedMatchesAccumulatorTuple.maybe.has(\n\t\t\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t)\n\t\t\t\t\t) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tnonFittingItemEntries.push(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif (nonFittingItemEntries.length > 0) {\n\t\t\t\t\tItemMatcherBase.addItemsToMatchingResults(\n\t\t\t\t\t\tmatchingResultsAccumulator,\n\t\t\t\t\t\tqueryString,\n\t\t\t\t\t\t'false',\n\t\t\t\t\t\tnonFittingItemEntries,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * For created items, we can write directly to the matching results accumulator.\n\t */\n\tpublic matchItemsInCreatedChangesDelta (\n\t\tcreatedChangesDelta: ParentChangesDelta['created'],\n\t\tgetMergedQueryGraph: GetMergedQueryGraph,\n\t\tmatchingResultsAccumulatorMap: MatchesAccumulatorMap<MatchingResultsAccumulatorMapType>,\n\t): void {\n\t\t// TODO: We should really group creates by item type.\n\t\tfor (const itemEntryId in createdChangesDelta) {\n\t\t\tconst tuple = createdChangesDelta[itemEntryId];\n\t\t\tconst itemType = tuple.entry.itemType;\n\t\t\tconst mergedQueryGraph = getMergedQueryGraph(\n\t\t\t\titemType,\n\t\t\t);\n\n\t\t\tif (mergedQueryGraph === null) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tmergedQueryGraph.doMatch(\n\t\t\t\ttuple.entry,\n\t\t\t\tcolumnId => tuple.fields[columnId],\n\t\t\t\tmatchingResultsAccumulatorMap.get(\n\t\t\t\t\titemType,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}\n\n\tpublic abstract itemIsDeleted<ItemTypeType extends ApiItemType> (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t): boolean;\n\n}\n","import { signal, WritableSignal } from '@angular/core';\nimport { ApiItemType, ItemId } from '@rentman/backend-types';\nimport { UnknownResponseColumn } from '@rentman/backend-types/dist/manual/api-response-column';\nimport { AbstractCache, ApiFormatter, ChangesDeltaBase, ChangesDeltaItemCreateDelta, COLUMN_SEPERATOR, ColumnCache, ColumnInfo, ColumnUtil, DerivedStringToRequestColumnPath, ErrorHandlerInterface, FieldMap, GetFieldValueType, ItemCache, ItemCacheFactory, ItemEntry, ItemEntryService, ItemMatcherBase, ItemTypeColumnId, RequestColumnExpansionFactory, RequestColumnsOperationsCache, RequestColumnsOperationsCacheFactory, ResolveDerivedValue, ResolveDerivedValues, SignalFieldMap } from '../../internal';\nimport { GetField } from '../matcher/QueryNode';\n\nexport interface ItemEntryChangesTuple<ItemTypeType extends ApiItemType> {\n\tentry: ItemEntry<ItemTypeType>,\n\tchanges: FieldMap<ItemTypeType>,\n}\n\nexport interface ItemHandlerFieldsProxyTarget<ItemTypeType extends ApiItemType> {\n\titemEntry: ItemEntry<ItemTypeType>,\n\titemHandler: ItemHandlerBase,\n}\n\n/**\n * We save the fields proxy handler as an instance property in order to ensure that all fields proxies of items\n * on this transaction (there can be many) will use the same proxy handler. Additionally, because the item entry\n * is stored the proxy target, we don't need to use a closure.\n */\nconst fieldsProxyHandler: ProxyHandler<ItemHandlerFieldsProxyTarget<any>> = {\n\tget: (\n\t\ttarget: ItemHandlerFieldsProxyTarget<any>,\n\t\tproperty: string,\n\t) => {\n\t\tconst result = target.itemHandler.lookUpItemField(\n\t\t\ttarget.itemEntry,\n\t\t\tproperty,\n\t\t);\n\n\t\t// todo: remove this when displayname is phased out, we don't want to put displayname on the transaction changes\n\t\t// since it's a readonly field which should never be on the transaction changes\n\t\tif (\n\t\t\tproperty === 'displayname'\n\t\t\t&& (\n\t\t\t\tresult === undefined\n\t\t\t\t// For local items it can be that we actually do have the required fields to create a displayname,\n\t\t\t\t// but because the actual column/data is also on the transaction (because readonly fields for local items are always stored there)\n\t\t\t\t// We also check for '' and attempt to manuall construct a displayname\n\t\t\t\t|| result === ''\n\t\t\t)\n\t\t) {\n\t\t\treturn target.itemHandler.getDisplayName(\n\t\t\t\ttarget.itemEntry,\n\t\t\t);\n\t\t}\n\n\t\treturn result;\n\t},\n};\n\nexport const fieldsSignalProxyHandler: ProxyHandler<ItemHandlerFieldsProxyTarget<any>> = {\n\tget: (\n\t\ttarget: ItemHandlerFieldsProxyTarget<any>,\n\t\tproperty: string,\n\t): WritableSignal<any> => {\n\t\treturn target.itemHandler.getItemFieldSignal(\n\t\t\ttarget.itemEntry,\n\t\t\tproperty,\n\t\t);\n\t},\n};\n\nexport abstract class ItemHandlerBase\n\textends ItemMatcherBase {\n\n\tpublic readonly entries: ItemCache;\n\n\tpublic itemChanges: {\n\t\t[itemEntryId: number]: FieldMap<any>,\n\t} = {};\n\n\tpublic itemFieldSignals: {\n\t\t[itemEntryId: number]: {\n\t\t\t[columnId: string]: WritableSignal<any>,\n\t\t},\n\t} = {};\n\n\tprotected constructor (\n\t\tprotected columnCache: ColumnCache,\n\t\tprotected errorHandler: ErrorHandlerInterface,\n\t\tprotected requestColumnExpansionFactory: RequestColumnExpansionFactory,\n\t\tprotected requestColumnsOperationsCacheFactory: RequestColumnsOperationsCacheFactory,\n\t\tprotected itemEntryService: ItemEntryService,\n\t\tprotected transaction: AbstractCache,\n\t\titemCacheFactory: ItemCacheFactory,\n\t) {\n\t\tsuper();\n\n\t\tthis.entries = itemCacheFactory.construct(\n\t\t\tthis.transaction,\n\t\t);\n\t}\n\n\tpublic getItemFieldSignal<ItemTypeType extends ApiItemType, ColumnId extends ItemTypeColumnId<ItemTypeType>> (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t\tcolumnId: ColumnId,\n\t): WritableSignal<GetFieldValueType<ItemTypeType, ColumnId>> {\n\t\tthis.itemFieldSignals[itemEntry.id] ??= {};\n\n\t\tlet cachedSignal: WritableSignal<any> | undefined = this.itemFieldSignals[itemEntry.id][columnId as string];\n\n\t\tif (cachedSignal === undefined) {\n\t\t\tcachedSignal = this.itemFieldSignals[itemEntry.id][columnId as string] = signal(\n\t\t\t\tthis.lookUpItemField(\n\t\t\t\t\titemEntry,\n\t\t\t\t\tcolumnId,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\treturn cachedSignal;\n\t}\n\n\tpublic getDisplayName<ItemTypeType extends ApiItemType> (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t): string {\n\t\tlet result: string | undefined = '';\n\n\t\tswitch (itemEntry.itemType) {\n\t\t\tcase 'Contact': {\n\t\t\t\tconst type = this.lookUpItemField(\n\t\t\t\t\titemEntry as ItemEntry<any> as ItemEntry<'Contact'>,\n\t\t\t\t\t'type',\n\t\t\t\t);\n\n\t\t\t\tif (type === 'bedrijf') {\n\t\t\t\t\tresult = this.lookUpItemField(\n\t\t\t\t\t\titemEntry as ItemEntry<any> as ItemEntry<'Contact'>,\n\t\t\t\t\t\t'bedrijf',\n\t\t\t\t\t);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tresult = this.itemEntryService.getFullName(\n\t\t\t\t\tthis.lookUpItemField(\n\t\t\t\t\t\titemEntry as ItemEntry<any> as ItemEntry<'Contact'>,\n\t\t\t\t\t\t'voornaam',\n\t\t\t\t\t)!,\n\t\t\t\t\tthis.lookUpItemField(\n\t\t\t\t\t\titemEntry as ItemEntry<any> as ItemEntry<'Contact'>,\n\t\t\t\t\t\t'tussenvoegsel',\n\t\t\t\t\t)!,\n\t\t\t\t\tthis.lookUpItemField(\n\t\t\t\t\t\titemEntry as ItemEntry<any> as ItemEntry<'Contact'>,\n\t\t\t\t\t\t'naam',\n\t\t\t\t\t)!,\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'Medewerker':\n\t\t\tcase 'Person':\n\t\t\t\tresult = this.itemEntryService.getFullName(\n\t\t\t\t\tthis.lookUpItemField(\n\t\t\t\t\t\titemEntry as ItemEntry<any> as ItemEntry<'Medewerker' | 'Person'>,\n\t\t\t\t\t\t'voornaam',\n\t\t\t\t\t)!,\n\t\t\t\t\tthis.lookUpItemField(\n\t\t\t\t\t\titemEntry as ItemEntry<any> as ItemEntry<'Medewerker' | 'Person'>,\n\t\t\t\t\t\t'tussenvoegsel',\n\t\t\t\t\t)!,\n\t\t\t\t\tthis.lookUpItemField(\n\t\t\t\t\t\titemEntry as ItemEntry<any> as ItemEntry<'Medewerker' | 'Person'>,\n\t\t\t\t\t\t'achternaam',\n\t\t\t\t\t)!,\n\t\t\t\t);\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tresult = this.lookUpItemField(\n\t\t\t\t\titemEntry,\n\t\t\t\t\t// `getTitleField` may return 'displayname' for items that don't have a simple name field.\n\t\t\t\t\t// In that case there is no other field to fall back to.\n\t\t\t\t\tthis.itemEntryService.getTitleField(\n\t\t\t\t\t\titemEntry.itemType,\n\t\t\t\t\t),\n\t\t\t\t) as string;\n\n\t\t\t\tbreak;\n\t\t}\n\n\t\treturn result ?? '';\n\t}\n\n\tpublic constructGetField<ItemTypeType extends ApiItemType> (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t): GetField<ItemTypeType> {\n\t\treturn columnId => this.lookUpItemField(\n\t\t\titemEntry,\n\t\t\tcolumnId,\n\t\t);\n\t}\n\n\t/**\n\t * Construct a proxy object for the fields of the item. Reading a field will traverse the transaction chain.\n\t */\n\tpublic constructFieldsProxy<ItemTypeType extends ApiItemType> (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t): FieldMap<ItemTypeType> {\n\t\treturn new Proxy(\n\t\t\t{\n\t\t\t\titemEntry,\n\t\t\t\titemHandler: this,\n\t\t\t},\n\t\t\tfieldsProxyHandler,\n\t\t) as FieldMap<ItemTypeType>;\n\t}\n\n\tpublic constructSignalFieldsProxy<ItemTypeType extends ApiItemType> (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t): SignalFieldMap<ItemTypeType> {\n\t\treturn new Proxy(\n\t\t\t{\n\t\t\t\titemEntry,\n\t\t\t\titemHandler: this,\n\t\t\t},\n\t\t\tfieldsSignalProxyHandler,\n\t\t) as SignalFieldMap<ItemTypeType>;\n\t}\n\n\tpublic lookUpItemField<ItemTypeType extends ApiItemType, ColumnId extends ItemTypeColumnId<ItemTypeType>> (\n\t\tentry: ItemEntry<ItemTypeType>,\n\t\tcolumnId: ColumnId,\n\t): GetFieldValueType<ItemTypeType, ColumnId> | undefined {\n\t\t// Start out with the given/current transaction, and then loop up\n\t\tlet t: AbstractCache | null = this.transaction;\n\n\t\twhile (t) {\n\t\t\t// Check if there are any changes at all for this item on the transaction\n\t\t\tconst itemChanges = t.itemHandler.itemChanges[entry.id];\n\n\t\t\tif (itemChanges !== undefined) {\n\t\t\t\t// There might be changes, but is this specific field also in the changes?\n\t\t\t\tconst fieldValue = itemChanges[columnId];\n\n\t\t\t\tif (fieldValue !== undefined) {\n\t\t\t\t\treturn fieldValue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Move to the parent, and repeat\n\t\t\tt = t.parent;\n\t\t}\n\n\t\t// The field was invalid/never requested (not even on the ServerCache)\n\t\treturn undefined;\n\t}\n\n\tpublic collectFields<ItemTypeType extends ApiItemType> (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t): FieldMap<ItemTypeType> {\n\t\tconst result: FieldMap<ItemTypeType> = {} as FieldMap<ItemTypeType>;\n\n\t\tfor (const column of itemEntry.columns.main) {\n\t\t\tresult[column.id] = this.lookUpItemField(\n\t\t\t\titemEntry,\n\t\t\t\tcolumn.id,\n\t\t\t);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * @description\n\t * Copies the passed ItemEntryChanges into a format the implementing ItemHandler can put in his ItemChanges\n\t * @param itemEntryChanges\n\t * @param entry\n\t */\n\tpublic copyTransactionItemEntryChanges<ItemTypeType extends ApiItemType> (\n\t\titemEntryChanges: FieldMap<ItemTypeType>,\n\t\tentry: ItemEntry<ItemTypeType>,\n\t): FieldMap<ItemTypeType> {\n\t\treturn ApiFormatter.copyFields(\n\t\t\titemEntryChanges,\n\t\t\t{},\n\t\t\tentry.columns.main,\n\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Recursively fetches derived values as separate requests, instead of as columns of a primary item\n\t * Can be used when derived values of a local item have to be fetched, since a local item can't be used as root item of a query\n\t *\n\t * @param refreshAggregateColumns - See {@link fetchItemEntryData}.\n\t */\n\tpublic async resolveDerivedValues<ItemTypeType extends ApiItemType> (\n\t\titemEntries: ItemEntry<ItemTypeType>[],\n\t\trootColumns: ColumnInfo<ItemTypeType>[],\n\t\trefreshAggregateColumns: boolean,\n\t\tchangesDelta?: ChangesDeltaBase,\n\t): Promise<void> {\n\t\tconst childItemEntriesPromises: Promise<ItemEntry[]>[] = [];\n\t\t// Columns that are actually root columns (they have children) and have associated items that should be resolved.\n\t\tconst filteredRootColumns: ColumnInfo<ItemTypeType>[] = [];\n\n\t\tfor (const rootColumn of rootColumns) {\n\t\t\tconst childColumns = rootColumn.children;\n\n\t\t\tif (childColumns.length === 0) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tchildColumns.length === 1\n\t\t\t\t&& childColumns[0].apiColumn.type === 'id'\n\t\t\t) {\n\t\t\t\t// This can also happen because of column expansion, in which case you do actually want the derived item, so we shouldn't error.\n\t\t\t\tthis.errorHandler.logWarning(\n\t\t\t\t\t'You should use fields[columnId] instead of derived[\\'columnId>id\\'] to get the ID of a derived item',\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst itemIdSet = new Set<ItemId>();\n\n\t\t\tfor (const itemEntry of itemEntries) {\n\t\t\t\tlet itemId = changesDelta?.updated[itemEntry.id]?.changes.fields[rootColumn.id] as ItemId | null | undefined;\n\n\t\t\t\tif (itemId === undefined) {\n\t\t\t\t\titemId = this.transaction.itemHandler.lookUpItemField(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\trootColumn.id,\n\t\t\t\t\t) as ItemId | null | undefined;\n\t\t\t\t}\n\n\t\t\t\tif (itemId === undefined) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Encountered missing ${rootColumn.id} field of ${itemEntry.itemType} item when resolving derived value`,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif (itemId === null) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\titemIdSet.add(\n\t\t\t\t\titemId,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (itemIdSet.size === 0) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tfilteredRootColumns.push(\n\t\t\t\trootColumn,\n\t\t\t);\n\n\t\t\tchildItemEntriesPromises.push(\n\t\t\t\tthis.fetchItemEntryData(\n\t\t\t\t\trootColumn.itemType!,\n\t\t\t\t\titemIdSet,\n\t\t\t\t\tthis.requestColumnsOperationsCacheFactory.construct(\n\t\t\t\t\t\trootColumn.itemType!,\n\t\t\t\t\t\tchildColumns.map(\n\t\t\t\t\t\t\tchildColumn => childColumn.id,\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t\trefreshAggregateColumns,\n\t\t\t\t\ttrue,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\tif (filteredRootColumns.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst childItemEntriesArray = await Promise.all(\n\t\t\tchildItemEntriesPromises,\n\t\t);\n\n\t\tconst childColumnPromises: Promise<void>[] = [];\n\n\t\tfor (let i = 0; i < filteredRootColumns.length; i++) {\n\t\t\tchildColumnPromises.push(\n\t\t\t\tthis.resolveDerivedValues(\n\t\t\t\t\tchildItemEntriesArray[i],\n\t\t\t\t\tfilteredRootColumns[i].children,\n\t\t\t\t\trefreshAggregateColumns,\n\t\t\t\t\tchangesDelta,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\tawait Promise.all(\n\t\t\tchildColumnPromises,\n\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Traverses the column path and returns the fields of the derived item, returns undefined if the item isn't found\n\t *\n\t * ---------------------\n\t *\n\t * @remark\n\t * Assumes the derived item's values are already cached\n\t */\n\tpublic getDerivedValues<ItemTypeType extends ApiItemType, T extends readonly string[]> (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t\tcolumnPath: T,\n\t): ResolveDerivedValues<ItemTypeType, T> | undefined {\n\t\tconst derivedItem = this.getDerivedEntry(\n\t\t\titemEntry,\n\t\t\tcolumnPath,\n\t\t);\n\n\t\tif (derivedItem === null) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn this.collectFields(\n\t\t\tderivedItem,\n\t\t) as ResolveDerivedValues<ItemTypeType, T>;\n\t}\n\n\t/**\n\t * @description\n\t * Returns the value of the columnPath, or undefined when the path couldn't be traversed\n\t *\n\t * @param itemEntry The root entry to start the path from\n\t * @param columnPath Can either be an array of columnIds (['column', 'column2']) or a config column string ('column>column2')\n\t */\n\tpublic getDerivedValue<ItemTypeType extends ApiItemType, T extends string, DefaultValue = unknown> (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t\tcolumnPath: T,\n\t\tdefaultValue?: DefaultValue,\n\t): ResolveDerivedValue<ItemTypeType, DerivedStringToRequestColumnPath<T>>;\n\n\tpublic getDerivedValue<ItemTypeType extends ApiItemType, T extends readonly string[], DefaultValue = unknown> (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t\tcolumnPath: T,\n\t\tdefaultValue?: DefaultValue,\n\t): ResolveDerivedValue<ItemTypeType, T>;\n\n\tpublic getDerivedValue<ItemTypeType extends ApiItemType, T extends any, DefaultValue = unknown> (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t\tcolumnPath: string | string[],\n\t\tdefaultValue?: DefaultValue,\n\t): unknown | DefaultValue {\n\t\tif (typeof columnPath === 'string') {\n\t\t\tcolumnPath = columnPath.split(\n\t\t\t\tCOLUMN_SEPERATOR,\n\t\t\t);\n\t\t}\n\n\t\tconst derivedEntry = this.getDerivedEntry(\n\t\t\titemEntry,\n\t\t\tcolumnPath.slice(\n\t\t\t\t0,\n\t\t\t\t-1,\n\t\t\t),\n\t\t);\n\n\t\tif (derivedEntry === null) {\n\t\t\tif (defaultValue !== undefined) {\n\t\t\t\treturn defaultValue;\n\t\t\t}\n\n\t\t\tconst joinedPath = columnPath.join(\n\t\t\t\t'>',\n\t\t\t);\n\n\t\t\tconst column = this.getDerivedColumn(\n\t\t\t\titemEntry.itemType,\n\t\t\t\tcolumnPath,\n\t\t\t);\n\n\t\t\tif (column !== undefined) {\n\t\t\t\treturn column.default;\n\t\t\t}\n\n\t\t\tthrow new Error(\n\t\t\t\t`Derived columns for path ${joinedPath} couldn't be found. Did you request them?`,\n\t\t\t);\n\t\t}\n\n\t\treturn this.lookUpItemField(\n\t\t\tderivedEntry,\n\t\t\tcolumnPath[columnPath.length - 1],\n\t\t) as T;\n\t}\n\n\t/**\n\t * @description\n\t * Clears the entry from this transaction, removing it from the {@link ItemCache ItemCache} and removing all changes\n\t *\n\t * @returns The deleted item changes.\n\t */\n\tpublic clearItemEntry<ItemTypeType extends ApiItemType> (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t): FieldMap<ItemTypeType> | undefined {\n\t\tthis.entries.clear(\n\t\t\titemEntry,\n\t\t);\n\n\t\tconst changes = this.itemChanges[itemEntry.id];\n\n\t\tdelete this.itemChanges[itemEntry.id];\n\t\tdelete this.itemFieldSignals[itemEntry.id];\n\n\t\treturn changes;\n\t}\n\n\t/**\n\t * @param refreshAggregateColumns - Do a server request for aggregate columns even if we already have a cached value.\n\t * This should be `true` when we actively request an item (e.g. using `getItemById`), but `false` when expanding an\n\t * item for collection matching purposes.\n\t * @param forceRequest - Always flush the request buffer when the timeout expires, ignoring request suspension,\n\t * which could introduce an additional delay.\n\t */\n\tpublic abstract fetchItemEntryData<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\titemIds: Iterable<ItemId>,\n\t\tcolumnsOperationsCache: RequestColumnsOperationsCache<ItemTypeType>,\n\t\trefreshAggregateColumns: boolean,\n\t\tforceRequest?: boolean,\n\t): Promise<ItemEntry<ItemTypeType>[]>;\n\n\t/**\n\t * @description\n\t * Creates a new {@link ItemEntry ItemEntry} from the passed {@link ChangesDeltaItemCreateDelta ChangesDeltaItemCreateDelta} and stores it in this transaction's {@link ItemCache ItemCache}\n\t */\n\tpublic createItemEntry (\n\t\tcreateTuple: ChangesDeltaItemCreateDelta,\n\t): ItemEntry {\n\t\tconst itemEntry = new ItemEntry(\n\t\t\tcreateTuple.columns.itemType,\n\t\t\tcreateTuple.itemId,\n\t\t\tcreateTuple.columns,\n\t\t);\n\n\t\tthis.entries.add(\n\t\t\titemEntry,\n\t\t);\n\n\t\treturn itemEntry;\n\t}\n\n\tprivate getDerivedEntry (\n\t\titemEntry: ItemEntry,\n\t\tcolumnPath: readonly string[],\n\t): ItemEntry | null {\n\t\tlet derivedItemEntry: ItemEntry = itemEntry;\n\n\t\tfor (const columnId of columnPath) {\n\t\t\tconst column = derivedItemEntry.columns.response[derivedItemEntry.itemType][columnId];\n\n\t\t\tif (column === undefined) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Column '${columnId}' not found on entry in ItemResource.getDerivedValue`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\t!ColumnUtil.isItemColumn(\n\t\t\t\t\tcolumn,\n\t\t\t\t)\n\t\t\t\t|| column.itemType === null\n\t\t\t) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Column '${columnId}' doesn't have children in ItemResource.getDerivedValue`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst itemId = this.lookUpItemField(\n\t\t\t\tderivedItemEntry,\n\t\t\t\tcolumnId,\n\t\t\t);\n\n\t\t\tif (itemId === null) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tderivedItemEntry = this.transaction.getLocalItemEntryByItemId(\n\t\t\t\tcolumn.itemType,\n\t\t\t\titemId,\n\t\t\t);\n\t\t}\n\n\t\treturn derivedItemEntry;\n\t}\n\n\tprivate getDerivedColumn (\n\t\titemType: ApiItemType,\n\t\tcolumnPath: string[],\n\t): UnknownResponseColumn {\n\t\tfor (let i = 0; i < columnPath.length; i++) {\n\t\t\tconst columnId = columnPath[i];\n\n\t\t\tconst column: UnknownResponseColumn = this.columnCache.getColumn(\n\t\t\t\titemType,\n\t\t\t\tcolumnId as any,\n\t\t\t);\n\n\t\t\tif (column === undefined) {\n\t\t\t\tconst joinedPath = columnPath.join(\n\t\t\t\t\t'>',\n\t\t\t\t);\n\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Column '${columnId}' not found in path '${joinedPath}' for itemType '${itemType}'`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (i === columnPath.length - 1) {\n\t\t\t\treturn column;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\t!ColumnUtil.isItemColumn(\n\t\t\t\t\tcolumn,\n\t\t\t\t)\n\t\t\t\t|| column.itemType === null\n\t\t\t) {\n\t\t\t\tconst joinedPath = columnPath.join(\n\t\t\t\t\t'>',\n\t\t\t\t);\n\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Column '${columnId}' doesn't have children in path '${joinedPath}' for itemType '${itemType}'`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\titemType = column.itemType;\n\t\t}\n\n\t\tthrow new Error(\n\t\t\t'Invalid path given in getDerivedColumn',\n\t\t);\n\t}\n\n}\n","import { ApiItemType, ItemId, TempItemTypeWithoutFixedIds } from '@rentman/backend-types';\nimport { UnknownResponseColumn } from '@rentman/backend-types/dist/manual/api-response-column';\nimport moment from 'moment';\nimport { ApiFormatter, ChangesDeltaBaseItemUpdateDelta, ChangesDeltaItemCreateDelta, ChangesDeltaItemUpdateDelta, ColumnCache, ColumnUtil, ErrorHandlerInterface, FieldMap, ItemCacheFactory, ItemEntry, ItemEntryService, ItemHandlerBase, ItemNotFoundException, KeyService, ParentChangesDelta, RequestColumnExpansionFactory, RequestColumnsOperationsCache, RequestColumnsOperationsCacheFactory, ServerCache } from '../../../internal';\n\nexport class ServerItemHandler\n\textends ItemHandlerBase {\n\n\tprivate itemFieldLastModified: {\n\t\t[itemEntryId: number]: {\n\t\t\t[columnId: string]: number,\n\t\t},\n\t} = {};\n\n\tpublic constructor (\n\t\terrorHandler: ErrorHandlerInterface,\n\t\tcolumnCache: ColumnCache,\n\t\titemCacheFactory: ItemCacheFactory,\n\t\titemEntryService: ItemEntryService,\n\t\trequestColumnExpansionFactory: RequestColumnExpansionFactory,\n\t\trequestColumnsOperationsCacheFactory: RequestColumnsOperationsCacheFactory,\n\t\tprotected transaction: ServerCache,\n\t) {\n\t\tsuper(\n\t\t\tcolumnCache,\n\t\t\terrorHandler,\n\t\t\trequestColumnExpansionFactory,\n\t\t\trequestColumnsOperationsCacheFactory,\n\t\t\titemEntryService,\n\t\t\ttransaction,\n\t\t\titemCacheFactory,\n\t\t);\n\t}\n\n\tpublic createItemEntry (\n\t\tcreateTuple: ChangesDeltaItemCreateDelta,\n\t): ItemEntry {\n\t\tconst itemEntry = super.createItemEntry(\n\t\t\tcreateTuple,\n\t\t);\n\n\t\tthis.itemChanges[itemEntry.id] = createTuple.fields;\n\t\tthis.itemFieldLastModified[itemEntry.id] = {};\n\n\t\tconst modifiedMoment = (createTuple.fields.modified as moment.Moment)?.valueOf() ?? moment.now();\n\n\t\tfor (const columnId in createTuple.fields) {\n\t\t\tconst column = createTuple.columns.response[itemEntry.itemType][columnId] as UnknownResponseColumn;\n\n\t\t\tif (\n\t\t\t\tcolumn === undefined\n\t\t\t\t// We don't track aggregate or method columns\n\t\t\t\t|| column.fieldtype === 'aggregate'\n\t\t\t\t|| column.fieldtype === 'method'\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tthis.itemFieldLastModified[itemEntry.id][columnId] = modifiedMoment;\n\t\t}\n\n\t\treturn itemEntry;\n\t}\n\n\t/**\n\t * @description\n\t * Fetches the data for the passed ItemType/ItemId/columns, will do nothing if the requested ItemEntry/columns are already cached.\n\t * Will create a new {@link ItemEntry ItemEntry} if the ItemEntry didn't exist yet\n\t */\n\tpublic override async fetchItemEntryData<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\titemIds: Iterable<ItemId>,\n\t\tcolumnsOperationsCache: RequestColumnsOperationsCache<ItemTypeType>,\n\t\trefreshAggregateColumns: boolean,\n\t\tforceRequest?: boolean,\n\t): Promise<ItemEntry<ItemTypeType>[]> {\n\t\tconst requestItemIds: ItemId[] = [];\n\t\tconst requestColumnExpansion = this.requestColumnExpansionFactory.construct();\n\t\tconst result: ItemEntry<ItemTypeType>[] = [];\n\t\tconst isTempItemType = TempItemTypeWithoutFixedIds.includes(\n\t\t\titemType,\n\t\t);\n\n\t\tfor (const itemId of itemIds) {\n\t\t\t// TempItemTypes exists on the serverCache even though they have local ids so we handle them seperately\n\t\t\tif (isTempItemType) {\n\t\t\t\tconst itemEntry = this.entries.get(\n\t\t\t\t\titemType,\n\t\t\t\t\titemId,\n\t\t\t\t);\n\n\t\t\t\t// A temp item can never be expanded because it doens't exist, so if we have it we just continue, otherwise we error\n\t\t\t\tif (\n\t\t\t\t\tcolumnsOperationsCache.setContainsAllColumns(\n\t\t\t\t\t\titemEntry.columns,\n\t\t\t\t\t\tthis.transaction,\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\tresult.push(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t);\n\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tthrow new ItemNotFoundException(\n\t\t\t\t\titemType,\n\t\t\t\t\titemId,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tKeyService.isLocalId(\n\t\t\t\t\titemId,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tthrow new ItemNotFoundException(\n\t\t\t\t\titemType,\n\t\t\t\t\titemId,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tthis.entries.contains(\n\t\t\t\t\titemType,\n\t\t\t\t\titemId,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tconst itemEntry = this.entries.get(\n\t\t\t\t\titemType,\n\t\t\t\t\titemId,\n\t\t\t\t);\n\n\t\t\t\tif (\n\t\t\t\t\tcolumnsOperationsCache.setContainsAllColumns(\n\t\t\t\t\t\titemEntry.columns,\n\t\t\t\t\t\tthis.transaction,\n\t\t\t\t\t)\n\t\t\t\t\t// If the itemEntry is outdated we have to re-fetch all data, not just aggregated columns.\n\t\t\t\t\t&& !itemEntry.isOutdated()\n\t\t\t\t) {\n\t\t\t\t\tif (\n\t\t\t\t\t\t!refreshAggregateColumns\n\t\t\t\t\t\t|| !columnsOperationsCache.hasAggregateColumns()\n\t\t\t\t\t) {\n\t\t\t\t\t\t// There already is an entry, and it contains the columns we need, so we can safely return it.\n\t\t\t\t\t\tresult.push(\n\t\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\trequestItemIds.push(\n\t\t\t\t\t\titemId,\n\t\t\t\t\t);\n\t\t\t\t\trequestColumnExpansion.expandWithRequestColumnsTuple(\n\t\t\t\t\t\titemType,\n\t\t\t\t\t\tcolumnsOperationsCache.getAggregateColumns(),\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\t// TODO: Replace this once we use request column sets with column sets.\n\t\t\t\t\tconst requestColumnsTuple = {\n\t\t\t\t\t\tobject: itemEntry.columns.request,\n\t\t\t\t\t\tstring: ColumnUtil.createRequestColumnSetId(\n\t\t\t\t\t\t\titemEntry.columns.request,\n\t\t\t\t\t\t),\n\t\t\t\t\t};\n\n\t\t\t\t\trequestItemIds.push(\n\t\t\t\t\t\titemId,\n\t\t\t\t\t);\n\n\t\t\t\t\tconst columns = columnsOperationsCache.getColumnsMergedWithTuple(\n\t\t\t\t\t\trequestColumnsTuple,\n\t\t\t\t\t\tthis.transaction,\n\t\t\t\t\t);\n\n\t\t\t\t\trequestColumnExpansion.expandWithRequestColumnsTuple(\n\t\t\t\t\t\titemType,\n\t\t\t\t\t\t// When an item is marked as outdated, we want to refresh all data, not just the missing data.\n\t\t\t\t\t\titemEntry.isOutdated()\n\t\t\t\t\t\t\t? columns.merged\n\t\t\t\t\t\t\t: columns.difference,\n\t\t\t\t\t);\n\t\t\t\t\titemEntry.markUpToDate();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\trequestItemIds.push(\n\t\t\t\t\titemId,\n\t\t\t\t);\n\t\t\t\trequestColumnExpansion.expandWithRequestColumnsTuple(\n\t\t\t\t\titemType,\n\t\t\t\t\tcolumnsOperationsCache.getRequestColumnsTuple(\n\t\t\t\t\t\tthis.transaction,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (requestItemIds.length === 0) {\n\t\t\treturn result;\n\t\t}\n\n\t\tawait this.transaction.requestBufferManager.fetchByIds(\n\t\t\titemType,\n\t\t\trequestItemIds,\n\t\t\trequestColumnExpansion.get()[itemType],\n\t\t\t{\n\t\t\t\tforceFlush: forceRequest,\n\t\t\t},\n\t\t);\n\n\t\tfor (const requestItemId of requestItemIds) {\n\t\t\tresult.push(\n\t\t\t\tthis.entries.get(\n\t\t\t\t\titemType,\n\t\t\t\t\trequestItemId,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Processes the changes on the transaction, and stores the changes as well as the previous values in\n\t * `parentChangesDelta`.\n\t *\n\t * Note: Even though both the server item handler and the transaction item handler have a\n\t * {@link processUpdatesFromDelta} method, it is not defined on the superclass as the transaction item handler\n\t * introduces the `createItemChangesIfNoneExist` parameter.\n\t */\n\tpublic processUpdatesFromDelta (\n\t\tupdated: {\n\t\t\t[itemEntryId: number]: ChangesDeltaBaseItemUpdateDelta<any>,\n\t\t},\n\t\tparentChangesDelta: ParentChangesDelta,\n\t): void {\n\t\tfor (const itemEntryId in updated) {\n\t\t\tconst tuple = updated[itemEntryId];\n\t\t\tconst previous = this.processItemEntryChanges(\n\t\t\t\ttuple,\n\t\t\t);\n\n\t\t\tparentChangesDelta.setItemUpdated(\n\t\t\t\ttuple.entry,\n\t\t\t\ttuple.changes.fields,\n\t\t\t\tprevious,\n\t\t\t\ttuple.mode,\n\t\t\t);\n\t\t}\n\t}\n\n\tpublic override itemIsDeleted (): boolean {\n\t\treturn false;\n\t}\n\n\t/**\n\t * @description\n\t * Processes the passed {@link ChangesDeltaBaseItemUpdateDelta update delta} on the server cache. New\n\t * {@link TransactionItemHandler.itemChanges item changes} will be created if none exist.\n\t *\n\t * @returns An object containing a previous value for each applied change. Because of the nature of item changes\n\t * it may also include changes applied on ancestor transactions. Is `null` when no changes have been made.\n\t */\n\tprotected processItemEntryChanges<ItemTypeType extends ApiItemType> (\n\t\titemEntryChangesTuple: ChangesDeltaBaseItemUpdateDelta<ItemTypeType>,\n\t): Readonly<Partial<FieldMap<ItemTypeType>>> | null {\n\t\tconst itemEntry = itemEntryChangesTuple.entry;\n\t\tconst changedFields = itemEntryChangesTuple.changes.fields;\n\n\t\tif (this.itemChanges[itemEntry.id] === undefined) {\n\t\t\tthis.itemChanges[itemEntry.id] = {};\n\t\t}\n\n\t\tif (this.itemFieldLastModified[itemEntry.id] === undefined) {\n\t\t\tthis.itemFieldLastModified[itemEntry.id] = {};\n\t\t}\n\n\t\tconst columnExpansions = (itemEntryChangesTuple as ChangesDeltaItemUpdateDelta<ItemTypeType>).changes.columnExpansions;\n\n\t\tif (\n\t\t\tcolumnExpansions !== undefined\n\t\t\t&& columnExpansions.length > 0\n\t\t) {\n\t\t\tfor (const columnExpansion of columnExpansions) {\n\t\t\t\t// The column expansion should run before updating the columns, the columns of the item entry might\n\t\t\t\t// have changed after the expansion has been constructed.\n\t\t\t\titemEntry.columns = columnExpansion.run(\n\t\t\t\t\titemEntry.columns,\n\t\t\t\t).merged;\n\t\t\t}\n\t\t}\n\n\t\tconst localChanges = this.itemChanges[itemEntry.id];\n\t\t// We assume modified is cached since we always request it in `expandColumnExpansionWithRequiredColumns`\n\t\tconst responseModified = (changedFields.modified as moment.Moment)?.valueOf();\n\t\tconst responseColumns = itemEntry.columns.response[itemEntry.itemType];\n\n\t\tlet previous: Partial<FieldMap<ItemTypeType>> | null = null;\n\n\t\tfor (const columnId in changedFields) {\n\t\t\tconst column = responseColumns[columnId as string] as UnknownResponseColumn;\n\n\t\t\tif (column === undefined) {\n\t\t\t\t// We don't have to store values we don't have columns for\n\t\t\t\t// This can happen when manually calling `applyChangesFromParent` from the client\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// We didn't have a local value yet, so we can set it and continue. It should not be interpreted as a change.\n\t\t\tif (localChanges[columnId] === undefined) {\n\t\t\t\tlocalChanges[columnId] = ApiFormatter.clone(\n\t\t\t\t\tcolumn.type,\n\t\t\t\t\tchangedFields[columnId],\n\t\t\t\t);\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst fieldLastModified = this.itemFieldLastModified[itemEntry.id][columnId];\n\n\t\t\tif (\n\t\t\t\tfieldLastModified !== undefined\n\t\t\t\t&& responseModified !== undefined\n\t\t\t\t&& fieldLastModified >= responseModified\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\t// The new value equals the old value, continue.\n\t\t\t\tApiFormatter.compareFields(\n\t\t\t\t\tcolumn.type,\n\t\t\t\t\tchangedFields[columnId],\n\t\t\t\t\tlocalChanges[columnId],\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// When doing a request it can happen that a derived value in the response also had its values changed\n\t\t\t// (by a side process) if this is the case it will be in QUERY mode in the delta (because it was a derived value)\n\t\t\t// but we should actually treat it as an update\n\t\t\tif (itemEntryChangesTuple.mode === 'QUERY') {\n\t\t\t\titemEntryChangesTuple.mode = 'CLEAR_WHEN_SAME';\n\t\t\t}\n\n\t\t\tif (previous === null) {\n\t\t\t\tprevious = {};\n\t\t\t}\n\n\t\t\tprevious[columnId] = localChanges[columnId];\n\n\t\t\tlocalChanges[columnId] = ApiFormatter.clone(\n\t\t\t\tcolumn.type,\n\t\t\t\tchangedFields[columnId],\n\t\t\t);\n\n\t\t\tif (\n\t\t\t\tcolumn.fieldtype !== 'aggregate'\n\t\t\t\t&& column.fieldtype !== 'method'\n\t\t\t) {\n\t\t\t\t// If `modified` is not provided (e.g. when manually syncing server cache after saving files),\n\t\t\t\t// default to `moment.now()` to ensure fields are treated as freshly updated and their\n\t\t\t\t// last-modified timestamps are correctly stored.\n\t\t\t\tthis.itemFieldLastModified[itemEntry.id][columnId] = responseModified ?? moment.now();\n\t\t\t}\n\t\t}\n\n\t\tif (changedFields.id !== undefined) {\n\t\t\tconst oldId: ItemId = itemEntry.itemId;\n\n\t\t\titemEntry.updateId(\n\t\t\t\tchangedFields.id as ItemId,\n\t\t\t);\n\n\t\t\tthis.entries.updateItemId(\n\t\t\t\titemEntry,\n\t\t\t\toldId,\n\t\t\t);\n\t\t}\n\n\t\treturn previous;\n\t}\n\n}\n","import { ApiItemType, BackendApiQuery, ItemId } from '@rentman/backend-types';\nimport { GraphQueryParserFactory } from '../../factories/GraphQueryParserFactory';\nimport { AbstractCache, ApiLinkTreeType, ApiQuery, ApiQueryConditionLinkedTo, ApiRequestColumn, ApiRequestColumnArray, ApiRequestColumns, ApiRequestService, CachedQueryItem, CachedQueryOptions, CachedQueryOptionsWithColumns, ChangesDeltaBase, CollectionOptions, CollectionQuery, CollectionResourceOrder, ErrorHandlerInterface, GetMergedQueryGraph, ItemEntry, LinkTreeServiceInterface, MatchesAccumulatorMap, MatchingResultsAccumulatorMapType, MatchingResultsAccumulatorTuple, ParentChangesDelta, QueryColumnExtractor, QueryParser, QueryService, RequestColumnExpansionFactory, RequestColumnsOperationsCache, RequestColumnsOperationsCacheFactory, RequestColumnsTuple } from '../../internal';\nimport { IsComparatorQueryNode } from '../matcher/IsComparatorQueryNode';\nimport { RootQueryNode } from '../matcher/RootQueryNode';\nimport { numberBooleanNullValueTransformer } from '../matcher/ValueTransformers';\n\nexport interface LinkCollectionBatchQueryTuple<ItemTypeType extends ApiItemType> {\n\tbatchQuery: CollectionQuery<ItemTypeType>,\n\tbatchQueryGraph?: RootQueryNode<ItemTypeType>,\n}\n\nexport interface ParentCachedQueryItemTuple<ItemTypeType extends ApiItemType> {\n\treadonly cachedQueryItem: CachedQueryItem<ItemTypeType>,\n\treadonly options: CollectionOptions<ItemTypeType>,\n\tchildren: CachedQueryItemsItemTypeTuple<ApiItemType>[] | null,\n}\n\nexport interface CachedQueryItemTuple<ItemTypeType extends ApiItemType>\n\textends ParentCachedQueryItemTuple<ItemTypeType> {\n\tchildren: null,\n}\n\nexport interface CachedQueryItemsItemTypeTuple<ItemTypeType extends ApiItemType> {\n\titemType: ItemTypeType,\n\tcachedQueryItemTuples: ParentCachedQueryItemTuple<ItemTypeType>[],\n}\n\nexport interface CachedQueryHandlerCollectionTuple<ItemTypeType extends ApiItemType> {\n\tcachedQueryItem?: CachedQueryItem<ItemTypeType>,\n}\n\ntype RequireOnly<ObjectType, Keys extends keyof ObjectType> = ObjectType & {\n\t[Key in Keys]-?: ObjectType[Key]\n};\n\nexport abstract class CachedQueryHandlerBase {\n\n\tprotected collections: {\n\t\t[ItemType in ApiItemType]?: {\n\t\t\t[queryString: string]: CachedQueryHandlerCollectionTuple<ItemType> | undefined,\n\t\t}\n\t} = {};\n\n\tprotected constructor (\n\t\tprotected dependencies: {\n\t\t\tapiRequestService: ApiRequestService,\n\t\t\terrorHandler: ErrorHandlerInterface,\n\t\t\tgraphQueryParserFactory: GraphQueryParserFactory,\n\t\t\tlinkTreeService: LinkTreeServiceInterface,\n\t\t\tqueryService: QueryService,\n\t\t\trequestColumnExpansionFactory: RequestColumnExpansionFactory,\n\t\t\trequestColumnsOperationsCacheFactory: RequestColumnsOperationsCacheFactory,\n\t\t},\n\t\tprotected transaction: AbstractCache,\n\t) {\n\t}\n\n\tpublic createQuery<ItemTypeType extends ApiItemType> (\n\t\tquery: ApiQuery<ItemTypeType>,\n\t): CollectionQuery<ItemTypeType> {\n\t\treturn new QueryParser()\n\t\t\t.run(\n\t\t\t\tquery,\n\t\t\t);\n\t};\n\n\t/**\n\t * Works out the effect the changes found in `parentChangesDelta` will have on the cached queries / collections on\n\t * the current transaction. This method does not update the collections themselves. A call to\n\t * {@link applyMatchingResultsToCachedQueries} or {@link applyMatchingResultsToCollections} will be required.\n\t *\n\t * Note that this method also resolves `maybe` matches.\n\t *\n\t * @param processEmptyUpdates - Processes empty updates. See: {@link ItemMatcherBase.matchEmptyItemsInUpdatedChangesDelta}.\n\t */\n\tpublic async matchItemsToCollectionQueries (\n\t\tparentChangesDelta: ParentChangesDelta,\n\t\tlimitToItemTypes: Iterable<ApiItemType> | undefined,\n\t\tprocessEmptyUpdates: boolean,\n\t): Promise<MatchesAccumulatorMap<MatchingResultsAccumulatorMapType>> {\n\t\t// Because the changes delta doesn't tell us much about the types of items we're going to change (at least,\n\t\t// when `_queryItemType` is unset), we want to create merged query graphs on demand. Furthermore, we want to\n\t\t// cache the ones we've already created.\n\t\tconst mergedQueryGraphs: {\n\t\t\t[ItemType in ApiItemType]?: RootQueryNode<ItemType> | null\n\t\t} = {};\n\t\tlet getMergedQueryGraph: GetMergedQueryGraph;\n\n\t\tif (limitToItemTypes !== undefined) {\n\t\t\tfor (const limitToItemType of limitToItemTypes) {\n\t\t\t\tmergedQueryGraphs[limitToItemType] = this.getMergedQueryGraph(\n\t\t\t\t\tlimitToItemType,\n\t\t\t\t\tparentChangesDelta._queryResults[limitToItemType],\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tgetMergedQueryGraph = itemType => {\n\t\t\t\tconst mergedQueryGraph = mergedQueryGraphs[itemType];\n\n\t\t\t\treturn mergedQueryGraph !== undefined\n\t\t\t\t\t? mergedQueryGraph\n\t\t\t\t\t: null;\n\t\t\t};\n\t\t} else {\n\t\t\tgetMergedQueryGraph = itemType => {\n\t\t\t\tconst mergedQueryGraph = mergedQueryGraphs[itemType];\n\n\t\t\t\treturn mergedQueryGraph !== undefined\n\t\t\t\t\t? mergedQueryGraph\n\t\t\t\t\t: (mergedQueryGraphs[itemType] as RootQueryNode<any> | null) = this.getMergedQueryGraph(\n\t\t\t\t\t\titemType,\n\t\t\t\t\t\tparentChangesDelta._queryResults[itemType],\n\t\t\t\t\t);\n\t\t\t};\n\t\t}\n\n\t\tconst matchingResultsAccumulatorMap = new MatchesAccumulatorMap<MatchingResultsAccumulatorMapType>();\n\n\t\tthis.transaction.itemHandler.matchItemsInDeletedChangesDelta(\n\t\t\tparentChangesDelta,\n\t\t\tgetMergedQueryGraph,\n\t\t\tmatchingResultsAccumulatorMap,\n\t\t);\n\n\t\tthis.transaction.itemHandler.matchItemsInUpdatedChangesDelta(\n\t\t\tparentChangesDelta.updated,\n\t\t\tgetMergedQueryGraph,\n\t\t\tmatchingResultsAccumulatorMap,\n\t\t);\n\n\t\tif (processEmptyUpdates) {\n\t\t\tthis.transaction.itemHandler.matchEmptyItemsInUpdatedChangesDelta(\n\t\t\t\tparentChangesDelta.updated,\n\t\t\t\tgetMergedQueryGraph,\n\t\t\t\tmatchingResultsAccumulatorMap,\n\t\t\t);\n\t\t}\n\n\t\tthis.transaction.itemHandler.matchItemsInCreatedChangesDelta(\n\t\t\tparentChangesDelta.created,\n\t\t\tgetMergedQueryGraph,\n\t\t\tmatchingResultsAccumulatorMap,\n\t\t);\n\n\t\t// We're resolving `maybe` matches before updating cached queries / collection resources. This has the advantage\n\t\t// that we can ensure all collections are up-to-date before changes listeners are fired. It has performance\n\t\t// implications though (in theory, at least): if we're dealing with an item matching cycle that touches locally\n\t\t// matchable queries as well, associated collections will only update once the server request has completed.\n\t\tconst promiseAccumulator: Promise<void>[] = [];\n\n\t\tfor (const matchingResultsMapEntry of matchingResultsAccumulatorMap) {\n\t\t\tconst itemType = matchingResultsMapEntry[0];\n\n\t\t\tfor (const matchingResultsEntry of matchingResultsMapEntry[1].entries() as Iterable<[string, MatchingResultsAccumulatorTuple<any>]>) {\n\t\t\t\tconst matchingResultsTuple = matchingResultsEntry[1];\n\n\t\t\t\tif (matchingResultsTuple.maybe === undefined) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tpromiseAccumulator.push(\n\t\t\t\t\tthis.processMaybeMatches(\n\t\t\t\t\t\titemType,\n\t\t\t\t\t\tmatchingResultsEntry[0],\n\t\t\t\t\t\tmatchingResultsTuple as RequireOnly<MatchingResultsAccumulatorTuple<any>, 'maybe'>,\n\t\t\t\t\t\tparentChangesDelta,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tawait Promise.all(\n\t\t\tpromiseAccumulator,\n\t\t);\n\n\t\treturn matchingResultsAccumulatorMap;\n\t}\n\n\tpublic applyMatchingResultsToCachedQueries (\n\t\tmatchingResultsAccumulatorMap: MatchesAccumulatorMap<MatchingResultsAccumulatorMapType>,\n\t): void {\n\t\tfor (const matchingResultsMapEntry of matchingResultsAccumulatorMap) {\n\t\t\tconst itemType = matchingResultsMapEntry[0];\n\n\t\t\tfor (const matchingResultsEntry of matchingResultsMapEntry[1].entries()) {\n\t\t\t\tconst cachedQueryItem = this.getCachedQueryItem(\n\t\t\t\t\titemType,\n\t\t\t\t\tmatchingResultsEntry[0],\n\t\t\t\t);\n\n\t\t\t\tif (cachedQueryItem === undefined) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst matchingResultsTuple = matchingResultsEntry[1] as MatchingResultsAccumulatorTuple<any>;\n\n\t\t\t\tcachedQueryItem.handleMatchedItemEntries(\n\t\t\t\t\tmatchingResultsTuple.true,\n\t\t\t\t\tmatchingResultsTuple.false,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Every time a cached query item is created, either 'resolve' or 'reject' has to be called on the cached query item.\n\t */\n\tpublic setCachedQuery<const ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tparsedQuery: CollectionQuery<ItemTypeType>,\n\t\trequestColumnsTuple: RequestColumnsTuple<ItemTypeType>,\n\t\titemEntries: ItemEntry<ItemTypeType>[],\n\t\tqueryGraph?: RootQueryNode<ItemTypeType>,\n\t): CachedQueryItem<ItemTypeType> {\n\t\tconst collectionTuple = this.getOrCreateCollectionTuple(\n\t\t\titemType,\n\t\t\tparsedQuery.string,\n\t\t);\n\n\t\treturn collectionTuple.cachedQueryItem = this.constructCachedQuery(\n\t\t\titemType,\n\t\t\tparsedQuery,\n\t\t\titemEntries,\n\t\t\trequestColumnsTuple,\n\t\t\tqueryGraph,\n\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Fetches a {@link CollectionEntry CollectionEntry} with the given options\n\t */\n\t// Renamed from fetchCollectionEntry\n\tpublic __fetchCachedQueryItem<const ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\toptions: CachedQueryOptionsWithColumns<ItemTypeType>,\n\t): Promise<CachedQueryItem<ItemTypeType>> {\n\t\tconst parsedQuery = this.createQueryFromOptions(\n\t\t\toptions,\n\t\t);\n\n\t\tthis.expandColumnsWithQueryColumns(\n\t\t\titemType,\n\t\t\toptions,\n\t\t\tparsedQuery.object,\n\t\t);\n\n\t\treturn this.__fetchItemEntriesByQueryData(\n\t\t\titemType,\n\t\t\toptions,\n\t\t\tthis.dependencies.requestColumnsOperationsCacheFactory.construct(\n\t\t\t\titemType,\n\t\t\t\toptions.columns,\n\t\t\t),\n\t\t\tparsedQuery,\n\t\t);\n\t}\n\n\tpublic getCachedQueryItemsByItemType<const ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t): CachedQueryItem<ItemTypeType>[] {\n\t\tconst collectionsforItemType = this.collections[itemType];\n\n\t\tif (collectionsforItemType === undefined) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst result: CachedQueryItem<ItemTypeType>[] = [];\n\n\t\tfor (const queryString in collectionsforItemType) {\n\t\t\tconst cachedQueryItem = collectionsforItemType[queryString]!.cachedQueryItem;\n\n\t\t\tif (cachedQueryItem !== undefined) {\n\t\t\t\tresult.push(\n\t\t\t\t\tcachedQueryItem,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic cloneCachedQuery<ItemTypeType extends ApiItemType> (\n\t\tcachedQueryItem: CachedQueryItem<ItemTypeType>,\n\t\tresolve: boolean = true,\n\t): CachedQueryItem<ItemTypeType> {\n\t\tconst clonedCacheQueryItem = this.setCachedQuery(\n\t\t\tcachedQueryItem.itemType,\n\t\t\tcachedQueryItem.query,\n\t\t\t// No need to copy here, whenever columns are expanded, a new copy is created.\n\t\t\tcachedQueryItem.requestColumnsTuple,\n\t\t\tcachedQueryItem.items.slice(),\n\t\t\tcachedQueryItem.queryGraph,\n\t\t);\n\n\t\tif (resolve) {\n\t\t\tclonedCacheQueryItem.resolve();\n\t\t}\n\n\t\treturn clonedCacheQueryItem;\n\t}\n\n\tpublic clearCachedQueryItem (\n\t\titemType: ApiItemType,\n\t\tqueryString: string,\n\t): void {\n\t\tif (this.collections[itemType]?.[queryString] === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tdelete this.collections[itemType][queryString].cachedQueryItem;\n\n\t\tthis.clearCollectionTupleIfEmpty(\n\t\t\titemType,\n\t\t\tqueryString,\n\t\t);\n\t}\n\n\t/**\n\t * Clears cached queries in the form of:\n\t * - {linkedTo: [itemType], query: {id: [itemId]}};\n\t * - {[linkField]: [itemId]}.\n\t *\n\t * This should catch most cached queries when deleting a parent item.\n\t */\n\tpublic clearLinkedCachedQueryItems (\n\t\titemEntry: ItemEntry,\n\t): void {\n\t\tconst linkTreeBranch = this.dependencies.linkTreeService.get()[itemEntry.itemType];\n\n\t\tfor (const linkedItemType in linkTreeBranch) {\n\t\t\tconst cachedQueriesForItemType = this.collections[linkedItemType as ApiItemType];\n\n\t\t\tif (cachedQueriesForItemType === undefined) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst linkTreeEntry = linkTreeBranch[linkedItemType];\n\n\t\t\tconst linkedToQuery: ApiQueryConditionLinkedTo<ApiItemType> = {\n\t\t\t\tlinkedTo: itemEntry.itemType,\n\t\t\t\tquery: {\n\t\t\t\t\tid: itemEntry.itemId,\n\t\t\t\t},\n\t\t\t};\n\n\t\t\tlet fieldQuery: ApiQuery<ApiItemType>;\n\n\t\t\tswitch (linkTreeEntry.type) {\n\t\t\t\tcase ApiLinkTreeType.ITEMTABLE:\n\t\t\t\t\tfieldQuery = {\n\t\t\t\t\t\tconditions: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\titemtype: itemEntry.itemType,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\titem: itemEntry.itemId,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t\t// Cast to query of an item linked using the table to get type checking.\n\t\t\t\t\t} as ApiQuery<'Taak'> as ApiQuery<ApiItemType>;\n\t\t\t\t\tbreak;\n\t\t\t\tcase ApiLinkTreeType.DIRECT:\n\t\t\t\t\tfieldQuery = {\n\t\t\t\t\t\t[linkTreeEntry.field]: itemEntry.itemId,\n\t\t\t\t\t} as ApiQuery<ApiItemType>;\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tconst linkedToQueryString = this\n\t\t\t\t.createQuery(\n\t\t\t\t\tlinkedToQuery,\n\t\t\t\t)\n\t\t\t\t.string;\n\t\t\tconst fieldQueryString = this\n\t\t\t\t.createQuery(\n\t\t\t\t\tfieldQuery,\n\t\t\t\t)\n\t\t\t\t.string;\n\n\t\t\tdelete cachedQueriesForItemType[linkedToQueryString];\n\t\t\tdelete cachedQueriesForItemType[fieldQueryString];\n\t\t}\n\t}\n\n\tpublic getCachedQueryItem<const ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tqueryString: string,\n\t): CachedQueryItem<ItemTypeType> | undefined {\n\t\treturn this.collections[itemType]?.[queryString]?.cachedQueryItem;\n\t}\n\n\t/**\n\t * Merges all query graphs for the given item type on the transaction. This allows changed items to be matched to\n\t * all queries simultaneously.\n\t * @param queryResults - When a set of items is already known to match a certain query, we can add a comparator node\n\t * for the item IDs to the end result. This can be beneficial for queries that can not be locally matched.\n\t */\n\tpublic getMergedQueryGraph<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tqueryResults?: {\n\t\t\t[queryString: string]: Set<ItemId<ItemTypeType>>,\n\t\t},\n\t): RootQueryNode<ItemTypeType> | null {\n\t\tconst queryGraphs = this.getQueryGraphsForItemType(\n\t\t\titemType,\n\t\t);\n\n\t\tif (queryGraphs.size === 0) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst result = new RootQueryNode<ItemTypeType>();\n\n\t\tfor (const queryGraph of queryGraphs) {\n\t\t\tresult.copyEdgesFrom(\n\t\t\t\tqueryGraph,\n\t\t\t\tundefined,\n\t\t\t);\n\t\t}\n\n\t\tif (queryResults !== undefined) {\n\t\t\tconst idQueryNode: IsComparatorQueryNode<ItemTypeType> = new IsComparatorQueryNode(\n\t\t\t\t'id',\n\t\t\t\tnumberBooleanNullValueTransformer,\n\t\t\t\tthis.dependencies.errorHandler,\n\t\t\t);\n\n\t\t\tfor (const queryString in queryResults) {\n\t\t\t\tconst leafNodes = this.getCollectionQueries(\n\t\t\t\t\titemType,\n\t\t\t\t\tqueryString,\n\t\t\t\t);\n\n\t\t\t\tfor (const itemId of queryResults[queryString]) {\n\t\t\t\t\tfor (const leafNode of leafNodes) {\n\t\t\t\t\t\tidQueryNode.connectLeafNode(\n\t\t\t\t\t\t\titemId,\n\t\t\t\t\t\t\tleafNode,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tresult.connectBranchNode(\n\t\t\t\tidQueryNode,\n\t\t\t);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic* getCachedQueryItemIterator (): Generator<CachedQueryItem> {\n\t\tconst collections = this.collections;\n\n\t\tfor (const itemType in collections) {\n\t\t\tfor (const queryString in collections[itemType]) {\n\t\t\t\tconst cachedQueryItem = collections[itemType as ApiItemType]![queryString]!.cachedQueryItem;\n\n\t\t\t\tif (cachedQueryItem !== undefined) {\n\t\t\t\t\tyield cachedQueryItem;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * @description\n\t * Fetches collections linked to the passed parents\n\t */\n\tpublic abstract __fetchItemEntriesByQueryData<const ItemTypeType extends ApiItemType> (\n\t\t// changesDelta: ChangesDelta,\n\t\titemType: ItemTypeType,\n\t\toptions: CachedQueryOptions<ItemTypeType>,\n\t\tcolumnsOperationsCache: RequestColumnsOperationsCache<ItemTypeType>,\n\t\tcollectionQuery: CollectionQuery<ItemTypeType>,\n\t\tlinkCollectionBatchQueryTuple?: LinkCollectionBatchQueryTuple<ItemTypeType>,\n\t): Promise<CachedQueryItem<ItemTypeType>>;\n\n\tpublic abstract __maybeExpandCachedQuery<const ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tqueryString: string,\n\t\tcolumnsOperationsCache: RequestColumnsOperationsCache<ItemTypeType>,\n\t\tbatchedLinkedToQuery?: CollectionQuery<ItemTypeType>,\n\t): Promise<CachedQueryItem<ItemTypeType>>;\n\n\tpublic queryIsCacheable<ItemTypeType extends ApiItemType> (\n\t\toptions: CachedQueryOptions<ItemTypeType>,\n\t\tquery: CollectionQuery<ItemTypeType>,\n\t): boolean {\n\t\treturn !options.preventCaching\n\t\t\t&& options.order?.limit === undefined\n\t\t\t// Never cache non-parsable queries since re-requesting them every time is less expensive than trying to match them\n\t\t\t&& query.isLocallyMatchable;\n\t}\n\n\tprotected createQueryFromOptions<ItemTypeType extends ApiItemType> (\n\t\toptions: CachedQueryOptions<ItemTypeType>,\n\t): CollectionQuery<ItemTypeType> {\n\t\tconst parent = options.parent;\n\t\tlet query: ApiQuery<ItemTypeType>;\n\n\t\tif (parent === undefined) {\n\t\t\tquery = options.query!;\n\t\t} else {\n\t\t\tconst linkedToQuery = {\n\t\t\t\tlinkedTo: parent.itemType,\n\t\t\t\tquery: {\n\t\t\t\t\tid: parent.itemId,\n\t\t\t\t},\n\t\t\t};\n\n\t\t\tquery = options.query === undefined\n\t\t\t\t? linkedToQuery\n\t\t\t\t: this.dependencies.queryService.addAndCondition(\n\t\t\t\t\toptions.query,\n\t\t\t\t\tlinkedToQuery,\n\t\t\t\t);\n\t\t}\n\n\t\treturn this.createQuery(\n\t\t\tquery,\n\t\t);\n\t};\n\n\t/**\n\t * @description\n\t * Expands the option's {@link CollectionOptions.columns columns} with the columns required for the {@link CacheSyncer CacheSyncer} to function.\n\t * Data fetched for a parent transaction might also fit in a child transaction, so those {@link CollectionOptions.queryColumns queryColumns} should also be taken into account\n\t */\n\tpublic expandColumnsWithQueryColumns<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\toptions: {\n\t\t\tcolumns: ApiRequestColumns<ItemTypeType>,\n\t\t\torder?: CollectionResourceOrder<ItemTypeType>,\n\t\t},\n\t\tquery: ApiQuery<ItemTypeType>,\n\t): void {\n\t\t// already have all columns, so can't expand them\n\t\tif (options.columns === true) {\n\t\t\treturn;\n\t\t}\n\n\t\t// The ID and permissions columns, as well as columns needed for delete relations are requested in the ServerCachedQueryHandler.\n\t\tconst requestColumnExpansion = this.dependencies.requestColumnExpansionFactory.construct();\n\n\t\trequestColumnExpansion.expandWithRequestColumns(\n\t\t\titemType,\n\t\t\toptions.columns,\n\t\t);\n\n\t\trequestColumnExpansion.expandWithRequestColumns(\n\t\t\titemType,\n\t\t\tnew QueryColumnExtractor(\n\t\t\t\tthis.dependencies.linkTreeService,\n\t\t\t\titemType,\n\t\t\t)\n\t\t\t\t.run(\n\t\t\t\t\tquery,\n\t\t\t\t) as ApiRequestColumnArray<ItemTypeType>,\n\t\t);\n\n\t\tif (options.order !== undefined) {\n\t\t\trequestColumnExpansion.expandWithRequestColumns(\n\t\t\t\titemType,\n\t\t\t\t[\n\t\t\t\t\toptions.order.field as ApiRequestColumn<ItemTypeType>,\n\t\t\t\t],\n\t\t\t);\n\t\t}\n\n\t\toptions.columns = requestColumnExpansion.get()[itemType] as ApiRequestColumnArray<ItemTypeType>;\n\t}\n\n\tprotected getOrCreateCollectionTuple<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tqueryString: string,\n\t): CachedQueryHandlerCollectionTuple<ItemTypeType> {\n\t\tlet collectionsForItemType = this.collections[itemType];\n\n\t\tif (collectionsForItemType === undefined) {\n\t\t\tcollectionsForItemType = this.collections[itemType] = {};\n\t\t}\n\n\t\tconst collectionTuple = collectionsForItemType[queryString];\n\n\t\treturn collectionTuple === undefined\n\t\t\t? collectionsForItemType[queryString] = {}\n\t\t\t: collectionTuple;\n\t}\n\n\t/**\n\t * Because this method is only called after a cached query (or collection resource) has been removed from the cache,\n\t * we're assuming the tuple is present.\n\t */\n\tprotected clearCollectionTupleIfEmpty<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tqueryString: string,\n\t): void {\n\t\tconst collectionsForItemType = this.collections[itemType]!;\n\n\t\tif (collectionsForItemType[queryString]!.cachedQueryItem === undefined) {\n\t\t\tdelete collectionsForItemType[queryString];\n\t\t}\n\t}\n\n\t/**\n\t * We're returning a set because multiple cached queries / collection resources might share the same query graph.\n\t * When using child collections, the query graph could already be a graph that matches multiple cached queries.\n\t * Collection resources often have the same query graph as the cached query.\n\t */\n\tprotected getQueryGraphsForItemType<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t): Set<RootQueryNode<ItemTypeType>> {\n\t\tconst collectionsForItemType = this.collections[itemType];\n\t\tconst result: Set<RootQueryNode<ItemTypeType>> = new Set();\n\n\t\tif (collectionsForItemType === undefined) {\n\t\t\treturn result;\n\t\t}\n\n\t\tfor (const queryString in collectionsForItemType) {\n\t\t\tconst cachedQueryItem = collectionsForItemType[queryString]!.cachedQueryItem;\n\n\t\t\tif (cachedQueryItem === undefined) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tresult.add(\n\t\t\t\tcachedQueryItem.queryGraph,\n\t\t\t);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * We're returning a set here to avoid duplicate collection query objects. When, for a specific query, both a cached\n\t * query and a collection resource exist, the collection query will be the same for both.\n\t */\n\tprotected getCollectionQueries<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tqueryString: string,\n\t): Set<CollectionQuery<ItemTypeType>> {\n\t\tconst cachedQueryItem = this.collections[itemType]?.[queryString]?.cachedQueryItem;\n\n\t\treturn cachedQueryItem !== undefined\n\t\t\t? new Set(\n\t\t\t\t[\n\t\t\t\t\tcachedQueryItem.query,\n\t\t\t\t],\n\t\t\t)\n\t\t\t: new Set();\n\t}\n\n\t/**\n\t * Handles `maybe` matches for the query identified by the `itemType` and `queryString`.\n\t *\n\t * @param matchingResultsTuple - A matching results tuple containing matched, non-matched and `maybe` item entries.\n\t * The properties containing matched and non-matched item entries are modified to include the `maybe` item entries.\n\t * The `maybe` property is kept, for now. (It is not read after this point.)\n\t * @param changesDelta - When doing a back-end request for `maybeMatchedItemEntries`, the resulting item IDs are\n\t * stored in this changes delta.\n\t */\n\tprotected async processMaybeMatches<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tqueryString: string,\n\t\tmatchingResultsTuple: RequireOnly<MatchingResultsAccumulatorTuple<any>, 'maybe'>,\n\t\tchangesDelta: ChangesDeltaBase,\n\t): Promise<void> {\n\t\tif (matchingResultsTuple.maybe.size === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst collectionQueries = this.getCollectionQueries(\n\t\t\titemType,\n\t\t\tqueryString,\n\t\t);\n\n\t\tif (collectionQueries.size === 0) {\n\t\t\tthis.dependencies.errorHandler.logError(\n\t\t\t\tnew Error(\n\t\t\t\t\t'CachedQueryHandlerBase: `processMaybeMatches()` called for query without associated cached query items or collection resources',\n\t\t\t\t),\n\t\t\t);\n\n\t\t\treturn;\n\t\t}\n\n\t\tlet queryResult: Set<ItemId> | undefined = changesDelta._getQueryResult(\n\t\t\titemType,\n\t\t\tqueryString,\n\t\t);\n\n\t\tif (queryResult === undefined) {\n\t\t\tconst response = await this.dependencies.apiRequestService.query(\n\t\t\t\titemType,\n\t\t\t\t(\n\t\t\t\t\t// We can be sure we have at least one value.\n\t\t\t\t\tcollectionQueries\n\t\t\t\t\t\t.values()\n\t\t\t\t\t\t.next() as IteratorYieldResult<CollectionQuery<ItemTypeType>>\n\t\t\t\t)\n\t\t\t\t\t.value\n\t\t\t\t\t.object as BackendApiQuery<ItemTypeType>,\n\t\t\t\t{\n\t\t\t\t\t[itemType]: [\n\t\t\t\t\t\t'id',\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tqueryResult = changesDelta._setQueryResult(\n\t\t\t\titemType,\n\t\t\t\tqueryString,\n\t\t\t\tresponse.links[itemType],\n\t\t\t);\n\t\t}\n\n\t\tfor (const itemEntry of matchingResultsTuple.maybe) {\n\t\t\tif (\n\t\t\t\tqueryResult.has(\n\t\t\t\t\titemEntry.itemId,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tmatchingResultsTuple.true.add(\n\t\t\t\t\titemEntry,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tif (matchingResultsTuple.false === undefined) {\n\t\t\t\t\tmatchingResultsTuple.false = new Set();\n\t\t\t\t}\n\n\t\t\t\tmatchingResultsTuple.false.add(\n\t\t\t\t\titemEntry,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Every time a cached query item is created, either 'resolve' or 'reject' has to be called on the cached query item.\n\t */\n\tprotected constructCachedQuery<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tparsedQuery: CollectionQuery<ItemTypeType>,\n\t\titemEntries: ItemEntry<ItemTypeType>[],\n\t\trequestColumnsTuple: RequestColumnsTuple<ItemTypeType>,\n\t\tqueryGraph: RootQueryNode<ItemTypeType> = this.createQueryGraph(\n\t\t\titemType,\n\t\t\tparsedQuery,\n\t\t),\n\t): CachedQueryItem<ItemTypeType> {\n\t\treturn new CachedQueryItem(\n\t\t\titemType,\n\t\t\tparsedQuery,\n\t\t\tqueryGraph,\n\t\t\titemEntries,\n\t\t\trequestColumnsTuple,\n\t\t);\n\t}\n\n\tprivate createQueryGraph<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tparsedQuery: CollectionQuery<ItemTypeType>,\n\t): RootQueryNode<ItemTypeType> {\n\t\treturn this.dependencies.graphQueryParserFactory\n\t\t\t.construct(\n\t\t\t\titemType,\n\t\t\t\tparsedQuery,\n\t\t\t)\n\t\t\t.run(\n\t\t\t\tparsedQuery.object,\n\t\t\t);\n\t}\n\n}\n","import { ApiItemType } from '@rentman/backend-types';\nimport { GraphQueryParserFactory } from '../../../factories/GraphQueryParserFactory';\nimport { ApiRequestLimit, ApiRequestService, CachedQueryHandlerBase, CachedQueryItem, CachedQueryOptions, CollectionQuery, CollectionResource, ErrorHandlerInterface, ItemEntry, LinkCollectionBatchQueryTuple, LinkTreeServiceInterface, QueryService, RequestColumnExpansionFactory, RequestColumnsOperationsCache, RequestColumnsOperationsCacheFactory, ServerCache, TransactionCache } from '../../../internal';\n\nexport class ServerCachedQueryHandler\n\textends CachedQueryHandlerBase {\n\n\tpublic constructor (\n\t\tdependencies: {\n\t\t\tapiRequestService: ApiRequestService,\n\t\t\terrorHandler: ErrorHandlerInterface,\n\t\t\tgraphQueryParserFactory: GraphQueryParserFactory,\n\t\t\tlinkTreeService: LinkTreeServiceInterface,\n\t\t\tqueryService: QueryService,\n\t\t\trequestColumnExpansionFactory: RequestColumnExpansionFactory,\n\t\t\trequestColumnsOperationsCacheFactory: RequestColumnsOperationsCacheFactory,\n\t\t},\n\t\tprotected transaction: ServerCache,\n\t) {\n\t\tsuper(\n\t\t\tdependencies,\n\t\t\ttransaction,\n\t\t);\n\t}\n\n\tpublic hasActiveCollectionsForQuery (\n\t\titemType: ApiItemType,\n\t\tqueryString: string,\n\t): boolean {\n\t\tconst iterator = this.transaction.getDescendantsIterator();\n\n\t\tfor (const transaction of iterator) {\n\t\t\tconst collectionIterator = transaction.cachedQueryHandler.getCollectionResources(\n\t\t\t\titemType,\n\t\t\t\tqueryString,\n\t\t\t);\n\n\t\t\tfor (const _collectionResource of collectionIterator) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tpublic markCachedQueriesOutdatedInAllTransactions (\n\t\titemType: ApiItemType,\n\t\tqueryString: string,\n\t): void {\n\t\tconst invalidateCachedQuery = (\n\t\t\tcachedQueryHandler: CachedQueryHandlerBase,\n\t\t): void => {\n\t\t\tconst cachedQueryItem = cachedQueryHandler.getCachedQueryItem(\n\t\t\t\titemType,\n\t\t\t\tqueryString,\n\t\t\t);\n\n\t\t\tcachedQueryItem?.markOutdated();\n\t\t};\n\n\t\tconst processChildTransactions = (\n\t\t\ttransactions: TransactionCache[],\n\t\t): void => {\n\t\t\tfor (const transaction of transactions) {\n\t\t\t\tinvalidateCachedQuery(\n\t\t\t\t\ttransaction.cachedQueryHandler,\n\t\t\t\t);\n\n\t\t\t\tprocessChildTransactions(\n\t\t\t\t\ttransaction.children,\n\t\t\t\t);\n\t\t\t}\n\t\t};\n\n\t\tinvalidateCachedQuery(\n\t\t\tthis,\n\t\t);\n\n\t\tprocessChildTransactions(\n\t\t\tthis.transaction.children,\n\t\t);\n\t}\n\n\tpublic* getUncachedCollectionsOnChildTransactionsIterator<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t): Generator<CollectionResource<ItemTypeType>> {\n\t\tconst transactionsAccumulator: TransactionCache[] = [];\n\n\t\tconst accumulateTransactions = (\n\t\t\ttransactions: TransactionCache[],\n\t\t) => {\n\t\t\tfor (const transaction of transactions) {\n\t\t\t\ttransactionsAccumulator.push(\n\t\t\t\t\ttransaction,\n\t\t\t\t);\n\n\t\t\t\taccumulateTransactions(\n\t\t\t\t\ttransaction.children,\n\t\t\t\t);\n\t\t\t}\n\t\t};\n\n\t\taccumulateTransactions(\n\t\t\tthis.transaction.children,\n\t\t);\n\n\t\tfor (const transaction of transactionsAccumulator) {\n\t\t\tconst iterator = transaction.cachedQueryHandler.getUncachedCollectionsIterator(\n\t\t\t\titemType,\n\t\t\t);\n\n\t\t\tfor (const collectionResource of iterator) {\n\t\t\t\tyield collectionResource;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * @description\n\t * Expands the columns of the items in the cached query\n\t */\n\tpublic __maybeExpandCachedQuery<const ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tqueryString: string,\n\t\tcolumnsOperationsCache: RequestColumnsOperationsCache<ItemTypeType>,\n\t\tbatchedLinkedToQuery?: CollectionQuery<ItemTypeType>,\n\t): Promise<CachedQueryItem<ItemTypeType>> {\n\t\tconst cachedQuery = this.getCachedQueryItem(\n\t\t\titemType,\n\t\t\tqueryString,\n\t\t);\n\n\t\tif (cachedQuery === undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t`ServerCachedQueryHandler: tried to expand non-existing query: ${itemType} - ${queryString}`,\n\t\t\t);\n\t\t}\n\n\t\tif (\n\t\t\t// If we're not expanding columns we can assume we either have everything or it's still underway (but at least we don't need more)\n\t\t\tcolumnsOperationsCache.tupleContainsAllColumns(\n\t\t\t\tcachedQuery.requestColumnsTuple,\n\t\t\t\tthis.transaction,\n\t\t\t)\n\t\t\t&& (\n\t\t\t\t// In that case, if the request is still pending, we will assume we get the latest aggregate values\n\t\t\t\t!cachedQuery.itemsResolved()\n\t\t\t\t// If the request is not pending, we need to re-fetch the data to ensure we have the latest aggregate values\n\t\t\t\t|| !columnsOperationsCache.hasAggregateColumns()\n\t\t\t)\n\t\t) {\n\t\t\treturn cachedQuery.promise;\n\t\t}\n\n\t\treturn this.transaction.requestBufferManager\n\t\t\t.fetchByQuery(\n\t\t\t\tcachedQuery.itemType,\n\t\t\t\tbatchedLinkedToQuery === undefined\n\t\t\t\t\t? cachedQuery.query\n\t\t\t\t\t: batchedLinkedToQuery,\n\t\t\t\t// When expanding a collection, it can happen that the backend returns more items that we have currently cached. This can happen\n\t\t\t\t// due to a race condition when refreshing items (over socket, when someone else saves), or when missing a socket message altoghether.\n\t\t\t\t// To ensure these newly returned items contain all data that we need to match and use in the UI we need to request all columns that are currently used in the cached query\n\t\t\t\tcolumnsOperationsCache.getColumnsMergedWithTuple(\n\t\t\t\t\tcachedQuery.requestColumnsTuple,\n\t\t\t\t\tthis.transaction,\n\t\t\t\t).merged,\n\t\t\t)\n\t\t\t.then(\n\t\t\t\t() => {\n\t\t\t\t\t// We call getColumnsMergedWithTuple here because another request could've changed the cached requestColumns in the meantime.\n\t\t\t\t\tcachedQuery.requestColumnsTuple = columnsOperationsCache.getColumnsMergedWithTuple(\n\t\t\t\t\t\tcachedQuery.requestColumnsTuple,\n\t\t\t\t\t\tthis.transaction,\n\t\t\t\t\t).merged;\n\n\t\t\t\t\treturn cachedQuery.promise;\n\t\t\t\t},\n\t\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Fetches the data for the passed ItemType/options, will do nothing if the requested CollectionEntry/columns are already cached.\n\t * Will create a new {@link CollectionEntry CollectionEntry} if the CollectionEntry didn't exist yet\n\t */\n\tpublic async __fetchItemEntriesByQueryData<const ItemTypeType extends ApiItemType> (\n\t\t// _changesDelta: ChangesDelta,\n\t\titemType: ItemTypeType,\n\t\toptions: CachedQueryOptions<ItemTypeType>,\n\t\tcolumnsOperationsCache: RequestColumnsOperationsCache<ItemTypeType>,\n\t\tcollectionQuery: CollectionQuery<ItemTypeType>,\n\t\tlinkCollectionBatchQueryTuple?: LinkCollectionBatchQueryTuple<ItemTypeType>,\n\t): Promise<CachedQueryItem<ItemTypeType>> {\n\t\t// If we have a limit we don't care about the cached entries, we just want to make sure the items we want in the limit are there\n\t\tif (\n\t\t\t!this.queryIsCacheable(\n\t\t\t\toptions,\n\t\t\t\tcollectionQuery,\n\t\t\t)\n\t\t) {\n\t\t\tconst requestColumnsTuple = columnsOperationsCache.getRequestColumnsTuple(\n\t\t\t\tthis.transaction,\n\t\t\t);\n\n\t\t\tconst result = await this.transaction.requestBufferManager.fetchByQuery(\n\t\t\t\titemType,\n\t\t\t\tcollectionQuery,\n\t\t\t\trequestColumnsTuple,\n\t\t\t\t{\n\t\t\t\t\tlimit: options.order?.limit !== undefined\n\t\t\t\t\t\t? options.order as ApiRequestLimit<ItemTypeType>\n\t\t\t\t\t\t: undefined,\n\t\t\t\t\t// We should not batch this request with other queries because we use the full result to construct the items of the cached query\n\t\t\t\t\t// (which could then contain items that don't actually match this query)\n\t\t\t\t\tflushTimeout: 0,\n\t\t\t\t\t// TODO: We could reduce the buffer flush timeout here.\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tconst itemEntries: ItemEntry<ItemTypeType>[] = [];\n\n\t\t\tfor (const itemId of result.response.links[itemType]) {\n\t\t\t\titemEntries.push(\n\t\t\t\t\tthis.transaction.itemHandler.entries.get(\n\t\t\t\t\t\titemType,\n\t\t\t\t\t\titemId,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst fakeCachedQuery = this.constructCachedQuery(\n\t\t\t\titemType,\n\t\t\t\tcollectionQuery,\n\t\t\t\titemEntries,\n\t\t\t\trequestColumnsTuple,\n\t\t\t);\n\n\t\t\tfakeCachedQuery.resolve();\n\n\t\t\treturn fakeCachedQuery;\n\t\t}\n\n\t\tlet cachedQuery = this.getCachedQueryItem(\n\t\t\titemType,\n\t\t\tcollectionQuery.string,\n\t\t);\n\n\t\tif (cachedQuery !== undefined) {\n\t\t\tif (!cachedQuery.isOutdated()) {\n\t\t\t\treturn this.__maybeExpandCachedQuery(\n\t\t\t\t\titemType,\n\t\t\t\t\tcollectionQuery.string,\n\t\t\t\t\tcolumnsOperationsCache,\n\t\t\t\t\tlinkCollectionBatchQueryTuple?.batchQuery,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Since we're going to re-fetch the data and then sync the cached query, we can immediately mark it as up-to-date\n\t\t\t// If we don't do this, we might end up re-fetching this data multiple times while the request is still pending\n\t\t\tcachedQuery.markUpToDate();\n\t\t} else {\n\t\t\t// We need to init the query string cache before fetching the items because transaction.processResponse will call a queryMatcher and add them\n\t\t\tcachedQuery = this.setCachedQuery(\n\t\t\t\titemType,\n\t\t\t\tcollectionQuery,\n\t\t\t\tcolumnsOperationsCache.getRequestColumnsTuple(\n\t\t\t\t\tthis.transaction,\n\t\t\t\t),\n\t\t\t\t[],\n\t\t\t\tlinkCollectionBatchQueryTuple?.batchQueryGraph,\n\t\t\t);\n\t\t}\n\n\t\treturn this.transaction.requestBufferManager\n\t\t\t.fetchByQuery(\n\t\t\t\titemType,\n\t\t\t\tlinkCollectionBatchQueryTuple?.batchQuery ?? collectionQuery,\n\t\t\t\tcolumnsOperationsCache.getRequestColumnsTuple(\n\t\t\t\t\tthis.transaction,\n\t\t\t\t),\n\t\t\t)\n\t\t\t.then(\n\t\t\t\t() => {\n\t\t\t\t\t// We re-call getColumnsMergedWithTuple because another request could've changed the cached requestColumns in the meantime\n\t\t\t\t\tcachedQuery.requestColumnsTuple = columnsOperationsCache.getColumnsMergedWithTuple(\n\t\t\t\t\t\tcachedQuery.requestColumnsTuple,\n\t\t\t\t\t\tthis.transaction,\n\t\t\t\t\t).merged;\n\n\t\t\t\t\tcachedQuery.resolve();\n\n\t\t\t\t\treturn cachedQuery;\n\t\t\t\t},\n\t\t\t\terror => {\n\t\t\t\t\tcachedQuery.reject(\n\t\t\t\t\t\terror,\n\t\t\t\t\t);\n\n\t\t\t\t\tthrow error;\n\t\t\t\t},\n\t\t\t);\n\t}\n\n}\n","export class TransactionPendingException\n\textends Error {\n\n}","import { computed, signal, untracked, WritableSignal } from '@angular/core';\nimport { ApiItemType, ItemId } from '@rentman/backend-types';\nimport { TransactionPendingException } from '../../../exceptions/TransactionPendingException';\nimport { AbstractCache, AbstractCacheDependencyInterface, AggregatedChangesByListener, AggregatedChangesListenerFunction, ApiQuery, ApiRequestColumnArray, ApiRequestColumns, CachedQueryItem, CachedQueryItemsItemTypeTuple, ChangesDelta, ChangesDeltaResult, ChildChangesDelta, ChildCollectionResources, CollectionItemResourceChanges, CollectionOptions, CollectionQuery, CollectionResource, ColumnSetMap, ConversionMap, createPath, CreateRequestParameterMap, DeregFunction, FieldMap, hasProperties, ItemAggregatedChangesListener, ItemChangesListener, ItemChangesListenerContext, ItemEntry, ItemIdConversionMap, ItemLockedException, ItemOptions, ItemResource, ItemResourcesItemTypeMap, ItemsByQueryOptions, ItemTypeMap, KeyService, LimitedCollectionResource, merge, ModuleChangesCompilationResult, NewItemOptions, OnAfterCreateCallback, ParentChangesDelta, ParentIdMap, ResponseColumnItemTypeMap, RmCore, RootCollectionOptions, RootCollectionOptionsWithParent, ServerCache, TransactionCacheCallbackCondition, TransactionCacheCallbackType, TransactionCachedQueryHandler, TransactionEventHandler, TransactionItemHandler, TransactionOptions, TransactionValidator, TransactionValidatorFactory } from '../../../internal';\nimport { TransactionValidatorWithDependencies } from './TransactionValidatorWithDependencies';\n\ntype ItemResourceLinks<\n\tItemTypeType extends ApiItemType,\n\tColumnIds extends ApiRequestColumnArray<ItemTypeType>,\n\tChildren extends ChildCollectionResources | undefined\n> = {\n\tmain: ItemResource<ItemTypeType, ColumnIds, Children>,\n\tlinked: ItemResourcesItemTypeMap,\n};\n\nexport enum TransactionErrorLevel {\n\twarning = 'warning',\n\terror = 'error'\n}\n\ntype TransactionState =\n\t'Ready' // Transaction is ready to be saved\n\t| 'Saving' // Transaction is currently in the state of being saved\n\t| 'Pending'; // Transaction is currently set to pending by an external source\n\nexport type TransactionError = {\n\tfieldString: string,\n\tstring: string,\n\tlevel: TransactionErrorLevel,\n\tlocation?: string,\n};\n\nexport type GlobalTransactionError = {\n\tstring: string,\n\tlevel: TransactionErrorLevel,\n};\n\n/**\n * Converts child CollectionOptionsInterfaces to CollectionResources.\n */\nexport type OptionsToChildCollections<\n\tOptionsType\n> = OptionsType extends {\n\t\tchildren: {\n\t\t\t[itemType: string]: {\n\t\t\t\tcolumns: any,\n\t\t\t},\n\t\t},\n\t}\n\t? {\n\t\t[ChildItemType in keyof OptionsType['children']]: ChildItemType extends ApiItemType\n\t\t\t? OptionsToCollectionResource<\n\t\t\t\tChildItemType,\n\t\t\t\tOptionsType['children'][ChildItemType]\n\t\t\t>\n\t\t\t: never\n\t}\n\t: undefined;\n\nexport type OptionsToCollectionResource<\n\tItemTypeType extends ApiItemType,\n\tOptionsType extends {\n\t\tcolumns: ApiRequestColumnArray<ItemTypeType>,\n\t}\n> = OptionsType extends {\n\t\torder: {\n\t\t\tlimit: number,\n\t\t},\n\t}\n\t? LimitedCollectionResource<ItemTypeType, OptionsType['columns'], OptionsToChildCollections<OptionsType>>\n\t: CollectionResource<ItemTypeType, OptionsType['columns'], OptionsToChildCollections<OptionsType>>;\n\n/**\n * @description\n * The {@link TransactionCache TransactionCache} is responsible for keeping track of newly created {@link ItemEntry ItemEntries}\n * and {@link CollectionEntry CollectionEntries}, and the changes of existing ItemEntries and CollectionEntries.\n *\n * The TransactionCache is also responsible for creating {@link ItemResource ItemResources}, which is a combination of an {@link ItemEntry ItemEntry} and the current transaction's changes on this ItemEntry\n */\nexport class TransactionCache\n\textends AbstractCache {\n\n\t/**\n\t * @description\n\t * A map of all item errors, can be populated using {@link TransactionValidator.setGlobalError TransactionValidator.setGlobalError} and {@link TransactionValidator.setItemError TransactionValidator.setItemError}.\n\t * Contains a translation and level for every error\n\t */\n\tpublic errors: {\n\t\titem: WritableSignal<{\n\t\t\t[itemEntryId: string]: {\n\t\t\t\t[columnId: string]: {\n\t\t\t\t\t[errorKey: string]: TransactionError,\n\t\t\t\t},\n\t\t\t},\n\t\t}>,\n\t\tglobal: WritableSignal<{\n\t\t\t[key: string]: GlobalTransactionError,\n\t\t}>,\n\t} = {\n\t\titem: signal(\n\t\t\t{},\n\t\t),\n\t\tglobal: signal(\n\t\t\t{},\n\t\t),\n\t};\n\n\tpublic firstError = computed(\n\t\t() => {\n\t\t\tconst globalErrors = this.errors.global();\n\n\t\t\tfor (const errorKey in globalErrors) {\n\t\t\t\tconst error = globalErrors[errorKey];\n\n\t\t\t\tif (error.level === TransactionErrorLevel.error) {\n\t\t\t\t\treturn error;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst allItemErrors = this.errors.item();\n\n\t\t\tfor (const itemEntryId in allItemErrors) {\n\t\t\t\tconst itemErrors = allItemErrors[itemEntryId];\n\n\t\t\t\tfor (const columnId in itemErrors) {\n\t\t\t\t\tconst columnErrors = itemErrors[columnId];\n\n\t\t\t\t\tfor (const errorKey in columnErrors) {\n\t\t\t\t\t\tconst error = columnErrors[errorKey];\n\n\t\t\t\t\t\tif (error.level === TransactionErrorLevel.error) {\n\t\t\t\t\t\t\treturn error;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn undefined;\n\t\t},\n\t);\n\n\tpublic firstErrorString = computed(\n\t\t() => this.firstError()?.string,\n\t);\n\n\tpublic rootItemSignal = signal<ItemEntry | undefined>(\n\t\tundefined,\n\t);\n\n\t/**\n\t * @description\n\t * Stores additional request parameters for when the transaction is stored to the server\n\t */\n\tpublic tabRequestParameters = {};\n\n\tpublic hasChangesSignal = signal(\n\t\tfalse,\n\t);\n\n\t/**\n\t * @description\n\t * The transaction's parent\n\t */\n\tpublic readonly parent: AbstractCache;\n\tpublic readonly itemHandler: TransactionItemHandler;\n\tpublic readonly cachedQueryHandler: TransactionCachedQueryHandler;\n\tpublic readonly eventHandler: TransactionEventHandler;\n\n\tpublic readonly validator?: TransactionValidator;\n\tpublic validatorWithDependencies?: TransactionValidatorWithDependencies<any>;\n\n\tprivate readonly options: TransactionOptions;\n\n\tprivate changesDeltasBeingApplied: Promise<void>[] = [];\n\n\tprivate transactionStateSignal = signal<TransactionState>(\n\t\t'Ready',\n\t);\n\n\tpublic isSavingSignal = computed(\n\t\t() => this.transactionStateSignal() === 'Saving',\n\t);\n\n\tpublic isReadySignal = computed(\n\t\t() => this.transactionStateSignal() === 'Ready',\n\t);\n\n\tpublic isPendingSignal = computed(\n\t\t() => {\n\t\t\tif (\n\t\t\t\tthis.isSavingSignal()\n\t\t\t\t|| this.transactionStateSignal() === 'Pending'\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif (this.children.length > 0) {\n\t\t\t\tfor (const child of this.children) {\n\t\t\t\t\tif (child.isPendingSignal()) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t},\n\t);\n\n\tpublic isDestroyedSignal: WritableSignal<boolean> = signal(\n\t\tfalse,\n\t);\n\n\tpublic isValidSignal = computed(\n\t\t() => {\n\t\t\tif (this.isPendingSignal()) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// Note: We cannot move the validator pending checks to isPending, because we often manually apply changes to the state right before saving.\n\t\t\t// In the `save` function we check if we're pending and exit early, which means this would block the save flow.\n\t\t\tif (this.validator?.isPendingSignal() === true) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif (this.validatorWithDependencies?.isPendingSignal() === true) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn this.firstError() === undefined;\n\t\t},\n\t);\n\n\tpublic constructor (\n\t\tdependencies: AbstractCacheDependencyInterface,\n\t\tcore: RmCore,\n\t\tparent: AbstractCache,\n\t\t/**\n\t\t * @description\n\t\t * For debugging purposes\n\t\t */\n\t\tpublic id?: string,\n\t\tvalidatorFactory?: TransactionValidatorFactory,\n\t\toptions?: Partial<TransactionOptions>,\n\t) {\n\t\tsuper(\n\t\t\tdependencies,\n\t\t\tcore,\n\t\t);\n\n\t\tthis.options = {\n\t\t\ttransparent: false,\n\t\t\t...options,\n\t\t};\n\n\t\tthis.validator = validatorFactory === undefined\n\t\t\t? undefined\n\t\t\t: validatorFactory.construct(\n\t\t\t\tthis,\n\t\t\t);\n\n\t\tthis.parent = parent;\n\n\t\tthis.itemHandler = new TransactionItemHandler(\n\t\t\tdependencies,\n\t\t\tthis,\n\t\t);\n\n\t\tthis.cachedQueryHandler = new TransactionCachedQueryHandler(\n\t\t\tdependencies,\n\t\t\tthis,\n\t\t);\n\n\t\tthis.eventHandler = new TransactionEventHandler(\n\t\t\tdependencies.errorHandler,\n\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Stores the 'root' {@link ItemEntry ItemEntry}, this {@link ItemEntry ItemEntry} can be used as request parent to store the whole transaction at once\n\t */\n\tpublic get rootItem (): ItemEntry | undefined {\n\t\treturn untracked(\n\t\t\t() => this.rootItemSignal(),\n\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Is true when the current transaction has:\n\t * - Newly created items\n\t * - Removed items (from collections)\n\t * - Changes on existing items\n\t */\n\tpublic get hasChanges (): boolean {\n\t\treturn untracked(\n\t\t\t() => this.hasChangesSignal(),\n\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Is true while the {@link TransactionCache TransactionCache} is applying changes to the parent (can either be through a merge or an Api save)\n\t */\n\tpublic get isSaving (): boolean {\n\t\treturn untracked(\n\t\t\t() => this.isSavingSignal(),\n\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Is true while the {@link TransactionCache TransactionCache} is ready to handle new saves\n\t */\n\tpublic get isReady (): boolean {\n\t\treturn untracked(\n\t\t\t() => this.isReadySignal(),\n\t\t);\n\t}\n\n\tpublic get isValid (): boolean {\n\t\treturn untracked(\n\t\t\t() => this.isValidSignal(),\n\t\t);\n\t}\n\n\tpublic attachValidator (\n\t\tvalidator: TransactionValidatorWithDependencies<any>,\n\t): void {\n\t\tif (this.validatorWithDependencies !== undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t'TransactionCache: validator already attached',\n\t\t\t);\n\t\t}\n\n\t\tif (validator.dependencies === undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t'TransactionCache: validator dependencies are undefined. Did you call `fetchDependencies` first?',\n\t\t\t);\n\t\t}\n\n\t\tthis.validatorWithDependencies = validator;\n\n\t\tconst aggregatedChanges = {\n\t\t\titem: {\n\t\t\t\t[validator.dependencies.rootItem.itemType]: [\n\t\t\t\t\tnew ItemChangesListenerContext(\n\t\t\t\t\t\tvalidator.dependencies.rootItem,\n\t\t\t\t\t\tthis.itemHandler,\n\t\t\t\t\t\t{},\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t),\n\t\t\t\t],\n\t\t\t},\n\t\t\tcollection: {},\n\t\t};\n\n\t\tconst addCollection = (\n\t\t\tcollectionResource: CollectionResource<any, any, any>,\n\t\t): void => {\n\t\t\tconst contexts = aggregatedChanges.collection[collectionResource.itemType] ??= [];\n\n\t\t\tcontexts.push(\n\t\t\t\t{\n\t\t\t\t\taddedItems: collectionResource.items,\n\t\t\t\t\tremovedItems: [],\n\t\t\t\t\tchangedItems: [],\n\t\t\t\t\tcollectionResource,\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tfor (const itemResource of collectionResource.items) {\n\t\t\t\tfor (const childCollectionItemType in itemResource.children) {\n\t\t\t\t\taddCollection(\n\t\t\t\t\t\titemResource.children[childCollectionItemType],\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tfor (const childCollectionItemType in validator.dependencies.rootItem.children) {\n\t\t\taddCollection(\n\t\t\t\tvalidator.dependencies.rootItem.children[childCollectionItemType],\n\t\t\t);\n\t\t}\n\n\t\tvalidator.validate(\n\t\t\taggregatedChanges.collection,\n\t\t\taggregatedChanges.item,\n\t\t\tfalse,\n\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Checks if the transaction is pending (or saving) on itself and on all of its children recursively\n\t * This can be used to block a transaction if one of the children is still loading (for instance for a file upload)\n\t */\n\tpublic isPending (): boolean {\n\t\treturn untracked(\n\t\t\t() => this.isPendingSignal(),\n\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Sets the transactionstate to pending, must recieve a promise as a parameter, on promise resolve, transactionstate gets put back to ready\n\t * If the transaction is already in state saving, we use that and let the save function return it to ready\n\t * @param promise\n\t */\n\tpublic setPending (\n\t\tpromise: Promise<any>,\n\t): Promise<any> {\n\t\tif (\n\t\t\tuntracked(\n\t\t\t\t() => this.transactionStateSignal() !== 'Ready',\n\t\t\t)\n\t\t) {\n\t\t\tthrow new TransactionPendingException(\n\t\t\t\t'TransactionCache: Tried to set pending on a transaction that is already saving or pending',\n\t\t\t);\n\t\t}\n\n\t\tthis.transactionStateSignal.set(\n\t\t\t'Pending',\n\t\t);\n\n\t\tvoid promise.finally(\n\t\t\t() => this.transactionStateSignal.set(\n\t\t\t\t'Ready',\n\t\t\t),\n\t\t);\n\n\t\treturn promise;\n\t}\n\n\t// WARNING: createChild is not in AbstractCache to prevent a circular dependency between AbstractCache <-> TransactionCache\n\tpublic createChild (\n\t\tid?: string,\n\t\tvalidatorFactory?: TransactionValidatorFactory,\n\t\toptions?: TransactionOptions,\n\t): TransactionCache {\n\t\tif (this.options.transparent) {\n\t\t\treturn this.parent.createChild(\n\t\t\t\tid,\n\t\t\t\tvalidatorFactory,\n\t\t\t\toptions,\n\t\t\t);\n\t\t}\n\n\t\tconst transaction = new TransactionCache(\n\t\t\tthis.dependencies,\n\t\t\tthis.core,\n\t\t\tthis,\n\t\t\tid,\n\t\t\tvalidatorFactory,\n\t\t\toptions,\n\t\t);\n\n\t\tthis.children.push(\n\t\t\ttransaction,\n\t\t);\n\n\t\treturn transaction;\n\t}\n\n\tpublic destroy (): void {\n\t\tif (this.rootItem !== undefined) {\n\t\t\tvoid this.dependencies.lockService.deleteLock(\n\t\t\t\tthis.rootItem,\n\t\t\t);\n\t\t}\n\n\t\tthis.eventHandler.clear();\n\n\t\tthis.parent.onChildDestroy(\n\t\t\tthis,\n\t\t);\n\n\t\tthis.isDestroyedSignal.set(\n\t\t\ttrue,\n\t\t);\n\t}\n\n\tpublic isDestroyed (): boolean {\n\t\treturn untracked(\n\t\t\t() => this.isDestroyedSignal(),\n\t\t);\n\t}\n\n\t// Renamed from expandCollectionEntry\n\tpublic expandCollectionResource<ItemTypeType extends ApiItemType> (\n\t\tcollectionResource: CollectionResource<ItemTypeType>,\n\t\tnewColumns: ApiRequestColumns<ItemTypeType>,\n\t): Promise<CollectionResource<ItemTypeType>> {\n\t\tif (collectionResource.transaction !== this) {\n\t\t\tthrow new Error(\n\t\t\t\t'TransactionCache: tried to expand collection resource on different transaction',\n\t\t\t);\n\t\t}\n\n\t\tconst itemType = collectionResource.entry.itemType;\n\n\t\t// This will always work, whether the query is cached or not. __expandCachedQuery will be called behind the\n\t\t// scenes if necessary.\n\t\treturn this.cachedQueryHandler\n\t\t\t.__fetchItemEntriesByQueryData(\n\t\t\t\titemType,\n\t\t\t\tcollectionResource.options,\n\t\t\t\tthis.dependencies.requestColumnsOperationsCacheFactory.construct(\n\t\t\t\t\titemType,\n\t\t\t\t\tnewColumns,\n\t\t\t\t),\n\t\t\t\tcollectionResource.entry.query,\n\t\t\t)\n\t\t\t.then(\n\t\t\t\t() => {\n\t\t\t\t\t// We assume all columns are there since they're fetched when fetching the data for the collection.\n\t\t\t\t\tcollectionResource.entry.expandColumns(\n\t\t\t\t\t\tthis.dependencies.columnExpansionFactory.construct(\n\t\t\t\t\t\t\titemType,\n\t\t\t\t\t\t\tnewColumns,\n\t\t\t\t\t\t\tthis.dependencies.columnCache.retrieve(\n\t\t\t\t\t\t\t\titemType,\n\t\t\t\t\t\t\t\tnewColumns,\n\t\t\t\t\t\t\t).cached as ResponseColumnItemTypeMap,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\n\t\t\t\t\treturn collectionResource;\n\t\t\t\t},\n\t\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Expands the collections with the new request columns. All collections should have the same query (excluding the\n\t * parent).\n\t */\n\tpublic expandCollectionResources<\n\t\tconst ItemTypeType extends ApiItemType,\n\t\tCollectionResourceType extends CollectionResource<ItemTypeType, any, any>,\n\t> (\n\t\titemType: ItemTypeType,\n\t\tcollections: ParentIdMap<CollectionResourceType>,\n\t\tnewColumns: ApiRequestColumnArray<ItemTypeType>,\n\t): Promise<ParentIdMap<CollectionResourceType>> {\n\t\tif (\n\t\t\t!hasProperties(\n\t\t\t\tcollections,\n\t\t\t)\n\t\t) {\n\t\t\treturn Promise.resolve(\n\t\t\t\t{},\n\t\t\t);\n\t\t}\n\n\t\tconst optionsTuples: {\n\t\t\toptions: RootCollectionOptionsWithParent<ItemTypeType, any, any>,\n\t\t\tquery: CollectionQuery<ItemTypeType>,\n\t\t}[] = [];\n\n\t\tfor (const parentId in collections) {\n\t\t\tconst collectionResource = collections[parentId];\n\n\t\t\tif (collectionResource.transaction !== this) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t'TransactionCache: tried to expand collection resource on different transaction',\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst options = collectionResource.options;\n\n\t\t\tif (options.parent === null) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t'TransactionCache: invalid collection map passed to expandCollectionResources',\n\t\t\t\t);\n\t\t\t}\n\n\t\t\toptionsTuples.push(\n\t\t\t\t{\n\t\t\t\t\toptions: options as RootCollectionOptionsWithParent<ItemTypeType, any, any>,\n\t\t\t\t\tquery: collectionResource.entry.query,\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tif (\n\t\t\t\t(options as RootCollectionOptionsWithParent<ItemTypeType, any, any>).parent.itemType !== optionsTuples[0].options.parent.itemType\n\t\t\t) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t'TransactionCache: invalid collection map passed to expandCollectionResources',\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst columnsOperationsCache = this.dependencies.requestColumnsOperationsCacheFactory.construct(\n\t\t\titemType,\n\t\t\tnewColumns,\n\t\t);\n\n\t\tconst batchQueryTuple = {\n\t\t\tbatchQuery: this.cachedQueryHandler.createBatchLinkedToQuery(\n\t\t\t\toptionsTuples[0].options.parent.itemType,\n\t\t\t\toptionsTuples.map(\n\t\t\t\t\toptionsTuple => optionsTuple.options.parent.itemId,\n\t\t\t\t),\n\t\t\t\toptionsTuples[0].options.query,\n\t\t\t),\n\t\t};\n\n\t\treturn Promise\n\t\t\t.all(\n\t\t\t\toptionsTuples.map(\n\t\t\t\t\toptionsTuple => this.cachedQueryHandler.__fetchItemEntriesByQueryData(\n\t\t\t\t\t\titemType,\n\t\t\t\t\t\toptionsTuple.options,\n\t\t\t\t\t\tcolumnsOperationsCache,\n\t\t\t\t\t\toptionsTuple.query,\n\t\t\t\t\t\tbatchQueryTuple,\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t)\n\t\t\t.then(\n\t\t\t\t() => {\n\t\t\t\t\tconst columnExpansion = this.dependencies.columnExpansionFactory.construct(\n\t\t\t\t\t\titemType,\n\t\t\t\t\t\tnewColumns,\n\t\t\t\t\t\tthis.dependencies.columnCache.retrieve(\n\t\t\t\t\t\t\titemType,\n\t\t\t\t\t\t\tnewColumns,\n\t\t\t\t\t\t).cached as ResponseColumnItemTypeMap,\n\t\t\t\t\t);\n\n\t\t\t\t\tfor (const parentId in collections) {\n\t\t\t\t\t\tcollections[parentId].entry.expandColumns(\n\t\t\t\t\t\t\tcolumnExpansion,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn collections;\n\t\t\t\t},\n\t\t\t);\n\t}\n\n\tpublic registerFieldChangeCallback<const ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\titemId: ItemId,\n\t\tcallback: ItemChangesListener<ItemTypeType>,\n\t): DeregFunction {\n\t\treturn this.itemHandler.registerFieldChangeCallback(\n\t\t\titemType,\n\t\t\titemId,\n\t\t\tcallback,\n\t\t);\n\t}\n\n\tpublic createChangesDelta (\n\t\tlogMissingColumnErrors: boolean = true,\n\t): ChangesDelta {\n\t\treturn this.dependencies.changesDeltaFactory.construct(\n\t\t\tlogMissingColumnErrors,\n\t\t);\n\t}\n\n\tpublic getFirstErrorString (): undefined | string {\n\t\treturn untracked(\n\t\t\t() => this.firstErrorString(),\n\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Should only be called by {@link TransactionValidator TransactionValidator}\n\t * @internal\n\t */\n\tpublic _setGlobalError (\n\t\tkey: string,\n\t\tisInvalid: boolean,\n\t\tsaveButtonErrorTranslationFn: () => string,\n\t\tlevel: TransactionErrorLevel,\n\t): void {\n\t\tif (!isInvalid) {\n\t\t\tthis.clearGlobalError(\n\t\t\t\tkey,\n\t\t\t);\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst globalErrors = this.errors.global();\n\n\t\tglobalErrors[key] = {\n\t\t\tstring: saveButtonErrorTranslationFn(),\n\t\t\tlevel: level,\n\t\t};\n\n\t\t// Only the root is reactive, so we don't have to make a full copy\n\t\tthis.errors.global.set(\n\t\t\t{\n\t\t\t\t...globalErrors,\n\t\t\t},\n\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Should only be called by {@link TransactionValidator TransactionValidator}\n\t * @internal\n\t */\n\tpublic _setItemError (\n\t\titemEntryId: ItemEntry['id'],\n\t\tcolumnId: string,\n\t\terrorKey: string,\n\t\tisInvalid: boolean,\n\t\tfieldErrorTranslationFn: () => string,\n\t\tsaveButtonErrorTranslationFn: () => string,\n\t\tlevel: TransactionErrorLevel,\n\t\tlocation?: string,\n\t): void {\n\t\tif (!isInvalid) {\n\t\t\tthis.clearItemError(\n\t\t\t\titemEntryId,\n\t\t\t\tcolumnId,\n\t\t\t\terrorKey,\n\t\t\t);\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst itemErrors = this.errors.item();\n\n\t\tcreatePath(\n\t\t\titemErrors,\n\t\t\t[\n\t\t\t\titemEntryId,\n\t\t\t\tcolumnId,\n\t\t\t\terrorKey,\n\t\t\t],\n\t\t\t[\n\t\t\t\t{},\n\t\t\t\t{},\n\t\t\t\t{\n\t\t\t\t\tfieldString: fieldErrorTranslationFn(),\n\t\t\t\t\tstring: saveButtonErrorTranslationFn(),\n\t\t\t\t\tlevel: level,\n\t\t\t\t\tlocation: location,\n\t\t\t\t},\n\t\t\t],\n\t\t\ttrue,\n\t\t);\n\n\t\t// Only the root is reactive, so we don't have to make a full copy\n\t\tthis.errors.item.set(\n\t\t\t{\n\t\t\t\t...itemErrors,\n\t\t\t},\n\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Merges the passed changes from the parent Transaction into this Transaction's own changes and then propagates\n\t * them to all child Transactions, this assumes that an action is already handled in a parent, so it does't handle created entries\n\t * and removes entries that were in {@link TransactionItemHandler.deletedItems deletedItems} since they are already deleted\n\t *\n\t * ------------------\n\t *\n\t * The difference between {@link TransactionCache.applyChangesFromParent} and {@link TransactionCache.applyChangesDelta} is that applyChangesFromParent assumes\n\t * the change has already been processed, and applyChangesDelta will process the changes once you save the transaction\n\t *\n\t * ------------------\n\t * Use {@link TransactionCache.applyChangesDelta applyChangesDelta} if you want to apply changes from outside the core\n\t */\n\tpublic async applyChangesFromParent (\n\t\tparentChangesDelta: ParentChangesDelta,\n\t\tisCalledAfterSocketUpdate: boolean = false,\n\t\tconversionMap?: ItemIdConversionMap,\n\t): Promise<void> {\n\t\tif (\n\t\t\tparentChangesDelta.isEmpty()\n\t\t\t&& conversionMap === undefined\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.handleCascadingDeletes(\n\t\t\tparentChangesDelta,\n\t\t);\n\n\t\t// We make a new parentChangesDelta because the child transactions for this transaction\n\t\t// should get the combined changes of all parents + this transaction\n\t\tconst newParentChangesDelta = this.dependencies.changesDeltaFactory.constructParentDelta(\n\t\t\tparentChangesDelta,\n\t\t);\n\n\t\tif (conversionMap !== undefined) {\n\t\t\t// This is moved out of processItemEntryChanges because itemChanges for the updated entry are not always on this transaction\n\t\t\t// but items can still be referencing it so they should be updated\n\t\t\tfor (const itemType in conversionMap) {\n\t\t\t\tfor (const stringOldId in conversionMap[itemType]) {\n\t\t\t\t\tconst newId: number = conversionMap[itemType][stringOldId];\n\t\t\t\t\tconst oldId: number = Number(\n\t\t\t\t\t\tstringOldId,\n\t\t\t\t\t);\n\n\t\t\t\t\tlet itemEntry: ItemEntry;\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\titemEntry = this.getLocalItemEntryByItemId(\n\t\t\t\t\t\t\titemType as ApiItemType,\n\t\t\t\t\t\t\tnewId,\n\t\t\t\t\t\t);\n\t\t\t\t\t} catch (exception) {\n\t\t\t\t\t\tthis.dependencies.errorHandler.logError(\n\t\t\t\t\t\t\texception,\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.itemHandler.updateLocalItemIdReferences(\n\t\t\t\t\t\titemEntry.itemType,\n\t\t\t\t\t\toldId,\n\t\t\t\t\t\tnewId,\n\t\t\t\t\t\tparentChangesDelta,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.cachedQueryHandler.updateLocalItemIdReferences(\n\t\t\t\tconversionMap,\n\t\t\t);\n\t\t}\n\n\t\t// We don't need to process created items, besides checking if they fit in collections\n\t\t// creating entries is already done by `applyChangesDelta` on a parent transaction\n\t\tfor (const itemEntryId in parentChangesDelta.created) {\n\t\t\tconst tuple = parentChangesDelta.created[itemEntryId];\n\n\t\t\tnewParentChangesDelta.setItemCreated(\n\t\t\t\ttuple.entry,\n\t\t\t\ttuple.fields,\n\t\t\t);\n\n\t\t\tthis.itemHandler.entries.clear(\n\t\t\t\ttuple.entry,\n\t\t\t);\n\t\t}\n\n\t\tthis.itemHandler.processUpdatesFromDelta(\n\t\t\tparentChangesDelta.updated,\n\t\t\tfalse,\n\t\t\tnewParentChangesDelta,\n\t\t);\n\n\t\tfor (const itemEntry of parentChangesDelta.getDeletedItemEntriesIterator()) {\n\t\t\tnewParentChangesDelta.setItemDeleted(\n\t\t\t\titemEntry,\n\t\t\t);\n\n\t\t\t// if an item is deleted on another cache we shouldn't attempt another request, so we remove it from the to-be-deleted array\n\t\t\tthis.itemHandler.removeFromDeletedItems(\n\t\t\t\titemEntry,\n\t\t\t);\n\n\t\t\tif (this.rootItem === itemEntry) {\n\t\t\t\tvoid this.eventHandler.executeCallbacks(\n\t\t\t\t\t'onRootItemDelete',\n\t\t\t\t\tcallback => callback(),\n\t\t\t\t\ttrue,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst matchingResults = await this.cachedQueryHandler.matchItemsToCollectionQueries(\n\t\t\tnewParentChangesDelta,\n\t\t\tnewParentChangesDelta._queryItemTypeSet,\n\t\t\tfalse,\n\t\t);\n\n\t\tconst collectionResourceChanges = await this.cachedQueryHandler.applyMatchingResultsToCollections(\n\t\t\tmatchingResults,\n\t\t);\n\n\t\tthis.runChangesListenersAndValidators(\n\t\t\tcollectionResourceChanges,\n\t\t\tnewParentChangesDelta,\n\t\t\tconversionMap,\n\t\t\tisCalledAfterSocketUpdate,\n\t\t);\n\n\t\tthis.clearChildCollectionResources(\n\t\t\tcollectionResourceChanges,\n\t\t);\n\n\t\tthis.detectChanges(\n\t\t\ttrue,\n\t\t);\n\n\t\tif (\n\t\t\tthis.validator !== undefined\n\t\t\t|| this.validatorWithDependencies !== undefined\n\t\t) {\n\t\t\tthis.clearGlobalError();\n\n\t\t\ttry {\n\t\t\t\tthis.validator?.validateTransaction();\n\t\t\t} catch (e) {\n\t\t\t\tthis.dependencies.errorHandler.logError(\n\t\t\t\t\te,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tawait Promise.all(\n\t\t\tthis.children.map(\n\t\t\t\tchildTransaction => childTransaction.applyChangesFromParent(\n\t\t\t\t\tnewParentChangesDelta,\n\t\t\t\t\tisCalledAfterSocketUpdate,\n\t\t\t\t\tconversionMap,\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\n\t\t// It's important that we only actually remove the values of items\n\t\t// *after* all sub-transactions have been processed and items have been removed from collections.\n\t\t// If we don't do this we will get a bunch of errors in getDerivedValue calls because the template\n\t\t// engine will call this during rerenders\n\t\tfor (const itemEntry of parentChangesDelta.getDeletedItemEntriesIterator()) {\n\t\t\tthis.clearItemEntry(\n\t\t\t\titemEntry,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Applies changes to this transaction and its children.\n\t *\n\t * The difference between {@link TransactionCache.applyChangesFromParent} and {@link TransactionCache.applyChangesDelta}\n\t * is that applyChangesFromParent assumes the change has already been processed on the parent, and applyChangesDelta\n\t * will process the changes itself.\n\t *\n\t * Please note that the resulting promise resolves before deletes have been processed. Deletes are processed after\n\t * the changes have been applied to child transactions. This is reflected by the `allChildrenDonePromise` on the\n\t * result.\n\t *\n\t * However, {@link TransactionCache.save} waits until the complete changes delta has been applied, so calling `save`\n\t * after `applyChangesDelta` should not cause any problems.\n\t */\n\tpublic applyChangesDelta (\n\t\tchangesDelta: ChangesDelta | ChildChangesDelta,\n\t): Promise<ChangesDeltaResult> {\n\t\tif (this.isDestroyed()) {\n\t\t\t// RM4-38815: There are flows where we intentionally write to a destroyed transaction and save immediately after.\n\t\t\t// This will work fine as writing to a parent will always succeed, even when destroyed.\n\t\t\tthis.dependencies.errorHandler.logWarning(\n\t\t\t\t`TransactionCache: tried to apply changes to destroyed transaction with id: '${this.id}'`,\n\t\t\t);\n\t\t}\n\n\t\tif (changesDelta.isEmpty()) {\n\t\t\treturn Promise.resolve(\n\t\t\t\t{\n\t\t\t\t\tchangesDelta,\n\t\t\t\t\tcreated: [],\n\t\t\t\t\tallChildrenDonePromise: Promise.resolve(),\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\tconst changesDeltaPromise = this.doApplyChangesDelta(\n\t\t\tchangesDelta,\n\t\t);\n\n\t\tthis.trackChangesDeltaBeingApplied(\n\t\t\tchangesDeltaPromise.then(\n\t\t\t\tresult => result.allChildrenDonePromise,\n\t\t\t),\n\t\t);\n\n\t\treturn changesDeltaPromise;\n\t}\n\n\tprivate trackChangesDeltaBeingApplied (\n\t\tallChildrenDonePromise: Promise<void>,\n\t): void {\n\t\tthis.changesDeltasBeingApplied.push(\n\t\t\tallChildrenDonePromise,\n\t\t);\n\n\t\tvoid allChildrenDonePromise.finally(\n\t\t\t() => {\n\t\t\t\tconst index = this.changesDeltasBeingApplied.indexOf(\n\t\t\t\t\tallChildrenDonePromise,\n\t\t\t\t);\n\n\t\t\t\tif (index === -1) {\n\t\t\t\t\tthis.dependencies.errorHandler.logError(\n\t\t\t\t\t\tnew Error(\n\t\t\t\t\t\t\t'TransactionCache: expected changes delta to be present in `changesDeltasBeingApplied`',\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvoid this.changesDeltasBeingApplied.splice(\n\t\t\t\t\tindex,\n\t\t\t\t\t1,\n\t\t\t\t);\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic getRootTransaction (): TransactionCache {\n\t\tif (this.parent instanceof ServerCache) {\n\t\t\treturn this;\n\t\t}\n\n\t\treturn (this.parent as TransactionCache).getRootTransaction();\n\t}\n\n\tpublic getServerCache (): ServerCache {\n\t\treturn this.parent.getServerCache();\n\t}\n\n\tpublic getCollectionChangesRecursively<const ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tparsedQuery: CollectionQuery<ItemTypeType>,\n\t): CachedQueryItem<ItemTypeType> | undefined {\n\t\tconst cachedQueryItem = this.cachedQueryHandler.getCachedQueryItem(\n\t\t\titemType,\n\t\t\tparsedQuery.string,\n\t\t);\n\n\t\tif (cachedQueryItem !== undefined) {\n\t\t\treturn cachedQueryItem;\n\t\t}\n\n\t\tconst parentCachedQueryItem = this.parent.getCollectionChangesRecursively(\n\t\t\titemType,\n\t\t\tparsedQuery,\n\t\t);\n\n\t\tif (parentCachedQueryItem === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn this.cachedQueryHandler.cloneCachedQuery(\n\t\t\tparentCachedQueryItem,\n\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Returns whether or not the {@link TransactionCache.rootItem rootItem} is uses locks\n\t */\n\tpublic isLockable (\n\t\trootItem: ItemEntry | undefined = this.rootItem,\n\t): rootItem is ItemEntry {\n\t\tif (rootItem === undefined) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn rootItem.isLockable();\n\t}\n\n\t/**\n\t * @description\n\t * Saves the transaction, this has a different effect depending on the transaction's parent.\n\t *\n\t * - If the parent is another {@link TransactionCache TransactionCache} it will merge the changes of the child transaction in the the parent transaction\n\t * - If the parent is the {@link ServerCache ServerCache} it will save the changes to the APi\n\t */\n\tpublic save (\n\t\tcloseTab: boolean = false,\n\t\tparameters: CreateRequestParameterMap = {},\n\t\tbreakUpByParent?: boolean,\n\t\tonAfterCreateCallback?: OnAfterCreateCallback,\n\t): Promise<ItemIdConversionMap> {\n\t\tif (this.isPending()) {\n\t\t\tthrow new TransactionPendingException(\n\t\t\t\t'TransactionCache: Transaction cannot be saved since it (or its children) are pending',\n\t\t\t);\n\t\t}\n\n\t\tthis.transactionStateSignal.set(\n\t\t\t'Saving',\n\t\t);\n\n\t\tthis.detectChanges();\n\n\t\tlet itemIdConversionMap: ItemIdConversionMap;\n\n\t\treturn Promise\n\t\t\t.all(\n\t\t\t\tthis.changesDeltasBeingApplied,\n\t\t\t)\n\t\t\t.then(\n\t\t\t\t() => this.fetchLock(),\n\t\t\t)\n\t\t\t.then(\n\t\t\t\t() => this.eventHandler.executeCallbacks(\n\t\t\t\t\t'onBeforeSave',\n\t\t\t\t\tcallback => callback(\n\t\t\t\t\t\tthis,\n\t\t\t\t\t),\n\t\t\t\t\tcloseTab,\n\t\t\t\t),\n\t\t\t)\n\t\t\t.then(\n\t\t\t\t() => {\n\t\t\t\t\tthis.tabRequestParameters = merge(\n\t\t\t\t\t\tthis.tabRequestParameters,\n\t\t\t\t\t\tparameters,\n\t\t\t\t\t);\n\n\t\t\t\t\treturn this.parent.applyChangesFromChild(\n\t\t\t\t\t\tthis,\n\t\t\t\t\t\tbreakUpByParent,\n\t\t\t\t\t\tonAfterCreateCallback,\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t)\n\t\t\t.then(\n\t\t\t\t_itemIdConversionMap => {\n\t\t\t\t\titemIdConversionMap = _itemIdConversionMap;\n\n\t\t\t\t\tthis.tabRequestParameters = {};\n\n\t\t\t\t\tif (\n\t\t\t\t\t\tthis.isLockable(\n\t\t\t\t\t\t\tthis.rootItem,\n\t\t\t\t\t\t)\n\t\t\t\t\t) {\n\t\t\t\t\t\tvoid this.dependencies.lockService.deleteLock(\n\t\t\t\t\t\t\tthis.rootItem,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.hasChangesSignal.set(\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t);\n\n\t\t\t\t\treturn this.eventHandler.executeCallbacks(\n\t\t\t\t\t\t'onSaveSuccess',\n\t\t\t\t\t\tcallback => callback(\n\t\t\t\t\t\t\tthis,\n\t\t\t\t\t\t\titemIdConversionMap,\n\t\t\t\t\t\t),\n\t\t\t\t\t\tcloseTab,\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t)\n\t\t\t.then(\n\t\t\t\t() => itemIdConversionMap,\n\t\t\t)\n\t\t\t.catch(\n\t\t\t\terror => {\n\t\t\t\t\tthrow error;\n\t\t\t\t},\n\t\t\t)\n\t\t\t.finally(\n\t\t\t\t() => {\n\t\t\t\t\tthis.transactionStateSignal.set(\n\t\t\t\t\t\t'Ready',\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t);\n\t}\n\n\t/**\n\t * Rejects when another user is holding the lock, as opposed to {@link LockService.fetchLock}.\n\t */\n\tpublic fetchLock (): Promise<void> {\n\t\tif (\n\t\t\t!this.isLockable(\n\t\t\t\tthis.rootItem,\n\t\t\t)\n\t\t) {\n\t\t\treturn Promise.resolve();\n\t\t}\n\n\t\treturn this.dependencies.lockService\n\t\t\t.fetchLock(\n\t\t\t\tthis.rootItem,\n\t\t\t)\n\t\t\t.then(\n\t\t\t\tlockItem => {\n\t\t\t\t\tif (\n\t\t\t\t\t\tthis.dependencies.lockService.isRemoteLock(\n\t\t\t\t\t\t\tlockItem,\n\t\t\t\t\t\t)\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow new ItemLockedException(\n\t\t\t\t\t\t\tlockItem.message,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn;\n\t\t\t\t},\n\t\t\t);\n\t}\n\n\tpublic detectChanges (\n\t\tforce: boolean = false,\n\t): boolean {\n\t\tif (\n\t\t\tthis.hasChanges\n\t\t\t&& !force\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (this.itemHandler.detectChanges()) {\n\t\t\tthis.hasChangesSignal.set(\n\t\t\t\ttrue,\n\t\t\t);\n\n\t\t\treturn true;\n\t\t}\n\n\t\tthis.hasChangesSignal.set(\n\t\t\tfalse,\n\t\t);\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * @description\n\t * Removes an {@link ItemEntry ItemEntry} through an {@link ItemResource ItemResource} from the {@link TransactionCache TransactionCache} which means that changes on this entry will no longer be tracked.\n\t */\n\tpublic clearItem (\n\t\titemResource: ItemResource<any>,\n\t): void {\n\t\tthis.clearItemEntry(\n\t\t\titemResource.entry,\n\t\t);\n\t}\n\n\tpublic clearItemEntry<ItemTypeType extends ApiItemType> (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t): FieldMap<ItemTypeType> | undefined {\n\t\tthis.clearItemError(\n\t\t\titemEntry.id,\n\t\t);\n\n\t\treturn super.clearItemEntry(\n\t\t\titemEntry,\n\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Adds a callback that will fire before the transaction is saved, rejecting this callback will prevent the transaction from saving\n\t */\n\tpublic onBeforeSave (\n\t\tkey: string,\n\t\tcallback: TransactionCacheCallbackType['onBeforeSave'],\n\t\tcondition?: TransactionCacheCallbackCondition,\n\t\tpriority?: number,\n\t): () => void {\n\t\treturn this.eventHandler.registerCallback(\n\t\t\t'onBeforeSave',\n\t\t\tkey,\n\t\t\tcallback,\n\t\t\tcondition,\n\t\t\tpriority,\n\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Adds a callback that will fire when the transaction is saved successfully\n\t */\n\tpublic onSaveSuccess (\n\t\tkey: string,\n\t\tcallback: TransactionCacheCallbackType['onSaveSuccess'],\n\t\tcondition?: TransactionCacheCallbackCondition,\n\t\tpriority?: number,\n\t): () => void {\n\t\treturn this.eventHandler.registerCallback(\n\t\t\t'onSaveSuccess',\n\t\t\tkey,\n\t\t\tcallback,\n\t\t\tcondition,\n\t\t\tpriority,\n\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Adds a callback that will fire when the root item of the transaction is deleted\n\t */\n\tpublic onRootItemDeleted (\n\t\tkey: string,\n\t\tcallback: TransactionCacheCallbackType['onRootItemDelete'],\n\t\tcondition?: TransactionCacheCallbackCondition,\n\t\tpriority?: number,\n\t): () => void {\n\t\treturn this.eventHandler.registerCallback(\n\t\t\t'onRootItemDelete',\n\t\t\tkey,\n\t\t\tcallback,\n\t\t\tcondition,\n\t\t\tpriority,\n\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Returns a {@link ModuleChangesCompilationResult ModuleChangesCompilationResult} for the transaction\n\t */\n\tpublic getModuleChanges (): ModuleChangesCompilationResult {\n\t\tif (this.rootItem === undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t'No root item for transaction cache ' + this.id,\n\t\t\t);\n\t\t}\n\n\t\treturn this.dependencies.moduleChangesCompilationFactory\n\t\t\t.construct(\n\t\t\t\tthis,\n\t\t\t)\n\t\t\t.process();\n\t}\n\n\t/**\n\t * @description\n\t * Updates the passed map with the new {@link ConversionMap CconversionMap} values\n\t */\n\tpublic updateItemIdMap (\n\t\tcollectionMap: {[itemId: number]: any,},\n\t\tconversionMap: ConversionMap,\n\t): void {\n\t\tif (conversionMap === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const oldId in conversionMap) {\n\t\t\tconst newId = conversionMap[oldId];\n\n\t\t\tif (collectionMap[oldId] === undefined) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tcollectionMap[newId] = collectionMap[oldId];\n\t\t\tdelete collectionMap[oldId];\n\t\t}\n\t}\n\n\t/**\n\t * @deprecated Use the `children` collection option instead.\n\t */\n\tpublic async getLinkCollections<\n\t\tconst ItemTypeType extends ApiItemType,\n\t\tconst OptionsType extends CollectionOptions<ItemTypeType>,\n\t> (\n\t\tlinkType: ApiItemType,\n\t\tlinkIdArray: ItemId[],\n\t\titemType: ItemTypeType,\n\t\toptions: OptionsType,\n\t): Promise<ParentIdMap<OptionsToCollectionResource<ItemTypeType, OptionsType>>> {\n\t\tif (linkIdArray.length === 0) {\n\t\t\treturn Promise.resolve(\n\t\t\t\t{},\n\t\t\t);\n\t\t}\n\n\t\tconst cachedQueryItemsItemTypeTuples = await this.cachedQueryHandler.__fetchChildCachedQueryItems(\n\t\t\tlinkType,\n\t\t\tlinkIdArray,\n\t\t\t{\n\t\t\t\t[itemType]: options,\n\t\t\t},\n\t\t);\n\t\tconst cachedQueryItemTuples = (\n\t\t\tcachedQueryItemsItemTypeTuples[0] as CachedQueryItemsItemTypeTuple<any> as CachedQueryItemsItemTypeTuple<ItemTypeType>\n\t\t).cachedQueryItemTuples;\n\t\tconst columnSetMap = {\n\t\t\t[itemType]: this.dependencies.collectionResourceFactory.constructColumnSet(\n\t\t\t\tcachedQueryItemTuples[0],\n\t\t\t),\n\t\t} as ColumnSetMap<any> as ColumnSetMap<ItemTypeType>;\n\n\t\tconst result: ParentIdMap<OptionsToCollectionResource<ItemTypeType, OptionsType>> = {};\n\t\tconst collectionResources: OptionsToCollectionResource<ItemTypeType, OptionsType>[] = [];\n\n\t\tfor (const cachedQueryItemTree of cachedQueryItemTuples) {\n\t\t\tconst parentId = cachedQueryItemTree.options.parent!.itemId;\n\n\t\t\t// Typescript cannot compile this type for some reason, so we cast it.\n\t\t\tconst collectionResource = this.dependencies.collectionResourceFactory.construct(\n\t\t\t\tcachedQueryItemTree,\n\t\t\t\tnull,\n\t\t\t\tthis,\n\t\t\t\tcolumnSetMap,\n\t\t\t) as any;\n\n\t\t\tresult[parentId] = collectionResource;\n\n\t\t\tcollectionResources.push(\n\t\t\t\tcollectionResource,\n\t\t\t);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic getCollection<\n\t\tconst ItemTypeType extends ApiItemType,\n\t\tconst OptionsType extends RootCollectionOptions<ItemTypeType>\n\t> (\n\t\titemType: ItemTypeType,\n\t\toptions: OptionsType,\n\t): Promise<OptionsToCollectionResource<ItemTypeType, OptionsType>> {\n\t\treturn this.cachedQueryHandler\n\t\t\t.__fetchParentCachedQueryItem(\n\t\t\t\titemType,\n\t\t\t\toptions,\n\t\t\t)\n\t\t\t.then(\n\t\t\t\tcachedQueryItemTuple => {\n\t\t\t\t\tconst collectionResource = this.dependencies.collectionResourceFactory.construct<ItemTypeType, OptionsType>(\n\t\t\t\t\t\tcachedQueryItemTuple,\n\t\t\t\t\t\tnull,\n\t\t\t\t\t\tthis,\n\t\t\t\t\t);\n\n\t\t\t\t\tthis.maybeCallInitialChangesListener(\n\t\t\t\t\t\toptions,\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\tcollectionResource,\n\t\t\t\t\t\t],\n\t\t\t\t\t\t[],\n\t\t\t\t\t);\n\n\t\t\t\t\treturn collectionResource;\n\t\t\t\t},\n\t\t\t);\n\t}\n\n\tpublic getNewResourceWithId<const ItemTypeType extends ApiItemType, const OptionsType extends NewItemOptions<ItemTypeType>> (\n\t\titemType: ItemTypeType,\n\t\titemId: ItemId,\n\t\toptions: OptionsType,\n\t\treturnLinks: true,\n\t\tisRoot?: boolean,\n\t): Promise<ItemResourceLinks<ItemTypeType, OptionsType['columns'], OptionsToChildCollections<OptionsType>>>;\n\n\tpublic getNewResourceWithId<const ItemTypeType extends ApiItemType, const OptionsType extends NewItemOptions<ItemTypeType>> (\n\t\titemType: ItemTypeType,\n\t\titemId: ItemId,\n\t\toptions: OptionsType,\n\t\treturnLinks?: boolean,\n\t\tisRoot?: boolean,\n\t): Promise<ItemResource<ItemTypeType, OptionsType['columns'], OptionsToChildCollections<OptionsType>>>;\n\n\tpublic async getNewResourceWithId<const ItemTypeType extends ApiItemType, const OptionsType extends NewItemOptions<ItemTypeType>> (\n\t\titemType: ItemTypeType,\n\t\titemId: ItemId,\n\t\toptions: OptionsType,\n\t\treturnLinks: boolean = false,\n\t\tisRoot?: boolean,\n\t): Promise<\n\t\tItemResourceLinks<ItemTypeType, OptionsType['columns'], OptionsToChildCollections<OptionsType>>\n\t\t| ItemResource<ItemTypeType, OptionsType['columns'], OptionsToChildCollections<OptionsType>>\n\t> {\n\t\tconst [\n\t\t\tchangedDeltaResult,\n\t\t\tchildCachedQueryItems,\n\t\t] = await Promise.all(\n\t\t\t[\n\t\t\t\tthis.itemHandler.fetchNewItemEntry(\n\t\t\t\t\titemType,\n\t\t\t\t\titemId,\n\t\t\t\t\toptions,\n\t\t\t\t\tisRoot,\n\t\t\t\t),\n\t\t\t\toptions.children === undefined\n\t\t\t\t\t? null\n\t\t\t\t\t: this.cachedQueryHandler.__fetchChildCachedQueryItems(\n\t\t\t\t\t\titemType,\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\titemId,\n\t\t\t\t\t\t],\n\t\t\t\t\t\toptions.children,\n\t\t\t\t\t),\n\t\t\t],\n\t\t);\n\n\t\tlet mainEntry: ItemEntry<ItemTypeType> | undefined;\n\t\tconst linkedEntriesMap: ItemTypeMap<ItemEntry[]> = {};\n\n\t\tfor (const itemEntry of changedDeltaResult.created) {\n\t\t\tif (\n\t\t\t\titemEntry.itemType === itemType\n\t\t\t\t&& itemEntry.itemId === itemId\n\t\t\t) {\n\t\t\t\tmainEntry = itemEntry as ItemEntry<ItemTypeType>;\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (linkedEntriesMap[itemEntry.itemType] === undefined) {\n\t\t\t\tlinkedEntriesMap[itemEntry.itemType] = [];\n\t\t\t}\n\n\t\t\tlinkedEntriesMap[itemEntry.itemType].push(\n\t\t\t\titemEntry,\n\t\t\t);\n\t\t}\n\n\t\tif (mainEntry === undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t'The ItemEntry with the requested ItemId was not in the template response',\n\t\t\t);\n\t\t}\n\n\t\tconst main = this.createItemResource<\n\t\t\tItemTypeType,\n\t\t\tOptionsType['columns'],\n\t\t\tOptionsToChildCollections<OptionsType>\n\t\t>(\n\t\t\tmainEntry,\n\t\t\tthis.dependencies.collectionResourceFactory.constructChildCollectionResources<OptionsToChildCollections<OptionsType>>(\n\t\t\t\tchildCachedQueryItems,\n\t\t\t\tnull,\n\t\t\t\tthis,\n\t\t\t)[mainEntry.itemId],\n\t\t\ttrue,\n\t\t\toptions.changesListener,\n\t\t\toptions.abortSignal,\n\t\t);\n\n\t\tif (!returnLinks) {\n\t\t\tthis.maybeCallInitialChangesListener(\n\t\t\t\toptions,\n\t\t\t\t[],\n\t\t\t\t[\n\t\t\t\t\tmain,\n\t\t\t\t],\n\t\t\t);\n\n\t\t\treturn main;\n\t\t}\n\n\t\tconst linkedResources: ItemResourcesItemTypeMap = this.processLinkedItems(\n\t\t\tlinkedEntriesMap,\n\t\t\toptions.changesListener,\n\t\t\toptions.abortSignal,\n\t\t);\n\n\t\tthis.maybeCallInitialChangesListener(\n\t\t\toptions,\n\t\t\t[],\n\t\t\t[\n\t\t\t\tmain,\n\t\t\t\t...Object\n\t\t\t\t\t.values(\n\t\t\t\t\t\tlinkedResources,\n\t\t\t\t\t)\n\t\t\t\t\t.flat(),\n\t\t\t],\n\t\t);\n\n\t\treturn {\n\t\t\tmain: main,\n\t\t\tlinked: linkedResources,\n\t\t};\n\t}\n\n\tpublic getNewResource<const ItemTypeType extends ApiItemType, const OptionsType extends NewItemOptions<ItemTypeType>> (\n\t\titemType: ItemTypeType,\n\t\toptions: OptionsType,\n\t\treturnLinks: true,\n\t\tisRoot?: boolean,\n\t): Promise<ItemResourceLinks<ItemTypeType, OptionsType['columns'], OptionsToChildCollections<OptionsType>>>;\n\n\tpublic getNewResource<const ItemTypeType extends ApiItemType, const OptionsType extends NewItemOptions<ItemTypeType>> (\n\t\titemType: ItemTypeType,\n\t\toptions: OptionsType,\n\t\treturnLinks?: boolean,\n\t\tisRoot?: boolean,\n\t): Promise<ItemResource<ItemTypeType, OptionsType['columns'], OptionsToChildCollections<OptionsType>>>;\n\n\t/**\n\t * @description\n\t * Fetches a new ItemEntry and resource\n\t */\n\tpublic getNewResource<const ItemTypeType extends ApiItemType, const OptionsType extends NewItemOptions<ItemTypeType>> (\n\t\titemType: ItemTypeType,\n\t\toptions: OptionsType,\n\t\treturnLinks?: boolean,\n\t\tisRoot?: boolean,\n\t): Promise<\n\t\tItemResourceLinks<ItemTypeType, OptionsType['columns'], OptionsToChildCollections<OptionsType>>\n\t\t| ItemResource<ItemTypeType, OptionsType['columns'], OptionsToChildCollections<OptionsType>>\n\t> {\n\t\treturn this.getNewResourceWithId(\n\t\t\titemType,\n\t\t\tKeyService.getLocalId(),\n\t\t\toptions,\n\t\t\treturnLinks,\n\t\t\tisRoot,\n\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Fetches multiple items with their respective changes of the current {@link TransactionCache transaction}\n\t */\n\tpublic async getItemsByQuery<\n\t\tconst ItemTypeType extends ApiItemType,\n\t\tconst OptionsType extends ItemsByQueryOptions<ItemTypeType>\n\t> (\n\t\titemType: ItemTypeType,\n\t\tquery: ApiQuery<ItemTypeType>,\n\t\toptions: OptionsType,\n\t): Promise<ItemResource<ItemTypeType, OptionsType['columns'], OptionsToChildCollections<OptionsType>>[]> {\n\t\tconst cachedQueryItemTuple = await this.cachedQueryHandler.__fetchParentCachedQueryItem(\n\t\t\titemType,\n\t\t\t{\n\t\t\t\t...options,\n\t\t\t\tquery,\n\t\t\t},\n\t\t);\n\n\t\treturn this.createItemResources<\n\t\t\tItemTypeType,\n\t\t\tOptionsType['columns'],\n\t\t\tOptionsToChildCollections<OptionsType>\n\t\t>(\n\t\t\tcachedQueryItemTuple.cachedQueryItem.items,\n\t\t\tthis.dependencies.collectionResourceFactory.constructChildCollectionResources(\n\t\t\t\tcachedQueryItemTuple.children,\n\t\t\t\tnull,\n\t\t\t\tthis,\n\t\t\t),\n\t\t\tundefined,\n\t\t\toptions.abortSignal,\n\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Fetches multiple items with their respective changes of the current {@link TransactionCache transaction}\n\t */\n\tpublic async getItemsById<\n\t\tconst ItemTypeType extends ApiItemType,\n\t\tconst OptionsType extends ItemOptions<ItemTypeType>\n\t> (\n\t\titemType: ItemTypeType,\n\t\titemIds: ItemId[],\n\t\toptions: OptionsType,\n\t): Promise<ItemResource<ItemTypeType, OptionsType['columns'], OptionsToChildCollections<OptionsType>>[]> {\n\t\tif (itemIds.length === 0) {\n\t\t\treturn Promise.resolve(\n\t\t\t\t[],\n\t\t\t);\n\t\t}\n\n\t\tconst [\n\t\t\titemEntries,\n\t\t\tchildCachedQueryItems,\n\t\t] = await Promise.all(\n\t\t\t[\n\t\t\t\tthis.itemHandler.fetchItemEntries(\n\t\t\t\t\titemType,\n\t\t\t\t\titemIds,\n\t\t\t\t\toptions.columns,\n\t\t\t\t),\n\t\t\t\toptions.children === undefined\n\t\t\t\t\t? null\n\t\t\t\t\t: this.cachedQueryHandler.__fetchChildCachedQueryItems(\n\t\t\t\t\t\titemType,\n\t\t\t\t\t\titemIds,\n\t\t\t\t\t\toptions.children,\n\t\t\t\t\t),\n\t\t\t],\n\t\t);\n\n\t\tconst itemResources = this.createItemResources<\n\t\t\tItemTypeType,\n\t\t\tOptionsType['columns'],\n\t\t\tOptionsToChildCollections<OptionsType>\n\t\t>(\n\t\t\titemEntries,\n\t\t\tthis.dependencies.collectionResourceFactory.constructChildCollectionResources(\n\t\t\t\tchildCachedQueryItems,\n\t\t\t\tnull,\n\t\t\t\tthis,\n\t\t\t),\n\t\t\toptions.changesListener,\n\t\t\toptions.abortSignal,\n\t\t);\n\n\t\tthis.maybeCallInitialChangesListener(\n\t\t\toptions,\n\t\t\t[],\n\t\t\titemResources,\n\t\t);\n\n\t\treturn itemResources;\n\t}\n\n\t/**\n\t * @description\n\t * Fetches the item with the changes of the current {@link TransactionCache transaction}\n\t *\n\t * @param isRoot Sets the item as the root item of the transaction, new items will be linked to this item (if there's a connection in the LinkTree)\n\t */\n\tpublic async getItemById<const ItemTypeType extends ApiItemType, const OptionsType extends ItemOptions<ItemTypeType>> (\n\t\titemType: ItemTypeType,\n\t\titemId: ItemId,\n\t\toptions: OptionsType,\n\t\tisRoot: boolean = false,\n\t): Promise<ItemResource<ItemTypeType, OptionsType['columns'], OptionsToChildCollections<OptionsType>>> {\n\t\tconst [\n\t\t\titemEntry,\n\t\t\tchildCachedQueryItems,\n\t\t] = await Promise.all(\n\t\t\t[\n\t\t\t\tthis.itemHandler.fetchItemEntry(\n\t\t\t\t\titemType,\n\t\t\t\t\titemId,\n\t\t\t\t\toptions.columns,\n\t\t\t\t),\n\t\t\t\toptions.children === undefined\n\t\t\t\t\t? null\n\t\t\t\t\t: this.cachedQueryHandler.__fetchChildCachedQueryItems(\n\t\t\t\t\t\titemType,\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\titemId,\n\t\t\t\t\t\t],\n\t\t\t\t\t\toptions.children,\n\t\t\t\t\t),\n\t\t\t],\n\t\t);\n\n\t\tif (isRoot) {\n\t\t\tthis.rootItemSignal.set(\n\t\t\t\titemEntry,\n\t\t\t);\n\t\t}\n\n\t\tconst itemResource = this.createItemResource<\n\t\t\tItemTypeType,\n\t\t\tOptionsType['columns'],\n\t\t\tOptionsToChildCollections<OptionsType>\n\t\t>(\n\t\t\titemEntry,\n\t\t\tthis.dependencies.collectionResourceFactory.constructChildCollectionResources(\n\t\t\t\tchildCachedQueryItems,\n\t\t\t\tnull,\n\t\t\t\tthis,\n\t\t\t)[itemId] as OptionsToChildCollections<OptionsType>,\n\t\t\tfalse,\n\t\t\toptions.changesListener,\n\t\t\toptions.abortSignal,\n\t\t);\n\n\t\tthis.maybeCallInitialChangesListener(\n\t\t\toptions,\n\t\t\t[],\n\t\t\t[\n\t\t\t\titemResource,\n\t\t\t],\n\t\t);\n\n\t\treturn itemResource;\n\t}\n\n\t/**\n\t * @description\n\t * Fetches the title of an item, does not create an {@link ItemResource ItemResource}\n\t */\n\tpublic fetchTitle (\n\t\titemType: ApiItemType,\n\t\titemId: ItemId,\n\t): Promise<string> {\n\t\treturn this.itemHandler.fetchTitle(\n\t\t\titemType,\n\t\t\titemId,\n\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Merges the passed child Transaction into this transaction and then propagates them to the other child transactions\n\t */\n\tpublic applyChangesFromChild (\n\t\tchildTransaction: TransactionCache,\n\t): Promise<ItemIdConversionMap> {\n\t\tthis.tabRequestParameters = merge(\n\t\t\tthis.tabRequestParameters,\n\t\t\tchildTransaction.tabRequestParameters,\n\t\t);\n\n\t\t// We can move the cached queries to the parent transaction because we're going to merge the changes (so items\n\t\t// that fitted in the child transaction will still fit after the changes merge) but only if there's not already\n\t\t// a cachedQuery (or it will break the callbacks)\n\t\tfor (const childCachedQueryItem of childTransaction.cachedQueryHandler.getCachedQueryItemIterator()) {\n\t\t\tif (\n\t\t\t\tthis.cachedQueryHandler.getCachedQueryItem(\n\t\t\t\t\tchildCachedQueryItem.itemType,\n\t\t\t\t\tchildCachedQueryItem.query.string,\n\t\t\t\t) !== undefined\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tthis.cachedQueryHandler.cloneCachedQuery(\n\t\t\t\tchildCachedQueryItem,\n\t\t\t);\n\t\t}\n\n\t\treturn this\n\t\t\t.applyChangesDelta(\n\t\t\t\tchildTransaction.getDelta(),\n\t\t\t)\n\t\t\t.then(\n\t\t\t\t// `applyChangesFromChild` might do a `create` request (and return an item ID conversion map) on the\n\t\t\t\t// server cache. Since we're not on the server cache, we're returning an empty object here.\n\t\t\t\t() => (\n\t\t\t\t\t{}\n\t\t\t\t),\n\t\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Gets an ItemEntry from the cache, doesn't do a API request, used for saving\n\t */\n\tpublic getLocalItemEntry (\n\t\titemEntryId: ItemEntry['id'],\n\t): ItemEntry {\n\t\treturn this.itemHandler.entries.containsByEntryId(\n\t\t\titemEntryId,\n\t\t)\n\t\t\t? this.itemHandler.entries.getByEntryId(\n\t\t\t\titemEntryId,\n\t\t\t)\n\t\t\t: this.parent.getLocalItemEntry(\n\t\t\t\titemEntryId,\n\t\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Gets an ItemEntry from the cache by ItemId. Looks at the current as well as the parent transaction.\n\t */\n\tpublic getLocalItemEntryByItemId<const ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\titemId: ItemEntry<ItemTypeType>['itemId'],\n\t): ItemEntry<ItemTypeType> {\n\t\treturn this.itemHandler.entries.contains(\n\t\t\titemType,\n\t\t\titemId,\n\t\t)\n\t\t\t? this.itemHandler.entries.get<ItemTypeType>(\n\t\t\t\titemType,\n\t\t\t\titemId,\n\t\t\t)\n\t\t\t: this.parent.getLocalItemEntryByItemId<ItemTypeType>(\n\t\t\t\titemType,\n\t\t\t\titemId,\n\t\t\t);\n\t}\n\n\tpublic containsLocalItemEntryByItemId (\n\t\titemType: ApiItemType,\n\t\titemId: ItemEntry['itemId'],\n\t): boolean {\n\t\treturn this.itemHandler.entries.contains(\n\t\t\t\titemType,\n\t\t\t\titemId,\n\t\t\t)\n\t\t\t|| this.parent.containsLocalItemEntryByItemId(\n\t\t\t\titemType,\n\t\t\t\titemId,\n\t\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Returns the complete {@link ChildChangesDelta} of the TransactionCache, this only takes into account the end\n\t * result (initial is compared to changes), so changing something and reverting it won't be included.\n\t */\n\tpublic getDelta (): ChildChangesDelta {\n\t\tconst childChangesDelta = this.dependencies.changesDeltaFactory.constructChildDelta();\n\n\t\tfor (const itemEntry of this.itemHandler.getItemEntriesWithChangesIterator()) {\n\t\t\t// An item can be used by a 2nd+ level child TransactionCache, it will be local than but it should only count as a create\n\t\t\t// on the transaction that actually created the entry\n\t\t\tif (\n\t\t\t\tthis.itemHandler.entries.contains(\n\t\t\t\t\titemEntry.itemType,\n\t\t\t\t\titemEntry.itemId,\n\t\t\t\t)\n\t\t\t\t&& itemEntry.isLocal()\n\t\t\t) {\n\t\t\t\tconst fields = this.itemHandler.collectFields(\n\t\t\t\t\titemEntry,\n\t\t\t\t);\n\n\t\t\t\titemEntry.itemId = fields.id;\n\n\t\t\t\tchildChangesDelta.setItemCreated(\n\t\t\t\t\titemEntry,\n\t\t\t\t\tfields,\n\t\t\t\t);\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tchildChangesDelta.setItemUpdated(\n\t\t\t\titemEntry,\n\t\t\t\tthis.itemHandler.itemChanges[itemEntry.id],\n\t\t\t\t'KEEP_WHEN_DIFFERENT',\n\t\t\t);\n\t\t}\n\n\t\tfor (const itemType in this.itemHandler.deletedItems) {\n\t\t\tfor (const deleteEntry of this.itemHandler.deletedItems[itemType]) {\n\t\t\t\tchildChangesDelta.setItemDeleted(\n\t\t\t\t\t{\n\t\t\t\t\t\tentry: deleteEntry.entry,\n\t\t\t\t\t\tchanges: this.itemHandler.itemChanges[deleteEntry.entry.id],\n\t\t\t\t\t\tisCascaded: deleteEntry.isCascaded,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn childChangesDelta;\n\t}\n\n\t// todo[cache] move to TransactionItemHandler\n\tpublic createItemResource<\n\t\tItemTypeType extends ApiItemType,\n\t\tRequestColumns extends ApiRequestColumns<ItemTypeType>,\n\t\tChildren extends ChildCollectionResources | undefined = undefined\n\t> (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t\tchildCollectionMap: Children = undefined as Children,\n\t\tisNew?: boolean,\n\t\tonChange?: ItemAggregatedChangesListener<ItemResource<ItemTypeType, RequestColumns, Children>>,\n\t\tabortSignal?: AbortSignal,\n\t): ItemResource<ItemTypeType, RequestColumns, Children> {\n\t\tconst itemResource = this.dependencies.itemResourceFactory.construct<ItemTypeType, RequestColumns, Children>(\n\t\t\titemEntry,\n\t\t\tthis,\n\t\t\tisNew,\n\t\t\tabortSignal,\n\t\t);\n\n\t\titemResource.setChildCollectionResources(\n\t\t\tchildCollectionMap,\n\t\t);\n\n\t\tif (\n\t\t\t// If the signal was aborted while we were loading, we don't have to register the itemResource.\n\t\t\t// Instead, we just clear is instead to clear any child collections and don't do anything else with it.\n\t\t\tabortSignal !== undefined\n\t\t\t&& abortSignal.aborted\n\t\t) {\n\t\t\titemResource.clearResource();\n\n\t\t\treturn itemResource;\n\t\t}\n\n\t\tif (onChange !== undefined) {\n\t\t\titemResource.registerChangesListener(\n\t\t\t\tonChange,\n\t\t\t);\n\t\t}\n\n\t\tthis.itemHandler.registerItemResource(\n\t\t\titemResource,\n\t\t);\n\n\t\treturn itemResource;\n\t}\n\n\tpublic createItemResources<\n\t\tItemTypeType extends ApiItemType,\n\t\tRequestColumns extends ApiRequestColumns<ItemTypeType>,\n\t\tChildren extends ChildCollectionResources | undefined = undefined\n\t> (\n\t\titemEntries: Iterable<ItemEntry<ItemTypeType>>,\n\t\tchildCollectionResourceMap: ParentIdMap<Children> = {},\n\t\tchangesListener?: ItemAggregatedChangesListener<ItemResource<ItemTypeType, any, any>>,\n\t\tabortSignal?: AbortSignal,\n\t): ItemResource<ItemTypeType, RequestColumns, Children>[] {\n\t\tconst result: ItemResource<ItemTypeType, RequestColumns, Children>[] = [];\n\n\t\tfor (const itemEntry of itemEntries) {\n\t\t\tresult.push(\n\t\t\t\tthis.createItemResource<ItemTypeType, RequestColumns, Children>(\n\t\t\t\t\titemEntry,\n\t\t\t\t\tchildCollectionResourceMap[itemEntry.itemId],\n\t\t\t\t\tfalse,\n\t\t\t\t\tchangesListener,\n\t\t\t\t\tabortSignal,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic processLinkedItems (\n\t\tlinkedEntries: ItemTypeMap<ItemEntry[]>,\n\t\tonChange?: ItemAggregatedChangesListener<any>,\n\t\tabortSignal?: AbortSignal,\n\t): ItemResourcesItemTypeMap {\n\t\tconst result: ItemResourcesItemTypeMap = {};\n\n\t\tfor (const itemType in linkedEntries) {\n\t\t\tresult[itemType] = this.createItemResources(\n\t\t\t\tlinkedEntries[itemType],\n\t\t\t\t{},\n\t\t\t\tonChange,\n\t\t\t\tabortSignal,\n\t\t\t);\n\t\t}\n\n\t\t// We don't have to call `callInitialChangesListener` here because we handle that in a higher level\n\n\t\treturn result;\n\t}\n\n\tpublic clearItemError (\n\t\titemEntryId?: ItemEntry['id'],\n\t\tcolumnId?: string,\n\t\terrorKey?: string,\n\t): void;\n\n\tpublic clearItemError (\n\t\titemEntryId: ItemEntry['id'],\n\t\tcolumnId?: string,\n\t\terrorKey?: string,\n\t): void;\n\n\tpublic clearItemError (\n\t\titemEntryId: ItemEntry['id'],\n\t\tcolumnId: string,\n\t\terrorKey?: string,\n\t): void;\n\n\tpublic clearItemError (\n\t\titemEntryId: ItemEntry['id'],\n\t\tcolumnId: string,\n\t\terrorKey: string,\n\t): void;\n\n\tpublic clearItemError (\n\t\titemEntryId?: ItemEntry['id'],\n\t\tcolumnId?: string,\n\t\terrorKey?: string,\n\t): void {\n\t\tif (itemEntryId === undefined) {\n\t\t\t// When no entry id is passed, we clear all errors\n\t\t\tthis.errors.item.set(\n\t\t\t\t{},\n\t\t\t);\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (columnId === undefined) {\n\t\t\t// When no column id is passed, we clear all errors for the item entry\n\n\t\t\tthis.errors.item.update(\n\t\t\t\terrors => {\n\t\t\t\t\tdelete errors[itemEntryId];\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...errors,\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t);\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (errorKey === undefined) {\n\t\t\tthis.errors.item.update(\n\t\t\t\terrors => {\n\t\t\t\t\tif (!errors[itemEntryId]) {\n\t\t\t\t\t\treturn errors;\n\t\t\t\t\t}\n\n\t\t\t\t\t// When no specific error key is passed, we clear all errors for the item entry and column\n\t\t\t\t\tdelete errors[itemEntryId][columnId];\n\n\t\t\t\t\tif (\n\t\t\t\t\t\t!hasProperties(\n\t\t\t\t\t\t\terrors[itemEntryId],\n\t\t\t\t\t\t)\n\t\t\t\t\t) {\n\t\t\t\t\t\tdelete errors[itemEntryId];\n\t\t\t\t\t}\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...errors,\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t);\n\n\t\t\treturn;\n\t\t}\n\n\t\tthis.errors.item.update(\n\t\t\terrors => {\n\t\t\t\tif (errors[itemEntryId]?.[columnId] === undefined) {\n\t\t\t\t\treturn errors;\n\t\t\t\t}\n\n\t\t\t\t// When all parameters are passed, we clear the specific error\n\t\t\t\tdelete errors[itemEntryId][columnId][errorKey];\n\n\t\t\t\tif (\n\t\t\t\t\t!hasProperties(\n\t\t\t\t\t\terrors[itemEntryId][columnId],\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\tdelete errors[itemEntryId][columnId];\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\t!hasProperties(\n\t\t\t\t\t\terrors[itemEntryId],\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\tdelete errors[itemEntryId];\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\t...errors,\n\t\t\t\t};\n\t\t\t},\n\t\t);\n\t}\n\n\tprivate async doApplyChangesDelta (\n\t\tchangesDelta: ChangesDelta | ChildChangesDelta,\n\t): Promise<ChangesDeltaResult> {\n\t\t// If you don't have the lock we don't want to apply any changes\n\t\tawait this.fetchLock();\n\n\t\tthis.handleCascadingDeletes(\n\t\t\tchangesDelta,\n\t\t);\n\n\t\t// We can assume that if an ChildChangesDelta is applied that the business logic is already done (on the child transaction)\n\t\tif (changesDelta instanceof ChangesDelta) {\n\t\t\tconst businessLogicChangesDelta = await this.dependencies.businessLogicManager.handleBusinessLogic(\n\t\t\t\tthis,\n\t\t\t\tchangesDelta,\n\t\t\t);\n\n\t\t\tif (businessLogicChangesDelta === null) {\n\t\t\t\treturn {\n\t\t\t\t\t// No changes have been applied, so return an empty changes delta.\n\t\t\t\t\tchangesDelta: this.createChangesDelta(),\n\t\t\t\t\tcreated: [],\n\t\t\t\t\tallChildrenDonePromise: Promise.resolve(),\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// Overwrite the changesDelta reference with the newly (combined) changesDelta from the business logic\n\t\t\tchangesDelta = businessLogicChangesDelta;\n\t\t}\n\n\t\tconst parentChangesDelta = this.dependencies.changesDeltaFactory.constructParentDelta(\n\t\t\tchangesDelta,\n\t\t);\n\n\t\tconst createdEntries: ItemEntry[] = [];\n\n\t\tif (changesDelta instanceof ChangesDelta) {\n\t\t\t// We only create new entries on the direct transaction, not on the children\n\t\t\tchangesDelta.created.forEach(\n\t\t\t\ttuple => {\n\t\t\t\t\tconst itemEntry = this.processCreatedItem(\n\t\t\t\t\t\ttuple,\n\t\t\t\t\t\tchangesDelta,\n\t\t\t\t\t);\n\n\t\t\t\t\tif (itemEntry === null) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tcreatedEntries.push(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t);\n\n\t\t\t\t\tparentChangesDelta.setItemCreated(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\tthis.itemHandler.itemChanges[itemEntry.id],\n\t\t\t\t\t);\n\n\t\t\t\t\tif (tuple.isRoot) {\n\t\t\t\t\t\tthis.rootItemSignal.set(\n\t\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t);\n\t\t} else {\n\t\t\tfor (const itemEntryId in changesDelta.created) {\n\t\t\t\tconst tuple = changesDelta.created[itemEntryId];\n\n\t\t\t\tthis.itemHandler.entries.add(\n\t\t\t\t\ttuple.entry,\n\t\t\t\t);\n\n\t\t\t\tconst localChanges = this.itemHandler.itemChanges[tuple.entry.id] = this.itemHandler.copyTransactionItemEntryChanges(\n\t\t\t\t\ttuple.fields,\n\t\t\t\t\ttuple.entry,\n\t\t\t\t);\n\n\t\t\t\tparentChangesDelta.setItemCreated(\n\t\t\t\t\ttuple.entry,\n\t\t\t\t\tlocalChanges,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// `expandLocalItemsFromDelta` should run after created items have been processed, so item changes are available,\n\t\t// and ideally, before `applyUpdatesFromDelta`, so default values are set before changes hooks will run.\n\t\t// This is why created and updated items are read from different changes deltas.\n\t\tawait this.expandLocalItemsFromDelta(\n\t\t\tparentChangesDelta.created,\n\t\t\tchangesDelta.updated,\n\t\t);\n\n\t\t// `fetchUpdatedDerivedValuesFromDelta` should run after the new items are created. This allows newly created\n\t\t// items to refer to other newly created items in their fields.\n\t\tawait this.fetchUpdatedDerivedValuesFromDelta(\n\t\t\tchangesDelta,\n\t\t\tundefined,\n\t\t);\n\n\t\tthis.itemHandler.processUpdatesFromDelta(\n\t\t\tchangesDelta.updated,\n\t\t\ttrue,\n\t\t\tparentChangesDelta,\n\t\t);\n\n\t\tif (changesDelta instanceof ChangesDelta) {\n\t\t\tfor (const itemEntryId in changesDelta.restored) {\n\t\t\t\tconst tuple = changesDelta.restored[itemEntryId];\n\n\t\t\t\tif (tuple.entry.isLocal()) {\n\t\t\t\t\tthis.itemHandler.entries.add(\n\t\t\t\t\t\ttuple.entry,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tthis.itemHandler.itemChanges[tuple.entry.id] = tuple.changes;\n\n\t\t\t\tparentChangesDelta.setItemUpdated(\n\t\t\t\t\ttuple.entry,\n\t\t\t\t\ttuple.changes,\n\t\t\t\t\tnull,\n\t\t\t\t\t'KEEP_WHEN_DIFFERENT',\n\t\t\t\t);\n\n\t\t\t\tthis.itemHandler.removeFromDeletedItems(\n\t\t\t\t\ttuple.entry,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tfor (const deleteTuple of changesDelta.getDeleteTuplesIterator()) {\n\t\t\tparentChangesDelta.setItemDeleted(\n\t\t\t\tdeleteTuple.entry,\n\t\t\t);\n\n\t\t\tthis.itemHandler.addToDeletedItems(\n\t\t\t\tdeleteTuple.entry,\n\t\t\t\tdeleteTuple.isCascaded,\n\t\t\t);\n\t\t}\n\n\t\tconst matchingResults = await this.cachedQueryHandler.matchItemsToCollectionQueries(\n\t\t\tparentChangesDelta,\n\t\t\tundefined,\n\t\t\ttrue,\n\t\t);\n\n\t\tconst collectionResourceChanges = await this.cachedQueryHandler.applyMatchingResultsToCollections(\n\t\t\tmatchingResults,\n\t\t);\n\n\t\tthis.runChangesListenersAndValidators(\n\t\t\tcollectionResourceChanges,\n\t\t\tparentChangesDelta,\n\t\t\t// Item ID conversion will only happen on save, where transaction changes will be propagated using\n\t\t\t// `applyChangesFromParent`.\n\t\t\tundefined,\n\t\t\tfalse,\n\t\t);\n\n\t\tthis.clearChildCollectionResources(\n\t\t\tcollectionResourceChanges,\n\t\t);\n\n\t\tthis.detectChanges(\n\t\t\ttrue,\n\t\t);\n\n\t\tif (this.validator !== undefined) {\n\t\t\ttry {\n\t\t\t\tthis.validator.validateTransaction();\n\t\t\t} catch (e) {\n\t\t\t\tthis.dependencies.errorHandler.logError(\n\t\t\t\t\te,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tchangesDelta,\n\t\t\tcreated: createdEntries,\n\t\t\tallChildrenDonePromise: Promise\n\t\t\t\t.all(\n\t\t\t\t\tthis.children.map(\n\t\t\t\t\t\tchildTransaction => childTransaction.applyChangesFromParent(\n\t\t\t\t\t\t\tparentChangesDelta,\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\t.then(\n\t\t\t\t\t() => {\n\t\t\t\t\t\t// We only actually remove the deleted items' values when we've synced the cached queries and collection\n\t\t\t\t\t\t// so that we can still reference their values in the callbacks\n\t\t\t\t\t\tfor (const deleteTuple of changesDelta.getDeleteTuplesIterator()) {\n\t\t\t\t\t\t\tthis.clearItemEntry(\n\t\t\t\t\t\t\t\tdeleteTuple.entry,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t};\n\t}\n\n\tprivate updateSignals (\n\t\tcollectionResourceChanges: CollectionItemResourceChanges<CollectionResource<any, any, any>>[],\n\t\tparentChangesDelta: ParentChangesDelta,\n\t): void {\n\t\tfor (const collectionResourceChangesTuple of collectionResourceChanges) {\n\t\t\tconst collectionResource = collectionResourceChangesTuple.collectionResource;\n\n\t\t\tif (\n\t\t\t\tcollectionResourceChangesTuple.addedItems.length > 0\n\t\t\t\t|| collectionResourceChangesTuple.removedItems.length > 0\n\t\t\t) {\n\t\t\t\tcollectionResource.itemsSignal.set(\n\t\t\t\t\t[\n\t\t\t\t\t\t...collectionResource.items,\n\t\t\t\t\t],\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// We don't handle create or delete items here, because:\n\t\t// - created items don't exist yet, so cannot have signals yet\n\t\t// - deleted items will be removed, so don't need updating\n\t\tfor (const itemEntryId in parentChangesDelta.updated) {\n\t\t\tconst signals = this.itemHandler.itemFieldSignals[itemEntryId];\n\n\t\t\tif (signals === undefined) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst changedFields = parentChangesDelta.updated[itemEntryId].changes.fields;\n\n\t\t\tfor (const columnId in changedFields) {\n\t\t\t\tsignals[columnId]?.set(\n\t\t\t\t\tchangedFields[columnId],\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * This method:\n\t * - calls changes listeners for single items;\n\t * - runs validators for single items;\n\t * - calls changes listeners for collections;\n\t * - calls aggregated changes listeners;\n\t *\n\t * When this method is called, all collections should already be updated. This ensures collections used in changes\n\t * listeners and validators are up-to-date.\n\t *\n\t * @param changesDelta - Newly created items as well as previous values for changed items are read from this\n\t * changes delta.\n\t * {@link processUpdatesFromDelta} should have been called already. TODO: Express this in the type somehow.\n\t */\n\tprivate runChangesListenersAndValidators (\n\t\tcollectionResourceChanges: CollectionItemResourceChanges<CollectionResource<any, any, any>>[],\n\t\tchangesDelta: ParentChangesDelta,\n\t\titemIdConversionMap: ItemIdConversionMap | undefined,\n\t\tisCalledAfterSocketUpdate: boolean,\n\t): void {\n\t\t// We have to run this before the validator runs so that all the values are updated in the signals\n\t\tthis.updateSignals(\n\t\t\tcollectionResourceChanges,\n\t\t\tchangesDelta,\n\t\t);\n\n\t\t// We must also validate newly created items as the template request does not always contain valid information\n\t\t// e.g. empty dates that still need to be set by the user\n\t\t// We validate created entries after fetching derived values because the validator might rely on those values being present\n\t\tif (this.validator !== undefined) {\n\t\t\tfor (const itemEntryId in changesDelta.created) {\n\t\t\t\tconst tuple = changesDelta.created[itemEntryId];\n\n\t\t\t\ttry {\n\t\t\t\t\tthis.validator.validateItem(\n\t\t\t\t\t\ttuple.entry,\n\t\t\t\t\t\ttuple.fields,\n\t\t\t\t\t\ttuple.fields,\n\t\t\t\t\t\t// As `fields` and `previous` refer to the same object, `compareField` will always return `true`.\n\t\t\t\t\t\t() => true,\n\t\t\t\t\t);\n\t\t\t\t} catch (exception) {\n\t\t\t\t\tthis.dependencies.errorHandler.notifyError(\n\t\t\t\t\t\texception,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst aggregatedListenerChangesAccumulator: AggregatedChangesByListener = new Map();\n\t\tconst fieldChangeCallbacks = this.itemHandler.fieldChangeCallbacks;\n\n\t\tfor (const itemEntryId in changesDelta.updated) {\n\t\t\tconst tuple = changesDelta.updated[itemEntryId];\n\t\t\tconst itemEntry = tuple.entry;\n\t\t\tconst onChangeCallbacks = fieldChangeCallbacks[itemEntry.itemType]?.[itemEntry.itemId];\n\t\t\tconst aggregatedListeners: Set<AggregatedChangesListenerFunction<any, any>> = new Set();\n\t\t\tconst itemResources: Generator<ItemResource<any, any, any>> = this.itemHandler.getItemResources(\n\t\t\t\titemEntry,\n\t\t\t);\n\n\t\t\tlet firstItemResource: ItemResource<any, any, any> | undefined;\n\n\t\t\tfor (const itemResource of itemResources) {\n\t\t\t\tif (firstItemResource === undefined) {\n\t\t\t\t\tfirstItemResource = itemResource;\n\t\t\t\t}\n\n\t\t\t\titemResource.getAggregatedChangesListeners(\n\t\t\t\t\taggregatedListeners,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tthis.validator === undefined\n\t\t\t\t&& onChangeCallbacks === undefined\n\t\t\t\t&& aggregatedListeners.size === 0\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (firstItemResource === undefined) {\n\t\t\t\tfirstItemResource = this.createItemResource(\n\t\t\t\t\titemEntry,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst context = new ItemChangesListenerContext(\n\t\t\t\tfirstItemResource,\n\t\t\t\tthis.itemHandler,\n\t\t\t\t// `previous` can be `null` when there are no changes on the current transaction. There\n\t\t\t\t// might be changes on the parent transaction, or an empty might have been used to add items to\n\t\t\t\t// newly created cached queries on the server cache. We do want to run validators in the first case.\n\t\t\t\ttuple.previous ?? {},\n\t\t\t\titemIdConversionMap,\n\t\t\t\tisCalledAfterSocketUpdate,\n\t\t\t);\n\n\t\t\tif (aggregatedListeners.size > 0) {\n\t\t\t\tfor (const aggregatedChangesListener of aggregatedListeners) {\n\t\t\t\t\tlet aggregatedChanges = aggregatedListenerChangesAccumulator.get(\n\t\t\t\t\t\taggregatedChangesListener,\n\t\t\t\t\t);\n\n\t\t\t\t\tif (aggregatedChanges === undefined) {\n\t\t\t\t\t\taggregatedListenerChangesAccumulator.set(\n\t\t\t\t\t\t\taggregatedChangesListener,\n\t\t\t\t\t\t\taggregatedChanges = {\n\t\t\t\t\t\t\t\titem: {},\n\t\t\t\t\t\t\t\tcollection: {},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\t(aggregatedChanges.item[itemEntry.itemType] as unknown as ItemChangesListenerContext<any>[]) ??= [];\n\n\t\t\t\t\t(aggregatedChanges.item[itemEntry.itemType] as unknown as ItemChangesListenerContext<any>[]).push(\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (this.validator !== undefined) {\n\t\t\t\ttry {\n\t\t\t\t\tthis.validator.validateItem(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\tcontext.fields,\n\t\t\t\t\t\tcontext.previous,\n\t\t\t\t\t\tcontext.compareField.bind(\n\t\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t} catch (e) {\n\t\t\t\t\tthis.dependencies.errorHandler.logError(\n\t\t\t\t\t\te,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (onChangeCallbacks !== undefined) {\n\t\t\t\tfor (const callback of onChangeCallbacks) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tcallback(\n\t\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tthis.dependencies.errorHandler.logError(\n\t\t\t\t\t\t\terror,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (const collectionResourceChangesTuple of collectionResourceChanges) {\n\t\t\tcollectionResourceChangesTuple.collectionResource.triggerCollectionChangesListeners(\n\t\t\t\tcollectionResourceChangesTuple,\n\t\t\t\tchangesDelta,\n\t\t\t\titemIdConversionMap,\n\t\t\t\tisCalledAfterSocketUpdate,\n\t\t\t\tfalse,\n\t\t\t\taggregatedListenerChangesAccumulator,\n\t\t\t);\n\t\t}\n\n\t\tfor (const aggregatedListenerChangesAccumulatorEntry of aggregatedListenerChangesAccumulator.entries()) {\n\t\t\taggregatedListenerChangesAccumulatorEntry[0](\n\t\t\t\taggregatedListenerChangesAccumulatorEntry[1].collection,\n\t\t\t\taggregatedListenerChangesAccumulatorEntry[1].item,\n\t\t\t\tisCalledAfterSocketUpdate,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate clearChildCollectionResources (\n\t\tcollectionResourceChanges: CollectionItemResourceChanges<CollectionResource<any, any, any>>[],\n\t): void {\n\t\tfor (const collectionResourceChangesTuple of collectionResourceChanges) {\n\t\t\tfor (const removedItemResource of collectionResourceChangesTuple.removedItems) {\n\t\t\t\tremovedItemResource.clearChildCollections();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Sets a default value for all columns required to match / fit in collections.\n\t *\n\t * This whole step could be removed once we always request all columns when doing a columns request. (RM4-25895).\n\t * We could set a default value for all columns when creating a local item, even if the column is not included in\n\t * the template.\n\t */\n\tprivate expandLocalItemsFromDelta (\n\t\tcreated: {\n\t\t\t[itemEntryId: string]: {\n\t\t\t\tentry: ItemEntry,\n\t\t\t},\n\t\t},\n\t\tupdated: {\n\t\t\t[itemEntryId: number]: {\n\t\t\t\tentry: ItemEntry,\n\t\t\t},\n\t\t},\n\t): Promise<void[]> {\n\t\tconst itemEntriesPerItemTypeMap: {\n\t\t\t[itemType: string]: ItemEntry[],\n\t\t} = {};\n\n\t\tconst columnsPerItemTypeMap: {\n\t\t\t[itemType: string]: ApiRequestColumns,\n\t\t} = {};\n\n\t\t// We can assume all created items will be stored on this transaction. (If `applyChangesFromChild` was called,\n\t\t// the items will be stored on this transaction as well.)\n\t\tfor (const itemEntryId in created) {\n\t\t\tconst itemEntry = created[itemEntryId].entry;\n\n\t\t\tif (itemEntriesPerItemTypeMap[itemEntry.itemType] === undefined) {\n\t\t\t\titemEntriesPerItemTypeMap[itemEntry.itemType] = [];\n\t\t\t}\n\n\t\t\titemEntriesPerItemTypeMap[itemEntry.itemType].push(\n\t\t\t\titemEntry,\n\t\t\t);\n\t\t}\n\n\t\tconst itemEntries = this.itemHandler.entries;\n\n\t\t// This can occur when:\n\t\t// 1. An item is created on a transaction;\n\t\t// 2. A query is added requiring additional columns;\n\t\t// 3. The item in question is updated (before saving).\n\t\t// However, this case should be extremely rare.\n\t\tfor (const itemEntryId in updated) {\n\t\t\tconst itemEntry = updated[itemEntryId].entry;\n\n\t\t\tif (\n\t\t\t\t!itemEntries.containsByEntryId(\n\t\t\t\t\titemEntry.id,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (itemEntriesPerItemTypeMap[itemEntry.itemType] === undefined) {\n\t\t\t\titemEntriesPerItemTypeMap[itemEntry.itemType] = [];\n\t\t\t}\n\n\t\t\titemEntriesPerItemTypeMap[itemEntry.itemType].push(\n\t\t\t\titemEntry,\n\t\t\t);\n\t\t}\n\n\t\tfor (const itemType in itemEntriesPerItemTypeMap) {\n\t\t\tconst cachedQueryItems = this.cachedQueryHandler.getCachedQueryItemsByItemType(\n\t\t\t\titemType as ApiItemType,\n\t\t\t);\n\n\t\t\tif (cachedQueryItems.length === 0) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst columnExpansion = this.dependencies.requestColumnExpansionFactory.construct();\n\n\t\t\tfor (const cachedQueryItem of cachedQueryItems) {\n\t\t\t\tcolumnExpansion.expandWithRequestColumnsTuple(\n\t\t\t\t\tcachedQueryItem.itemType,\n\t\t\t\t\tcachedQueryItem.requestColumnsTuple,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tcolumnsPerItemTypeMap[itemType] = columnExpansion.get()[itemType];\n\t\t}\n\n\t\tconst promises: Promise<void>[] = [];\n\n\t\tfor (const itemType in columnsPerItemTypeMap) {\n\t\t\tconst requestColumns = columnsPerItemTypeMap[itemType] as ApiRequestColumns<ApiItemType>;\n\n\t\t\tpromises.push(\n\t\t\t\tthis.itemHandler.expandLocalItemEntries(\n\t\t\t\t\titemType,\n\t\t\t\t\titemEntriesPerItemTypeMap[itemType],\n\t\t\t\t\trequestColumns,\n\t\t\t\t\tthis.dependencies.columnCache\n\t\t\t\t\t\t.retrieve(\n\t\t\t\t\t\t\titemType as ApiItemType,\n\t\t\t\t\t\t\trequestColumns,\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.cached,\n\t\t\t\t\tfalse,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\treturn Promise.all(\n\t\t\tpromises,\n\t\t);\n\t}\n\n\tprivate clearGlobalError (\n\t\tkey?: string,\n\t): void {\n\t\tif (key === undefined) {\n\t\t\tthis.errors.global.set(\n\t\t\t\t{},\n\t\t\t);\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst globalErrors = this.errors.global();\n\n\t\tdelete globalErrors[key];\n\n\t\t// Only the root is reactive, so we don't have to make a full copy\n\t\tthis.errors.global.set(\n\t\t\t{\n\t\t\t\t...globalErrors,\n\t\t\t},\n\t\t);\n\t}\n\n\tprivate maybeCallInitialChangesListener (\n\t\toptions: {\n\t\t\tchangesListener?: AggregatedChangesListenerFunction<any, any>,\n\t\t\timmediatelyCallChangesListener?: boolean,\n\t\t},\n\t\tcollectionResources: CollectionResource<any, any, any>[],\n\t\titemResources: ItemResource<any, any, any>[],\n\t): void {\n\t\tif (\n\t\t\toptions.changesListener === undefined\n\t\t\t|| options.immediatelyCallChangesListener !== true\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst aggregatedListenerChangesAccumulator: AggregatedChangesByListener = new Map();\n\n\t\tconst addCollectionAndChildren = (\n\t\t\tcollectionResource: CollectionResource<any>,\n\t\t): void => {\n\t\t\tcollectionResource.triggerCollectionChangesListeners(\n\t\t\t\t{\n\t\t\t\t\taddedItems: collectionResource.items,\n\t\t\t\t\tremovedItems: [],\n\t\t\t\t},\n\t\t\t\tnull,\n\t\t\t\tundefined,\n\t\t\t\tfalse,\n\t\t\t\ttrue,\n\t\t\t\taggregatedListenerChangesAccumulator,\n\t\t\t);\n\n\t\t\tfor (const itemResource of collectionResource.items) {\n\t\t\t\taddItemResourceAndChildren(\n\t\t\t\t\titemResource,\n\t\t\t\t);\n\t\t\t}\n\t\t};\n\n\t\tconst addItemResourceAndChildren = (\n\t\t\titemResource: ItemResource<any, any, any>,\n\t\t): void => {\n\t\t\tconst listenerSet: Set<AggregatedChangesListenerFunction<any, any>> = new Set();\n\n\t\t\titemResource.getAggregatedChangesListeners(\n\t\t\t\tlistenerSet,\n\t\t\t);\n\n\t\t\tfor (const aggregatedChangesListener of listenerSet) {\n\t\t\t\tlet aggregatedChanges = aggregatedListenerChangesAccumulator.get(\n\t\t\t\t\taggregatedChangesListener,\n\t\t\t\t);\n\n\t\t\t\tif (aggregatedChanges === undefined) {\n\t\t\t\t\taggregatedListenerChangesAccumulator.set(\n\t\t\t\t\t\taggregatedChangesListener,\n\t\t\t\t\t\taggregatedChanges = {\n\t\t\t\t\t\t\titem: {},\n\t\t\t\t\t\t\tcollection: {},\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t(aggregatedChanges.item[itemResource.itemType] as unknown as ItemChangesListenerContext<any>[]) ??= [];\n\n\t\t\t\t(aggregatedChanges.item[itemResource.itemType] as unknown as ItemChangesListenerContext<any>[]).push(\n\t\t\t\t\tnew ItemChangesListenerContext(\n\t\t\t\t\t\titemResource,\n\t\t\t\t\t\tthis.itemHandler,\n\t\t\t\t\t\t{},\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tfor (const childItemType in itemResource.children) {\n\t\t\t\taddCollectionAndChildren(\n\t\t\t\t\titemResource.children[childItemType] as CollectionResource<any>,\n\t\t\t\t);\n\t\t\t}\n\t\t};\n\n\t\tfor (const collectionResource of collectionResources) {\n\t\t\taddCollectionAndChildren(\n\t\t\t\tcollectionResource,\n\t\t\t);\n\t\t}\n\n\t\tfor (const itemResource of itemResources) {\n\t\t\taddItemResourceAndChildren(\n\t\t\t\titemResource,\n\t\t\t);\n\t\t}\n\n\t\tfor (const aggregatedListenerChangesAccumulatorEntry of aggregatedListenerChangesAccumulator.entries()) {\n\t\t\taggregatedListenerChangesAccumulatorEntry[0](\n\t\t\t\taggregatedListenerChangesAccumulatorEntry[1].collection,\n\t\t\t\taggregatedListenerChangesAccumulatorEntry[1].item,\n\t\t\t\tfalse,\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { WritableSignal } from '@angular/core';\nimport { ApiEnumApiType, ApiItemType, ItemId } from '@rentman/backend-types';\nimport { ApiFormatter, ApiRequestColumnArray, ApiRequestColumns, ChangesDelta, ChangesDeltaBase, ChangesDeltaBaseItemUpdateDelta, ChangesDeltaItemCreateDelta, ChangesDeltaResult, ColumnUtil, createPath, DeregFunction, FieldMap, hasProperties, ItemAlreadyExistsException, ItemChangesListenerContext, ItemEntry, ItemHandlerBase, ItemHandlerFieldsProxyTarget, ItemIdConversionMap, ItemResource, ItemTypeColumnId, ItemTypeColumnIds, ItemTypeMap, KeyService, ModifyFieldsCallback, NewItemOptions, ParentChangesDelta, ParentChangesDeltaItemUpdateDelta, RequestColumnExpansion, RequestColumnsOperationsCache, ResponseColumnItemTypeMap, ResponseColumnMap, TransactionCache, TransactionItemHandlerDependencyInterface } from '../../../internal';\n\nexport type TransactionDeletedItem = {\n\tentry: ItemEntry,\n\tisCascaded: boolean,\n};\n\nexport interface TransactionItemHandlerFieldsProxyTarget<ItemTypeType extends ApiItemType>\n\textends ItemHandlerFieldsProxyTarget<ItemTypeType> {\n\n\titemHandler: TransactionItemHandler,\n}\n\nexport type ItemChangesListener<\n\tItemTypeType extends ApiItemType,\n\tColumnIds extends ItemTypeColumnIds<ItemTypeType> = ItemTypeColumnIds<ItemTypeType>\n> = (\n\targs: ItemChangesListenerContext<ItemResource<ItemTypeType, ColumnIds>>,\n) => void;\n\n/**\n * See {@link ItemHandlerBase.fieldsProxyHandler}.\n */\nexport const initialProxyHandler: ProxyHandler<TransactionItemHandlerFieldsProxyTarget<any>> = {\n\tget: (\n\t\ttarget: TransactionItemHandlerFieldsProxyTarget<any>,\n\t\tproperty: string,\n\t) => {\n\t\tconst itemEntry = target.itemEntry;\n\t\tconst targetItemHandler = target.itemHandler;\n\t\t// If an item is stored on the current transaction we can assume there won't be changes on the parent.\n\t\tconst itemHandler = targetItemHandler.entries.contains(\n\t\t\titemEntry.itemType,\n\t\t\titemEntry.itemId,\n\t\t)\n\t\t\t? targetItemHandler\n\t\t\t: targetItemHandler.transaction.parent.itemHandler;\n\n\t\tconst result = itemHandler.lookUpItemField(\n\t\t\titemEntry,\n\t\t\tproperty,\n\t\t);\n\n\t\t// todo: remove this when displayname is phased out, we don't want to put displayname on the transaction changes\n\t\t// since it's a readonly field which should never be on the transaction changes\n\t\tif (\n\t\t\tproperty === 'displayname'\n\t\t\t&& (\n\t\t\t\tresult === undefined\n\t\t\t\t// For local items it can be that we actually do have the required fields to create a displayname,\n\t\t\t\t// but because the actual column/data is also on the transaction (because readonly fields for local items are always stored there)\n\t\t\t\t// We also check for '' and attempt to manuall construct a displayname\n\t\t\t\t|| result === ''\n\t\t\t)\n\t\t) {\n\t\t\treturn itemHandler.getDisplayName(\n\t\t\t\titemEntry,\n\t\t\t);\n\t\t}\n\n\t\treturn result;\n\t},\n};\n\n/**\n * @description\n * In a {@link TransactionCache Transaction} only local items can be stored, so all entries in {@link TransactionItemHandler.entries this.entries} are local\n * If a non-local entry is requested it should be passed on to the {@link ServerItemHandler ServerItemHandler} which will __fetchCachedQueryItem the entry from the server\n */\nexport class TransactionItemHandler\n\textends ItemHandlerBase {\n\n\tpublic fieldChangeCallbacks: {\n\t\t[itemType: string]: {\n\t\t\t[itemId: string]: ItemChangesListener<any, any>[],\n\t\t},\n\t} = {};\n\n\t// todo[cache] should this be {[itemType: string]: {[itemEntryId: number]: ItemEntry}} for quick lookup ?\n\t/**\n\t * @warning\n\t * Can contain both local and non-local {@link ItemEntry itemEntries}\n\t */\n\tpublic deletedItems: ItemTypeMap<TransactionDeletedItem[]> = {};\n\n\t// eslint-disable-next-line max-len\n\tpublic itemResourcesPerEntry: Map<ItemEntry, WeakRef<ItemResource<any, any, any>>[]> = new Map<ItemEntry, WeakRef<ItemResource<any, any, any>>[]>();\n\n\tpublic constructor (\n\t\tprivate dependencies: TransactionItemHandlerDependencyInterface,\n\t\tpublic transaction: TransactionCache,\n\t) {\n\t\tsuper(\n\t\t\tdependencies.columnCache,\n\t\t\tdependencies.errorHandler,\n\t\t\tdependencies.requestColumnExpansionFactory,\n\t\t\tdependencies.requestColumnsOperationsCacheFactory,\n\t\t\tdependencies.itemEntryService,\n\t\t\ttransaction,\n\t\t\tdependencies.itemCacheFactory,\n\t\t);\n\t}\n\n\tpublic registerItemResource (\n\t\titemResource: ItemResource<any, any, any>,\n\t): void {\n\t\t// We always register itemResources so we can check which ones are \"live\" when handling socket messages\n\t\tif (\n\t\t\t!this.itemResourcesPerEntry.has(\n\t\t\t\titemResource.entry,\n\t\t\t)\n\t\t) {\n\t\t\tthis.itemResourcesPerEntry.set(\n\t\t\t\titemResource.entry,\n\t\t\t\t[\n\t\t\t\t\tnew WeakRef(\n\t\t\t\t\t\titemResource,\n\t\t\t\t\t),\n\t\t\t\t],\n\t\t\t);\n\t\t} else {\n\t\t\tthis.itemResourcesPerEntry.get(\n\t\t\t\titemResource.entry,\n\t\t\t)!.push(\n\t\t\t\tnew WeakRef(\n\t\t\t\t\titemResource,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}\n\n\tpublic* getItemResources<const ItemTypeType extends ApiItemType> (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t\tcleanUpStaleResources: boolean = false,\n\t): Generator<ItemResource<ItemTypeType, any, any>> {\n\t\tconst itemResourceRefs = this.itemResourcesPerEntry.get(\n\t\t\titemEntry,\n\t\t);\n\n\t\tif (itemResourceRefs === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet hasStaleResources: boolean = false;\n\n\t\tfor (const itemResourceRef of itemResourceRefs) {\n\t\t\tconst itemResource = itemResourceRef.deref();\n\n\t\t\tif (itemResource === undefined) {\n\t\t\t\thasStaleResources = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tyield itemResource;\n\t\t}\n\n\t\tif (\n\t\t\tcleanUpStaleResources\n\t\t\t&& hasStaleResources\n\t\t) {\n\t\t\tthis.cleanUpItemResourcesForEntry(\n\t\t\t\titemEntry,\n\t\t\t);\n\t\t}\n\t}\n\n\tpublic cleanUpItemResourcesForEntry (\n\t\titemEntry: ItemEntry<any>,\n\t): void {\n\t\tconst itemResources = this.itemResourcesPerEntry.get(\n\t\t\titemEntry,\n\t\t);\n\n\t\tif (itemResources === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst newRefs: WeakRef<ItemResource<any>>[] = [];\n\n\t\t// We don't use `this.getCollectionResources` here, because we want to clean up the refs itself\n\t\tfor (const itemResourceRef of itemResources) {\n\t\t\tconst itemResource = itemResourceRef.deref();\n\n\t\t\tif (itemResource === undefined) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tnewRefs.push(\n\t\t\t\titemResourceRef,\n\t\t\t);\n\t\t}\n\n\t\tif (newRefs.length !== itemResources.length) {\n\t\t\tthis.itemResourcesPerEntry.set(\n\t\t\t\titemEntry,\n\t\t\t\tnewRefs,\n\t\t\t);\n\t\t}\n\t}\n\n\tpublic override clearItemEntry<ItemTypeType extends ApiItemType> (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t): FieldMap<ItemTypeType> | undefined {\n\t\tthis.itemResourcesPerEntry.delete(\n\t\t\titemEntry,\n\t\t);\n\n\t\treturn super.clearItemEntry(\n\t\t\titemEntry,\n\t\t);\n\t}\n\n\tpublic addToDeletedItems (\n\t\titemEntry: ItemEntry<any>,\n\t\tisCascaded: boolean,\n\t): void {\n\t\t// We only store references of deleted items on child transactions of transactions containing the item itself.\n\t\t// We can also refer to local items here.\n\t\tif (\n\t\t\tthis.entries.contains(\n\t\t\t\titemEntry.itemType,\n\t\t\t\titemEntry.itemId,\n\t\t\t)\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst itemType = itemEntry.itemType;\n\n\t\tif (this.deletedItems[itemType] === undefined) {\n\t\t\tthis.deletedItems[itemType] = [];\n\t\t}\n\n\t\tconst deletedItem = this.deletedItems[itemType].find(\n\t\t\tdeleteEntry => deleteEntry.entry === itemEntry,\n\t\t);\n\n\t\tif (deletedItem === undefined) {\n\t\t\tthis.deletedItems[itemType].push(\n\t\t\t\t{\n\t\t\t\t\tentry: itemEntry,\n\t\t\t\t\tisCascaded,\n\t\t\t\t},\n\t\t\t);\n\t\t} else if (isCascaded) {\n\t\t\tdeletedItem.isCascaded = true;\n\t\t}\n\t}\n\n\tpublic removeFromDeletedItems (\n\t\titemEntry: ItemEntry<any>,\n\t): void {\n\t\tconst deletedItemsForItemType = this.deletedItems[itemEntry.itemType];\n\n\t\tif (deletedItemsForItemType === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst index = deletedItemsForItemType.findIndex(\n\t\t\tdeletedItem => deletedItem.entry === itemEntry,\n\t\t);\n\n\t\tif (index !== -1) {\n\t\t\tdeletedItemsForItemType.splice(\n\t\t\t\tindex,\n\t\t\t\t1,\n\t\t\t);\n\t\t}\n\t}\n\n\tpublic* getDeletedItemsIterator<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t): IterableIterator<ItemEntry<ItemTypeType>> {\n\t\tconst deletedItemsForItemType = this.deletedItems[itemType];\n\n\t\tif (deletedItemsForItemType === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const deletedItem of deletedItemsForItemType) {\n\t\t\tyield deletedItem.entry;\n\t\t}\n\t}\n\n\tpublic getDeletedItemsAmount<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t): number {\n\t\tconst deletedItemsForItemType = this.deletedItems[itemType];\n\n\t\treturn deletedItemsForItemType !== undefined\n\t\t\t? deletedItemsForItemType.length\n\t\t\t: 0;\n\t}\n\n\t/**\n\t * Construct a proxy object for the initial fields of the item. Reading a field will traverse the transaction chain.\n\t * The fields will come from the parent transaction, if avaiable.\n\t */\n\tpublic constructInitialProxy<ItemTypeType extends ApiItemType> (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t): FieldMap<ItemTypeType> {\n\t\treturn new Proxy(\n\t\t\t{\n\t\t\t\titemEntry,\n\t\t\t\titemHandler: this,\n\t\t\t},\n\t\t\tinitialProxyHandler,\n\t\t) as FieldMap<ItemTypeType>;\n\t}\n\n\tpublic* getItemEntriesWithChangesIterator (): Generator<ItemEntry<any>> {\n\t\tfor (const itemEntryId in this.itemChanges) {\n\t\t\ttry {\n\t\t\t\t// TODO: Move `getLocalItemEntry()` to item handler?\n\t\t\t\tyield this.transaction.getLocalItemEntry(\n\t\t\t\t\tNumber(\n\t\t\t\t\t\titemEntryId,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t} catch (exception) {\n\t\t\t\tthis.dependencies.errorHandler.logError(\n\t\t\t\t\texception,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Processes the changes on the transaction, and stores the changes as well as the previous values in\n\t * `parentChangesDelta`. Also handles changes listeners and validators.\n\t *\n\t * Note: Even though both the server item handler and the transaction item handler have a\n\t * {@link processUpdatesFromDelta} method, it is not defined on the superclass as the transaction item handler\n\t * introduces the `createItemChangesIfNoneExist` parameter.\n\t */\n\tpublic processUpdatesFromDelta (\n\t\tupdated: {\n\t\t\t[itemEntryId: number]: ChangesDeltaBaseItemUpdateDelta<any>,\n\t\t},\n\t\tcreateItemChangesIfNoneExist: boolean,\n\t\tparentChangesDelta: ParentChangesDelta,\n\t): void {\n\t\tfor (const itemEntryId in updated) {\n\t\t\tconst tuple = updated[itemEntryId];\n\n\t\t\tif (\n\t\t\t\t// RM4-42749: We need to ensure that a deleted item can never receive an update\n\t\t\t\t// because processing this update will try to re-match the item to collections.\n\t\t\t\t// On the transaction where the item was deleted this will properly be ignored, but on child\n\t\t\t\t// transactions this item is not in `deletedItems` and would be re-added (and error).\n\t\t\t\tthis.itemIsDeleted(\n\t\t\t\t\ttuple.entry,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst previous = this.processItemEntryChanges(\n\t\t\t\ttuple,\n\t\t\t\tcreateItemChangesIfNoneExist,\n\t\t\t);\n\n\t\t\tparentChangesDelta.setItemUpdated(\n\t\t\t\ttuple.entry,\n\t\t\t\ttuple.changes.fields,\n\t\t\t\tprevious,\n\t\t\t\ttuple.mode,\n\t\t\t);\n\t\t}\n\t}\n\n\tpublic updateLocalItemIdReferences (\n\t\titemType: ApiItemType,\n\t\toldItemId: ItemId,\n\t\tnewItemId: ItemId,\n\t\tchangesDelta: ChangesDeltaBase,\n\t): void {\n\t\tif (this.fieldChangeCallbacks[itemType] !== undefined && this.fieldChangeCallbacks[itemType][oldItemId] !== undefined) {\n\t\t\tthis.fieldChangeCallbacks[itemType][newItemId] = this.fieldChangeCallbacks[itemType][oldItemId];\n\n\t\t\tdelete this.fieldChangeCallbacks[itemType][oldItemId];\n\t\t}\n\n\t\t/**\n\t\t * Update all direct references\n\t\t * e.x. fields: { standaard_contactpersoon: -11 } to fields: { standaard_contactpersoon: 123 }\n\t\t * This is required because create requests are done before update requests (so that the update will contain the newly created ID)\n\t\t */\n\t\tfor (const itemEntry of this.getItemEntriesWithChangesIterator()) {\n\t\t\tif (\n\t\t\t\t// We shouldn't process the entry we're currently updating\n\t\t\t\titemEntry.itemId === newItemId\n\t\t\t\t|| (\n\t\t\t\t\t// Items that are created in the same create request shouldn't be updated, since the server response will already include the proper IDs\n\t\t\t\t\t// This is so that the `previous` values will still contain the old IDs\n\t\t\t\t\t// (We check `updated` since the entries are already created, so they aren't in created)\n\t\t\t\t\tchangesDelta.updated[itemEntry.id] !== undefined\n\t\t\t\t\t&& changesDelta.updated[itemEntry.id].mode !== 'QUERY'\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst changes = this.itemChanges[itemEntry.id];\n\n\t\t\tfor (const column of itemEntry.columns.item.main) {\n\t\t\t\tif (column.apiColumn.itemType !== itemType) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (changes[column.id] !== oldItemId) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tchanges[column.id] = newItemId;\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic registerFieldChangeCallback<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\titemId: ItemId,\n\t\tcallback: ItemChangesListener<ItemTypeType>,\n\t): DeregFunction {\n\t\tcreatePath(\n\t\t\tthis.fieldChangeCallbacks,\n\t\t\t[\n\t\t\t\titemType,\n\t\t\t\titemId,\n\t\t\t],\n\t\t\t[\n\t\t\t\t{},\n\t\t\t\t[],\n\t\t\t],\n\t\t);\n\n\t\tconst callbacks = this.fieldChangeCallbacks[itemType][itemId];\n\n\t\tcallbacks.push(\n\t\t\tcallback,\n\t\t);\n\n\t\treturn () => {\n\t\t\tconst index = callbacks.indexOf(\n\t\t\t\tcallback,\n\t\t\t);\n\n\t\t\tif (index === -1) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tcallbacks.splice(\n\t\t\t\tindex,\n\t\t\t\t1,\n\t\t\t);\n\t\t};\n\t}\n\n\tpublic createItemEntry (\n\t\tcreateTuple: ChangesDeltaItemCreateDelta,\n\t): ItemEntry {\n\t\tconst itemEntry = super.createItemEntry(\n\t\t\tcreateTuple,\n\t\t);\n\n\t\tthis.itemChanges[itemEntry.id] = ApiFormatter.copyFields(\n\t\t\tcreateTuple.fields,\n\t\t\t{},\n\t\t\tcreateTuple.columns.main,\n\t\t);\n\n\t\tthis.itemChanges[itemEntry.id].id = itemEntry.itemId;\n\n\t\treturn itemEntry;\n\t}\n\n\t/**\n\t * @description\n\t * Gets the local {@link FieldMap changes} of the {@link ItemEntry entry} on the {@link TransactionCache transaction} in a formatted way the API accepts\n\t */\n\tpublic formatRequest<ItemEntryType extends ItemEntry> (\n\t\tentry: ItemEntryType,\n\t): {[columnId: string]: any,} {\n\t\tif (this.itemChanges[entry.id] === undefined) {\n\t\t\treturn {};\n\t\t}\n\n\t\treturn ApiFormatter.formatRequestLocal(\n\t\t\tthis.itemChanges[entry.id],\n\t\t\tentry.columns.main,\n\t\t);\n\t}\n\n\tpublic detectChanges (): boolean {\n\t\tfor (const _ in this.itemChanges) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// if an entry is in this transaction's cache it's a local one, which counts as a change\n\t\tfor (const itemType in this.deletedItems) {\n\t\t\tif (this.deletedItems[itemType].length > 0) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * @description\n\t * Checks if the transaction has changes for the passed {@link ItemEntry.id ItemEntryId}\n\t */\n\tpublic detectEntryChanges (\n\t\titemEntryId: ItemEntry['id'],\n\t): boolean {\n\t\treturn this.itemChanges[itemEntryId] !== undefined;\n\t}\n\n\tpublic cloneItemEntries<ItemTypeType extends ApiItemType> (\n\t\tchangesDelta: ChangesDelta,\n\t\titemEntries: ItemEntry<ItemTypeType>[],\n\t\tconversionMap: ItemIdConversionMap = {},\n\t\tmodifyFieldsCallback?: ModifyFieldsCallback,\n\t): ItemId[] {\n\t\t// the the items might reference each other, so update the conversion map first\n\t\tthis.dependencies.conversionMapService.batchExpandConversionMap(\n\t\t\titemEntries,\n\t\t\tconversionMap,\n\t\t);\n\n\t\tconst result: ItemId[] = [];\n\n\t\tfor (const itemEntry of itemEntries) {\n\t\t\tresult.push(\n\t\t\t\tthis.cloneItemEntry(\n\t\t\t\t\tchangesDelta,\n\t\t\t\t\titemEntry,\n\t\t\t\t\tconversionMap,\n\t\t\t\t\tmodifyFieldsCallback,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic cloneItemEntry<ItemTypeType extends ApiItemType> (\n\t\tchangesDelta: ChangesDelta,\n\t\tsourceEntry: ItemEntry<ItemTypeType>,\n\t\tconversionMap: ItemIdConversionMap = {},\n\t\tmodifyFieldsCallback?: ModifyFieldsCallback,\n\t): ItemId {\n\t\tconst sourceEntryChanges: FieldMap<ItemTypeType> = this.transaction.itemHandler.collectFields(\n\t\t\tsourceEntry,\n\t\t);\n\n\t\tconst newItemId = this.dependencies.conversionMapService.expandConversionMap(\n\t\t\tsourceEntry.itemType,\n\t\t\tsourceEntry.itemId,\n\t\t\tconversionMap,\n\t\t);\n\n\t\tconst fieldsCopy = ApiFormatter.copyFields(\n\t\t\tsourceEntryChanges,\n\t\t\t{},\n\t\t\tsourceEntry.columns.main,\n\t\t);\n\n\t\tthis.dependencies.conversionMapService.updateItemValues(\n\t\t\tfieldsCopy,\n\t\t\tfieldsCopy,\n\t\t\tsourceEntry.columns.item.main,\n\t\t\tconversionMap,\n\t\t);\n\n\t\tif (modifyFieldsCallback !== undefined) {\n\t\t\tmodifyFieldsCallback(\n\t\t\t\tsourceEntry.itemType,\n\t\t\t\tfieldsCopy,\n\t\t\t);\n\t\t}\n\n\t\tchangesDelta._setItemCreated(\n\t\t\tnewItemId,\n\t\t\tfieldsCopy as Partial<FieldMap<ItemTypeType>>,\n\t\t\tsourceEntry.columns,\n\t\t);\n\n\t\treturn newItemId;\n\t}\n\n\tpublic fetchItemEntry<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\titemId: ItemId,\n\t\trequestColumns: ApiRequestColumns<ItemTypeType>,\n\t): Promise<ItemEntry<ItemTypeType>> {\n\t\tif (\n\t\t\titemId === undefined\n\t\t\t|| itemId === null\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t'undefined/null id passed to fetchItemEntry',\n\t\t\t);\n\t\t}\n\n\t\treturn this\n\t\t\t.fetchItemEntryData(\n\t\t\t\titemType,\n\t\t\t\t[\n\t\t\t\t\titemId,\n\t\t\t\t],\n\t\t\t\tthis.requestColumnsOperationsCacheFactory.construct(\n\t\t\t\t\titemType,\n\t\t\t\t\trequestColumns,\n\t\t\t\t),\n\t\t\t\ttrue,\n\t\t\t)\n\t\t\t.then(\n\t\t\t\titemEntries => itemEntries[0],\n\t\t\t);\n\t}\n\n\tpublic fetchItemEntries<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\titemIds: ItemId[],\n\t\trequestColumns: ApiRequestColumns<ItemTypeType>,\n\t): Promise<ItemEntry<ItemTypeType>[]> {\n\t\treturn this.fetchItemEntryData(\n\t\t\titemType,\n\t\t\titemIds,\n\t\t\tthis.requestColumnsOperationsCacheFactory.construct(\n\t\t\t\titemType,\n\t\t\t\trequestColumns,\n\t\t\t),\n\t\t\ttrue,\n\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Fetches a template and creates a new {@link ItemEntry ItemEntry}, will error if the ItemEntry with the given ItemId already exists\n\t */\n\tpublic async fetchNewItemEntry<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\titemId: ItemId,\n\t\toptions: NewItemOptions<ItemTypeType>,\n\t\tisRoot: boolean = false,\n\t): Promise<ChangesDeltaResult> {\n\t\tif (\n\t\t\tthis.entries.contains(\n\t\t\t\titemType,\n\t\t\t\titemId,\n\t\t\t)\n\t\t) {\n\t\t\tthrow new ItemAlreadyExistsException(\n\t\t\t\titemType,\n\t\t\t\titemId,\n\t\t\t);\n\t\t}\n\n\t\tconst requestColumnExpansion = this.dependencies.requestColumnExpansionFactory.construct();\n\n\t\trequestColumnExpansion.expandWithRequestColumns(\n\t\t\titemType,\n\t\t\toptions.columns,\n\t\t);\n\n\t\tif (options.defaultValues !== undefined) {\n\t\t\trequestColumnExpansion.expandWithRequestColumns(\n\t\t\t\titemType,\n\t\t\t\tObject.keys(\n\t\t\t\t\toptions.defaultValues,\n\t\t\t\t) as ApiRequestColumnArray<ItemTypeType>,\n\t\t\t);\n\t\t}\n\n\t\tconst template = await this.dependencies.templateCache.fetchTemplate(\n\t\t\titemType,\n\t\t\titemId,\n\t\t\toptions.templateOptions,\n\t\t\t// We should only pass columns here when we plan on setting a value later on.\n\t\t\trequestColumnExpansion.get(),\n\t\t\toptions.parent,\n\t\t);\n\n\t\t// It could be that for whatever reason 'fetchNewItem' is called a second time while loading\n\t\tif (\n\t\t\tthis.entries.contains(\n\t\t\t\titemType,\n\t\t\t\titemId,\n\t\t\t)\n\t\t) {\n\t\t\tthrow new ItemAlreadyExistsException(\n\t\t\t\titemType,\n\t\t\t\titemId,\n\t\t\t);\n\t\t}\n\n\t\tconst changesDelta = this.dependencies.changesDeltaFactory.construct(\n\t\t\tfalse,\n\t\t);\n\n\t\tthis.dependencies.itemCreateService.processTemplate(\n\t\t\tchangesDelta,\n\t\t\titemType,\n\t\t\titemId,\n\t\t\toptions.parent ?? null,\n\t\t\ttemplate,\n\t\t\tundefined,\n\t\t\t(\n\t\t\t\t_itemType: ApiItemType,\n\t\t\t\tfields,\n\t\t\t) => {\n\t\t\t\tif (\n\t\t\t\t\t_itemType !== itemType\n\t\t\t\t\t|| options.defaultValues === undefined\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tfor (const columnId in options.defaultValues) {\n\t\t\t\t\tfields[columnId] = options.defaultValues[columnId];\n\t\t\t\t}\n\t\t\t},\n\t\t\tisRoot,\n\t\t);\n\n\t\tconst itemTypeRequestMap: ItemTypeMap<{\n\t\t\tcolumns: RequestColumnExpansion,\n\t\t\titemIds: Set<ItemId>,\n\t\t}> = {};\n\n\t\t// TODO: The expanding of items should be handled in `applyChangesDelta`.\n\t\tchangesDelta.created.forEach(\n\t\t\t(\n\t\t\t\ttuple,\n\t\t\t\tcreatedItemType,\n\t\t\t) => {\n\t\t\t\tfor (const column of tuple.columns.root) {\n\t\t\t\t\tconst columnItemType: ApiItemType = column.itemType;\n\t\t\t\t\tconst derivedItemId = tuple.fields[column.id];\n\n\t\t\t\t\tif (derivedItemId === undefined) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t`ItemId for derived item of type for ${createdItemType}:${column.id} could not be found when fetching derived values for template item.`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (\n\t\t\t\t\t\tderivedItemId === null\n\t\t\t\t\t\t// We can assume that any local item here is also in the template and therefore in `created` itself\n\t\t\t\t\t\t|| KeyService.isLocalId(\n\t\t\t\t\t\t\tderivedItemId,\n\t\t\t\t\t\t)\n\t\t\t\t\t) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst rquestColumnsAndIdsTuple = itemTypeRequestMap[columnItemType] ??= {\n\t\t\t\t\t\tcolumns: this.dependencies.requestColumnExpansionFactory.construct(),\n\t\t\t\t\t\titemIds: new Set(),\n\t\t\t\t\t};\n\n\t\t\t\t\trquestColumnsAndIdsTuple.columns.expandWithRequestColumns(\n\t\t\t\t\t\tcolumn.itemType,\n\t\t\t\t\t\t// `toRequestColumns` returns a set like `[{<columnId>: [<columns>]}]` but we just want `[<columns>]`\n\t\t\t\t\t\tcolumn.toRequestColumns()[0][column.id],\n\t\t\t\t\t);\n\n\t\t\t\t\trquestColumnsAndIdsTuple.itemIds.add(\n\t\t\t\t\t\tderivedItemId,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\n\t\tconst promises: Promise<any>[] = [];\n\n\t\tfor (const requestItemType in itemTypeRequestMap) {\n\t\t\tconst requestColumnsAndIdsTuple = itemTypeRequestMap[requestItemType];\n\n\t\t\tpromises.push(\n\t\t\t\tthis.fetchItemEntries(\n\t\t\t\t\trequestItemType as ApiItemType,\n\t\t\t\t\tArray.from(\n\t\t\t\t\t\trequestColumnsAndIdsTuple.itemIds,\n\t\t\t\t\t),\n\t\t\t\t\trequestColumnsAndIdsTuple.columns.get()[requestItemType],\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\tawait Promise.all(\n\t\t\tpromises,\n\t\t);\n\n\t\treturn this.transaction.applyChangesDelta(\n\t\t\tchangesDelta,\n\t\t);\n\t}\n\n\tpublic override async fetchItemEntryData<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\titemIds: Iterable<ItemId>,\n\t\tcolumnsOperationsCache: RequestColumnsOperationsCache<ItemTypeType>,\n\t\trefreshAggregateColumns: boolean,\n\t\tforceRequest?: boolean,\n\t): Promise<ItemEntry<ItemTypeType>[]> {\n\t\tconst serverItemCache = this.transaction\n\t\t\t.getServerCache()\n\t\t\t.itemHandler\n\t\t\t.entries;\n\t\tconst itemIdsToDeferToParent: ItemId<ItemTypeType>[] = [];\n\t\tconst localItemIds: ItemId<ItemTypeType>[] = [];\n\t\tconst result: ItemEntry<ItemTypeType>[] = [];\n\n\t\tfor (const itemId of itemIds) {\n\t\t\tif (\n\t\t\t\tserverItemCache.contains(\n\t\t\t\t\titemType,\n\t\t\t\t\titemId,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tconst serverItemEntry = serverItemCache.get(\n\t\t\t\t\titemType,\n\t\t\t\t\titemId,\n\t\t\t\t);\n\n\t\t\t\tif (\n\t\t\t\t\t// We're looking in the server cache from the transaction cache because, on the server cache itself,\n\t\t\t\t\t// the columns will be expanded with the superset of all columns present there, which is fine when\n\t\t\t\t\t// requesting / expanding, but not necessary when the item is already cached.\n\t\t\t\t\t// These operations will probably run on multiple transactions when expanding, but won't\n\t\t\t\t\t// result in additional overhead since we're using a columns operations cache.\n\t\t\t\t\t!columnsOperationsCache.hasAggregateColumns()\n\t\t\t\t\t&& columnsOperationsCache.setContainsAllColumns(\n\t\t\t\t\t\tserverItemEntry.columns,\n\t\t\t\t\t\tthis.transaction,\n\t\t\t\t\t)\n\t\t\t\t\t&& !serverItemEntry.isOutdated()\n\t\t\t\t) {\n\t\t\t\t\tresult.push(\n\t\t\t\t\t\tserverItemEntry,\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\titemIdsToDeferToParent.push(\n\t\t\t\t\t\titemId,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tthis.entries.contains(\n\t\t\t\t\titemType,\n\t\t\t\t\titemId,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tlocalItemIds.push(\n\t\t\t\t\titemId,\n\t\t\t\t);\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\titemIdsToDeferToParent.push(\n\t\t\t\titemId,\n\t\t\t);\n\t\t}\n\n\t\t// Technically, we could use `Promise.all()` here, but as we rarely request local items and remote items\n\t\t// simultaneously, we opt for increased readability.\n\t\tif (localItemIds.length > 0) {\n\t\t\tconst localItemEntries = await this.fetchLocalItemEntryData(\n\t\t\t\titemType,\n\t\t\t\tlocalItemIds,\n\t\t\t\tcolumnsOperationsCache,\n\t\t\t);\n\n\t\t\tfor (const localItemEntry of localItemEntries) {\n\t\t\t\tresult.push(\n\t\t\t\t\tlocalItemEntry,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (itemIdsToDeferToParent.length > 0) {\n\t\t\tconst parentItemEntries = await this.transaction.parent.itemHandler.fetchItemEntryData(\n\t\t\t\titemType,\n\t\t\t\titemIdsToDeferToParent,\n\t\t\t\tcolumnsOperationsCache,\n\t\t\t\trefreshAggregateColumns,\n\t\t\t\tforceRequest,\n\t\t\t);\n\n\t\t\tfor (const parentItemEntry of parentItemEntries) {\n\t\t\t\tresult.push(\n\t\t\t\t\tparentItemEntry,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t// todo[cache] move to TransactionCache ?\n\tpublic fetchTitle<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\titemId: ItemId,\n\t): Promise<string> {\n\t\tconst titleField = this.dependencies.itemEntryService.getTitleField(\n\t\t\titemType,\n\t\t);\n\n\t\treturn this\n\t\t\t.fetchItemEntry(\n\t\t\t\titemType,\n\t\t\t\titemId,\n\t\t\t\t[\n\t\t\t\t\ttitleField,\n\t\t\t\t],\n\t\t\t)\n\t\t\t.then(\n\t\t\t\titemEntry => this.lookUpItemField(\n\t\t\t\t\titemEntry,\n\t\t\t\t\ttitleField,\n\t\t\t\t),\n\t\t\t) as Promise<string>;\n\t}\n\n\t/**\n\t * `expandLocalItemEntries` ensures values are available for the columns passed in `requestColumns`. As this method\n\t * only handles local items, it will set a default value.\n\t *\n\t * This is not handled using a changes delta because:\n\t * - these changes are strictly limited to the current transaction;\n\t * - existing fields are not affected, so no changes hooks should be triggered.\n\t *\n\t * @param itemEntries - Only local item entries (stored on this transaction only) should be passed here.\n\t */\n\tpublic expandLocalItemEntries<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\titemEntries: ItemEntry<ItemTypeType>[],\n\t\trequestColumns: ApiRequestColumns<ItemTypeType>,\n\t\tresponseColumns: Partial<ResponseColumnItemTypeMap>,\n\t\trefreshAggregateColumns: boolean,\n\t): Promise<void> {\n\t\tif (itemEntries.length === 0) {\n\t\t\treturn Promise.resolve();\n\t\t}\n\n\t\tconst columnExpansion = this.dependencies.columnExpansionFactory.construct(\n\t\t\titemType,\n\t\t\trequestColumns,\n\t\t\tresponseColumns as ResponseColumnItemTypeMap,\n\t\t);\n\n\t\tfor (const itemEntry of itemEntries) {\n\t\t\tconst columnExpansionResult = columnExpansion.run(\n\t\t\t\titemEntry.columns,\n\t\t\t);\n\n\t\t\tif (columnExpansionResult.difference === null) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\titemEntry.columns = columnExpansionResult.merged;\n\n\t\t\tconst changes: Partial<FieldMap<ItemTypeType>> = this.itemChanges[itemEntry.id];\n\n\t\t\tif (changes === undefined) {\n\t\t\t\tthis.errorHandler.logError(\n\t\t\t\t\tnew Error(\n\t\t\t\t\t\t`TransactionItemHandler: expected item changes for '${itemEntry.itemType}' item to be present`,\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tfor (const column of columnExpansionResult.difference.main) {\n\t\t\t\t// We test for `undefined` specifically because we don't want to overwrite `null` values.\n\t\t\t\tif (changes[column.id] !== undefined) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tchanges[column.id] = ApiFormatter.formatResponseValue(\n\t\t\t\t\tcolumn.apiColumn.type,\n\t\t\t\t\tcolumn.apiColumn.default,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn this.resolveDerivedValues(\n\t\t\titemEntries,\n\t\t\tcolumnExpansion.aggregateRootColumns(),\n\t\t\trefreshAggregateColumns,\n\t\t);\n\t}\n\n\t/**\n\t * If the entry was previously deleted, and somehow updated by another call (could be from server) we don't want to\n\t * re-add it to collections.\n\t */\n\tpublic override itemIsDeleted<ItemTypeType extends ApiItemType> (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t): boolean {\n\t\tconst deletedItemsForItemType = this.deletedItems[itemEntry.itemType];\n\n\t\treturn deletedItemsForItemType !== undefined\n\t\t\t&& deletedItemsForItemType.some(\n\t\t\t\tdeletedEntry => deletedEntry.entry === itemEntry,\n\t\t\t);\n\t}\n\n\tpublic clearItemResource (\n\t\tresource: ItemResource<any, any, any>,\n\t): void {\n\t\tconst resourceRefsForEntry = this.itemResourcesPerEntry.get(\n\t\t\tresource.entry,\n\t\t);\n\n\t\tif (resourceRefsForEntry === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst newResourceRefsForEntry: WeakRef<ItemResource<any, any, any>>[] = [];\n\n\t\t// We don't use `this.getItemResources` here, because we want to remove the the passed resource from the array, and we\n\t\t// need the original `WeakRef`s to do that.\n\t\tfor (const resourceRef of resourceRefsForEntry) {\n\t\t\tconst itemResource = resourceRef.deref();\n\n\t\t\tif (\n\t\t\t\titemResource !== undefined\n\t\t\t\t&& itemResource !== resource\n\t\t\t) {\n\t\t\t\tnewResourceRefsForEntry.push(\n\t\t\t\t\tresourceRef,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tthis.itemResourcesPerEntry.set(\n\t\t\tresource.entry,\n\t\t\tnewResourceRefsForEntry,\n\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Processes on a cached entry, if there are no {@link TransactionItemHandler.itemChanges itemChanges} the new\n\t * values will not be processed unless `createItemChangesIfNoneExist` is set.\n\t *\n\t * Note: Even though both the server item handler and the transaction item handler have a\n\t * {@link processItemEntryChanges} method, it is not defined on the superclass as the transaction item handler\n\t * introduces a `createItemChangesIfNoneExist` parameter.\n\t *\n\t * @param createItemChangesIfNoneExist Is `true` when called from `applyChangesDelta`. We assume that when\n\t * `applyChangesDelta` is called with updates that aren't on the transaction they should be added.\n\t *\n\t * @returns An object containing a previous value for each applied change. Because of the nature of item changes\n\t * it may also include changes applied on ancestor transactions. Is `null` when no changes have been made.\n\t */\n\t// TODO: A better way to do this would be to split this method into `applyChanges` and `applyChangesFromParent`,\n\t// to mirror the transactions themselves. (We could also get rid of the `createItemChangesIfNoneExist` parameter.)\n\tprotected processItemEntryChanges<ItemTypeType extends ApiItemType> (\n\t\titemEntryChangesTuple: ChangesDeltaBaseItemUpdateDelta<ItemTypeType>,\n\t\tcreateItemChangesIfNoneExist: boolean,\n\t): Readonly<Partial<FieldMap<ItemTypeType>>> | null {\n\t\tconst itemEntry = itemEntryChangesTuple.entry;\n\n\t\t// A query result can only put data on the ServerCache so we can ignore this\n\t\tif (itemEntryChangesTuple.mode === 'QUERY') {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (\n\t\t\tthis.itemChanges[itemEntry.id] === undefined\n\t\t\t&& createItemChangesIfNoneExist\n\t\t) {\n\t\t\tthis.itemChanges[itemEntry.id] = {};\n\t\t}\n\n\t\tconst responseColumns = itemEntry.columns.response[itemEntry.itemType] as ResponseColumnMap<ItemTypeType>;\n\t\tconst localChanges = this.itemChanges[itemEntry.id];\n\t\t// `previousInherited` contains a previous value for each of the changes applied to ancestor transactions.\n\t\t// Note: we could forgo an inherited 'previous' object all together if we would apply the changes in the child\n\t\t// transactions first, but that's quite a drastic change.\n\t\tconst previousInherited = ('previous' in itemEntryChangesTuple)\n\t\t\t? (itemEntryChangesTuple as ParentChangesDeltaItemUpdateDelta<ItemTypeType>).previous\n\t\t\t: null;\n\n\t\tlet previous: Partial<FieldMap<ItemTypeType>>;\n\n\t\tconst fieldSignals = this.itemFieldSignals[itemEntry.id];\n\n\t\tif (fieldSignals !== undefined) {\n\t\t\tfor (const columnId in itemEntryChangesTuple.changes.fields) {\n\t\t\t\tconst signal: WritableSignal<any> | undefined = fieldSignals[columnId];\n\n\t\t\t\tif (signal === undefined) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tsignal.set(\n\t\t\t\t\titemEntryChangesTuple.changes.fields[columnId],\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (localChanges === undefined) {\n\t\t\t// If we don't have changes on this transaction but there were changes on a parent transaction we still want to validate/call onChange here\n\t\t\t// so we only exit early if this is not the case\n\t\t\tif (previousInherited === null) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// As we don't have any local changes, we can inherit all previous values. Please note that we can only do\n\t\t\t// a direct assignment because `previous` is only written to when there *are* local changes.\n\t\t\t// The `previousInherited` object is also used when applying changes to sibling transactions.\n\t\t\tprevious = previousInherited;\n\t\t} else {\n\t\t\tconst changedFields = itemEntryChangesTuple.changes.fields;\n\t\t\tconst isLocalEntry = this.entries.containsByEntryId(\n\t\t\t\titemEntry.id,\n\t\t\t);\n\n\t\t\tprevious = {};\n\n\t\t\tswitch (itemEntryChangesTuple.mode) {\n\t\t\t\t// When a value is committed to the server the response of it is the \"absolute truth\" so we can blindly take over those values\n\t\t\t\t// we do this by deleting any user changes for those fields\n\t\t\t\tcase 'CLEAR_ALWAYS':\n\t\t\t\t\tif (isLocalEntry) {\n\t\t\t\t\t\t// If you have an entry that only lives on this transaction and you attempt to delete all the fields\n\t\t\t\t\t\t// that would mean you just have an empty entry without any properties which is never possible\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t'Cannot clear the fields of a local entry',\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (const columnId in changedFields) {\n\t\t\t\t\t\tif (localChanges[columnId] === undefined) {\n\t\t\t\t\t\t\t// If we've got a `previousInherited` value, it means the value has changed on the parent.\n\t\t\t\t\t\t\t// Because changes are hereditary, we can just copy this previous value.\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tpreviousInherited !== null\n\t\t\t\t\t\t\t\t&& previousInherited[columnId] !== undefined\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tprevious[columnId] = previousInherited[columnId];\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst responseColumn = responseColumns[columnId as string];\n\n\t\t\t\t\t\tif (responseColumn === undefined) {\n\t\t\t\t\t\t\t// We don't have to store values we don't have columns for\n\t\t\t\t\t\t\t// This can happen when manually calling `applyChangesFromParent` from the client\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t// Only update previous if the value has changed.\n\t\t\t\t\t\t\t!ApiFormatter.compareFields(\n\t\t\t\t\t\t\t\tresponseColumn.type,\n\t\t\t\t\t\t\t\tchangedFields[columnId],\n\t\t\t\t\t\t\t\tlocalChanges[columnId],\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tprevious[columnId] = localChanges[columnId];\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tdelete localChanges[columnId];\n\t\t\t\t\t}\n\n\t\t\t\t\t// We iterate over whatever is left of the local changes and remove all fields that are not writable (since they shouldn't be on the transaction)\n\t\t\t\t\tfor (const columnId in localChanges) {\n\t\t\t\t\t\tconst responseColumn = responseColumns[columnId];\n\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tresponseColumn.readOnly === false\n\t\t\t\t\t\t\t// Link columns are readOnly because you can only set them with a linkTo request\n\t\t\t\t\t\t\t|| responseColumn.type === ApiEnumApiType.TYPE_LINK\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t// Only update previous if the *current local* value is different than the *current value* on the parent\n\t\t\t\t\t\t\t// We are *not* interested in the old value on the parent\n\t\t\t\t\t\t\t!ApiFormatter.compareFields(\n\t\t\t\t\t\t\t\tresponseColumn.type,\n\t\t\t\t\t\t\t\tthis.transaction.parent.itemHandler.lookUpItemField(\n\t\t\t\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\t\t\t\tcolumnId as any,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tlocalChanges[columnId],\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tprevious[columnId] = localChanges[columnId];\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// If the value is equal to that of a parent transaction we can remove it here\n\t\t\t\t\t\tdelete localChanges[columnId];\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t// When a new value comes from the socket we should check if this new value is equal to what the user already has\n\t\t\t\t// and in that case remove the value from the transaction\n\t\t\t\tcase 'CLEAR_WHEN_SAME':\n\t\t\t\t\tfor (const columnId in changedFields) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tlocalChanges[columnId] !== undefined\n\t\t\t\t\t\t\t&& ApiFormatter.compareFields(\n\t\t\t\t\t\t\t\tresponseColumns[columnId as string].type,\n\t\t\t\t\t\t\t\tchangedFields[columnId],\n\t\t\t\t\t\t\t\tlocalChanges[columnId],\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tdelete localChanges[columnId];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t// A user change should only be saved on the transaction if it's different than the stored value on\n\t\t\t\t// a parent transaction.\n\t\t\t\tcase 'KEEP_WHEN_DIFFERENT':\n\t\t\t\t\tfor (const columnId in changedFields) {\n\t\t\t\t\t\t// We have no local value, and the changes are coming from the parent. We can just copy the\n\t\t\t\t\t\t// inherited previous value.\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tlocalChanges[columnId] === undefined\n\t\t\t\t\t\t\t&& previousInherited !== null\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tif (previousInherited[columnId] !== undefined) {\n\t\t\t\t\t\t\t\tprevious[columnId] = previousInherited[columnId];\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst responseColumn = responseColumns[columnId as string];\n\n\t\t\t\t\t\tif (responseColumn === undefined) {\n\t\t\t\t\t\t\t// We don't have to store values we don't have columns for.\n\t\t\t\t\t\t\t// This can happen when manually calling `applyChangesFromParent` from the client\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Local items have no value on the parent by definition.\n\t\t\t\t\t\tconst parentValue = isLocalEntry\n\t\t\t\t\t\t\t? undefined\n\t\t\t\t\t\t\t: this.transaction.parent.itemHandler.lookUpItemField(\n\t\t\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\t\t\tcolumnId as ItemTypeColumnId<ItemTypeType>,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\tconst newValueEqualToParentValue = parentValue !== undefined\n\t\t\t\t\t\t\t&& ApiFormatter.compareFields(\n\t\t\t\t\t\t\t\tresponseColumn.type,\n\t\t\t\t\t\t\t\tchangedFields[columnId],\n\t\t\t\t\t\t\t\tparentValue,\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\tif (localChanges[columnId] === undefined) {\n\t\t\t\t\t\t\t// We have no local value, and the changes are not coming from the parent.\n\t\t\t\t\t\t\t// We should only set our local value if it is not equal to the value on the parent.\n\t\t\t\t\t\t\tif (!newValueEqualToParentValue) {\n\t\t\t\t\t\t\t\tprevious[columnId] = parentValue;\n\t\t\t\t\t\t\t\tlocalChanges[columnId] = ApiFormatter.clone(\n\t\t\t\t\t\t\t\t\tresponseColumn.type,\n\t\t\t\t\t\t\t\t\tchangedFields[columnId],\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// From here on out, we can assume the transaction has a local value.\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t!ApiFormatter.compareFields(\n\t\t\t\t\t\t\t\tresponseColumn.type,\n\t\t\t\t\t\t\t\tchangedFields[columnId],\n\t\t\t\t\t\t\t\tlocalChanges[columnId],\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t// If the local value is not equal to the new value we should store our local value in previous.\n\t\t\t\t\t\t\tprevious[columnId] = localChanges[columnId];\n\n\t\t\t\t\t\t\t// We should only update our local value if it is not equal to the value on the parent.\n\t\t\t\t\t\t\tif (!newValueEqualToParentValue) {\n\t\t\t\t\t\t\t\tlocalChanges[columnId] = ApiFormatter.clone(\n\t\t\t\t\t\t\t\t\tresponseColumn.type,\n\t\t\t\t\t\t\t\t\tchangedFields[columnId],\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// If a parent has the value already we should *never* have the same value on the child.\n\t\t\t\t\t\tif (newValueEqualToParentValue) {\n\t\t\t\t\t\t\tdelete localChanges[columnId];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\t!hasProperties(\n\t\t\t\t\tlocalChanges,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\t// Item changes should only remain if there's anything in there, this makes the hasChanges check way simpler\n\t\t\t\tdelete this.itemChanges[itemEntry.id];\n\t\t\t}\n\t\t}\n\n\t\t// Our previous object now contains the previous values for all changes made on this transaction, or changes\n\t\t// inherited from ancestor transactions.\n\t\treturn hasProperties(\n\t\t\tprevious,\n\t\t)\n\t\t\t? previous\n\t\t\t: null;\n\t}\n\n\tprivate async fetchLocalItemEntryData<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\titemIds: ItemId[],\n\t\tcolumnsOperationsCache: RequestColumnsOperationsCache<ItemTypeType>,\n\t): Promise<ItemEntry<ItemTypeType>[]> {\n\t\tconst result: ItemEntry<ItemTypeType>[] = [];\n\t\tconst itemEntriesToExpand: ItemEntry<ItemTypeType>[] = [];\n\t\tconst requestColumnExpansion = this.requestColumnExpansionFactory.construct();\n\n\t\tfor (const itemId of itemIds) {\n\t\t\tconst itemEntry = this.entries.get(\n\t\t\t\titemType,\n\t\t\t\titemId,\n\t\t\t);\n\n\t\t\tresult.push(\n\t\t\t\titemEntry,\n\t\t\t);\n\n\t\t\tif (\n\t\t\t\tcolumnsOperationsCache.setContainsAllColumns(\n\t\t\t\t\titemEntry.columns,\n\t\t\t\t\tthis.transaction,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\titemEntriesToExpand.push(\n\t\t\t\titemEntry,\n\t\t\t);\n\n\t\t\t// TODO: Replace this once we use request column sets with column sets.\n\t\t\tconst requestColumnsTuple = {\n\t\t\t\tobject: itemEntry.columns.request,\n\t\t\t\tstring: ColumnUtil.createRequestColumnSetId(\n\t\t\t\t\titemEntry.columns.request,\n\t\t\t\t),\n\t\t\t};\n\n\t\t\trequestColumnExpansion.expandWithRequestColumnsTuple(\n\t\t\t\titemType,\n\t\t\t\tcolumnsOperationsCache\n\t\t\t\t\t.getColumnsMergedWithTuple(\n\t\t\t\t\t\trequestColumnsTuple,\n\t\t\t\t\t\tthis.transaction,\n\t\t\t\t\t)\n\t\t\t\t\t.difference,\n\t\t\t);\n\t\t}\n\n\t\tif (itemEntriesToExpand.length === 0) {\n\t\t\treturn result;\n\t\t}\n\n\t\tconst columnDifference = requestColumnExpansion.get()[itemType];\n\t\tconst responseColumnMap = await this.dependencies.columnHandler.fetch(\n\t\t\titemType,\n\t\t\tcolumnDifference,\n\t\t);\n\n\t\tawait this.expandLocalItemEntries(\n\t\t\titemType,\n\t\t\titemEntriesToExpand,\n\t\t\tcolumnDifference,\n\t\t\tresponseColumnMap,\n\t\t\ttrue,\n\t\t);\n\n\t\treturn result;\n\t}\n\n}\n","import { ApiItemType, ItemId } from '@rentman/backend-types';\nimport { ApiQuery, CachedQueryHandlerBase, CachedQueryHandlerCollectionTuple, CachedQueryItem, CachedQueryItemsItemTypeTuple, CachedQueryItemTuple, CachedQueryOptions, ChildCollectionsOption, CollectionItemResourceChanges, CollectionOptions, CollectionQuery, CollectionResource, EntryParent, GraphQueryParser, ItemEntry, ItemIdConversionMap, KeyService, LinkCollectionBatchQueryTuple, MatchesAccumulatorMap, MatchingResultsAccumulatorMapType, MatchingResultsAccumulatorTuple, ParentCachedQueryItemTuple, QueryParserIdUpdater, RequestColumnsOperationsCache, RootCollectionOptions, ServerCache, ServerCachedQueryHandler, TransactionCache, TransactionCollectionHandlerDependencyInterface } from '../../../internal';\nimport { QueryNode } from '../../matcher/QueryNode';\nimport { RootQueryNode } from '../../matcher/RootQueryNode';\n\nexport interface LinkCollectionOptionsItemTypeTuple<ItemTypeType extends ApiItemType> {\n\titemType: ItemTypeType,\n\tlinkCollectionOptions: LinkCollectionOptionsTuple<ItemTypeType>,\n}\n\ninterface CollectionQueryTuple<ItemTypeType extends ApiItemType> {\n\tparsedQuery: CollectionQuery<ItemTypeType>,\n\toptions: CollectionOptions<ItemTypeType>,\n}\n\ninterface LinkCollectionOptionsTuple<ItemTypeType extends ApiItemType>\n\textends LinkCollectionBatchQueryTuple<ItemTypeType> {\n\n\tcollectionQueryTuples: CollectionQueryTuple<ItemTypeType>[],\n}\n\ninterface TransactionCachedQueryHandlerCollectionTuple<ItemTypeType extends ApiItemType>\n\textends CachedQueryHandlerCollectionTuple<ItemTypeType> {\n\t// If we want `collectionResources` to be set always, we could override `setCachedQuery()`.\n\tcollectionResources?: WeakRef<CollectionResource<ItemTypeType, any, any>>[],\n}\n\nexport class TransactionCachedQueryHandler\n\textends CachedQueryHandlerBase {\n\n\t/**\n\t * As opposed to the server cache, where `collections` only contains cached queries, on the transaction cache\n\t * `collections` can contain collection resources as well.\n\t */\n\tprotected override collections: {\n\t\t[ItemType in ApiItemType]?: {\n\t\t\t[queryString: string]: TransactionCachedQueryHandlerCollectionTuple<ItemType> | undefined,\n\t\t}\n\t} = {};\n\n\tdeclare protected transaction: TransactionCache;\n\n\tpublic constructor (\n\t\tprotected override dependencies: TransactionCollectionHandlerDependencyInterface,\n\t\ttransaction: TransactionCache,\n\t) {\n\t\tsuper(\n\t\t\tdependencies,\n\t\t\ttransaction,\n\t\t);\n\t}\n\n\tpublic* getCollectionResources<const ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tqueryString: string,\n\t\tcleanUpStaleResources: boolean = false,\n\t): Generator<CollectionResource<ItemTypeType, any, any>> {\n\t\tconst collectionResourceRefs = this.collections[itemType]?.[queryString]?.collectionResources;\n\n\t\tif (collectionResourceRefs === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet hasStaleResources: boolean = false;\n\n\t\tfor (const collectionResourceRef of collectionResourceRefs) {\n\t\t\tconst collectionResource = collectionResourceRef.deref();\n\n\t\t\tif (collectionResource === undefined) {\n\t\t\t\thasStaleResources = true;\n\t\t\t} else {\n\t\t\t\tyield collectionResource;\n\t\t\t}\n\t\t}\n\n\t\tif (\n\t\t\tcleanUpStaleResources\n\t\t\t&& hasStaleResources\n\t\t) {\n\t\t\tthis.cleanUpQueryString(\n\t\t\t\titemType,\n\t\t\t\tqueryString,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * This method is called when constructing a collection resource. There should be no need to call it in any other\n\t * situation.\n\t */\n\tpublic addCollectionResource<CollectionResourceType extends CollectionResource<any, any, any>> (\n\t\tresource: CollectionResourceType,\n\t): CollectionResourceType {\n\t\tconst collectionTuple = this.getOrCreateCollectionTuple(\n\t\t\tresource.itemType,\n\t\t\tresource.entry.query.string,\n\t\t) as TransactionCachedQueryHandlerCollectionTuple<CollectionResourceType['itemType']>;\n\n\t\tif (collectionTuple.collectionResources === undefined) {\n\t\t\tcollectionTuple.collectionResources = [];\n\t\t}\n\n\t\tcollectionTuple.collectionResources.push(\n\t\t\tnew WeakRef(\n\t\t\t\tresource,\n\t\t\t),\n\t\t);\n\n\t\tthis.cleanUpQueryString(\n\t\t\tresource.itemType,\n\t\t\tresource.entry.query.string,\n\t\t);\n\n\t\treturn resource;\n\t}\n\n\t/**\n\t * Iterates over all collection resources that don't have an associated cached query.\n\t */\n\tpublic* getUncachedCollectionsIterator<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t): Generator<CollectionResource<ItemTypeType>> {\n\t\tconst collectionsForItemType = this.collections[itemType];\n\n\t\tif (collectionsForItemType === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const queryString in collectionsForItemType) {\n\t\t\tconst collectionTuple = collectionsForItemType[queryString]!;\n\n\t\t\tif (\n\t\t\t\t// If we have a cachedQueryItem this is not an uncached collection.\n\t\t\t\tcollectionTuple.cachedQueryItem !== undefined\n\t\t\t\t|| collectionTuple.collectionResources === undefined\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// fixme: test this\n\t\t\tyield* this.getCollectionResources(\n\t\t\t\titemType,\n\t\t\t\tqueryString,\n\t\t\t\ttrue,\n\t\t\t);\n\t\t}\n\t}\n\n\tpublic clearCollectionResource<ItemTypeType extends ApiItemType> (\n\t\tresource: CollectionResource<ItemTypeType, any, any>,\n\t): void {\n\t\tconst itemType = resource.entry.itemType;\n\t\tconst queryString = resource.entry.query.string;\n\n\t\tif (\n\t\t\t// Typescript doens't understand optional chaining undefined checks and will complain below if we do that\n\t\t\tthis.collections[itemType] === undefined\n\t\t\t|| this.collections[itemType][queryString] === undefined\n\t\t\t|| this.collections[itemType][queryString].collectionResources === undefined\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst collectionResources = this.collections[itemType][queryString].collectionResources;\n\t\tconst cleanedUpResources: WeakRef<CollectionResource<any, any, any>>[] = [];\n\n\t\t// We don't use `this.getCollectionResources` here, because we want to remove the passed resource from the array, and we\n\t\t// need the original `WeakRef`s to do that.\n\t\tfor (const collectionResourceRef of collectionResources) {\n\t\t\tconst collectionResource = collectionResourceRef.deref();\n\n\t\t\tif (\n\t\t\t\tcollectionResource !== undefined\n\t\t\t\t&& collectionResource.entry !== resource.entry\n\t\t\t) {\n\t\t\t\tcleanedUpResources.push(\n\t\t\t\t\tcollectionResourceRef,\n\t\t\t\t);\n\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tthis.collections[itemType][queryString].collectionResources = cleanedUpResources;\n\n\t\tthis.clearCollectionTupleIfEmpty(\n\t\t\titemType,\n\t\t\tqueryString,\n\t\t\ttrue,\n\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Updates all cached queries which references one of the updated IDs in the conversionMap\n\t *\n\t * @param conversionMap ConversionMap with the updated IDs\n\t */\n\tpublic updateLocalItemIdReferences (\n\t\tconversionMap: ItemIdConversionMap,\n\t): void {\n\t\tfor (const itemType in this.collections) {\n\t\t\tconst collectionsForItemType = this.collections[itemType as ApiItemType];\n\n\t\t\tfor (const queryString in collectionsForItemType) {\n\t\t\t\tconst collectionTuple = collectionsForItemType[queryString]!;\n\t\t\t\tconst cachedQueryItem = collectionTuple.cachedQueryItem as CachedQueryItem<any> | undefined;\n\n\t\t\t\tif (cachedQueryItem !== undefined) {\n\t\t\t\t\tconst didUpdate = this.updateQueryLocalItemIdReferences(\n\t\t\t\t\t\tcachedQueryItem.query,\n\t\t\t\t\t\tcachedQueryItem.queryGraph,\n\t\t\t\t\t\tconversionMap,\n\t\t\t\t\t);\n\n\t\t\t\t\tif (didUpdate) {\n\t\t\t\t\t\t// TODO: We'd want to move this code to ServerCache.applyChangesFromParent, but that function calls\n\t\t\t\t\t\t// TransactionCache.applyChangesFromParent, which does two things:\n\t\t\t\t\t\t// - Update item IDs (which we want to wait for);\n\t\t\t\t\t\t// - Run the collection matcher (which we don't want to wait for).\n\t\t\t\t\t\t// This code can be moved once that is addressed.\n\t\t\t\t\t\tconst parentCachedQueryHandler = this.transaction.parent.cachedQueryHandler;\n\n\t\t\t\t\t\tif (parentCachedQueryHandler instanceof ServerCachedQueryHandler) {\n\t\t\t\t\t\t\tparentCachedQueryHandler.cloneCachedQuery(\n\t\t\t\t\t\t\t\tcachedQueryItem,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Check whether we need to store the cached query under the updated query string. We cannot rely on\n\t\t\t\t\t// `didUpdate` here, since the collection query could have been updated on a parent transaction already.\n\t\t\t\t\tif (cachedQueryItem.query.string !== queryString) {\n\t\t\t\t\t\tcollectionsForItemType[cachedQueryItem.query.string] = collectionsForItemType[queryString];\n\n\t\t\t\t\t\tdelete collectionsForItemType[queryString];\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst collectionResourcesIterator = this.getCollectionResourcesByTuple<any>(\n\t\t\t\t\tcollectionTuple,\n\t\t\t\t);\n\n\t\t\t\tfor (const collectionResource of collectionResourcesIterator) {\n\t\t\t\t\t// If the collection resource uses the same collection query object as the cached query, it\n\t\t\t\t\t// will be updated already.\n\t\t\t\t\tconst didUpdate = (\n\t\t\t\t\t\tcachedQueryItem !== undefined\n\t\t\t\t\t\t&& collectionResource.entry.query === cachedQueryItem.query\n\t\t\t\t\t)\n\t\t\t\t\t\t? cachedQueryItem.query.string !== queryString\n\t\t\t\t\t\t: this.updateQueryLocalItemIdReferences(\n\t\t\t\t\t\t\tcollectionResource.entry.query,\n\t\t\t\t\t\t\tcollectionResource.queryGraph,\n\t\t\t\t\t\t\tconversionMap,\n\t\t\t\t\t\t);\n\n\t\t\t\t\tif (didUpdate) {\n\t\t\t\t\t\tconst parent = collectionResource.entry.parent;\n\n\t\t\t\t\t\tif (parent !== null) {\n\t\t\t\t\t\t\tconst newParentId = conversionMap[parent.itemType]?.[parent.itemId];\n\n\t\t\t\t\t\t\tif (newParentId !== undefined) {\n\t\t\t\t\t\t\t\t// The {@link EntryParentNull} type has read-only properties to increase type safety when\n\t\t\t\t\t\t\t\t// using it as a function argument.\n\t\t\t\t\t\t\t\tcollectionResource.entry.parent = {\n\t\t\t\t\t\t\t\t\titemType: parent.itemType,\n\t\t\t\t\t\t\t\t\titemId: newParentId,\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (cachedQueryItem === undefined) {\n\t\t\t\t\t\t\t// When there's no cachedQueryItem the query/collection has not been re-cached under the new query string yet\n\t\t\t\t\t\t\t// so we have to do it here.\n\n\t\t\t\t\t\t\tcollectionsForItemType[collectionResource.entry.query.string] = collectionsForItemType[queryString];\n\t\t\t\t\t\t\tdelete collectionsForItemType[queryString];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic __maybeExpandCachedQuery<const ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tqueryString: string,\n\t\tcolumnsOperationsCache: RequestColumnsOperationsCache<ItemTypeType>,\n\t\tbatchedLinkedToQuery?: CollectionQuery<ItemTypeType>,\n\t): Promise<CachedQueryItem<ItemTypeType>> {\n\t\tconst cachedQuery = this.getCachedQueryItem(\n\t\t\titemType,\n\t\t\tqueryString,\n\t\t);\n\n\t\tif (cachedQuery === undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t`TransactionCachedQueryHandler: tried to expand non-existing query: ${itemType} - ${queryString}`,\n\t\t\t);\n\t\t}\n\n\t\tif (\n\t\t\tcolumnsOperationsCache.tupleContainsAllColumns(\n\t\t\t\tcachedQuery.requestColumnsTuple,\n\t\t\t\tthis.transaction,\n\t\t\t)\n\t\t\t// In order to keep aggregated columns always in sync, we refetch them every time they are requested.\n\t\t\t&& (\n\t\t\t\t!cachedQuery.itemsResolved()\n\t\t\t\t|| !columnsOperationsCache.hasAggregateColumns()\n\t\t\t)\n\t\t) {\n\t\t\t// We have the columns, but it can be that the entries aren't fetched yet, so we're waiting on those.\n\t\t\treturn cachedQuery.promise;\n\t\t}\n\n\t\tif (\n\t\t\t// Do instance check first.\n\t\t\tthis.transaction.parent instanceof ServerCache\n\t\t\t&& this.dependencies.queryService.containsLocalId(\n\t\t\t\tcachedQuery.query.object,\n\t\t\t)\n\t\t) {\n\t\t\t// This function already checks the column difference.\n\t\t\treturn this.mergeColumnsAndExpandLocalItems(\n\t\t\t\tcachedQuery,\n\t\t\t\tcolumnsOperationsCache,\n\t\t\t);\n\t\t}\n\n\t\t// We should just ask the parent for a item with the new columns. Multiple requests should be aggregated,\n\t\t// and the resolved cached query item should have a column superset.\n\t\treturn this.transaction.parent.cachedQueryHandler\n\t\t\t.__maybeExpandCachedQuery(\n\t\t\t\titemType,\n\t\t\t\tqueryString,\n\t\t\t\tcolumnsOperationsCache,\n\t\t\t\tbatchedLinkedToQuery,\n\t\t\t)\n\t\t\t.then(\n\t\t\t\t() => this.mergeColumnsAndExpandLocalItems(\n\t\t\t\t\tcachedQuery,\n\t\t\t\t\tcolumnsOperationsCache,\n\t\t\t\t),\n\t\t\t);\n\t}\n\n\t// renamed from fetchCollectionData\n\tpublic __fetchItemEntriesByQueryData<const ItemTypeType extends ApiItemType> (\n\t\t// changesDelta: ChangesDelta,\n\t\titemType: ItemTypeType,\n\t\toptions: CachedQueryOptions<ItemTypeType>,\n\t\tcolumnsOperationsCache: RequestColumnsOperationsCache<ItemTypeType>,\n\t\tcollectionQuery: CollectionQuery<ItemTypeType>,\n\t\tlinkCollectionBatchQueryTuple?: LinkCollectionBatchQueryTuple<ItemTypeType>,\n\t): Promise<CachedQueryItem<ItemTypeType>> {\n\t\tif (\n\t\t\t!this.queryIsCacheable(\n\t\t\t\toptions,\n\t\t\t\tcollectionQuery,\n\t\t\t)\n\t\t) {\n\t\t\t// When we have a limit the ServerCache always makes a new fake cachedQueryItem\n\t\t\treturn this.transaction.parent.cachedQueryHandler\n\t\t\t\t.__fetchItemEntriesByQueryData(\n\t\t\t\t\titemType,\n\t\t\t\t\toptions,\n\t\t\t\t\tcolumnsOperationsCache,\n\t\t\t\t\tcollectionQuery,\n\t\t\t\t\tlinkCollectionBatchQueryTuple,\n\t\t\t\t)\n\t\t\t\t.then(\n\t\t\t\t\t// In this case, calling `resolve` on the cached query item itself isn't strictly necessary.\n\t\t\t\t\tparentCachedQueryItem => this.resolveLocalCachedQueryItem(\n\t\t\t\t\t\tparentCachedQueryItem,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t}\n\n\t\tconst cachedQuery = this.getCachedQueryItem(\n\t\t\titemType,\n\t\t\tcollectionQuery.string,\n\t\t);\n\n\t\tif (cachedQuery !== undefined) {\n\t\t\tif (!cachedQuery.isOutdated()) {\n\t\t\t\treturn this.__maybeExpandCachedQuery(\n\t\t\t\t\titemType,\n\t\t\t\t\tcollectionQuery.string,\n\t\t\t\t\tcolumnsOperationsCache,\n\t\t\t\t\tlinkCollectionBatchQueryTuple?.batchQuery,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Since we're going to re-fetch the data and then sync the cached query, we can immediately mark it as up-to-date\n\t\t\t// If we don't do this, we might end up re-fetching this data multiple times while the request is still pending\n\t\t\tcachedQuery.markUpToDate();\n\t\t}\n\n\t\t// 1. Ask the parent if this collection is cached (Local queries should never go to the ServerCache)\n\t\tif (\n\t\t\t// Do instance check first.\n\t\t\tthis.transaction.parent instanceof ServerCache\n\t\t\t&& this.isLocal(\n\t\t\t\toptions,\n\t\t\t\tcollectionQuery.object,\n\t\t\t)\n\t\t) {\n\t\t\treturn this.resolveLocalCachedQueryItem(\n\t\t\t\tcachedQuery ?? this.setCachedQuery(\n\t\t\t\t\titemType,\n\t\t\t\t\tcollectionQuery,\n\t\t\t\t\tcolumnsOperationsCache.getRequestColumnsTuple(\n\t\t\t\t\t\tthis.transaction,\n\t\t\t\t\t),\n\t\t\t\t\t[],\n\t\t\t\t\tlinkCollectionBatchQueryTuple?.batchQueryGraph,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\t// 2. Store a copy of the CachedQueryItem on this transaction\n\t\treturn this.transaction.parent.cachedQueryHandler\n\t\t\t.__fetchItemEntriesByQueryData(\n\t\t\t\titemType,\n\t\t\t\toptions,\n\t\t\t\tcolumnsOperationsCache,\n\t\t\t\tcollectionQuery,\n\t\t\t\tlinkCollectionBatchQueryTuple,\n\t\t\t)\n\t\t\t.then(\n\t\t\t\tparentCachedQueryItem => {\n\t\t\t\t\tconst createdCachedQueryItem = this.getCachedQueryItem(\n\t\t\t\t\t\titemType,\n\t\t\t\t\t\tcollectionQuery.string,\n\t\t\t\t\t);\n\n\t\t\t\t\t// It could be that another cached query item has been created in the mean time.\n\t\t\t\t\t// We've chosen not to create a local item beforehand, because in the case of multiple calls to\n\t\t\t\t\t// the parent, we want to return the item that resolves first.\n\t\t\t\t\tif (createdCachedQueryItem !== undefined) {\n\t\t\t\t\t\treturn this.mergeColumnsAndExpandLocalItems(\n\t\t\t\t\t\t\tcreatedCachedQueryItem,\n\t\t\t\t\t\t\tcolumnsOperationsCache,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn this.resolveLocalCachedQueryItem(\n\t\t\t\t\t\tthis.cloneCachedQuery(\n\t\t\t\t\t\t\tparentCachedQueryItem,\n\t\t\t\t\t\t\tfalse,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t);\n\t}\n\n\t/**\n\t * @remark\n\t * todo not only linkedTo should be checked, but it should check if there's a local ID anywhere in the query\n\t * ({<field>: <localId>}) is also a local query\n\t */\n\tpublic isLocal<ItemTypeType extends ApiItemType> (\n\t\toptions: {\n\t\t\tparent?: EntryParent,\n\t\t},\n\t\tquery: ApiQuery<ItemTypeType>,\n\t): boolean {\n\t\tif (options.parent === undefined) {\n\t\t\treturn this.dependencies.queryService.containsLocalId(\n\t\t\t\tquery,\n\t\t\t);\n\t\t}\n\n\t\treturn KeyService.isLocalId(\n\t\t\toptions.parent.itemId,\n\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Fetches collections linked to the passed parents\n\t * @returns An array of cached query items. The items are in the same order as the parent IDs.\n\t */\n\tpublic async __fetchLinkedCachedQueryItems<const ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tlinkCollectionOptionsTuple: LinkCollectionOptionsTuple<ItemTypeType>,\n\t): Promise<CachedQueryItemTuple<ItemTypeType>[]> {\n\t\tconst collectionQueryTuples = linkCollectionOptionsTuple.collectionQueryTuples;\n\n\t\tif (collectionQueryTuples.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst columnsOperationsCache = this.dependencies.requestColumnsOperationsCacheFactory.construct(\n\t\t\titemType,\n\t\t\tcollectionQueryTuples[0].options.columns,\n\t\t);\n\n\t\tconst cachedQueryItems = await Promise.all(\n\t\t\tcollectionQueryTuples.map(\n\t\t\t\tcollectionQueryTuple => this.__fetchItemEntriesByQueryData(\n\t\t\t\t\titemType,\n\t\t\t\t\tcollectionQueryTuple.options,\n\t\t\t\t\tcolumnsOperationsCache,\n\t\t\t\t\tcollectionQueryTuple.parsedQuery,\n\t\t\t\t\tlinkCollectionOptionsTuple,\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\n\t\tconst result: CachedQueryItemTuple<ItemTypeType>[] = [];\n\n\t\tfor (let i = 0; i < collectionQueryTuples.length; i++) {\n\t\t\tresult.push(\n\t\t\t\t{\n\t\t\t\t\tcachedQueryItem: cachedQueryItems[i],\n\t\t\t\t\toptions: collectionQueryTuples[i].options,\n\t\t\t\t\tchildren: null,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic createBatchLinkedToQuery<ItemTypeType extends ApiItemType> (\n\t\tparentItemType: ApiItemType,\n\t\tparentItemIds: ItemId[],\n\t\tadditionalQuery?: ApiQuery<ItemTypeType>,\n\t): CollectionQuery<ItemTypeType> {\n\t\tlet batchQuery: ApiQuery<ItemTypeType> = {\n\t\t\tconditions: [\n\t\t\t\t{\n\t\t\t\t\tlinkedTo: parentItemType,\n\t\t\t\t\tquery: {\n\t\t\t\t\t\tid: parentItemIds,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t};\n\n\t\tif (additionalQuery !== undefined) {\n\t\t\tbatchQuery = this.dependencies.queryService.addAndCondition(\n\t\t\t\tbatchQuery,\n\t\t\t\tadditionalQuery,\n\t\t\t);\n\t\t}\n\n\t\treturn this.createQuery(\n\t\t\tbatchQuery,\n\t\t);\n\t}\n\n\t/**\n\t * The order of the `collectionQueryTuples` property of the result will be the same as the order of\n\t * `parentItemIds`.\n\t */\n\tpublic processLinkCollectionOptions<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tparentItemType: ApiItemType,\n\t\tparentItemIds: ItemId[],\n\t\toptions: CollectionOptions<ItemTypeType>,\n\t): LinkCollectionOptionsTuple<ItemTypeType> {\n\t\tif (parentItemIds.length === 0) {\n\t\t\tthrow new Error(\n\t\t\t\t'Expected `parentItemIds` to have at least one element',\n\t\t\t);\n\t\t}\n\n\t\tconst collectionQueryTuples: CollectionQueryTuple<ItemTypeType>[] = [];\n\t\tconst leafNodeTuples: {\n\t\t\tvalue: ItemId,\n\t\t\tnode: CollectionQuery<ItemTypeType>,\n\t\t}[] = [];\n\n\t\tlet firstOptions: CollectionOptions<ItemTypeType> | undefined;\n\n\t\tfor (const parentItemId of parentItemIds) {\n\t\t\tlet clonedOptions: CollectionOptions<ItemTypeType>;\n\t\t\tlet parsedQuery: CollectionQuery<ItemTypeType>;\n\n\t\t\tif (firstOptions === undefined) {\n\t\t\t\tclonedOptions = this.cloneOptions(\n\t\t\t\t\toptions,\n\t\t\t\t\t{\n\t\t\t\t\t\titemType: parentItemType,\n\t\t\t\t\t\titemId: parentItemId,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tparsedQuery = this.createQueryFromOptions<ItemTypeType>(\n\t\t\t\t\tclonedOptions,\n\t\t\t\t);\n\n\t\t\t\t// The columns will be the same for all sibling cached queries (only the parent is different).\n\t\t\t\tthis.expandColumnsWithQueryColumns(\n\t\t\t\t\titemType,\n\t\t\t\t\tclonedOptions,\n\t\t\t\t\tparsedQuery.object,\n\t\t\t\t);\n\n\t\t\t\tfirstOptions = clonedOptions;\n\t\t\t} else {\n\t\t\t\tclonedOptions = this.cloneOptions(\n\t\t\t\t\tfirstOptions,\n\t\t\t\t\t{\n\t\t\t\t\t\titemType: parentItemType,\n\t\t\t\t\t\titemId: parentItemId,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tparsedQuery = this.createQueryFromOptions<ItemTypeType>(\n\t\t\t\t\tclonedOptions,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tcollectionQueryTuples.push(\n\t\t\t\t{\n\t\t\t\t\toptions: clonedOptions,\n\t\t\t\t\tparsedQuery: parsedQuery,\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tleafNodeTuples.push(\n\t\t\t\t{\n\t\t\t\t\tvalue: parentItemId,\n\t\t\t\t\tnode: parsedQuery,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\tconst additionalQueryGraph = firstOptions!.query === undefined\n\t\t\t? new RootQueryNode<ItemTypeType>()\n\t\t\t: this.dependencies.graphQueryParserFactory.construct(\n\t\t\t\titemType,\n\t\t\t\tleafNodeTuples[0].node,\n\t\t\t)\n\t\t\t\t.run(\n\t\t\t\t\tfirstOptions!.query,\n\t\t\t\t);\n\n\t\treturn {\n\t\t\tcollectionQueryTuples,\n\t\t\tbatchQuery: this.createBatchLinkedToQuery(\n\t\t\t\tparentItemType,\n\t\t\t\tparentItemIds,\n\t\t\t\toptions.query,\n\t\t\t),\n\t\t\t/**\n\t\t\t * The batch query graph is the query graph equivalent of the batch query. I.E. it should match all child\n\t\t\t * items of `parentItemIds`. We're creating the query graph by taking the additional query graph (the graph\n\t\t\t * created using the `query` property in the collection options) and replacing the leaf nodes with a\n\t\t\t * comparator node for the link field of the child items.\n\t\t\t */\n\t\t\tbatchQueryGraph: additionalQueryGraph.clone(\n\t\t\t\tleafNodeTuple => {\n\t\t\t\t\tleafNodeTuple.leafNodes = [];\n\n\t\t\t\t\tQueryNode.addBranchNode(\n\t\t\t\t\t\tleafNodeTuple,\n\t\t\t\t\t\tGraphQueryParser.createLinkedToComparatorQueryNode(\n\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n\t\t\t\t\t\t\titemType as ApiItemType,\n\t\t\t\t\t\t\tparentItemType,\n\t\t\t\t\t\t\tleafNodeTuples,\n\t\t\t\t\t\t\tthis.dependencies.linkTreeService,\n\t\t\t\t\t\t\tthis.dependencies.errorHandler,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t),\n\t\t};\n\t}\n\n\tpublic __fetchParentCachedQueryItem<const ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\toptions: CollectionOptions<ItemTypeType>,\n\t): Promise<ParentCachedQueryItemTuple<ItemTypeType>> {\n\t\tconst parsedQuery = this.createQueryFromOptions(\n\t\t\toptions,\n\t\t);\n\n\t\tthis.expandColumnsWithQueryColumns(\n\t\t\titemType,\n\t\t\toptions,\n\t\t\tparsedQuery.object,\n\t\t);\n\n\t\treturn this.__fetchParentItemEntriesByQueryData(\n\t\t\titemType,\n\t\t\toptions,\n\t\t\tthis.dependencies.requestColumnsOperationsCacheFactory.construct(\n\t\t\t\titemType,\n\t\t\t\toptions.columns,\n\t\t\t),\n\t\t\tparsedQuery,\n\t\t);\n\t}\n\n\tpublic __fetchChildCachedQueryItems (\n\t\tparentItemType: ApiItemType,\n\t\tparentItemIds: ItemId[],\n\t\tchildCollectionOptions: ChildCollectionsOption,\n\t): Promise<CachedQueryItemsItemTypeTuple<ApiItemType>[]> {\n\t\tif (parentItemIds.length === 0) {\n\t\t\treturn Promise.resolve(\n\t\t\t\t[],\n\t\t\t);\n\t\t}\n\n\t\tconst childLinkCollectionOptionsItemTypeTuples: LinkCollectionOptionsItemTypeTuple<ApiItemType>[] = [];\n\n\t\tfor (const childItemType in childCollectionOptions) {\n\t\t\t// Because there is a lot of overlap between the child collections, we generate the collection options, parsed\n\t\t\t// queries and batch queries beforehand.\n\t\t\tchildLinkCollectionOptionsItemTypeTuples.push(\n\t\t\t\t{\n\t\t\t\t\titemType: childItemType as ApiItemType,\n\t\t\t\t\tlinkCollectionOptions: this.processLinkCollectionOptions<any>(\n\t\t\t\t\t\tchildItemType as ApiItemType,\n\t\t\t\t\t\tparentItemType,\n\t\t\t\t\t\tparentItemIds,\n\t\t\t\t\t\tchildCollectionOptions[childItemType as ApiItemType]!,\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\treturn this.fetchChildCachedQueryItems(\n\t\t\tchildLinkCollectionOptionsItemTypeTuples,\n\t\t);\n\t}\n\n\t/**\n\t * Fetches a cached query, respecting children. Like {@link __fetchItemEntriesByQueryData}, assumes the options are\n\t * processed already.\n\t *\n\t * todo: Rename this method and {@link __fetchItemEntriesByQueryData} to something that's easier to understand.\n\t */\n\tpublic async __fetchParentItemEntriesByQueryData<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\toptions: CollectionOptions<ItemTypeType>,\n\t\tcolumnsOperationsCache: RequestColumnsOperationsCache<ItemTypeType>,\n\t\tcollectionQuery: CollectionQuery<ItemTypeType>,\n\t): Promise<ParentCachedQueryItemTuple<ItemTypeType>> {\n\t\tconst cachedQueryItem = await this.__fetchItemEntriesByQueryData(\n\t\t\titemType,\n\t\t\toptions,\n\t\t\tcolumnsOperationsCache,\n\t\t\tcollectionQuery,\n\t\t);\n\n\t\tconst resolvedCachedQueryItems = await this.resolveParentCachedQueryItems(\n\t\t\titemType,\n\t\t\t[\n\t\t\t\t{\n\t\t\t\t\tcachedQueryItem,\n\t\t\t\t\toptions,\n\t\t\t\t\tchildren: null,\n\t\t\t\t},\n\t\t\t],\n\t\t);\n\n\t\treturn resolvedCachedQueryItems.cachedQueryItemTuples[0];\n\t}\n\n\t// no need to worry about the columns property, it will be replaced in when columns are expanded\n\tprivate cloneOptions<OptionsType extends CollectionOptions<any>> (\n\t\toptions: OptionsType,\n\t\tparent?: EntryParent,\n\t): OptionsType {\n\t\tconst result = {\n\t\t\t...options,\n\t\t};\n\n\t\tif (parent !== undefined) {\n\t\t\tresult.parent = parent;\n\t\t}\n\n\t\tconst children = options.children;\n\n\t\tif (children !== undefined) {\n\t\t\tconst childrenClone: RootCollectionOptions<any>['children'] = {};\n\n\t\t\tfor (const itemType in children) {\n\t\t\t\tchildrenClone[itemType] = this.cloneOptions(\n\t\t\t\t\tchildren[itemType as ApiItemType]!,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tresult.children = childrenClone;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic async fetchChildCachedQueryItems (\n\t\tlinkCollectionOptionsItemTypeTuples: LinkCollectionOptionsItemTypeTuple<ApiItemType>[],\n\t): Promise<CachedQueryItemsItemTypeTuple<ApiItemType>[]> {\n\t\tconst cachedQueryItemOptionsTuples = await Promise.all(\n\t\t\tlinkCollectionOptionsItemTypeTuples.map(\n\t\t\t\ttuple => this.__fetchLinkedCachedQueryItems(\n\t\t\t\t\ttuple.itemType,\n\t\t\t\t\ttuple.linkCollectionOptions,\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\n\t\tconst promises: Promise<CachedQueryItemsItemTypeTuple<ApiItemType>>[] = [];\n\n\t\tfor (let i = 0; i < linkCollectionOptionsItemTypeTuples.length; i++) {\n\t\t\tpromises.push(\n\t\t\t\tthis.resolveParentCachedQueryItems(\n\t\t\t\t\tlinkCollectionOptionsItemTypeTuples[i].itemType,\n\t\t\t\t\tcachedQueryItemOptionsTuples[i],\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\treturn Promise.all(\n\t\t\tpromises,\n\t\t);\n\t}\n\n\t/**\n\t * Updates the items included in cached queries and collection resources based on query matcher results. Note that\n\t * method does not clear child collection resources of removed item resources.\n\t */\n\tpublic applyMatchingResultsToCollections (\n\t\tmatchingResultsAccumulatorMap: MatchesAccumulatorMap<MatchingResultsAccumulatorMapType>,\n\t): Promise<CollectionItemResourceChanges<any>[]> {\n\t\tconst promiseAccumulator: Promise<CollectionItemResourceChanges<CollectionResource<any, any, any>>>[] = [];\n\n\t\tfor (const matchingResultsMapEntry of matchingResultsAccumulatorMap) {\n\t\t\tconst itemType = matchingResultsMapEntry[0];\n\n\t\t\tfor (const matchingResultsEntry of matchingResultsMapEntry[1].entries()) {\n\t\t\t\tconst collectionTuple = this.collections[itemType]?.[matchingResultsEntry[0]];\n\n\t\t\t\tif (collectionTuple === undefined) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst cachedQueryItem = collectionTuple.cachedQueryItem;\n\t\t\t\tconst matchingResultsTuple = matchingResultsEntry[1] as MatchingResultsAccumulatorTuple<any>;\n\n\t\t\t\tif (cachedQueryItem !== undefined) {\n\t\t\t\t\tcachedQueryItem.handleMatchedItemEntries(\n\t\t\t\t\t\tmatchingResultsTuple.true,\n\t\t\t\t\t\tmatchingResultsTuple.false,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tconst collectionResources = this.getCollectionResources(\n\t\t\t\t\titemType,\n\t\t\t\t\tmatchingResultsEntry[0],\n\t\t\t\t\ttrue,\n\t\t\t\t);\n\n\t\t\t\tfor (const collectionResource of collectionResources) {\n\t\t\t\t\tpromiseAccumulator.push(\n\t\t\t\t\t\tcollectionResource.handleMatchedItemEntries(\n\t\t\t\t\t\t\tmatchingResultsTuple.true,\n\t\t\t\t\t\t\tmatchingResultsTuple.false,\n\t\t\t\t\t\t\tfalse,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn Promise.all(\n\t\t\tpromiseAccumulator,\n\t\t);\n\t}\n\n\tprotected override clearCollectionTupleIfEmpty<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tqueryString: string,\n\t\tdidAlreadyClearResourceRefs: boolean = false,\n\t): void {\n\t\tconst collectionsForItemType = this.collections[itemType]!;\n\t\tconst collectionTuple = collectionsForItemType[queryString];\n\n\t\tif (collectionTuple === undefined) {\n\t\t\tthis.dependencies.errorHandler.logError(\n\t\t\t\tnew Error(\n\t\t\t\t\t`TransactionCachedQueryHandler::clearCollectionTupleIfEmpty, tried to check for empty tuple with tuple not present in cache: ${itemType} - ${queryString}`,\n\t\t\t\t),\n\t\t\t);\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Somethis we call this function after already having cleanup the collectionResource refs, but in case we haven't, we should\n\t\t// clear them so our length check is correct.\n\t\tif (!didAlreadyClearResourceRefs) {\n\t\t\tthis.cleanUpQueryString(\n\t\t\t\titemType,\n\t\t\t\tqueryString,\n\t\t\t);\n\t\t}\n\n\t\tif (\n\t\t\tcollectionTuple.cachedQueryItem === undefined\n\t\t\t&& (\n\t\t\t\tcollectionTuple.collectionResources === undefined\n\t\t\t\t|| collectionTuple.collectionResources.length === 0\n\t\t\t)\n\t\t) {\n\t\t\tdelete collectionsForItemType[queryString];\n\t\t}\n\t}\n\n\tprotected override getQueryGraphsForItemType<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t): Set<RootQueryNode<ItemTypeType>> {\n\t\tconst collectionsForItemType = this.collections[itemType];\n\t\tconst result: Set<RootQueryNode<ItemTypeType>> = new Set();\n\n\t\tif (collectionsForItemType === undefined) {\n\t\t\treturn result;\n\t\t}\n\n\t\tfor (const queryString in collectionsForItemType) {\n\t\t\tconst collectionTuple = collectionsForItemType[queryString]!;\n\n\t\t\tif (collectionTuple.cachedQueryItem !== undefined) {\n\t\t\t\tresult.add(\n\t\t\t\t\tcollectionTuple.cachedQueryItem.queryGraph,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst collectionResources = this.getCollectionResources(\n\t\t\t\titemType,\n\t\t\t\tqueryString,\n\t\t\t\ttrue,\n\t\t\t);\n\n\t\t\tif (collectionTuple.collectionResources !== undefined) {\n\t\t\t\tfor (const collectionResource of collectionResources) {\n\t\t\t\t\tresult.add(\n\t\t\t\t\t\tcollectionResource.queryGraph,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprotected override getCollectionQueries<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tqueryString: string,\n\t): Set<CollectionQuery<ItemTypeType>> {\n\t\tconst collectionTuple = this.collections[itemType]?.[queryString];\n\n\t\tif (collectionTuple === undefined) {\n\t\t\treturn new Set();\n\t\t}\n\n\t\tconst result: Set<CollectionQuery<ItemTypeType>> = new Set();\n\n\t\tif (collectionTuple.cachedQueryItem !== undefined) {\n\t\t\tresult.add(\n\t\t\t\tcollectionTuple.cachedQueryItem.query,\n\t\t\t);\n\t\t}\n\n\t\tlet shouldCleanUp: boolean = false;\n\n\t\tif (collectionTuple.collectionResources !== undefined) {\n\t\t\tfor (const collectionResourceRef of collectionTuple.collectionResources) {\n\t\t\t\tconst collectionResource = collectionResourceRef.deref();\n\n\t\t\t\tif (collectionResource === undefined) {\n\t\t\t\t\tshouldCleanUp = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tresult.add(\n\t\t\t\t\tcollectionResource.entry.query,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (shouldCleanUp) {\n\t\t\tthis.cleanUpQueryString(\n\t\t\t\titemType,\n\t\t\t\tqueryString,\n\t\t\t);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate* getCollectionResourcesByTuple<ItemTypeType extends ApiItemType> (\n\t\ttuple: TransactionCachedQueryHandlerCollectionTuple<ItemTypeType>,\n\t): Generator<CollectionResource<ItemTypeType, any, any>> {\n\t\tconst collectionResources = tuple.collectionResources;\n\n\t\tif (collectionResources === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const collectionResourceRef of collectionResources) {\n\t\t\tconst collectionResource = collectionResourceRef.deref();\n\n\t\t\tif (collectionResource !== undefined) {\n\t\t\t\tyield collectionResource;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate updateQueryLocalItemIdReferences<ItemTypeType extends ApiItemType> (\n\t\tquery: CollectionQuery<ItemTypeType>,\n\t\tqueryGraph: RootQueryNode<ItemTypeType>,\n\t\tconversionMap: ItemIdConversionMap,\n\t): boolean {\n\t\t// Don't need to check queries that contain all items\n\t\tif (query.string === '{}') {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (\n\t\t\t!new QueryParserIdUpdater(\n\t\t\t\tconversionMap,\n\t\t\t)\n\t\t\t\t.run(\n\t\t\t\t\tquery.object,\n\t\t\t\t)\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// create new query with remote link ID\n\t\tconst updatedQuery = this.createQuery(\n\t\t\tquery.object,\n\t\t);\n\n\t\tquery.string = updatedQuery.string;\n\t\tquery.object = updatedQuery.object;\n\n\t\tqueryGraph.updateLocalItemIdReferences(\n\t\t\tconversionMap,\n\t\t);\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Sets the `children` property for each of the cached queries in `cachedQueryItemTuples`. Assumes the `children`\n\t * *options* property is the same for all cached query items.\n\t *\n\t * The `children` property will remain `null` if the children option is unset.\n\t */\n\tprivate async resolveParentCachedQueryItems<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tcachedQueryItemTuples: CachedQueryItemTuple<ItemTypeType>[],\n\t): Promise<CachedQueryItemsItemTypeTuple<ItemTypeType>> {\n\t\tif (cachedQueryItemTuples.length === 0) {\n\t\t\treturn {\n\t\t\t\titemType,\n\t\t\t\tcachedQueryItemTuples,\n\t\t\t};\n\t\t}\n\n\t\tconst childCollectionOptions = cachedQueryItemTuples[0].options.children;\n\n\t\tif (childCollectionOptions === null) {\n\t\t\treturn {\n\t\t\t\titemType,\n\t\t\t\tcachedQueryItemTuples,\n\t\t\t};\n\t\t}\n\n\t\t// Concatenate all the item IDs across the next generation, so all child collections can be fetched using a\n\t\t// single batch query.\n\t\t// TODO: Instead of concatenating item IDs, we could use a subquery. We should probably phase out\n\t\t// getLinkCollections first, so only one batch query type is used.\n\t\tconst generationItemIds = cachedQueryItemTuples.map(\n\t\t\tcachedQueryItemTuple => cachedQueryItemTuple.cachedQueryItem.items.map(\n\t\t\t\titemEntry => itemEntry.itemId,\n\t\t\t),\n\t\t);\n\t\tconst generationItemIdsFlat = generationItemIds.flat();\n\n\t\tif (generationItemIdsFlat.length === 0) {\n\t\t\treturn {\n\t\t\t\titemType,\n\t\t\t\tcachedQueryItemTuples,\n\t\t\t};\n\t\t}\n\n\t\tconst childLinkCollectionOptionsItemTypeTuples: LinkCollectionOptionsItemTypeTuple<ApiItemType>[] = [];\n\n\t\tfor (const childItemType in childCollectionOptions) {\n\t\t\t// Because there is a lot of overlap between the child collections, we generate the collection options, parsed\n\t\t\t// queries and batch queries beforehand.\n\t\t\tchildLinkCollectionOptionsItemTypeTuples.push(\n\t\t\t\t{\n\t\t\t\t\titemType: childItemType as ApiItemType,\n\t\t\t\t\tlinkCollectionOptions: this.processLinkCollectionOptions<any>(\n\t\t\t\t\t\tchildItemType as ApiItemType,\n\t\t\t\t\t\titemType,\n\t\t\t\t\t\tgenerationItemIdsFlat,\n\t\t\t\t\t\tchildCollectionOptions[childItemType as ApiItemType]!,\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\tconst childCachedQueryItemsItemTypeTuples = await this.fetchChildCachedQueryItems(\n\t\t\tchildLinkCollectionOptionsItemTypeTuples,\n\t\t);\n\n\t\tfor (const cachedQueryItemTuple of cachedQueryItemTuples) {\n\t\t\t(cachedQueryItemTuple as ParentCachedQueryItemTuple<ItemTypeType>).children = [];\n\t\t}\n\n\t\tfor (const childCachedQueryItemsItemTypeTuple of childCachedQueryItemsItemTypeTuples) {\n\t\t\tconst childItemType = childCachedQueryItemsItemTypeTuple.itemType;\n\t\t\tconst childCachedQueryItemTypeTuples = childCachedQueryItemsItemTypeTuple.cachedQueryItemTuples;\n\n\t\t\t// `generationItemIds` contains an array of item IDs for each cached query in `cachedQueryItemTuples`.\n\t\t\t// We're reading from `generationItemIds` rather than the item entries in the cached query, because,\n\t\t\t// in theory, items could have been added or removed while retrieving the child cached queries.\n\t\t\t// As the `childCachedQueryItemTypeTuples` are in the same order as the\n\t\t\t// `childLinkCollectionOptionsItemTypeTuples`, and the `childLinkCollectionOptionsItemTypeTuples` are in the\n\t\t\t// same order as the item IDs in `generationItemIds`, we can extract the child queries for each cached query\n\t\t\t// item using a `slice()`.\n\t\t\t// This behavior is tested in `child_collections.test.ts`.\n\t\t\tlet childCachedQueryItemTypeTuplesIndex = 0;\n\n\t\t\tfor (let i = 0; i < cachedQueryItemTuples.length; i++) {\n\t\t\t\tconst numItemEntries = generationItemIds[i].length;\n\n\t\t\t\t(cachedQueryItemTuples[i] as ParentCachedQueryItemTuple<ItemTypeType>).children!.push(\n\t\t\t\t\t{\n\t\t\t\t\t\titemType: childItemType,\n\t\t\t\t\t\tcachedQueryItemTuples: childCachedQueryItemTypeTuples.slice(\n\t\t\t\t\t\t\tchildCachedQueryItemTypeTuplesIndex,\n\t\t\t\t\t\t\tchildCachedQueryItemTypeTuplesIndex + numItemEntries,\n\t\t\t\t\t\t),\n\t\t\t\t\t},\n\t\t\t\t);\n\n\t\t\t\tchildCachedQueryItemTypeTuplesIndex += numItemEntries;\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\titemType,\n\t\t\tcachedQueryItemTuples,\n\t\t};\n\t}\n\n\tprivate resolveLocalCachedQueryItem<ItemTypeType extends ApiItemType> (\n\t\tlocalCachedQueryItem: CachedQueryItem<ItemTypeType>,\n\t): Promise<CachedQueryItem<ItemTypeType>> {\n\t\treturn this\n\t\t\t.syncCachedQueryWithLocalItems(\n\t\t\t\tlocalCachedQueryItem,\n\t\t\t)\n\t\t\t.then(\n\t\t\t\t() => {\n\t\t\t\t\tlocalCachedQueryItem.resolve();\n\n\t\t\t\t\treturn localCachedQueryItem;\n\t\t\t\t},\n\t\t\t\terror => {\n\t\t\t\t\t// localCachedQueryItem can be undefined when the column or item fetching fails\n\t\t\t\t\tif (localCachedQueryItem !== undefined) {\n\t\t\t\t\t\tlocalCachedQueryItem.reject(\n\t\t\t\t\t\t\terror,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tthrow error;\n\t\t\t\t},\n\t\t\t);\n\t}\n\n\tprivate async mergeColumnsAndExpandLocalItems<ItemTypeType extends ApiItemType> (\n\t\tlocalCachedQueryItem: CachedQueryItem<ItemTypeType>,\n\t\tcolumnsOperationsCache: RequestColumnsOperationsCache<ItemTypeType>,\n\t): Promise<CachedQueryItem> {\n\t\t// Local items might not have been added yet, and additional columns might be added while we're waiting.\n\t\tawait localCachedQueryItem.promise;\n\n\t\tif (\n\t\t\tcolumnsOperationsCache.tupleContainsAllColumns(\n\t\t\t\tlocalCachedQueryItem.requestColumnsTuple,\n\t\t\t\tthis.transaction,\n\t\t\t)\n\t\t) {\n\t\t\treturn localCachedQueryItem;\n\t\t}\n\n\t\tconst mergedColumns = columnsOperationsCache.getColumnsMergedWithTuple(\n\t\t\tlocalCachedQueryItem.requestColumnsTuple,\n\t\t\tthis.transaction,\n\t\t);\n\n\t\tlocalCachedQueryItem.requestColumnsTuple = mergedColumns.merged;\n\n\t\t// TODO: implement request column sets for items.\n\t\tconst requestColumns = mergedColumns.difference.object;\n\n\t\t// We cannot assume the columns are cached.\n\t\tconst responseColumns = await this.transaction.dependencies.columnHandler.fetch(\n\t\t\tlocalCachedQueryItem.itemType,\n\t\t\trequestColumns,\n\t\t);\n\n\t\tawait this.transaction.itemHandler.expandLocalItemEntries(\n\t\t\tlocalCachedQueryItem.itemType,\n\t\t\tthis.getLocalItemEntries(\n\t\t\t\tlocalCachedQueryItem,\n\t\t\t),\n\t\t\trequestColumns,\n\t\t\tresponseColumns,\n\t\t\tfalse,\n\t\t);\n\n\t\treturn localCachedQueryItem;\n\t}\n\n\tprivate getLocalItemEntries<ItemTypeType extends ApiItemType> (\n\t\tlocalCachedQueryItem: CachedQueryItem<ItemTypeType>,\n\t): ItemEntry<ItemTypeType>[] {\n\t\tconst itemEntries = this.transaction.itemHandler.entries;\n\n\t\treturn localCachedQueryItem.items.filter(\n\t\t\t// Items with al local ID could also be present on the parent transaction, so check the item handler.\n\t\t\titemEntry => itemEntries.containsByEntryId(\n\t\t\t\titemEntry.id,\n\t\t\t),\n\t\t);\n\t}\n\n\t/**\n\t * For all items with changes on the transaction, check whether they fit the query. This will catch both items\n\t * that now fit the query and items that no longer fit the query. Because items that are created on this transaction\n\t * are also considered to have changes, this will cover those, too.\n\t */\n\tprivate matchItemEntriesWithChangesToCachedQuery<ItemTypeType extends ApiItemType> (\n\t\tlocalCachedQueryItem: CachedQueryItem<ItemTypeType>,\n\t): MatchingResultsAccumulatorTuple<ItemTypeType> {\n\t\tconst itemEntriesWithChanges: ItemEntry<ItemTypeType>[] = [];\n\n\t\tfor (const itemEntry of this.transaction.itemHandler.getItemEntriesWithChangesIterator()) {\n\t\t\tif (itemEntry.itemType === localCachedQueryItem.itemType) {\n\t\t\t\titemEntriesWithChanges.push(\n\t\t\t\t\titemEntry,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst matchesAccumulatorTuple: MatchingResultsAccumulatorTuple<ItemTypeType> = {\n\t\t\ttrue: new Set(),\n\t\t};\n\n\t\tif (itemEntriesWithChanges.length > 0) {\n\t\t\tthis.transaction.itemHandler.matchItemsToQueryGraph(\n\t\t\t\tlocalCachedQueryItem.queryGraph,\n\t\t\t\tlocalCachedQueryItem.query,\n\t\t\t\titemEntriesWithChanges,\n\t\t\t\tmatchesAccumulatorTuple,\n\t\t\t);\n\n\t\t\tfor (const itemEntry of itemEntriesWithChanges) {\n\t\t\t\tif (\n\t\t\t\t\tmatchesAccumulatorTuple.true.has(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t)\n\t\t\t\t\t|| !localCachedQueryItem.items.includes(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (matchesAccumulatorTuple.false === undefined) {\n\t\t\t\t\tmatchesAccumulatorTuple.false = new Set();\n\t\t\t\t}\n\n\t\t\t\tmatchesAccumulatorTuple.false.add(\n\t\t\t\t\titemEntry,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// a server request can return remote items which have been deleted on the transaction so should be filtered out\n\t\t// See: https://rentman.atlassian.net/browse/RM4-16979\n\t\tconst deletedItemEntries = [\n\t\t\t...this.transaction.itemHandler.getDeletedItemsIterator(\n\t\t\t\tlocalCachedQueryItem.itemType,\n\t\t\t),\n\t\t];\n\n\t\t// We treat *all* the deleted items as not matching here. Alternatively, we could filter the deleted item\n\t\t// entries using the query matcher, as the fields should still be available on the parent transaction.\n\t\tif (deletedItemEntries.length > 0) {\n\t\t\tif (matchesAccumulatorTuple.false === undefined) {\n\t\t\t\tmatchesAccumulatorTuple.false = new Set();\n\t\t\t}\n\n\t\t\tfor (const deletedItemEntry of deletedItemEntries) {\n\t\t\t\tmatchesAccumulatorTuple.false.add(\n\t\t\t\t\tdeletedItemEntry,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn matchesAccumulatorTuple;\n\t}\n\n\tprivate async syncCachedQueryWithLocalItems<ItemTypeType extends ApiItemType> (\n\t\tlocalCachedQueryItem: CachedQueryItem<ItemTypeType>,\n\t): Promise<void> {\n\t\tconst accumulatorTuple = this.matchItemEntriesWithChangesToCachedQuery(\n\t\t\tlocalCachedQueryItem,\n\t\t);\n\n\t\tconst itemEntriesToAdd = accumulatorTuple.maybe === undefined\n\t\t\t? [\n\t\t\t\t...accumulatorTuple.true,\n\t\t\t]\n\t\t\t: [\n\t\t\t\t...accumulatorTuple.true,\n\t\t\t\t...accumulatorTuple.maybe,\n\t\t\t];\n\n\t\t// We always fetch the columns, which are assumed to be there in other places (ColumnHandler.retrieve() is used).\n\t\tconst responseColumns = await this.transaction.dependencies.columnHandler.fetch(\n\t\t\tlocalCachedQueryItem.itemType,\n\t\t\tlocalCachedQueryItem.requestColumnsTuple.object,\n\t\t);\n\n\t\t// 5. Expand local items before (potentially) adding them to the query.\n\t\tif (itemEntriesToAdd.length > 0) {\n\t\t\tawait this.transaction.itemHandler.expandLocalItemEntries(\n\t\t\t\tlocalCachedQueryItem.itemType,\n\t\t\t\titemEntriesToAdd,\n\t\t\t\tlocalCachedQueryItem.requestColumnsTuple.object,\n\t\t\t\tresponseColumns,\n\t\t\t\tfalse,\n\t\t\t);\n\t\t}\n\n\t\tlocalCachedQueryItem.handleMatchedItemEntries(\n\t\t\titemEntriesToAdd,\n\t\t\taccumulatorTuple.false,\n\t\t);\n\t}\n\n\tprivate cleanUpQueryString (\n\t\titemType: ApiItemType,\n\t\tqueryString: string,\n\t): void {\n\t\tconst collectionsForItemType = this.collections[itemType];\n\n\t\tif (collectionsForItemType === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst collectionTuple = collectionsForItemType[queryString];\n\n\t\tif (\n\t\t\tcollectionTuple === undefined\n\t\t\t|| collectionTuple.collectionResources === undefined\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst filteredResources: TransactionCachedQueryHandlerCollectionTuple<any>['collectionResources'] = [];\n\n\t\t// We don't use `this.getCollectionResources` here, because we want to remove the the passed\n\t\t// resource from the array, and we need the refs for that.\n\t\tfor (const collectionResourceRef of collectionTuple.collectionResources) {\n\t\t\tif (collectionResourceRef.deref() !== undefined) {\n\t\t\t\tfilteredResources.push(\n\t\t\t\t\tcollectionResourceRef,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// We only have to reassign the array if there were any collections cleaned up.\n\t\tif (filteredResources.length !== collectionTuple.collectionResources.length) {\n\t\t\tcollectionTuple.collectionResources = filteredResources;\n\t\t}\n\n\t\tthis.clearCollectionTupleIfEmpty(\n\t\t\titemType,\n\t\t\tqueryString,\n\t\t\ttrue,\n\t\t);\n\t}\n\n}\n","import { computed, signal, untracked, WritableSignal } from '@angular/core';\nimport { hasProperties, isPromiseLike, ItemEntry, TransactionCache, TransactionErrorLevel } from '../../../internal';\n\nexport abstract class TransactionValidatorBase {\n\n\tprivate lastCallIdMap: {\n\t\tglobal: WritableSignal<{\n\t\t\t[key: string]: number,\n\t\t}>,\n\t\titem: WritableSignal<{\n\t\t\t[hash: string]: number,\n\t\t}>,\n\t} = {\n\t\tglobal: signal(\n\t\t\t{},\n\t\t),\n\t\titem: signal(\n\t\t\t{},\n\t\t),\n\t};\n\n\tpublic isPendingSignal = computed(\n\t\t() =>\n\t\t\thasProperties(\n\t\t\t\tthis.lastCallIdMap.global(),\n\t\t\t)\n\t\t\t|| hasProperties(\n\t\t\t\tthis.lastCallIdMap.item(),\n\t\t\t),\n\t);\n\n\tprotected _lastCallId: number = 0;\n\n\t// The constructor is public so that extending classes can be constructred without overriding the constructor\n\t// This is usefull since we do Angular DI through `inject()`\n\tpublic constructor (\n\t\tprotected transaction: TransactionCache,\n\t) {\n\n\t}\n\n\t/**\n\t * @description\n\t * Will return `true` if there are any validators pending\n\t */\n\tpublic isPending (): boolean {\n\t\treturn untracked(\n\t\t\t() => this.isPendingSignal(),\n\t\t);\n\t}\n\n\tpublic setItemError (\n\t\titemEntryId: ItemEntry['id'],\n\t\tcolumnId: string,\n\t\terrorKey: string,\n\t\tisInvalid: boolean | Promise<boolean>,\n\t\tfieldErrorTranslationFn: () => string,\n\t\tsaveButtonErrorTranslationFn: () => string = fieldErrorTranslationFn,\n\t\tlevel: TransactionErrorLevel = TransactionErrorLevel.error,\n\t\tlocation?: string,\n\t): void {\n\t\tconst hash = this.getHash(\n\t\t\titemEntryId,\n\t\t\tcolumnId,\n\t\t\terrorKey,\n\t\t);\n\n\t\tif (\n\t\t\t!isPromiseLike(\n\t\t\t\tisInvalid,\n\t\t\t)\n\t\t) {\n\t\t\tthis.deleteLastCall(\n\t\t\t\thash,\n\t\t\t\t'item',\n\t\t\t);\n\n\t\t\tthis.transaction._setItemError(\n\t\t\t\titemEntryId,\n\t\t\t\tcolumnId,\n\t\t\t\terrorKey,\n\t\t\t\tisInvalid,\n\t\t\t\tfieldErrorTranslationFn,\n\t\t\t\tsaveButtonErrorTranslationFn,\n\t\t\t\tlevel,\n\t\t\t\tlocation,\n\t\t\t);\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst lastCallId = this._lastCallId++;\n\n\t\tthis.setLastCall(\n\t\t\thash,\n\t\t\tlastCallId,\n\t\t\t'item',\n\t\t);\n\n\t\tisInvalid.then(\n\t\t\tisInvalidResult => {\n\t\t\t\tif (\n\t\t\t\t\t!this.isLastCall(\n\t\t\t\t\t\thash,\n\t\t\t\t\t\tlastCallId,\n\t\t\t\t\t\t'item',\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.deleteLastCall(\n\t\t\t\t\thash,\n\t\t\t\t\t'item',\n\t\t\t\t);\n\n\t\t\t\tthis.transaction._setItemError(\n\t\t\t\t\titemEntryId,\n\t\t\t\t\tcolumnId,\n\t\t\t\t\terrorKey,\n\t\t\t\t\tisInvalidResult,\n\t\t\t\t\tfieldErrorTranslationFn,\n\t\t\t\t\tsaveButtonErrorTranslationFn,\n\t\t\t\t\tlevel,\n\t\t\t\t\tlocation,\n\t\t\t\t);\n\t\t\t},\n\t\t\t() => {\n\t\t\t\tif (\n\t\t\t\t\t!this.isLastCall(\n\t\t\t\t\t\thash,\n\t\t\t\t\t\tlastCallId,\n\t\t\t\t\t\t'item',\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.deleteLastCall(\n\t\t\t\t\thash,\n\t\t\t\t\t'item',\n\t\t\t\t);\n\n\t\t\t\t// Todo: Should we unset the error here?\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic setGlobalError (\n\t\tkey: string,\n\t\tisInvalid: boolean | Promise<boolean>,\n\t\tsaveButtonErrorTranslationFn: () => string,\n\t\tlevel: TransactionErrorLevel = TransactionErrorLevel.error,\n\t): void {\n\t\tif (\n\t\t\t!isPromiseLike(\n\t\t\t\tisInvalid,\n\t\t\t)\n\t\t) {\n\t\t\tthis.deleteLastCall(\n\t\t\t\tkey,\n\t\t\t\t'global',\n\t\t\t);\n\n\t\t\tthis.transaction._setGlobalError(\n\t\t\t\tkey,\n\t\t\t\tisInvalid,\n\t\t\t\tsaveButtonErrorTranslationFn,\n\t\t\t\tlevel,\n\t\t\t);\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst lastCallId = this._lastCallId++;\n\n\t\tthis.setLastCall(\n\t\t\tkey,\n\t\t\tlastCallId,\n\t\t\t'global',\n\t\t);\n\n\t\tisInvalid.then(\n\t\t\tisInvalidResult => {\n\t\t\t\tif (\n\t\t\t\t\t!this.isLastCall(\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tlastCallId,\n\t\t\t\t\t\t'global',\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.deleteLastCall(\n\t\t\t\t\tkey,\n\t\t\t\t\t'global',\n\t\t\t\t);\n\n\t\t\t\tthis.transaction._setGlobalError(\n\t\t\t\t\tkey,\n\t\t\t\t\tisInvalidResult,\n\t\t\t\t\tsaveButtonErrorTranslationFn,\n\t\t\t\t\tlevel,\n\t\t\t\t);\n\t\t\t},\n\t\t\t() => {\n\t\t\t\tif (\n\t\t\t\t\t!this.isLastCall(\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tlastCallId,\n\t\t\t\t\t\t'global',\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.deleteLastCall(\n\t\t\t\t\tkey,\n\t\t\t\t\t'global',\n\t\t\t\t);\n\n\t\t\t\t// Todo: Should we unset the error here?\n\t\t\t},\n\t\t);\n\t}\n\n\tprivate getHash (\n\t\t...args: (string | number)[]\n\t): string {\n\t\treturn args.join(\n\t\t\t'-',\n\t\t);\n\t}\n\n\tprivate deleteLastCall (\n\t\tkey: string,\n\t\ttype: keyof TransactionValidatorBase['lastCallIdMap'],\n\t): void {\n\t\tthis.lastCallIdMap[type].update(\n\t\t\tmap => {\n\t\t\t\tif (map[key] === undefined) {\n\t\t\t\t\treturn map;\n\t\t\t\t}\n\n\t\t\t\tconst newMap = {\n\t\t\t\t\t...map,\n\t\t\t\t};\n\n\t\t\t\tdelete newMap[key];\n\n\t\t\t\treturn newMap;\n\t\t\t},\n\t\t);\n\t}\n\n\tprivate setLastCall (\n\t\tkey: string,\n\t\tlastCallId: number,\n\t\ttype: keyof TransactionValidatorBase['lastCallIdMap'],\n\t): void {\n\t\tthis.lastCallIdMap[type].update(\n\t\t\tmap => {\n\t\t\t\treturn {\n\t\t\t\t\t...map,\n\t\t\t\t\t[key]: lastCallId,\n\t\t\t\t};\n\t\t\t},\n\t\t);\n\t}\n\n\tprivate isLastCall (\n\t\tkey: string,\n\t\tlastCallId: number,\n\t\ttype: keyof TransactionValidatorBase['lastCallIdMap'],\n\t): boolean {\n\t\treturn this.lastCallIdMap[type]()[key] === lastCallId;\n\t}\n\n}\n","import { ApiItemType } from '@rentman/backend-types';\nimport { FieldMap, ItemChangesListenerContext, ItemEntry, ItemResource, ItemTypeColumnIds, TransactionCache } from '../../../internal';\nimport { TransactionValidatorBase } from './TransactionValidatorBase';\n\nexport interface TransactionValidatorFactory {\n\tconstruct (\n\t\ttransaction: TransactionCache,\n\t): TransactionValidator,\n}\n\nexport type TransactionValidatorCompareField<\n\tItemTypeType extends ApiItemType,\n\tColumnIds extends ItemTypeColumnIds<ItemTypeType> = ItemTypeColumnIds<ItemTypeType>\n> = ItemChangesListenerContext<ItemResource<ItemTypeType, ColumnIds>>['compareField'];\n\nexport abstract class TransactionValidator\n\textends TransactionValidatorBase {\n\n\t/**\n\t * @description\n\t * Will be called after {@link TransactionCache.applyChangesFromParent applyChangesFromParent}, {@link TransactionCache.applyChangesFromChild applyChangesFromChild} or {@link TransactionCache.applyChangesDelta applyChangesDelta} is called\n\t * Allows you to set {@link TransactionCache.errors global errors}\n\t */\n\tpublic abstract validateTransaction (): void;\n\n\t/**\n\t * @description\n\t * Will be called whenever an item is changed, allows you to set errors on the transaction\n\t * @param itemEntry\n\t * @param fields\n\t * @param previous Previous contain only fields changed on this transaction\n\t * @param compareField\n\t */\n\tpublic abstract validateItem<ItemTypeType extends ApiItemType> (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t\tfields: FieldMap<ItemTypeType>,\n\t\tprevious: Partial<FieldMap<ItemTypeType>>,\n\t\tcompareField: TransactionValidatorCompareField<ItemTypeType>,\n\t): void;\n\n\tprotected hasFields<ItemTypeType extends ApiItemType, ColumnIds extends ItemTypeColumnIds<ItemTypeType>> (\n\t\tfields: FieldMap<ItemTypeType, []>,\n\t\tcolumnIds: ColumnIds,\n\t): fields is FieldMap<ItemTypeType, ColumnIds> {\n\t\treturn columnIds.every(\n\t\t\tcolumnId => Object.prototype.hasOwnProperty.call(\n\t\t\t\tfields,\n\t\t\t\tcolumnId,\n\t\t\t),\n\t\t);\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource, ItemResourceToAggregatedChanges, TransactionCache } from '../../../internal';\nimport { TransactionValidatorBase } from './TransactionValidatorBase';\n\nexport interface TransactionValidatorDependencies {\n\trootItem: ItemResource<any, any, any>,\n};\n\n/**\n * Base class for a transaction validator which manages their own dependencies.\n * You are expected to use item and collection change listeners to call the validation functions.\n */\nexport abstract class TransactionValidatorWithDependencies<Dependency extends TransactionValidatorDependencies>\n\textends TransactionValidatorBase {\n\n\tpublic dependencies: Dependency;\n\n\tpublic abstract validate (\n\t\taggregatedCollectionChanges: unknown,\n\t\taggregatedItemChanges: ItemResourceToAggregatedChanges<Dependency['rootItem']>,\n\t\tisCalledAfterSocketUpdate: boolean,\n\t): void;\n\n\tpublic abstract fetchDependencies (\n\t\ttransaction: TransactionCache,\n\t\trootItemId: ItemId,\n\t): Promise<Dependency>;\n\n}\n","import { ApiItemType, ItemId } from '@rentman/backend-types';\nimport { ChangesDelta, ChildChangesDelta, FieldMap, GetFieldValueType, hasProperties, ItemEntry, ItemEntryService, ItemTypeColumnId } from '../internal';\n\nexport type ChangesDeltaResult = {\n\t/**\n\t * The changes delta included in the changes delta result is not necessarily the same as the one being passed to\n\t * the `applyChangesDelta()` method, as business logic rules might have been applied.\n\t * TODO: Separate results for changes delta and child changes delta.\n\t */\n\tchangesDelta: ChangesDelta | ChildChangesDelta,\n\tcreated: ItemEntry[],\n\tallChildrenDonePromise: Promise<void>,\n\t// todo[cache] other statuses\n};\n\nexport type ChangesDeltaItemUpdateMode =\n/**\n * For create/update responses you always want to overwrite whatever is cached\n */\n\t'CLEAR_ALWAYS'\n\t/**\n\t * For socket messages you want to clear the user's changes if they are the same as what is received\n\t */\n\t| 'CLEAR_WHEN_SAME'\n\t/**\n\t * Used for query responses (you don't want to do anything with user changes)\n\t */\n\t| 'QUERY'\n\t/**\n\t * For user changes you want to store them if they are different than on a parent\n\t */\n\t| 'KEEP_WHEN_DIFFERENT';\n\n/**\n * @remark\n * We explicitly keep track of the new parent, so we can set an item to moved if it isn't null (Needed for linkTo request)\n */\nexport interface ChangesDeltaBaseItemUpdateDelta<ItemTypeType extends ApiItemType> {\n\tentry: ItemEntry<ItemTypeType>,\n\tchanges: {\n\t\tfields: FieldMap<ItemTypeType>,\n\t},\n\tmode: ChangesDeltaItemUpdateMode,\n}\n\nexport interface ChangesDeltaBaseItemDeleteDelta<ItemTypeType extends ApiItemType> {\n\tentry: ItemEntry<ItemTypeType>,\n}\n\n// TODO: Add type variables for created and updated.\nexport abstract class ChangesDeltaBase<ItemDeleteDeltaType extends ChangesDeltaBaseItemDeleteDelta<any> = ChangesDeltaBaseItemDeleteDelta<any>> {\n\n\tpublic updated: {\n\t\t[itemEntryId: number]: ChangesDeltaBaseItemUpdateDelta<any>,\n\t} = {};\n\n\tprotected deleted: {\n\t\t[ItemType in ApiItemType]?: Map<ItemEntry<ItemType>, ItemDeleteDeltaType>\n\t} = {};\n\n\t/**\n\t * @private\n\t */\n\tpublic _queryResults: {\n\t\t[itemType: string]: {\n\t\t\t[queryString: string]: Set<ItemId>,\n\t\t},\n\t} = {};\n\n\t/**\n\t * @private\n\t * When set, only collections of this item type will be matched.\n\t */\n\tpublic _queryItemTypeSet?: Set<ApiItemType>;\n\n\tprotected constructor (\n\t\tprotected itemEntryService: ItemEntryService,\n\t\tqueryItemTypes?: Iterable<ApiItemType>,\n\t) {\n\t\tif (queryItemTypes !== undefined) {\n\t\t\tfor (const itemType of queryItemTypes) {\n\t\t\t\tthis.addQueryItemType(\n\t\t\t\t\titemType,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic addQueryItemType (\n\t\titemType: ApiItemType,\n\t): void {\n\t\tthis._queryItemTypeSet ??= new Set();\n\n\t\tthis._queryItemTypeSet.add(\n\t\t\titemType,\n\t\t);\n\t}\n\n\tpublic getUpdatedValue<ItemTypeType extends ApiItemType, ColumnId extends ItemTypeColumnId<ItemTypeType>> (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t\tcolumnId: ColumnId,\n\t): GetFieldValueType<ItemTypeType, ColumnId> | undefined {\n\t\tconst tuple = this.updated[itemEntry.id];\n\n\t\tif (tuple === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn tuple.changes.fields[columnId];\n\t}\n\n\tpublic hasDeletedItem<ItemTypeType extends ApiItemType> (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t): boolean {\n\t\tconst deleted = this.deleted[itemEntry.itemType];\n\n\t\tif (deleted === undefined) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn deleted.has(\n\t\t\titemEntry,\n\t\t);\n\t}\n\n\tpublic hasUpdatedValue<ItemTypeType extends ApiItemType> (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t\tcolumnId: ItemTypeColumnId<ItemTypeType>,\n\t): boolean {\n\t\tconst tuple = this.updated[itemEntry.id];\n\n\t\tif (tuple === undefined) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn tuple.changes.fields[columnId] !== undefined;\n\t}\n\n\tpublic* getDeletedItemTypesIterator (): Generator<ApiItemType> {\n\t\tfor (const itemType in this.deleted) {\n\t\t\tyield itemType as ApiItemType;\n\t\t}\n\t}\n\n\tpublic getDeletedItemEntriesIterator<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t): Generator<ItemEntry<ItemTypeType>>;\n\n\tpublic getDeletedItemEntriesIterator (\n\t\titemType?: undefined,\n\t): Generator<ItemEntry<any>>;\n\n\tpublic* getDeletedItemEntriesIterator (\n\t\titemType?: ApiItemType,\n\t): Generator<ItemEntry<any>> {\n\t\tif (itemType === undefined) {\n\t\t\tfor (const deletedItemType in this.deleted) {\n\t\t\t\tfor (const deletedItemEntry of this.deleted[deletedItemType as ApiItemType]!.keys()) {\n\t\t\t\t\tyield deletedItemEntry;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst deletedMap = this.deleted[itemType];\n\n\t\tif (deletedMap === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const deletedItemEntry of deletedMap.keys()) {\n\t\t\tyield deletedItemEntry;\n\t\t}\n\t}\n\n\tpublic* getDeleteTuplesIterator (\n\t\titemType?: ApiItemType,\n\t): Generator<ItemDeleteDeltaType> {\n\t\tif (itemType === undefined) {\n\t\t\tfor (const deletedItemType in this.deleted) {\n\t\t\t\tfor (const deletedTuple of this.deleted[deletedItemType as ApiItemType]!.values()) {\n\t\t\t\t\tyield deletedTuple;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst deletedMap = this.deleted[itemType];\n\n\t\tif (deletedMap === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const deletedTuple of deletedMap.values()) {\n\t\t\tyield deletedTuple;\n\t\t}\n\t}\n\n\tpublic isEmpty (): boolean {\n\t\treturn !hasProperties(\n\t\t\t\tthis.updated,\n\t\t\t)\n\t\t\t&& !hasProperties(\n\t\t\t\tthis.deleted,\n\t\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Adds a hint for the {@link CollectionMatcherBase CacheSyncer] to the ChangesDelta, when the CollectionMatcher encounters a collection\n\t * with the exact query, it will use the hint instead of running the matcher\n\t *\n\t * @private\n\t */\n\tpublic _setQueryResult<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tqueryString: string,\n\t\titemIds: Iterable<ItemId>,\n\t): Set<ItemId> {\n\t\tif (this._queryResults[itemType] === undefined) {\n\t\t\tthis._queryResults[itemType] = {};\n\t\t}\n\n\t\treturn this._queryResults[itemType][queryString] = new Set(\n\t\t\titemIds,\n\t\t);\n\t}\n\n\tpublic _getQueryResult<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tqueryString: string,\n\t): Set<ItemId> | undefined {\n\t\treturn this._queryResults[itemType]?.[queryString];\n\t}\n\n\tprotected setItemDeletedByTuple (\n\t\tdeletedTuple: ItemDeleteDeltaType,\n\t): this {\n\t\tconst itemType = deletedTuple.entry.itemType;\n\n\t\tlet deletedTuples = this.deleted[itemType];\n\n\t\tif (deletedTuples === undefined) {\n\t\t\tthis.deleted[itemType] = deletedTuples = new Map();\n\t\t}\n\n\t\tdeletedTuples.set(\n\t\t\tdeletedTuple.entry,\n\t\t\tdeletedTuple,\n\t\t);\n\n\t\treturn this;\n\t}\n\n}\n","import { ApiItemType } from '@rentman/backend-types';\nimport { ItemEntry } from '../models/ItemEntry';\nimport { ItemTypeColumnId } from '../types/ItemTypesCollection';\n\nexport class MissingColumnException<ItemTypeType extends ApiItemType>\n\textends Error {\n\n\tpublic constructor (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t\tcolumnId: ItemTypeColumnId<ItemTypeType>,\n\t) {\n\t\tsuper(\n\t\t\t`Missing column '${columnId as string}' for item with type '${itemEntry.itemType}' and ID '${itemEntry.itemId}'`,\n\t\t);\n\t}\n\n}","import { ApiFields, ApiItemType, ItemId } from '@rentman/backend-types';\nimport { MissingColumnException } from '../exceptions/MissingColumnException';\nimport { ApiFormatter, ChangesDeltaBase, ChangesDeltaBaseItemDeleteDelta, ChangesDeltaBaseItemUpdateDelta, ChangesDeltaItemCreateDelta, ChangesDeltaItemUpdateMode, ColumnExpansion, ColumnSet, CreatedChangesDelta, EntryParentNull, ErrorHandlerInterface, FieldMap, hasProperties, ItemCreateService, ItemEntry, ItemEntryChangesTuple, ItemEntryService, RequestParameters, ResponseColumnMap } from '../internal';\n\nexport interface ChangesDeltaItemDeleteDelta<ItemTypeType extends ApiItemType>\n\textends ChangesDeltaBaseItemDeleteDelta<ItemTypeType> {\n\tisCascaded: boolean,\n}\n\nexport interface ChangesDeltaItemUpdateDelta<ItemTypeType extends ApiItemType>\n\textends ChangesDeltaBaseItemUpdateDelta<ItemTypeType> {\n\tentry: ItemEntry<ItemTypeType>,\n\tchanges: {\n\t\tfields: FieldMap<ItemTypeType>,\n\t\t// TODO: If the delta was used to apply changes from outside of the core only, this wouldn't be necessary here.\n\t\t// However, it is currently also used to process server responses.\n\t\tcolumnExpansions: ColumnExpansion<ItemTypeType>[],\n\t},\n\tmode: ChangesDeltaItemUpdateMode,\n}\n\n/**\n * @description\n * ChangesDelta used to apply changes from outside of the core to a transaction\n *\n * ----------\n *\n * The difference between {@link ChildChangesDelta} and {@link ChangesDelta} is that the ChangesDelta\n * assumes 'created' values have no itemEntries yet.\n *\n * Use this when calling {@link TransactionCache.applyChangesDelta applyChangesDelta}\n */\nexport class ChangesDelta\n\textends ChangesDeltaBase<ChangesDeltaItemDeleteDelta<any>> {\n\n\tpublic declare updated: {\n\t\t[itemEntryId: number]: ChangesDeltaItemUpdateDelta<any>,\n\t};\n\n\tpublic created: CreatedChangesDelta = new CreatedChangesDelta();\n\n\t/**\n\t * Only contains remote items, when rolling back local items the whole entries are deleted.\n\t */\n\tpublic restored: {\n\t\t[itemEntryId: number]: ItemEntryChangesTuple<any>,\n\t} = {};\n\n\tpublic constructor (\n\t\tpublic logMissingColumnErrors: boolean,\n\t\tqueryItemTypes: Iterable<ApiItemType> | undefined,\n\t\tprivate errorHandler: ErrorHandlerInterface,\n\t\tprivate itemCreateService: ItemCreateService,\n\t\titemEntryService: ItemEntryService,\n\t) {\n\t\tsuper(\n\t\t\titemEntryService,\n\t\t\tqueryItemTypes,\n\t\t);\n\t}\n\n\tpublic getCreatedTuplesIterator<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t): IterableIterator<ChangesDeltaItemCreateDelta<ItemTypeType>> {\n\t\treturn this.created.getTuplesIterator(\n\t\t\titemType,\n\t\t);\n\t}\n\n\tpublic* getUpdatedTuplesIterator<ItemTypes extends ApiItemType[]> (\n\t\t...itemTypes: ItemTypes\n\t): Generator<ChangesDeltaItemUpdateDelta<ItemTypes extends [] ? any : ItemTypes[number]>> {\n\t\tif (itemTypes.length === 0) {\n\t\t\tfor (const itemEntryId in this.updated) {\n\t\t\t\tyield this.updated[itemEntryId];\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (itemTypes.length === 1) {\n\t\t\tconst itemType = itemTypes[0];\n\n\t\t\tfor (const itemEntryId in this.updated) {\n\t\t\t\tconst tuple = this.updated[itemEntryId];\n\n\t\t\t\tif (tuple.entry.itemType === itemType) {\n\t\t\t\t\tyield tuple;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const itemEntryId in this.updated) {\n\t\t\tconst tuple = this.updated[itemEntryId];\n\n\t\t\tif (\n\t\t\t\titemTypes.includes(\n\t\t\t\t\ttuple.entry.itemType,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tyield tuple;\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic merge (\n\t\totherChangesDelta: ChangesDelta,\n\t): ChangesDelta {\n\t\tconst newChangesDelta = new ChangesDelta(\n\t\t\tthis.logMissingColumnErrors,\n\t\t\tundefined,\n\t\t\tthis.errorHandler,\n\t\t\tthis.itemCreateService,\n\t\t\tthis.itemEntryService,\n\t\t);\n\n\t\tfor (\n\t\t\tconst delta of [\n\t\t\tthis,\n\t\t\totherChangesDelta,\n\t\t]\n\t\t\t) {\n\t\t\tfor (const itemEntryId in delta.updated) {\n\t\t\t\tconst tuple = delta.updated[itemEntryId];\n\t\t\t\tconst columnExpansions = tuple.changes.columnExpansions;\n\n\t\t\t\tnewChangesDelta.setItemUpdated(\n\t\t\t\t\ttuple.entry,\n\t\t\t\t\ttuple.changes.fields,\n\t\t\t\t\tcolumnExpansions.length === 0\n\t\t\t\t\t\t? null\n\t\t\t\t\t\t: columnExpansions[0],\n\t\t\t\t\tnull,\n\t\t\t\t\ttuple.mode,\n\t\t\t\t);\n\n\t\t\t\t// Add any additional column expansions we might have.\n\t\t\t\tfor (let i = 1; i < columnExpansions.length; i++) {\n\t\t\t\t\tnewChangesDelta.updated[itemEntryId].changes.columnExpansions.push(\n\t\t\t\t\t\tcolumnExpansions[i],\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const itemEntryId in delta.restored) {\n\t\t\t\tconst tuple = delta.restored[itemEntryId];\n\n\t\t\t\tnewChangesDelta.setItemRestored(\n\t\t\t\t\ttuple.entry,\n\t\t\t\t\ttuple.changes,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tdelta.created.forEach(\n\t\t\t\t(\n\t\t\t\t\ttuple: ChangesDeltaItemCreateDelta,\n\t\t\t\t) => {\n\t\t\t\t\tnewChangesDelta._setItemCreated(\n\t\t\t\t\t\ttuple.itemId,\n\t\t\t\t\t\ttuple.fields,\n\t\t\t\t\t\ttuple.columns,\n\t\t\t\t\t\t// Parent fields are already processed\n\t\t\t\t\t\tnull,\n\t\t\t\t\t\ttuple.isRoot,\n\t\t\t\t\t\t// Never an api response since that logic is already handled\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tfor (const deleteTuple of delta.getDeleteTuplesIterator()) {\n\t\t\t\tnewChangesDelta.setItemDeletedByTuple(\n\t\t\t\t\tdeleteTuple,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Moves shouldn't be processed because they are treated as updates\n\t\t}\n\n\t\treturn newChangesDelta;\n\t}\n\n\t/**\n\t * @description\n\t * Fetches a template for the passed itemType and processes the passed values and sets the item to be created when the delta is applied\n\t *\n\t * @remark\n\t * - If the values don't contain an `id` a new one will be generated\n\t * - If you want to set a parent set the proper field, you can't pass it as a separate object\n\t */\n\tpublic setItemCreated<ItemTypeType extends ApiItemType, Fields extends Partial<FieldMap<ItemTypeType>>> (\n\t\titemType: ItemTypeType,\n\t\tvalues: Fields,\n\t\ttemplateOptions: Partial<RequestParameters<ItemTypeType>> = {},\n\t): Promise<this> {\n\t\treturn this.itemCreateService\n\t\t\t.createItemsFromValues(\n\t\t\t\tthis,\n\t\t\t\titemType,\n\t\t\t\t[\n\t\t\t\t\tvalues,\n\t\t\t\t],\n\t\t\t\tnull,\n\t\t\t\ttemplateOptions,\n\t\t\t)\n\t\t\t.then(\n\t\t\t\t() => this,\n\t\t\t);\n\t}\n\n\tpublic setItemCreatedByTuple<ItemTypeType extends ApiItemType> (\n\t\titemCreateTuple: ChangesDeltaItemCreateDelta<ItemTypeType>,\n\t\tupdatedFields: Partial<FieldMap<ItemTypeType>>,\n\t): ChangesDelta {\n\t\treturn this._setItemCreated(\n\t\t\titemCreateTuple.itemId,\n\t\t\t{\n\t\t\t\t...ApiFormatter.copyFields(\n\t\t\t\t\titemCreateTuple.fields,\n\t\t\t\t\t{},\n\t\t\t\t\titemCreateTuple.columns.main,\n\t\t\t\t),\n\t\t\t\t...updatedFields,\n\t\t\t},\n\t\t\titemCreateTuple.columns,\n\t\t);\n\t}\n\n\tpublic setItemUpdated<ItemTypeType extends ApiItemType> (\n\t\tentry: ItemEntry<ItemTypeType>,\n\t\tfields: Partial<FieldMap<ItemTypeType>>,\n\t\tcolumnExpansion: ColumnExpansion<ItemTypeType> | null = null,\n\t\tparent: EntryParentNull = null,\n\t\t// TODO: Currently, when calling `setItemUpdated` for the same entry multiple times, `mode` is overwritten.\n\t\t// Ideally, the changes delta would be used to apply changes from outside of the core only, and the mode would\n\t\t// be 'KEEP_WHEN_DIFFERENT' always.\n\t\tmode: ChangesDeltaItemUpdateMode = 'KEEP_WHEN_DIFFERENT',\n\t): this {\n\t\tconst entryId = entry.id;\n\n\t\tif (\n\t\t\t// An item can be updated whilst in deleted entries by the cascading deletes (if multiple items at the\n\t\t\t// same time are deleted which influence eachother)\n\t\t\tthis.hasDeletedItem(\n\t\t\t\tentry,\n\t\t\t)\n\t\t) {\n\t\t\treturn this;\n\t\t}\n\n\t\tlet updateDelta: ChangesDeltaItemUpdateDelta<ItemTypeType> | undefined = this.updated[entryId];\n\n\t\tif (updateDelta === undefined) {\n\t\t\tupdateDelta = this.updated[entryId] = {\n\t\t\t\tentry: entry,\n\t\t\t\tchanges: {\n\t\t\t\t\tfields: {} as FieldMap<ItemTypeType>,\n\t\t\t\t\tcolumnExpansions: columnExpansion === null\n\t\t\t\t\t\t? []\n\t\t\t\t\t\t: [\n\t\t\t\t\t\t\tcolumnExpansion,\n\t\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t\tmode,\n\t\t\t};\n\t\t} else {\n\t\t\tif (columnExpansion !== null) {\n\t\t\t\tupdateDelta.changes.columnExpansions.push(\n\t\t\t\t\tcolumnExpansion,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tupdateDelta.mode = mode;\n\t\t}\n\n\t\tif (parent !== null) {\n\t\t\tconst parentFields = this.itemEntryService.getLinkFieldsByParent(\n\t\t\t\tparent,\n\t\t\t\tentry.itemType,\n\t\t\t);\n\n\t\t\tfor (const columnId in parentFields) {\n\t\t\t\tfields[columnId] = parentFields[columnId];\n\t\t\t}\n\t\t}\n\n\t\tlet columnSet: ColumnSet<ItemTypeType> = entry.columns;\n\n\t\tif (columnExpansion !== null) {\n\t\t\t// We should always run column expansions in the same order, this way the results are cached correctly.\n\t\t\tfor (const expansion of updateDelta.changes.columnExpansions) {\n\t\t\t\tcolumnSet = expansion\n\t\t\t\t\t.run(\n\t\t\t\t\t\tcolumnSet,\n\t\t\t\t\t)\n\t\t\t\t\t.merged;\n\t\t\t}\n\t\t}\n\n\t\tApiFormatter.shallowCopyFields(\n\t\t\tfields,\n\t\t\tupdateDelta.changes.fields,\n\t\t\tcolumnSet.response[entry.itemType] as ResponseColumnMap<ItemTypeType>,\n\t\t\tthis.logMissingColumnErrors\n\t\t\t\t? columnId => this.errorHandler.logError(\n\t\t\t\t\tnew MissingColumnException(\n\t\t\t\t\t\tentry,\n\t\t\t\t\t\tcolumnId,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\t: undefined,\n\t\t);\n\n\t\treturn this;\n\t}\n\n\tpublic setItemDeleted (\n\t\tentry: ItemEntry,\n\t\t__isCascaded: boolean = false,\n\t): this {\n\t\tdelete this.updated[entry.id];\n\t\tdelete this.restored[entry.id];\n\n\t\treturn this.setItemDeletedByTuple(\n\t\t\t{\n\t\t\t\tentry,\n\t\t\t\tisCascaded: __isCascaded,\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic setItemsDeleted (\n\t\tdeleted: ItemEntry[],\n\t): this {\n\t\tfor (const itemEntry of deleted) {\n\t\t\tthis.setItemDeleted(\n\t\t\t\titemEntry,\n\t\t\t);\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tpublic setItemDeletedCascaded (\n\t\titemEntry: ItemEntry,\n\t): this {\n\t\tthis.setItemDeleted(\n\t\t\titemEntry,\n\t\t\ttrue,\n\t\t);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * @description\n\t * Fetches a template for the passed itemType and processes the passed values and sets the items to be created when the delta is applied\n\t *\n\t * @remark\n\t * - If the values don't contain an `id` a new one will be generated\n\t * - If you want to set a parent set the proper field, you can't pass it as a separate object\n\t */\n\tpublic setItemsCreated<ItemTypeType extends ApiItemType, ColumnIds extends (\n\t\tkeyof ApiFields[ItemTypeType])[] = (keyof ApiFields[ItemTypeType])[]> (\n\t\titemType: ItemTypeType,\n\t\tvaluesArray: Partial<FieldMap<ItemTypeType, ColumnIds>>[],\n\t): Promise<this> {\n\t\treturn this.itemCreateService\n\t\t\t.createItemsFromValues(\n\t\t\t\tthis,\n\t\t\t\titemType,\n\t\t\t\tvaluesArray,\n\t\t\t)\n\t\t\t.then(\n\t\t\t\t() => this,\n\t\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * Will create an {@link ItemEntry ItemEntry} when the delta is applied\n\t * Does not always mean the item is local, just that it isn't cached yet\n\t *\n\t * @remark\n\t * If you're calling this from the frontend you probably want to call `setItemCreated`, which will fetch a template and process the values for you\n\t * If you don't, you have to make sure the values are all correct and all template items are processed\n\t *\n\t * @internal\n\t */\n\tpublic _setItemCreated<ItemTypeType extends ApiItemType, Fields extends Partial<FieldMap<ItemTypeType>>> (\n\t\titemId: ItemId,\n\t\tfields: Fields,\n\t\tcolumns: ColumnSet<ItemTypeType>,\n\t\tparent: EntryParentNull = null,\n\t\tisRoot: boolean = false,\n\t\tisApiResponse: boolean = false,\n\t): this {\n\t\t// In most cases, when we call `_setItemCreated`, we don't set the `id` field.\n\t\t// TODO: Remove the `itemId`, `parent` parameters and set these in `fields`. (We could include `id` in the type.)\n\t\tfields.id = itemId;\n\n\t\tlet parentFields: Partial<Fields> = {};\n\n\t\tif (parent !== null) {\n\t\t\tparentFields = this.itemEntryService.getLinkFieldsByParent(\n\t\t\t\tparent,\n\t\t\t\tcolumns.itemType,\n\t\t\t) as Partial<Fields>;\n\n\t\t\tfor (const columnId in parentFields) {\n\t\t\t\tfields[columnId] = parentFields[columnId]!;\n\t\t\t}\n\t\t}\n\n\t\t// in the case that we process an API response we don't want to set these values\n\t\tif (!isApiResponse) {\n\t\t\t// todo: these should be set when expanding locally\n\t\t\tconst defaultValues = this.itemEntryService.getLocalDefaultValues();\n\n\t\t\tfor (const columnId in defaultValues) {\n\t\t\t\tif (\n\t\t\t\t\tObject.prototype.hasOwnProperty.call(\n\t\t\t\t\t\tfields,\n\t\t\t\t\t\tcolumnId,\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tfields[columnId] = defaultValues[columnId];\n\t\t\t}\n\t\t}\n\n\t\tthis.created.add(\n\t\t\titemId,\n\t\t\tfields,\n\t\t\tcolumns,\n\t\t\tisRoot,\n\t\t);\n\n\t\treturn this;\n\t}\n\n\tpublic setItemRestored<ItemTypeType extends ApiItemType> (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t\ttransactionItemEntryChanges: FieldMap<ItemTypeType>,\n\t): void {\n\t\tthis.restored[itemEntry.id] = {\n\t\t\tentry: itemEntry,\n\t\t\tchanges: transactionItemEntryChanges,\n\t\t};\n\t}\n\n\tpublic isEmpty (): boolean {\n\t\treturn super.isEmpty()\n\t\t\t&& this.created.isEmpty()\n\t\t\t&& !hasProperties(\n\t\t\t\tthis.restored,\n\t\t\t);\n\t}\n\n\tpublic toJSON (): any {\n\t\treturn {\n\t\t\tupdated: this.updated,\n\t\t\tcreated: this.created,\n\t\t\tdeleted: this.deleted,\n\t\t};\n\t}\n\n}\n","import { ApiItemType } from '@rentman/backend-types';\nimport { ApiFormatter, ChangesDeltaBase, ChangesDeltaBaseItemDeleteDelta, ChangesDeltaBaseItemUpdateDelta, ChangesDeltaItemUpdateMode, FieldMap, hasProperties, ItemEntry, ItemEntryService, ResponseColumnMap } from '../internal';\n\nexport type ChildChangesDeltaItemCreateDelta<ItemTypeType extends ApiItemType = any> = {\n\tentry: ItemEntry<ItemTypeType>,\n\tfields: FieldMap<ItemTypeType>,\n};\n\nexport interface ChildChangesDeltaItemUpdateDelta<ItemTypeType extends ApiItemType>\n\textends ChangesDeltaBaseItemUpdateDelta<ItemTypeType> {\n\n\tentry: ItemEntry<ItemTypeType>,\n\tchanges: {\n\t\tfields: Readonly<FieldMap<ItemTypeType>>,\n\t},\n\tmode: ChangesDeltaItemUpdateMode,\n}\n\nexport interface ChildChangesDeltaItemDeleteDelta<ItemTypeType extends ApiItemType>\n\textends ChangesDeltaBaseItemDeleteDelta<ItemTypeType> {\n\tchanges: FieldMap<ItemTypeType>,\n\tisCascaded: boolean,\n}\n\n/**\n * @description\n * The difference between {@link ChildChangesDelta} and {@link ChangesDelta} is that the {@link ChildChangesDelta}\n * assumes 'created' entries are already existing, so it has a different format.\n *\n * Use this when calling {@link TransactionCache.applyChangesFromChild}.\n */\nexport class ChildChangesDelta\n\textends ChangesDeltaBase<ChildChangesDeltaItemDeleteDelta<any>> {\n\n\tpublic updated: {\n\t\t[itemEntryId: number]: ChildChangesDeltaItemUpdateDelta<any>,\n\t} = {};\n\n\tpublic created: {\n\t\t[itemEntryId: string]: ChildChangesDeltaItemCreateDelta,\n\t} = {};\n\n\tpublic constructor (\n\t\titemEntryService: ItemEntryService,\n\t) {\n\t\tsuper(\n\t\t\titemEntryService,\n\t\t);\n\t}\n\n\tpublic setItemUpdated<ItemTypeType extends ApiItemType> (\n\t\tentry: ItemEntry<ItemTypeType>,\n\t\tfields: Readonly<Partial<FieldMap<ItemTypeType>>>,\n\t\tmode: ChangesDeltaItemUpdateMode = 'KEEP_WHEN_DIFFERENT',\n\t): this {\n\t\tif (this.updated[entry.id] === undefined) {\n\t\t\tthis.updated[entry.id] = {\n\t\t\t\tentry: entry,\n\t\t\t\tchanges: {\n\t\t\t\t\tfields: fields,\n\t\t\t\t},\n\t\t\t\tmode,\n\t\t\t};\n\t\t} else {\n\t\t\tconst updateDelta = this.updated[entry.id] as ChildChangesDeltaItemUpdateDelta<ItemTypeType>;\n\n\t\t\tApiFormatter.shallowCopyFields(\n\t\t\t\tfields,\n\t\t\t\tupdateDelta.changes.fields,\n\t\t\t\tentry.columns.response[entry.itemType] as ResponseColumnMap<ItemTypeType>,\n\t\t\t);\n\n\t\t\tupdateDelta.mode = mode;\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tpublic setItemDeleted (\n\t\ttuple: ChildChangesDeltaItemDeleteDelta<any>,\n\t): this {\n\t\treturn this.setItemDeletedByTuple(\n\t\t\ttuple,\n\t\t);\n\t}\n\n\tpublic setItemsDeleted (\n\t\tdeleted: ChildChangesDeltaItemDeleteDelta<any>[],\n\t): this {\n\t\tfor (const tuple of deleted) {\n\t\t\tthis.setItemDeleted(\n\t\t\t\ttuple,\n\t\t\t);\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tpublic setItemCreated<ItemTypeType extends ApiItemType> (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t\tfields: Partial<FieldMap<ItemTypeType>>,\n\t): void {\n\t\tthis.created[itemEntry.id] = {\n\t\t\tentry: itemEntry,\n\t\t\tfields: fields,\n\t\t};\n\t}\n\n\tpublic isEmpty (): boolean {\n\t\treturn super.isEmpty()\n\t\t\t&& !hasProperties(\n\t\t\t\tthis.created,\n\t\t\t);\n\t}\n\n}\n","import { ApiItemType } from '@rentman/backend-types';\nimport { ApiFormatter, ChangesDeltaBase, ChangesDeltaBaseItemUpdateDelta, ChangesDeltaItemUpdateMode, ChildChangesDeltaItemCreateDelta, FieldMap, hasProperties, ItemEntry, ItemEntryService, ResponseColumnMap } from '../internal';\n\nexport interface ParentChangesDeltaItemUpdateDelta<ItemTypeType extends ApiItemType>\n\textends ChangesDeltaBaseItemUpdateDelta<ItemTypeType> {\n\tentry: ItemEntry<ItemTypeType>,\n\tchanges: {\n\t\tfields: Readonly<FieldMap<ItemTypeType>>,\n\t},\n\tprevious: Partial<FieldMap<ItemTypeType>> | null,\n\tmode: ChangesDeltaItemUpdateMode,\n}\n\n/**\n * @description\n * ChangesDelta used internally by the core\n *\n * ----------\n *\n * The difference between {@link ParentChangesDelta ParentChangesDelta} and {@link ChangesDelta ChangesDelta} is that the ParentChangesDelta\n * assumes 'created' entries are already existing, and deletedEntries don't have changes (since you cannot undo an action that happened on a parent on a child transaction)\n *\n * Use this when calling {@link TransactionCache.applyChangesFromParent applyChangesFromParent}\n */\nexport class ParentChangesDelta\n\textends ChangesDeltaBase {\n\n\tpublic updated: {\n\t\t[itemEntryId: number]: ParentChangesDeltaItemUpdateDelta<any>,\n\t} = {};\n\n\tpublic created: {\n\t\t[itemEntryId: string]: ChildChangesDeltaItemCreateDelta,\n\t} = {};\n\n\tpublic constructor (\n\t\titemEntryService: ItemEntryService,\n\t\tqueryItemTypes?: Iterable<ApiItemType>,\n\t) {\n\t\tsuper(\n\t\t\titemEntryService,\n\t\t\tqueryItemTypes,\n\t\t);\n\t}\n\n\t/**\n\t * @param entry\n\t * @param fields\n\t * @param previous - The values of the affected fields before the changes were applied, or `null` if no changes have\n\t * been made. Because of the nature of item changes also includes values on ancestor transactions.\n\t * @param mode\n\t */\n\tpublic setItemUpdated<ItemTypeType extends ApiItemType> (\n\t\tentry: ItemEntry<ItemTypeType>,\n\t\tfields: Readonly<Partial<FieldMap<ItemTypeType>>>,\n\t\tprevious: Partial<FieldMap<ItemTypeType>> | null = null,\n\t\tmode: ChangesDeltaItemUpdateMode = 'KEEP_WHEN_DIFFERENT',\n\t): this {\n\t\tif (this.updated[entry.id] === undefined) {\n\t\t\tthis.updated[entry.id] = {\n\t\t\t\tentry: entry,\n\t\t\t\tchanges: {\n\t\t\t\t\tfields: fields,\n\t\t\t\t},\n\t\t\t\tprevious,\n\t\t\t\tmode,\n\t\t\t};\n\t\t} else {\n\t\t\tconst updateDelta = this.updated[entry.id] as ParentChangesDeltaItemUpdateDelta<ItemTypeType>;\n\t\t\tconst responseColumns = entry.columns.response[entry.itemType] as ResponseColumnMap<ItemTypeType>;\n\n\t\t\tApiFormatter.shallowCopyFields(\n\t\t\t\tfields,\n\t\t\t\tupdateDelta.changes.fields,\n\t\t\t\tresponseColumns,\n\t\t\t);\n\n\t\t\tif (previous !== null) {\n\t\t\t\tif (updateDelta.previous !== null) {\n\t\t\t\t\tApiFormatter.shallowCopyFields(\n\t\t\t\t\t\tprevious,\n\t\t\t\t\t\tupdateDelta.previous,\n\t\t\t\t\t\tresponseColumns,\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tupdateDelta.previous = previous;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tupdateDelta.mode = mode;\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tpublic setItemDeleted (\n\t\titemEntry: ItemEntry<any>,\n\t): this {\n\t\tdelete this.updated[itemEntry.id];\n\n\t\treturn this.setItemDeletedByTuple(\n\t\t\t{\n\t\t\t\tentry: itemEntry,\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic setItemsDeleted (\n\t\tdeleted: ItemEntry<any>[],\n\t): this {\n\t\tfor (const itemEntry of deleted) {\n\t\t\tthis.setItemDeleted(\n\t\t\t\titemEntry,\n\t\t\t);\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tpublic setItemCreated<ItemTypeType extends ApiItemType> (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t\tfields: FieldMap<ItemTypeType>,\n\t): void {\n\t\tthis.created[itemEntry.id] = {\n\t\t\tentry: itemEntry,\n\t\t\tfields: fields,\n\t\t};\n\t}\n\n\tpublic isEmpty (): boolean {\n\t\treturn super.isEmpty()\n\t\t\t&& !hasProperties(\n\t\t\t\tthis.created,\n\t\t\t);\n\t}\n\n}\n","import { ApiItemType, ItemId } from '@rentman/backend-types';\nimport { ApiRequestColumnMap, ApiRequestColumns, ApiRequestLimit, ApiRequestService, ApiResponseProcessor, CollectionQuery, Deferred, promiseCreateDeferred, RequestColumnExpansion, RequestColumnExpansionFactory, RequestColumnsTuple } from '../../internal';\n\nexport interface RequestBufferOptions<ItemTypeType extends ApiItemType> {\n\t/**\n\t * By default, flushing is prevented while requests are suspended. This prevents conflicts while saving. Enable to\n\t * ignore request suspension, which could introduce an additional delay.\n\t */\n\tforceFlush: boolean,\n\t/**\n\t * Time that should expire before the back-end request is executed, in milliseconds. Set to `0` to execute request\n\t * immediately. 150 milliseconds by default.\n\t */\n\tflushTimeout: number,\n\tlimit: ApiRequestLimit<ItemTypeType> | undefined,\n}\n\nexport const defaultRequestBufferOptions: Readonly<RequestBufferOptions<any>> = {\n\tforceFlush: false,\n\tflushTimeout: window.IS_IN_TEST ? 0 : 150,\n\tlimit: undefined,\n};\n\nexport interface RequestBufferResult<ItemTypeType extends ApiItemType> {\n\trequestColumns: ApiRequestColumnMap,\n\tresponse: ApiResponseProcessor<ItemTypeType>,\n\tnonLocallyMatchableQueryString: string | null,\n}\n\nexport abstract class RequestBufferBase<ItemTypeType extends ApiItemType> {\n\n\tprotected readonly deferred: Deferred<RequestBufferResult<ItemTypeType>> = promiseCreateDeferred();\n\tprotected readonly requestColumnExpansion: RequestColumnExpansion;\n\n\tpublic readonly createdDate: number = Date.now();\n\n\tprotected constructor (\n\t\tprotected readonly apiRequestService: ApiRequestService,\n\t\trequestColumnExpansionFactory: RequestColumnExpansionFactory,\n\t\tpublic readonly itemType: ItemTypeType,\n\t\tpublic readonly options: Readonly<RequestBufferOptions<ItemTypeType>>,\n\t) {\n\t\tthis.requestColumnExpansion = requestColumnExpansionFactory.construct();\n\t}\n\n\tpublic abstract addSingleItems (\n\t\titemIds: ItemId[],\n\t\trequestColumns: ApiRequestColumns<ItemTypeType>,\n\t\tforceFlush: boolean,\n\t): this | null;\n\n\tpublic abstract addQuery (\n\t\tquery: CollectionQuery<ItemTypeType>,\n\t\trequestColumnsTuple: RequestColumnsTuple<ItemTypeType>,\n\t\toptions: RequestBufferOptions<ItemTypeType>,\n\t): this | null;\n\n\tpublic async flush (\n\t\tonBufferFlushed?: (\n\t\t\tresult: RequestBufferResult<any>,\n\t\t) => Promise<any>,\n\t): Promise<RequestBufferResult<ItemTypeType>> {\n\t\ttry {\n\t\t\tconst result = await this.executeQuery();\n\n\t\t\tif (onBufferFlushed !== undefined) {\n\t\t\t\tawait onBufferFlushed(\n\t\t\t\t\tresult,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.deferred.resolve(\n\t\t\t\tresult,\n\t\t\t);\n\n\t\t\treturn result;\n\t\t} catch (exception) {\n\t\t\tthis.deferred.reject(\n\t\t\t\texception,\n\t\t\t);\n\n\t\t\tthrow exception;\n\t\t}\n\t}\n\n\tpublic getPromise (): Promise<RequestBufferResult<ItemTypeType>> {\n\t\treturn this.deferred.promise;\n\t}\n\n\tprotected abstract executeQuery (): Promise<RequestBufferResult<ItemTypeType>>;\n\n\tprotected acceptsRequestColumns (\n\t\trequestColumns: ApiRequestColumns<ItemTypeType>,\n\t): boolean {\n\t\tconst bufferRequestColumns = this.requestColumnExpansion.get()[this.itemType];\n\n\t\tif (bufferRequestColumns === undefined) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (requestColumns === true) {\n\t\t\treturn bufferRequestColumns === true;\n\t\t}\n\n\t\treturn bufferRequestColumns !== true;\n\t}\n\n\tprotected compareApiRequestLimit (\n\t\tlimitA: ApiRequestLimit | undefined,\n\t\tlimitB: ApiRequestLimit | undefined,\n\t): boolean {\n\t\treturn (\n\t\t\t\tlimitA === undefined\n\t\t\t\t&& limitB === undefined\n\t\t\t)\n\t\t\t|| (\n\t\t\t\tlimitA !== undefined\n\t\t\t\t&& limitB !== undefined\n\t\t\t\t&& limitA.field === limitB.field\n\t\t\t\t&& limitA.order === limitB.order\n\t\t\t\t&& limitA.limit === limitB.limit\n\t\t\t);\n\t}\n\n}\n","import { ApiItemType, BackendApiQuery, ItemId } from '@rentman/backend-types';\nimport { ApiQuery, ApiQueryConditionIn, ApiRequestColumns, ApiRequestService, CollectionQuery, RequestBufferBase, RequestBufferOptions, RequestBufferResult, RequestColumnExpansionFactory, RequestColumnsTuple } from '../../internal';\n\nexport class RequestBuffer<ItemTypeType extends ApiItemType>\n\textends RequestBufferBase<ItemTypeType> {\n\n\tprivate readonly contents: {\n\t\tqueries: Map<string, CollectionQuery<ItemTypeType, true>>,\n\t\tsingleItemIds: Set<ItemId<ItemTypeType>>,\n\t} = {\n\t\tqueries: new Map(),\n\t\tsingleItemIds: new Set(),\n\t};\n\n\tpublic static constructWithSingleItems<ConstructorItemTypeType extends ApiItemType> (\n\t\tapiRequestService: ApiRequestService,\n\t\trequestColumnExpansionFactory: RequestColumnExpansionFactory,\n\t\titemType: ConstructorItemTypeType,\n\t\titemIds: ItemId<ConstructorItemTypeType>[],\n\t\trequestColumns: ApiRequestColumns<ConstructorItemTypeType>,\n\t\toptions: RequestBufferOptions<ConstructorItemTypeType>,\n\t): RequestBuffer<ConstructorItemTypeType> {\n\t\treturn new RequestBuffer(\n\t\t\tapiRequestService,\n\t\t\trequestColumnExpansionFactory,\n\t\t\titemType,\n\t\t\toptions,\n\t\t)\n\t\t\t._addSingleItems(\n\t\t\t\titemIds,\n\t\t\t\trequestColumns,\n\t\t\t);\n\t}\n\n\tpublic static constructWithQuery<ConstructorItemTypeType extends ApiItemType> (\n\t\tapiRequestService: ApiRequestService,\n\t\trequestColumnExpansionFactory: RequestColumnExpansionFactory,\n\t\titemType: ConstructorItemTypeType,\n\t\tquery: CollectionQuery<ConstructorItemTypeType, true>,\n\t\trequestColumnsTuple: RequestColumnsTuple<ConstructorItemTypeType>,\n\t\toptions: RequestBufferOptions<ConstructorItemTypeType>,\n\t): RequestBuffer<ConstructorItemTypeType> {\n\t\treturn new RequestBuffer(\n\t\t\tapiRequestService,\n\t\t\trequestColumnExpansionFactory,\n\t\t\titemType,\n\t\t\toptions,\n\t\t)\n\t\t\t._addQuery(\n\t\t\t\tquery,\n\t\t\t\trequestColumnsTuple,\n\t\t\t);\n\t}\n\n\tpublic addSingleItems (\n\t\titemIds: ItemId[],\n\t\trequestColumns: ApiRequestColumns<ItemTypeType>,\n\t\tforceFlush: boolean,\n\t): this | null {\n\t\treturn (\n\t\t\tthis.options.forceFlush === forceFlush\n\t\t\t&& this.acceptsRequestColumns(\n\t\t\t\trequestColumns,\n\t\t\t)\n\t\t)\n\t\t\t? this._addSingleItems(\n\t\t\t\titemIds,\n\t\t\t\trequestColumns,\n\t\t\t)\n\t\t\t: null;\n\t}\n\n\tpublic addQuery (\n\t\tquery: CollectionQuery<ItemTypeType>,\n\t\trequestColumnsTuple: RequestColumnsTuple<ItemTypeType>,\n\t\toptions: RequestBufferOptions<ItemTypeType>,\n\t): this | null {\n\t\treturn (\n\t\t\tthis.options.forceFlush === options.forceFlush\n\t\t\t&& this.acceptsRequestColumns(\n\t\t\t\trequestColumnsTuple.object,\n\t\t\t)\n\t\t\t&& query.isLocallyMatchable\n\t\t)\n\t\t\t? this._addQuery(\n\t\t\t\tquery as CollectionQuery<ItemTypeType, true>,\n\t\t\t\trequestColumnsTuple,\n\t\t\t)\n\t\t\t: null;\n\t}\n\n\tprotected override async executeQuery (): Promise<RequestBufferResult<ItemTypeType>> {\n\t\tconst requestColumns = this.requestColumnExpansion.get();\n\t\tconst response = await this.apiRequestService.query(\n\t\t\tthis.itemType,\n\t\t\tthis.createAggregateQuery(),\n\t\t\trequestColumns,\n\t\t);\n\n\t\treturn {\n\t\t\trequestColumns,\n\t\t\tresponse,\n\t\t\tnonLocallyMatchableQueryString: null,\n\t\t};\n\t}\n\n\tprivate _addSingleItems (\n\t\titemIds: ItemId[],\n\t\trequestColumns: ApiRequestColumns<ItemTypeType>,\n\t): this {\n\t\tthis.requestColumnExpansion.expandWithRequestColumns(\n\t\t\tthis.itemType,\n\t\t\trequestColumns,\n\t\t);\n\n\t\tfor (const itemId of itemIds) {\n\t\t\tthis.contents.singleItemIds.add(\n\t\t\t\titemId,\n\t\t\t);\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tprivate _addQuery (\n\t\tquery: CollectionQuery<ItemTypeType, true>,\n\t\trequestColumnsTuple: RequestColumnsTuple<ItemTypeType>,\n\t): this {\n\t\tthis.contents.queries.set(\n\t\t\tquery.string,\n\t\t\tquery,\n\t\t);\n\n\t\tthis.requestColumnExpansion.expandWithRequestColumnsTuple(\n\t\t\tthis.itemType,\n\t\t\trequestColumnsTuple,\n\t\t);\n\n\t\treturn this;\n\t}\n\n\tprivate createAggregateQuery (): BackendApiQuery<ItemTypeType> {\n\t\tconst contents = this.contents;\n\n\t\tif (\n\t\t\tcontents === undefined\n\t\t\t|| (\n\t\t\t\tcontents.queries.size === 0\n\t\t\t\t&& contents.singleItemIds.size === 0\n\t\t\t)\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t'Tried to flush a RequestBuffer without singleItems or queries',\n\t\t\t);\n\t\t}\n\n\t\tconst conditions: ApiQuery<ItemTypeType>[] = [];\n\n\t\tif (contents.singleItemIds.size > 0) {\n\t\t\tconditions.push(\n\t\t\t\t{\n\t\t\t\t\tkey: 'id',\n\t\t\t\t\tcomparator: 'IN',\n\t\t\t\t\tvalue: [\n\t\t\t\t\t\t...contents.singleItemIds.values(),\n\t\t\t\t\t],\n\t\t\t\t} as ApiQueryConditionIn<ItemTypeType, 'id'>,\n\t\t\t);\n\t\t}\n\n\t\tfor (const query of contents.queries.values()) {\n\t\t\tconditions.push(\n\t\t\t\tquery.object,\n\t\t\t);\n\t\t}\n\n\t\treturn conditions.length === 1\n\t\t\t? conditions[0] as BackendApiQuery<ItemTypeType>\n\t\t\t: {\n\t\t\t\tconditions: conditions as BackendApiQuery<ItemTypeType>[],\n\t\t\t\toperator: 'OR',\n\t\t\t};\n\t}\n\n}\n","import { ApiItemType, BackendApiQuery } from '@rentman/backend-types';\nimport { ApiRequestService, CollectionQuery, RequestBufferBase, RequestBufferOptions, RequestBufferResult, RequestColumnExpansionFactory, RequestColumnsTuple } from '../../internal';\n\nexport class SingleQueryRequestBuffer<ItemTypeType extends ApiItemType>\n\textends RequestBufferBase<ItemTypeType> {\n\n\tpublic constructor (\n\t\tapiRequestService: ApiRequestService,\n\t\trequestColumnExpansionFactory: RequestColumnExpansionFactory,\n\t\titemType: ItemTypeType,\n\t\t/**\n\t\t * When we store a query that cannot be matched locally, we cannot store any other queries because we depend on the\n\t\t * response to figure out what items match.\n\t\t */\n\t\tprivate readonly contents: CollectionQuery<ItemTypeType>,\n\t\trequestColumnsTuple: RequestColumnsTuple<ItemTypeType>,\n\t\toptions: RequestBufferOptions<ItemTypeType>,\n\t) {\n\t\tsuper(\n\t\t\tapiRequestService,\n\t\t\trequestColumnExpansionFactory,\n\t\t\titemType,\n\t\t\toptions,\n\t\t);\n\n\t\tthis.requestColumnExpansion.expandWithRequestColumnsTuple(\n\t\t\tthis.itemType,\n\t\t\trequestColumnsTuple,\n\t\t);\n\t}\n\n\tpublic override addSingleItems (): null {\n\t\treturn null;\n\t}\n\n\tpublic override addQuery (\n\t\tquery: CollectionQuery<ItemTypeType>,\n\t\trequestColumnsTuple: RequestColumnsTuple<ItemTypeType>,\n\t\toptions: RequestBufferOptions<ItemTypeType>,\n\t): this | null {\n\t\tif (\n\t\t\tthis.options.forceFlush === options.forceFlush\n\t\t\t&& this.compareApiRequestLimit(\n\t\t\t\tthis.options.limit,\n\t\t\t\toptions.limit,\n\t\t\t)\n\t\t\t&& this.acceptsRequestColumns(\n\t\t\t\trequestColumnsTuple.object,\n\t\t\t)\n\t\t\t&& query.string === this.contents.string\n\t\t) {\n\t\t\tthis.requestColumnExpansion.expandWithRequestColumnsTuple(\n\t\t\t\tthis.itemType,\n\t\t\t\trequestColumnsTuple,\n\t\t\t);\n\n\t\t\treturn this;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tprotected override async executeQuery (): Promise<RequestBufferResult<ItemTypeType>> {\n\t\tconst requestColumns = this.requestColumnExpansion.get();\n\t\tconst response = await this.apiRequestService.query(\n\t\t\tthis.itemType,\n\t\t\tthis.contents.object as BackendApiQuery<ItemTypeType>,\n\t\t\trequestColumns,\n\t\t\tthis.options.limit,\n\t\t);\n\n\t\treturn {\n\t\t\trequestColumns,\n\t\t\tresponse,\n\t\t\tnonLocallyMatchableQueryString: this.contents.isLocallyMatchable\n\t\t\t\t? null\n\t\t\t\t: this.contents.string,\n\t\t};\n\t}\n\n}\n","import { ApiItemType, ItemId } from '@rentman/backend-types';\nimport { ApiRequestColumns, ApiRequestService, CollectionQuery, defaultRequestBufferOptions, RequestBuffer, RequestBufferBase, RequestBufferOptions, RequestBufferResult, RequestColumnExpansionFactory, RequestColumnsTuple, SingleQueryRequestBuffer } from '../../internal';\n\nexport class RequestBufferManager {\n\n\tprivate pendingBufferMap: {\n\t\t[ItemTypeType in ApiItemType]?: RequestBufferBase<ItemTypeType>[]\n\t} = {};\n\n\t/**\n\t * Because we're not saving multiple transactions simultaneously, we can get by with a simple flag here.\n\t */\n\tprivate requestsSuspended: boolean = false;\n\n\tpublic constructor (\n\t\tprivate apiRequestService: ApiRequestService,\n\t\tprivate requestColumnExpansionFactory: RequestColumnExpansionFactory,\n\t\tprivate onBufferFlushed?: (\n\t\t\tresult: RequestBufferResult<any>,\n\t\t) => Promise<any>,\n\t) {\n\n\t}\n\n\t/**\n\t * We could make this extra safe by waiting for responses to arrive for requests that are in-flight.\n\t * However, this comes at a performance cost, as we have to wait longer before saving our changes.\n\t */\n\tpublic suspendRequests (): void {\n\t\tthis.requestsSuspended = true;\n\t}\n\n\tpublic continueRequests (): void {\n\t\tthis.requestsSuspended = false;\n\n\t\tthis.flushPendingBuffers();\n\t}\n\n\tpublic fetchByIds<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\titemIds: ItemId[],\n\t\trequestColumns: ApiRequestColumns<ItemTypeType>,\n\t\tpartialOptions?: Partial<RequestBufferOptions<ItemTypeType>>,\n\t): Promise<RequestBufferResult<ItemTypeType>> {\n\t\tconst options = this.processOptions(\n\t\t\tpartialOptions,\n\t\t);\n\t\tconst pendingBuffers = this.pendingBufferMap[itemType];\n\n\t\tif (pendingBuffers !== undefined) {\n\t\t\tfor (const pendingBuffer of pendingBuffers) {\n\t\t\t\tif (\n\t\t\t\t\tpendingBuffer.addSingleItems(\n\t\t\t\t\t\titemIds,\n\t\t\t\t\t\trequestColumns,\n\t\t\t\t\t\toptions.forceFlush,\n\t\t\t\t\t) !== null\n\t\t\t\t) {\n\t\t\t\t\treturn pendingBuffer.getPromise();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this.addBuffer(\n\t\t\tRequestBuffer.constructWithSingleItems(\n\t\t\t\tthis.apiRequestService,\n\t\t\t\tthis.requestColumnExpansionFactory,\n\t\t\t\titemType,\n\t\t\t\titemIds,\n\t\t\t\trequestColumns,\n\t\t\t\toptions,\n\t\t\t),\n\t\t);\n\t}\n\n\tpublic fetchByQuery<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\t// queryParser result\n\t\tquery: CollectionQuery<ItemTypeType>,\n\t\trequestColumnsTuple: RequestColumnsTuple<ItemTypeType>,\n\t\tpartialOptions: Partial<RequestBufferOptions<ItemTypeType>> = {},\n\t): Promise<RequestBufferResult<ItemTypeType>> {\n\t\tconst options = this.processOptions(\n\t\t\tpartialOptions,\n\t\t);\n\t\tconst pendingBuffers = this.pendingBufferMap[itemType];\n\n\t\tif (pendingBuffers !== undefined) {\n\t\t\tfor (const pendingBuffer of pendingBuffers) {\n\t\t\t\tif (\n\t\t\t\t\tpendingBuffer.addQuery(\n\t\t\t\t\t\tquery,\n\t\t\t\t\t\trequestColumnsTuple,\n\t\t\t\t\t\toptions,\n\t\t\t\t\t) !== null\n\t\t\t\t) {\n\t\t\t\t\treturn pendingBuffer.getPromise();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this.addBuffer(\n\t\t\t(\n\t\t\t\tquery.isLocallyMatchable\n\t\t\t\t&& options.limit === undefined\n\t\t\t\t&& partialOptions.flushTimeout !== 0\n\t\t\t)\n\t\t\t\t? RequestBuffer.constructWithQuery(\n\t\t\t\t\tthis.apiRequestService,\n\t\t\t\t\tthis.requestColumnExpansionFactory,\n\t\t\t\t\titemType,\n\t\t\t\t\tquery as CollectionQuery<ItemTypeType, true>,\n\t\t\t\t\trequestColumnsTuple,\n\t\t\t\t\toptions,\n\t\t\t\t)\n\t\t\t\t: new SingleQueryRequestBuffer(\n\t\t\t\t\tthis.apiRequestService,\n\t\t\t\t\tthis.requestColumnExpansionFactory,\n\t\t\t\t\titemType,\n\t\t\t\t\tquery as CollectionQuery<ItemTypeType, false>,\n\t\t\t\t\trequestColumnsTuple,\n\t\t\t\t\toptions,\n\t\t\t\t),\n\t\t);\n\t}\n\n\tprivate processOptions<ItemTypeType extends ApiItemType> (\n\t\tpartialOptions: Partial<RequestBufferOptions<ItemTypeType>> = {},\n\t): RequestBufferOptions<ItemTypeType> {\n\t\tconst result: Partial<RequestBufferOptions<ItemTypeType>> = {};\n\n\t\tlet key: keyof RequestBufferOptions<ItemTypeType>;\n\n\t\t// We cannot use an object spread here because `partialOptions` might contain the literal `undefined` value.\n\t\tfor (key in defaultRequestBufferOptions) {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n\t\t\t(result[key] as RequestBufferOptions<ItemTypeType>[keyof RequestBufferOptions<ItemTypeType>]) = partialOptions[key] !== undefined\n\t\t\t\t? partialOptions[key]\n\t\t\t\t: defaultRequestBufferOptions[key];\n\t\t}\n\n\t\treturn result as RequestBufferOptions<ItemTypeType>;\n\t}\n\n\tprivate addBuffer<ItemTypeType extends ApiItemType> (\n\t\tbuffer: RequestBufferBase<ItemTypeType>,\n\t): Promise<RequestBufferResult<ItemTypeType>> {\n\t\tlet pendingBuffers = this.pendingBufferMap[buffer.itemType];\n\n\t\tif (pendingBuffers === undefined) {\n\t\t\tpendingBuffers = this.pendingBufferMap[buffer.itemType] = [];\n\t\t}\n\n\t\tpendingBuffers.push(\n\t\t\tbuffer,\n\t\t);\n\n\t\tif (buffer.options.flushTimeout > 0) {\n\t\t\twindow.setTimeout(\n\t\t\t\t() => {\n\t\t\t\t\tthis.flushPendingBuffers();\n\t\t\t\t},\n\t\t\t\tbuffer.options.flushTimeout,\n\t\t\t);\n\t\t} else {\n\t\t\tthis.flushPendingBuffers();\n\t\t}\n\n\t\treturn buffer.getPromise();\n\t}\n\n\tprivate flushPendingBuffers (): void {\n\t\tconst currentDate = Date.now();\n\n\t\tfor (const itemType in this.pendingBufferMap) {\n\t\t\tconst pendingBuffers = this.pendingBufferMap[itemType as ApiItemType]!;\n\t\t\tconst remainingPendingBuffers: RequestBufferBase<any>[] = [];\n\n\t\t\tfor (const pendingBuffer of pendingBuffers) {\n\t\t\t\tif (\n\t\t\t\t\t(\n\t\t\t\t\t\t!this.requestsSuspended\n\t\t\t\t\t\t|| pendingBuffer.options.forceFlush\n\t\t\t\t\t)\n\t\t\t\t\t&& currentDate - pendingBuffer.createdDate >= pendingBuffer.options.flushTimeout\n\t\t\t\t) {\n\t\t\t\t\tvoid pendingBuffer.flush(\n\t\t\t\t\t\tthis.onBufferFlushed,\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tremainingPendingBuffers.push(\n\t\t\t\t\t\tpendingBuffer,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (remainingPendingBuffers.length === 0) {\n\t\t\t\tdelete this.pendingBufferMap[itemType];\n\t\t\t} else {\n\t\t\t\tthis.pendingBufferMap[itemType] = remainingPendingBuffers;\n\t\t\t}\n\t\t}\n\t}\n\n}\n","import { ApiFields, ApiItemType, ItemId } from '@rentman/backend-types';\nimport { ChangesDelta, ColumnSet, ConversionMapService, EntryParentNull, FieldMap, FilterItemEntryCallback, ItemIdConversionMap, KeyService, ModifyFieldsCallback, RequestParameters, Template, TemplateCache } from '../internal';\n\nexport class ItemCreateService {\n\n\tpublic constructor (\n\t\tprivate conversionMapService: ConversionMapService,\n\t\tprivate templateCache: TemplateCache,\n\t) {\n\n\t}\n\n\t/**\n\t * @description\n\t * Fetches a new {@link Template template} and sets the items created on the passed {@link ChangesDelta}\n\t */\n\tpublic createItemsFromValues<ItemTypeType extends ApiItemType, ColumnIds extends (\n\t\tkeyof ApiFields[ItemTypeType])[] = (keyof ApiFields[ItemTypeType])[]> (\n\t\tchangesDelta: ChangesDelta,\n\t\titemType: ItemTypeType,\n\t\tvaluesArray: Partial<FieldMap<ItemTypeType, ColumnIds>>[],\n\t\tparent: EntryParentNull = null,\n\t\ttemplateOptions: Partial<RequestParameters<ItemTypeType>> = {},\n\t): Promise<void[]> {\n\t\tif (valuesArray.length === 0) {\n\t\t\treturn Promise.resolve(\n\t\t\t\t[],\n\t\t\t);\n\t\t}\n\n\t\tconst promises: any[] = [];\n\n\t\tfor (const values of valuesArray) {\n\t\t\tconst itemId: ItemId = Object.prototype.hasOwnProperty.call(\n\t\t\t\tvalues,\n\t\t\t\t'id',\n\t\t\t)\n\t\t\t\t// @ts-ignore we check if id is on values\n\t\t\t\t? values.id\n\t\t\t\t: KeyService.getLocalId();\n\n\t\t\tpromises.push(\n\t\t\t\tthis.templateCache\n\t\t\t\t\t.fetchTemplate(\n\t\t\t\t\t\titemType,\n\t\t\t\t\t\titemId,\n\t\t\t\t\t\ttemplateOptions,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Ensure the columns we're trying to set are there\n\t\t\t\t\t\t\t[itemType]: Object.keys(\n\t\t\t\t\t\t\t\tvaluesArray[0] as any,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tparent,\n\t\t\t\t\t)\n\t\t\t\t\t.then(\n\t\t\t\t\t\t(\n\t\t\t\t\t\t\ttemplate: Template<ItemTypeType>,\n\t\t\t\t\t\t) => {\n\t\t\t\t\t\t\tthis.processTemplate(\n\t\t\t\t\t\t\t\tchangesDelta,\n\t\t\t\t\t\t\t\titemType,\n\t\t\t\t\t\t\t\titemId,\n\t\t\t\t\t\t\t\tparent,\n\t\t\t\t\t\t\t\ttemplate,\n\t\t\t\t\t\t\t\t() => true,\n\t\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\t\t_itemType: ApiItemType,\n\t\t\t\t\t\t\t\t\tfields,\n\t\t\t\t\t\t\t\t) => {\n\t\t\t\t\t\t\t\t\tif (_itemType !== itemType) {\n\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tfor (const columnId in values) {\n\t\t\t\t\t\t\t\t\t\tfields[columnId] = values[columnId];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t},\n\t\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\treturn Promise.all(\n\t\t\tpromises,\n\t\t);\n\t}\n\n\tpublic processTemplate<ItemTypeType extends ApiItemType> (\n\t\tchangesDelta: ChangesDelta,\n\t\titemType: ItemTypeType,\n\t\titemId: ItemId,\n\t\tparent: EntryParentNull,\n\t\ttemplate: Template<ItemTypeType>,\n\t\tfilterItemEntryCallback: FilterItemEntryCallback = () => true,\n\t\tmodifyFieldsCallback?: ModifyFieldsCallback,\n\t\tisRoot: boolean = false,\n\t): void {\n\t\tconst itemIdConversion: ItemIdConversionMap = this.conversionMapService.createLocalConversionMap(\n\t\t\titemType,\n\t\t\titemId,\n\t\t\ttemplate.response,\n\t\t);\n\n\t\tfor (const linkItemType in template.response.links) {\n\t\t\tconst columnSet = template.getColumnSet(\n\t\t\t\tlinkItemType as ApiItemType,\n\t\t\t);\n\n\t\t\tfor (const apiItemId of template.response.links[linkItemType]) {\n\t\t\t\tconst newItemId = itemIdConversion[linkItemType][apiItemId];\n\n\t\t\t\tconst fields = template.getFields(\n\t\t\t\t\tlinkItemType as ApiItemType,\n\t\t\t\t\tapiItemId,\n\t\t\t\t);\n\n\t\t\t\tthis.conversionMapService.updateItemValues(\n\t\t\t\t\tfields,\n\t\t\t\t\tfields,\n\t\t\t\t\tcolumnSet.item.main,\n\t\t\t\t\titemIdConversion,\n\t\t\t\t\tparent,\n\t\t\t\t);\n\n\t\t\t\tmodifyFieldsCallback?.(\n\t\t\t\t\tlinkItemType,\n\t\t\t\t\tfields,\n\t\t\t\t\titemIdConversion,\n\t\t\t\t);\n\n\t\t\t\tchangesDelta._setItemCreated(\n\t\t\t\t\tnewItemId,\n\t\t\t\t\tfields,\n\t\t\t\t\tcolumnSet,\n\t\t\t\t\tparent,\n\t\t\t\t\titemType === linkItemType && isRoot,\n\t\t\t\t);\n\n\t\t\t\tthis.processTemplateLinkItems(\n\t\t\t\t\tchangesDelta,\n\t\t\t\t\tlinkItemType as ApiItemType,\n\t\t\t\t\tnewItemId,\n\t\t\t\t\ttemplate,\n\t\t\t\t\titemIdConversion,\n\t\t\t\t\tfilterItemEntryCallback,\n\t\t\t\t\tmodifyFieldsCallback,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic processTemplateLinkItems<ParentItemType extends ApiItemType> (\n\t\tchangesDelta: ChangesDelta,\n\t\tparentType: ParentItemType,\n\t\tlocalParentId: ItemId,\n\t\ttemplate: Template<any>,\n\t\titemIdConversion: ItemIdConversionMap,\n\t\tfilterItemEntryCallback: FilterItemEntryCallback = () => true,\n\t\tmodifyFieldsCallback?: ModifyFieldsCallback,\n\t): void {\n\t\tconst columnSetMap: {\n\t\t\t[itemType in ApiItemType]?: ColumnSet<itemType>\n\t\t} = {};\n\n\t\tconst createEntries = (\n\t\t\t_parentType: ApiItemType,\n\t\t\t_localParentId: ItemId,\n\t\t\tapiParentId: ItemId,\n\t\t) => {\n\t\t\tconst parent = {\n\t\t\t\titemType: _parentType,\n\t\t\t\titemId: _localParentId,\n\t\t\t};\n\n\t\t\tconst links = template.response.items[_parentType][apiParentId].links;\n\n\t\t\tfor (const itemType in links) {\n\t\t\t\tif (\n\t\t\t\t\t!Object.prototype.hasOwnProperty.call(\n\t\t\t\t\t\tlinks,\n\t\t\t\t\t\titemType,\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (columnSetMap[itemType] === undefined) {\n\t\t\t\t\tcolumnSetMap[itemType] = template.getColumnSet(\n\t\t\t\t\t\titemType as ApiItemType,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tfor (const apiItemId of links[itemType]) {\n\t\t\t\t\tconst fields = template.getFields(\n\t\t\t\t\t\titemType as ApiItemType,\n\t\t\t\t\t\tapiItemId,\n\t\t\t\t\t);\n\n\t\t\t\t\tif (\n\t\t\t\t\t\t!filterItemEntryCallback(\n\t\t\t\t\t\t\titemType as ApiItemType,\n\t\t\t\t\t\t\tfields,\n\t\t\t\t\t\t)\n\t\t\t\t\t) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst localItemId = itemIdConversion[itemType][apiItemId];\n\n\t\t\t\t\tthis.conversionMapService.updateItemValues(\n\t\t\t\t\t\tfields,\n\t\t\t\t\t\tfields,\n\t\t\t\t\t\tcolumnSetMap[itemType].item.main,\n\t\t\t\t\t\titemIdConversion,\n\t\t\t\t\t\tparent,\n\t\t\t\t\t);\n\n\t\t\t\t\tif (modifyFieldsCallback !== undefined) {\n\t\t\t\t\t\tmodifyFieldsCallback(\n\t\t\t\t\t\t\titemType as ApiItemType,\n\t\t\t\t\t\t\tfields,\n\t\t\t\t\t\t\titemIdConversion,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tchangesDelta._setItemCreated(\n\t\t\t\t\t\tlocalItemId,\n\t\t\t\t\t\tfields,\n\t\t\t\t\t\tcolumnSetMap[itemType],\n\t\t\t\t\t\tparent,\n\t\t\t\t\t);\n\n\t\t\t\t\tcreateEntries(\n\t\t\t\t\t\titemType as ApiItemType,\n\t\t\t\t\t\tlocalItemId,\n\t\t\t\t\t\tapiItemId,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tcreateEntries(\n\t\t\tparentType,\n\t\t\tlocalParentId,\n\t\t\ttemplate.response.links[parentType][0],\n\t\t);\n\t}\n\n}\n","import { ApiItemType, ItemId } from '@rentman/backend-types';\nimport { ColumnSet, FieldMap, hasProperties } from '../internal';\nimport { MatchesAccumulator } from './matcher/QueryNode';\nimport { RootQueryNode } from './matcher/RootQueryNode';\n\nexport type ChangesDeltaItemCreateDelta<ItemTypeType extends ApiItemType = any> = {\n\titemId: ItemId,\n\tfields: FieldMap<ItemTypeType>,\n\tcolumns: ColumnSet<ItemTypeType>,\n\tisRoot: boolean,\n};\n\nexport class CreatedChangesDelta {\n\n\tprivate tuples: {\n\t\t[itemType: string]: Map<ItemId, ChangesDeltaItemCreateDelta> | undefined,\n\t} = {};\n\n\tpublic remove (\n\t\titemType: ApiItemType,\n\t\titemId: ItemId,\n\t): boolean {\n\t\tif (this.tuples[itemType] === undefined) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (\n\t\t\t!this.tuples[itemType].has(\n\t\t\t\titemId,\n\t\t\t)\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\tthis.tuples[itemType].delete(\n\t\t\titemId,\n\t\t);\n\n\t\treturn true;\n\t}\n\n\tpublic add<ItemTypeType extends ApiItemType> (\n\t\titemId: ItemId,\n\t\tfields: Partial<FieldMap<ItemTypeType>>,\n\t\tcolumns: ColumnSet<ItemTypeType>,\n\t\tisRoot: boolean = false,\n\t): void {\n\t\tconst itemType = columns.itemType;\n\n\t\tif (this.tuples[itemType] === undefined) {\n\t\t\tthis.tuples[itemType] = new Map();\n\t\t}\n\n\t\tconst foundTuple = this.tuples[itemType].get(\n\t\t\titemId,\n\t\t);\n\n\t\tif (foundTuple === undefined) {\n\t\t\tthis.tuples[itemType].set(\n\t\t\t\titemId,\n\t\t\t\t{\n\t\t\t\t\titemId: itemId,\n\t\t\t\t\tfields: fields,\n\t\t\t\t\tcolumns: columns,\n\t\t\t\t\tisRoot: isRoot,\n\t\t\t\t},\n\t\t\t);\n\n\t\t\treturn;\n\t\t}\n\n\t\tfoundTuple.columns = foundTuple.columns.expand(\n\t\t\tcolumns.request,\n\t\t\tcolumns.requestColumnsTrue,\n\t\t\tcolumns.response,\n\t\t).merged;\n\n\t\tfor (const columnId in fields) {\n\t\t\tfoundTuple.fields[columnId] = fields[columnId];\n\t\t}\n\t}\n\n\tpublic isEmpty (): boolean {\n\t\treturn !hasProperties(\n\t\t\tthis.tuples,\n\t\t);\n\t}\n\n\tpublic getTuplesIterator<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t): IterableIterator<ChangesDeltaItemCreateDelta<ItemTypeType>> {\n\t\tconst tuples = this.tuples[itemType];\n\n\t\tif (tuples === undefined) {\n\t\t\treturn {\n\t\t\t\tnext: function () {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tvalue: undefined,\n\t\t\t\t\t\tdone: true,\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t\t[Symbol.iterator]: function () {\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\treturn tuples.values();\n\t}\n\n\t// TODO: Replace with iterator.\n\tpublic forEach (\n\t\tcallback: (\n\t\t\ttuple: ChangesDeltaItemCreateDelta,\n\t\t\titemType: ApiItemType,\n\t\t) => void,\n\t): void {\n\t\tfor (const itemType in this.tuples) {\n\t\t\tconst tuplesEntry = this.tuples[itemType];\n\n\t\t\tfor (const tuple of tuplesEntry!.values()) {\n\t\t\t\tcallback(\n\t\t\t\t\ttuple,\n\t\t\t\t\titemType as ApiItemType,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t// TODO: Replace with `getIterator()`.\n\tpublic forEachOfItemType (\n\t\titemType: ApiItemType,\n\t\tcallback: (\n\t\t\ttuple: ChangesDeltaItemCreateDelta,\n\t\t) => void,\n\t): void {\n\t\tconst tuplesEntry = this.tuples[itemType];\n\n\t\tif (tuplesEntry === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const tuple of tuplesEntry.values()) {\n\t\t\tcallback(\n\t\t\t\ttuple,\n\t\t\t);\n\t\t}\n\t}\n\n\tpublic contains (\n\t\titemType: ApiItemType,\n\t): boolean {\n\t\treturn this.tuples[itemType] !== undefined;\n\t}\n\n\tpublic getTupleByItemId<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\titemId: ItemId,\n\t): ChangesDeltaItemCreateDelta<ItemTypeType> | undefined {\n\t\tconst tuples = this.tuples[itemType];\n\n\t\tif (tuples === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn tuples.get(\n\t\t\titemId,\n\t\t);\n\t}\n\n\tpublic matchTuplesToQueryGraph<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tqueryGraph: RootQueryNode<ItemTypeType>,\n\t\tmatchesAccumulator: MatchesAccumulator<ChangesDeltaItemCreateDelta<ItemTypeType>>,\n\t): MatchesAccumulator<ChangesDeltaItemCreateDelta<ItemTypeType>> {\n\t\tconst tuples = this.tuples[itemType];\n\n\t\tif (tuples === undefined) {\n\t\t\treturn matchesAccumulator;\n\t\t}\n\n\t\tfor (const tuple of tuples.values()) {\n\t\t\tqueryGraph.doMatch(\n\t\t\t\ttuple,\n\t\t\t\tcolumnId => tuple.fields[columnId],\n\t\t\t\tmatchesAccumulator,\n\t\t\t);\n\t\t}\n\n\t\treturn matchesAccumulator;\n\t}\n\n}\n","import { ApiItemType, ItemId, ResponseColumn } from '@rentman/backend-types';\nimport { ApiRequestColumn, ApiRequestColumnArrayMap, ApiRequestService, ApiResponseProcessor, ColumnHandler, ColumnSetFactory, ColumnUtil, EntryParentNull, hasProperties, ItemEntryService, LinkTreeServiceInterface, RequestColumnExpansion, RequestColumnExpansionFactory, RequestParameters, ResponseColumnItemTypeMap, Template } from '../internal';\n\nexport class TemplateCache {\n\n\tprivate pendingTemplateBufferMap: {\n\t\t[itemType: string]: {\n\t\t\t[localItemId: string]: Promise<ApiResponseProcessor>,\n\t\t},\n\t} = {};\n\n\tprivate templateResponses: {\n\t\t[itemType: string]: ApiResponseProcessor,\n\t} = {};\n\n\tpublic constructor (\n\t\tprivate apiRequestService: ApiRequestService,\n\t\tprivate columnHandler: ColumnHandler,\n\t\tprivate columnSetFactory: ColumnSetFactory,\n\t\tprivate requestColumnExpansionFactory: RequestColumnExpansionFactory,\n\t\tprivate linkTreeService: LinkTreeServiceInterface,\n\t\tprivate itemEntryService: ItemEntryService,\n\t) {\n\n\t}\n\n\t/**\n\t * @description\n\t * Fetches a {@link Template template}, use {@link ItemCreateService.createItemsFromValues createItemsFromValues} to easily create new items from a set of values.\n\t * The best way to process the template's values is to call {@link ItemCreateService.processTemplate processTemplate}\n\t *\n\t * @param itemType The {@link ApiItemType ItemType} of the template item\n\t * @param itemId Used for caching, multiple concurrent template calls for the same itemId will return the same template\n\t * @param templateOptions\n\t * @param templateRequestColumns Additional columns to be fetched, will be stored in the template - warning - the Template won't have values for those columns\n\t * @param entryParentOrParentItemType An optional {@link EntryParentNull entry parent} or {@link ApiItemType parent itemType}, if the parent is passed the templateColumns will be expanded with the proper link columns (Through {@link ColumnUtil.getColumnsFromLink ColumnUtil.getColumnsFromLink})\n\t *\n\t * @example\n\t * ```\n\t * const parent: EntryParent = {\n\t * itemType: 'Functie',\n\t * itemId: 10,\n\t * };\n\t *\n\t * return core.templateCache\n\t * .fetchTemplate(\n\t * 'Planningpersoneel',\n\t * undefined,\n\t * {},\n\t * {},\n\t * parent,\n\t * )\n\t * .then(\n\t * (template: Template<'Planningpersoneel'>) => {\n\t * const changesDelta = transaction.createChangesDelta();\n\t *\n\t * for (const itemResource of selectedItems) {\n\t * changesDelta.setItemCreated(\n\t * core.keyService.getLocalId(),\n\t * template.getFields(),\n\t * template.columns,\n\t * parent,\n\t * );\n\t * }\n\t *\n\t * return transaction.applyChangesDelta(changesDelta);\n\t * );\n\t * ```\n\t */\n\tpublic fetchTemplate<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\titemId?: ItemId,\n\t\ttemplateOptions: Partial<RequestParameters<ItemTypeType>> = {},\n\t\ttemplateRequestColumns: ApiRequestColumnArrayMap = {},\n\t\tentryParentOrParentItemType: EntryParentNull | ApiItemType = null,\n\t): Promise<Template<ItemTypeType>> {\n\t\tlet templateResponse: ApiResponseProcessor<ItemTypeType>;\n\n\t\tconst hasTemplateOptions = hasProperties(\n\t\t\ttemplateOptions,\n\t\t);\n\n\t\tlet templateResponsePromise: Promise<ApiResponseProcessor<ItemTypeType>>;\n\n\t\tif (\n\t\t\t!hasTemplateOptions\n\t\t\t&& this.templateResponses[itemType] !== undefined\n\t\t) {\n\t\t\ttemplateResponsePromise = Promise.resolve(\n\t\t\t\tthis.templateResponses[itemType],\n\t\t\t);\n\t\t} else {\n\t\t\ttemplateResponsePromise = this.fetchTemplateById(\n\t\t\t\titemType,\n\t\t\t\titemId,\n\t\t\t\ttemplateOptions,\n\t\t\t);\n\t\t}\n\n\t\tconst requestColumnExpansion: RequestColumnExpansion = this.requestColumnExpansionFactory.construct();\n\n\t\treturn templateResponsePromise\n\t\t\t.then(\n\t\t\t\tresponse => {\n\t\t\t\t\ttemplateResponse = response;\n\n\t\t\t\t\t// We cache the response columns in case they are required in any other place\n\t\t\t\t\tfor (const responseItemType in templateResponse.columns) {\n\t\t\t\t\t\tfor (const column of templateResponse.columns[responseItemType]) {\n\t\t\t\t\t\t\tthis.columnHandler.setColumn(\n\t\t\t\t\t\t\t\tresponseItemType as ApiItemType,\n\t\t\t\t\t\t\t\tcolumn as ResponseColumn<any>,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// If the template has options we cannot cache it, since different options can give different results\n\t\t\t\t\tif (!hasTemplateOptions && templateResponse.cacheable) {\n\t\t\t\t\t\tthis.templateResponses[itemType] = response;\n\t\t\t\t\t}\n\n\t\t\t\t\t// We expand the request columns with the template request columns, so that these are present for processing afterwards\n\t\t\t\t\tfor (const requestColumnItemType in templateRequestColumns) {\n\t\t\t\t\t\trequestColumnExpansion.expandWithRequestColumns(\n\t\t\t\t\t\t\trequestColumnItemType as ApiItemType,\n\t\t\t\t\t\t\ttemplateRequestColumns[requestColumnItemType],\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\t// We always request the creator, created and permissions because these set by ItemEntryService.getLocalDefaultValues\n\t\t\t\t\tthis.expandWithDefaultRequestColumns(\n\t\t\t\t\t\trequestColumnExpansion,\n\t\t\t\t\t\titemType,\n\t\t\t\t\t);\n\n\t\t\t\t\t// Duplicating items is done through a template request, when the duplicated item has linked items\n\t\t\t\t\t// those are also duplicated. But we need the default columns for those duplicated linked items too.\n\t\t\t\t\t// So we also always request the default columns for all child items that we get back in the template.\n\t\t\t\t\tthis.expandWithLinkedItemTypesDefaultColumns(\n\t\t\t\t\t\tObject.keys(\n\t\t\t\t\t\t\ttemplateResponse.columns,\n\t\t\t\t\t\t) as ApiItemType[],\n\t\t\t\t\t\trequestColumnExpansion,\n\t\t\t\t\t);\n\n\t\t\t\t\t// If a parent is passed we need the parent columns\n\t\t\t\t\tif (entryParentOrParentItemType !== null) {\n\t\t\t\t\t\trequestColumnExpansion.expandWithRequestColumns(\n\t\t\t\t\t\t\titemType,\n\t\t\t\t\t\t\tthis.linkTreeService.getColumnsFromLink(\n\t\t\t\t\t\t\t\t(typeof entryParentOrParentItemType === 'string')\n\t\t\t\t\t\t\t\t\t? entryParentOrParentItemType\n\t\t\t\t\t\t\t\t\t: entryParentOrParentItemType.itemType,\n\t\t\t\t\t\t\t\titemType,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\t// We ensure that also all the columns which are in the template response are in there so that the fields are processed\n\t\t\t\t\tfor (const responseItemType in templateResponse.columns) {\n\t\t\t\t\t\trequestColumnExpansion.expandWithRequestColumns(\n\t\t\t\t\t\t\tresponseItemType as ApiItemType,\n\t\t\t\t\t\t\ttemplateResponse.columns[responseItemType].map(\n\t\t\t\t\t\t\t\tcolumn => column.id as ApiRequestColumn,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst templateRequestColumnItemTypeMap = requestColumnExpansion.get();\n\n\t\t\t\t\tconst promises: Promise<ResponseColumnItemTypeMap>[] = [];\n\n\t\t\t\t\tfor (const requestColumnItemType in templateRequestColumnItemTypeMap) {\n\t\t\t\t\t\tpromises.push(\n\t\t\t\t\t\t\tthis.columnHandler.fetch(\n\t\t\t\t\t\t\t\trequestColumnItemType as ApiItemType,\n\t\t\t\t\t\t\t\ttemplateRequestColumnItemTypeMap[requestColumnItemType],\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn Promise.all(\n\t\t\t\t\t\tpromises,\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t)\n\t\t\t.then(\n\t\t\t\tresolvedColumnsArray => {\n\t\t\t\t\tlet additionalResponseColumns: ResponseColumnItemTypeMap = {} as ResponseColumnItemTypeMap;\n\n\t\t\t\t\tfor (const resolvedColumns of resolvedColumnsArray) {\n\t\t\t\t\t\tadditionalResponseColumns = ColumnUtil.mergeResponseColumns(\n\t\t\t\t\t\t\tadditionalResponseColumns,\n\t\t\t\t\t\t\tresolvedColumns,\n\t\t\t\t\t\t).merged;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn new Template(\n\t\t\t\t\t\titemType,\n\t\t\t\t\t\ttemplateResponse,\n\t\t\t\t\t\tthis.columnSetFactory,\n\t\t\t\t\t\tthis.itemEntryService,\n\t\t\t\t\t\tadditionalResponseColumns,\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t);\n\t}\n\n\tprivate expandWithLinkedItemTypesDefaultColumns (\n\t\tchildItemTypes: ApiItemType[],\n\t\trequestColumnExpansion: RequestColumnExpansion,\n\t): void {\n\t\tfor (const childItemType of childItemTypes) {\n\t\t\tthis.expandWithDefaultRequestColumns(\n\t\t\t\trequestColumnExpansion,\n\t\t\t\tchildItemType,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate fetchTemplateById<ItemTypeType extends ApiItemType = any> (\n\t\titemType: ItemTypeType,\n\t\titemId: ItemId | string = 'no-id',\n\t\ttemplateOptions?: Partial<RequestParameters<ItemTypeType>>,\n\t): Promise<ApiResponseProcessor> {\n\t\tif (\n\t\t\tthis.pendingTemplateBufferMap[itemType] === undefined\n\t\t\t|| this.pendingTemplateBufferMap[itemType][itemId] === undefined\n\t\t) {\n\t\t\treturn this.constructTemplateBuffer(\n\t\t\t\titemType,\n\t\t\t\titemId,\n\t\t\t\ttemplateOptions,\n\t\t\t);\n\t\t}\n\n\t\treturn this.pendingTemplateBufferMap[itemType][itemId];\n\t}\n\n\tprivate constructTemplateBuffer<ItemTypeType extends ApiItemType = any> (\n\t\titemType: ItemTypeType,\n\t\titemId: ItemId | string,\n\t\ttemplateOptions?: Partial<RequestParameters<ItemTypeType>>,\n\t): Promise<ApiResponseProcessor> {\n\t\tif (this.pendingTemplateBufferMap[itemType] === undefined) {\n\t\t\tthis.pendingTemplateBufferMap[itemType] = {};\n\t\t}\n\n\t\treturn this.pendingTemplateBufferMap[itemType][itemId] = this.apiRequestService\n\t\t\t.template(\n\t\t\t\titemType,\n\t\t\t\ttemplateOptions,\n\t\t\t)\n\t\t\t.then(\n\t\t\t\tresponse => {\n\t\t\t\t\tdelete this.pendingTemplateBufferMap[itemType][itemId];\n\n\t\t\t\t\treturn response;\n\t\t\t\t},\n\t\t\t\terror => {\n\t\t\t\t\tdelete this.pendingTemplateBufferMap[itemType][itemId];\n\n\t\t\t\t\tthrow error;\n\t\t\t\t},\n\t\t\t);\n\t}\n\n\tprivate expandWithDefaultRequestColumns (\n\t\trequestColumnExpansion: RequestColumnExpansion,\n\t\titemType: ApiItemType,\n\t): void {\n\t\trequestColumnExpansion.expandWithRequestColumns(\n\t\t\titemType,\n\t\t\t[\n\t\t\t\t{\n\t\t\t\t\tcreator: [\n\t\t\t\t\t\t'displayname',\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t\t'created',\n\t\t\t\t'permissions',\n\t\t\t],\n\t\t);\n\t}\n\n}\n","import { ApiItemType, ItemId } from '@rentman/backend-types';\nimport { UnknownResponseColumn } from '@rentman/backend-types/dist/manual/api-response-column';\nimport { ColumnUtil, FieldMap, ItemEntry, ItemHandlerFieldsProxyTarget, ItemIdConversionMap, TransactionCache, TransactionItemHandler } from '../../internal';\n\ninterface ItemChangesListenerContextPreviousProxyTarget<ItemTypeType extends ApiItemType>\n\textends ItemHandlerFieldsProxyTarget<ItemTypeType> {\n\n\tprevious: Partial<FieldMap<ItemTypeType>>,\n}\n\nconst previousProxyHandler: ProxyHandler<ItemChangesListenerContextPreviousProxyTarget<any>> = {\n\tget: (\n\t\ttarget: ItemChangesListenerContextPreviousProxyTarget<any>,\n\t\tproperty: string,\n\t) => {\n\t\tconst previousValue = target.previous[property];\n\n\t\tif (previousValue !== undefined) {\n\t\t\treturn previousValue;\n\t\t}\n\n\t\treturn target.itemHandler.lookUpItemField(\n\t\t\ttarget.itemEntry,\n\t\t\tproperty,\n\t\t);\n\t},\n};\n\nexport type ChangesListenerContextItemResourceShape = {\n\titemType: string,\n\tentry: ItemEntry<any>,\n\ttransaction: TransactionCache,\n\tfields: {\n\t\t[columnId: string]: any,\n\t},\n};\n\nexport abstract class ItemChangesListenerContextBase<\n\tItemResourceType extends ChangesListenerContextItemResourceShape\n> {\n\n\tprotected constructor (\n\t\tpublic readonly itemResource: ItemResourceType,\n\t\t/**\n\t\t * Note that `fields` is a proxy object for the `CollectionItemChangesListenerContext` subclass.\n\t\t */\n\t\tpublic readonly fields: ItemResourceType['fields'],\n\t\tprivate readonly itemHandler: TransactionItemHandler,\n\t\tprivate readonly partialPrevious: Partial<ItemResourceType['fields']>,\n\t\tprivate readonly itemIdConversionMap: ItemIdConversionMap | undefined,\n\t\tprivate readonly isInitialCall: boolean = false,\n\t) {\n\t}\n\n\tprivate _previous?: ItemChangesListenerContextPreviousProxyTarget<any>;\n\n\t/**\n\t * `previous` is defined as a getter here because it is not used very often, and should be evaluated lazily.\n\t */\n\tpublic get previous (): ItemResourceType['fields'] {\n\t\tif (this._previous !== undefined) {\n\t\t\treturn this._previous as ItemResourceType['fields'];\n\t\t}\n\n\t\treturn (\n\t\t\tthis._previous = new Proxy(\n\t\t\t\t{\n\t\t\t\t\titemEntry: this.itemResource.entry,\n\t\t\t\t\titemHandler: this.itemHandler,\n\t\t\t\t\tprevious: this.partialPrevious,\n\t\t\t\t},\n\t\t\t\tpreviousProxyHandler,\n\t\t\t)\n\t\t) as ItemResourceType['fields'];\n\t}\n\n\t/**\n\t * Returns `false` if the field changed. If `includeItemIdConversion` is `false`, an update to an item field because\n\t * of a save is not interpreted as a change.\n\t *\n\t * When a field cannot be found, returns `true`.\n\t */\n\tpublic compareField (\n\t\tcolumnId: keyof ItemResourceType['fields'],\n\t\tincludeItemIdConversion: boolean = true,\n\t): boolean {\n\t\tconst previousValue = this.partialPrevious[columnId];\n\n\t\t// If we have no previous value for a column, we can assume there are no changes.\n\t\tif (previousValue === undefined) {\n\t\t\tif (this.isInitialCall) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tif (\n\t\t\tincludeItemIdConversion\n\t\t\t|| this.itemIdConversionMap === undefined\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst responseColumn = this.itemResource.entry.columns.response[this.itemResource.entry.itemType][columnId] as UnknownResponseColumn;\n\n\t\treturn ColumnUtil.isItemColumn(\n\t\t\t\tresponseColumn,\n\t\t\t)\n\t\t\t&& this.itemIdConversionMap[responseColumn.itemType]?.[previousValue as ItemId] !== undefined;\n\t}\n\n\t/**\n\t * Returns `false` if one of the fields changed. If `includeItemIdConversion` is `false`, an update to an item field\n\t * because of a save is not interpreted as a change.\n\t *\n\t * When a field cannot be found, returns `true`.\n\t */\n\tpublic compareFields (\n\t\tfields: (keyof ItemResourceType['fields'])[] | readonly (keyof ItemResourceType['fields'])[],\n\t\tincludeItemIdConversion?: boolean,\n\t): boolean {\n\t\tfor (const field of fields) {\n\t\t\tif (\n\t\t\t\t!this.compareField(\n\t\t\t\t\tfield,\n\t\t\t\t\tincludeItemIdConversion,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n}\n","import { ItemIdConversionMap } from '../../types/ItemTypesCollection';\nimport { TransactionItemHandler } from '../cache/transaction/TransactionItemHandler';\nimport { ChangesListenerContextItemResourceShape, ItemChangesListenerContextBase } from './ItemChangesListenerContextBase';\n\nexport class ItemChangesListenerContext<ItemResourceType extends ChangesListenerContextItemResourceShape>\n\textends ItemChangesListenerContextBase<ItemResourceType> {\n\n\tpublic constructor (\n\t\titemResource: ItemResourceType,\n\t\titemHandler: TransactionItemHandler,\n\t\tpartialPrevious: Partial<ItemResourceType['fields']>,\n\t\titemIdConversionMap: ItemIdConversionMap | undefined,\n\t\tpublic readonly isCalledAfterSocketUpdate: boolean,\n\t\tisInitialCall: boolean = false,\n\t) {\n\t\tsuper(\n\t\t\titemResource,\n\t\t\t// We're calling `collectFields` here because validators are calling `hasOwnProperty` to find out whether\n\t\t\t// a field is present. This will always be `false` when we're using a proxy object.\n\t\t\t// Fixme: Don't do this any more\n\t\t\titemHandler.collectFields(\n\t\t\t\titemResource.entry,\n\t\t\t),\n\t\t\titemHandler,\n\t\t\tpartialPrevious,\n\t\t\titemIdConversionMap,\n\t\t\tisInitialCall,\n\t\t);\n\t}\n\n}\n","import { ChangesListenerContextItemResourceShape, CollectionToItemResource, ItemChangesListenerContextBase, ItemIdConversionMap } from '../../internal';\n\nexport class CollectionItemChangesListenerContext<\n\tCollectionResourceType extends {\n\t\titems: ChangesListenerContextItemResourceShape[],\n\t}\n>\n\textends ItemChangesListenerContextBase<CollectionToItemResource<CollectionResourceType>> {\n\n\tpublic constructor (\n\t\t/**\n\t\t * @deprecated This property will be removed once the `onChange` collection callback is phased out.\n\t\t */\n\t\tpublic readonly collectionResource: CollectionResourceType,\n\t\titemResource: CollectionToItemResource<CollectionResourceType>,\n\t\t/**\n\t\t * @deprecated This property will be removed once the `onChange` collection callback is phased out.\n\t\t */\n\t\tpublic readonly isCalledAfterSocketUpdate: boolean,\n\t\t// We don't really need to type the columns of `partialPrevious`, as long as the generic of the base type is correct.\n\t\tpartialPrevious: Partial<CollectionToItemResource<CollectionResourceType>['fields']>,\n\t\titemIdConversionMap: ItemIdConversionMap | undefined,\n\t) {\n\t\tsuper(\n\t\t\titemResource,\n\t\t\titemResource.fields,\n\t\t\titemResource.transaction.itemHandler,\n\t\t\tpartialPrevious,\n\t\t\titemIdConversionMap,\n\t\t);\n\t}\n\n}\n","import { ApiItemType, ItemId } from '@rentman/backend-types';\nimport { CachedQueryItemsItemTypeTuple, ChangesDelta, ChangesDeltaItemCreateDelta, ChangesDeltaItemUpdateDelta, FieldMap, GetFieldValueType, ItemEntry, ItemHandlerFieldsProxyTarget, ItemTypeColumnId, LinkCollectionOptionsItemTypeTuple, TransactionCache } from '../../internal';\nimport { MatchesAccumulator } from '../matcher/QueryNode';\n\nexport type LatestItemColumnsArray<ItemTypeType extends ApiItemType> = readonly ItemTypeColumnId<ItemTypeType>[];\n\nexport type UpdatedLatestItem<ItemTypeType extends ApiItemType, ColumnIds extends LatestItemColumnsArray<ItemTypeType>> = {\n\titemEntry: ItemEntry<ItemTypeType>,\n\tupdatedTuple?: ChangesDeltaItemUpdateDelta<ItemTypeType>,\n\tfields: FieldMap<ItemTypeType, ColumnIds>,\n};\n\n/**\n * A 'latest' item can either be:\n * - A created changes delta (for created items).\n * - An object containing an item entry and a `fields` property (for updated items). The `fields` property will\n * read updated values from the changes delta if available.\n *\n * In both cases, we can access the latest values through the `fields` property.\n */\nexport type LatestItem<ItemTypeType extends ApiItemType, ColumnIds extends LatestItemColumnsArray<ItemTypeType>>\n\t= UpdatedLatestItem<ItemTypeType, ColumnIds> | ChangesDeltaItemCreateDelta<ItemTypeType>;\n\nconst fieldsProxyHandler: ProxyHandler<BusinessLogicRuleContextFieldsProxyTarget<any>> = {\n\tget: (\n\t\ttarget: BusinessLogicRuleContextFieldsProxyTarget<any>,\n\t\tproperty: string,\n\t) => {\n\t\tconst updatedValue = target.updatedTuple.changes.fields[property];\n\n\t\tif (updatedValue !== undefined) {\n\t\t\treturn updatedValue;\n\t\t}\n\n\t\treturn target.itemHandler.lookUpItemField(\n\t\t\ttarget.itemEntry,\n\t\t\tproperty,\n\t\t);\n\t},\n};\n\ninterface BusinessLogicRuleContextFieldsProxyTarget<ItemTypeType extends ApiItemType>\n\textends ItemHandlerFieldsProxyTarget<ItemTypeType> {\n\n\tupdatedTuple: ChangesDeltaItemUpdateDelta<ItemTypeType>,\n}\n\nexport abstract class BusinessLogicRuleContextBase {\n\n\t/**\n\t * @param transaction - The transaction the business logic rule is being applied on.\n\t * @param previousChangesDelta - A changes delta containing source changes, *or* the changes made during the last\n\t * rule application cycle only. Should be used to determine whether the business logic rule should run.\n\t * @param mergedChangesDelta - A changes delta containing the source changes, plus the changes made during *all*\n\t * previous rule application cycles.\n\t */\n\tprotected constructor (\n\t\tpublic readonly transaction: TransactionCache,\n\t\tpublic readonly previousChangesDelta: ChangesDelta,\n\t\tpublic readonly mergedChangesDelta: ChangesDelta,\n\t) {\n\t}\n\n\t/**\n\t * This function will get the latest value of the given itemEntry by first looking in the merged changes delta.\n\t * It will return the value found in the transaction chain otherwise.\n\t *\n\t * You could assume this function never returns `undefined` if you fetch the resource in your dependency function.\n\t */\n\tpublic getLatestValue<ItemTypeType extends ApiItemType, ColumnId extends ItemTypeColumnId<ItemTypeType>> (\n\t\tentry: ItemEntry<ItemTypeType>,\n\t\tcolumnId: ColumnId,\n\t): GetFieldValueType<ItemTypeType, ColumnId> | undefined {\n\t\tconst updatedValue = this.mergedChangesDelta.getUpdatedValue(\n\t\t\tentry,\n\t\t\tcolumnId,\n\t\t);\n\n\t\tif (updatedValue !== undefined) {\n\t\t\treturn updatedValue;\n\t\t}\n\n\t\treturn this.transaction.itemHandler.lookUpItemField(\n\t\t\tentry,\n\t\t\tcolumnId,\n\t\t);\n\t}\n\n\tpublic isUpdatedLatestItem<ItemTypeType extends ApiItemType, ColumnIds extends LatestItemColumnsArray<ItemTypeType>> (\n\t\tlatestItem: LatestItem<ItemTypeType, ColumnIds>,\n\t): latestItem is UpdatedLatestItem<ItemTypeType, ColumnIds> {\n\t\treturn (latestItem as UpdatedLatestItem<ItemTypeType, any>).itemEntry !== undefined;\n\t}\n\n\tpublic collectFields<ItemTypeType extends ApiItemType> (\n\t\tlatestItem: LatestItem<ItemTypeType, any>,\n\t): FieldMap<ItemTypeType> {\n\t\treturn this.isUpdatedLatestItem(\n\t\t\tlatestItem,\n\t\t)\n\t\t\t? this.transaction.itemHandler.collectFields(\n\t\t\t\tlatestItem.itemEntry,\n\t\t\t)\n\t\t\t: latestItem.fields;\n\t}\n\n\t/**\n\t * The equivalent of `getLinkCollections` on the transaction. Returns an array of 'latest' items for each parent\n\t * ID. Covers the merged changes delta as well as the transaction. Currently doesn't take deleted items into account.\n\t *\n\t * TODO: Instead of replicating transaction functionality in the business rule context, we should apply business\n\t * logic rules on a child transaction.\n\t */\n\tpublic async fetchLatestItemsByParent<\n\t\tParentItemType extends ApiItemType,\n\t\tItemTypeType extends ApiItemType,\n\t\tColumnIds extends LatestItemColumnsArray<ItemTypeType>,\n\t> (\n\t\tparentItemType: ParentItemType,\n\t\tparentItemIds: ItemId<ParentItemType>[],\n\t\titemType: ItemTypeType,\n\t\trequestColumns: ColumnIds,\n\t): Promise<Map<ItemId<ParentItemType>, LatestItem<ItemTypeType, ColumnIds>[]>> {\n\t\tif (parentItemIds.length === 0) {\n\t\t\treturn new Map();\n\t\t}\n\n\t\tconst linkCollectionOptions = this.transaction.cachedQueryHandler.processLinkCollectionOptions(\n\t\t\titemType,\n\t\t\tparentItemType,\n\t\t\tparentItemIds,\n\t\t\t{\n\t\t\t\tcolumns: requestColumns,\n\t\t\t},\n\t\t);\n\t\tconst cachedQueryItemsItemTypeTuples = await this.transaction.cachedQueryHandler.fetchChildCachedQueryItems(\n\t\t\t[\n\t\t\t\t{\n\t\t\t\t\titemType,\n\t\t\t\t\tlinkCollectionOptions,\n\t\t\t\t} as LinkCollectionOptionsItemTypeTuple<any> as LinkCollectionOptionsItemTypeTuple<ApiItemType>,\n\t\t\t],\n\t\t);\n\t\tconst cachedQueryItemTuples = (\n\t\t\tcachedQueryItemsItemTypeTuples[0] as CachedQueryItemsItemTypeTuple<any> as CachedQueryItemsItemTypeTuple<ItemTypeType>\n\t\t).cachedQueryItemTuples;\n\t\tconst matchesAccumulator: MatchesAccumulator<ChangesDeltaItemCreateDelta<ItemTypeType>> = new Map();\n\n\t\tfor (const cachedQueryItemTree of cachedQueryItemTuples) {\n\t\t\tmatchesAccumulator.set(\n\t\t\t\tcachedQueryItemTree.cachedQueryItem.query.string,\n\t\t\t\t{\n\t\t\t\t\ttrue: new Set(),\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\tthis.mergedChangesDelta.created.matchTuplesToQueryGraph(\n\t\t\titemType,\n\t\t\tlinkCollectionOptions.batchQueryGraph!,\n\t\t\tmatchesAccumulator,\n\t\t);\n\n\t\tconst result: Map<ItemId<ParentItemType>, LatestItem<ItemTypeType, ColumnIds>[]> = new Map();\n\n\t\tfor (const cachedQueryItemTree of cachedQueryItemTuples) {\n\t\t\tconst parentId = cachedQueryItemTree.options.parent!.itemId;\n\t\t\tconst cachedQueryItem = cachedQueryItemTree.cachedQueryItem;\n\n\t\t\tresult.set(\n\t\t\t\tparentId,\n\t\t\t\t[\n\t\t\t\t\t...this.constructLatestItems(\n\t\t\t\t\t\tcachedQueryItem.items,\n\t\t\t\t\t),\n\t\t\t\t\t...matchesAccumulator\n\t\t\t\t\t\t.get(\n\t\t\t\t\t\t\tcachedQueryItem.query.string,\n\t\t\t\t\t\t)!\n\t\t\t\t\t\t.true,\n\t\t\t\t],\n\t\t\t);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * This method should only be used when we're sure the items do not occur in the created changes. Generally,\n\t * {@link fetchLatestItemsById} should be used instead.\n\t */\n\tpublic async fetchUpdatedLatestItemsById<ItemTypeType extends ApiItemType, ColumnIds extends LatestItemColumnsArray<ItemTypeType>> (\n\t\titemType: ItemTypeType,\n\t\titemIds: ItemId[],\n\t\trequestColumns: ColumnIds,\n\t): Promise<UpdatedLatestItem<ItemTypeType, ColumnIds>[]> {\n\t\tconst itemEntries = await this.transaction.itemHandler.fetchItemEntryData(\n\t\t\titemType,\n\t\t\titemIds,\n\t\t\tthis.transaction.core.requestColumnOperationsCacheFactory.construct(\n\t\t\t\titemType,\n\t\t\t\trequestColumns,\n\t\t\t),\n\t\t\ttrue,\n\t\t);\n\n\t\treturn this.constructLatestItems(\n\t\t\titemEntries,\n\t\t);\n\t}\n\n\t/**\n\t * Returns an array of {@link LatestItem}s, taking both changes on the transaction and the merged changes delta into\n\t * account.\n\t */\n\tpublic async fetchLatestItemsById<\n\t\tItemTypeType extends ApiItemType,\n\t\tColumnIds extends LatestItemColumnsArray<ItemTypeType>\n\t> (\n\t\titemType: ItemTypeType,\n\t\titemIds: Iterable<ItemId>,\n\t\trequestColumns: ColumnIds,\n\t): Promise<LatestItem<ItemTypeType, ColumnIds>[]> {\n\t\tconst result: ChangesDeltaItemCreateDelta<ItemTypeType>[] = [];\n\t\tconst itemsIdsOnTransaction: ItemId[] = [];\n\n\t\tfor (const itemId of itemIds) {\n\t\t\tconst createdTuple = this.mergedChangesDelta.created.getTupleByItemId(\n\t\t\t\titemType,\n\t\t\t\titemId,\n\t\t\t);\n\n\t\t\tif (createdTuple !== undefined) {\n\t\t\t\tresult.push(\n\t\t\t\t\tcreatedTuple,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\titemsIdsOnTransaction.push(\n\t\t\t\t\titemId,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn [\n\t\t\t...result,\n\t\t\t...await this.fetchUpdatedLatestItemsById(\n\t\t\t\titemType,\n\t\t\t\titemsIdsOnTransaction,\n\t\t\t\trequestColumns,\n\t\t\t),\n\t\t];\n\t}\n\n\tprivate constructLatestItems<ItemTypeType extends ApiItemType> (\n\t\titemEntries: ItemEntry<ItemTypeType>[],\n\t): UpdatedLatestItem<ItemTypeType, any>[] {\n\t\tconst itemHandler = this.transaction.itemHandler;\n\t\tconst result: UpdatedLatestItem<ItemTypeType, any>[] = [];\n\n\t\tfor (const itemEntry of itemEntries) {\n\t\t\tconst updatedTuple = this.mergedChangesDelta.updated[itemEntry.id];\n\n\t\t\tresult.push(\n\t\t\t\t{\n\t\t\t\t\titemEntry,\n\t\t\t\t\tupdatedTuple,\n\t\t\t\t\tfields: updatedTuple !== undefined\n\t\t\t\t\t\t? new Proxy(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\t\t\titemHandler,\n\t\t\t\t\t\t\t\tupdatedTuple,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tfieldsProxyHandler,\n\t\t\t\t\t\t) as FieldMap<ItemTypeType>\n\t\t\t\t\t\t: itemHandler.constructFieldsProxy(\n\t\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\treturn result;\n\t}\n\n}\n\n","import { ApiItemType, ApiModuleFunctionResponse, ResponseColumn } from '@rentman/backend-types';\nimport { ItemEntry } from '../../models/ItemEntry';\nimport { GetFieldValueType, HasFlagFn, ItemTypeColumnId } from '../../types/ItemTypesCollection';\nimport { TransactionCache } from '../cache/transaction/TransactionCache';\nimport { BusinessLogicRuleApplyContext } from './BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from './BusinessLogicRuleConditionContext';\nimport { BusinessLogicRuleContextBase } from './BusinessLogicRuleContextBase';\n\nexport const BLR_SKIP_RULE = Symbol(\n\t'Skip rule',\n);\n\nexport const BLR_CONTINUE_WITH_DEFAULTS = Symbol(\n\t'Continue with defaults',\n);\n\n/**\n * As the 'condition' function can return any value, we introduce a unique identifier to return when a business\n * logic rule confirm function has been rejected, and changes should be abandoned.\n */\nexport const BLR_ABANDON_CHANGES = Symbol(\n\t'Stop execution',\n);\n\nexport interface RuleConditionResultTuple {\n\truleInstance: BusinessLogicRule<any, any, any>,\n\tconditionResult: any,\n\tconfirmResult?: any,\n}\n\nexport interface RuleDependencyResultTuple\n\textends RuleConditionResultTuple {\n\n\tdependencyResult: any,\n\tconfirmResult?: any,\n}\n\ntype MaybePromise<T> = T | Promise<T>;\n\nexport type BusinessLogicRuleConditionConfirmFn<ConditionResult, ConfirmResult> = (\n\tconditionResult: ConditionResult,\n\ttransaction: TransactionCache,\n) => MaybePromise<ConfirmResult | typeof BLR_SKIP_RULE | typeof BLR_ABANDON_CHANGES | typeof BLR_CONTINUE_WITH_DEFAULTS>;\n\nexport type BusinessLogicRuleConfirmFnWithDependency<ConditionResult, Dependency, ConfirmResult> = (\n\tconditionResult: ConditionResult,\n\tdependency: Dependency,\n\ttransaction: TransactionCache,\n) => MaybePromise<ConfirmResult | typeof BLR_SKIP_RULE | typeof BLR_ABANDON_CHANGES | typeof BLR_CONTINUE_WITH_DEFAULTS>;\n\nexport type BusinessLogicConditionResult<ItemTypeType extends ApiItemType, ColumnId extends ItemTypeColumnId<ItemTypeType>> = {\n\titemEntry: ItemEntry<ItemTypeType>,\n\tresponseColumn: ResponseColumn<ItemTypeType, ColumnId>,\n\toldValue: GetFieldValueType<ItemTypeType, ColumnId>,\n\tnewValue: GetFieldValueType<ItemTypeType, ColumnId>,\n};\n\n/**\n * @description\n * A business rule is a class that does some data transformation depending on other fields.\n * You can hook into any data change using the {@link BusinessLogicRule.condition `condition`} function (also deletes/creates)\n *\n * All business rule logic is always run in these phases:\n * 1. condition checking - handled by the {@link BusinessLogicRule.condition `condition`} function\n * 2. dependency fetching - handled by the {@link BusinessLogicRule.dependency `dependency`} function\n * 3. rule applying - handled by the {@link BusinessLogicRule.apply `apply`} function\n */\n\nexport abstract class BusinessLogicRule<ConditionResult, DependencyType, ConfirmResult = undefined> {\n\n\tpublic confirm: BusinessLogicRuleConditionConfirmFn<ConditionResult, ConfirmResult> | null = null;\n\n\tpublic postDependencyConfirm: BusinessLogicRuleConfirmFnWithDependency<ConditionResult, DependencyType, ConfirmResult> | null = null;\n\n\tpublic constructor (\n\t\tprotected readonly locals: ApiModuleFunctionResponse<'locals', 'getLocals'>,\n\t\tprotected readonly hasFlag: HasFlagFn,\n\t) {\n\t}\n\n\t/**\n\t * @description\n\t * The {@link BusinessLogicRule.dependency `dependency`} function gets the result of the\n\t * {@link BusinessLogicRule.condition `condition`} function and has to ensure that the data that the\n\t * {@link BusinessLogicRule.apply `apply`} function reads/writes is fetched (because you cannot write columns you don't have).\n\t *\n\t * @param transaction The transaction that the delta is being applied on\n\t * @param conditionResult The result of the {@link BusinessLogicRule.condition `condition`} call\n\t */\n\tpublic abstract dependency (\n\t\ttransaction: TransactionCache,\n\t\tconditionResult: ConditionResult,\n\t\tcontext: BusinessLogicRuleContextBase,\n\t): Promise<DependencyType>;\n\n\t/**\n\t * @description\n\t * The {@link BusinessLogicRule.apply `apply`} function gets the result of the\n\t * {@link BusinessLogicRule.dependency `dependency`} function and is responsible for actually doing the business\n\t * logic. In this function other fields can be updated or new items can be created.\n\t *\n\t * @remark\n\t * Do not alter data in the `changesDelta` but use the `destinationChangesDelta`, this is so that for the changed\n\t * values in the `destinationChangesDelta` business logic can also be done.\n\t *\n\t * @param dependencies The result of the {@link BusinessLogicRule.dependency `dependency`} function\n\t */\n\tpublic abstract apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tdependencies: DependencyType,\n\t\tconditionResult: ConditionResult,\n\t\t// We can never assume an options modal is implemented. If there are no options you should apply all changes.\n\t\tconfirmResult: ConfirmResult,\n\t): void;\n\n\t/**\n\t * @description\n\t * The {@link BusinessLogicRule.condition `condition`} function should extract the items from the {@link ChangesDelta `ChangesDelta`} so that the {@link BusinessLogicRule.dependency `dependency`} function can fetch the required data for the business rule.\n\t * This function can return `undefined` if the rule does not apply to the items in the given ChangesDelta.\n\t *\n\t * @protected\n\t */\n\tpublic abstract condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): Promise<ConditionResult | typeof BLR_SKIP_RULE> | ConditionResult | typeof BLR_SKIP_RULE;\n\n}\n","import { ApiItemType, ItemId, ResponseColumn, UnknownResponseColumn } from '@rentman/backend-types';\nimport { ErrorHandlerInterface } from '../../interfaces/ErrorHandlerInterface';\nimport { GetFieldValueType, ItemTypeColumnId } from '../../types/ItemTypesCollection';\nimport { ApiFormatter } from '../ApiFormatter';\nimport { TransactionCache } from '../cache/transaction/TransactionCache';\nimport { ChangesDelta, ChangesDeltaItemUpdateDelta } from '../ChangesDelta';\nimport { BLR_SKIP_RULE, BusinessLogicConditionResult } from './BusinessLogicRule';\nimport { BusinessLogicRuleContextBase } from './BusinessLogicRuleContextBase';\n\n/**\n * Class that represents the context for the business logic rule `condition()` function.\n *\n * Please note that, while the transaction, merged changes delta and previous changes delta are available on the\n * class instance, using the helper functions is preferred.\n */\nexport class BusinessLogicRuleConditionContext\n\textends BusinessLogicRuleContextBase {\n\n\tpublic constructor (\n\t\ttransaction: TransactionCache,\n\t\tpreviousChangesDelta: ChangesDelta,\n\t\tmergedChangesDelta: ChangesDelta,\n\t\tprivate errorHandler: ErrorHandlerInterface,\n\t) {\n\t\tsuper(\n\t\t\ttransaction,\n\t\t\tpreviousChangesDelta,\n\t\t\tmergedChangesDelta,\n\t\t);\n\t}\n\n\t/**\n\t * @description\n\t * This function will compare the stored changes with the given changes, and return a\n\t * {@link BusinessLogicConditionResult} if the fields have been changed, `null` otherwise.\n\t * If either the source or changed field is `undefined` it will always return `null` (not changed)\n\t *\n\t * @param tuple The {@link ChangesDelta.updated update tuple} from a ChangesDelta\n\t * @param columnId The columnId of the field that should've been changed for the ID to be included\n\t */\n\tpublic fieldChanged<ItemTypeType extends ApiItemType, ColumnId extends ItemTypeColumnId<ItemTypeType>> (\n\t\ttuple: ChangesDeltaItemUpdateDelta<ItemTypeType>,\n\t\tcolumnId: ColumnId,\n\t): null | BusinessLogicConditionResult<ItemTypeType, ColumnId> {\n\t\tconst newValue = tuple.changes.fields[columnId];\n\n\t\t// The field wasn't updated so we just continue\n\t\tif (newValue === undefined) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst oldValue = this.transaction.itemHandler.lookUpItemField(\n\t\t\ttuple.entry,\n\t\t\tcolumnId,\n\t\t);\n\n\t\tif (oldValue === undefined) {\n\t\t\tthis.errorHandler.logWarning(\n\t\t\t\t`BusinessLogicManager: could not check business logic because the stored value for column '${columnId as string}' was undefined. Value in update: ${newValue}. Please make sure you fetched column ${columnId as string} for itemType ${tuple.entry.itemType}`,\n\t\t\t);\n\n\t\t\t// The field isn't in the delta, so it's not changed\n\t\t\treturn null;\n\t\t}\n\n\t\tconst responseColumn = tuple.entry.columns.response[tuple.entry.itemType][columnId];\n\n\t\t// If the applied field is the same value as the field already cached, it did not change so we shouldn't do business logic\n\t\tif (\n\t\t\tApiFormatter.compareFields(\n\t\t\t\t(responseColumn as UnknownResponseColumn).type,\n\t\t\t\tnewValue,\n\t\t\t\toldValue,\n\t\t\t)\n\t\t) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn {\n\t\t\titemEntry: tuple.entry,\n\t\t\tresponseColumn: responseColumn as ResponseColumn<ItemTypeType, ColumnId>,\n\t\t\toldValue,\n\t\t\tnewValue,\n\t\t};\n\t}\n\n\t/**\n\t * This function is a utility function that will return the {@link ItemId ItemIds} of updated items in the\n\t * {@link ChangesDelta ChangesDelta} which match the {@link ApiItemType ItemType} and of which the provided\n\t * column's field has changed.\n\t *\n\t * @param itemType The ItemType of the item you want to compare a field from\n\t * @param columnId The columnId of the field that should've been changed for the ID to be included\n\t */\n\tpublic getItemIdsWithUpdatedField<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tcolumnId: ItemTypeColumnId<ItemTypeType>,\n\t): ItemId[] | typeof BLR_SKIP_RULE {\n\t\tconst updatedIterator = this.previousChangesDelta.getUpdatedTuplesIterator(\n\t\t\titemType,\n\t\t);\n\t\tconst result: ItemId[] = [];\n\n\t\tfor (const tuple of updatedIterator) {\n\t\t\tif (\n\t\t\t\tthis.fieldChanged(\n\t\t\t\t\ttuple,\n\t\t\t\t\tcolumnId,\n\t\t\t\t) !== null\n\t\t\t) {\n\t\t\t\tresult.push(\n\t\t\t\t\ttuple.entry.itemId,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (result.length === 0) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Like {@link getItemIdsWithUpdatedField}, but allows for a new value to be provided. Only IDs of items where the\n\t * field has been updated to the new value will be included in the result.\n\t */\n\tpublic getItemIdsWithFieldUpdatedTo<ItemTypeType extends ApiItemType, ColumnId extends ItemTypeColumnId<ItemTypeType>> (\n\t\titemType: ItemTypeType,\n\t\tcolumnId: ColumnId,\n\t\tnewValue: GetFieldValueType<ItemTypeType, ColumnId>,\n\t): ItemId[] | typeof BLR_SKIP_RULE {\n\t\tconst updatedIterator = this.previousChangesDelta.getUpdatedTuplesIterator(\n\t\t\titemType,\n\t\t);\n\t\tconst result: ItemId[] = [];\n\n\t\tfor (const tuple of updatedIterator) {\n\t\t\tconst updatedValue = this.previousChangesDelta.getUpdatedValue(\n\t\t\t\ttuple.entry,\n\t\t\t\tcolumnId,\n\t\t\t);\n\n\t\t\tif (updatedValue === undefined) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Retrieve the response column only when a value has been set. We cannot be sure it's available otherwise.\n\t\t\tconst responseColumn = tuple.entry.columns.response[tuple.entry.itemType][columnId];\n\n\t\t\tif (\n\t\t\t\tApiFormatter.compareFields(\n\t\t\t\t\t(responseColumn as UnknownResponseColumn).type,\n\t\t\t\t\tupdatedValue,\n\t\t\t\t\tnewValue,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tresult.push(\n\t\t\t\t\ttuple.entry.itemId,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (result.length === 0) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn result;\n\t}\n\n}\n","import { ApiItemType, UnknownResponseColumn } from '@rentman/backend-types';\nimport { ItemEntry } from '../../models/ItemEntry';\nimport { FieldMap, GetFieldValueType, ItemTypeColumnId } from '../../types/ItemTypesCollection';\nimport { ApiFormatter } from '../ApiFormatter';\nimport { TransactionCache } from '../cache/transaction/TransactionCache';\nimport { ChangesDelta } from '../ChangesDelta';\nimport { BusinessLogicRuleContextBase } from './BusinessLogicRuleContextBase';\n\n/**\n * Class that represents the context for the business logic rule `apply()` function.\n */\nexport class BusinessLogicRuleApplyContext\n\textends BusinessLogicRuleContextBase {\n\n\t/**\n\t * @param destinationChangesDelta - Changes should be written to this changes delta.\n\t */\n\tpublic constructor (\n\t\ttransactionCache: TransactionCache,\n\t\tpreviousChangesDelta: ChangesDelta,\n\t\tmergedChangesDelta: ChangesDelta,\n\t\tpublic readonly destinationChangesDelta: ChangesDelta,\n\t) {\n\t\tsuper(\n\t\t\ttransactionCache,\n\t\t\tpreviousChangesDelta,\n\t\t\tmergedChangesDelta,\n\t\t);\n\t}\n\n\t/**\n\t * An alias for `destinationChangesDelta.setItemUpdated().\n\t *\n\t * In most cases, `setUpdatedValue()`, would be preferred, because it only sets the value when differs from the\n\t * current value.\n\t */\n\tpublic setItemUpdated<ItemTypeType extends ApiItemType> (\n\t\tentry: ItemEntry<ItemTypeType>,\n\t\tfields: Partial<FieldMap<ItemTypeType>>,\n\t): void {\n\t\tthis.destinationChangesDelta.setItemUpdated(\n\t\t\tentry,\n\t\t\tfields,\n\t\t);\n\t}\n\n\t/**\n\t * An alias for `destinationChangesDelta.setItemsDeleted().\n\t */\n\tpublic setItemsDeleted<ItemTypeType extends ApiItemType> (\n\t\tentries: ItemEntry<ItemTypeType>[],\n\t): void {\n\t\tthis.destinationChangesDelta.setItemsDeleted(\n\t\t\tentries,\n\t\t);\n\t}\n\n\t/**\n\t * Convenience function to write an updated value to the destination changes delta. Only sets the value when differs\n\t * from the current value.\n\t */\n\tpublic setUpdatedValue<ItemTypeType extends ApiItemType, ColumnId extends ItemTypeColumnId<ItemTypeType>> (\n\t\tentry: ItemEntry<ItemTypeType>,\n\t\tcolumnId: ColumnId,\n\t\tnewValue: GetFieldValueType<ItemTypeType, ColumnId>,\n\t): void {\n\t\tconst currentValue = this.getLatestValue(\n\t\t\tentry,\n\t\t\tcolumnId,\n\t\t);\n\t\tconst responseColumn = entry.columns.response[entry.itemType][columnId];\n\n\t\tif (\n\t\t\tApiFormatter.compareFields(\n\t\t\t\t(responseColumn as UnknownResponseColumn).type,\n\t\t\t\tcurrentValue,\n\t\t\t\tnewValue,\n\t\t\t)\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.destinationChangesDelta.setItemUpdated(\n\t\t\tentry,\n\t\t\t{\n\t\t\t\t[columnId]: newValue,\n\t\t\t} as Partial<FieldMap<ItemTypeType>>,\n\t\t);\n\t}\n\n}","import { ApiModuleFunctionResponse } from '@rentman/backend-types';\nimport { HasFlagFn } from '../../types/ItemTypesCollection';\nimport { BusinessLogicRule } from './BusinessLogicRule';\n\nexport type BusinessLogicRuleConstructor<BusinessLogicRuleType extends BusinessLogicRule<any, any> = BusinessLogicRule<any, any>> = new (\n\tlocals: ApiModuleFunctionResponse<'locals', 'getLocals'>,\n\thasFlagFn: HasFlagFn,\n) => BusinessLogicRuleType;\n\nexport type BusinessLogicRuleConstructorName = BusinessLogicRuleConstructor & {\n\t__name: string,\n};\n\n/**\n * Decorator for business logic rules. Currently defines the name. We could add additional metadata in the future.\n *\n * All business logic rules should be registered in `registeredBusinessLogicRules.ts`.\n */\nexport function businessLogicRule (\n\tname: string,\n): (\n\tconstructor: BusinessLogicRuleConstructor,\n) => void {\n\treturn function (\n\t\tconstructor: BusinessLogicRuleConstructor,\n\t): void {\n\t\t(constructor as BusinessLogicRuleConstructorName).__name = name;\n\t};\n}\n","/*! *****************************************************************************\r\nCopyright (c) Microsoft Corporation. All rights reserved.\r\nLicensed under the Apache License, Version 2.0 (the \"License\"); you may not use\r\nthis file except in compliance with the License. You may obtain a copy of the\r\nLicense at http://www.apache.org/licenses/LICENSE-2.0\r\n\r\nTHIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\r\nKIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED\r\nWARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,\r\nMERCHANTABLITY OR NON-INFRINGEMENT.\r\n\r\nSee the Apache Version 2.0 License for specific language governing permissions\r\nand limitations under the License.\r\n***************************************************************************** */\r\n/* global Reflect, Promise */\r\n\r\nvar extendStatics = function(d, b) {\r\n extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };\r\n return extendStatics(d, b);\r\n};\r\n\r\nexport function __extends(d, b) {\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n}\r\n\r\nexport var __assign = function() {\r\n __assign = Object.assign || function __assign(t) {\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments[i];\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\r\n }\r\n return t;\r\n }\r\n return __assign.apply(this, arguments);\r\n}\r\n\r\nexport function __rest(s, e) {\r\n var t = {};\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\r\n t[p] = s[p];\r\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\r\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\r\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\r\n t[p[i]] = s[p[i]];\r\n }\r\n return t;\r\n}\r\n\r\nexport function __decorate(decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n}\r\n\r\nexport function __param(paramIndex, decorator) {\r\n return function (target, key) { decorator(target, key, paramIndex); }\r\n}\r\n\r\nexport function __metadata(metadataKey, metadataValue) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\r\n}\r\n\r\nexport function __awaiter(thisArg, _arguments, P, generator) {\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n}\r\n\r\nexport function __generator(thisArg, body) {\r\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n function verb(n) { return function (v) { return step([n, v]); }; }\r\n function step(op) {\r\n if (f) throw new TypeError(\"Generator is already executing.\");\r\n while (_) try {\r\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n if (y = 0, t) op = [op[0] & 2, t.value];\r\n switch (op[0]) {\r\n case 0: case 1: t = op; break;\r\n case 4: _.label++; return { value: op[1], done: false };\r\n case 5: _.label++; y = op[1]; op = [0]; continue;\r\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n default:\r\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n if (t[2]) _.ops.pop();\r\n _.trys.pop(); continue;\r\n }\r\n op = body.call(thisArg, _);\r\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n }\r\n}\r\n\r\nexport function __exportStar(m, exports) {\r\n for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];\r\n}\r\n\r\nexport function __values(o) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator], i = 0;\r\n if (m) return m.call(o);\r\n return {\r\n next: function () {\r\n if (o && i >= o.length) o = void 0;\r\n return { value: o && o[i++], done: !o };\r\n }\r\n };\r\n}\r\n\r\nexport function __read(o, n) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\r\n if (!m) return o;\r\n var i = m.call(o), r, ar = [], e;\r\n try {\r\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\r\n }\r\n catch (error) { e = { error: error }; }\r\n finally {\r\n try {\r\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\r\n }\r\n finally { if (e) throw e.error; }\r\n }\r\n return ar;\r\n}\r\n\r\nexport function __spread() {\r\n for (var ar = [], i = 0; i < arguments.length; i++)\r\n ar = ar.concat(__read(arguments[i]));\r\n return ar;\r\n}\r\n\r\nexport function __spreadArrays() {\r\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\r\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\r\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\r\n r[k] = a[j];\r\n return r;\r\n};\r\n\r\nexport function __await(v) {\r\n return this instanceof __await ? (this.v = v, this) : new __await(v);\r\n}\r\n\r\nexport function __asyncGenerator(thisArg, _arguments, generator) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\r\n return i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i;\r\n function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }\r\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\r\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\r\n function fulfill(value) { resume(\"next\", value); }\r\n function reject(value) { resume(\"throw\", value); }\r\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\r\n}\r\n\r\nexport function __asyncDelegator(o) {\r\n var i, p;\r\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\r\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === \"return\" } : f ? f(v) : v; } : f; }\r\n}\r\n\r\nexport function __asyncValues(o) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var m = o[Symbol.asyncIterator], i;\r\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\r\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\r\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\r\n}\r\n\r\nexport function __makeTemplateObject(cooked, raw) {\r\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\r\n return cooked;\r\n};\r\n\r\nexport function __importStar(mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];\r\n result.default = mod;\r\n return result;\r\n}\r\n\r\nexport function __importDefault(mod) {\r\n return (mod && mod.__esModule) ? mod : { default: mod };\r\n}\r\n","import { ItemId } from '@rentman/backend-types';\nimport { DurationInputArg2 } from 'moment';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { FieldMap, GetFieldValueType } from '../../../types/ItemTypesCollection';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype RecurrentItemType = 'Afspraak' | 'Functie' | 'Beschikbaarheid';\n\nconst dependencyColumns = [\n\t'recureind',\n\t'recurperiode',\n\t'recurhoe',\n] as const;\n\ntype ConditionResult = ItemId[];\n\ntype Dependency<ItemTypeType extends RecurrentItemType, ToField extends keyof FieldMap<ItemTypeType>> = ItemResource<ItemTypeType, [\n\t...typeof dependencyColumns,\n\tToField,\n]>[];\n\n/**\n * @description\n * Based on the recurhoe field, this business rule will choose a date for recureind that will make sure\n * at least two recurrences are created after the current tot/plantot date of the item that is being edited.\n */\n@businessLogicRule(\n\t'RecurrentItemRecureindBusinessLogicRule',\n)\nexport class RecurrentItemRecureindBusinessLogicRule<ItemTypeType extends RecurrentItemType, ToField extends keyof FieldMap<ItemTypeType>>\n\textends BusinessLogicRule<ConditionResult, Dependency<ItemTypeType, ToField>> {\n\n\tprotected itemType: ItemTypeType;\n\tprotected toField: keyof FieldMap<ItemTypeType>;\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\tconst previousChangesDelta = context.previousChangesDelta;\n\n\t\tconst updatedIterator = previousChangesDelta.getUpdatedTuplesIterator(\n\t\t\tthis.itemType,\n\t\t);\n\n\t\tconst result: ItemId[] = [];\n\n\t\tfor (const tuple of updatedIterator) {\n\t\t\tconst recurEindChanged = previousChangesDelta.getUpdatedValue(\n\t\t\t\ttuple.entry,\n\t\t\t\t'recureind',\n\t\t\t) !== undefined;\n\n\t\t\tif (recurEindChanged) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst recurHoeChanged = previousChangesDelta.getUpdatedValue(\n\t\t\t\ttuple.entry,\n\t\t\t\t'recurhoe',\n\t\t\t) !== undefined;\n\n\t\t\tconst recurPeriodeChanged = previousChangesDelta.getUpdatedValue(\n\t\t\t\ttuple.entry,\n\t\t\t\t'recurperiode',\n\t\t\t) !== undefined;\n\n\t\t\tif (\n\t\t\t\trecurHoeChanged\n\t\t\t\t|| recurPeriodeChanged\n\t\t\t) {\n\t\t\t\tresult.push(\n\t\t\t\t\ttuple.entry.itemId,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (result.length === 0) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\trecurrentItemIds: ConditionResult,\n\t): Promise<Dependency<ItemTypeType, ToField>> {\n\t\treturn transaction.getItemsById(\n\t\t\tthis.itemType,\n\t\t\trecurrentItemIds,\n\t\t\t{\n\t\t\t\tcolumns: [\n\t\t\t\t\t...dependencyColumns,\n\t\t\t\t\tthis.toField,\n\t\t\t\t],\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\trecurrentItemResources: Dependency<ItemTypeType, ToField>,\n\t): void {\n\t\tfor (const recurrentItemResource of recurrentItemResources as ItemResource<any>[] as ItemResource<'Afspraak', typeof dependencyColumns>[]) {\n\t\t\tconst recurHoe = context.getLatestValue(\n\t\t\t\trecurrentItemResource.entry,\n\t\t\t\t'recurhoe',\n\t\t\t);\n\n\t\t\tif (\n\t\t\t\trecurHoe === undefined\n\t\t\t\t|| recurHoe === 'eenmalig'\n\t\t\t\t|| recurHoe === 'specifieke_dagen'\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst momentUnit: DurationInputArg2 = this.convertRecurhoeToMomentDuration(\n\t\t\t\trecurHoe,\n\t\t\t);\n\n\t\t\tconst recurPeriode = context.getLatestValue(\n\t\t\t\trecurrentItemResource.entry,\n\t\t\t\t'recurperiode',\n\t\t\t);\n\n\t\t\tconst sensibleRecurEind: moment.Moment = (\n\t\t\t\t(recurrentItemResource as any).fields[this.toField] as moment.Moment\n\t\t\t)\n\t\t\t\t.clone()\n\t\t\t\t.add(\n\t\t\t\t\trecurPeriode,\n\t\t\t\t\tmomentUnit,\n\t\t\t\t)\n\t\t\t\t.startOf(\n\t\t\t\t\t'day',\n\t\t\t\t)\n\t\t\t\t.add(\n\t\t\t\t\t1,\n\t\t\t\t\t'day',\n\t\t\t\t);\n\n\t\t\tif (\n\t\t\t\tsensibleRecurEind.isAfter(\n\t\t\t\t\trecurrentItemResource.fields.recureind,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tcontext.setItemUpdated(\n\t\t\t\t\trecurrentItemResource.entry,\n\t\t\t\t\t{\n\t\t\t\t\t\trecureind: sensibleRecurEind,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate convertRecurhoeToMomentDuration (\n\t\trecurrenceDurationUnit: Exclude<GetFieldValueType<'Afspraak', 'recurhoe'>, 'eenmalig' | 'weekdag'>,\n\t): DurationInputArg2 {\n\t\tswitch (recurrenceDurationUnit) {\n\t\t\tcase 'dag':\n\t\t\tcase 'specifieke_dagen':\n\t\t\t\treturn 'days';\n\t\t\tcase 'week':\n\t\t\t\treturn 'weeks';\n\t\t\tcase 'maand':\n\t\t\t\treturn 'months';\n\t\t\tcase 'jaar':\n\t\t\t\treturn 'years';\n\t\t}\n\t}\n\n}\n","import { businessLogicRule } from '../businessLogicRule.decorator';\nimport { RecurrentItemRecureindBusinessLogicRule } from '../RecurrentItem/RecurrentItemRecureindBusinessLogicRule';\n\n@businessLogicRule(\n\t'AfspraakRecureindBusinessLogicRule',\n)\nexport class AfspraakRecureindBusinessLogicRule\n\textends RecurrentItemRecureindBusinessLogicRule<'Afspraak', 'tot'> {\n\n\tprotected override itemType = 'Afspraak' as const;\n\n\tprotected override toField = 'tot' as const;\n\n}\n","import { businessLogicRule } from '../businessLogicRule.decorator';\nimport { RecurrentItemRecureindBusinessLogicRule } from '../RecurrentItem/RecurrentItemRecureindBusinessLogicRule';\n\n@businessLogicRule(\n\t'BeschikbaarheidRecureindBusinessLogicRule',\n)\nexport class BeschikbaarheidRecureindBusinessLogicRule\n\textends RecurrentItemRecureindBusinessLogicRule<'Beschikbaarheid', 'plantot'> {\n\n\tprotected override itemType = 'Beschikbaarheid' as const;\n\n\tprotected override toField = 'plantot' as const;\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\nconst ADDRESS_FIELDS = [\n\t'straat',\n\t'huisnummer',\n\t'postcode',\n\t'stad',\n\t'provincie',\n\t'land',\n] as const;\n\nconst ADDRESS_PREFIXES = [\n\t'bezoek',\n\t'post',\n\t'factuur',\n] as const;\n\ntype RequestColumns = (\n\t{\n\t\t[Prefix in typeof ADDRESS_PREFIXES[number]]: {\n\t\t[Field in typeof ADDRESS_FIELDS[number]]: `${Prefix}${Field}`\n\t}[typeof ADDRESS_FIELDS[number]]\n\t}[typeof ADDRESS_PREFIXES[number]]\n\t)[];\n\ntype ConditionResult = ItemId[];\n\ntype Dependency = ItemResource<'Contact', RequestColumns>[];\n\n@businessLogicRule(\n\t'ContactAddressBusinessLogicRule',\n)\nexport class ContactAddressBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\tconst updatedIterator = context.previousChangesDelta.getUpdatedTuplesIterator(\n\t\t\t'Contact',\n\t\t);\n\t\tconst result: ItemId[] = [];\n\n\t\tfor (const tuple of updatedIterator) {\n\t\t\tif (\n\t\t\t\tADDRESS_FIELDS.some(\n\t\t\t\t\tfield => context.fieldChanged(\n\t\t\t\t\t\ttuple,\n\t\t\t\t\t\t`bezoek${field}`,\n\t\t\t\t\t) !== null,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tresult.push(\n\t\t\t\t\ttuple.entry.itemId,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (result.length === 0) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\tcontactIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\tconst columns: RequestColumns = [];\n\n\t\tfor (const prefix of ADDRESS_PREFIXES) {\n\t\t\tfor (const addressField of ADDRESS_FIELDS) {\n\t\t\t\tcolumns.push(\n\t\t\t\t\t`${prefix}${addressField}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn transaction.getItemsById(\n\t\t\t'Contact',\n\t\t\tcontactIds,\n\t\t\t{\n\t\t\t\tcolumns: columns,\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tcontactResources: Dependency,\n\t): void {\n\t\tconst prefixes: string[] = [\n\t\t\t'post',\n\t\t\t'factuur',\n\t\t];\n\n\t\tfor (const contactResource of contactResources) {\n\t\t\tfor (const prefix of prefixes) {\n\t\t\t\tif (\n\t\t\t\t\t!this.addressEqualsVisitingAddress(\n\t\t\t\t\t\tcontactResource,\n\t\t\t\t\t\tprefix,\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tcontext.setItemUpdated(\n\t\t\t\t\tcontactResource.entry,\n\t\t\t\t\tADDRESS_FIELDS.reduce(\n\t\t\t\t\t\t(\n\t\t\t\t\t\t\taccumulator,\n\t\t\t\t\t\t\tfield,\n\t\t\t\t\t\t) => {\n\t\t\t\t\t\t\taccumulator[prefix + field] = context.getLatestValue(\n\t\t\t\t\t\t\t\tcontactResource.entry,\n\t\t\t\t\t\t\t\t`bezoek${field}`,\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\treturn accumulator;\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{},\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate addressEqualsVisitingAddress (\n\t\tcontactResource: Dependency[number],\n\t\tprefix: string,\n\t): boolean {\n\t\tfor (const addressField of ADDRESS_FIELDS) {\n\t\t\tif (contactResource.fields[prefix + addressField] !== contactResource.fields['bezoek' + addressField]) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = ItemId[];\n\ntype Dependency = ItemResource<'Customfield', ['defaultvalue']>[];\n\n/**\n * @description\n * If the 'type' field changes we reset the 'defaultvalue' and 'attribute' fields so that they do not contain invalid values\n */\n@businessLogicRule(\n\t'CustomFieldLinkedItemTypeBusinessLogicRule',\n)\nexport class CustomFieldLinkedItemTypeBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\treturn context.getItemIdsWithUpdatedField(\n\t\t\t'Customfield',\n\t\t\t'linkedItemType',\n\t\t);\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\tfunctionIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\treturn transaction.getItemsById(\n\t\t\t'Customfield',\n\t\t\tfunctionIds,\n\t\t\t{\n\t\t\t\tcolumns: [\n\t\t\t\t\t'defaultvalue',\n\t\t\t\t],\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tcustomFieldResources: Dependency,\n\t): void {\n\t\tfor (const customFieldResource of customFieldResources) {\n\t\t\tcontext.setItemUpdated(\n\t\t\t\tcustomFieldResource.entry,\n\t\t\t\t{\n\t\t\t\t\tdefaultvalue: null,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ApiEnumApiType, ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { ApiFormatter } from '../../ApiFormatter';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = ItemId[];\n\ntype Dependency = ItemResource<'Customfield', ['defaultvalue', 'attributes', 'type']>[];\n\n/**\n * @description\n * If the 'type' field changes we reset the 'defaultvalue' and 'attribute' fields so that they do not contain invalid values\n */\n@businessLogicRule(\n\t'CustomFieldTypeBusinessLogicRule',\n)\nexport class CustomFieldTypeBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\treturn context.getItemIdsWithUpdatedField(\n\t\t\t'Customfield',\n\t\t\t'type',\n\t\t);\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\tfunctionIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\treturn transaction.getItemsById(\n\t\t\t'Customfield',\n\t\t\tfunctionIds,\n\t\t\t{\n\t\t\t\tcolumns: [\n\t\t\t\t\t'defaultvalue',\n\t\t\t\t\t'attributes',\n\t\t\t\t\t'type',\n\t\t\t\t],\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tcustomFieldResources: Dependency,\n\t): void {\n\t\tfor (const customFieldResource of customFieldResources) {\n\t\t\tconst typeValue = context.getLatestValue(\n\t\t\t\tcustomFieldResource.entry,\n\t\t\t\t'type',\n\t\t\t);\n\n\t\t\tlet defaultvalue;\n\n\t\t\t/*\n\t\t\t Ugly hack/workaround; see confluence for info.\n\t\t\t https://rentman.atlassian.net/wiki/spaces/DEV/pages/2882895877/ApiType+TYPE+JSON+problems\n\t\t\t */\n\t\t\tif (typeValue === 'enum') {\n\t\t\t\tdefaultvalue = 0;\n\t\t\t} else {\n\t\t\t\tdefaultvalue = ApiFormatter.getDefaultValue(\n\t\t\t\t\ttypeValue as ApiEnumApiType,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tcontext.setItemUpdated(\n\t\t\t\tcustomFieldResource.entry,\n\t\t\t\t{\n\t\t\t\t\tdefaultvalue: defaultvalue,\n\t\t\t\t\tattributes: {},\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ApiItemType, ItemId } from '@rentman/backend-types';\nimport { ItemEntry } from '../../models/ItemEntry';\nimport { ItemResource } from '../../models/ItemResource';\nimport { ItemTypeColumnId } from '../../types/ItemTypesCollection';\nimport { TransactionCache } from '../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from './BusinessLogicRule';\nimport { businessLogicRule } from './businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from './BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from './BusinessLogicRuleConditionContext';\n\n// The keys refer to fields that link to a Contact, the values refer to fields\n// that link to a Person\nconst itemTypeFieldMap = {\n\tOfferte: {\n\t\topdrachtgever: 'contactpersoon',\n\t},\n\tContract: {\n\t\topdrachtgever: 'contactpersoon',\n\t},\n\tFactuur: {\n\t\topdrachtgever: 'contactpersoon',\n\t},\n\tProject: {\n\t\topdrachtgever: 'opdrachtgever_persoon',\n\t\tlocatie: 'locatie_persoon',\n\t},\n\tSubproject: {\n\t\tlocatie: 'locatie_persoon',\n\t},\n\tInhuur: {\n\t\tlocatie: 'locatie_persoon',\n\t\tleverancier: 'contactpersoon',\n\t},\n\tProjectRequest: {\n\t\taanvrager: 'accountmanager',\n\t},\n} satisfies {\n\t[ItemTypeType in ApiItemType]?: {\n\t\t[ColumnId in ItemTypeColumnId<ItemTypeType>]?: ItemTypeColumnId<ItemTypeType>\n\t}\n};\n\ntype ConditionResult = {\n\t[ItemTypeType in ApiItemType]?: Map<ItemEntry, {\n\t\t[ColumnId in ItemTypeColumnId<ItemTypeType>]?: ItemId<'Contact'>\n\t}>\n};\n\nconst dependencyColumns = [\n\t'id',\n\t'contactpersoon',\n] as const;\n\ntype Dependency = {\n\tconditionResult: ConditionResult,\n\tcontactMap: {\n\t\t[contactId: string]: ItemResource<'Contact', typeof dependencyColumns>,\n\t},\n};\n\n/**\n * This business rule is responsible for setting the default contactperson related to a\n * selected contact for itemTypes that have fields for this.\n */\n@businessLogicRule(\n\t'DefaultContactPersonUpdateBusinessLogicRule',\n)\nexport class DefaultContactPersonUpdateBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\tconst result: ConditionResult = {};\n\t\tlet hasValues: boolean = false;\n\n\t\tfor (const tuple of context.previousChangesDelta.getUpdatedTuplesIterator()) {\n\t\t\tconst columnIdMap = itemTypeFieldMap[tuple.entry.itemType];\n\n\t\t\tif (columnIdMap === undefined) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tfor (const columnId in columnIdMap) {\n\t\t\t\tif (\n\t\t\t\t\tcontext.fieldChanged(\n\t\t\t\t\t\ttuple,\n\t\t\t\t\t\tcolumnId,\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\tresult[tuple.entry.itemType] ??= new Map();\n\n\t\t\t\t\tif (\n\t\t\t\t\t\t!result[tuple.entry.itemType].has(\n\t\t\t\t\t\t\ttuple.entry,\n\t\t\t\t\t\t)\n\t\t\t\t\t) {\n\t\t\t\t\t\tresult[tuple.entry.itemType].set(\n\t\t\t\t\t\t\ttuple.entry,\n\t\t\t\t\t\t\t{},\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst mapEntry = result[tuple.entry.itemType].get(\n\t\t\t\t\t\ttuple.entry,\n\t\t\t\t\t);\n\n\t\t\t\t\tmapEntry[columnId] = tuple.changes.fields[columnId];\n\t\t\t\t\thasValues = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (!hasValues) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\tconditionResult: ConditionResult,\n\t): Promise<Dependency> {\n\t\tconst contactIds: Set<ItemId<'Contact'>> = new Set();\n\n\t\tfor (const itemType in conditionResult) {\n\t\t\tfor (const mapObj of conditionResult[itemType as ApiItemType]!.values()) {\n\t\t\t\tfor (const columnId in mapObj) {\n\t\t\t\t\tconst contactId = mapObj[columnId];\n\n\t\t\t\t\tif (contactId === null) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tcontactIds.add(\n\t\t\t\t\t\tcontactId,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst contactResources = await transaction.getItemsById(\n\t\t\t'Contact',\n\t\t\tArray.from(\n\t\t\t\tcontactIds,\n\t\t\t),\n\t\t\t{\n\t\t\t\tcolumns: dependencyColumns,\n\t\t\t},\n\t\t);\n\n\t\treturn {\n\t\t\tconditionResult,\n\t\t\tcontactMap: contactResources.reduce(\n\t\t\t\t(\n\t\t\t\t\tacc,\n\t\t\t\t\titemResource,\n\t\t\t\t) => {\n\t\t\t\t\tacc[itemResource.fields.id] = itemResource;\n\n\t\t\t\t\treturn acc;\n\t\t\t\t},\n\t\t\t\t{},\n\t\t\t),\n\t\t};\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tdependencyResult: Dependency,\n\t): void {\n\t\tfor (const itemType in dependencyResult.conditionResult) {\n\t\t\tdependencyResult.conditionResult[itemType as ApiItemType]!.forEach(\n\t\t\t\t(\n\t\t\t\t\tmapObj,\n\t\t\t\t\titemEntry,\n\t\t\t\t) => {\n\t\t\t\t\tfor (const columnId in mapObj) {\n\t\t\t\t\t\tconst personColumnId = itemTypeFieldMap[itemType][columnId];\n\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tcontext.mergedChangesDelta.hasUpdatedValue(\n\t\t\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\t\t\tpersonColumnId,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst contactId = mapObj[columnId];\n\n\t\t\t\t\t\tcontext.setItemUpdated(\n\t\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t[personColumnId]: contactId === null\n\t\t\t\t\t\t\t\t\t? null\n\t\t\t\t\t\t\t\t\t: dependencyResult.contactMap[contactId].fields.contactpersoon,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemEntry } from '../../../models/ItemEntry';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { promiseAllObject } from '../../Util';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\nconst documentTypes = [\n\t'Factuur',\n\t'Offerte',\n\t'Contract',\n\t'Bon',\n\t'Inhuurbon',\n\t'Materiaalbon',\n\t'Medewerkerbon',\n\t'Aanmaning',\n\t'Reparatiebon',\n\t'Voertuigbon',\n] as const;\n\ntype DocumentTypes = (typeof documentTypes)[number];\n\ntype ConditionResult = {\n\t[key in DocumentTypes]?: ItemId[]\n};\n\ntype Dependency = {\n\t[key in DocumentTypes]?: ItemResource<DocumentTypes, ['filename', 'betreft']>[]\n};\n\n@businessLogicRule(\n\t'DocumentTemplateBusinessLogicRule',\n)\nexport class DocumentTemplateBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\tconst updatedIterator = context.previousChangesDelta.getUpdatedTuplesIterator(\n\t\t\t...documentTypes,\n\t\t);\n\t\tconst result: ConditionResult = {};\n\n\t\tlet hasValues: boolean = false;\n\n\t\tfor (const tuple of updatedIterator) {\n\t\t\tif (\n\t\t\t\tcontext.fieldChanged(\n\t\t\t\t\ttuple,\n\t\t\t\t\t'template',\n\t\t\t\t) !== null\n\t\t\t) {\n\t\t\t\tif (result[tuple.entry.itemType] === undefined) {\n\t\t\t\t\tresult[tuple.entry.itemType] = [];\n\t\t\t\t}\n\n\t\t\t\thasValues = true;\n\n\t\t\t\tresult[tuple.entry.itemType]!.push(\n\t\t\t\t\ttuple.entry.itemId,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (!hasValues) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic dependency (\n\t\ttransaction: TransactionCache,\n\t\titemIdMap: ConditionResult,\n\t): Promise<Dependency> {\n\t\tconst promises: {\n\t\t\t[key in keyof Dependency]: Promise<Dependency[key]>\n\t\t} = {};\n\n\t\tfor (const itemType in itemIdMap) {\n\t\t\tpromises[itemType] = transaction.getItemsById(\n\t\t\t\titemType as DocumentTypes,\n\t\t\t\titemIdMap[itemType],\n\t\t\t\t{\n\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t'filename',\n\t\t\t\t\t\t'betreft',\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\treturn promiseAllObject(\n\t\t\tpromises,\n\t\t) as Promise<Dependency>;\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\titems: Dependency,\n\t): void {\n\t\tfor (const itemType in items) {\n\t\t\tfor (const itemResource of items[itemType]) {\n\t\t\t\tcontext.setItemUpdated(\n\t\t\t\t\titemResource.entry as ItemEntry<DocumentTypes>,\n\t\t\t\t\t{\n\t\t\t\t\t\tfilename: '',\n\t\t\t\t\t\tbetreft: '',\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport moment from 'moment';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = ItemId[];\n\ntype Dependency = ItemResource<'Exemplaar', ['actief']>[];\n\n@businessLogicRule(\n\t'ExemplaarAanschafdatumBusinessLogicRule',\n)\nexport class ExemplaarAanschafdatumBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\t{\n\t\t\tpreviousChangesDelta,\n\t\t}: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\tconst updatedIterator = previousChangesDelta.getUpdatedTuplesIterator(\n\t\t\t'Exemplaar',\n\t\t);\n\t\tconst result: ItemId[] = [];\n\t\tconst now: moment.Moment = moment();\n\n\t\tfor (const tuple of updatedIterator) {\n\t\t\tconst newValue = previousChangesDelta.getUpdatedValue(\n\t\t\t\ttuple.entry,\n\t\t\t\t'aanschafdatum',\n\t\t\t);\n\n\t\t\tif (\n\t\t\t\tnewValue !== undefined\n\t\t\t\t&& newValue.isAfter(\n\t\t\t\t\tnow,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tresult.push(\n\t\t\t\t\ttuple.entry.itemId,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (result.length === 0) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\texemplaarIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\treturn transaction.getItemsById(\n\t\t\t'Exemplaar',\n\t\t\texemplaarIds,\n\t\t\t{\n\t\t\t\tcolumns: [\n\t\t\t\t\t'actief',\n\t\t\t\t],\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\texemplaarResources: Dependency,\n\t): void {\n\t\tfor (const exemplaarResource of exemplaarResources) {\n\t\t\tcontext.setItemUpdated(\n\t\t\t\texemplaarResource.entry,\n\t\t\t\t{\n\t\t\t\t\tactief: true,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemEntry } from '../../../models/ItemEntry';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = ItemId[];\n\ntype Dependency = ItemEntry<'Barcode'>[];\n\n@businessLogicRule(\n\t'ExemplaarBarcodeDeleteBusinessLogicRule',\n)\nexport class ExemplaarBarcodeDeleteBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\t{\n\t\t\tpreviousChangesDelta,\n\t\t}: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\tconst deletedItemEntriesIterator = previousChangesDelta.getDeletedItemEntriesIterator(\n\t\t\t'Exemplaar',\n\t\t);\n\t\tconst result: ItemId[] = [];\n\n\t\tfor (const entry of deletedItemEntriesIterator) {\n\t\t\tresult.push(\n\t\t\t\tentry.itemId,\n\t\t\t);\n\t\t}\n\n\t\tif (result.length === 0) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\texemplaarIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\t// TODO -> replace getItemsByQuery with getItemsByParent call\n\t\tconst barcodeItems = await transaction.getItemsByQuery(\n\t\t\t'Barcode',\n\t\t\t{\n\t\t\t\tconditions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: 'itemtype',\n\t\t\t\t\t\tcomparator: '=',\n\t\t\t\t\t\tvalue: 'Exemplaar',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: 'item',\n\t\t\t\t\t\tcomparator: 'IN',\n\t\t\t\t\t\tvalue: exemplaarIds,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t\t{\n\t\t\t\tcolumns: [],\n\t\t\t},\n\t\t);\n\n\t\treturn barcodeItems.map(\n\t\t\titem =>\n\t\t\t\titem.entry,\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tbarcodeResources: Dependency,\n\t): void {\n\t\tcontext.setItemsDeleted(\n\t\t\tbarcodeResources,\n\t\t);\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicConditionResult, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\nimport { BusinessLogicRuleContextBase } from '../BusinessLogicRuleContextBase';\n\ntype ConditionResult = BusinessLogicConditionResult<'Factuur', 'betalingsconditie'>[];\n\ntype Dependency = {\n\tFactuur: ItemResource<'Factuur', ['vervaldatum', 'datum']>[],\n\tBetalingsconditie: {\n\t\t[conditieId: string]: ItemResource<'Betalingsconditie', ['dagen']>,\n\t},\n\tdefaultPaymentConditionId: ItemId | null,\n};\n\n@businessLogicRule(\n\t'FactuurBetalingsconditieBusinessLogicRule',\n)\nexport class FactuurBetalingsconditieBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\tconst updatedIterator = context.previousChangesDelta.getUpdatedTuplesIterator(\n\t\t\t'Factuur',\n\t\t);\n\t\tconst result: ConditionResult = [];\n\n\t\tfor (const tuple of updatedIterator) {\n\t\t\tconst fieldResult = context.fieldChanged(\n\t\t\t\ttuple,\n\t\t\t\t'betalingsconditie',\n\t\t\t);\n\n\t\t\tif (fieldResult !== null) {\n\t\t\t\tresult.push(\n\t\t\t\t\tfieldResult,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (result.length === 0) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\tresult: ConditionResult,\n\t\tcontext: BusinessLogicRuleContextBase,\n\t): Promise<Dependency> {\n\t\tconst factuurResources = await transaction.getItemsById(\n\t\t\t'Factuur',\n\t\t\tresult.map(\n\t\t\t\tr => r.itemEntry.itemId,\n\t\t\t),\n\t\t\t{\n\t\t\t\tcolumns: [\n\t\t\t\t\t'vervaldatum',\n\t\t\t\t\t'datum',\n\t\t\t\t],\n\t\t\t},\n\t\t);\n\n\t\tconst factuurMap: Map<null | ItemId, true> = new Map();\n\n\t\tfor (const resource of factuurResources) {\n\t\t\tconst paymentConditionId = context.mergedChangesDelta.getUpdatedValue(\n\t\t\t\tresource.entry,\n\t\t\t\t'betalingsconditie',\n\t\t\t);\n\n\t\t\tif (paymentConditionId === undefined) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tfactuurMap.set(\n\t\t\t\tpaymentConditionId,\n\t\t\t\ttrue,\n\t\t\t);\n\t\t}\n\n\t\tlet defaultPaymentConditionId: Dependency['defaultPaymentConditionId'] = null;\n\n\t\tif (\n\t\t\tfactuurMap.has(\n\t\t\t\tnull,\n\t\t\t)\n\t\t) {\n\t\t\tconst stateResource = await transaction.getItemById(\n\t\t\t\t'State',\n\t\t\t\t1,\n\t\t\t\t{\n\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t'betalingsconditie',\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tif (\n\t\t\t\tstateResource.fields.betalingsconditie !== null\n\t\t\t\t&& !factuurMap.has(\n\t\t\t\t\tstateResource.fields.betalingsconditie,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tdefaultPaymentConditionId = stateResource.fields.betalingsconditie;\n\n\t\t\t\tfactuurMap.set(\n\t\t\t\t\tstateResource.fields.betalingsconditie,\n\t\t\t\t\ttrue,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst paymentConditionIds: ItemId[] = [];\n\n\t\tfor (const itemId of factuurMap.keys()) {\n\t\t\tif (itemId !== null) {\n\t\t\t\tpaymentConditionIds.push(\n\t\t\t\t\titemId,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst paymentConditionResources = await transaction.getItemsById(\n\t\t\t'Betalingsconditie',\n\t\t\tpaymentConditionIds,\n\t\t\t{\n\t\t\t\tcolumns: [\n\t\t\t\t\t'id',\n\t\t\t\t\t'dagen',\n\t\t\t\t],\n\t\t\t},\n\t\t);\n\n\t\treturn {\n\t\t\tFactuur: factuurResources,\n\t\t\tBetalingsconditie: paymentConditionResources.reduce(\n\t\t\t\t(\n\t\t\t\t\tacc,\n\t\t\t\t\tbetalingsconditieResource,\n\t\t\t\t) => {\n\t\t\t\t\tacc[betalingsconditieResource.fields.id] = betalingsconditieResource;\n\n\t\t\t\t\treturn acc;\n\t\t\t\t},\n\t\t\t\t{},\n\t\t\t),\n\t\t\tdefaultPaymentConditionId: defaultPaymentConditionId,\n\t\t};\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tdeps: Dependency,\n\t): void {\n\t\tfor (const factuurResource of deps.Factuur) {\n\t\t\tlet newBetalingsConditie: ItemId | null = context.mergedChangesDelta.getUpdatedValue(\n\t\t\t\tfactuurResource.entry,\n\t\t\t\t'betalingsconditie',\n\t\t\t)!;\n\n\t\t\tif (newBetalingsConditie === null) {\n\t\t\t\tnewBetalingsConditie = deps.defaultPaymentConditionId;\n\t\t\t}\n\n\t\t\t// If both the updated and default payment condition are null we can't set the payment condition.\n\t\t\tif (newBetalingsConditie === null) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tcontext.setItemUpdated(\n\t\t\t\tfactuurResource.entry,\n\t\t\t\t{\n\t\t\t\t\tvervaldatum: factuurResource.fields.datum\n\t\t\t\t\t\t.clone()\n\t\t\t\t\t\t.add(\n\t\t\t\t\t\t\tdeps.Betalingsconditie[newBetalingsConditie].fields.dagen,\n\t\t\t\t\t\t\t'days',\n\t\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\nimport { BusinessLogicRuleContextBase } from '../BusinessLogicRuleContextBase';\n\ntype ConditionResult = ItemId[];\n\ntype Dependency = {\n\tFactuur: ItemResource<'Factuur', ['vervaldatum', 'betalingsconditie']>[],\n\tBetalingsconditie: {\n\t\t[conditieId: string]: ItemResource<'Betalingsconditie', ['dagen']>,\n\t},\n\tlatestTaxSchemasByDateMap: {\n\t\t[taxschemaId: string]: ItemId<'TaxSchema'>,\n\t},\n};\n\n@businessLogicRule(\n\t'FactuurDatumBusinessLogicRule',\n)\nexport class FactuurDatumBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\treturn context.getItemIdsWithUpdatedField(\n\t\t\t'Factuur',\n\t\t\t'datum',\n\t\t);\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\tfactuurIds: ConditionResult,\n\t\tcontext: BusinessLogicRuleContextBase,\n\t): Promise<Dependency> {\n\t\tconst factuurResources = await transaction.getItemsById(\n\t\t\t'Factuur',\n\t\t\tfactuurIds,\n\t\t\t{\n\t\t\t\tcolumns: [\n\t\t\t\t\t'taxschema',\n\t\t\t\t\t'vervaldatum',\n\t\t\t\t\t'betalingsconditie',\n\t\t\t\t\t'datum',\n\t\t\t\t],\n\t\t\t},\n\t\t);\n\n\t\tconst paymentConditionIds: ItemId[] = factuurResources\n\t\t\t.map(\n\t\t\t\tresource => resource.fields.betalingsconditie,\n\t\t\t)\n\t\t\t// Filter out null values and duplicates\n\t\t\t.filter(\n\t\t\t\t(\n\t\t\t\t\tid,\n\t\t\t\t\tindex,\n\t\t\t\t\tarr,\n\t\t\t\t) => id !== null\n\t\t\t\t\t&& arr.indexOf(\n\t\t\t\t\t\tid,\n\t\t\t\t\t) === index,\n\t\t\t);\n\n\t\tconst paymentConditionResources = await transaction.getItemsById(\n\t\t\t'Betalingsconditie',\n\t\t\tpaymentConditionIds,\n\t\t\t{\n\t\t\t\tcolumns: [\n\t\t\t\t\t'id',\n\t\t\t\t\t'dagen',\n\t\t\t\t],\n\t\t\t},\n\t\t);\n\n\t\tconst result = await Promise.all(\n\t\t\tfactuurResources.map(\n\t\t\t\tfactuurResource => transaction.core.apiRequestService.module<ItemId<'TaxSchema'>>(\n\t\t\t\t\t'taxes',\n\t\t\t\t\t'getTaxRateForDate',\n\t\t\t\t\t{\n\t\t\t\t\t\tschemaId: context.getLatestValue(\n\t\t\t\t\t\t\tfactuurResource.entry,\n\t\t\t\t\t\t\t'taxschema',\n\t\t\t\t\t\t),\n\t\t\t\t\t\tdate: context.getLatestValue(\n\t\t\t\t\t\t\tfactuurResource.entry,\n\t\t\t\t\t\t\t'datum',\n\t\t\t\t\t\t),\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\n\t\tconst latestTaxSchemaByDateMap = {};\n\n\t\tfor (let i = 0; i < factuurResources.length; i++) {\n\t\t\tconst factuurId = context.getLatestValue(\n\t\t\t\tfactuurResources[i].entry,\n\t\t\t\t'id',\n\t\t\t)!;\n\n\t\t\tlatestTaxSchemaByDateMap[factuurId] = result[i];\n\t\t}\n\n\t\treturn {\n\t\t\tFactuur: factuurResources,\n\t\t\tBetalingsconditie: paymentConditionResources.reduce(\n\t\t\t\t(\n\t\t\t\t\tacc,\n\t\t\t\t\tbetalingsconditieResource,\n\t\t\t\t) => {\n\t\t\t\t\tacc[betalingsconditieResource.fields.id] = betalingsconditieResource;\n\n\t\t\t\t\treturn acc;\n\t\t\t\t},\n\t\t\t\t{},\n\t\t\t),\n\t\t\tlatestTaxSchemasByDateMap: latestTaxSchemaByDateMap,\n\t\t};\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tdeps: Dependency,\n\t): void {\n\t\tfor (const factuurResource of deps.Factuur) {\n\t\t\tconst factuurId = context.getLatestValue(\n\t\t\t\tfactuurResource.entry,\n\t\t\t\t'id',\n\t\t\t)!;\n\t\t\tconst taxSchemaId = context.getLatestValue(\n\t\t\t\tfactuurResource.entry,\n\t\t\t\t'taxschema',\n\t\t\t)!;\n\n\t\t\tif (taxSchemaId !== deps.latestTaxSchemasByDateMap[factuurId]) {\n\t\t\t\tcontext.setItemUpdated(\n\t\t\t\t\tfactuurResource.entry,\n\t\t\t\t\t{\n\t\t\t\t\t\ttaxschema: deps.latestTaxSchemasByDateMap[factuurId],\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (factuurResource.fields.betalingsconditie !== null) {\n\t\t\t\tconst newDatum = context.getLatestValue(\n\t\t\t\t\tfactuurResource.entry,\n\t\t\t\t\t'datum',\n\t\t\t\t)!;\n\t\t\t\tconst latestBelatingconditie = context.getLatestValue(\n\t\t\t\t\tfactuurResource.entry,\n\t\t\t\t\t'betalingsconditie',\n\t\t\t\t)!;\n\t\t\t\tconst betalingconditieDays = context.getLatestValue(\n\t\t\t\t\tdeps.Betalingsconditie[latestBelatingconditie].entry,\n\t\t\t\t\t'dagen',\n\t\t\t\t);\n\n\t\t\t\tcontext.setItemUpdated(\n\t\t\t\t\tfactuurResource.entry,\n\t\t\t\t\t{\n\t\t\t\t\t\tvervaldatum: newDatum\n\t\t\t\t\t\t\t.clone()\n\t\t\t\t\t\t\t.add(\n\t\t\t\t\t\t\t\tbetalingconditieDays,\n\t\t\t\t\t\t\t\t'days',\n\t\t\t\t\t\t\t),\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = ItemId[];\n\ntype Dependency = ItemResource<'Factuur', ['nummer']>[];\n\n@businessLogicRule(\n\t'FactuurNumberseriesBusinessLogicRule',\n)\nexport class FactuurNumberseriesBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\treturn context.getItemIdsWithUpdatedField(\n\t\t\t'Factuur',\n\t\t\t'numberseries',\n\t\t);\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\tfactuurIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\treturn transaction.getItemsById(\n\t\t\t'Factuur',\n\t\t\tfactuurIds,\n\t\t\t{\n\t\t\t\tcolumns: [\n\t\t\t\t\t'nummer',\n\t\t\t\t],\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tfactuurResources: Dependency,\n\t): void {\n\t\tfor (const factuurResource of factuurResources) {\n\t\t\tcontext.setItemUpdated(\n\t\t\t\tfactuurResource.entry,\n\t\t\t\t{\n\t\t\t\t\t// todo[types] remove this when NULL_BEHAVIOUR is properly worked out\n\t\t\t\t\tnummer: null as unknown as string,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { ApiRequestColumns } from '../../../types/ItemTypesCollection';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = ItemId[];\n\nconst filesColumns = [\n\t'name',\n\t'friendlyname',\n] as const satisfies ApiRequestColumns<'Files'>;\n\ntype Dependency = ItemResource<'Files', ['name', 'friendlyname']>[];\n\n/**\n * @description\n * Automatically appends the file extension again when the user removes it from the name\n * so that, when the file is downloaded, it is still properly openable\n */\n@businessLogicRule(\n\t'FilesNameExtensionBusinessLogicRule',\n)\nexport class FilesNameExtensionBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tprivate static getExtension (\n\t\tstr: string,\n\t): string | null {\n\t\tconst index = str.lastIndexOf(\n\t\t\t'.',\n\t\t);\n\n\t\tif (index === -1) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn str.slice(\n\t\t\tindex,\n\t\t);\n\t}\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\tconst updatedIterator = context.previousChangesDelta.getUpdatedTuplesIterator(\n\t\t\t'Files',\n\t\t);\n\t\tconst result: ItemId<'Files'>[] = [];\n\n\t\tfor (const tuple of updatedIterator) {\n\t\t\tif (\n\t\t\t\tcontext.fieldChanged(\n\t\t\t\t\ttuple,\n\t\t\t\t\t'name',\n\t\t\t\t) !== null\n\t\t\t\t|| context.fieldChanged(\n\t\t\t\t\ttuple,\n\t\t\t\t\t'friendlyname',\n\t\t\t\t) !== null\n\t\t\t) {\n\t\t\t\tresult.push(\n\t\t\t\t\ttuple.entry.itemId,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (result.length === 0) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\tfileIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\treturn transaction.getItemsById(\n\t\t\t'Files',\n\t\t\tfileIds,\n\t\t\t{\n\t\t\t\tcolumns: [\n\t\t\t\t\t'name',\n\t\t\t\t\t'friendlyname',\n\t\t\t\t],\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tfileResources: Dependency,\n\t): void {\n\t\tfor (const fileResource of fileResources) {\n\t\t\tfor (const columnId of filesColumns) {\n\t\t\t\tconst previousValue = context.transaction.itemHandler.lookUpItemField(\n\t\t\t\t\tfileResource.entry,\n\t\t\t\t\tcolumnId,\n\t\t\t\t);\n\n\t\t\t\tconst newValue = context.getLatestValue(\n\t\t\t\t\tfileResource.entry,\n\t\t\t\t\tcolumnId,\n\t\t\t\t);\n\n\t\t\t\tif (\n\t\t\t\t\tpreviousValue === undefined\n\t\t\t\t\t|| newValue === undefined\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst previousExtension = FilesNameExtensionBusinessLogicRule.getExtension(\n\t\t\t\t\tpreviousValue,\n\t\t\t\t);\n\n\t\t\t\tconst newExtension = FilesNameExtensionBusinessLogicRule.getExtension(\n\t\t\t\t\tnewValue,\n\t\t\t\t);\n\n\t\t\t\tif (previousExtension === null) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\tnewExtension === null\n\t\t\t\t\t|| newExtension !== previousExtension\n\t\t\t\t) {\n\t\t\t\t\tcontext.setItemUpdated(\n\t\t\t\t\t\tfileResource.entry,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t[columnId]: newValue + previousExtension,\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = ItemId[];\n\ntype Dependency = ItemResource<'Functie', ['naamintern']>[];\n\n/**\n * @description\n * If the `naamofferte` is set and the user hasn't filled in a `naamintern` we sync the fields\n */\n@businessLogicRule(\n\t'FunctieNaaminternBusinessLogicRule',\n)\nexport class FunctieNaaminternBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\treturn context.getItemIdsWithUpdatedField(\n\t\t\t'Functie',\n\t\t\t'naamofferte',\n\t\t);\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\tfunctionIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\treturn transaction.getItemsById(\n\t\t\t'Functie',\n\t\t\tfunctionIds,\n\t\t\t{\n\t\t\t\tcolumns: [\n\t\t\t\t\t'naamintern',\n\t\t\t\t],\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tfunctionResources: Dependency,\n\t): void {\n\t\tfor (const functionResource of functionResources) {\n\t\t\t// We don't want to overwrite the 'naamintern' if the user already set one\n\t\t\tif (\n\t\t\t\tcontext\n\t\t\t\t\t.getLatestValue(\n\t\t\t\t\t\tfunctionResource.entry,\n\t\t\t\t\t\t'naamintern',\n\t\t\t\t\t)!\n\t\t\t\t\t.trim() !== ''\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tcontext.setItemUpdated(\n\t\t\t\tfunctionResource.entry,\n\t\t\t\t{\n\t\t\t\t\tnaamintern: context.mergedChangesDelta.getUpdatedValue(\n\t\t\t\t\t\tfunctionResource.entry,\n\t\t\t\t\t\t'naamofferte',\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { businessLogicRule } from '../businessLogicRule.decorator';\nimport { RecurrentItemRecureindBusinessLogicRule } from '../RecurrentItem/RecurrentItemRecureindBusinessLogicRule';\n\n@businessLogicRule(\n\t'FunctieRecureindBusinessLogicRule',\n)\nexport class FunctieRecureindBusinessLogicRule\n\textends RecurrentItemRecureindBusinessLogicRule<'Functie', 'plantot'> {\n\n\tprotected override itemType = 'Functie' as const;\n\n\tprotected override toField = 'plantot' as const;\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = ItemId[];\n\ntype Dependency = ItemResource<'Functie', ['afstand']>[];\n\n@businessLogicRule(\n\t'FunctieTwowayBusinessLogicRule',\n)\nexport class FunctieTwowayBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\treturn context.getItemIdsWithUpdatedField(\n\t\t\t'Functie',\n\t\t\t'twoway',\n\t\t);\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\tfunctionIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\treturn transaction.getItemsById(\n\t\t\t'Functie',\n\t\t\tfunctionIds,\n\t\t\t{\n\t\t\t\tcolumns: [\n\t\t\t\t\t'afstand',\n\t\t\t\t],\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tfunctionResources: Dependency,\n\t): void {\n\t\tfor (const functionResource of functionResources) {\n\t\t\tcontext.setItemUpdated(\n\t\t\t\tfunctionResource.entry,\n\t\t\t\t{\n\t\t\t\t\tafstand: functionResource.fields.afstand * (\n\t\t\t\t\t\tcontext.mergedChangesDelta.getUpdatedValue(\n\t\t\t\t\t\t\tfunctionResource.entry,\n\t\t\t\t\t\t\t'twoway',\n\t\t\t\t\t\t) === true\n\t\t\t\t\t\t\t? 2\n\t\t\t\t\t\t\t: 0.5\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ItemResource } from '../../../models/ItemResource';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicConditionResult, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = BusinessLogicConditionResult<'Functiegroep', 'subproject'>[];\ntype Dependency = ItemResource<'Functie', ['subproject']>[][];\n\n/**\n * When the subproject field of a function group is updated, set the subproject field of all the functions within the\n * function group to the same value.\n */\n@businessLogicRule(\n\t'FunctiegroepSubprojectBusinessLogicRule',\n)\nexport class FunctiegroepSubprojectBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic override condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\tconst updatedIterator = context.previousChangesDelta.getUpdatedTuplesIterator(\n\t\t\t'Functiegroep',\n\t\t);\n\t\tconst result: ConditionResult = [];\n\n\t\tfor (const tuple of updatedIterator) {\n\t\t\tconst changedFieldTuple = context.fieldChanged(\n\t\t\t\ttuple,\n\t\t\t\t'subproject',\n\t\t\t);\n\n\t\t\tif (changedFieldTuple !== null) {\n\t\t\t\tresult.push(\n\t\t\t\t\tchangedFieldTuple,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (result.length === 0) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic override dependency (\n\t\ttransaction: TransactionCache,\n\t\tconditionResult: ConditionResult,\n\t): Promise<Dependency> {\n\t\treturn Promise.all(\n\t\t\tconditionResult.map(\n\t\t\t\tchangedFieldTuple => transaction.getItemsByQuery(\n\t\t\t\t\t'Functie',\n\t\t\t\t\t{\n\t\t\t\t\t\tfunctiegroep: changedFieldTuple.itemEntry.itemId,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\t'subproject',\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\t}\n\n\tpublic override apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tfunctionResourcesArray: Dependency,\n\t\tconditionResult: ConditionResult,\n\t): void {\n\t\tfor (let i = 0; i < conditionResult.length; i++) {\n\t\t\tfor (const functionResource of functionResourcesArray[i]) {\n\t\t\t\tcontext.setUpdatedValue(\n\t\t\t\t\tfunctionResource.entry,\n\t\t\t\t\t'subproject',\n\t\t\t\t\tconditionResult[i].newValue,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../models/ItemResource';\nimport { FieldMap, GetFieldValueType, RequestColumnsFieldMap } from '../../types/ItemTypesCollection';\nimport { TransactionCache } from '../cache/transaction/TransactionCache';\nimport { ChangesDeltaItemCreateDelta } from '../CreatedChangesDelta';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from './BusinessLogicRule';\nimport { BusinessLogicRuleApplyContext } from './BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from './BusinessLogicRuleConditionContext';\nimport { BusinessLogicRuleContextBase } from './BusinessLogicRuleContextBase';\n\nexport const commonEquipmentColumns = [\n\t'id',\n\t'aantal',\n\t'parent',\n\t'materiaal',\n] as const;\n\ntype MateriaalTypeMap = {\n\t[equipmentId: number]: GetFieldValueType<'Materiaal', 'type'>,\n};\n\ntype MateriaalType = 'Planningmateriaal' | 'Inhuurmateriaal';\n\ntype ConditionResult<ItemTypeType extends MateriaalType> = {\n\tcreated: ChangesDeltaItemCreateDelta<ItemTypeType>[],\n\tupdated: ItemId[],\n};\n\ntype Dependency<ItemTypeType extends MateriaalType> = {\n\tcreatedTuples: ChangesDeltaItemCreateDelta<ItemTypeType>[],\n\tupdatedItemResources: ItemResource<ItemTypeType, typeof commonEquipmentColumns>[],\n\tmateriaalTypeMap: MateriaalTypeMap,\n};\n\n/**\n * @description\n * If Planningmateriaal 'aantal' is changed make sure it is rounded for rental items.\n * Note: We're assuming 'aantal' is fractional only for sets & set's content here.\n */\n\nexport abstract class AantalBusinessLogicRuleBase<ItemTypeType extends MateriaalType>\n\textends BusinessLogicRule<ConditionResult<ItemTypeType>, Dependency<ItemTypeType>> {\n\n\tprotected readonly itemType: ItemTypeType;\n\n\tpublic condition (\n\t\t{\n\t\t\tpreviousChangesDelta,\n\t\t\ttransaction,\n\t\t}: BusinessLogicRuleConditionContext,\n\t): ConditionResult<ItemTypeType> | typeof BLR_SKIP_RULE {\n\t\tconst created: ChangesDeltaItemCreateDelta[] = [];\n\t\tconst updated: ItemId[] = [];\n\n\t\tpreviousChangesDelta.created.forEachOfItemType(\n\t\t\tthis.itemType,\n\t\t\tcreateChangesTuple => {\n\t\t\t\tif (createChangesTuple.fields.materiaal !== null) {\n\t\t\t\t\tcreated.push(\n\t\t\t\t\t\tcreateChangesTuple,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\n\t\tconst updatedIterator = previousChangesDelta.getUpdatedTuplesIterator(\n\t\t\tthis.itemType,\n\t\t);\n\n\t\tfor (const tuple of updatedIterator) {\n\t\t\tif (\n\t\t\t\t(\n\t\t\t\t\tpreviousChangesDelta.hasUpdatedValue(\n\t\t\t\t\t\ttuple.entry,\n\t\t\t\t\t\t'aantal',\n\t\t\t\t\t)\n\t\t\t\t\t|| previousChangesDelta.hasUpdatedValue(\n\t\t\t\t\t\ttuple.entry,\n\t\t\t\t\t\t'parent',\n\t\t\t\t\t)\n\t\t\t\t) && transaction.itemHandler.lookUpItemField(\n\t\t\t\t\ttuple.entry,\n\t\t\t\t\t'materiaal',\n\t\t\t\t) !== null\n\t\t\t) {\n\t\t\t\tupdated.push(\n\t\t\t\t\ttuple.entry.itemId,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (\n\t\t\tcreated.length === 0\n\t\t\t&& updated.length === 0\n\t\t) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn {\n\t\t\tcreated,\n\t\t\tupdated,\n\t\t};\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\tconditionResult: ConditionResult<ItemTypeType>,\n\t\tcontext: BusinessLogicRuleContextBase,\n\t): Promise<Dependency<ItemTypeType>> {\n\t\tconst updatedItemResources = await transaction.getItemsById(\n\t\t\tthis.itemType,\n\t\t\tconditionResult.updated,\n\t\t\t{\n\t\t\t\tcolumns: commonEquipmentColumns,\n\t\t\t},\n\t\t);\n\n\t\tconst materiaalIds: Set<ItemId> = new Set();\n\n\t\tfor (const createdTuple of conditionResult.created) {\n\t\t\tmateriaalIds.add(\n\t\t\t\tcreatedTuple.fields.materiaal as number,\n\t\t\t);\n\t\t}\n\n\t\tfor (const itemResource of updatedItemResources) {\n\t\t\tmateriaalIds.add(\n\t\t\t\t(itemResource.fields as RequestColumnsFieldMap<MateriaalType, typeof commonEquipmentColumns>).materiaal!,\n\t\t\t);\n\t\t}\n\n\t\tconst materiaalTypeMap = await this.getMateriaalTypeMap(\n\t\t\tcontext,\n\t\t\tArray.from(\n\t\t\t\tmateriaalIds,\n\t\t\t),\n\t\t);\n\n\t\treturn {\n\t\t\tcreatedTuples: conditionResult.created,\n\t\t\tupdatedItemResources: updatedItemResources,\n\t\t\tmateriaalTypeMap: materiaalTypeMap,\n\t\t};\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tdependency: Dependency<ItemTypeType>,\n\t): void {\n\t\tfor (const changedResource of dependency.updatedItemResources) {\n\t\t\tconst newQuantity = context.getLatestValue(\n\t\t\t\tchangedResource.entry,\n\t\t\t\t'aantal',\n\t\t\t) as number;\n\n\t\t\tconst newParent = context.getLatestValue(\n\t\t\t\tchangedResource.entry,\n\t\t\t\t'parent',\n\t\t\t) as number;\n\n\t\t\tconst materiaalType = dependency.materiaalTypeMap[(changedResource.fields as FieldMap<MateriaalType>).materiaal!];\n\n\t\t\tif (\n\t\t\t\tmateriaalType === 'set'\n\t\t\t\t|| newParent !== null\n\t\t\t\t|| Number.isInteger(\n\t\t\t\t\tnewQuantity,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tcontext.setItemUpdated(\n\t\t\t\tchangedResource.entry,\n\t\t\t\t{\n\t\t\t\t\taantal: Math.ceil(\n\t\t\t\t\t\tnewQuantity,\n\t\t\t\t\t),\n\t\t\t\t} as Partial<FieldMap<ItemTypeType>>,\n\t\t\t);\n\t\t}\n\n\t\tfor (const createdItem of dependency.createdTuples) {\n\t\t\tconst materiaalType = dependency.materiaalTypeMap[createdItem.fields.materiaal as number];\n\n\t\t\tif (\n\t\t\t\tmateriaalType === 'set'\n\t\t\t\t|| createdItem.fields.parent !== null\n\t\t\t\t|| Number.isInteger(\n\t\t\t\t\tcreatedItem.fields.aantal,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tcontext.destinationChangesDelta.setItemCreatedByTuple(\n\t\t\t\tcreatedItem,\n\t\t\t\t{\n\t\t\t\t\taantal: Math.ceil(\n\t\t\t\t\t\tcreatedItem.fields.aantal as number,\n\t\t\t\t\t),\n\t\t\t\t} as Partial<FieldMap<ItemTypeType>>,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate async getMateriaalTypeMap (\n\t\tcontext: BusinessLogicRuleContextBase,\n\t\tmateriaalIds: ItemId[],\n\t): Promise<MateriaalTypeMap> {\n\t\tconst equipmentResources = await context.fetchLatestItemsById(\n\t\t\t'Materiaal',\n\t\t\tmateriaalIds,\n\t\t\t[\n\t\t\t\t'id',\n\t\t\t\t'type',\n\t\t\t],\n\t\t);\n\n\t\tconst materiaalTypeMap: MateriaalTypeMap = {};\n\n\t\tfor (const equipmentResource of equipmentResources) {\n\t\t\tmateriaalTypeMap[equipmentResource.fields.id] = equipmentResource.fields.type;\n\t\t}\n\n\t\treturn materiaalTypeMap;\n\t}\n\n}\n","import { AantalBusinessLogicRuleBase } from '../AantalBusinessLogicRuleBase';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\n\n@businessLogicRule(\n\t'InhuurmateriaalAantalBusinessLogicRule',\n)\nexport class InhuurmateriaalAantalBusinessLogicRule\n\textends AantalBusinessLogicRuleBase<'Inhuurmateriaal'> {\n\n\tprotected readonly itemType = 'Inhuurmateriaal';\n\n}\n","export class CriticalBusinessLogicRuleException\n\textends Error {\n\n\tpublic constructor (\n\t\tmessage: string,\n\t\tpublic readonly context?: any,\n\t) {\n\t\tsuper(\n\t\t\tmessage,\n\t\t);\n\t}\n\n}","import { ItemId } from '@rentman/backend-types';\nimport { CriticalBusinessLogicRuleException } from '../../exceptions/CriticalBusinessLogicRuleException';\nimport { ApiRequestColumnArray } from '../../types/ItemTypesCollection';\nimport { TransactionCache } from '../cache/transaction/TransactionCache';\nimport { ChangesDeltaItemCreateDelta } from '../CreatedChangesDelta';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from './BusinessLogicRule';\nimport { BusinessLogicRuleApplyContext } from './BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from './BusinessLogicRuleConditionContext';\nimport { BusinessLogicRuleContextBase, LatestItem } from './BusinessLogicRuleContextBase';\n\nconst commonEquipmentColumns = [\n\t'id',\n\t'aantal',\n\t'aantaltotaal',\n\t'parent',\n\t'materiaal',\n] as const;\n\nexport const plannedEquipmentColumns = [\n\t...commonEquipmentColumns,\n\t'categorie',\n] as const satisfies ApiRequestColumnArray<'Planningmateriaal'>;\n\nexport const subhireEquipmentColumns = [\n\t...commonEquipmentColumns,\n\t'inhuurgroep',\n] as const satisfies ApiRequestColumnArray<'Inhuurmateriaal'>;\n\ntype PlannedEquipmentItemType = 'Planningmateriaal' | 'Inhuurmateriaal';\n\ntype LatestEquipmentItem<ItemTypeType extends PlannedEquipmentItemType> = {\n\tPlanningmateriaal: LatestItem<'Planningmateriaal', typeof commonEquipmentColumns>,\n\tInhuurmateriaal: LatestItem<'Inhuurmateriaal', typeof commonEquipmentColumns>,\n}[ItemTypeType];\n\ntype LatestEquipmentItemIdMap<ItemTypeType extends PlannedEquipmentItemType> = Map<ItemId, LatestEquipmentItem<ItemTypeType>>;\n\ntype LatestEquipmentItemParentMap<ItemTypeType extends PlannedEquipmentItemType>\n\t= Map<ItemId | null, LatestEquipmentItem<ItemTypeType>[]>;\n\ntype EquipmentIsPhysicalMap = Map<ItemId<'Materiaal'> | null, boolean>;\n\ninterface Dependency<ItemTypeType extends PlannedEquipmentItemType> {\n\t/**\n\t * Because the fractional total quantity is not stored with the item (only the ceiled value is), we need to\n\t * calculate it starting at the root item(s) of the items we'd like to update.\n\t */\n\trootItemIds: Iterable<ItemId<ItemTypeType>>,\n\t/**\n\t * We're requesting all planned equipment items in affected groups because we need both the ancestors and the\n\t * descendants of the created / updated items. The ancestors to determine the root items, and the descendants\n\t * because their total quantity will change as well.\n\t */\n\taffectedEquipmentItemsByParent: LatestEquipmentItemParentMap<ItemTypeType>,\n\taffectedEquipmentItemsById: LatestEquipmentItemIdMap<ItemTypeType>,\n\tequipmentIsPhysicalMap: EquipmentIsPhysicalMap,\n}\n\n/**\n * @description\n * If Planningmateriaal total is changed recalculate the fields\n * Note: We're assuming 'aantal' is fractional only for sets here.\n */\nexport abstract class AantaltotaalBusinessLogicRuleBase<ItemTypeType extends PlannedEquipmentItemType>\n\textends BusinessLogicRule<LatestEquipmentItem<ItemTypeType>[], Dependency<ItemTypeType>> {\n\n\tprotected abstract readonly itemType: ItemTypeType;\n\n\tprotected abstract readonly groupingProperties: {\n\t\tPlanningmateriaal: {\n\t\t\titemType: 'MateriaalCat',\n\t\t\tcolumnId: 'categorie',\n\t\t},\n\t\tInhuurmateriaal: {\n\t\t\titemType: 'Inhuurgroep',\n\t\t\tcolumnId: 'inhuurgroep',\n\t\t},\n\t}[ItemTypeType];\n\n\tprotected abstract readonly requestColumns: {\n\t\tPlanningmateriaal: typeof plannedEquipmentColumns,\n\t\tInhuurmateriaal: typeof subhireEquipmentColumns,\n\t}[ItemTypeType];\n\n\tpublic async condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): Promise<LatestEquipmentItem<ItemTypeType>[] | typeof BLR_SKIP_RULE> {\n\t\tconst created: ChangesDeltaItemCreateDelta<ItemTypeType>[] = [];\n\n\t\tcontext.previousChangesDelta.created.forEachOfItemType(\n\t\t\tthis.itemType,\n\t\t\tcreateChangesTuple => {\n\t\t\t\tif (createChangesTuple.fields.materiaal !== null) {\n\t\t\t\t\tcreated.push(\n\t\t\t\t\t\tcreateChangesTuple,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\n\t\tconst updatedIterator = context.previousChangesDelta.getUpdatedTuplesIterator(\n\t\t\tthis.itemType,\n\t\t);\n\t\tconst updated: ItemId[] = [];\n\n\t\tfor (const tuple of updatedIterator) {\n\t\t\tif (\n\t\t\t\t(\n\t\t\t\t\tcontext.previousChangesDelta.hasUpdatedValue(\n\t\t\t\t\t\ttuple.entry,\n\t\t\t\t\t\t'aantal',\n\t\t\t\t\t)\n\t\t\t\t\t|| context.previousChangesDelta.hasUpdatedValue(\n\t\t\t\t\t\ttuple.entry,\n\t\t\t\t\t\t'parent',\n\t\t\t\t\t)\n\t\t\t\t) && context.getLatestValue(\n\t\t\t\t\ttuple.entry,\n\t\t\t\t\t'materiaal',\n\t\t\t\t) !== null\n\t\t\t) {\n\t\t\t\tupdated.push(\n\t\t\t\t\ttuple.entry.itemId,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (\n\t\t\tcreated.length === 0\n\t\t\t&& updated.length === 0\n\t\t) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn [\n\t\t\t...created,\n\t\t\t...await context.fetchUpdatedLatestItemsById(\n\t\t\t\tthis.itemType,\n\t\t\t\tupdated,\n\t\t\t\tthis.requestColumns as unknown as typeof commonEquipmentColumns,\n\t\t\t),\n\t\t] as LatestEquipmentItem<any>[] as LatestEquipmentItem<ItemTypeType>[];\n\t}\n\n\tpublic async dependency (\n\t\t_transaction: TransactionCache,\n\t\taffectedEquipmentItems: LatestEquipmentItem<ItemTypeType>[],\n\t\tcontext: BusinessLogicRuleContextBase,\n\t): Promise<Dependency<ItemTypeType>> {\n\t\tconst equipmentGroupIdSet: Set<ItemId> = new Set();\n\n\t\tfor (const affectedEquipmentItem of affectedEquipmentItems) {\n\t\t\tequipmentGroupIdSet.add(\n\t\t\t\taffectedEquipmentItem.fields[this.groupingProperties.columnId],\n\t\t\t);\n\t\t}\n\n\t\tconst itemsInAffectedGroupsMap = await context.fetchLatestItemsByParent(\n\t\t\tthis.groupingProperties.itemType,\n\t\t\t[\n\t\t\t\t...equipmentGroupIdSet,\n\t\t\t],\n\t\t\tthis.itemType,\n\t\t\tthis.requestColumns as unknown as typeof commonEquipmentColumns,\n\t\t);\n\n\t\tconst affectedEquipmentItemsById: LatestEquipmentItemIdMap<ItemTypeType> = new Map();\n\t\tconst affectedEquipmentItemsByParent: LatestEquipmentItemParentMap<ItemTypeType> = new Map();\n\n\t\t// Note that `itemsInAffectedGroupsMap` will contain updated and created items (from the merged changes delta)\n\t\t// as well. When running a business logic rule, we can assume that all changes present in the previous changes\n\t\t// delta are present in the merged changes delta as well, so there's no need to iterate over the condition result\n\t\t// here.\n\t\tfor (const itemsInAffectedGroups of itemsInAffectedGroupsMap.values()) {\n\t\t\tfor (const itemInAffectedGroup of itemsInAffectedGroups as LatestEquipmentItem<any>[] as LatestEquipmentItem<ItemTypeType>[]) {\n\t\t\t\taffectedEquipmentItemsById.set(\n\t\t\t\t\titemInAffectedGroup.fields.id,\n\t\t\t\t\titemInAffectedGroup,\n\t\t\t\t);\n\n\t\t\t\tconst parentId = itemInAffectedGroup.fields.parent;\n\n\t\t\t\tif (parentId === undefined) {\n\t\t\t\t\tthrow new CriticalBusinessLogicRuleException(\n\t\t\t\t\t\t'AantaltotaalBusinessLogicRuleBase: \\'parent\\' field missing for planned equipment item',\n\t\t\t\t\t\t// Cast to member of union to avoid type shenanigans.\n\t\t\t\t\t\tcontext.collectFields(\n\t\t\t\t\t\t\titemInAffectedGroup as LatestEquipmentItem<'Planningmateriaal'>,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tlet siblingItems = affectedEquipmentItemsByParent.get(\n\t\t\t\t\tparentId,\n\t\t\t\t);\n\n\t\t\t\tif (siblingItems === undefined) {\n\t\t\t\t\taffectedEquipmentItemsByParent.set(\n\t\t\t\t\t\tparentId,\n\t\t\t\t\t\tsiblingItems = [],\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tsiblingItems.push(\n\t\t\t\t\titemInAffectedGroup,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// We're using a set of item IDs here because equipment items can occur in `affectedEquipmentItems` themselves,\n\t\t// while also being a parent of another item that occurs in `affectedEquipmentItems`.\n\t\tconst rootItemIds: Set<ItemId<ItemTypeType>> = new Set();\n\n\t\tfor (const affectedEquipmentItem of affectedEquipmentItems) {\n\t\t\tlet currentItem = affectedEquipmentItem;\n\t\t\tlet parentId = currentItem.fields.parent;\n\n\t\t\twhile (parentId !== null) {\n\t\t\t\tconst parentItem = affectedEquipmentItemsById.get(\n\t\t\t\t\tparentId,\n\t\t\t\t);\n\n\t\t\t\tif (parentItem === undefined) {\n\t\t\t\t\tthrow new CriticalBusinessLogicRuleException(\n\t\t\t\t\t\t'AantaltotaalBusinessLogicRuleBase: parent planned equipment item not available in equipment group',\n\t\t\t\t\t\tcontext.collectFields(\n\t\t\t\t\t\t\t// Cast to member of union to avoid type shenanigans.\n\t\t\t\t\t\t\tcurrentItem as LatestEquipmentItem<'Planningmateriaal'>,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tcurrentItem = parentItem;\n\t\t\t\tparentId = currentItem.fields.parent;\n\t\t\t}\n\n\t\t\trootItemIds.add(\n\t\t\t\tcurrentItem.fields.id,\n\t\t\t);\n\t\t}\n\n\t\tconst equipmentIsPhysicalMap = await this.fetchEquipmentIsPhysicalMap(\n\t\t\t// We need to know which of the combinations are physical in order to round up the content. By iterating\n\t\t\t// over the root IDs we ensure we only request the `is_physical` property for combinations that are\n\t\t\t// necessary to determine the total quantity.\n\t\t\trootItemIds,\n\t\t\taffectedEquipmentItemsById,\n\t\t\taffectedEquipmentItemsByParent,\n\t\t\tcontext,\n\t\t);\n\n\t\treturn {\n\t\t\trootItemIds,\n\t\t\taffectedEquipmentItemsByParent,\n\t\t\taffectedEquipmentItemsById,\n\t\t\tequipmentIsPhysicalMap,\n\t\t};\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tdependency: Dependency<ItemTypeType>,\n\t): void {\n\t\tfor (const rootItemId of dependency.rootItemIds) {\n\t\t\tthis.updatePlannedEquipmentItem(\n\t\t\t\tcontext,\n\t\t\t\t// Cast to member of union to avoid type shenanigans.\n\t\t\t\tdependency.affectedEquipmentItemsById.get(\n\t\t\t\t\trootItemId,\n\t\t\t\t) as LatestEquipmentItem<'Planningmateriaal'> | undefined,\n\t\t\t\t1,\n\t\t\t\tdependency as Dependency<'Planningmateriaal'>,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate async fetchEquipmentIsPhysicalMap (\n\t\trootItemIds: Iterable<ItemId<ItemTypeType>>,\n\t\taffectedEquipmentItemsById: LatestEquipmentItemIdMap<ItemTypeType>,\n\t\taffectedEquipmentItemsByParent: LatestEquipmentItemParentMap<ItemTypeType> = new Map(),\n\t\tcontext: BusinessLogicRuleContextBase,\n\t): Promise<EquipmentIsPhysicalMap> {\n\t\tconst equipmentIdSet: Set<ItemId<'Materiaal'>> = new Set();\n\n\t\tconst expandEquipmentIdSet: (\n\t\t\titemId: ItemId,\n\t\t) => void = itemId => {\n\t\t\tconst children = affectedEquipmentItemsByParent.get(\n\t\t\t\titemId,\n\t\t\t);\n\n\t\t\t// We're only interested in items that have children.\n\t\t\tif (children === undefined) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst affectedEquipmentItem = affectedEquipmentItemsById.get(\n\t\t\t\titemId,\n\t\t\t)!;\n\n\t\t\tconst equipmentId = affectedEquipmentItem.fields.materiaal;\n\n\t\t\t// This should never occur.\n\t\t\tif (equipmentId === null) {\n\t\t\t\tthrow new CriticalBusinessLogicRuleException(\n\t\t\t\t\t'AantaltotaalBusinessLogicRuleBase: \\'materiaal\\' field `null` for planned equipment item with content',\n\t\t\t\t\tcontext.collectFields(\n\t\t\t\t\t\t// Cast to member of union to avoid type shenanigans.\n\t\t\t\t\t\taffectedEquipmentItem as LatestEquipmentItem<'Planningmateriaal'>,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// TODO: This can be removed after we've ensured this no longer occurs.\n\t\t\tif (equipmentId === undefined) {\n\t\t\t\tthrow new CriticalBusinessLogicRuleException(\n\t\t\t\t\t'AantaltotaalBusinessLogicRuleBase: \\'materiaal\\' field missing for planned equipment item',\n\t\t\t\t\tcontext.collectFields(\n\t\t\t\t\t\t// Cast to member of union to avoid type shenanigans.\n\t\t\t\t\t\taffectedEquipmentItem as LatestEquipmentItem<'Planningmateriaal'>,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tequipmentIdSet.add(\n\t\t\t\tequipmentId,\n\t\t\t);\n\n\t\t\tfor (const child of children) {\n\t\t\t\texpandEquipmentIdSet(\n\t\t\t\t\tchild.fields.id,\n\t\t\t\t);\n\t\t\t}\n\t\t};\n\n\t\tfor (const rootItemId of rootItemIds) {\n\t\t\texpandEquipmentIdSet(\n\t\t\t\trootItemId,\n\t\t\t);\n\t\t}\n\n\t\tconst relatedLatestEquipmentItems = await context.fetchLatestItemsById(\n\t\t\t'Materiaal',\n\t\t\tequipmentIdSet,\n\t\t\t[\n\t\t\t\t'id',\n\t\t\t\t'is_physical',\n\t\t\t],\n\t\t);\n\n\t\treturn relatedLatestEquipmentItems.reduce(\n\t\t\t(\n\t\t\t\tmap,\n\t\t\t\tlatestEquipmentItem,\n\t\t\t) => {\n\t\t\t\tmap.set(\n\t\t\t\t\tlatestEquipmentItem.fields.id,\n\t\t\t\t\tlatestEquipmentItem.fields.is_physical,\n\t\t\t\t);\n\n\t\t\t\treturn map;\n\t\t\t},\n\t\t\tnew Map() as EquipmentIsPhysicalMap,\n\t\t);\n\t}\n\n\tprivate updatePlannedEquipmentItem (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\t// Declare as member of union to avoid type shenanigans.\n\t\tlatestEquipmentItem: LatestEquipmentItem<'Planningmateriaal'> | undefined,\n\t\tquantityFactor: number,\n\t\tdependency: Dependency<'Planningmateriaal'>,\n\t): void {\n\t\tif (!latestEquipmentItem) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst newTotalQuantity = latestEquipmentItem.fields.aantal * quantityFactor;\n\t\tconst newTotalQuantityCeiled = Math.ceil(\n\t\t\tnewTotalQuantity,\n\t\t);\n\n\t\tif (newTotalQuantityCeiled !== latestEquipmentItem.fields.aantaltotaal) {\n\t\t\tif (\n\t\t\t\tcontext.isUpdatedLatestItem(\n\t\t\t\t\t// Cast to member of union to avoid type shenanigans.\n\t\t\t\t\tlatestEquipmentItem,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tcontext.setItemUpdated(\n\t\t\t\t\tlatestEquipmentItem.itemEntry,\n\t\t\t\t\t{\n\t\t\t\t\t\taantaltotaal: newTotalQuantityCeiled,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tcontext.destinationChangesDelta.setItemCreatedByTuple(\n\t\t\t\t\tlatestEquipmentItem,\n\t\t\t\t\t{\n\t\t\t\t\t\taantaltotaal: newTotalQuantityCeiled,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst children = dependency.affectedEquipmentItemsByParent.get(\n\t\t\tlatestEquipmentItem.fields.id,\n\t\t);\n\n\t\tif (children === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\t/**\n\t\t * RM4-38229:\n\t\t * When we're dealing with physical combinations we need to make sure that any parent with fractional quantities\n\t\t * is rounded up to the nearest whole number. This is because we can't have a fraction of a physical\n\t\t * combination's content.\n\t\t *\n\t\t * Virtual combination 1\n\t\t * - Flightcase 0.25 (1)\n\t\t * - Physical content 4 (4)\n\t\t *\n\t\t * In this example we have a flightcase combination (physical) inside a virtual combination. The flightcase\n\t\t * contains 4 physical items as content. Even though it's set to 0.25 flightcase, we can't say there's only 1 content.\n\t\t * The flightcase is physical and always 'whole', meaning it would still have the 4 physical items as content.\n\t\t */\n\t\tconst newQuantityFactor = dependency.equipmentIsPhysicalMap.get(\n\t\t\tlatestEquipmentItem.fields.materiaal,\n\t\t) === true\n\t\t\t? newTotalQuantityCeiled\n\t\t\t: newTotalQuantity;\n\n\t\tfor (const child of children) {\n\t\t\tthis.updatePlannedEquipmentItem(\n\t\t\t\tcontext,\n\t\t\t\tchild,\n\t\t\t\tnewQuantityFactor,\n\t\t\t\tdependency,\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { AantaltotaalBusinessLogicRuleBase, subhireEquipmentColumns } from '../AantaltotaalBusinessLogicRuleBase';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\n\n@businessLogicRule(\n\t'InhuurmateriaalAantaltotaalBusinessLogicRule',\n)\nexport class InhuurmateriaalAantaltotaalBusinessLogicRule\n\textends AantaltotaalBusinessLogicRuleBase<'Inhuurmateriaal'> {\n\n\tprotected override readonly itemType = 'Inhuurmateriaal';\n\n\tprotected override readonly groupingProperties = {\n\t\titemType: 'Inhuurgroep',\n\t\tcolumnId: 'inhuurgroep',\n\t} as const;\n\n\tprotected override readonly requestColumns = subhireEquipmentColumns;\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport moment from 'moment';\nimport { BLR_SKIP_RULE, BusinessLogicRule, businessLogicRule, BusinessLogicRuleApplyContext, BusinessLogicRuleConditionContext, ItemEntry, ItemResource, KeyService, TransactionCache } from '../../../internal';\n\nexport type ConditionResult = ItemId[];\n\ntype Dependency = {\n\tvoorraadmutatieTuples: {\n\t\tlocal: ItemEntry<'Voorraadmutatie'>[],\n\t\tremote: ItemEntry<'Voorraadmutatie'>[],\n\t},\n\tmateriaalResources: ItemResource<'Materiaal', ['is_combination']>[],\n\tcontainerContentResources: ItemResource<'ContainerContent', ['equipment']>[],\n};\n\n@businessLogicRule(\n\t'MateriaalBulkToSerialBusinessLogicRule',\n)\nexport class MateriaalBulkToSerialBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\tmateriaalIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\tconst remoteMateriaalIds = materiaalIds.filter(\n\t\t\tmateriaalId => !KeyService.isLocalId(\n\t\t\t\tmateriaalId,\n\t\t\t),\n\t\t);\n\n\t\t// All existing Voorraadmutaties which are in the future should be deleted\n\t\tconst remoteVoorraadmutatiePromise = remoteMateriaalIds.length > 0\n\t\t\t? transaction.cachedQueryHandler.__fetchCachedQueryItem(\n\t\t\t\t'Voorraadmutatie',\n\t\t\t\t{\n\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t'id',\n\t\t\t\t\t],\n\t\t\t\t\tquery: {\n\t\t\t\t\t\tconditions: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tkey: 'datum',\n\t\t\t\t\t\t\t\tvalue: moment(),\n\t\t\t\t\t\t\t\tcomparator: '>',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tkey: 'materiaal',\n\t\t\t\t\t\t\t\tvalue: remoteMateriaalIds,\n\t\t\t\t\t\t\t\tcomparator: 'IN',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tkey: 'type',\n\t\t\t\t\t\t\t\tvalue: 'manual',\n\t\t\t\t\t\t\t\tcomparator: '=',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t)\n\t\t\t: Promise.resolve(\n\t\t\t\tnull,\n\t\t\t);\n\n\t\t// We fetch these resources in order to show a confirmation modal in the app and web. Container content is used\n\t\t// to determine whether the item is content of a combination, as they will be removed if user confirms the modal\n\t\tconst [\n\t\t\tmateriaalResources,\n\t\t\tcontainerContentResources,\n\t\t\tremoteVoorraadmutaties,\n\t\t] = await Promise.all(\n\t\t\t[\n\t\t\t\ttransaction.getItemsById(\n\t\t\t\t\t'Materiaal',\n\t\t\t\t\tmateriaalIds,\n\t\t\t\t\t{\n\t\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\t'is_combination',\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t\ttransaction.getItemsByQuery(\n\t\t\t\t\t'ContainerContent',\n\t\t\t\t\t{\n\t\t\t\t\t\tequipment: materiaalIds,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\t'equipment',\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t\tremoteVoorraadmutatiePromise,\n\t\t\t],\n\t\t);\n\n\t\tconst result: Dependency = {\n\t\t\tvoorraadmutatieTuples: {\n\t\t\t\tremote: remoteVoorraadmutaties?.items ?? [],\n\t\t\t\tlocal: [],\n\t\t\t},\n\t\t\tmateriaalResources,\n\t\t\tcontainerContentResources,\n\t\t};\n\n\t\tconst transactionChain = transaction.getTransactionChain(\n\t\t\tfalse,\n\t\t);\n\n\t\t// All local unsaved Vooraadmutatie items should be deleted, also if they are in the past\n\t\tfor (const _transaction of transactionChain) {\n\t\t\tconst entries = _transaction.itemHandler.entries.getByQuery(\n\t\t\t\t'Voorraadmutatie',\n\t\t\t\t{\n\t\t\t\t\tconditions: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tkey: 'type',\n\t\t\t\t\t\t\tvalue: 'manual',\n\t\t\t\t\t\t\tcomparator: '=',\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tkey: 'materiaal',\n\t\t\t\t\t\t\tvalue: materiaalIds,\n\t\t\t\t\t\t\tcomparator: 'IN',\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\toperator: 'AND',\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tresult.voorraadmutatieTuples.local = result.voorraadmutatieTuples.local.concat(\n\t\t\t\tentries,\n\t\t\t);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tdependencies: Dependency,\n\t): void {\n\t\tcontext.destinationChangesDelta.setItemsDeleted(\n\t\t\tdependencies.voorraadmutatieTuples.local,\n\t\t);\n\n\t\tcontext.destinationChangesDelta.setItemsDeleted(\n\t\t\tdependencies.voorraadmutatieTuples.remote,\n\t\t);\n\t}\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\treturn context.getItemIdsWithFieldUpdatedTo(\n\t\t\t'Materiaal',\n\t\t\t'telexemplaren',\n\t\t\ttrue,\n\t\t);\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemEntry } from '../../../models/ItemEntry';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = ItemId[];\n\ntype Dependency = ItemEntry<'Setinhoud'>[];\n\n/**\n * @description\n * Whenever the item is changed from (is_combination: true -> is_combination: false),\n * pop-up a modal to ensure the user of the consequences he might face when doing that.\n * If the modal is confirmed, we ensure that the content of the combination is cleared.\n */\n@businessLogicRule(\n\t'MateriaalIsCombinationBusinessLogicRule',\n)\nexport class MateriaalIsCombinationBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\treturn context.getItemIdsWithFieldUpdatedTo(\n\t\t\t'Materiaal',\n\t\t\t'is_combination',\n\t\t\tfalse,\n\t\t);\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\tequipmentIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\tconst setinhoudResources = await transaction.getItemsByQuery(\n\t\t\t'Setinhoud',\n\t\t\t{\n\t\t\t\tpackage: equipmentIds,\n\t\t\t},\n\t\t\t{\n\t\t\t\tcolumns: [\n\t\t\t\t\t'id',\n\t\t\t\t],\n\t\t\t},\n\t\t);\n\n\t\treturn setinhoudResources.map(\n\t\t\tsetinhoudResource => setinhoudResource.entry,\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tsetinhoudEntries: Dependency,\n\t): void {\n\t\tcontext.destinationChangesDelta.setItemsDeleted(\n\t\t\tsetinhoudEntries,\n\t\t);\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { ApiRequestColumnArray } from '../../../types/ItemTypesCollection';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\nconst materiaalColumns = [\n\t'is_physical',\n\t'is_combination',\n\t'telexemplaren',\n\t'can_edit_content_during_planning',\n] as const satisfies ApiRequestColumnArray<'Materiaal'>;\n\ntype ConditionResult = ItemId<'Materiaal'>[];\ntype Dependency = ItemResource<'Materiaal', typeof materiaalColumns>[];\n\n/**\n * We want to force equipment to have `can_edit_content_during_planning` set to false\n * when it's a physical combination bulk equipment\n */\n@businessLogicRule(\n\t'MateriaalIsPhysicalCombinationBulkBusinessLogicRule',\n)\nexport class MateriaalIsPhysicalCombinationBulkBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\t{\n\t\t\tpreviousChangesDelta,\n\t\t}: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\tconst updatedIterator = previousChangesDelta.getUpdatedTuplesIterator(\n\t\t\t'Materiaal',\n\t\t);\n\t\tconst result: ItemId<'Materiaal'>[] = [];\n\n\t\tfor (const tuple of updatedIterator) {\n\t\t\tif (\n\t\t\t\tpreviousChangesDelta.getUpdatedValue(\n\t\t\t\t\ttuple.entry,\n\t\t\t\t\t'is_combination',\n\t\t\t\t) === true\n\t\t\t\t|| previousChangesDelta.getUpdatedValue(\n\t\t\t\t\ttuple.entry,\n\t\t\t\t\t'is_physical',\n\t\t\t\t) === true\n\t\t\t\t|| previousChangesDelta.getUpdatedValue(\n\t\t\t\t\ttuple.entry,\n\t\t\t\t\t'telexemplaren',\n\t\t\t\t) === false\n\t\t\t) {\n\t\t\t\tresult.push(\n\t\t\t\t\ttuple.entry.itemId,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (result.length === 0) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\tconditionResult: ConditionResult,\n\t): Promise<Dependency> {\n\t\treturn transaction.getItemsById(\n\t\t\t'Materiaal',\n\t\t\tconditionResult,\n\t\t\t{\n\t\t\t\tcolumns: materiaalColumns,\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tequipmentResources: Dependency,\n\t): void {\n\t\tfor (const equipmentResource of equipmentResources) {\n\t\t\tif (\n\t\t\t\tcontext.getLatestValue(\n\t\t\t\t\tequipmentResource.entry,\n\t\t\t\t\t'can_edit_content_during_planning',\n\t\t\t\t) === false\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tcontext.getLatestValue(\n\t\t\t\t\tequipmentResource.entry,\n\t\t\t\t\t'is_physical',\n\t\t\t\t) === true\n\t\t\t\t&& context.getLatestValue(\n\t\t\t\t\tequipmentResource.entry,\n\t\t\t\t\t'is_combination',\n\t\t\t\t) === true\n\t\t\t\t&& context.getLatestValue(\n\t\t\t\t\tequipmentResource.entry,\n\t\t\t\t\t'telexemplaren',\n\t\t\t\t) === false\n\t\t\t) {\n\t\t\t\tcontext.setItemUpdated(\n\t\t\t\t\tequipmentResource.entry,\n\t\t\t\t\t{\n\t\t\t\t\t\tcan_edit_content_during_planning: false,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = ItemId[];\n\ntype Dependency = {\n\tmateriaalResources: ItemResource<'Materiaal', ['is_combination']>[],\n\tcontainerContentResources: ItemResource<'ContainerContent', ['equipment']>[],\n};\n\n@businessLogicRule(\n\t'MateriaalSerialToBulkBusinessLogicRule',\n)\nexport class MateriaalSerialToBulkBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\tmateriaalIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\t// We fetch these resources in order to show a confirmation modal in the app and web. Container content is used\n\t\t// to determine whether the item is content of a combination, as they will be removed if user confirms the modal\n\t\tconst [\n\t\t\tmateriaalResources,\n\t\t\tcontainerContentResources,\n\t\t] = await Promise.all(\n\t\t\t[\n\t\t\t\ttransaction.getItemsById(\n\t\t\t\t\t'Materiaal',\n\t\t\t\t\tmateriaalIds,\n\t\t\t\t\t{\n\t\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\t'is_combination',\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t\ttransaction.getItemsByQuery(\n\t\t\t\t\t'ContainerContent',\n\t\t\t\t\t{\n\t\t\t\t\t\tequipment: materiaalIds,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\t'equipment',\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t],\n\t\t);\n\n\t\treturn {\n\t\t\tmateriaalResources,\n\t\t\tcontainerContentResources,\n\t\t};\n\t}\n\n\t// When confirming, the combinations that are content of another combination will be removed from the parent. This process\n\t// is done through the backend, so FE/APP only use this rule to show the modal\n\tpublic apply (): void {\n\t}\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\treturn context.getItemIdsWithFieldUpdatedTo(\n\t\t\t'Materiaal',\n\t\t\t'telexemplaren',\n\t\t\tfalse,\n\t\t);\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { ApiRequestColumnArray } from '../../../types/ItemTypesCollection';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\nconst materiaalColumns = [\n\t'is_combination',\n\t'verhuur',\n\t'can_edit_content_during_planning',\n] as const satisfies ApiRequestColumnArray<'Materiaal'>;\n\ntype ConditionResult = ItemId[];\n\ntype Dependency = ItemResource<'Materiaal', typeof materiaalColumns>[];\n\n/**\n * This BLR only triggers a confirmFn in the frontend (RmCoreService)\n */\n@businessLogicRule(\n\t'MateriaalToPhysicalBusinessLogicRule',\n)\nexport class MateriaalToPhysicalBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\treturn context.getItemIdsWithFieldUpdatedTo(\n\t\t\t'Materiaal',\n\t\t\t'is_physical',\n\t\t\ttrue,\n\t\t);\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\tmateriaalIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\treturn transaction.getItemsById(\n\t\t\t'Materiaal',\n\t\t\tmateriaalIds,\n\t\t\t{\n\t\t\t\tcolumns: materiaalColumns,\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tmateriaalResources: Dependency,\n\t): void {\n\t\tconst hasFlexibleCombinationInPlanningFlag = this.hasFlag(\n\t\t\t'FUNCTIONALITY_FLEXIBLE_COMBINATION_IN_PLANNING',\n\t\t);\n\n\t\tfor (const materiaalResource of materiaalResources) {\n\t\t\tif (\n\t\t\t\tcontext.getLatestValue(\n\t\t\t\t\tmateriaalResource.entry,\n\t\t\t\t\t'is_combination',\n\t\t\t\t) === true\n\t\t\t) {\n\t\t\t\t// For legacy users physical combinations shouldn't be editable during planning\n\t\t\t\t// this will make equipment behave like cases pre equipment types\n\t\t\t\t// Without the flag this field is always disabled\n\t\t\t\t// Users on the new license are free to set this field\n\t\t\t\tif (!hasFlexibleCombinationInPlanningFlag) {\n\t\t\t\t\tcontext.setUpdatedValue(\n\t\t\t\t\t\tmateriaalResource.entry,\n\t\t\t\t\t\t'can_edit_content_during_planning',\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tcontext.setUpdatedValue(\n\t\t\t\t\tmateriaalResource.entry,\n\t\t\t\t\t'verhuur',\n\t\t\t\t\ttrue,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { ApiRequestColumnArray } from '../../../types/ItemTypesCollection';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\nconst materiaalColumns = [\n\t'is_combination',\n\t'can_edit_content_during_planning',\n] as const satisfies ApiRequestColumnArray<'Materiaal'>;\n\ntype ConditionResult = ItemId[];\n\ntype Dependency = ItemResource<'Materiaal', typeof materiaalColumns>[];\n\n/**\n * @description\n * A virtual equipment (is_phyiscal: false)\n * - is always a combination (otherwise it doesn't make sense)\n * - shows a warning letting the user know the consequences of this field\n * (it will delete serials & stock mutations, this happens onSave through backend)\n */\n@businessLogicRule(\n\t'MateriaalToVirtualBusinessLogicRule',\n)\nexport class MateriaalToVirtualBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\treturn context.getItemIdsWithFieldUpdatedTo(\n\t\t\t'Materiaal',\n\t\t\t'is_physical',\n\t\t\tfalse,\n\t\t);\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\tmateriaalIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\treturn transaction.getItemsById(\n\t\t\t'Materiaal',\n\t\t\tmateriaalIds,\n\t\t\t{\n\t\t\t\tcolumns: materiaalColumns,\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tmateriaalResources: Dependency,\n\t): void {\n\t\tfor (const materiaalResource of materiaalResources) {\n\t\t\t// Switching to virtual should always set it to combination as a singular virtual item is not possible\n\t\t\tcontext.setUpdatedValue(\n\t\t\t\tmateriaalResource.entry,\n\t\t\t\t'is_combination',\n\t\t\t\ttrue,\n\t\t\t);\n\n\t\t\t// This field is disabled in the frontend for legacy users\n\t\t\t// For virtual combinations it is required to be true at all times\n\t\t\t// This will make equipment behave like sets pre equipment types\n\t\t\tcontext.setUpdatedValue(\n\t\t\t\tmateriaalResource.entry,\n\t\t\t\t'can_edit_content_during_planning',\n\t\t\t\ttrue,\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\nconst materiaalColumns = [\n\t'type',\n\t'is_combination',\n\t'is_physical',\n\t'can_edit_content_during_planning',\n] as const;\n\ntype ConditionResult = ItemId<'Materiaal'>[];\n\ntype Dependency = ItemResource<'Materiaal', typeof materiaalColumns>[];\n\n/**\n * Untill we fully remove `type` we still need to correctly set this value in the background,\n * based on the new equipment types properties\n */\n@businessLogicRule(\n\t'MateriaalTypePropertiesBusinessLogicRule',\n)\nexport class MateriaalTypePropertiesBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\t{\n\t\t\tpreviousChangesDelta,\n\t\t}: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\tconst updatedIterator = previousChangesDelta.getUpdatedTuplesIterator(\n\t\t\t'Materiaal',\n\t\t);\n\n\t\tconst result: ItemId<'Materiaal'>[] = [];\n\n\t\tfor (const tuple of updatedIterator) {\n\t\t\tif (\n\t\t\t\tpreviousChangesDelta.hasUpdatedValue(\n\t\t\t\t\ttuple.entry,\n\t\t\t\t\t'is_combination',\n\t\t\t\t)\n\t\t\t\t|| previousChangesDelta.hasUpdatedValue(\n\t\t\t\t\ttuple.entry,\n\t\t\t\t\t'is_physical',\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tresult.push(\n\t\t\t\t\ttuple.entry.itemId,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (result.length === 0) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\tmateriaalIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\treturn transaction.getItemsById(\n\t\t\t'Materiaal',\n\t\t\tmateriaalIds,\n\t\t\t{\n\t\t\t\tcolumns: materiaalColumns,\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tmateriaalResources: Dependency,\n\t): void {\n\t\tfor (const materiaalResource of materiaalResources) {\n\t\t\tconst equipmentIsCombination = context.getLatestValue(\n\t\t\t\tmateriaalResource.entry,\n\t\t\t\t'is_combination',\n\t\t\t);\n\n\t\t\t// item = non-combination\n\t\t\tif (equipmentIsCombination === false) {\n\t\t\t\tcontext.setUpdatedValue(\n\t\t\t\t\tmateriaalResource.entry,\n\t\t\t\t\t'type',\n\t\t\t\t\t'item',\n\t\t\t\t);\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst equipmentIsPhysical = context.getLatestValue(\n\t\t\t\tmateriaalResource.entry,\n\t\t\t\t'is_physical',\n\t\t\t);\n\n\t\t\t// case = physical combination\n\t\t\t// set = virtual combination\n\t\t\tcontext.setUpdatedValue(\n\t\t\t\tmateriaalResource.entry,\n\t\t\t\t'type',\n\t\t\t\tequipmentIsPhysical === true\n\t\t\t\t\t? 'case'\n\t\t\t\t\t: 'set',\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = ItemId[];\n\ntype Dependency = ItemResource<'Materiaal', ['type']>[];\n\n/**\n * @description\n * A sales item can never be a case, so if it is we reset it to an item\n * A physical sales item can never be a combination, if it is we set it to a single item\n */\n@businessLogicRule(\n\t'MateriaalVerhuurBusinessLogicRule',\n)\nexport class MateriaalVerhuurBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\treturn context.getItemIdsWithFieldUpdatedTo(\n\t\t\t'Materiaal',\n\t\t\t'verhuur',\n\t\t\tfalse,\n\t\t);\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\tmateriaalIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\treturn transaction.getItemsById(\n\t\t\t'Materiaal',\n\t\t\tmateriaalIds,\n\t\t\t{\n\t\t\t\tcolumns: [\n\t\t\t\t\t'type',\n\t\t\t\t\t'is_physical',\n\t\t\t\t],\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tmateriaalResources: Dependency,\n\t): void {\n\t\tfor (const materiaalResource of materiaalResources) {\n\t\t\tif (\n\t\t\t\tcontext.getLatestValue(\n\t\t\t\t\tmateriaalResource.entry,\n\t\t\t\t\t'type',\n\t\t\t\t) === 'case'\n\t\t\t) {\n\t\t\t\tcontext.setItemUpdated(\n\t\t\t\t\tmateriaalResource.entry,\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'item',\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tcontext.getLatestValue(\n\t\t\t\t\tmateriaalResource.entry,\n\t\t\t\t\t'is_physical',\n\t\t\t\t) === true\n\t\t\t) {\n\t\t\t\tcontext.setItemUpdated(\n\t\t\t\t\tmateriaalResource.entry,\n\t\t\t\t\t{\n\t\t\t\t\t\tis_combination: false,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { FieldMap } from '../../../types/ItemTypesCollection';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = ItemId[];\n\ntype DependencyColumns = [\n\t'width',\n\t'height',\n\t'oppervlakteartikel',\n\t'nieuwprijs',\n\t'inhuurprijs',\n\t'verhuurprijs',\n\t'naam',\n];\n\ntype Dependency = ItemResource<'Materiaal', DependencyColumns>[];\n\n@businessLogicRule(\n\t'SurfaceArticleSizeBusinessLogicRule',\n)\nexport class SurfaceArticleSizeBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\t{\n\t\t\tpreviousChangesDelta,\n\t\t}: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\tconst updatedIterator = previousChangesDelta.getUpdatedTuplesIterator(\n\t\t\t'Materiaal',\n\t\t);\n\t\tconst result: ItemId[] = [];\n\n\t\tfor (const tuple of updatedIterator) {\n\t\t\tif (\n\t\t\t\tpreviousChangesDelta.hasUpdatedValue(\n\t\t\t\t\ttuple.entry,\n\t\t\t\t\t'width',\n\t\t\t\t)\n\t\t\t\t|| previousChangesDelta.hasUpdatedValue(\n\t\t\t\t\ttuple.entry,\n\t\t\t\t\t'height',\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tresult.push(\n\t\t\t\t\ttuple.entry.itemId,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (result.length === 0) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\tmateriaalIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\treturn transaction.getItemsById(\n\t\t\t'Materiaal',\n\t\t\tmateriaalIds,\n\t\t\t{\n\t\t\t\tcolumns: [\n\t\t\t\t\t'width',\n\t\t\t\t\t'height',\n\t\t\t\t\t'oppervlakteartikel',\n\t\t\t\t\t'nieuwprijs',\n\t\t\t\t\t'inhuurprijs',\n\t\t\t\t\t'verhuurprijs',\n\t\t\t\t\t'naam',\n\t\t\t\t] as DependencyColumns,\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tmateriaalResources: Dependency,\n\t): void {\n\t\tfor (const materiaalResource of materiaalResources) {\n\t\t\t// If it's not a surface article we don't want to automatically update the prices\n\t\t\tif (!materiaalResource.fields.oppervlakteartikel) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst tuple = context.mergedChangesDelta.updated[materiaalResource.entry.id];\n\n\t\t\t// Todo do we allow updating the original tuple fields?\n\t\t\tif (tuple.changes.fields.height < 1) {\n\t\t\t\ttuple.changes.fields.height = 1;\n\t\t\t}\n\n\t\t\tif (tuple.changes.fields.width < 1) {\n\t\t\t\ttuple.changes.fields.width = 1;\n\t\t\t}\n\n\t\t\tconst newWidth = tuple.changes.fields.width ?? materiaalResource.fields.width;\n\t\t\tconst newHeight = tuple.changes.fields.height ?? materiaalResource.fields.height;\n\t\t\tconst newFields: Partial<FieldMap<'Materiaal'>> = {};\n\n\t\t\tconst sizeUnit: string = this.locals.units.dimension;\n\n\t\t\tconst findDimensionText = /\\((.*)\\)/;\n\t\t\tconst newDimensionText = `(${newWidth} ${sizeUnit} x ${newHeight} ${sizeUnit})`;\n\n\t\t\t// Add content between parentheses or replace content with new measurements\n\t\t\tif (\n\t\t\t\t!findDimensionText.test(\n\t\t\t\t\tmateriaalResource.fields.naam,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tnewFields.naam = `${materiaalResource.fields.naam} ${newDimensionText}`;\n\t\t\t} else {\n\t\t\t\tnewFields.naam = materiaalResource.fields.naam.replace(\n\t\t\t\t\tfindDimensionText,\n\t\t\t\t\tnewDimensionText,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// calculate the base price (normalized to square meter) using the previous surface prices\n\t\t\t// apply new surface to base price to calculate the new prices\n\t\t\tconst previousSurface: number = materiaalResource.fields.width * materiaalResource.fields.height;\n\n\t\t\tif (previousSurface !== 0) {\n\t\t\t\tconst currentSurface: number = newWidth * newHeight;\n\n\t\t\t\tfor (\n\t\t\t\t\tconst priceColumnId of [\n\t\t\t\t\t'nieuwprijs',\n\t\t\t\t\t'inhuurprijs',\n\t\t\t\t\t'verhuurprijs',\n\t\t\t\t]\n\t\t\t\t\t) {\n\t\t\t\t\tnewFields[priceColumnId] = (materiaalResource.fields[priceColumnId] / previousSurface) * currentSurface;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcontext.setItemUpdated(\n\t\t\t\ttuple.entry,\n\t\t\t\tnewFields,\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ApiEnumApiType, ItemId } from '@rentman/backend-types';\nimport moment from 'moment';\nimport { FieldMap, ItemTypeColumnId } from '../../../types/ItemTypesCollection';\nimport { ApiFormatter } from '../../ApiFormatter';\n\ntype TimeColumnDefinitions = typeof timeColumnDefinitions;\n\nexport type TimeColumnId = keyof TimeColumnDefinitions;\n\nexport type TimeColumnIdExcludingTimeFrame = Exclude<TimeColumnId, 'timeframe'>;\n\ntype TimeColumnDefinitionToInstance<TimeColumnDefinitionType extends TimeColumnDefinitions[TimeColumnId]> = {\n\t[ColumnId in keyof TimeColumnDefinitionType]: ColumnId extends NonReferenceProperty\n\t\t? TimeColumnDefinitionType[ColumnId]\n\t\t: TimeColumnDefinitionType[ColumnId] extends TimeColumnId\n\t\t\t? TimeColumnInstance<TimeColumnDefinitionType[ColumnId]>\n\t\t\t: never\n};\n\nexport type TimeColumnInstance<ColumnId extends TimeColumnId> = {\n\tid: ColumnId,\n} & TimeColumnDefinitionToInstance<TimeColumnDefinitions[ColumnId]>;\n\ntype TimeItemFields = {\n\tid: ItemId | null,\n\tvan: moment.Moment,\n\ttot: moment.Moment,\n};\n\nexport const LINKED_TIME_ITEM_TYPES = [\n\t'MateriaalCat',\n\t'Functie',\n\t'Functiegroep',\n] as const;\n\nexport type LinkedTimeItemType = (typeof LINKED_TIME_ITEM_TYPES)[number];\n\nexport type LinkedItemTypeFieldMap<ItemTypeType extends LinkedTimeItemType> = ItemTypeType extends 'Functie'\n\t?\n\tFieldMap<'Functie', TimeColumnId[]>\n\t: FieldMap<ItemTypeType, TimeColumnIdExcludingTimeFrame[]>;\n\ninterface TimeColumnDefinition<ItemTypeType extends LinkedTimeItemType = LinkedTimeItemType> {\n\ttype: ApiEnumApiType.TYPE_DATETIME\n\t\t| ApiEnumApiType.TYPE_ITEM\n\t\t| ApiEnumApiType.TYPE_BOOL\n\t\t| ApiEnumApiType.TYPE_DURATION,\n\t/**\n\t * @description For 'from' columns, refers to the 'to' column and vice versa.\n\t * E.g. 'gebruikvan' -> 'gebruiktot', 'schema_gv' -> 'schema_gt'.\n\t */\n\topposite?: ItemTypeColumnId<ItemTypeType>,\n\t/**\n\t * @description For 'value' columns, refers to the corresponding 'scheme' column, e.g. 'gebruikvan' -> 'schema_gv'.\n\t * Only present in 'value' columns.\n\t */\n\tscheme?: ItemTypeColumnId<ItemTypeType>,\n\t/**\n\t * @description For 'scheme' columns, refers to the corresponding 'value' column, e.g. 'schema_gv' -> 'gebruikvan'.\n\t * Only present in 'scheme' columns.\n\t */\n\tvalue?: ItemTypeColumnId<ItemTypeType>,\n\t/**\n\t * @description For 'usage' columns, refers to the corresponding 'plan' column, e.g. 'gebruikvan' -> 'planvan'.\n\t * Only present in 'usage' columns.\n\t */\n\tplan?: ItemTypeColumnId<ItemTypeType>,\n\t/**\n\t * @description For 'plan' columns, refers to the corresponding 'usage' column, e.g. 'planvan' -> 'gebruikvan'.\n\t * Only present in 'plan' columns.\n\t */\n\tusage?: ItemTypeColumnId<ItemTypeType>,\n\t/**\n\t * @description For 'scheme' columns, refers to the corresponding 'start' column. e.g. 'schema_gv' -> 'schema_gv_begin'.\n\t * The 'start' column determines whether the 'from' or the 'to' component of the time the scheme column refers to\n\t * is used. (If true, 'from' is used, 'to' otherwise.)\n\t * Only present in 'scheme' columns.\n\t */\n\tstart?: ItemTypeColumnId<ItemTypeType>,\n\t/**\n\t * @description Indicates whether the column is used to signify a 'starting' time, e.g. 'gebruikvan', 'schema_gv'.\n\t * Only present for in 'scheme' and 'value' columns.\n\t */\n\tisStart?: boolean,\n\tdefaultValue?: boolean,\n}\n\nconst nonReferenceProperties = [\n\t'type',\n\t'isStart',\n\t'defaultValue',\n] as const;\n\ntype NonReferenceProperty = (typeof nonReferenceProperties)[number];\n\nconst timeColumnDefinitions = {\n\tschema_gv: {\n\t\ttype: ApiEnumApiType.TYPE_ITEM,\n\t\tstart: 'schema_gv_begin',\n\t\tvalue: 'gebruikvan',\n\t\topposite: 'schema_gt',\n\t\tplan: 'schema_pv',\n\t\tisStart: true,\n\t},\n\tschema_gt: {\n\t\ttype: ApiEnumApiType.TYPE_ITEM,\n\t\tstart: 'schema_gt_begin',\n\t\tvalue: 'gebruiktot',\n\t\topposite: 'schema_gv',\n\t\tplan: 'schema_pt',\n\t\tisStart: false,\n\t},\n\tschema_pv: {\n\t\ttype: ApiEnumApiType.TYPE_ITEM,\n\t\tstart: 'schema_pv_begin',\n\t\tvalue: 'planvan',\n\t\topposite: 'schema_pt',\n\t\tusage: 'schema_gv',\n\t\tisStart: true,\n\t},\n\tschema_pt: {\n\t\ttype: ApiEnumApiType.TYPE_ITEM,\n\t\tstart: 'schema_pt_begin',\n\t\tvalue: 'plantot',\n\t\topposite: 'schema_pv',\n\t\tusage: 'schema_gt',\n\t\tisStart: false,\n\t},\n\tgebruikvan: {\n\t\ttype: ApiEnumApiType.TYPE_DATETIME,\n\t\tscheme: 'schema_gv',\n\t\topposite: 'gebruiktot',\n\t\tplan: 'planvan',\n\t\tisStart: true,\n\t},\n\tgebruiktot: {\n\t\ttype: ApiEnumApiType.TYPE_DATETIME,\n\t\tscheme: 'schema_gt',\n\t\topposite: 'gebruikvan',\n\t\tplan: 'plantot',\n\t\tisStart: false,\n\t},\n\tplanvan: {\n\t\ttype: ApiEnumApiType.TYPE_DATETIME,\n\t\tscheme: 'schema_pv',\n\t\topposite: 'plantot',\n\t\tusage: 'gebruikvan',\n\t\tisStart: true,\n\t},\n\tplantot: {\n\t\ttype: ApiEnumApiType.TYPE_DATETIME,\n\t\tscheme: 'schema_pt',\n\t\topposite: 'planvan',\n\t\tusage: 'gebruiktot',\n\t\tisStart: false,\n\t},\n\tschema_pv_begin: {\n\t\ttype: ApiEnumApiType.TYPE_BOOL,\n\t\tusage: 'schema_gv_begin',\n\t\tdefaultValue: true,\n\t},\n\tschema_pt_begin: {\n\t\ttype: ApiEnumApiType.TYPE_BOOL,\n\t\tusage: 'schema_gt_begin',\n\t\tdefaultValue: false,\n\t},\n\tschema_gv_begin: {\n\t\ttype: ApiEnumApiType.TYPE_BOOL,\n\t\tplan: 'schema_pv_begin',\n\t\tdefaultValue: true,\n\t},\n\tschema_gt_begin: {\n\t\ttype: ApiEnumApiType.TYPE_BOOL,\n\t\tplan: 'schema_pt_begin',\n\t\tdefaultValue: false,\n\t},\n\tduur: {\n\t\ttype: ApiEnumApiType.TYPE_DURATION,\n\t},\n\ttimeframe: {\n\t\ttype: ApiEnumApiType.TYPE_ITEM,\n\t},\n} as const satisfies {\n\t[ColumnId in ItemTypeColumnId<LinkedTimeItemType> | 'timeframe']?: TimeColumnDefinition\n};\n\nexport abstract class TimeColumnUtil {\n\n\tprivate static columnInstances: {\n\t\t[ColumnId in TimeColumnId]?: TimeColumnInstance<ColumnId>\n\t} = {};\n\n\tpublic static schemeValueStartColumnIds = [\n\t\t'schema_gv',\n\t\t'schema_pv',\n\t] as const satisfies readonly TimeColumnId[];\n\n\tpublic static schemeValueEndColumnIds = [\n\t\t'schema_gt',\n\t\t'schema_pt',\n\t] as const satisfies readonly TimeColumnId[];\n\n\tpublic static schemeValueColumnIds = [\n\t\t'schema_gv',\n\t\t'schema_pv',\n\t\t'schema_gt',\n\t\t'schema_pt',\n\t] as const satisfies readonly TimeColumnId[];\n\n\tpublic static schemeStartColumnIds = [\n\t\t'schema_gv_begin',\n\t\t'schema_gt_begin',\n\t\t'schema_pv_begin',\n\t\t'schema_pt_begin',\n\t] as const satisfies readonly TimeColumnId[];\n\n\tpublic static valueStartColumnIds = [\n\t\t'gebruikvan',\n\t\t'planvan',\n\t] as const satisfies readonly TimeColumnId[];\n\n\tpublic static valueEndColumnIds = [\n\t\t'gebruiktot',\n\t\t'plantot',\n\t] as const satisfies readonly TimeColumnId[];\n\n\tpublic static valueColumnIds = [\n\t\t'gebruikvan',\n\t\t'planvan',\n\t\t'gebruiktot',\n\t\t'plantot',\n\t] as const satisfies readonly TimeColumnId[];\n\n\tpublic static usageColumnIds = [\n\t\t'gebruikvan',\n\t\t'gebruiktot',\n\t\t'schema_gv',\n\t\t'schema_gt',\n\t\t'schema_gv_begin',\n\t\t'schema_gt_begin',\n\t] as const satisfies readonly TimeColumnId[];\n\n\tpublic static planColumnIds = [\n\t\t'planvan',\n\t\t'plantot',\n\t\t'schema_pv',\n\t\t'schema_pt',\n\t\t'schema_pv_begin',\n\t\t'schema_pt_begin',\n\t] as const satisfies readonly TimeColumnId[];\n\n\tpublic static isTimeColumn (\n\t\tcolumnId: string,\n\t): columnId is TimeColumnId {\n\t\treturn timeColumnDefinitions[columnId] !== undefined;\n\t}\n\n\tpublic static getColumnInstance<ColumnId extends TimeColumnId> (\n\t\tcolumnId: ColumnId,\n\t): TimeColumnInstance<ColumnId> {\n\t\tif (this.columnInstances[columnId] !== undefined) {\n\t\t\treturn this.columnInstances[columnId];\n\t\t}\n\n\t\tconst columnDefinition = timeColumnDefinitions[columnId];\n\n\t\tconst result = {\n\t\t\tid: columnId,\n\t\t} as TimeColumnInstance<ColumnId>;\n\n\t\t(this.columnInstances[columnId] as TimeColumnInstance<ColumnId>) = result; // prevents infinite loops :-p\n\n\t\tfor (const key in columnDefinition) {\n\t\t\tresult[key] = nonReferenceProperties.includes(\n\t\t\t\tkey as NonReferenceProperty,\n\t\t\t)\n\t\t\t\t? columnDefinition[key]\n\t\t\t\t: this.getColumnInstance(\n\t\t\t\t\tcolumnDefinition[key as Exclude<keyof TimeColumnDefinition, NonReferenceProperty>],\n\t\t\t\t);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic static getColumnIdIterator (\n\t\titemType: 'Functie',\n\t): Generator<TimeColumnId>;\n\n\tpublic static getColumnIdIterator (\n\t\titemType: any,\n\t): Generator<TimeColumnIdExcludingTimeFrame>;\n\n\tpublic static* getColumnIdIterator (\n\t\titemType: LinkedTimeItemType,\n\t): Generator<TimeColumnId> {\n\t\tfor (const columnId in timeColumnDefinitions) {\n\t\t\tif (\n\t\t\t\t(columnId as TimeColumnId) === 'timeframe'\n\t\t\t\t&& itemType !== 'Functie'\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tyield columnId as TimeColumnId;\n\t\t}\n\t}\n\n\tpublic static getColumnIds (\n\t\titemType: 'Functie',\n\t): TimeColumnId[];\n\n\tpublic static getColumnIds (\n\t\titemType: any,\n\t): TimeColumnIdExcludingTimeFrame[];\n\n\tpublic static getColumnIds (\n\t\titemType: LinkedTimeItemType,\n\t): TimeColumnId[] {\n\t\treturn [\n\t\t\t...this.getColumnIdIterator(\n\t\t\t\titemType,\n\t\t\t),\n\t\t];\n\t}\n\n\tpublic static getDefaultValues<ItemTypeType extends LinkedTimeItemType> (\n\t\titemType: ItemTypeType,\n\t\tusageFields: TimeItemFields = {\n\t\t\tid: null,\n\t\t\tvan: moment.invalid(),\n\t\t\ttot: moment.invalid(),\n\t\t},\n\t\tplanFields: TimeItemFields = usageFields,\n\t): LinkedItemTypeFieldMap<ItemTypeType> {\n\t\tconst result = {\n\t\t\tschema_gv: usageFields.id,\n\t\t\tschema_gt: usageFields.id,\n\t\t\tschema_pv: planFields.id,\n\t\t\tschema_pt: planFields.id,\n\t\t\tschema_pv_begin: this\n\t\t\t\t.getColumnInstance(\n\t\t\t\t\t'schema_pv_begin',\n\t\t\t\t)\n\t\t\t\t.defaultValue,\n\t\t\tschema_pt_begin: this\n\t\t\t\t.getColumnInstance(\n\t\t\t\t\t'schema_pt_begin',\n\t\t\t\t)\n\t\t\t\t.defaultValue,\n\t\t\tschema_gv_begin: this\n\t\t\t\t.getColumnInstance(\n\t\t\t\t\t'schema_gv_begin',\n\t\t\t\t)\n\t\t\t\t.defaultValue,\n\t\t\tschema_gt_begin: this\n\t\t\t\t.getColumnInstance(\n\t\t\t\t\t'schema_gt_begin',\n\t\t\t\t)\n\t\t\t\t.defaultValue,\n\t\t\tgebruiktot: usageFields.tot.clone(),\n\t\t\tgebruikvan: usageFields.van.clone(),\n\t\t\tplantot: planFields.tot.clone(),\n\t\t\tplanvan: planFields.van.clone(),\n\t\t\tduur: moment.duration(\n\t\t\t\t(\n\t\t\t\t\tusageFields.van.isValid()\n\t\t\t\t\t&& usageFields.tot.isValid()\n\t\t\t\t)\n\t\t\t\t\t? usageFields.tot.diff(\n\t\t\t\t\t\tusageFields.van,\n\t\t\t\t\t)\n\t\t\t\t\t: 0,\n\t\t\t),\n\t\t};\n\n\t\treturn (\n\t\t\titemType === 'Functie'\n\t\t\t\t? {\n\t\t\t\t\t...result,\n\t\t\t\t\ttimeframe: null,\n\t\t\t\t}\n\t\t\t\t: result\n\t\t) as LinkedItemTypeFieldMap<ItemTypeType>;\n\t}\n\n\tpublic static cloneValues<SourceItemType extends LinkedTimeItemType, DestinationItemType extends LinkedTimeItemType> (\n\t\titemType: SourceItemType,\n\t\tfields: LinkedItemTypeFieldMap<SourceItemType>,\n\t\tdestination: Partial<LinkedItemTypeFieldMap<DestinationItemType>> = {},\n\t): LinkedItemTypeFieldMap<DestinationItemType> {\n\t\tconst iterator = this.getColumnIdIterator(\n\t\t\titemType,\n\t\t);\n\n\t\tfor (const columnId of iterator) {\n\t\t\tdestination[columnId] = ApiFormatter.clone(\n\t\t\t\ttimeColumnDefinitions[columnId].type,\n\t\t\t\tfields[columnId],\n\t\t\t);\n\t\t}\n\n\t\treturn destination as LinkedItemTypeFieldMap<DestinationItemType>;\n\t}\n\n\tpublic static compareValues<ItemTypeType extends LinkedTimeItemType> (\n\t\titemType: ItemTypeType,\n\t\tfieldsA: LinkedItemTypeFieldMap<ItemTypeType>,\n\t\tfieldsB: LinkedItemTypeFieldMap<ItemTypeType>,\n\t): boolean {\n\t\tconst iterator = this.getColumnIdIterator(\n\t\t\titemType,\n\t\t);\n\n\t\tfor (const columnId of iterator) {\n\t\t\tif (\n\t\t\t\t!ApiFormatter.compareFields(\n\t\t\t\t\ttimeColumnDefinitions[columnId].type,\n\t\t\t\t\t// @ts-ignore TODO: Allow for `null` values in `compareFields` type.\n\t\t\t\t\tfieldsA[columnId],\n\t\t\t\t\tfieldsB[columnId],\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n}","import { ItemEntry } from '../../../models/ItemEntry';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { ApiRequestColumnArray, GetFieldValueType } from '../../../types/ItemTypesCollection';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { ChangesDeltaItemCreateDelta } from '../../CreatedChangesDelta';\nimport { promiseAllObject } from '../../Util';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\nimport { LINKED_TIME_ITEM_TYPES, LinkedTimeItemType, TimeColumnId } from './TimeColumnUtil';\n\ntype LinkedTimeItemColumn = 'project' | 'subproject' | Exclude<TimeColumnId, 'timeframe'>;\n\ntype LinkedTimeItemColumnArray = readonly LinkedTimeItemColumn[];\n\ntype LinkedTimeItemRequestColumnsMap = {\n\t[ItemType in LinkedTimeItemType]: ApiRequestColumnArray<ItemType>\n};\n\ntype LinkedTimeItemRequestColumnsMapToItemResourceMap<RequestColumnsMap extends LinkedTimeItemRequestColumnsMap> = {\n\t[ItemType in LinkedTimeItemType]: ItemResource<\n\t\tItemType,\n\t\tRequestColumnsMap[ItemType] extends ApiRequestColumnArray<ItemType>\n\t\t\t? RequestColumnsMap[ItemType]\n\t\t\t: never\n\t>[]\n};\n\nexport type LinkedTimeItemResourceMap<RequestColumns extends ApiRequestColumnArray<LinkedTimeItemType>> = {\n\t[ItemType in LinkedTimeItemType]: ItemResource<ItemType, RequestColumns>[]\n};\n\ntype CreatedTupleMap = {\n\t[ItemType in LinkedTimeItemType]: ChangesDeltaItemCreateDelta<ItemType>[]\n};\n\nexport type LinkedTimeItemBusinessLogicRuleBaseUpdatedTuples<RequestColumns extends LinkedTimeItemColumnArray> = {\n\t[ItemType in LinkedTimeItemType]: UpdatedTuple<LinkedTimeItemType, RequestColumns[number]>[]\n};\n\ninterface UpdatedTuple<\n\tItemTypeType extends LinkedTimeItemType,\n\tColumnId extends LinkedTimeItemColumn = LinkedTimeItemColumn,\n> {\n\titemEntry: ItemEntry<ItemTypeType>,\n\tcolumnId: ColumnId,\n\tnewValue: GetFieldValueType<ItemTypeType, ColumnId>,\n}\n\nexport abstract class LinkedTimeItemBusinessLogicRuleBase<\n\tConditionColumns extends LinkedTimeItemColumnArray,\n\tConditionResult,\n\tDependency\n>\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tprotected conditionColumns: ConditionColumns;\n\n\tprotected extractCreatedTuples (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): CreatedTupleMap {\n\t\tconst result: Partial<CreatedTupleMap> = {};\n\n\t\tfor (const itemType of LINKED_TIME_ITEM_TYPES) {\n\t\t\t(result[itemType] as ChangesDeltaItemCreateDelta<LinkedTimeItemType>[]) = [\n\t\t\t\t...context.previousChangesDelta.getCreatedTuplesIterator(\n\t\t\t\t\titemType,\n\t\t\t\t),\n\t\t\t];\n\t\t}\n\n\t\treturn result as CreatedTupleMap;\n\t}\n\n\t/**\n\t * Extract updated fields of functions / function groups / equipment groups, using the columns specified in\n\t * `conditionColumns`.\n\t */\n\tprotected extractUpdatedTuples (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): LinkedTimeItemBusinessLogicRuleBaseUpdatedTuples<ConditionColumns> {\n\t\tconst updatedIterator = context.previousChangesDelta.getUpdatedTuplesIterator(\n\t\t\t...LINKED_TIME_ITEM_TYPES,\n\t\t);\n\t\tconst result: LinkedTimeItemBusinessLogicRuleBaseUpdatedTuples<ConditionColumns> = {\n\t\t\tMateriaalCat: [],\n\t\t\tFunctie: [],\n\t\t\tFunctiegroep: [],\n\t\t};\n\n\t\tfor (const tuple of updatedIterator) {\n\t\t\tconst itemEntry = tuple.entry;\n\n\t\t\tfor (const columnId of this.conditionColumns) {\n\t\t\t\tconst updatedValue = context.previousChangesDelta.getUpdatedValue(\n\t\t\t\t\titemEntry,\n\t\t\t\t\tcolumnId,\n\t\t\t\t);\n\n\t\t\t\tif (updatedValue === undefined) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t(result[itemEntry.itemType] as UpdatedTuple<LinkedTimeItemType>[]).push(\n\t\t\t\t\t{\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\tcolumnId,\n\t\t\t\t\t\tnewValue: updatedValue,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Like {@link extractUpdatedTuples}, but returns `undefined` when no fields have been updated.\n\t */\n\tprotected extractUpdatedTuplesCondition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): LinkedTimeItemBusinessLogicRuleBaseUpdatedTuples<ConditionColumns> | typeof BLR_SKIP_RULE {\n\t\tconst result = this.extractUpdatedTuples(\n\t\t\tcontext,\n\t\t);\n\n\t\tif (\n\t\t\tLINKED_TIME_ITEM_TYPES.every(\n\t\t\t\titemType => result[itemType].length === 0,\n\t\t\t)\n\t\t) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprotected async fetchLinkedItemResourcesWithColumns<RequestColumnsMap extends LinkedTimeItemRequestColumnsMap> (\n\t\ttransaction: TransactionCache,\n\t\tupdatedTuples: LinkedTimeItemBusinessLogicRuleBaseUpdatedTuples<any>,\n\t\trequestColumnsMap: RequestColumnsMap,\n\t): Promise<LinkedTimeItemRequestColumnsMapToItemResourceMap<RequestColumnsMap>> {\n\t\treturn promiseAllObject(\n\t\t\tLINKED_TIME_ITEM_TYPES.reduce(\n\t\t\t\t(\n\t\t\t\t\taccumulator,\n\t\t\t\t\titemType,\n\t\t\t\t) => {\n\t\t\t\t\taccumulator[itemType] = transaction.getItemsById(\n\t\t\t\t\t\titemType,\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t...new Set(\n\t\t\t\t\t\t\t\tupdatedTuples[itemType].map(\n\t\t\t\t\t\t\t\t\tconditionResultElement => conditionResultElement.itemEntry.itemId,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t],\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcolumns: requestColumnsMap[itemType] as ApiRequestColumnArray<LinkedTimeItemType>,\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\n\t\t\t\t\treturn accumulator;\n\t\t\t\t},\n\t\t\t\t{} as Promise<LinkedTimeItemRequestColumnsMapToItemResourceMap<RequestColumnsMap>>,\n\t\t\t),\n\t\t);\n\t}\n\n\tprotected async fetchLinkedItemResources<RequestColumns extends ApiRequestColumnArray<LinkedTimeItemType>> (\n\t\ttransaction: TransactionCache,\n\t\tupdatedTuples: LinkedTimeItemBusinessLogicRuleBaseUpdatedTuples<any>,\n\t\trequestColumns: RequestColumns,\n\t): Promise<LinkedTimeItemResourceMap<RequestColumns>> {\n\t\treturn this.fetchLinkedItemResourcesWithColumns(\n\t\t\ttransaction,\n\t\t\tupdatedTuples,\n\t\t\t{\n\t\t\t\tMateriaalCat: requestColumns,\n\t\t\t\tFunctie: requestColumns,\n\t\t\t\tFunctiegroep: requestColumns,\n\t\t\t},\n\t\t);\n\t}\n\n}\n","import moment from 'moment';\nimport { ItemEntry } from '../../../models/ItemEntry';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\nimport { LinkedTimeItemBusinessLogicRuleBase, LinkedTimeItemBusinessLogicRuleBaseUpdatedTuples, LinkedTimeItemResourceMap } from './LinkedTimeItemBusinessLogicRuleBase';\nimport { LINKED_TIME_ITEM_TYPES, LinkedTimeItemType } from './TimeColumnUtil';\n\nconst conditionColumns = [\n\t'gebruikvan',\n\t'gebruiktot',\n] as const;\n\nconst requestColumns = [\n\t...conditionColumns,\n\t'duur',\n] as const;\n\n/**\n * When changing 'gebruikvan' or 'gebruiktot', and both fields are valid, set the duration.\n */\n@businessLogicRule(\n\t'LinkedTimeItemDurationBusinessLogicRule',\n)\nexport class LinkedTimeItemDurationBusinessLogicRule\n\textends LinkedTimeItemBusinessLogicRuleBase<\n\t\ttypeof conditionColumns,\n\t\tLinkedTimeItemBusinessLogicRuleBaseUpdatedTuples<typeof conditionColumns>,\n\t\tLinkedTimeItemResourceMap<typeof requestColumns>\n\t> {\n\n\tprotected override conditionColumns = conditionColumns;\n\n\tpublic override condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): LinkedTimeItemBusinessLogicRuleBaseUpdatedTuples<typeof conditionColumns> | typeof BLR_SKIP_RULE {\n\t\treturn this.extractUpdatedTuplesCondition(\n\t\t\tcontext,\n\t\t);\n\t}\n\n\tpublic override apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tdependencies: LinkedTimeItemResourceMap<typeof requestColumns>,\n\t): void {\n\t\tfor (const linkedItemType of LINKED_TIME_ITEM_TYPES) {\n\t\t\tfor (const itemResource of dependencies[linkedItemType]) {\n\t\t\t\tconst itemEntry = itemResource.entry as ItemEntry<LinkedTimeItemType>;\n\t\t\t\tconst usageStartValue = context.getLatestValue(\n\t\t\t\t\titemEntry,\n\t\t\t\t\t'gebruikvan',\n\t\t\t\t)!;\n\t\t\t\tconst usageEndValue = context.getLatestValue(\n\t\t\t\t\titemEntry,\n\t\t\t\t\t'gebruiktot',\n\t\t\t\t)!;\n\n\t\t\t\tif (\n\t\t\t\t\tusageStartValue.isValid()\n\t\t\t\t\t&& usageEndValue.isValid()\n\t\t\t\t) {\n\t\t\t\t\tcontext.setUpdatedValue(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\t'duur',\n\t\t\t\t\t\tmoment.duration(\n\t\t\t\t\t\t\tusageEndValue.diff(\n\t\t\t\t\t\t\t\tusageStartValue,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic override dependency (\n\t\ttransaction: TransactionCache,\n\t\tconditionResult: LinkedTimeItemBusinessLogicRuleBaseUpdatedTuples<typeof conditionColumns>,\n\t): Promise<LinkedTimeItemResourceMap<typeof requestColumns>> {\n\t\treturn this.fetchLinkedItemResources(\n\t\t\ttransaction,\n\t\t\tconditionResult,\n\t\t\trequestColumns,\n\t\t);\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { ApiRequestColumnArray, ItemTypeColumnId } from '../../../types/ItemTypesCollection';\nimport { ApiFormatter } from '../../ApiFormatter';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = ItemId<'MateriaalCat'>[];\n\ntype TimeScheduleFieldInformation = Pick<\n\t{\n\t\t[ColumnId in ItemTypeColumnId<'MateriaalCat'>]: {\n\t\t\trelated_schema_field: ItemTypeColumnId<'MateriaalCat'> & 'schema_pv' | 'schema_pt' | 'schema_gv' | 'schema_gt',\n\t\t\trelated_schema_time_field: ItemTypeColumnId<'Tijd'> & 'van' | 'tot',\n\t\t};\n\t},\n\t'planvan' | 'plantot' | 'gebruikvan' | 'gebruiktot'\n>;\n\nconst timeScheduleFieldInformation: TimeScheduleFieldInformation = {\n\tplanvan: {\n\t\trelated_schema_field: 'schema_pv',\n\t\trelated_schema_time_field: 'van',\n\t},\n\tplantot: {\n\t\trelated_schema_field: 'schema_pt',\n\t\trelated_schema_time_field: 'tot',\n\t},\n\tgebruikvan: {\n\t\trelated_schema_field: 'schema_gv',\n\t\trelated_schema_time_field: 'van',\n\t},\n\tgebruiktot: {\n\t\trelated_schema_field: 'schema_gt',\n\t\trelated_schema_time_field: 'tot',\n\t},\n} as const satisfies TimeScheduleFieldInformation;\n\nconst timeScheduleFieldInformationColumnIds = Object.keys(\n\ttimeScheduleFieldInformation,\n) as (keyof typeof timeScheduleFieldInformation)[];\n\nconst changedMateriaalCatResourceColumns = [\n\t'gebruikvan',\n\t'gebruiktot',\n\t'planvan',\n\t'plantot',\n\t{\n\t\tschema_pv: [\n\t\t\t'van',\n\t\t\t'tot',\n\t\t\t'is_absolute_times_substitute',\n\t\t],\n\t},\n\t{\n\t\tschema_pt: [\n\t\t\t'van',\n\t\t\t'tot',\n\t\t\t'is_absolute_times_substitute',\n\t\t],\n\t},\n\t{\n\t\tschema_gv: [\n\t\t\t'van',\n\t\t\t'tot',\n\t\t\t'is_absolute_times_substitute',\n\t\t],\n\t},\n\t{\n\t\tschema_gt: [\n\t\t\t'van',\n\t\t\t'tot',\n\t\t\t'is_absolute_times_substitute',\n\t\t],\n\t},\n] as const satisfies ApiRequestColumnArray<'MateriaalCat'>;\n\ntype Dependency = {\n\tchangedResources: ItemResource<'MateriaalCat', typeof changedMateriaalCatResourceColumns>[],\n};\n\n@businessLogicRule(\n\t'LinkedTimeItemMateriaalCatBusinessLogicRule',\n)\nexport class LinkedTimeItemMateriaalCatBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\tconst updatedIterator = context.previousChangesDelta.getUpdatedTuplesIterator(\n\t\t\t'MateriaalCat',\n\t\t);\n\n\t\tconst result: ItemId[] = [];\n\n\t\tfor (const tuple of updatedIterator) {\n\t\t\t// If any of the fields defined with the TimeScheduleFieldInformation changed, we need to perform modifications with the rule\n\t\t\tif (\n\t\t\t\ttimeScheduleFieldInformationColumnIds.some(\n\t\t\t\t\tcolumnId => context.fieldChanged(\n\t\t\t\t\t\ttuple,\n\t\t\t\t\t\tcolumnId,\n\t\t\t\t\t) !== null,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tresult.push(\n\t\t\t\t\ttuple.entry.itemId,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (result.length === 0) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\tchangedMateriaalCatItemIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\tconst changedResources = await transaction.getItemsById(\n\t\t\t'MateriaalCat',\n\t\t\tchangedMateriaalCatItemIds,\n\t\t\t{\n\t\t\t\tcolumns: changedMateriaalCatResourceColumns,\n\t\t\t},\n\t\t);\n\n\t\treturn {\n\t\t\tchangedResources,\n\t\t};\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tdependency: Dependency,\n\t): void {\n\t\tfor (const materialCatResource of dependency.changedResources) {\n\t\t\tfor (const columnId of timeScheduleFieldInformationColumnIds) {\n\t\t\t\tconst timeEntryValue = context.getLatestValue(\n\t\t\t\t\tmaterialCatResource.entry,\n\t\t\t\t\tcolumnId,\n\t\t\t\t);\n\n\t\t\t\tconst timeEntryItemId = context.getLatestValue(\n\t\t\t\t\tmaterialCatResource.entry,\n\t\t\t\t\ttimeScheduleFieldInformation[columnId].related_schema_field,\n\t\t\t\t) as ItemId<'Tijd'> | null;\n\n\t\t\t\tif (\n\t\t\t\t\ttimeEntryValue !== undefined\n\t\t\t\t\t&& !ApiFormatter.compareFields(\n\t\t\t\t\t\tmaterialCatResource.columns[columnId].type,\n\t\t\t\t\t\ttimeEntryValue,\n\t\t\t\t\t\tmaterialCatResource.fields[columnId],\n\t\t\t\t\t)\n\t\t\t\t\t&& timeEntryItemId !== null\n\t\t\t\t) {\n\t\t\t\t\tconst itemEntry = context.transaction.getLocalItemEntryByItemId(\n\t\t\t\t\t\t'Tijd',\n\t\t\t\t\t\ttimeEntryItemId,\n\t\t\t\t\t);\n\t\t\t\t\t\n\t\t\t\t\tif (\n\t\t\t\t\t\tcontext.getLatestValue(\n\t\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\t\t'is_absolute_times_substitute',\n\t\t\t\t\t\t) === true\n\t\t\t\t\t) {\n\t\t\t\t\t\tcontext.setItemUpdated(\n\t\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t[timeScheduleFieldInformation[columnId].related_schema_time_field]: timeEntryValue.clone(),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemNotFoundException } from '../../../exceptions/ItemNotFoundException';\nimport { ItemEntry } from '../../../models/ItemEntry';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { FieldMap } from '../../../types/ItemTypesCollection';\nimport { ChangesDeltaItemCreateDelta } from '../../CreatedChangesDelta';\nimport { BLR_SKIP_RULE } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\nimport { LinkedTimeItemBusinessLogicRuleBase, LinkedTimeItemResourceMap } from './LinkedTimeItemBusinessLogicRuleBase';\nimport { LINKED_TIME_ITEM_TYPES, LinkedTimeItemType, TimeColumnUtil } from './TimeColumnUtil';\n\nconst conditionColumns = [\n\t/**\n\t * Currently, it is not possible to move linked time items to another project. Supporting this is trivial, so we're\n\t * implementing this either way. It *is* possible to paste items in another project.\n\t */\n\t'project',\n\t'subproject',\n] as const;\n\nconst schemeValueColumnIds = TimeColumnUtil.schemeValueColumnIds;\n\n/**\n * Function items are the only linked time item that have a 'timeframe' field, which, like the 'schema_**' fields,\n * refers to a project time.\n */\nconst schemeValueTimeFrameColumnIds = [\n\t...TimeColumnUtil.schemeValueColumnIds,\n\t'timeframe',\n] as const;\n\ntype SchemeValueTimeFrameColumnId = (typeof schemeValueTimeFrameColumnIds)[number];\n\ntype CreatedUpdatedTuple<ItemTypeType extends LinkedTimeItemType> = {\n\tcreated: {\n\t\titem: ChangesDeltaItemCreateDelta<ItemTypeType>,\n\t\tinvalidTimes: SchemeValueTimeFrameColumnId[],\n\t}[],\n\tupdated: {\n\t\titem: ItemEntry<ItemTypeType>,\n\t\tinvalidTimes: SchemeValueTimeFrameColumnId[],\n\t}[],\n};\n\nexport type LinkedTimeItemSubprojectBusinessLogicRuleConditionResult = {\n\t[ItemType in LinkedTimeItemType]: CreatedUpdatedTuple<ItemType>\n};\n\ntype TimeSubprojectTuple = {\n\t/**\n\t * `projectId` / `subprojectId` refers to the subproject the function / function group / equipment group is in.\n\t */\n\tprojectId: ItemId,\n\tsubprojectId: ItemId,\n\ttimeId: ItemId,\n\tcolumnId: SchemeValueTimeFrameColumnId,\n};\n\n/**\n * When updating the subproject of a function / function group / equipment group, or creating a new\n * function / function group / equipment group, and one of the times of these items is not in the project / subproject\n * the created or updated item is in, set the associated item field to `null`.\n */\n@businessLogicRule(\n\t'LinkedTimeItemSubprojectBusinessLogicRule',\n)\nexport class LinkedTimeItemSubprojectBusinessLogicRule\n\textends LinkedTimeItemBusinessLogicRuleBase<typeof conditionColumns, LinkedTimeItemSubprojectBusinessLogicRuleConditionResult, null> {\n\n\tprotected override conditionColumns = conditionColumns;\n\n\tpublic override async condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): Promise<LinkedTimeItemSubprojectBusinessLogicRuleConditionResult | typeof BLR_SKIP_RULE> {\n\t\tconst createdTuples = this.extractCreatedTuples(\n\t\t\tcontext,\n\t\t);\n\t\tconst updatedTuples = this.extractUpdatedTuples(\n\t\t\tcontext,\n\t\t);\n\n\t\tif (\n\t\t\tLINKED_TIME_ITEM_TYPES.every(\n\t\t\t\titemType => createdTuples[itemType].length === 0\n\t\t\t\t\t&& updatedTuples[itemType].length === 0,\n\t\t\t)\n\t\t) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\t// We retrieve the time resources in the condition function already, because we need to know which subproject\n\t\t// the times are in, in order to call the confirm function.\n\t\tconst linkedItemResources = await this.fetchLinkedItemResourcesWithColumns(\n\t\t\tcontext.transaction,\n\t\t\tupdatedTuples,\n\t\t\t{\n\t\t\t\tMateriaalCat: schemeValueColumnIds,\n\t\t\t\tFunctie: schemeValueTimeFrameColumnIds,\n\t\t\t\tFunctiegroep: schemeValueColumnIds,\n\t\t\t},\n\t\t);\n\n\t\tlet timeItemResources: ItemResource<'Tijd', ['subproject', 'project', 'id', 'is_absolute_times_substitute']>[];\n\n\t\ttry {\n\t\t\ttimeItemResources = await context.transaction.getItemsById(\n\t\t\t\t'Tijd',\n\t\t\t\t[\n\t\t\t\t\t...this.extractTimeItemIds(\n\t\t\t\t\t\tlinkedItemResources,\n\t\t\t\t\t\tcreatedTuples,\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t),\n\t\t\t\t],\n\t\t\t\t{\n\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t'id',\n\t\t\t\t\t\t'project',\n\t\t\t\t\t\t'subproject',\n\t\t\t\t\t\t'is_absolute_times_substitute',\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t);\n\t\t} catch (e) {\n\t\t\t// Fixme: RM4-37196 In templates the times are also new items, so cannot be found on the transaction. Ideally we get them from the changesDelta\n\t\t\tif (e instanceof ItemNotFoundException) {\n\t\t\t\treturn BLR_SKIP_RULE;\n\t\t\t}\n\n\t\t\tthrow e;\n\t\t}\n\n\t\tconst conditionResult = this.validateLinkedTimes(\n\t\t\tlinkedItemResources,\n\t\t\tcreatedTuples,\n\t\t\ttimeItemResources,\n\t\t\tcontext,\n\t\t);\n\n\t\tif (\n\t\t\tLINKED_TIME_ITEM_TYPES.every(\n\t\t\t\titemType => conditionResult[itemType].created.length === 0\n\t\t\t\t\t&& conditionResult[itemType].updated.length === 0,\n\t\t\t)\n\t\t) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn conditionResult;\n\t}\n\n\tpublic override apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\t_dependency: null,\n\t\tconditionResult: LinkedTimeItemSubprojectBusinessLogicRuleConditionResult,\n\t): void {\n\t\tfor (const linkedTimeItemType of LINKED_TIME_ITEM_TYPES) {\n\t\t\tfor (const createdTuple of conditionResult[linkedTimeItemType].created) {\n\t\t\t\tcontext.destinationChangesDelta.setItemCreatedByTuple(\n\t\t\t\t\tcreatedTuple.item as ChangesDeltaItemCreateDelta<LinkedTimeItemType>,\n\t\t\t\t\tthis.schemeValueColumnIdArrayToFieldMap(\n\t\t\t\t\t\tcreatedTuple.invalidTimes,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tfor (const updatedTuple of conditionResult[linkedTimeItemType].updated) {\n\t\t\t\tcontext.setItemUpdated(\n\t\t\t\t\tupdatedTuple.item as ItemEntry<LinkedTimeItemType>,\n\t\t\t\t\tthis.schemeValueColumnIdArrayToFieldMap(\n\t\t\t\t\t\tupdatedTuple.invalidTimes,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic override dependency (): Promise<null> {\n\t\treturn Promise.resolve(\n\t\t\tnull,\n\t\t);\n\t}\n\n\tprivate schemeValueColumnIdArrayToFieldMap (\n\t\tcolumnIds: SchemeValueTimeFrameColumnId[],\n\t\t// Exclude the 'timeframe' column from the type to save ourselves some type juggling.\n\t): Partial<FieldMap<LinkedTimeItemType, typeof schemeValueColumnIds>> {\n\t\tconst result: Partial<FieldMap<LinkedTimeItemType, typeof schemeValueColumnIds>> = {};\n\n\t\tfor (const columnId of columnIds) {\n\t\t\tresult[columnId] = null;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate validateLinkedTimes (\n\t\tlinkedTimeItemResourceMap: LinkedTimeItemResourceMap<typeof schemeValueColumnIds>,\n\t\tcreatedTupleMap: {\n\t\t\t[ItemType in LinkedTimeItemType]: ChangesDeltaItemCreateDelta<ItemType>[]\n\t\t},\n\t\ttimeItemResources: ItemResource<'Tijd', ['subproject', 'id', 'project', 'is_absolute_times_substitute']>[],\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): LinkedTimeItemSubprojectBusinessLogicRuleConditionResult {\n\t\tconst result: Partial<LinkedTimeItemSubprojectBusinessLogicRuleConditionResult> = {};\n\n\t\tfor (const linkedTimeItemType of LINKED_TIME_ITEM_TYPES) {\n\t\t\tconst created: {\n\t\t\t\titem: ChangesDeltaItemCreateDelta<LinkedTimeItemType>,\n\t\t\t\tinvalidTimes: SchemeValueTimeFrameColumnId[],\n\t\t\t}[] = [];\n\t\t\tconst updated: {\n\t\t\t\titem: ItemEntry<LinkedTimeItemType>,\n\t\t\t\tinvalidTimes: SchemeValueTimeFrameColumnId[],\n\t\t\t}[] = [];\n\n\t\t\tfor (const createdTuple of createdTupleMap[linkedTimeItemType]) {\n\t\t\t\tconst invalidTimes = this.getInvalidTimeColumnIds(\n\t\t\t\t\tthis.getCreatedItemTimeIdIterator(\n\t\t\t\t\t\tlinkedTimeItemType,\n\t\t\t\t\t\tcreatedTuple as ChangesDeltaItemCreateDelta<LinkedTimeItemType>,\n\t\t\t\t\t),\n\t\t\t\t\ttimeItemResources,\n\t\t\t\t);\n\n\t\t\t\tif (invalidTimes.length > 0) {\n\t\t\t\t\tcreated.push(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\titem: createdTuple as ChangesDeltaItemCreateDelta<LinkedTimeItemType>,\n\t\t\t\t\t\t\tinvalidTimes,\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const itemResource of linkedTimeItemResourceMap[linkedTimeItemType]) {\n\t\t\t\tconst invalidTimes = this.getInvalidTimeColumnIds(\n\t\t\t\t\tthis.getUpdatedItemTimeIdIterator(\n\t\t\t\t\t\tlinkedTimeItemType,\n\t\t\t\t\t\titemResource as ItemResource<LinkedTimeItemType, typeof schemeValueColumnIds>,\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t),\n\t\t\t\t\ttimeItemResources,\n\t\t\t\t);\n\n\t\t\t\tif (invalidTimes.length > 0) {\n\t\t\t\t\tupdated.push(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\titem: itemResource.entry as ItemEntry<LinkedTimeItemType>,\n\t\t\t\t\t\t\tinvalidTimes,\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t(result[linkedTimeItemType] as CreatedUpdatedTuple<LinkedTimeItemType>) = {\n\t\t\t\tcreated,\n\t\t\t\tupdated,\n\t\t\t};\n\t\t}\n\n\t\treturn result as LinkedTimeItemSubprojectBusinessLogicRuleConditionResult;\n\t}\n\n\tprivate getInvalidTimeColumnIds (\n\t\ttimeSubprojectTuples: Iterable<TimeSubprojectTuple>,\n\t\ttimeItemResources: ItemResource<'Tijd', ['subproject', 'id', 'project', 'is_absolute_times_substitute']>[],\n\t): SchemeValueTimeFrameColumnId[] {\n\t\tconst result: SchemeValueTimeFrameColumnId[] = [];\n\n\t\tfor (const timeSubprojectTuple of timeSubprojectTuples) {\n\t\t\tconst timeResource = timeItemResources.find(\n\t\t\t\titemResource => itemResource.fields.id === timeSubprojectTuple.timeId,\n\t\t\t)!;\n\t\t\tconst timeSubproject = timeResource.fields.subproject;\n\n\t\t\t// Absolute time substitute items should be excluded from linked time item validation\n\t\t\tif (timeResource.fields.is_absolute_times_substitute) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\ttimeResource.fields.project === timeSubprojectTuple.projectId\n\t\t\t\t&& (\n\t\t\t\t\ttimeSubproject === null\n\t\t\t\t\t|| timeSubproject === timeSubprojectTuple.subprojectId\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tresult.push(\n\t\t\t\ttimeSubprojectTuple.columnId,\n\t\t\t);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate extractTimeItemIds (\n\t\titemResourceMap: LinkedTimeItemResourceMap<typeof schemeValueColumnIds>,\n\t\tcreatedTupleMap: {\n\t\t\t[ItemType in LinkedTimeItemType]: ChangesDeltaItemCreateDelta<ItemType>[]\n\t\t},\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): Set<ItemId> {\n\t\tconst result: Set<ItemId> = new Set();\n\n\t\tfor (const linkedTimeItemType of LINKED_TIME_ITEM_TYPES) {\n\t\t\tfor (const createdTuple of createdTupleMap[linkedTimeItemType]) {\n\t\t\t\tconst timeIdIterator = this.getCreatedItemTimeIdIterator(\n\t\t\t\t\tlinkedTimeItemType,\n\t\t\t\t\tcreatedTuple as ChangesDeltaItemCreateDelta<LinkedTimeItemType>,\n\t\t\t\t);\n\n\t\t\t\tfor (const timeSubprojectTuple of timeIdIterator) {\n\t\t\t\t\tresult.add(\n\t\t\t\t\t\ttimeSubprojectTuple.timeId,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const itemResource of itemResourceMap[linkedTimeItemType]) {\n\t\t\t\tconst timeIdIterator = this.getUpdatedItemTimeIdIterator(\n\t\t\t\t\tlinkedTimeItemType,\n\t\t\t\t\titemResource as ItemResource<LinkedTimeItemType, typeof schemeValueColumnIds>,\n\t\t\t\t\tcontext,\n\t\t\t\t);\n\n\t\t\t\tfor (const timeSubprojectTuple of timeIdIterator) {\n\t\t\t\t\tresult.add(\n\t\t\t\t\t\ttimeSubprojectTuple.timeId,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * The iterator includes the IDs of all times linked to the items in the updated or created items.\n\t */\n\tprivate* getCreatedItemTimeIdIterator<ItemTypeType extends LinkedTimeItemType> (\n\t\titemType: ItemTypeType,\n\t\tsource: ChangesDeltaItemCreateDelta<ItemTypeType>,\n\t): Generator<TimeSubprojectTuple> {\n\t\tconst columnIds = itemType === 'Functie'\n\t\t\t? schemeValueTimeFrameColumnIds\n\t\t\t: schemeValueColumnIds;\n\t\tconst projectId = source.fields.project as number;\n\t\tconst subprojectId = source.fields.subproject as number;\n\n\t\tfor (const columnId of columnIds) {\n\t\t\tconst timeId = source.fields[columnId];\n\n\t\t\tif (timeId === null) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tyield {\n\t\t\t\tprojectId,\n\t\t\t\tsubprojectId,\n\t\t\t\ttimeId,\n\t\t\t\tcolumnId,\n\t\t\t};\n\t\t}\n\t}\n\n\tprivate* getUpdatedItemTimeIdIterator<ItemTypeType extends LinkedTimeItemType> (\n\t\titemType: ItemTypeType,\n\t\tsource: ItemResource<ItemTypeType, typeof schemeValueColumnIds>,\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): Generator<TimeSubprojectTuple> {\n\t\tconst columnIds = itemType === 'Functie'\n\t\t\t? schemeValueTimeFrameColumnIds\n\t\t\t: schemeValueColumnIds;\n\t\tconst projectId = context.getLatestValue(\n\t\t\tsource.entry,\n\t\t\t'project',\n\t\t) as number;\n\t\tconst subprojectId = context.getLatestValue(\n\t\t\tsource.entry,\n\t\t\t'subproject',\n\t\t) as number;\n\n\t\tfor (const columnId of columnIds) {\n\t\t\tconst timeId = context.getLatestValue(\n\t\t\t\tsource.entry,\n\t\t\t\t// Exclude the 'timeframe' column from the type to save ourselves some type juggling.\n\t\t\t\tcolumnId as (typeof schemeValueColumnIds)[number],\n\t\t\t);\n\n\t\t\tif (timeId === null) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tyield {\n\t\t\t\tprojectId,\n\t\t\t\tsubprojectId,\n\t\t\t\ttimeId: timeId as number,\n\t\t\t\tcolumnId,\n\t\t\t};\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { ApiRequestColumnArray } from '../../../types/ItemTypesCollection';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\nimport { LinkedTimeItemBusinessLogicRuleBase, LinkedTimeItemBusinessLogicRuleBaseUpdatedTuples, LinkedTimeItemResourceMap } from './LinkedTimeItemBusinessLogicRuleBase';\nimport { LINKED_TIME_ITEM_TYPES, TimeColumnUtil } from './TimeColumnUtil';\n\nconst requestColumns = [\n\t...TimeColumnUtil.valueColumnIds,\n\t...TimeColumnUtil.schemeStartColumnIds,\n] as const;\n\nexport const timeColumns = [\n\t'id',\n\t'van',\n\t'tot',\n] as const satisfies ApiRequestColumnArray<'Tijd'>;\n\ninterface Dependency {\n\ttimeResources: ItemResource<'Tijd', typeof timeColumns>[],\n\tlinkedTimeItemResources: LinkedTimeItemResourceMap<typeof requestColumns>,\n}\n\n/**\n * - When setting 'schema_gv', set 'gebruikvan' to the corresponding time, and 'schema_gv_begin' to `true`.\n * - When setting 'schema_gt', set 'gebruiktot' to the corresponding time, and 'schema_gt_begin' to `false`.\n * - When setting 'schema_pv', set 'planvan' to the corresponding time, and 'schema_pv_begin' to `true`.\n * - When setting 'schema_pt', set 'plantot' to the corresponding time, and 'schema_pt_begin' to `false`.\n */\n@businessLogicRule(\n\t'LinkedTimeItemTimeSchemeBusinessLogicRule',\n)\nexport class LinkedTimeItemTimeSchemeBusinessLogicRule\n\textends LinkedTimeItemBusinessLogicRuleBase<\n\t\ttypeof TimeColumnUtil.schemeValueColumnIds,\n\t\tLinkedTimeItemBusinessLogicRuleBaseUpdatedTuples<typeof TimeColumnUtil.schemeValueColumnIds>,\n\t\tDependency\n\t> {\n\n\tprotected override conditionColumns = TimeColumnUtil.schemeValueColumnIds;\n\n\tpublic override condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): LinkedTimeItemBusinessLogicRuleBaseUpdatedTuples<typeof TimeColumnUtil.schemeValueColumnIds> | typeof BLR_SKIP_RULE {\n\t\treturn this.extractUpdatedTuplesCondition(\n\t\t\tcontext,\n\t\t);\n\t}\n\n\tpublic override async dependency (\n\t\ttransaction: TransactionCache,\n\t\tconditionResult: LinkedTimeItemBusinessLogicRuleBaseUpdatedTuples<typeof TimeColumnUtil.schemeValueColumnIds>,\n\t): Promise<Dependency> {\n\t\tconst [\n\t\t\ttimeResources,\n\t\t\tlinkedTimeItemResources,\n\t\t] = await Promise.all(\n\t\t\t[\n\t\t\t\ttransaction.getItemsById(\n\t\t\t\t\t'Tijd',\n\t\t\t\t\tthis.getTimeItemIds(\n\t\t\t\t\t\tconditionResult,\n\t\t\t\t\t),\n\t\t\t\t\t{\n\t\t\t\t\t\tcolumns: timeColumns,\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t\tthis.fetchLinkedItemResources(\n\t\t\t\t\ttransaction,\n\t\t\t\t\tconditionResult,\n\t\t\t\t\trequestColumns,\n\t\t\t\t),\n\t\t\t],\n\t\t);\n\n\t\treturn {\n\t\t\ttimeResources,\n\t\t\tlinkedTimeItemResources,\n\t\t};\n\t}\n\n\tpublic override apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tdependency: Dependency,\n\t\tconditionResult: LinkedTimeItemBusinessLogicRuleBaseUpdatedTuples<typeof TimeColumnUtil.schemeValueColumnIds>,\n\t): void {\n\t\tfor (const linkedItemType of LINKED_TIME_ITEM_TYPES) {\n\t\t\tfor (const conditionResultElement of conditionResult[linkedItemType]) {\n\t\t\t\tconst itemEntry = conditionResultElement.itemEntry;\n\t\t\t\tconst columnInstance = TimeColumnUtil.getColumnInstance(\n\t\t\t\t\tconditionResultElement.columnId,\n\t\t\t\t);\n\n\t\t\t\t// If 'schema_gv_begin' etc. is already set in the changes delta, we don't want to overwrite that\n\t\t\t\t// value.\n\t\t\t\tlet schemeStartValue: boolean | undefined = context.previousChangesDelta.getUpdatedValue(\n\t\t\t\t\titemEntry,\n\t\t\t\t\tcolumnInstance.start.id,\n\t\t\t\t);\n\n\t\t\t\tif (schemeStartValue === undefined) {\n\t\t\t\t\tcontext.setItemUpdated(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t[columnInstance.start.id]: schemeStartValue = columnInstance.isStart,\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// We always want to set the corresponding time value field.\n\t\t\t\tif (conditionResultElement.newValue !== null) {\n\t\t\t\t\tconst timeResource = dependency.timeResources.find(\n\t\t\t\t\t\titemResource => itemResource.fields.id === conditionResultElement.newValue,\n\t\t\t\t\t)!;\n\n\t\t\t\t\tcontext.setUpdatedValue(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\tcolumnInstance.value.id,\n\t\t\t\t\t\tschemeStartValue\n\t\t\t\t\t\t\t? timeResource.fields.van\n\t\t\t\t\t\t\t: timeResource.fields.tot,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate getTimeItemIds (\n\t\tconditionResult: LinkedTimeItemBusinessLogicRuleBaseUpdatedTuples<typeof TimeColumnUtil.schemeValueColumnIds>,\n\t): ItemId[] {\n\t\tconst result: Set<ItemId> = new Set();\n\n\t\tfor (const linkedItemType of LINKED_TIME_ITEM_TYPES) {\n\t\t\tfor (const conditionResultElement of conditionResult[linkedItemType]) {\n\t\t\t\tconst timeItemId = conditionResultElement.newValue;\n\n\t\t\t\tif (timeItemId !== null) {\n\t\t\t\t\tresult.add(\n\t\t\t\t\t\ttimeItemId,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn [\n\t\t\t...result,\n\t\t];\n\t}\n\n}\n","import { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\nimport { LinkedTimeItemBusinessLogicRuleBase, LinkedTimeItemBusinessLogicRuleBaseUpdatedTuples, LinkedTimeItemResourceMap } from './LinkedTimeItemBusinessLogicRuleBase';\nimport { LINKED_TIME_ITEM_TYPES, TimeColumnUtil } from './TimeColumnUtil';\n\n/**\n * - If 'schema_gv' changes, while 'schema_gv_start' is `true`, and previously, 'schema_gv' and 'schema_gt' had the same\n * value, set 'schema_gt' to the new value of 'schema_gv'.\n * - If 'schema_pv' changes, while 'schema_pv_start' is `true` and previously, 'schema_pv' and 'schema_pt' had the same\n * value, set 'schema_pt' to the new value of 'schema_pv'.\n */\n@businessLogicRule(\n\t'LinkedTimeItemTimeSchemeStartBusinessLogicRule',\n)\nexport class LinkedTimeItemTimeSchemeStartBusinessLogicRule\n\textends LinkedTimeItemBusinessLogicRuleBase<\n\t\ttypeof TimeColumnUtil.schemeValueStartColumnIds,\n\t\tLinkedTimeItemBusinessLogicRuleBaseUpdatedTuples<typeof TimeColumnUtil.schemeValueStartColumnIds>,\n\t\tLinkedTimeItemResourceMap<typeof TimeColumnUtil.schemeValueColumnIds>\n\t> {\n\n\tprotected override conditionColumns = TimeColumnUtil.schemeValueStartColumnIds;\n\n\tpublic override condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): LinkedTimeItemBusinessLogicRuleBaseUpdatedTuples<typeof TimeColumnUtil.schemeValueStartColumnIds> | typeof BLR_SKIP_RULE {\n\t\treturn this.extractUpdatedTuplesCondition(\n\t\t\tcontext,\n\t\t);\n\t}\n\n\tpublic override dependency (\n\t\ttransaction: TransactionCache,\n\t\tconditionResult: LinkedTimeItemBusinessLogicRuleBaseUpdatedTuples<typeof TimeColumnUtil.schemeValueStartColumnIds>,\n\t): Promise<LinkedTimeItemResourceMap<typeof TimeColumnUtil.schemeValueColumnIds>> {\n\t\treturn this.fetchLinkedItemResources(\n\t\t\ttransaction,\n\t\t\tconditionResult,\n\t\t\tTimeColumnUtil.schemeValueColumnIds,\n\t\t);\n\t}\n\n\tpublic override apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\t_dependencies: LinkedTimeItemResourceMap<typeof TimeColumnUtil.schemeValueColumnIds>,\n\t\tconditionResult: LinkedTimeItemBusinessLogicRuleBaseUpdatedTuples<typeof TimeColumnUtil.schemeValueStartColumnIds>,\n\t): void {\n\t\tconst itemHandler = context.transaction.itemHandler;\n\n\t\tfor (const linkedItemType of LINKED_TIME_ITEM_TYPES) {\n\t\t\tfor (const conditionResultElement of conditionResult[linkedItemType]) {\n\t\t\t\tconst itemEntry = conditionResultElement.itemEntry;\n\t\t\t\tconst columnInstance = TimeColumnUtil.getColumnInstance(\n\t\t\t\t\tconditionResultElement.columnId,\n\t\t\t\t);\n\t\t\t\tconst oppositeColumnId = columnInstance.opposite.id;\n\n\t\t\t\tif (\n\t\t\t\t\t!context.previousChangesDelta.hasUpdatedValue(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\toppositeColumnId,\n\t\t\t\t\t)\n\t\t\t\t\t&& context.getLatestValue(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\tcolumnInstance.start.id,\n\t\t\t\t\t) === true\n\t\t\t\t\t&& itemHandler.lookUpItemField(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\tconditionResultElement.columnId,\n\t\t\t\t\t) === itemHandler.lookUpItemField(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\toppositeColumnId,\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\tcontext.setUpdatedValue(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\toppositeColumnId,\n\t\t\t\t\t\tconditionResultElement.newValue,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n}\n","import { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\nimport { LinkedTimeItemBusinessLogicRuleBase, LinkedTimeItemBusinessLogicRuleBaseUpdatedTuples, LinkedTimeItemResourceMap } from './LinkedTimeItemBusinessLogicRuleBase';\nimport { LINKED_TIME_ITEM_TYPES, TimeColumnUtil } from './TimeColumnUtil';\n\nconst requestColumns = [\n\t...TimeColumnUtil.valueColumnIds,\n\t...TimeColumnUtil.schemeValueEndColumnIds,\n] as const;\n\n/**\n * - When 'gebruikvan' changes, and 'gebruiktot' is invalid or equal to the previous value of 'gebruikvan',\n * and 'schema_gt' is `null` (not referring to a time), set 'gebruiktot' to the new value of 'gebruikvan'.\n * - When 'planvan' changes, and 'plantot' is invalid or equal to the previous value of 'planvan',\n * and 'schema_pt' is `null` (not referring to a time), set 'plantot' to the new value of 'planvan'.\n */\n@businessLogicRule(\n\t'LinkedTimeItemTimeValueStartBusinessLogicRule',\n)\nexport class LinkedTimeItemTimeValueStartBusinessLogicRule\n\textends LinkedTimeItemBusinessLogicRuleBase<\n\t\ttypeof TimeColumnUtil.valueStartColumnIds,\n\t\tLinkedTimeItemBusinessLogicRuleBaseUpdatedTuples<typeof TimeColumnUtil.valueStartColumnIds>,\n\t\tLinkedTimeItemResourceMap<typeof requestColumns>\n\t> {\n\n\tprotected override conditionColumns = TimeColumnUtil.valueStartColumnIds;\n\n\tpublic override condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): LinkedTimeItemBusinessLogicRuleBaseUpdatedTuples<typeof TimeColumnUtil.valueStartColumnIds> | typeof BLR_SKIP_RULE {\n\t\treturn this.extractUpdatedTuplesCondition(\n\t\t\tcontext,\n\t\t);\n\t}\n\n\tpublic override dependency (\n\t\ttransaction: TransactionCache,\n\t\tconditionResult: LinkedTimeItemBusinessLogicRuleBaseUpdatedTuples<typeof TimeColumnUtil.valueStartColumnIds>,\n\t): Promise<LinkedTimeItemResourceMap<typeof requestColumns>> {\n\t\treturn this.fetchLinkedItemResources(\n\t\t\ttransaction,\n\t\t\tconditionResult,\n\t\t\trequestColumns,\n\t\t);\n\t}\n\n\tpublic override apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\t_dependencies: LinkedTimeItemResourceMap<typeof requestColumns>,\n\t\tconditionResult: LinkedTimeItemBusinessLogicRuleBaseUpdatedTuples<typeof TimeColumnUtil.valueStartColumnIds>,\n\t): void {\n\t\tconst itemHandler = context.transaction.itemHandler;\n\n\t\tfor (const linkedItemType of LINKED_TIME_ITEM_TYPES) {\n\t\t\tfor (const conditionResultElement of conditionResult[linkedItemType]) {\n\t\t\t\tconst itemEntry = conditionResultElement.itemEntry;\n\t\t\t\tconst columnInstance = TimeColumnUtil.getColumnInstance(\n\t\t\t\t\tconditionResultElement.columnId,\n\t\t\t\t);\n\t\t\t\tconst oppositeColumnInstance = columnInstance.opposite;\n\n\t\t\t\tif (\n\t\t\t\t\tcontext.previousChangesDelta.hasUpdatedValue(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\toppositeColumnInstance.id,\n\t\t\t\t\t)\n\t\t\t\t\t|| context.getLatestValue(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\toppositeColumnInstance.scheme.id,\n\t\t\t\t\t) !== null\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst previousOppositeValue = itemHandler.lookUpItemField(\n\t\t\t\t\titemEntry,\n\t\t\t\t\toppositeColumnInstance.id,\n\t\t\t\t)!;\n\n\t\t\t\tif (\n\t\t\t\t\t!previousOppositeValue.isValid()\n\t\t\t\t\t|| previousOppositeValue.isSame(\n\t\t\t\t\t\titemHandler.lookUpItemField(\n\t\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\t\tcolumnInstance.id,\n\t\t\t\t\t\t),\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\tcontext.setUpdatedValue(\n\t\t\t\t\t\titemEntry,\n\t\t\t\t\t\toppositeColumnInstance.id,\n\t\t\t\t\t\tconditionResultElement.newValue.clone(),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemEntry } from '../../../models/ItemEntry';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { promiseAllObject } from '../../Util';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = {\n\tOfferte: ItemId[],\n\tContract: ItemId[],\n};\n\ntype Dependency = {\n\tOfferte: ItemResource<'Offerte', ['vervaldatum']>[],\n\tContract: ItemResource<'Contract', ['vervaldatum']>[],\n\tState: ItemResource<'State', ['geldigheidofferte']>,\n};\n\n@businessLogicRule(\n\t'OfferteContractDatumBusinessLogicRule',\n)\nexport class OfferteContractDatumBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\tconst updatedIterator = context.previousChangesDelta.getUpdatedTuplesIterator(\n\t\t\t'Offerte',\n\t\t\t'Contract',\n\t\t);\n\t\tconst result: ConditionResult = {\n\t\t\tOfferte: [],\n\t\t\tContract: [],\n\t\t};\n\t\tlet hasValues: boolean = false;\n\n\t\tfor (const tuple of updatedIterator) {\n\t\t\tif (\n\t\t\t\tcontext.fieldChanged(\n\t\t\t\t\ttuple,\n\t\t\t\t\t'datum',\n\t\t\t\t) !== null\n\t\t\t) {\n\t\t\t\thasValues = true;\n\t\t\t\tresult[tuple.entry.itemType].push(\n\t\t\t\t\ttuple.entry.itemId,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (!hasValues) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\titemIdMap: ConditionResult,\n\t): Promise<Dependency> {\n\t\treturn promiseAllObject(\n\t\t\t{\n\t\t\t\tOfferte: transaction.getItemsById(\n\t\t\t\t\t'Offerte',\n\t\t\t\t\titemIdMap.Offerte,\n\t\t\t\t\t{\n\t\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\t'vervaldatum',\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t\tContract: transaction.getItemsById(\n\t\t\t\t\t'Contract',\n\t\t\t\t\titemIdMap.Contract,\n\t\t\t\t\t{\n\t\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\t'vervaldatum',\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t\tState: transaction.getItemById(\n\t\t\t\t\t'State',\n\t\t\t\t\t1,\n\t\t\t\t\t{\n\t\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\t'geldigheidofferte',\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\titems: Dependency,\n\t): void {\n\t\tfor (\n\t\t\tconst itemType of [\n\t\t\t'Offerte',\n\t\t\t'Contract',\n\t\t]\n\t\t\t) {\n\t\t\tfor (const itemResource of items[itemType]) {\n\t\t\t\tconst itemEntry = itemResource.entry as ItemEntry<'Offerte' | 'Contract'>;\n\t\t\t\tconst newValue = context.mergedChangesDelta.getUpdatedValue(\n\t\t\t\t\titemEntry,\n\t\t\t\t\t'datum',\n\t\t\t\t)!;\n\n\t\t\t\tcontext.setItemUpdated(\n\t\t\t\t\titemEntry,\n\t\t\t\t\t{\n\t\t\t\t\t\tvervaldatum: newValue\n\t\t\t\t\t\t\t.clone()\n\t\t\t\t\t\t\t.add(\n\t\t\t\t\t\t\t\titems.State.fields.geldigheidofferte,\n\t\t\t\t\t\t\t\t'days',\n\t\t\t\t\t\t\t),\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n}\n","import { AantalBusinessLogicRuleBase } from '../AantalBusinessLogicRuleBase';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\n\n@businessLogicRule(\n\t'PlanningmateriaalAantalBusinessLogicRule',\n)\nexport class PlanningmateriaalAantalBusinessLogicRule\n\textends AantalBusinessLogicRuleBase<'Planningmateriaal'> {\n\n\tprotected readonly itemType = 'Planningmateriaal';\n\n}\n","import { AantaltotaalBusinessLogicRuleBase, plannedEquipmentColumns } from '../AantaltotaalBusinessLogicRuleBase';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\n\n@businessLogicRule(\n\t'PlanningmateriaalAantaltotaalBusinessLogicRule',\n)\nexport class PlanningmateriaalAantaltotaalBusinessLogicRule\n\textends AantaltotaalBusinessLogicRuleBase<'Planningmateriaal'> {\n\n\tprotected override readonly itemType = 'Planningmateriaal';\n\n\tprotected override readonly groupingProperties = {\n\t\titemType: 'MateriaalCat',\n\t\tcolumnId: 'categorie',\n\t} as const;\n\n\tprotected override readonly requestColumns = plannedEquipmentColumns;\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { ApiRequestColumnArray } from '../../../types/ItemTypesCollection';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { ChangesDelta } from '../../ChangesDelta';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = ItemId[];\n\nconst childPlanningmateriaalColumns = [\n\t'id',\n\t'optie',\n\t'parent',\n] as const satisfies ApiRequestColumnArray<'Planningmateriaal'>;\n\nconst changedPlanningMateriaalColumns = [\n\t'id',\n\t'optie',\n\t'categorie',\n\t'parent',\n\t{\n\t\tmateriaal: [\n\t\t\t'type',\n\t\t],\n\t},\n] as const satisfies ApiRequestColumnArray<'Planningmateriaal'>;\n\ntype Dependency = {\n\tchildPlanningmateriaalResourcesInCategories: ItemResource<'Planningmateriaal', typeof childPlanningmateriaalColumns>[],\n\tchangedPlanningmateriaalResources: ItemResource<'Planningmateriaal', typeof changedPlanningMateriaalColumns>[],\n};\n\n/**\n * @description\n * If the kit's 'optie' is changed then the children should follow\n */\n@businessLogicRule(\n\t'PlanningmateriaalOptieBusinessLogicRule',\n)\nexport class PlanningmateriaalOptieBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\treturn context.getItemIdsWithUpdatedField(\n\t\t\t'Planningmateriaal',\n\t\t\t'optie',\n\t\t);\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\tchangedPlanningmateriaalIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\tconst changedPlanningmateriaalResources = await transaction.getItemsById(\n\t\t\t'Planningmateriaal',\n\t\t\tchangedPlanningmateriaalIds,\n\t\t\t{\n\t\t\t\tcolumns: changedPlanningMateriaalColumns,\n\t\t\t},\n\t\t);\n\n\t\tconst categoryIdSet: Set<ItemId> = new Set();\n\n\t\tfor (const changedPlanningmateriaalResource of changedPlanningmateriaalResources) {\n\t\t\tcategoryIdSet.add(\n\t\t\t\tchangedPlanningmateriaalResource.fields.categorie,\n\t\t\t);\n\t\t}\n\n\t\tconst childPlanningmateriaalResourcesInCategories = await transaction.getItemsByQuery(\n\t\t\t'Planningmateriaal',\n\t\t\t{\n\t\t\t\tconditions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: 'categorie',\n\t\t\t\t\t\tvalue: Array.from(\n\t\t\t\t\t\t\tcategoryIdSet.values(),\n\t\t\t\t\t\t),\n\t\t\t\t\t\tcomparator: 'IN',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: 'parent',\n\t\t\t\t\t\tvalue: null,\n\t\t\t\t\t\tcomparator: '!=',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t\t{\n\t\t\t\tcolumns: childPlanningmateriaalColumns,\n\t\t\t},\n\t\t);\n\n\t\treturn {\n\t\t\tchildPlanningmateriaalResourcesInCategories: childPlanningmateriaalResourcesInCategories,\n\t\t\tchangedPlanningmateriaalResources: changedPlanningmateriaalResources,\n\t\t};\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tdependency: Dependency,\n\t): void {\n\t\tfor (const changedPlanningmateriaalResource of dependency.changedPlanningmateriaalResources) {\n\t\t\tif (\n\t\t\t\tchangedPlanningmateriaalResource.getDerivedValue(\n\t\t\t\t\t'materiaal>type',\n\t\t\t\t) !== 'set'\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst updatedValue = context.getLatestValue(\n\t\t\t\tchangedPlanningmateriaalResource.entry,\n\t\t\t\t'optie',\n\t\t\t) as boolean;\n\n\t\t\tthis.updatePlanningmateriaalByParent(\n\t\t\t\tchangedPlanningmateriaalResource.fields.id,\n\t\t\t\tdependency.childPlanningmateriaalResourcesInCategories,\n\t\t\t\tupdatedValue,\n\t\t\t\tcontext.destinationChangesDelta,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate updatePlanningmateriaalByParent (\n\t\tparentPlanningmateriaalId: ItemId,\n\t\tchildPlanningmateriaalResourcesInCategories: Dependency['childPlanningmateriaalResourcesInCategories'],\n\t\tupdatedValue: boolean,\n\t\tdestinationChangesDelta: ChangesDelta,\n\t): void {\n\t\tfor (const planningmateriaalResource of childPlanningmateriaalResourcesInCategories) {\n\t\t\tif (\n\t\t\t\tplanningmateriaalResource.fields.parent !== parentPlanningmateriaalId\n\t\t\t\t|| parentPlanningmateriaalId === planningmateriaalResource.fields.id\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (planningmateriaalResource.fields.optie !== updatedValue) {\n\t\t\t\tdestinationChangesDelta.setItemUpdated(\n\t\t\t\t\tplanningmateriaalResource.entry,\n\t\t\t\t\t{\n\t\t\t\t\t\toptie: updatedValue,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.updatePlanningmateriaalByParent(\n\t\t\t\tplanningmateriaalResource.fields.id,\n\t\t\t\tchildPlanningmateriaalResourcesInCategories,\n\t\t\t\tupdatedValue,\n\t\t\t\tdestinationChangesDelta,\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\nconst planningmateriaalColumns = [\n\t'parent',\n\t{\n\t\tsetcontent: [\n\t\t\t'is_fixed',\n\t\t],\n\t},\n] as const;\n\ntype ConditionResult = ItemId<'Planningmateriaal'>[];\n\ntype Dependency = ItemResource<'Planningmateriaal', typeof planningmateriaalColumns>[];\n\n/*\n * When there's a planningmateriaal with a parent set & setcontent>is_fixed is false (meaning you CAN drag/drop)\n * Whenever this item is moved outside it's current parent we set the setcontent to `null` since this would no longer be correct\n */\n@businessLogicRule(\n\t'PlanningmateriaalParentBusinessLogicRule',\n)\nexport class PlanningmateriaalParentBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\treturn context.getItemIdsWithUpdatedField(\n\t\t\t'Planningmateriaal',\n\t\t\t'parent',\n\t\t);\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\tplanningmateriaalIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\treturn transaction.getItemsById(\n\t\t\t'Planningmateriaal',\n\t\t\tplanningmateriaalIds,\n\t\t\t{\n\t\t\t\tcolumns: planningmateriaalColumns,\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tplanningmateriaalResources: Dependency,\n\t): void {\n\t\tfor (const planningmateriaalResource of planningmateriaalResources) {\n\t\t\tcontext.setUpdatedValue(\n\t\t\t\tplanningmateriaalResource.entry,\n\t\t\t\t'setcontent',\n\t\t\t\tnull,\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { ChangesDeltaItemCreateDelta } from '../../CreatedChangesDelta';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = {\n\tchangedItems: ItemId[],\n\tcreatedItems: ChangesDeltaItemCreateDelta[],\n};\n\nconst planningMateriaalColumns = [\n\t'aantaltotaal',\n\t'stays_at_location',\n\t{\n\t\tcategorie: [\n\t\t\t{\n\t\t\t\tproject: [\n\t\t\t\t\t{\n\t\t\t\t\t\tprojecttype: [\n\t\t\t\t\t\t\t'type',\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t},\n] as const;\n\ntype Dependency = {\n\tchangedPlanningMateriaalResources: ItemResource<'Planningmateriaal', typeof planningMateriaalColumns>[],\n\tcreatedItems: ChangesDeltaItemCreateDelta<'Planningmateriaal'>[],\n};\n\n/**\n * @description\n * If the planningmateriaal 'aantaltotaal' is changed in a transfer project, stays_at_location should copy this value.\n */\n@businessLogicRule(\n\t'PlanningmateriaalStaysAtLocationBusinessLogicRule',\n)\nexport class PlanningmateriaalStaysAtLocationBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\tconst createdItems: ChangesDeltaItemCreateDelta[] = [];\n\n\t\tcontext.previousChangesDelta.created.forEach(\n\t\t\ttuple => {\n\t\t\t\tif (tuple.columns.itemType !== 'Planningmateriaal') {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tcreatedItems.push(\n\t\t\t\t\ttuple,\n\t\t\t\t);\n\t\t\t},\n\t\t);\n\n\t\tlet changedItems = context.getItemIdsWithUpdatedField(\n\t\t\t'Planningmateriaal',\n\t\t\t'aantaltotaal',\n\t\t);\n\n\t\tif (changedItems === BLR_SKIP_RULE) {\n\t\t\tchangedItems = [];\n\t\t}\n\n\t\tif (\n\t\t\tchangedItems.length === 0\n\t\t\t&& createdItems.length === 0\n\t\t) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn {\n\t\t\tchangedItems: changedItems,\n\t\t\tcreatedItems: createdItems,\n\t\t};\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\tconditionResult: ConditionResult,\n\t): Promise<Dependency> {\n\t\tconst changedPlanningMateriaalResources = await transaction.getItemsById(\n\t\t\t'Planningmateriaal',\n\t\t\tconditionResult.changedItems,\n\t\t\t{\n\t\t\t\tcolumns: planningMateriaalColumns,\n\t\t\t},\n\t\t);\n\n\t\treturn {\n\t\t\tchangedPlanningMateriaalResources: changedPlanningMateriaalResources,\n\t\t\tcreatedItems: conditionResult.createdItems,\n\t\t};\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tdependency: Dependency,\n\t): void {\n\t\tfor (const changedPlanningmateriaalResource of dependency.changedPlanningMateriaalResources) {\n\t\t\tif (\n\t\t\t\tchangedPlanningmateriaalResource.getDerivedValue(\n\t\t\t\t'categorie>project>projecttype>type',\n\t\t\t\t) !== 'transfer'\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst updatedValue = context.getLatestValue(\n\t\t\t\tchangedPlanningmateriaalResource.entry,\n\t\t\t\t'aantaltotaal',\n\t\t\t);\n\n\t\t\tcontext.setItemUpdated(\n\t\t\t\tchangedPlanningmateriaalResource.entry,\n\t\t\t\t{\n\t\t\t\t\tstays_at_location: updatedValue,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\tconst transaction = context.transaction;\n\n\t\tfor (const createdItem of dependency.createdItems) {\n\t\t\tif (\n\t\t\t\t!transaction.containsLocalItemEntryByItemId(\n\t\t\t\t\t'MateriaalCat',\n\t\t\t\t\tcreatedItem.fields.categorie,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst categorie = transaction.getLocalItemEntryByItemId(\n\t\t\t\t'MateriaalCat',\n\t\t\t\tcreatedItem.fields.categorie,\n\t\t\t);\n\t\t\tconst projectType = transaction.itemHandler.getDerivedValue(\n\t\t\t\tcategorie,\n\t\t\t\t'project>projecttype>type',\n\t\t\t\t'regular',\n\t\t\t);\n\n\t\t\tif (\n\t\t\t\tcreatedItem.fields.stays_at_location === createdItem.fields.aantaltotaal\n\t\t\t\t|| projectType !== 'transfer'\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tcontext.destinationChangesDelta.setItemCreatedByTuple(\n\t\t\t\tcreatedItem,\n\t\t\t\t{\n\t\t\t\t\tstays_at_location: createdItem.fields.aantaltotaal,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport moment from 'moment';\nimport { ItemEntry } from '../../../models/ItemEntry';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { FieldMap } from '../../../types/ItemTypesCollection';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { ChangesDelta } from '../../ChangesDelta';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\nconst START = {\n\tplanning: 'planvan',\n\ttravel: 'reistijd_vooraf',\n\tfactor: -1,\n} as const;\n\nconst END = {\n\tplanning: 'plantot',\n\ttravel: 'reistijd_achteraf',\n\tfactor: 1,\n} as const;\n\nconst TRAVEL_TIME_COLUMNS = {\n\tgeen: [],\n\theen: [\n\t\tSTART,\n\t],\n\tterug: [\n\t\tEND,\n\t],\n\tretour: [\n\t\tSTART,\n\t\tEND,\n\t],\n};\n\ntype ConditionResult = {\n\tPlanningpersoneel: ItemId[],\n\tPlanningtransport: ItemId[],\n};\n\ntype Dependency = {\n\tPlanningpersoneel: ItemResource<'Planningpersoneel', ['vervoer', 'functie', 'planvan', 'plantot']>[],\n\tPlanningtransport: ItemResource<'Planningtransport', ['vervoer', 'functie', 'planvan', 'plantot']>[],\n\tFunctie: {\n\t\t[functieId: string]: ItemResource<'Functie', ['reistijd_vooraf', 'reistijd_achteraf']>,\n\t},\n};\n\n@businessLogicRule(\n\t'PlanningPersoneelTransportBusinessLogicRule',\n)\nexport class PlanningPersoneelTransportBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\tconst updatedIterator = context.previousChangesDelta.getUpdatedTuplesIterator(\n\t\t\t'Planningpersoneel',\n\t\t\t'Planningtransport',\n\t\t);\n\t\tconst result: ConditionResult = {\n\t\t\tPlanningpersoneel: [],\n\t\t\tPlanningtransport: [],\n\t\t};\n\t\tlet hasValues: boolean = false;\n\n\t\tfor (const tuple of updatedIterator) {\n\t\t\tif (\n\t\t\t\tcontext.fieldChanged(\n\t\t\t\t\ttuple,\n\t\t\t\t\t'vervoer',\n\t\t\t\t) !== null\n\t\t\t) {\n\t\t\t\thasValues = true;\n\t\t\t\tresult[tuple.entry.itemType].push(\n\t\t\t\t\ttuple.entry.itemId,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (!hasValues) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\titemIdMap: ConditionResult,\n\t): Promise<Dependency> {\n\t\tconst [\n\t\t\tPlanningpersoneel,\n\t\t\tPlanningtransport,\n\t\t] = await Promise.all(\n\t\t\t[\n\t\t\t\ttransaction.getItemsById(\n\t\t\t\t\t'Planningpersoneel',\n\t\t\t\t\titemIdMap.Planningpersoneel,\n\t\t\t\t\t{\n\t\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\t'vervoer',\n\t\t\t\t\t\t\t'functie',\n\t\t\t\t\t\t\tSTART.planning,\n\t\t\t\t\t\t\tEND.planning,\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t\ttransaction.getItemsById(\n\t\t\t\t\t'Planningtransport',\n\t\t\t\t\titemIdMap.Planningtransport,\n\t\t\t\t\t{\n\t\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\t'vervoer',\n\t\t\t\t\t\t\t'functie',\n\t\t\t\t\t\t\tSTART.planning,\n\t\t\t\t\t\t\tEND.planning,\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t],\n\t\t);\n\n\t\tconst functionIds: ItemId[] = [];\n\n\t\tfor (\n\t\t\tconst itemResources of [\n\t\t\tPlanningpersoneel,\n\t\t\tPlanningtransport,\n\t\t]\n\t\t\t) {\n\t\t\tfor (const itemResource of itemResources) {\n\t\t\t\tconst functionId = itemResource.fields.functie;\n\n\t\t\t\tif (\n\t\t\t\t\t!functionIds.includes(\n\t\t\t\t\t\tfunctionId,\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\tfunctionIds.push(\n\t\t\t\t\t\tfunctionId,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst functionResources = await transaction.getItemsById(\n\t\t\t'Functie',\n\t\t\tfunctionIds,\n\t\t\t{\n\t\t\t\tcolumns: [\n\t\t\t\t\t'id',\n\t\t\t\t\tSTART.travel,\n\t\t\t\t\tEND.travel,\n\t\t\t\t],\n\t\t\t},\n\t\t);\n\n\t\treturn {\n\t\t\tPlanningpersoneel,\n\t\t\tPlanningtransport,\n\t\t\tFunctie: functionResources.reduce(\n\t\t\t\t(\n\t\t\t\t\tacc,\n\t\t\t\t\tfunctionResource,\n\t\t\t\t) => {\n\t\t\t\t\tacc[functionResource.fields.id] = functionResource;\n\n\t\t\t\t\treturn acc;\n\t\t\t\t},\n\t\t\t\t{},\n\t\t\t),\n\t\t};\n\t}\n\n\tpublic apply (\n\t\t{\n\t\t\ttransaction,\n\t\t\tmergedChangesDelta,\n\t\t\tdestinationChangesDelta,\n\t\t}: BusinessLogicRuleApplyContext,\n\t\titems: Dependency,\n\t): void {\n\t\tfor (\n\t\t\tconst itemType of [\n\t\t\t'Planningpersoneel',\n\t\t\t'Planningtransport',\n\t\t]\n\t\t\t) {\n\t\t\tfor (const planningResource of items[itemType]) {\n\t\t\t\tconst functionResource = items.Functie[planningResource.fields.functie];\n\t\t\t\tconst newValue = mergedChangesDelta.getUpdatedValue(\n\t\t\t\t\tplanningResource.entry as ItemEntry<'Planningtransport' | 'Planningpersoneel'>,\n\t\t\t\t\t'vervoer',\n\t\t\t\t)!;\n\n\t\t\t\t// Set the old values back\n\t\t\t\tthis.updatePlanningColumns(\n\t\t\t\t\ttransaction,\n\t\t\t\t\tdestinationChangesDelta,\n\t\t\t\t\tplanningResource,\n\t\t\t\t\tTRAVEL_TIME_COLUMNS[planningResource.fields.vervoer],\n\t\t\t\t\t-1,\n\t\t\t\t\tfunctionResource.fields,\n\t\t\t\t);\n\n\t\t\t\t// Update with the new transport values\n\t\t\t\tthis.updatePlanningColumns(\n\t\t\t\t\ttransaction,\n\t\t\t\t\tdestinationChangesDelta,\n\t\t\t\t\tplanningResource,\n\t\t\t\t\tTRAVEL_TIME_COLUMNS[newValue],\n\t\t\t\t\t1,\n\t\t\t\t\tfunctionResource.fields,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate updatePlanningColumns (\n\t\ttransaction: TransactionCache,\n\t\tchangesDelta: ChangesDelta,\n\t\titemResource: ItemResource<'Planningpersoneel' | 'Planningtransport', ['planvan', 'plantot']>,\n\t\ttravelTimeColumns,\n\t\tfactor: -1 | 1,\n\t\tfunctionFields: FieldMap<'Functie', ['reistijd_vooraf', 'reistijd_achteraf']>,\n\t): void {\n\t\tfor (const column of travelTimeColumns) {\n\t\t\tlet planningTime: moment.Moment | undefined = changesDelta.getUpdatedValue(\n\t\t\t\titemResource.entry,\n\t\t\t\tcolumn.planning,\n\t\t\t);\n\n\t\t\tif (planningTime === undefined) {\n\t\t\t\tplanningTime = transaction.itemHandler.lookUpItemField(\n\t\t\t\t\titemResource.entry,\n\t\t\t\t\tcolumn.planning,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tchangesDelta.setItemUpdated(\n\t\t\t\titemResource.entry,\n\t\t\t\t{\n\t\t\t\t\t[column.planning]: planningTime!\n\t\t\t\t\t\t.clone()\n\t\t\t\t\t\t.add(\n\t\t\t\t\t\t\tfactor * column.factor * functionFields[column.travel],\n\t\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { BLR_SKIP_RULE, BusinessLogicRule, businessLogicRule, BusinessLogicRuleApplyContext, BusinessLogicRuleConditionContext, ChangesDelta, CollectionResource, ItemEntry, ItemResource, promiseAllObject, TransactionCache } from '../../../internal';\n\nconst projectColumns = [\n\t'factuurmoment',\n\t'taxschema',\n] as const;\n\nconst subprojectColumns = [\n\t'korting_personeel',\n\t'korting_transport',\n\t'korting_verkoop',\n\t'korting_verhuur',\n\t'korting_totaal',\n\t'verzekering',\n] as const;\n\nconst clientColumns = [\n\t'factuurmoment',\n\t'taxschema',\n\t'personeelkorting',\n\t'transportkorting',\n\t'verkoopkorting',\n\t'verhuurkorting',\n\t'totaalkorting',\n\t'verzekering',\n\t'verzekering_aangepast',\n] as const;\n\ntype ConditionResult = {\n\tprojectId: ItemId,\n\tclientId: ItemId,\n}[];\n\ntype Dependency = {\n\t[projectId: number]: {\n\t\tprojectResource: ItemResource<'Project', typeof projectColumns>,\n\t\tsubprojectCollection: CollectionResource<'Subproject', typeof subprojectColumns>,\n\t\tclientResource: ItemResource<'Contact', typeof clientColumns>,\n\t},\n};\n\nconst fieldMap = {\n\tProject: {\n\t\tfactuurmoment: 'factuurmoment',\n\t\ttaxschema: 'taxschema',\n\t},\n\tSubproject: {\n\t\tpersoneelkorting: 'korting_personeel',\n\t\ttransportkorting: 'korting_transport',\n\t\tverkoopkorting: 'korting_verkoop',\n\t\tverhuurkorting: 'korting_verhuur',\n\t\ttotaalkorting: 'korting_totaal',\n\t\tverzekering: 'verzekering',\n\t},\n};\n\n/**\n * @description\n * Whenever the location of a Client changes in a Project\n * and client financial values are different from project ones,\n * trigger the copy financial values modal to provide user\n * an option to copy the financial values from client.\n */\n@businessLogicRule(\n\t'ProjectClientChangedBusinessLogicRule',\n)\nexport class ProjectClientChangedBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic async condition (\n\t\t{\n\t\t\tpreviousChangesDelta,\n\t\t\ttransaction,\n\t\t}: BusinessLogicRuleConditionContext,\n\t): Promise<ConditionResult | typeof BLR_SKIP_RULE> {\n\t\tconst updatedIterator = previousChangesDelta.getUpdatedTuplesIterator(\n\t\t\t'Project',\n\t\t);\n\t\tconst promises: Promise<{projectId: ItemId, clientId: ItemId, hasEqualValues: boolean,}>[] = [];\n\n\t\tfor (const tuple of updatedIterator) {\n\t\t\tconst clientId = previousChangesDelta.getUpdatedValue(\n\t\t\t\ttuple.entry,\n\t\t\t\t'opdrachtgever',\n\t\t\t);\n\n\t\t\tif (\n\t\t\t\tclientId !== undefined\n\t\t\t\t&& clientId !== null\n\t\t\t) {\n\t\t\t\tpromises.push(\n\t\t\t\t\tpromiseAllObject(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tprojectId: tuple.entry.itemId,\n\t\t\t\t\t\t\tclientId: clientId,\n\t\t\t\t\t\t\thasEqualValues: this.valuesEqual(\n\t\t\t\t\t\t\t\ttuple.entry.itemId,\n\t\t\t\t\t\t\t\tclientId,\n\t\t\t\t\t\t\t\ttransaction,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t},\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (promises.length === 0) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\tconst result = await Promise.all(\n\t\t\tpromises,\n\t\t);\n\n\t\tconst noEqualValuesArray = result.filter(\n\t\t\titem => !item.hasEqualValues,\n\t\t);\n\n\t\tif (noEqualValuesArray.length === 0) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn noEqualValuesArray.map(\n\t\t\titem => ({\n\t\t\t\tprojectId: item.projectId,\n\t\t\t\tclientId: item.clientId,\n\t\t\t}),\n\t\t);\n\t}\n\n\tpublic dependency (\n\t\ttransaction: TransactionCache,\n\t\tobj: ConditionResult,\n\t): Promise<Dependency> {\n\t\tconst promises = {};\n\n\t\tfor (const projectClientIds of obj) {\n\t\t\tconst {\n\t\t\t\tprojectId,\n\t\t\t\tclientId,\n\t\t\t} = projectClientIds;\n\n\t\t\tpromises[projectId] = promiseAllObject(\n\t\t\t\t{\n\t\t\t\t\tprojectResource: transaction.getItemById(\n\t\t\t\t\t\t'Project',\n\t\t\t\t\t\tprojectId,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcolumns: projectColumns,\n\t\t\t\t\t\t},\n\t\t\t\t\t),\n\t\t\t\t\tsubprojectCollection: transaction.getCollection(\n\t\t\t\t\t\t'Subproject',\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tparent: {\n\t\t\t\t\t\t\t\titemType: 'Project',\n\t\t\t\t\t\t\t\titemId: projectId,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tcolumns: subprojectColumns,\n\t\t\t\t\t\t},\n\t\t\t\t\t),\n\t\t\t\t\tclientResource: transaction.getItemById(\n\t\t\t\t\t\t'Contact',\n\t\t\t\t\t\tclientId,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcolumns: clientColumns,\n\t\t\t\t\t\t},\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\treturn promiseAllObject(\n\t\t\tpromises,\n\t\t);\n\t}\n\n\tpublic apply (\n\t\t{\n\t\t\tdestinationChangesDelta,\n\t\t}: BusinessLogicRuleApplyContext,\n\t\tobj: Dependency,\n\t): void {\n\t\tfor (const projectId in obj) {\n\t\t\tthis.setValues(\n\t\t\t\tobj[projectId].projectResource,\n\t\t\t\tobj[projectId].clientResource.fields,\n\t\t\t\tdestinationChangesDelta,\n\t\t\t);\n\n\t\t\tfor (const subprojectItem of obj[projectId].subprojectCollection.items) {\n\t\t\t\tthis.setValues(\n\t\t\t\t\tsubprojectItem,\n\t\t\t\t\tobj[projectId].clientResource.fields,\n\t\t\t\t\tdestinationChangesDelta,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async valuesEqual (\n\t\tprojectId: ItemId,\n\t\tclientId: ItemId,\n\t\ttransaction: TransactionCache,\n\t): Promise<boolean> {\n\t\tconst result = await promiseAllObject(\n\t\t\t{\n\t\t\t\tprojectResource: transaction.getItemById(\n\t\t\t\t\t'Project',\n\t\t\t\t\tprojectId,\n\t\t\t\t\t{\n\t\t\t\t\t\tcolumns: projectColumns,\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t\tsubprojectCollection: transaction.getCollection(\n\t\t\t\t\t'Subproject',\n\t\t\t\t\t{\n\t\t\t\t\t\tparent: {\n\t\t\t\t\t\t\titemType: 'Project',\n\t\t\t\t\t\t\titemId: projectId,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tcolumns: subprojectColumns,\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t\tclientResource: transaction.getItemById(\n\t\t\t\t\t'Contact',\n\t\t\t\t\tclientId,\n\t\t\t\t\t{\n\t\t\t\t\t\tcolumns: clientColumns,\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t},\n\t\t);\n\n\t\tconst subprojectItems = result.subprojectCollection.items;\n\t\tconst clientValues = result.clientResource.fields;\n\n\t\tlet key;\n\t\tlet fieldName;\n\n\t\tfor (const subprojectItemResource of subprojectItems) {\n\t\t\tfor (key in fieldMap.Subproject) {\n\t\t\t\tfieldName = fieldMap.Subproject[key];\n\n\t\t\t\tif (\n\t\t\t\t\tkey === 'verzekering'\n\t\t\t\t\t&& !clientValues.verzekering_aangepast\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\tkey === 'taxschema'\n\t\t\t\t\t&& clientValues.taxschema === null\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (subprojectItemResource.fields[fieldName] !== clientValues[key]) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (key in fieldMap.Project) {\n\t\t\tfieldName = fieldMap.Project[key];\n\n\t\t\tif (\n\t\t\t\tkey === 'factuurmoment'\n\t\t\t\t&& clientValues[key] === null\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tclientValues[key] !== null\n\t\t\t\t&& result.projectResource.fields[fieldName] !== clientValues[key]\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tprivate setValues (\n\t\titemResource: Dependency[number]['projectResource'] | Dependency[number]['subprojectCollection']['items'][number],\n\t\tclientValues: Dependency[number]['clientResource']['fields'],\n\t\tchangesDelta: ChangesDelta,\n\t): ChangesDelta {\n\t\tconst itemType = itemResource.entry.itemType;\n\t\tconst fieldNames = fieldMap[itemType];\n\t\tconst updatedFields = {};\n\n\t\tfor (const key in fieldNames) {\n\t\t\tconst fieldName = fieldNames[key];\n\n\t\t\tif (\n\t\t\t\t(\n\t\t\t\t\tkey === 'factuurmoment' || key === 'taxschema'\n\t\t\t\t) && clientValues[key] === null\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tkey === 'verzekering'\n\t\t\t\t&& !clientValues.verzekering_aangepast\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tupdatedFields[fieldName] = clientValues[key];\n\t\t}\n\n\t\treturn changesDelta.setItemUpdated(\n\t\t\titemResource.entry as ItemEntry,\n\t\t\tupdatedFields,\n\t\t);\n\t}\n\n}\n\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { Template } from '../../../models/Template';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { KeyService } from '../../KeyService';\nimport { promiseAllObject } from '../../Util';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = {\n\tprojectId: ItemId,\n\tupdatedContactIds: Set<ItemId>,\n}[];\n\ntype Dependency = {\n\ttemplate: Template<'Projectnotitie'>,\n\tprojectTuples: {\n\t\tprojectId: ItemId,\n\t\tContact: ItemResource<'Contact', ['projectnotitie_naam', 'projectnotitie']>[],\n\t\tProjectnotitie: ItemResource<'Projectnotitie', ['naam', 'omschrijving']>[],\n\t}[],\n};\n\nconst contactFields = [\n\t'opdrachtgever',\n\t'locatie',\n] as const;\n\n@businessLogicRule(\n\t'ProjectContactProjectNoteBusinessLogicRule',\n)\nexport class ProjectContactProjectNoteBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\tconst updatedIterator = context.previousChangesDelta.getUpdatedTuplesIterator(\n\t\t\t'Project',\n\t\t);\n\t\tconst result: ConditionResult = [];\n\n\t\tfor (const tuple of updatedIterator) {\n\t\t\tconst updatedContactIds = contactFields.reduce(\n\t\t\t\t(\n\t\t\t\t\taccumulator,\n\t\t\t\t\tcolumnId,\n\t\t\t\t) => {\n\t\t\t\t\tconst fieldChangedResult = context.fieldChanged(\n\t\t\t\t\t\ttuple,\n\t\t\t\t\t\tcolumnId,\n\t\t\t\t\t);\n\n\t\t\t\t\tif (\n\t\t\t\t\t\tfieldChangedResult !== null\n\t\t\t\t\t\t&& fieldChangedResult.newValue !== null\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn accumulator.add(\n\t\t\t\t\t\t\tfieldChangedResult.newValue,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn accumulator;\n\t\t\t\t},\n\t\t\t\tnew Set<ItemId>(),\n\t\t\t);\n\n\t\t\tif (updatedContactIds.size > 0) {\n\t\t\t\tresult.push(\n\t\t\t\t\t{\n\t\t\t\t\t\tprojectId: tuple.entry.itemId,\n\t\t\t\t\t\tupdatedContactIds,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn result.length > 0\n\t\t\t? result\n\t\t\t: BLR_SKIP_RULE;\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\tconditionResult: ConditionResult,\n\t): Promise<Dependency> {\n\t\tconst projectTuples = Promise.all(\n\t\t\tconditionResult.map(\n\t\t\t\tprojectIdTuple => promiseAllObject(\n\t\t\t\t\t{\n\t\t\t\t\t\tprojectId: projectIdTuple.projectId,\n\t\t\t\t\t\tContact: transaction.getItemsById(\n\t\t\t\t\t\t\t'Contact',\n\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t...projectIdTuple.updatedContactIds,\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\t\t\t'projectnotitie_naam',\n\t\t\t\t\t\t\t\t\t'projectnotitie',\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t),\n\t\t\t\t\t\tProjectnotitie: transaction.getItemsByQuery(\n\t\t\t\t\t\t\t'Projectnotitie',\n\t\t\t\t\t\t\t{},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// Use the `parent` property to generate the same query as used in the notes widget.\n\t\t\t\t\t\t\t\t// Query will already be cached.\n\t\t\t\t\t\t\t\tparent: {\n\t\t\t\t\t\t\t\t\titemType: 'Project',\n\t\t\t\t\t\t\t\t\titemId: projectIdTuple.projectId,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\t\t\t'naam',\n\t\t\t\t\t\t\t\t\t'omschrijving',\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t),\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\n\t\treturn promiseAllObject(\n\t\t\t{\n\t\t\t\ttemplate: transaction.core.templateCache.fetchTemplate(\n\t\t\t\t\t'Projectnotitie',\n\t\t\t\t),\n\t\t\t\tprojectTuples,\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tdependency: Dependency,\n\t): void {\n\t\tfor (const projectTuple of dependency.projectTuples) {\n\t\t\tfor (const contactResource of projectTuple.Contact) {\n\t\t\t\tconst {\n\t\t\t\t\tprojectnotitie_naam: name,\n\t\t\t\t\tprojectnotitie: body,\n\t\t\t\t} = contactResource.fields;\n\n\t\t\t\tif (name.length === 0 && body.length === 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// We assume if the name and desc of the notes are identical we don't create a new one\n\t\t\t\tif (\n\t\t\t\t\tprojectTuple.Projectnotitie.some(\n\t\t\t\t\t\tprojectNoteResource => projectNoteResource.fields.naam === name && projectNoteResource.fields.omschrijving === body,\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tcontext.destinationChangesDelta._setItemCreated(\n\t\t\t\t\tKeyService.getLocalId(),\n\t\t\t\t\t{\n\t\t\t\t\t\t...dependency.template.getFields(),\n\t\t\t\t\t\tnaam: name,\n\t\t\t\t\t\tomschrijving: body,\n\t\t\t\t\t\tproject: projectTuple.projectId,\n\t\t\t\t\t},\n\t\t\t\t\tdependency.template.getMainColumnSet(),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { promiseAllObject } from '../../Util';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = ItemId[];\n\ntype Dependency = {\n\t[projectId: number]: {\n\t\tsubprojectResources: ItemResource<'Subproject', ['id', 'locatie',]>[],\n\t\tprojectResource: ItemResource<'Project', ['id', 'locatie', 'locatie_persoon']>,\n\t},\n};\n\n/**\n * @description\n * Whenever the location of a Project changes in a one-sub (Project with no subprojects)\n * we ensure the `locatie` & 'locatie_persoon` field gets applied on the Subproject too\n *\n * * Has similar opposite Business Rule for Subprojects {@link SubprojectOneSubLocationAlignBusinessLogicRule}\n */\n@businessLogicRule(\n\t'ProjectOneSubLocationAlignBusinessLogicRule',\n)\nexport class ProjectOneSubLocationAlignBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\treturn context.getItemIdsWithUpdatedField(\n\t\t\t'Project',\n\t\t\t'locatie',\n\t\t);\n\t}\n\n\tpublic dependency (\n\t\ttransaction: TransactionCache,\n\t\tobj: ConditionResult,\n\t): Promise<Dependency> {\n\t\tconst promises = {};\n\n\t\tfor (const projectId of obj) {\n\t\t\tpromises[projectId] = promiseAllObject(\n\t\t\t\t{\n\t\t\t\t\tsubprojectResources: transaction.getItemsByQuery(\n\t\t\t\t\t\t'Subproject',\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tproject: projectId,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\t\t'id',\n\t\t\t\t\t\t\t\t'locatie',\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t},\n\t\t\t\t\t),\n\t\t\t\t\tprojectResource: transaction.getItemById(\n\t\t\t\t\t\t'Project',\n\t\t\t\t\t\tprojectId,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\t\t'id',\n\t\t\t\t\t\t\t\t'locatie',\n\t\t\t\t\t\t\t\t'locatie_persoon',\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t},\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\treturn promiseAllObject(\n\t\t\tpromises,\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tobj: Dependency,\n\t): void {\n\t\tfor (const projectId in obj) {\n\t\t\tif (obj[projectId].subprojectResources.length !== 1) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst projectLocatieValue = context.getLatestValue(\n\t\t\t\tobj[projectId].projectResource.entry,\n\t\t\t\t'locatie',\n\t\t\t);\n\n\t\t\tconst subprojectLocatieValue = context.getLatestValue(\n\t\t\t\tobj[projectId].subprojectResources[0].entry,\n\t\t\t\t'locatie',\n\t\t\t);\n\n\t\t\tif (projectLocatieValue === subprojectLocatieValue) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tcontext.setItemUpdated(\n\t\t\t\tobj[projectId].subprojectResources[0].entry,\n\t\t\t\t{\n\t\t\t\t\tlocatie: projectLocatieValue,\n\t\t\t\t\tlocatie_persoon: context.mergedChangesDelta.getUpdatedValue(\n\t\t\t\t\t\tobj[projectId].projectResource.entry,\n\t\t\t\t\t\t'locatie_persoon',\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemEntry } from '../../../models/ItemEntry';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = {\n\tProject: ItemId[],\n\tSubproject: ItemId[],\n};\n\ntype Dependency = {\n\tproject: ItemResource<'Project', typeof projectColumns>[],\n\tsubproject: ItemResource<'Subproject', typeof projectColumns>[],\n};\n\nconst projectColumns = [\n\t'gebruiksperiode',\n\t'planperiode',\n\t'transport_pickup',\n\t'transport_return',\n] as const;\n\n/**\n * @description\n * Whenever you set a new default time on a project or subproject we make sure the same time isn't used\n * multiple times (except for gebruik/plan)\n */\n@businessLogicRule(\n\t'ProjectSubprojectDefaultTimeBusinessLogicRule',\n)\nexport class ProjectSubprojectDefaultTimeBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\t{\n\t\t\tpreviousChangesDelta,\n\t\t}: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\tconst updatedIterator = previousChangesDelta.getUpdatedTuplesIterator(\n\t\t\t'Project',\n\t\t\t'Subproject',\n\t\t);\n\t\tconst result: ConditionResult = {\n\t\t\tProject: [],\n\t\t\tSubproject: [],\n\t\t};\n\n\t\tlet hasValues: boolean = false;\n\n\t\tfor (const tuple of updatedIterator) {\n\t\t\tfor (const columnId of projectColumns) {\n\t\t\t\tif (\n\t\t\t\t\t!previousChangesDelta.getUpdatedValue(\n\t\t\t\t\t\ttuple.entry,\n\t\t\t\t\t\tcolumnId,\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\t// If the value is `null` (reset) or `undefined` (not set) then we skip processing\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\thasValues = true;\n\n\t\t\t\tresult[tuple.entry.itemType].push(\n\t\t\t\t\ttuple.entry.itemId,\n\t\t\t\t);\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (!hasValues) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\titemIdMap: ConditionResult,\n\t): Promise<Dependency> {\n\t\tconst [\n\t\t\tproject,\n\t\t\tsubproject,\n\t\t] = await Promise.all(\n\t\t\t[\n\t\t\t\ttransaction.getItemsById(\n\t\t\t\t\t'Project',\n\t\t\t\t\titemIdMap.Project,\n\t\t\t\t\t{\n\t\t\t\t\t\tcolumns: projectColumns,\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t\ttransaction.getItemsById(\n\t\t\t\t\t'Subproject',\n\t\t\t\t\titemIdMap.Subproject,\n\t\t\t\t\t{\n\t\t\t\t\t\tcolumns: projectColumns,\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t],\n\t\t);\n\n\t\treturn {\n\t\t\tproject: project,\n\t\t\tsubproject: subproject,\n\t\t};\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tdep: Dependency,\n\t): void {\n\t\tconst allProjects = [\n\t\t\t...dep.project,\n\t\t\t...dep.subproject,\n\t\t];\n\n\t\tfor (const projectResource of allProjects) {\n\t\t\tfor (const columnId of projectColumns) {\n\t\t\t\tconst newValue = context.mergedChangesDelta.getUpdatedValue(\n\t\t\t\t\tprojectResource.entry as ItemEntry,\n\t\t\t\t\tcolumnId,\n\t\t\t\t);\n\n\t\t\t\tif (!newValue) {\n\t\t\t\t\t// If the value is `undefined` it means it didn't change so no need to process\n\t\t\t\t\t// If theh value is `null` it has been reset and we also don't need to process\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tfor (const columnIdToReset of projectColumns) {\n\t\t\t\t\tif (columnIdToReset === columnId) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst fieldValue = context.getLatestValue(\n\t\t\t\t\t\tprojectResource.entry as ItemEntry,\n\t\t\t\t\t\tcolumnIdToReset,\n\t\t\t\t\t);\n\n\t\t\t\t\tif (fieldValue === newValue) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\tcolumnIdToReset === 'planperiode'\n\t\t\t\t\t\t\t\t&& columnId === 'gebruiksperiode'\n\t\t\t\t\t\t\t) || (\n\t\t\t\t\t\t\t\tcolumnIdToReset === 'gebruiksperiode'\n\t\t\t\t\t\t\t\t&& columnId === 'planperiode'\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t// Plan and usage periods are allowed to be the same\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcontext.setItemUpdated(\n\t\t\t\t\t\t\tprojectResource.entry as ItemEntry,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t[columnIdToReset]: null,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { ApiRequestColumnArray } from '../../../types/ItemTypesCollection';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\nconst purchaseOrderColumns = [\n\t'approval_status',\n\t'previous_status',\n] as const satisfies ApiRequestColumnArray<'PurchaseOrder'>;\n\ntype ConditionResult = ItemId<'PurchaseOrder'>[];\n\ntype Dependency = ItemResource<'PurchaseOrder', typeof purchaseOrderColumns>[];\n\n/**\n * @description\n * When the `approval_status` updates we want to update `previous_status` accordingly\n */\n@businessLogicRule(\n\t'PurchaseOrderApprovalStatusBusinessLogicRule',\n)\nexport class PurchaseOrderApprovalStatusBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\treturn context.getItemIdsWithUpdatedField(\n\t\t\t'PurchaseOrder',\n\t\t\t'approval_status',\n\t\t);\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\tpurchaseOrderIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\treturn transaction.getItemsById(\n\t\t\t'PurchaseOrder',\n\t\t\tpurchaseOrderIds,\n\t\t\t{\n\t\t\t\tcolumns: purchaseOrderColumns,\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tpurchaseOrderResources: Dependency,\n\t): void {\n\t\tfor (const purchaseOrderResource of purchaseOrderResources) {\n\t\t\tcontext.setUpdatedValue(\n\t\t\t\tpurchaseOrderResource.entry,\n\t\t\t\t'previous_status',\n\t\t\t\t// This intentionally uses the resource and not latest value\n\t\t\t\tpurchaseOrderResource.fields.approval_status,\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = ItemId[];\ntype Dependency = void;\n\n/**\n * @description\n * Whenever the item has a changed owner\n * pop-up a modal to ensure the user of the consequences they might face when doing that.\n */\n@businessLogicRule(\n\t'PurchaseOrderOwnerBusinessLogicRule',\n)\nexport class PurchaseOrderOwnerBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\treturn context.getItemIdsWithUpdatedField(\n\t\t\t'PurchaseOrder',\n\t\t\t'owner',\n\t\t);\n\t}\n\n\tpublic async dependency (): Promise<Dependency> {\n\t\treturn Promise.resolve();\n\t}\n\n\t// We need this BLR for the FE to notify the user with a modal that changes will have consequences\n\tpublic apply (): void {\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = Set<ItemId>;\n\ntype Dependency = ItemResource<'Rate', ['rate_group', 'active', 'id']>[];\n\n@businessLogicRule(\n\t'RateUpdatedBusinessLogicRule',\n)\nexport class RateUpdatedBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\tconst updatedGroups: Set<ItemId> = new Set<ItemId>();\n\n\t\tcontext.previousChangesDelta.created.forEachOfItemType(\n\t\t\t'Rate',\n\t\t\trate => {\n\t\t\t\tif (rate.fields.rate_group !== 0) {\n\t\t\t\t\tupdatedGroups.add(\n\t\t\t\t\t\trate.fields.rate_group,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\n\t\tif (updatedGroups.size === 0) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn updatedGroups;\n\t}\n\n\tpublic dependency (\n\t\ttransaction: TransactionCache,\n\t\tupdatedGroups: ConditionResult,\n\t): Promise<Dependency> {\n\t\treturn transaction.getItemsByQuery(\n\t\t\t'Rate',\n\t\t\t{\n\t\t\t\tconditions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: 'rate_group',\n\t\t\t\t\t\tcomparator: 'IN',\n\t\t\t\t\t\tvalue: [\n\t\t\t\t\t\t\t...updatedGroups,\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tactive: true,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\toperator: 'AND',\n\t\t\t},\n\t\t\t{\n\t\t\t\tcolumns: [\n\t\t\t\t\t'rate_group',\n\t\t\t\t\t'active',\n\t\t\t\t\t'id',\n\t\t\t\t],\n\t\t\t\tpreventCaching: true,\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tdependency: Dependency,\n\t): void {\n\t\tfor (const rate of dependency) {\n\t\t\tcontext.setItemUpdated(\n\t\t\t\trate.entry,\n\t\t\t\t{\n\t\t\t\t\tactive: false,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = ItemId[];\n\ntype Dependency = ItemResource<'Reparatie', ['aantal']>[];\n\n@businessLogicRule(\n\t'ReparatiesExemplaarAantalBusinessLogicRule',\n)\nexport class ReparatiesExemplaarAantalBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\t{\n\t\t\tpreviousChangesDelta,\n\t\t}: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\tconst updatedIterator = previousChangesDelta.getUpdatedTuplesIterator(\n\t\t\t'Reparatie',\n\t\t);\n\t\tconst result: ItemId[] = [];\n\n\t\tfor (const tuple of updatedIterator) {\n\t\t\tconst newValue = previousChangesDelta.getUpdatedValue(\n\t\t\t\ttuple.entry,\n\t\t\t\t'exemplaar',\n\t\t\t);\n\n\t\t\tif (\n\t\t\t\tnewValue !== undefined\n\t\t\t\t&& newValue !== null\n\t\t\t) {\n\t\t\t\tresult.push(\n\t\t\t\t\ttuple.entry.itemId,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (result.length === 0) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\treparatieIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\treturn transaction.getItemsById(\n\t\t\t'Reparatie',\n\t\t\treparatieIds,\n\t\t\t{\n\t\t\t\tcolumns: [\n\t\t\t\t\t'aantal',\n\t\t\t\t],\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\treparatieResources: Dependency,\n\t): void {\n\t\tfor (const reparatieResource of reparatieResources) {\n\t\t\tcontext.setItemUpdated(\n\t\t\t\treparatieResource.entry,\n\t\t\t\t{\n\t\t\t\t\taantal: 1,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemEntry } from '../../../models/ItemEntry';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = {\n\tentry: ItemEntry<'Reparatie' | 'MateriaalLost'>,\n\texemplaar: ItemId,\n}[];\n\ntype Dependency = {\n\tentries: ItemEntry<'Reparatie' | 'MateriaalLost'>[],\n\texemplaarResources: ItemResource<'Exemplaar', ['id', 'asset_location']>[],\n};\n\n@businessLogicRule(\n\t'ReparatieLostItemExemplaarLocationBusinessLogicRule',\n)\nexport class ReparatieLostItemExemplaarLocationBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\t{\n\t\t\tpreviousChangesDelta,\n\t\t}: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\tconst updatedIterator = previousChangesDelta.getUpdatedTuplesIterator(\n\t\t\t'Reparatie',\n\t\t\t'MateriaalLost',\n\t\t);\n\t\tconst result: ConditionResult = [];\n\n\t\tfor (const tuple of updatedIterator) {\n\t\t\tconst newValue = previousChangesDelta.getUpdatedValue(\n\t\t\t\ttuple.entry,\n\t\t\t\t'exemplaar',\n\t\t\t);\n\n\t\t\tif (\n\t\t\t\tnewValue !== undefined\n\t\t\t\t&& newValue !== null\n\t\t\t) {\n\t\t\t\tresult.push(\n\t\t\t\t\t{\n\t\t\t\t\t\tentry: tuple.entry,\n\t\t\t\t\t\texemplaar: newValue,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (result.length === 0) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\tconditionResult: ConditionResult,\n\t): Promise<Dependency> {\n\t\treturn {\n\t\t\tentries: conditionResult.map(\n\t\t\t\tresult => result.entry,\n\t\t\t),\n\t\t\texemplaarResources: await transaction.getItemsById(\n\t\t\t\t'Exemplaar',\n\t\t\t\tArray.from(\n\t\t\t\t\tnew Set(\n\t\t\t\t\t\tconditionResult.map(\n\t\t\t\t\t\t\tresult => result.exemplaar,\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\t{\n\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t'id',\n\t\t\t\t\t\t'asset_location',\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t),\n\t\t};\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tdependency: Dependency,\n\t): void {\n\t\tfor (const entry of dependency.entries) {\n\t\t\tconst exemplaarId = context.mergedChangesDelta.getUpdatedValue(\n\t\t\t\tentry,\n\t\t\t\t'exemplaar',\n\t\t\t);\n\n\t\t\tconst exemplaarResource = dependency.exemplaarResources.find(\n\t\t\t\tresource => resource.fields.id === exemplaarId,\n\t\t\t);\n\n\t\t\tif (exemplaarResource === undefined) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Exemplaar ${exemplaarId} linked to Repair/MateriaalLost ${entry.itemId} does not exist`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tcontext.setItemUpdated(\n\t\t\t\tentry,\n\t\t\t\t{\n\t\t\t\t\tasset_location: exemplaarResource.fields.asset_location,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = ItemId[];\n\ntype Dependency = ItemResource<'Rol', [\n\t'general_eigen_medewerker_edit',\n]>[];\n\n/**\n * @description\n * If you can access update crew data, you can also always update your own data\n */\n@businessLogicRule(\n\t'RolEditOwnDataBusinessLogicRule',\n)\nexport class RolEditOwnDataBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\t{\n\t\t\tpreviousChangesDelta,\n\t\t}: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\tconst updatedIterator = previousChangesDelta.getUpdatedTuplesIterator(\n\t\t\t'Rol',\n\t\t);\n\t\tconst result: ItemId[] = [];\n\n\t\tfor (const tuple of updatedIterator) {\n\t\t\tconst newValue = previousChangesDelta.getUpdatedValue(\n\t\t\t\ttuple.entry,\n\t\t\t\t'medewerkers_rechten',\n\t\t\t);\n\n\t\t\tif (\n\t\t\t\t(\n\t\t\t\t\tnewValue !== undefined\n\t\t\t\t\t&& newValue !== 'read'\n\t\t\t\t)\n\t\t\t\t|| previousChangesDelta.getUpdatedValue(\n\t\t\t\t\ttuple.entry,\n\t\t\t\t\t'medewerkers_toegang',\n\t\t\t\t) === true\n\t\t\t) {\n\t\t\t\tresult.push(\n\t\t\t\t\ttuple.entry.itemId,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (result.length === 0) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\trolIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\treturn transaction.getItemsById(\n\t\t\t'Rol',\n\t\t\trolIds,\n\t\t\t{\n\t\t\t\tcolumns: [\n\t\t\t\t\t'general_eigen_medewerker_edit',\n\t\t\t\t],\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\trolResources: Dependency,\n\t): void {\n\t\tfor (const rolResource of rolResources) {\n\t\t\tcontext.setItemUpdated(\n\t\t\t\trolResource.entry,\n\t\t\t\t{\n\t\t\t\t\tgeneral_eigen_medewerker_edit: true,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { ApiRequestColumnArray } from '../../../types/ItemTypesCollection';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = ItemId[];\n\nconst rolColumns = [\n\t'facturen_eigen',\n\t'general_bestanden_downloaden',\n\t'facturen_toegang',\n\t'projecten_offertes_maken',\n\t'projecten_facturen_maken',\n] as const satisfies ApiRequestColumnArray<'Rol'>;\n\ntype Dependency = ItemResource<'Rol', typeof rolColumns>[];\n\n/**\n * @description\n * If you have project access or can make invoices you should have permissions to download files, see invoices and edit invoices\n */\n@businessLogicRule(\n\t'RolFileAccessBusinessLogicRule',\n)\nexport class RolFileAccessBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\t{\n\t\t\tpreviousChangesDelta,\n\t\t}: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\tconst updatedIterator = previousChangesDelta.getUpdatedTuplesIterator(\n\t\t\t'Rol',\n\t\t);\n\t\tconst result: ItemId[] = [];\n\n\t\tfor (const tuple of updatedIterator) {\n\t\t\tif (\n\t\t\t\tpreviousChangesDelta.getUpdatedValue(\n\t\t\t\t\ttuple.entry,\n\t\t\t\t\t'projecten_facturen_maken',\n\t\t\t\t) === true\n\t\t\t\t|| previousChangesDelta.getUpdatedValue(\n\t\t\t\t\ttuple.entry,\n\t\t\t\t\t'projecten_offertes_maken',\n\t\t\t\t) === true\n\t\t\t) {\n\t\t\t\tresult.push(\n\t\t\t\t\ttuple.entry.itemId,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (result.length === 0) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\trolIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\treturn transaction.getItemsById(\n\t\t\t'Rol',\n\t\t\trolIds,\n\t\t\t{\n\t\t\t\tcolumns: rolColumns,\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\trolResources: Dependency,\n\t): void {\n\t\tfor (const rolResource of rolResources) {\n\t\t\tconst canCreateInvoices = context.getLatestValue(\n\t\t\t\trolResource.entry,\n\t\t\t\t'projecten_facturen_maken',\n\t\t\t);\n\n\t\t\tconst canCreateQuotes = context.getLatestValue(\n\t\t\t\trolResource.entry,\n\t\t\t\t'projecten_offertes_maken',\n\t\t\t);\n\n\t\t\tif (\n\t\t\t\t!canCreateInvoices\n\t\t\t\t&& !canCreateQuotes\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tcontext.setItemUpdated(\n\t\t\t\trolResource.entry,\n\t\t\t\t{\n\t\t\t\t\tgeneral_bestanden_downloaden: 'all',\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tif (canCreateInvoices) {\n\t\t\t\tconst ownInvoicesPermission = context.getLatestValue(\n\t\t\t\t\trolResource.entry,\n\t\t\t\t\t'facturen_eigen',\n\t\t\t\t);\n\n\t\t\t\tcontext.setItemUpdated(\n\t\t\t\t\trolResource.entry,\n\t\t\t\t\t{\n\t\t\t\t\t\tfacturen_toegang: true,\n\t\t\t\t\t\tfacturen_eigen: ownInvoicesPermission === 'read'\n\t\t\t\t\t\t\t? 'write'\n\t\t\t\t\t\t\t: ownInvoicesPermission,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = ItemId[];\n\ntype Dependency = ItemResource<'Rol', [\n\t'projecten_toegang',\n]>[];\n\n/**\n * @description\n * \tIf you can enter the crew planner you can also access projects\n */\n@businessLogicRule(\n\t'RolPersoneelsplannerToegangBusinessLogicRule',\n)\nexport class RolPersoneelsplannerToegangBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\treturn context.getItemIdsWithFieldUpdatedTo(\n\t\t\t'Rol',\n\t\t\t'personeelsplanner_toegang',\n\t\t\ttrue,\n\t\t);\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\trolIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\treturn transaction.getItemsById(\n\t\t\t'Rol',\n\t\t\trolIds,\n\t\t\t{\n\t\t\t\tcolumns: [\n\t\t\t\t\t'projecten_toegang',\n\t\t\t\t] as const,\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\trolResources: Dependency,\n\t): void {\n\t\tfor (const rolResource of rolResources) {\n\t\t\tcontext.setItemUpdated(\n\t\t\t\trolResource.entry,\n\t\t\t\t{\n\t\t\t\t\tprojecten_toegang: true,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = ItemId[];\n\ntype Dependency = ItemResource<'Rol', [\n\t'materialen_tijdlijn',\n]>[];\n\n/**\n * @description\n * If you can edit projects you should be able to see the equipment availability\n */\n@businessLogicRule(\n\t'RolProjectenBewerkenBusinessLogicRule',\n)\nexport class RolProjectenBewerkenBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\t{\n\t\t\tpreviousChangesDelta,\n\t\t}: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\tconst updatedIterator = previousChangesDelta.getUpdatedTuplesIterator(\n\t\t\t'Rol',\n\t\t);\n\t\tconst result: ItemId[] = [];\n\n\t\tfor (const tuple of updatedIterator) {\n\t\t\tconst newValue = previousChangesDelta.getUpdatedValue(\n\t\t\t\ttuple.entry,\n\t\t\t\t'projecten_bewerken',\n\t\t\t);\n\n\t\t\tif (\n\t\t\t\tnewValue !== undefined\n\t\t\t\t&& newValue !== 'no'\n\t\t\t) {\n\t\t\t\tresult.push(\n\t\t\t\t\ttuple.entry.itemId,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (result.length === 0) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\trolIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\treturn transaction.getItemsById(\n\t\t\t'Rol',\n\t\t\trolIds,\n\t\t\t{\n\t\t\t\tcolumns: [\n\t\t\t\t\t'materialen_tijdlijn',\n\t\t\t\t],\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\trolResources: Dependency,\n\t): void {\n\t\tfor (const rolResource of rolResources) {\n\t\t\tcontext.setItemUpdated(\n\t\t\t\trolResource.entry,\n\t\t\t\t{\n\t\t\t\t\tmaterialen_tijdlijn: 'projects',\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = ItemId[];\n\ntype Dependency = ItemResource<'Rol', [\n\t'uren_kosten',\n\t'visibility_financials',\n]>[];\n\n/**\n * @description\n * \tIf you have access to projects you should be able to make costs for registered hours\n */\n@businessLogicRule(\n\t'RolProjectenToegangBusinessLogicRule',\n)\nexport class RolProjectenToegangBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\treturn context.getItemIdsWithFieldUpdatedTo(\n\t\t\t'Rol',\n\t\t\t'projecten_toegang',\n\t\t\ttrue,\n\t\t);\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\trolIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\treturn transaction.getItemsById(\n\t\t\t'Rol',\n\t\t\trolIds,\n\t\t\t{\n\t\t\t\tcolumns: [\n\t\t\t\t\t'uren_kosten',\n\t\t\t\t\t'visibility_financials',\n\t\t\t\t],\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\trolResources: Dependency,\n\t): void {\n\t\tfor (const rolResource of rolResources) {\n\t\t\t// The visibility_financials permission trumps the projecten_toegang permission for uren_kosten.\n\t\t\t// If you're not allowed to see financials, you shouldn't see the hourly cost as well\n\t\t\tif (rolResource.fields.visibility_financials === false) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tcontext.setItemUpdated(\n\t\t\t\trolResource.entry,\n\t\t\t\t{\n\t\t\t\t\turen_kosten: true,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { ApiRequestColumnArray } from '../../../types/ItemTypesCollection';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = ItemId[];\n\nconst roleColumns = [\n\t'purchaseorders_edit',\n] as const satisfies ApiRequestColumnArray<'Rol'>;\n\ntype Dependency = ItemResource<'Rol', typeof roleColumns>[];\n\n/**\n * @description\n * \tYou can only have the right to attach crew plannings to purchase orders if you can edit all purchase orders\n */\n@businessLogicRule(\n\t'RolPurchaseOrderAttachPlanningBusinessLogicRule',\n)\nexport class RolPurchaseOrderAttachPlanningBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\t{\n\t\t\tpreviousChangesDelta,\n\t\t}: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\tconst updatedIterator = previousChangesDelta.getUpdatedTuplesIterator(\n\t\t\t'Rol',\n\t\t);\n\t\tconst result: ItemId[] = [];\n\n\t\tfor (const tuple of updatedIterator) {\n\t\t\tconst newValue = previousChangesDelta.getUpdatedValue(\n\t\t\t\ttuple.entry,\n\t\t\t\t'purchaseorders_edit',\n\t\t\t);\n\n\t\t\tif (\n\t\t\t\tnewValue !== undefined\n\t\t\t\t&& newValue !== 'all'\n\t\t\t) {\n\t\t\t\tresult.push(\n\t\t\t\t\ttuple.entry.itemId,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (result.length === 0) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\trolIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\treturn transaction.getItemsById(\n\t\t\t'Rol',\n\t\t\trolIds,\n\t\t\t{\n\t\t\t\tcolumns: roleColumns,\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\trolResources: Dependency,\n\t): void {\n\t\tfor (const rolResource of rolResources) {\n\t\t\tcontext.setItemUpdated(\n\t\t\t\trolResource.entry,\n\t\t\t\t{\n\t\t\t\t\tpurchaseorders_attach_crew_plannings: false,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = ItemId[];\n\ntype Dependency = ItemResource<'Rol', [\n\t'visibility_financials',\n\t'facturen_toegang',\n\t'projecten_facturen_maken',\n\t'projecten_offertes_maken',\n\t'projecten_toegang',\n]>[];\n\n/**\n * @description\n * If you're not allowed to see financials, then you should not have the permission to\n * 1. access the invoices module\n * 2. create invoices, quotes and contracts in projects\n * 3. see rates of crew members in activities in the time registration.\n */\n@businessLogicRule(\n\t'RolVisibilityFinancialsBusinessLogicRule',\n)\nexport class RolVisibilityFinancialsBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\treturn context.getItemIdsWithUpdatedField(\n\t\t\t'Rol',\n\t\t\t'visibility_financials',\n\t\t);\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\trolIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\treturn transaction.getItemsById(\n\t\t\t'Rol',\n\t\t\trolIds,\n\t\t\t{\n\t\t\t\tcolumns: [\n\t\t\t\t\t'visibility_financials',\n\t\t\t\t\t'facturen_toegang',\n\t\t\t\t\t'projecten_facturen_maken',\n\t\t\t\t\t'projecten_offertes_maken',\n\t\t\t\t\t'projecten_toegang',\n\t\t\t\t],\n\t\t\t},\n\t\t);\n\t}\n\n\t/**\n\t * If the financial visibility is turned off:\n\t *\n\t * all financial related permissions should be off as well\n\t * with the exception of \"uren_kosten\", which can be set independently from financial visibility.\n\t *\n\t *\n\t */\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\trolResources: Dependency,\n\t): void {\n\t\tfor (const rolResource of rolResources) {\n\t\t\tconst hasFinancialsVisibility = context.mergedChangesDelta.getUpdatedValue(\n\t\t\t\trolResource.entry,\n\t\t\t\t'visibility_financials',\n\t\t\t);\n\n\t\t\tif (hasFinancialsVisibility === false) {\n\t\t\t\tcontext.setItemUpdated(\n\t\t\t\t\trolResource.entry,\n\t\t\t\t\t{\n\t\t\t\t\t\tprojecten_facturen_maken: false,\n\t\t\t\t\t\tprojecten_offertes_maken: false,\n\t\t\t\t\t\tfacturen_toegang: false,\n\t\t\t\t\t},\n\t\t\t\t);\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst projectenFacturenMakenValue = context.getLatestValue(\n\t\t\t\trolResource.entry,\n\t\t\t\t'projecten_facturen_maken',\n\t\t\t);\n\n\t\t\tif (projectenFacturenMakenValue === true) {\n\t\t\t\tcontext.setItemUpdated(\n\t\t\t\t\trolResource.entry,\n\t\t\t\t\t{\n\t\t\t\t\t\tfacturen_toegang: true,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { ApiRequestColumnArray } from '../../../types/ItemTypesCollection';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = ItemId[];\n\ntype Dependency = ItemResource<'Rol', [\n\t'magazijn_toegang',\n]>[];\n\n/**\n * @description\n * \tIf you can enter access the Warehouse Tracking Log, you can also access Warehouse module\n */\n@businessLogicRule(\n\t'RolWarehouseTrackingLogAccessBusinessLogicRule',\n)\nexport class RolWarehouseTrackingLogAccessBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\treturn context.getItemIdsWithFieldUpdatedTo(\n\t\t\t'Rol',\n\t\t\t'warehouse_trackinglog_access',\n\t\t\ttrue,\n\t\t);\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\troldIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\treturn transaction.getItemsById(\n\t\t\t'Rol',\n\t\t\troldIds,\n\t\t\t{\n\t\t\t\tcolumns: [\n\t\t\t\t\t'magazijn_toegang',\n\t\t\t\t] as const satisfies ApiRequestColumnArray<'Rol'>,\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\trolResources: Dependency,\n\t): void {\n\t\tfor (const rolResource of rolResources) {\n\t\t\tcontext.setItemUpdated(\n\t\t\t\trolResource.entry,\n\t\t\t\t{\n\t\t\t\t\tmagazijn_toegang: true,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ItemResource } from '../../../models/ItemResource';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { ChangesDeltaItemCreateDelta } from '../../CreatedChangesDelta';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\nconst materiaalColumns = [\n\t'id',\n\t'type',\n] as const;\n\ntype ConditionResult = ChangesDeltaItemCreateDelta<'Setinhoud'>[];\ntype Dependency = Record<string, ItemResource<'Materiaal', typeof materiaalColumns>>;\n\n/**\n * Legacy users won't have the `FUNCTIONALITY_FLEXIBLE_COMBINATION_IN_PLANNING` flag, meaning the `is_fixed` column from `Setinhoud` column isn't editable\n * With this business rule we enforce the correct (default) value based on the equipment properties (Backend enforces this as well)\n *\n * For users with the flag this just sets a default value in the same way, but `is_fixed` is editable after it has been created\n */\n@businessLogicRule(\n\t'SetinhoudCreateFixedBusinessLogicRule',\n)\nexport class SetinhoudCreateFixedBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\tconst result: ConditionResult = [];\n\n\t\tcontext.previousChangesDelta.created.forEachOfItemType(\n\t\t\t'Setinhoud',\n\t\t\ttuple => {\n\t\t\t\tif (tuple.fields.package !== undefined) {\n\t\t\t\t\tresult.push(\n\t\t\t\t\t\ttuple,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\n\t\tif (result.length === 0) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\tconditionResult: ConditionResult,\n\t): Promise<Dependency> {\n\t\treturn (\n\t\t\tawait transaction.getItemsById(\n\t\t\t\t'Materiaal',\n\t\t\t\tArray.from(\n\t\t\t\t\tnew Set(\n\t\t\t\t\t\tconditionResult.map(\n\t\t\t\t\t\t\tcreateTuple => createTuple.fields.package,\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\t{\n\t\t\t\t\tcolumns: materiaalColumns,\n\t\t\t\t},\n\t\t\t)\n\t\t).reduce(\n\t\t\t(\n\t\t\t\tacc,\n\t\t\t\tmateriaalResource,\n\t\t\t) => {\n\t\t\t\tacc[materiaalResource.fields.id] = materiaalResource;\n\n\t\t\t\treturn acc;\n\t\t\t},\n\t\t\t{},\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tdependencyResult: Dependency,\n\t\tconditionResult: ConditionResult,\n\t): void {\n\t\tfor (const createTuple of conditionResult) {\n\t\t\tconst materiaalResource = dependencyResult[createTuple.fields.package];\n\n\t\t\tconst equipmentIsCombination = context.getLatestValue(\n\t\t\t\tmateriaalResource.entry,\n\t\t\t\t'is_combination',\n\t\t\t);\n\n\t\t\tconst equipmentIsPhysical = context.getLatestValue(\n\t\t\t\tmateriaalResource.entry,\n\t\t\t\t'is_physical',\n\t\t\t);\n\n\t\t\tconst shouldBeFixed = equipmentIsCombination && equipmentIsPhysical;\n\n\t\t\tif (shouldBeFixed === createTuple.fields.is_fixed) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tcontext.destinationChangesDelta._setItemCreated(\n\t\t\t\tcreateTuple.itemId,\n\t\t\t\t{\n\t\t\t\t\tis_fixed: shouldBeFixed,\n\t\t\t\t},\n\t\t\t\tcreateTuple.columns,\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemEntry } from '../../../models/ItemEntry';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\nconst setinhoudColumns = [\n\t'is_fixed',\n\t{\n\t\tpackage: [\n\t\t\t'type',\n\t\t],\n\t},\n] as const;\n\ntype ConditionResult = {\n\tMateriaal: ItemId<'Materiaal'>[],\n\tSetinhoud: ItemId<'Setinhoud'>[],\n};\n\ntype Dependency = ItemResource<'Setinhoud', typeof setinhoudColumns>[];\n\n/**\n * For legacy users we have to keep track of the correct value based on the equipment properties,\n * similarly to when creating a new `Setinhoud`, see {@link SetinhoudCreateFixedBusinessLogicRule}\n *\n * For normal users the `is_fixed` column is editable, so we don't have to update it\n */\n@businessLogicRule(\n\t'SetinhoudUpdateFixedBusinessLogicRule',\n)\nexport class SetinhoudUpdateFixedBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\t{\n\t\t\tpreviousChangesDelta,\n\t\t}: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\tif (\n\t\t\t// We only want to enforce this business rule for legacy users. Read the class description\n\t\t\tthis.hasFlag(\n\t\t\t\t'FUNCTIONALITY_FLEXIBLE_COMBINATION_IN_PLANNING',\n\t\t\t)\n\t\t) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\tconst updatedIterator = previousChangesDelta.getUpdatedTuplesIterator(\n\t\t\t'Materiaal',\n\t\t\t'Setinhoud',\n\t\t);\n\n\t\tconst result: ConditionResult = {\n\t\t\tMateriaal: [],\n\t\t\tSetinhoud: [],\n\t\t};\n\n\t\tfor (const tuple of updatedIterator) {\n\t\t\tif (\n\t\t\t\ttuple.entry.itemType === 'Materiaal'\n\t\t\t\t&& (\n\t\t\t\t\tpreviousChangesDelta.hasUpdatedValue(\n\t\t\t\t\t\t(tuple.entry as ItemEntry<'Materiaal'>),\n\t\t\t\t\t\t'is_physical',\n\t\t\t\t\t)\n\t\t\t\t\t|| previousChangesDelta.hasUpdatedValue(\n\t\t\t\t\t\t(tuple.entry as ItemEntry<'Materiaal'>),\n\t\t\t\t\t\t'is_combination',\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tresult.Materiaal.push(\n\t\t\t\t\ttuple.entry.itemId,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\ttuple.entry.itemType === 'Setinhoud'\n\t\t\t\t&& previousChangesDelta.hasUpdatedValue(\n\t\t\t\t\t(tuple.entry as ItemEntry<'Setinhoud'>),\n\t\t\t\t\t'is_fixed',\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tresult.Setinhoud.push(\n\t\t\t\t\ttuple.entry.itemId,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (\n\t\t\tresult.Materiaal.length === 0\n\t\t\t&& result.Setinhoud.length === 0\n\t\t) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\tconditionResult: ConditionResult,\n\t): Promise<Dependency> {\n\t\tconst [\n\t\t\tupdatedSetinhoudResources,\n\t\t\tmateriaalsSetinhoudResources,\n\t\t] = await Promise.all(\n\t\t\t[\n\t\t\t\tconditionResult.Setinhoud.length > 0\n\t\t\t\t\t? transaction.getItemsById(\n\t\t\t\t\t\t'Setinhoud',\n\t\t\t\t\t\tconditionResult.Setinhoud,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcolumns: setinhoudColumns,\n\t\t\t\t\t\t},\n\t\t\t\t\t)\n\t\t\t\t\t: [] as Dependency,\n\t\t\t\tconditionResult.Materiaal.length > 0\n\t\t\t\t\t? transaction.getItemsByQuery(\n\t\t\t\t\t\t'Setinhoud',\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tpackage: conditionResult.Materiaal,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcolumns: setinhoudColumns,\n\t\t\t\t\t\t},\n\t\t\t\t\t)\n\t\t\t\t\t: [] as Dependency,\n\t\t\t],\n\t\t);\n\n\t\treturn [\n\t\t\t...updatedSetinhoudResources,\n\t\t\t...materiaalsSetinhoudResources.filter(\n\t\t\t\tmateriaalSetinhoudResource => updatedSetinhoudResources.find(\n\t\t\t\t\tupdatedSetinhoudResource => materiaalSetinhoudResource.entry.id !== updatedSetinhoudResource.entry.id,\n\t\t\t\t) === undefined,\n\t\t\t),\n\t\t];\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tsetinhoudResources: Dependency,\n\t): void {\n\t\tfor (const setinhoudResource of setinhoudResources) {\n\t\t\tconst equipmentId = context.getLatestValue(\n\t\t\t\tsetinhoudResource.entry,\n\t\t\t\t'package',\n\t\t\t);\n\n\t\t\tif (equipmentId === undefined) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst equipmentItemEntry = context.transaction.getLocalItemEntryByItemId(\n\t\t\t\t'Materiaal',\n\t\t\t\tequipmentId,\n\t\t\t);\n\n\t\t\tconst materiaalIsPhysical = context.getLatestValue(\n\t\t\t\tequipmentItemEntry,\n\t\t\t\t'is_physical',\n\t\t\t);\n\n\t\t\tconst materiaalIsCombination = context.getLatestValue(\n\t\t\t\tequipmentItemEntry,\n\t\t\t\t'is_combination',\n\t\t\t);\n\n\t\t\tconst isFixedValue = context.getLatestValue(\n\t\t\t\tsetinhoudResource.entry,\n\t\t\t\t'is_fixed',\n\t\t\t);\n\n\t\t\tconst shouldBeFixed = materiaalIsPhysical && materiaalIsCombination;\n\n\t\t\tif (shouldBeFixed === isFixedValue) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tcontext.setItemUpdated(\n\t\t\t\tsetinhoudResource.entry,\n\t\t\t\t{\n\t\t\t\t\tis_fixed: shouldBeFixed,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { BLR_SKIP_RULE, businessLogicRule, BusinessLogicRule, BusinessLogicRuleApplyContext, BusinessLogicRuleConditionContext, FieldMap, ItemResource, TransactionCache } from '../../../internal';\n\ntype Dependency = Map<\n\tItemId<'Subproject'>,\n\tItemResource<'Functie', ['subproject', 'inplanning']>[]\n>;\n\ntype ConditionResult = Map<ItemId<'Subproject'>, boolean>;\n\n/**\n * Whenever the 'inplanning' field of a subproject changes, set the 'inplanning' field of all functions in the\n * subproject to the same value.\n */\n@businessLogicRule(\n\t'SubprojectInPlanningBusinessLogicRule',\n)\nexport class SubprojectInPlanningBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic override condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\tconst updatedTuplesIterator = context.previousChangesDelta.getUpdatedTuplesIterator(\n\t\t\t'Subproject',\n\t\t);\n\t\tconst result: ConditionResult = new Map();\n\n\t\tfor (const updatedTuple of updatedTuplesIterator) {\n\t\t\tconst updatedValue = context.previousChangesDelta.getUpdatedValue(\n\t\t\t\tupdatedTuple.entry,\n\t\t\t\t'inplanning',\n\t\t\t);\n\n\t\t\tif (updatedValue === undefined) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tresult.set(\n\t\t\t\tupdatedTuple.entry.itemId,\n\t\t\t\tupdatedValue,\n\t\t\t);\n\t\t}\n\n\t\treturn result.size > 0\n\t\t\t? result\n\t\t\t: BLR_SKIP_RULE;\n\t}\n\n\tpublic override async dependency (\n\t\ttransaction: TransactionCache,\n\t\tsubprojectInPlanningMap: ConditionResult,\n\t): Promise<Dependency> {\n\t\tconst subprojectResources = await transaction.getItemsById(\n\t\t\t'Subproject',\n\t\t\t[\n\t\t\t\t...subprojectInPlanningMap.keys(),\n\t\t\t],\n\t\t\t{\n\t\t\t\tcolumns: [\n\t\t\t\t\t'project',\n\t\t\t\t],\n\t\t\t},\n\t\t);\n\n\t\tconst projectId = subprojectResources[0].fields.project;\n\n\t\tfor (let i = 1; i < subprojectResources.length; i++) {\n\t\t\tif (subprojectResources[i].fields.project !== projectId) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t'SubprojectInPlanningBusinessLogicRuleBase: unexpected change of multiple projects',\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// We're fetching all the functions in the project because the data is likely to be cached already.\n\t\tconst projectFunctionResources = await transaction.getItemsByQuery(\n\t\t\t'Functie',\n\t\t\t{},\n\t\t\t{\n\t\t\t\tparent: {\n\t\t\t\t\titemType: 'Project',\n\t\t\t\t\titemId: projectId,\n\t\t\t\t},\n\t\t\t\tcolumns: [\n\t\t\t\t\t'subproject',\n\t\t\t\t\t'inplanning',\n\t\t\t\t],\n\t\t\t},\n\t\t);\n\n\t\tconst result: Dependency = new Map();\n\n\t\tfor (const subprojectId of subprojectInPlanningMap.keys()) {\n\t\t\tresult.set(\n\t\t\t\tsubprojectId,\n\t\t\t\t[],\n\t\t\t);\n\t\t}\n\n\t\tfor (const functionResource of projectFunctionResources) {\n\t\t\tresult\n\t\t\t\t.get(\n\t\t\t\t\tfunctionResource.fields.subproject,\n\t\t\t\t)\n\t\t\t\t?.push(\n\t\t\t\t\tfunctionResource,\n\t\t\t\t);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic override apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tsubprojectFunctionResourceMap: Dependency,\n\t\tsubprojectInPlanningMap: ConditionResult,\n\t): void {\n\t\tfor (const functionMapEntry of subprojectFunctionResourceMap.entries()) {\n\t\t\tconst fields: FieldMap<'Functie', ['inplanning']> = {\n\t\t\t\tinplanning: subprojectInPlanningMap.get(\n\t\t\t\t\tfunctionMapEntry[0],\n\t\t\t\t)!,\n\t\t\t};\n\n\t\t\tfor (const functionResource of functionMapEntry[1]) {\n\t\t\t\tcontext.setItemUpdated(\n\t\t\t\t\tfunctionResource.entry,\n\t\t\t\t\tfields,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { promiseAllObject } from '../../Util';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = ItemId[];\n\ntype Dependency = {\n\t[projectId: number]: {\n\t\tSubproject: ItemResource<'Subproject', ['id', 'project', 'locatie', 'locatie_persoon']>,\n\t\tProject: ItemResource<'Project', ['id', 'locatie']>,\n\t\tamountOfSubprojects: number,\n\t},\n};\n\n/**\n * @description\n * Whenever the location of a Subproject changes in a one-sub (Project with no subprojects)\n * we ensure the `locatie` & 'locatie_persoon` field gets applied on the Project too\n *\n * Has similar opposite Business Rule for Projects {@link ProjectOneSubLocationAlignBusinessLogicRule}\n */\n@businessLogicRule(\n\t'SubprojectOneSubLocationAlignBusinessLogicRule',\n)\nexport class SubprojectOneSubLocationAlignBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\treturn context.getItemIdsWithUpdatedField(\n\t\t\t'Subproject',\n\t\t\t'locatie',\n\t\t);\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\tobj: ConditionResult,\n\t): Promise<Dependency> {\n\t\tconst promises = {};\n\n\t\tfor (const subprojectId of obj) {\n\t\t\tconst subprojectResource: Dependency[number]['Subproject'] = await transaction.getItemById(\n\t\t\t\t'Subproject',\n\t\t\t\tsubprojectId,\n\t\t\t\t{\n\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t'id',\n\t\t\t\t\t\t'project',\n\t\t\t\t\t\t'locatie',\n\t\t\t\t\t\t'locatie_persoon',\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tconst projectId: ItemId = subprojectResource.fields.project;\n\n\t\t\tif (promises[projectId] === undefined) {\n\t\t\t\tpromises[projectId] = {};\n\t\t\t}\n\n\t\t\tpromises[projectId].Subproject = subprojectResource;\n\n\t\t\tpromises[projectId].Project = await transaction.getItemById(\n\t\t\t\t'Project',\n\t\t\t\tprojectId,\n\t\t\t\t{\n\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t'id',\n\t\t\t\t\t\t'locatie',\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tconst allSubprojectResources = await transaction.getItemsByQuery(\n\t\t\t\t'Subproject',\n\t\t\t\t{\n\t\t\t\t\tproject: projectId,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t'id',\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tpromises[projectId].amountOfSubprojects = allSubprojectResources.length;\n\t\t}\n\n\t\treturn promiseAllObject(\n\t\t\tpromises,\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tobj: Dependency,\n\t): void {\n\t\tfor (const projectId in obj) {\n\t\t\tif (obj[projectId].amountOfSubprojects !== 1) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst subprojectLocatieValue = context.getLatestValue(\n\t\t\t\tobj[projectId].Subproject.entry,\n\t\t\t\t'locatie',\n\t\t\t);\n\n\t\t\tconst projectLocatieValue = context.getLatestValue(\n\t\t\t\tobj[projectId].Project.entry,\n\t\t\t\t'locatie',\n\t\t\t);\n\n\t\t\tif (subprojectLocatieValue === projectLocatieValue) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tcontext.setItemUpdated(\n\t\t\t\tobj[projectId].Project.entry,\n\t\t\t\t{\n\t\t\t\t\tlocatie: subprojectLocatieValue,\n\t\t\t\t\tlocatie_persoon: context.mergedChangesDelta.getUpdatedValue(\n\t\t\t\t\t\tobj[projectId].Subproject.entry,\n\t\t\t\t\t\t'locatie_persoon',\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { promiseAllObject } from '../../Util';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = ItemId[];\n\ntype Dependency = {\n\tprojectResource: ItemResource<'Project', ['id', 'naam']>,\n\tsubprojectResources: ItemResource<'Subproject', ['id', 'project', 'naam']>[],\n}[];\n\n/**\n * @description\n * Whenever the name of a subproject changes in a one-sub (Project with no subprojects) we ensure the name field gets\n * applied to the project too.\n */\n@businessLogicRule(\n\t'SubprojectOneSubNameAlignBusinessLogicRule',\n)\nexport class SubprojectOneSubNameAlignBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\treturn context.getItemIdsWithUpdatedField(\n\t\t\t'Project',\n\t\t\t'naam',\n\t\t);\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\tprojectIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\treturn Promise.all(\n\t\t\tprojectIds.map(\n\t\t\t\tprojectId => promiseAllObject(\n\t\t\t\t\t{\n\t\t\t\t\t\tprojectResource: transaction.getItemById(\n\t\t\t\t\t\t\t'Project',\n\t\t\t\t\t\t\tprojectId,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\t\t\t'id',\n\t\t\t\t\t\t\t\t\t'naam',\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t),\n\t\t\t\t\t\tsubprojectResources: transaction.getItemsByQuery(\n\t\t\t\t\t\t\t'Subproject',\n\t\t\t\t\t\t\t{},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tparent: {\n\t\t\t\t\t\t\t\t\titemType: 'Project',\n\t\t\t\t\t\t\t\t\titemId: projectId,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\t\t\t'id',\n\t\t\t\t\t\t\t\t\t'naam',\n\t\t\t\t\t\t\t\t\t'project',\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t),\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tprojectTuples: Dependency,\n\t): void {\n\t\tfor (const projectTuple of projectTuples) {\n\t\t\tif (projectTuple.subprojectResources.length !== 1) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst projectNameValue = context.getLatestValue(\n\t\t\t\tprojectTuple.projectResource.entry,\n\t\t\t\t'naam',\n\t\t\t);\n\n\t\t\tif (\n\t\t\t\tprojectNameValue === context.getLatestValue(\n\t\t\t\t\tprojectTuple.subprojectResources[0].entry,\n\t\t\t\t\t'naam',\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tcontext.setItemUpdated(\n\t\t\t\tprojectTuple.subprojectResources[0].entry,\n\t\t\t\t{\n\t\t\t\t\tnaam: projectNameValue,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ItemResource } from '../../../models/ItemResource';\nimport { TransactionCache } from '../../cache/transaction/TransactionCache';\nimport { BLR_SKIP_RULE, BusinessLogicRule } from '../BusinessLogicRule';\nimport { businessLogicRule } from '../businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from '../BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from '../BusinessLogicRuleConditionContext';\n\ntype ConditionResult = ItemId[];\n\ntype Dependency = {\n\ttijdResource: ItemResource<'Tijd', ['naam', 'id']>,\n\tfunctiegroepResource: ItemResource<'Functiegroep', ['naam']>,\n}[];\n\n/**\n * @description\n * If the 'naam' of the Tijd item changes, update function groups with the same name connected to this Tijd item\n */\n@businessLogicRule(\n\t'TijdNameChangedBusinessLogicRule',\n)\nexport class TijdNameChangedBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\treturn context.getItemIdsWithUpdatedField(\n\t\t\t'Tijd',\n\t\t\t'naam',\n\t\t);\n\t}\n\n\tpublic async dependency (\n\t\ttransaction: TransactionCache,\n\t\ttijdIds: ConditionResult,\n\t): Promise<Dependency> {\n\t\tconst tijdItems = await transaction.getItemsById(\n\t\t\t'Tijd',\n\t\t\ttijdIds,\n\t\t\t{\n\t\t\t\tcolumns: [\n\t\t\t\t\t'id',\n\t\t\t\t\t'naam',\n\t\t\t\t],\n\t\t\t},\n\t\t);\n\n\t\tconst functiegroepen = await transaction.getItemsByQuery(\n\t\t\t'Functiegroep',\n\t\t\t{\n\t\t\t\tconditions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: 'schema_pv',\n\t\t\t\t\t\tcomparator: 'IN',\n\t\t\t\t\t\tvalue: tijdIds,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: 'schema_pt',\n\t\t\t\t\t\tcomparator: 'IN',\n\t\t\t\t\t\tvalue: tijdIds,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: 'schema_gv',\n\t\t\t\t\t\tcomparator: 'IN',\n\t\t\t\t\t\tvalue: tijdIds,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: 'schema_gt',\n\t\t\t\t\t\tcomparator: 'IN',\n\t\t\t\t\t\tvalue: tijdIds,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\toperator: 'OR',\n\t\t\t},\n\t\t\t{\n\t\t\t\tcolumns: [\n\t\t\t\t\t'schema_pv',\n\t\t\t\t\t'schema_gv',\n\t\t\t\t\t'schema_pt',\n\t\t\t\t\t'schema_gt',\n\t\t\t\t\t'naam',\n\t\t\t\t],\n\t\t\t},\n\t\t);\n\n\t\tconst dependencyResult: Dependency = [];\n\n\t\tfor (const tijd of tijdItems) {\n\t\t\tconst tijdId = tijd.fields.id;\n\n\t\t\tconst functiegroepItems = functiegroepen.filter(\n\t\t\t\tfunctiegroep => (\n\t\t\t\t\tfunctiegroep.fields.schema_pv === tijdId\n\t\t\t\t\t&& functiegroep.fields.schema_gv === tijdId\n\t\t\t\t\t&& functiegroep.fields.schema_pt === tijdId\n\t\t\t\t\t&& functiegroep.fields.schema_gt === tijdId\n\t\t\t\t\t&& functiegroep.fields.naam === tijd.fields.naam\n\t\t\t\t),\n\t\t\t);\n\n\t\t\tdependencyResult.push(\n\t\t\t\t...functiegroepItems.map(\n\t\t\t\t\tfunctieGroep => (\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttijdResource: tijd,\n\t\t\t\t\t\t\tfunctiegroepResource: functieGroep,\n\t\t\t\t\t\t}\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\treturn dependencyResult;\n\t}\n\n\tpublic apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\ttijdFunctiegroepTuples: Dependency,\n\t): void {\n\t\tfor (const tuple of tijdFunctiegroepTuples) {\n\t\t\tcontext.setItemUpdated(\n\t\t\t\ttuple.functiegroepResource.entry,\n\t\t\t\t{\n\t\t\t\t\tnaam: context.getLatestValue(\n\t\t\t\t\t\ttuple.tijdResource.entry,\n\t\t\t\t\t\t'naam',\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\n\n}\n","import { ItemId } from '@rentman/backend-types';\nimport { ApiRequestColumnArray, BLR_SKIP_RULE, BusinessLogicConditionResult, BusinessLogicRule, businessLogicRule, BusinessLogicRuleApplyContext, BusinessLogicRuleConditionContext, CollectionResource, ItemResource, TransactionCache } from '../../../internal';\n\nconst projectDefaultTimeColumns = [\n\t'id',\n\t'gebruiksperiode',\n\t'planperiode',\n] as const satisfies ApiRequestColumnArray<'Project' | 'Subproject'>;\n\ntype ConditionResult = BusinessLogicConditionResult<'Tijd', 'subproject'>[];\n\ntype Dependency = ItemResource<\n\t'Project',\n\ttypeof projectDefaultTimeColumns,\n\t{\n\t\tSubproject: CollectionResource<'Subproject', typeof projectDefaultTimeColumns>,\n\t}\n>;\n\n/**\n * When moving a time to a subproject, if the default times of the main project and any subprojects\n * other than the destination subproject refer to the time, set them to `null`. We need to check all subprojects\n * because the time might be originating from the main project.\n */\n@businessLogicRule(\n\t'TijdSubprojectChangedBusinessLogicRule',\n)\nexport class TijdSubprojectChangedBusinessLogicRule\n\textends BusinessLogicRule<ConditionResult, Dependency> {\n\n\tpublic override condition (\n\t\tcontext: BusinessLogicRuleConditionContext,\n\t): ConditionResult | typeof BLR_SKIP_RULE {\n\t\tconst updatedIterator = context.previousChangesDelta.getUpdatedTuplesIterator(\n\t\t\t'Tijd',\n\t\t);\n\t\tconst result: BusinessLogicConditionResult<'Tijd', 'subproject'>[] = [];\n\n\t\tfor (const tuple of updatedIterator) {\n\t\t\tconst conditionResult = context.fieldChanged(\n\t\t\t\ttuple,\n\t\t\t\t'subproject',\n\t\t\t);\n\n\t\t\tif (\n\t\t\t\tconditionResult === null\n\t\t\t\t// If we're moving the time to the main project, there's no need to act.\n\t\t\t\t|| conditionResult.newValue === null\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tresult.push(\n\t\t\t\tconditionResult,\n\t\t\t);\n\t\t}\n\n\t\tif (result.length === 0) {\n\t\t\treturn BLR_SKIP_RULE;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic override async dependency (\n\t\ttransaction: TransactionCache,\n\t\ttimeItemChanges: ConditionResult,\n\t): Promise<Dependency> {\n\t\tconst timeResources = await transaction.getItemsById(\n\t\t\t'Tijd',\n\t\t\ttimeItemChanges.map(\n\t\t\t\ttimeItemChange => timeItemChange.itemEntry.itemId,\n\t\t\t),\n\t\t\t{\n\t\t\t\tcolumns: [\n\t\t\t\t\t'project',\n\t\t\t\t],\n\t\t\t},\n\t\t);\n\t\tconst projectItemIds = timeResources.reduce(\n\t\t\t(\n\t\t\t\taccumulator,\n\t\t\t\ttimeResource,\n\t\t\t) => accumulator.add(\n\t\t\t\ttimeResource.fields.project,\n\t\t\t),\n\t\t\tnew Set<ItemId>(),\n\t\t);\n\n\t\tif (projectItemIds.size > 1) {\n\t\t\tthrow new Error(\n\t\t\t\t'Updating times of multiple projects currently unsupported',\n\t\t\t);\n\t\t}\n\n\t\treturn transaction.getItemById(\n\t\t\t'Project',\n\t\t\t[\n\t\t\t\t...projectItemIds,\n\t\t\t][0],\n\t\t\t{\n\t\t\t\tcolumns: projectDefaultTimeColumns,\n\t\t\t\tchildren: {\n\t\t\t\t\tSubproject: {\n\t\t\t\t\t\tcolumns: projectDefaultTimeColumns,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic override apply (\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t\tprojectResource: Dependency,\n\t\ttimeItemChanges: ConditionResult,\n\t): void {\n\t\tfor (const timeItemChange of timeItemChanges) {\n\t\t\tfor (const defaultTimeColumnId of projectDefaultTimeColumns) {\n\t\t\t\tconst timeItemId = timeItemChange.itemEntry.itemId;\n\n\t\t\t\tif (\n\t\t\t\t\tcontext.getLatestValue(\n\t\t\t\t\t\tprojectResource.entry,\n\t\t\t\t\t\tdefaultTimeColumnId,\n\t\t\t\t\t) === timeItemId\n\t\t\t\t) {\n\t\t\t\t\tcontext.setItemUpdated(\n\t\t\t\t\t\tprojectResource.entry,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t[defaultTimeColumnId]: null,\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tfor (const subprojectResource of projectResource.children.Subproject.items) {\n\t\t\t\t\tif (\n\t\t\t\t\t\ttimeItemChange.newValue !== subprojectResource.fields.id\n\t\t\t\t\t\t&& context.getLatestValue(\n\t\t\t\t\t\t\tsubprojectResource.entry,\n\t\t\t\t\t\t\tdefaultTimeColumnId,\n\t\t\t\t\t\t) === timeItemId\n\t\t\t\t\t) {\n\t\t\t\t\t\tcontext.setItemUpdated(\n\t\t\t\t\t\t\tsubprojectResource.entry,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t[defaultTimeColumnId]: null,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n}\n","import { AfspraakRecureindBusinessLogicRule } from './Afspraak/AfspraakRecureindBusinessLogicRule';\nimport { BeschikbaarheidRecureindBusinessLogicRule } from './Beschikbaarheid/BeschikbaarheidRecureindBusinessLogicRule';\nimport { ContactAddressBusinessLogicRule } from './Contact/ContactAddressBusinessLogicRule';\nimport { CustomFieldLinkedItemTypeBusinessLogicRule } from './Customfield/CustomFieldLinkedItemTypeBusinessLogicRule';\nimport { CustomFieldTypeBusinessLogicRule } from './Customfield/CustomFieldTypeBusinessLogicRule';\nimport { DefaultContactPersonUpdateBusinessLogicRule } from './DefaultContactPersonUpdateBusinessLogicRule';\nimport { DocumentTemplateBusinessLogicRule } from './Documents/DocumentTemplateBusinessLogicRule';\nimport { ExemplaarAanschafdatumBusinessLogicRule } from './Exemplaar/ExemplaarAanschafdatumBusinessLogicRule';\nimport { ExemplaarBarcodeDeleteBusinessLogicRule } from './Exemplaar/ExemplaarBarcodeDeleteBusinessLogicRule';\nimport { FactuurBetalingsconditieBusinessLogicRule } from './Factuur/FactuurBetalingsconditieBusinessLogicRule';\nimport { FactuurDatumBusinessLogicRule } from './Factuur/FactuurDatumBusinessLogicRule';\nimport { FactuurNumberseriesBusinessLogicRule } from './Factuur/FactuurNumberseriesBusinessLogicRule';\nimport { FilesNameExtensionBusinessLogicRule } from './Files/FilesNameExtensionBusinessLogicRule';\nimport { FunctieNaaminternBusinessLogicRule } from './Functie/FunctieNaaminternBusinessLogicRule';\nimport { FunctieRecureindBusinessLogicRule } from './Functie/FunctieRecureindBusinessLogicRule';\nimport { FunctieTwowayBusinessLogicRule } from './Functie/FunctieTwowayBusinessLogicRule';\nimport { FunctiegroepSubprojectBusinessLogicRule } from './Functiegroep/FunctiegroepSubprojectBusinessLogicRule';\nimport { InhuurmateriaalAantalBusinessLogicRule } from './Inhuurmateriaal/InhuurmateriaalAantalBusinessLogicRule';\nimport { InhuurmateriaalAantaltotaalBusinessLogicRule } from './Inhuurmateriaal/InhuurmateriaalAantaltotaalBusinessLogicRule';\nimport { MateriaalBulkToSerialBusinessLogicRule } from './Materiaal/MateriaalBulkToSerialBusinessLogicRule';\nimport { MateriaalIsCombinationBusinessLogicRule } from './Materiaal/MateriaalIsCombinationBusinessLogicRule';\nimport { MateriaalIsPhysicalCombinationBulkBusinessLogicRule } from './Materiaal/MateriaalIsPhysicalCombinationBulkBusinessLogicRule';\nimport { MateriaalSerialToBulkBusinessLogicRule } from './Materiaal/MateriaalSerialToBulkBusinessLogicRule';\nimport { MateriaalToPhysicalBusinessLogicRule } from './Materiaal/MateriaalToPhysicalBusinessLogicRule';\nimport { MateriaalToVirtualBusinessLogicRule } from './Materiaal/MateriaalToVirtualBusinessLogicRule';\nimport { MateriaalTypePropertiesBusinessLogicRule } from './Materiaal/MateriaalTypePropertiesBusinessLogicRule';\nimport { MateriaalVerhuurBusinessLogicRule } from './Materiaal/MateriaalVerhuurBusinessLogicRule';\nimport { SurfaceArticleSizeBusinessLogicRule } from './Materiaal/SurfaceArticleSizeBusinessLogicRule';\nimport { LinkedTimeItemDurationBusinessLogicRule } from './MateriaalCatFunctieFunctiegroep/LinkedTimeItemDurationBusinessLogicRule';\nimport { LinkedTimeItemMateriaalCatBusinessLogicRule } from './MateriaalCatFunctieFunctiegroep/LinkedTimeItemMateriaalCatBusinessLogicRule';\nimport { LinkedTimeItemSubprojectBusinessLogicRule } from './MateriaalCatFunctieFunctiegroep/LinkedTimeItemSubprojectBusinessLogicRule';\nimport { LinkedTimeItemTimeSchemeBusinessLogicRule } from './MateriaalCatFunctieFunctiegroep/LinkedTimeItemTimeSchemeBusinessLogicRule';\nimport { LinkedTimeItemTimeSchemeStartBusinessLogicRule } from './MateriaalCatFunctieFunctiegroep/LinkedTimeItemTimeSchemeStartBusinessLogicRule';\nimport { LinkedTimeItemTimeValueStartBusinessLogicRule } from './MateriaalCatFunctieFunctiegroep/LinkedTimeItemTimeValueStartBusinessLogicRule';\nimport { OfferteContractDatumBusinessLogicRule } from './OfferteContract/OfferteContractDatumBusinessLogicRule';\nimport { PlanningmateriaalAantalBusinessLogicRule } from './Planningmateriaal/PlanningmateriaalAantalBusinessLogicRule';\nimport { PlanningmateriaalAantaltotaalBusinessLogicRule } from './Planningmateriaal/PlanningmateriaalAantaltotaalBusinessLogicRule';\nimport { PlanningmateriaalOptieBusinessLogicRule } from './Planningmateriaal/PlanningmateriaalOptieBusinessLogicRule';\nimport { PlanningmateriaalParentBusinessLogicRule } from './Planningmateriaal/PlanningmateriaalParentBusinessLogicRule';\nimport { PlanningmateriaalStaysAtLocationBusinessLogicRule } from './Planningmateriaal/PlanningmateriaalStaysAtLocationBusinessLogicRule';\nimport { PlanningPersoneelTransportBusinessLogicRule } from './PlanningPersoneelTransport/PlanningPersoneelTransportBusinessLogicRule';\nimport { ProjectClientChangedBusinessLogicRule } from './Project/ProjectClientChangedBusinessLogicRule';\nimport { ProjectContactProjectNoteBusinessLogicRule } from './Project/ProjectContactProjectNoteBusinessLogicRule';\nimport { ProjectOneSubLocationAlignBusinessLogicRule } from './Project/ProjectOneSubLocationAlignBusinessRule';\nimport { ProjectSubprojectDefaultTimeBusinessLogicRule } from './ProjectSubproject/ProjectSubprojectDefaultTimeBusinessLogicRule';\nimport { PurchaseOrderApprovalStatusBusinessLogicRule } from './PurchaseOrder/PurchaseOrderApprovalStatusBusinessLogicRule';\nimport { PurchaseOrderOwnerBusinessLogicRule } from './PurchaseOrder/PurchaseOrderOwnerBusinessLogicRule';\nimport { RateUpdatedBusinessLogicRule } from './Rate/RateUpdatedBusinessLogicRule';\nimport { ReparatiesExemplaarAantalBusinessLogicRule } from './Reparatie/ReparatieExemplaarAantalBusinessLogicRule';\nimport { ReparatieLostItemExemplaarLocationBusinessLogicRule } from './Reparatie/ReparatieLostItemExemplaarLocationBusinessLogicRule';\nimport { RolEditOwnDataBusinessLogicRule } from './Rol/RolEditOwnDataBusinessLogicRule';\nimport { RolFileAccessBusinessLogicRule } from './Rol/RolFileAccessBusinessLogicRule';\nimport { RolPersoneelsplannerToegangBusinessLogicRule } from './Rol/RolPersoneelsplannerToegangBusinessLogicRule';\nimport { RolProjectenBewerkenBusinessLogicRule } from './Rol/RolProjectenBewerkenBusinessLogicRule';\nimport { RolProjectenToegangBusinessLogicRule } from './Rol/RolProjectenToegangBusinessLogicRule';\nimport { RolPurchaseOrderAttachPlanningBusinessLogicRule } from './Rol/RolPurchaseOrderAttachPlanningBusinessLogicRule';\nimport { RolVisibilityFinancialsBusinessLogicRule } from './Rol/RolVisibilityFinancialsBusinessLogicRule';\nimport { RolWarehouseTrackingLogAccessBusinessLogicRule } from './Rol/RolWarehosueTrackingLogAccessBusinessLogicRule';\nimport { SetinhoudCreateFixedBusinessLogicRule } from './Setinhoud/SetinhoudCreateFixedBusinessLogicRule';\nimport { SetinhoudUpdateFixedBusinessLogicRule } from './Setinhoud/SetinhoudUpdateFixedBusinessLogicRule';\nimport { SubprojectInPlanningBusinessLogicRule } from './Subproject/SubprojectInPlanningBusinessLogicRule';\nimport { SubprojectOneSubLocationAlignBusinessLogicRule } from './Subproject/SubprojectOneSubLocationAlignBusinessRule';\nimport { SubprojectOneSubNameAlignBusinessLogicRule } from './Subproject/SubprojectOneSubNameAlignBusinessRule';\nimport { TijdNameChangedBusinessLogicRule } from './Tijd/TijdNameChangedBusinessLogicRule';\nimport { TijdSubprojectChangedBusinessLogicRule } from './Tijd/TijdSubprojectChangedBusinessLogicRule';\n\nexport const registeredBusinessLogicRules = [\n\tDefaultContactPersonUpdateBusinessLogicRule,\n\tContactAddressBusinessLogicRule,\n\tCustomFieldLinkedItemTypeBusinessLogicRule,\n\tCustomFieldTypeBusinessLogicRule,\n\n\tDocumentTemplateBusinessLogicRule,\n\n\tExemplaarAanschafdatumBusinessLogicRule,\n\tExemplaarBarcodeDeleteBusinessLogicRule,\n\n\tFactuurBetalingsconditieBusinessLogicRule,\n\tFactuurDatumBusinessLogicRule,\n\tFactuurNumberseriesBusinessLogicRule,\n\n\tFilesNameExtensionBusinessLogicRule,\n\tFunctieNaaminternBusinessLogicRule,\n\tFunctieTwowayBusinessLogicRule,\n\tFunctieRecureindBusinessLogicRule,\n\n\tFunctiegroepSubprojectBusinessLogicRule,\n\n\tInhuurmateriaalAantaltotaalBusinessLogicRule,\n\tInhuurmateriaalAantalBusinessLogicRule,\n\n\tMateriaalIsCombinationBusinessLogicRule,\n\tMateriaalIsPhysicalCombinationBulkBusinessLogicRule,\n\tMateriaalToVirtualBusinessLogicRule,\n\tMateriaalToPhysicalBusinessLogicRule,\n\tMateriaalBulkToSerialBusinessLogicRule,\n\tMateriaalSerialToBulkBusinessLogicRule,\n\tMateriaalTypePropertiesBusinessLogicRule,\n\tMateriaalVerhuurBusinessLogicRule,\n\tSurfaceArticleSizeBusinessLogicRule,\n\n\tLinkedTimeItemDurationBusinessLogicRule,\n\tLinkedTimeItemTimeSchemeBusinessLogicRule,\n\tLinkedTimeItemTimeSchemeStartBusinessLogicRule,\n\tLinkedTimeItemTimeValueStartBusinessLogicRule,\n\tLinkedTimeItemSubprojectBusinessLogicRule,\n\tLinkedTimeItemMateriaalCatBusinessLogicRule,\n\n\tOfferteContractDatumBusinessLogicRule,\n\n\tPlanningmateriaalAantalBusinessLogicRule,\n\tPlanningmateriaalAantaltotaalBusinessLogicRule,\n\tPlanningmateriaalOptieBusinessLogicRule,\n\tPlanningmateriaalParentBusinessLogicRule,\n\tPlanningmateriaalStaysAtLocationBusinessLogicRule,\n\n\tPlanningPersoneelTransportBusinessLogicRule,\n\n\tProjectClientChangedBusinessLogicRule,\n\tProjectContactProjectNoteBusinessLogicRule,\n\tProjectOneSubLocationAlignBusinessLogicRule,\n\n\tProjectSubprojectDefaultTimeBusinessLogicRule,\n\n\tPurchaseOrderOwnerBusinessLogicRule,\n\tPurchaseOrderApprovalStatusBusinessLogicRule,\n\n\tRateUpdatedBusinessLogicRule,\n\n\tReparatiesExemplaarAantalBusinessLogicRule,\n\tReparatieLostItemExemplaarLocationBusinessLogicRule,\n\n\tRolEditOwnDataBusinessLogicRule,\n\tRolFileAccessBusinessLogicRule,\n\tRolPersoneelsplannerToegangBusinessLogicRule,\n\tRolProjectenBewerkenBusinessLogicRule,\n\tRolProjectenToegangBusinessLogicRule,\n\tRolVisibilityFinancialsBusinessLogicRule,\n\tRolWarehouseTrackingLogAccessBusinessLogicRule,\n\tRolPurchaseOrderAttachPlanningBusinessLogicRule,\n\n\tSetinhoudCreateFixedBusinessLogicRule,\n\tSetinhoudUpdateFixedBusinessLogicRule,\n\n\tSubprojectOneSubLocationAlignBusinessLogicRule,\n\tSubprojectOneSubNameAlignBusinessLogicRule,\n\tSubprojectInPlanningBusinessLogicRule,\n\n\tTijdSubprojectChangedBusinessLogicRule,\n\tTijdNameChangedBusinessLogicRule,\n\n\tAfspraakRecureindBusinessLogicRule,\n\n\tBeschikbaarheidRecureindBusinessLogicRule,\n] as const;\n","import { ApiModuleFunctionResponse } from '@rentman/backend-types';\nimport { CriticalBusinessLogicRuleException } from '../../exceptions/CriticalBusinessLogicRuleException';\nimport { ErrorHandlerInterface } from '../../interfaces/ErrorHandlerInterface';\nimport { HasFlagFn } from '../../types/ItemTypesCollection';\nimport { TransactionCache } from '../cache/transaction/TransactionCache';\nimport { ChangesDelta } from '../ChangesDelta';\nimport { BLR_ABANDON_CHANGES, BLR_CONTINUE_WITH_DEFAULTS, BLR_SKIP_RULE, BusinessLogicRule, BusinessLogicRuleConditionConfirmFn, BusinessLogicRuleConfirmFnWithDependency, RuleConditionResultTuple, RuleDependencyResultTuple } from './BusinessLogicRule';\nimport { BusinessLogicRuleConstructor, BusinessLogicRuleConstructorName } from './businessLogicRule.decorator';\nimport { BusinessLogicRuleApplyContext } from './BusinessLogicRuleApplyContext';\nimport { BusinessLogicRuleConditionContext } from './BusinessLogicRuleConditionContext';\nimport { BusinessLogicRuleContextBase } from './BusinessLogicRuleContextBase';\nimport { registeredBusinessLogicRules } from './registeredBusinessLogicRules';\n\n/**\n * @description\n * The BusinessLogicManager is responsible for calling all business rules with a ChangesDelta and storing their results for the {@link BusinessLogicRule business logic phases}.\n */\nexport class BusinessLogicManager {\n\n\tpublic constructor (\n\t\tprivate errorHandler: ErrorHandlerInterface,\n\t\t/**\n\t\t * We set the business logic rule instances using a constructor parameter to facilitate testing of combinations\n\t\t * of rules.\n\t\t */\n\t\tprivate readonly businessLogicRuleInstances: readonly BusinessLogicRule<any, any, any>[],\n\t) {\n\t}\n\n\tpublic static constructBusinessLogicRules (\n\t\tlocals: ApiModuleFunctionResponse<'locals', 'getLocals'>,\n\t\thasFlagFn: HasFlagFn,\n\t\tbusinessLogicRuleClasses: readonly BusinessLogicRuleConstructor[] = registeredBusinessLogicRules,\n\t): BusinessLogicRule<any, any, any>[] {\n\t\tconst result: BusinessLogicRule<any, any, any>[] = [];\n\n\t\tfor (const businessLogicRuleConstructor of businessLogicRuleClasses) {\n\t\t\tresult.push(\n\t\t\t\tnew businessLogicRuleConstructor(\n\t\t\t\t\tlocals,\n\t\t\t\t\thasFlagFn,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * @description\n\t * Allows the implementer to add a confirm function which is called after the condition of the business rule has fired\n\t * And before the dependency is fetched, preventing unnessesary dependecy calls\n\t * With this confirm the process can be aborted without applying the changes from the delta\n\t */\n\tpublic setBusinessLogicRuleConfirmation<BusinessLogicRuleType extends BusinessLogicRule<any, any, any>> (\n\t\tbusinessLogicRuleClass: BusinessLogicRuleConstructor<BusinessLogicRuleType>,\n\t\tconfirmFunction: BusinessLogicRuleType extends BusinessLogicRule<infer Condition, any, infer Options>\n\t\t\t? BusinessLogicRuleConditionConfirmFn<Condition, Options>\n\t\t\t: never,\n\t): void {\n\t\tconst businessLogicRule = this.findBusinessLogicRuleInstance(\n\t\t\tbusinessLogicRuleClass,\n\t\t);\n\n\t\tbusinessLogicRule.confirm = confirmFunction;\n\t}\n\n\t/**\n\t * @description\n\t * Allows the implementer to add a confirm function which is called after the dependency of the business rule is fetched\n\t * And before the apply step is fired.\n\t * With this confirm the process can be aborted without applying the changes from the delta\n\t */\n\tpublic setBusinessLogicRulePostDependencyConfirmation<BusinessLogicRuleType extends BusinessLogicRule<any, any, any>> (\n\t\tbusinessLogicRuleClass: BusinessLogicRuleConstructor<BusinessLogicRuleType>,\n\t\tconfirmFunction: BusinessLogicRuleType extends BusinessLogicRule<infer Condition, infer Dependency, infer Options>\n\t\t\t? BusinessLogicRuleConfirmFnWithDependency<Condition, Dependency, Options>\n\t\t\t: never,\n\t): void {\n\t\tconst businessLogicRule = this.findBusinessLogicRuleInstance(\n\t\t\tbusinessLogicRuleClass,\n\t\t);\n\n\t\tbusinessLogicRule.postDependencyConfirm = confirmFunction;\n\t}\n\n\t/**\n\t * @description\n\t * Handles the business logic for a given ChangesDelta. It will provide a *new* ChangesDelta on which the business\n\t * rules can apply their data, so that if new changes are made on *only those new changes* the business logic can be\n\t * run again.\n\t *\n\t * example:\n\t * - `Functie.twoway` changes the `Functie.afstand` field\n\t * - In a second iteration (recursive call) the `Functie.afstand` field updates `Functie.prijs`\n\t * (by doing `Functie.afstand` * `Functie.kilometerprijs`)\n\t * - In a third iteration (2nd recursive call) the `Functie.kilometerprijs` has no business logic, so the function\n\t * exits early (`rulesToRun.size === 0`) and the recursion ends\n\t *\n\t * @param transaction The transaction the ChangesDelta will be applied on\n\t * @param mergedChangesDelta - A changes delta containing the source changes, plus the changes made during *all*\n\t * previous rule application cycles.\n\t * @param previousChangesDelta - A changes delta containing source changes, *or* the changes made during the last\n\t * rule application cycle only. Should be used to determine whether the business logic rule should run.\n\t *\n\t * @private should only be called by the core\n\t */\n\tpublic async handleBusinessLogic (\n\t\t// We could also construct a BusinessLogicManager per transaction so we don't have to pass it\n\t\ttransaction: TransactionCache,\n\t\tmergedChangesDelta: ChangesDelta,\n\t\tpreviousChangesDelta: ChangesDelta = mergedChangesDelta,\n\t): Promise<ChangesDelta | null> {\n\t\tconst context = new BusinessLogicRuleConditionContext(\n\t\t\ttransaction,\n\t\t\tpreviousChangesDelta,\n\t\t\tmergedChangesDelta,\n\t\t\tthis.errorHandler,\n\t\t);\n\n\t\tconst ruleConditionResultTuples = await this.extractRulesToRun(\n\t\t\tcontext,\n\t\t);\n\n\t\tif (ruleConditionResultTuples === null) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst ruleDependencyResultTuples = await this.waitForRuleDependencies(\n\t\t\truleConditionResultTuples as RuleDependencyResultTuple[],\n\t\t\tcontext,\n\t\t);\n\n\t\tif (ruleDependencyResultTuples === null) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst destinationChangesDelta = transaction.createChangesDelta();\n\n\t\tthis.applyRules(\n\t\t\truleDependencyResultTuples,\n\t\t\tnew BusinessLogicRuleApplyContext(\n\t\t\t\ttransaction,\n\t\t\t\tpreviousChangesDelta,\n\t\t\t\tmergedChangesDelta,\n\t\t\t\tdestinationChangesDelta,\n\t\t\t),\n\t\t);\n\n\t\t// While running business logic rules, we can assume that changes in `previousChangesDelta` are also in\n\t\t// `mergedChangesDelta`.\n\t\tconst merged = mergedChangesDelta.merge(\n\t\t\tdestinationChangesDelta,\n\t\t);\n\n\t\tif (destinationChangesDelta.isEmpty()) {\n\t\t\treturn merged;\n\t\t}\n\n\t\t// We aren't stable yet so we have to handle the business logic for the newly changed fields\n\t\tconst childMerged = await this.handleBusinessLogic(\n\t\t\ttransaction,\n\t\t\t// We use the merged changesDelta here so it also contains the changes of previous ones\n\t\t\tmerged,\n\t\t\tdestinationChangesDelta,\n\t\t);\n\n\t\tif (childMerged === null) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn merged.merge(\n\t\t\tchildMerged,\n\t\t);\n\t}\n\n\tprivate findBusinessLogicRuleInstance<BusinessLogicRuleType extends BusinessLogicRule<any, any, any>> (\n\t\tbusinessLogicRuleClass: BusinessLogicRuleConstructor<BusinessLogicRuleType>,\n\t): BusinessLogicRule<any, any, any> {\n\t\tconst businessLogicRuleInstances = this.businessLogicRuleInstances.filter(\n\t\t\tinstance => instance instanceof businessLogicRuleClass,\n\t\t);\n\n\t\tif (businessLogicRuleInstances.length === 0) {\n\t\t\tthrow new Error(\n\t\t\t\t`BusinessLogicManager: Could not find instance of '${(businessLogicRuleClass as unknown as BusinessLogicRuleConstructorName).__name}'. Have you registered it?`,\n\t\t\t);\n\t\t}\n\n\t\tif (businessLogicRuleInstances.length > 1) {\n\t\t\tthrow new Error(\n\t\t\t\t`BusinessLogicManager: Multiple instances of '${(businessLogicRuleClass as unknown as BusinessLogicRuleConstructorName).__name}' found.`,\n\t\t\t);\n\t\t}\n\n\t\treturn businessLogicRuleInstances[0];\n\t}\n\n\tprivate applyRules (\n\t\truleApplyOptionsResultTuples: RuleDependencyResultTuple[],\n\t\tcontext: BusinessLogicRuleApplyContext,\n\t): void {\n\t\tfor (const ruleApplyOptionsResultTuple of ruleApplyOptionsResultTuples) {\n\t\t\ttry {\n\t\t\t\truleApplyOptionsResultTuple.ruleInstance.apply(\n\t\t\t\t\tcontext,\n\t\t\t\t\truleApplyOptionsResultTuple.dependencyResult,\n\t\t\t\t\truleApplyOptionsResultTuple.conditionResult,\n\t\t\t\t\truleApplyOptionsResultTuple.confirmResult === BLR_CONTINUE_WITH_DEFAULTS\n\t\t\t\t\t\t? undefined\n\t\t\t\t\t\t: ruleApplyOptionsResultTuple.confirmResult,\n\t\t\t\t);\n\t\t\t} catch (exception) {\n\t\t\t\tthis.errorHandler.logError(\n\t\t\t\t\texception,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async waitForRuleDependencies (\n\t\truleConditionResultTuples: RuleDependencyResultTuple[],\n\t\tcontext: BusinessLogicRuleContextBase,\n\t): Promise<RuleDependencyResultTuple[] | null> {\n\t\tconst ruleDependencyResults = await Promise.allSettled(\n\t\t\truleConditionResultTuples.map(\n\t\t\t\tasync ruleTuple => {\n\t\t\t\t\truleTuple.dependencyResult = await ruleTuple.ruleInstance.dependency(\n\t\t\t\t\t\tcontext.transaction,\n\t\t\t\t\t\truleTuple.conditionResult,\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t);\n\n\t\t\t\t\tif (ruleTuple.ruleInstance.postDependencyConfirm !== null) {\n\t\t\t\t\t\truleTuple.confirmResult = await ruleTuple.ruleInstance.postDependencyConfirm(\n\t\t\t\t\t\t\truleTuple.conditionResult,\n\t\t\t\t\t\t\truleTuple.dependencyResult,\n\t\t\t\t\t\t\tcontext.transaction,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn ruleTuple;\n\t\t\t\t},\n\t\t\t),\n\t\t);\n\n\t\tconst result: RuleDependencyResultTuple[] = [];\n\n\t\tfor (const settledPromise of ruleDependencyResults) {\n\t\t\tif (settledPromise.status === 'rejected') {\n\t\t\t\tif (settledPromise.reason instanceof CriticalBusinessLogicRuleException) {\n\t\t\t\t\tthis.errorHandler.notifyError(\n\t\t\t\t\t\tsettledPromise.reason,\n\t\t\t\t\t);\n\n\t\t\t\t\t// We abort the changes application when a critical exception is thrown.\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tthis.errorHandler.logError(\n\t\t\t\t\tsettledPromise.reason,\n\t\t\t\t);\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (settledPromise.value.confirmResult === BLR_SKIP_RULE) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (settledPromise.value.confirmResult === BLR_ABANDON_CHANGES) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tresult.push(\n\t\t\t\tsettledPromise.value,\n\t\t\t);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate async extractRulesToRun (\n\t\tconditionContext: BusinessLogicRuleConditionContext,\n\t): Promise<RuleConditionResultTuple[] | null> {\n\t\tconst ruleConditionResults = await Promise.allSettled(\n\t\t\tthis.businessLogicRuleInstances.map(\n\t\t\t\tasync businessLogicRule => {\n\t\t\t\t\tconst conditionResult = await businessLogicRule.condition(\n\t\t\t\t\t\tconditionContext,\n\t\t\t\t\t);\n\n\t\t\t\t\tlet confirmResult: any;\n\n\t\t\t\t\tif (\n\t\t\t\t\t\tbusinessLogicRule.confirm !== null\n\t\t\t\t\t\t// No need to confirm if it was no match\n\t\t\t\t\t\t&& conditionResult !== BLR_SKIP_RULE\n\t\t\t\t\t) {\n\t\t\t\t\t\tconfirmResult = await businessLogicRule.confirm(\n\t\t\t\t\t\t\tconditionResult,\n\t\t\t\t\t\t\tconditionContext.transaction,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\truleInstance: businessLogicRule,\n\t\t\t\t\t\tconditionResult,\n\t\t\t\t\t\tconfirmResult,\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t),\n\t\t);\n\n\t\tconst result: RuleConditionResultTuple[] = [];\n\n\t\tfor (const settledPromise of ruleConditionResults) {\n\t\t\tif (settledPromise.status === 'rejected') {\n\t\t\t\tif (settledPromise.reason instanceof CriticalBusinessLogicRuleException) {\n\t\t\t\t\tthis.errorHandler.notifyError(\n\t\t\t\t\t\tsettledPromise.reason,\n\t\t\t\t\t);\n\n\t\t\t\t\t// We abort the changes application when a critical exception is thrown.\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tthis.errorHandler.logError(\n\t\t\t\t\tsettledPromise.reason,\n\t\t\t\t);\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tsettledPromise.value.conditionResult === BLR_SKIP_RULE\n\t\t\t\t|| settledPromise.value.confirmResult === BLR_SKIP_RULE\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// If one of the condition confirmation methods returned STOP_EXECUTION, none of the changes will be applied and we abort\n\t\t\tif (settledPromise.value.confirmResult === BLR_ABANDON_CHANGES) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tresult.push(\n\t\t\t\tsettledPromise.value,\n\t\t\t);\n\t\t}\n\n\t\treturn result;\n\t}\n\n}\n","import { ApiItemType } from '@rentman/backend-types';\nimport { ApiResponse, ApiResponseProcessor } from '../internal';\n\nexport class ApiResponseProcessorFactory {\n\n\tpublic construct<ItemTypeType extends ApiItemType = any> (\n\t\tresponse: ApiResponse<ItemTypeType>,\n\t): ApiResponseProcessor<ItemTypeType> {\n\t\treturn new ApiResponseProcessor(\n\t\t\tresponse,\n\t\t);\n\t}\n\n}\n","import { ChangesCompilation, TransactionCache } from '../internal';\n\nexport class ChangesCompilationFactory {\n\n\tpublic constructor () {\n\t}\n\n\tpublic construct (\n\t\ttransaction: TransactionCache,\n\t): ChangesCompilation {\n\t\treturn new ChangesCompilation(\n\t\t\ttransaction,\n\t\t);\n\t}\n\n}\n","import { ApiItemType } from '@rentman/backend-types';\nimport { CachedQueryItemsItemTypeTuple, ChildCollectionResources, CollectionResource, ColumnCache, ColumnSet, ColumnSetFactory, ErrorHandlerInterface, ItemEntryService, LimitedCollectionResource, OptionsToChildCollections, OptionsToCollectionResource, OrderedCollectionResource, ParentCachedQueryItemTuple, ParentIdMap, QueryService, RequestColumnsOperationsCacheFactory, ResponseColumnItemTypeMap, RootCollectionOptions, TransactionCache } from '../internal';\n\nexport type ColumnSetMap<ItemTypeType extends ApiItemType> = {\n\t[ColumnSetItemType in ItemTypeType]: ColumnSet<ColumnSetItemType>\n};\n\nexport class CollectionResourceFactory {\n\n\tpublic constructor (\n\t\tpublic errorHandler: ErrorHandlerInterface,\n\t\tpublic itemEntryService: ItemEntryService,\n\t\tpublic queryService: QueryService,\n\t\tpublic requestColumnsOperationsCacheFactory: RequestColumnsOperationsCacheFactory,\n\t\tprivate columnCache: ColumnCache,\n\t\tprivate columnSetFactory: ColumnSetFactory,\n\t) {\n\t}\n\n\t/**\n\t * @internal\n\t */\n\tpublic construct<ItemTypeType extends ApiItemType, OptionsType extends RootCollectionOptions<ItemTypeType>> (\n\t\tparentCachedQueryItemTuple: ParentCachedQueryItemTuple<ItemTypeType>,\n\t\tparentCollectionResource: CollectionResource<any, any, any> | null,\n\t\ttransaction: TransactionCache,\n\t\tcolumnSetMap?: ColumnSetMap<ItemTypeType>,\n\t): OptionsToCollectionResource<ItemTypeType, OptionsType> {\n\t\tconst cachedQueryItem = parentCachedQueryItemTuple.cachedQueryItem;\n\t\tconst options = parentCachedQueryItemTuple.options as RootCollectionOptions<ItemTypeType>;\n\t\tconst columnSet = columnSetMap !== undefined\n\t\t\t? columnSetMap[cachedQueryItem.itemType]\n\t\t\t: this.constructColumnSet(\n\t\t\t\tparentCachedQueryItemTuple,\n\t\t\t);\n\n\t\tlet collectionResource: OptionsToCollectionResource<ItemTypeType, OptionsType>;\n\n\t\tif (options.order === undefined) {\n\t\t\tcollectionResource = new CollectionResource<\n\t\t\t\tItemTypeType,\n\t\t\t\tOptionsType['columns'],\n\t\t\t\tOptionsToChildCollections<OptionsType>\n\t\t\t>(\n\t\t\t\tthis,\n\t\t\t\toptions,\n\t\t\t\ttransaction,\n\t\t\t\tcachedQueryItem.queryGraph,\n\t\t\t\tcachedQueryItem.query,\n\t\t\t\tcolumnSet,\n\t\t\t\tparentCollectionResource,\n\t\t\t) as OptionsToCollectionResource<ItemTypeType, OptionsType>;\n\t\t} else if (options.order.limit === undefined) {\n\t\t\tcollectionResource = new OrderedCollectionResource<\n\t\t\t\tItemTypeType,\n\t\t\t\tOptionsType['columns'],\n\t\t\t\tOptionsToChildCollections<OptionsType>\n\t\t\t>(\n\t\t\t\tthis,\n\t\t\t\toptions,\n\t\t\t\ttransaction,\n\t\t\t\tcachedQueryItem.queryGraph,\n\t\t\t\tcachedQueryItem.query,\n\t\t\t\tcolumnSet,\n\t\t\t\tparentCollectionResource,\n\t\t\t) as OptionsToCollectionResource<ItemTypeType, OptionsType>;\n\t\t} else {\n\t\t\tcollectionResource = new LimitedCollectionResource<\n\t\t\t\tItemTypeType,\n\t\t\t\tOptionsType['columns'],\n\t\t\t\tOptionsToChildCollections<OptionsType>\n\t\t\t>(\n\t\t\t\tthis,\n\t\t\t\toptions,\n\t\t\t\ttransaction,\n\t\t\t\tcachedQueryItem.queryGraph,\n\t\t\t\tcachedQueryItem.query,\n\t\t\t\tcolumnSet,\n\t\t\t\tparentCollectionResource,\n\t\t\t) as OptionsToCollectionResource<ItemTypeType, OptionsType>;\n\t\t}\n\n\t\tcollectionResource.initializeItems(\n\t\t\tcachedQueryItem.items,\n\t\t\tthis.constructChildCollectionResources<OptionsToChildCollections<OptionsType>>(\n\t\t\t\tparentCachedQueryItemTuple.children,\n\t\t\t\tcollectionResource,\n\t\t\t\ttransaction,\n\t\t\t\tcolumnSetMap,\n\t\t\t),\n\t\t);\n\n\t\tif (\n\t\t\tcollectionResource.options.abortSignal !== undefined\n\t\t\t&& collectionResource.options.abortSignal.aborted\n\t\t) {\n\t\t\t// We have to clear it to clear the child collections\n\t\t\tcollectionResource.clearResource();\n\n\t\t\t// But we don't have to add it to the transaction cache\n\t\t\treturn collectionResource;\n\t\t}\n\n\t\ttransaction.cachedQueryHandler.addCollectionResource(\n\t\t\tcollectionResource,\n\t\t);\n\n\t\treturn collectionResource;\n\t}\n\n\tpublic constructChildCollectionResources<Children extends ChildCollectionResources | undefined> (\n\t\tcachedQueryItemTypeTuples: CachedQueryItemsItemTypeTuple<ApiItemType>[] | null,\n\t\tparentCollectionResource: CollectionResource<any, any, any> | null,\n\t\ttransaction: TransactionCache,\n\t\tcolumnSetMap: Partial<ColumnSetMap<ApiItemType>> = {},\n\t): ParentIdMap<Children> {\n\t\tif (cachedQueryItemTypeTuples === null) {\n\t\t\treturn {};\n\t\t}\n\n\t\tconst result: ParentIdMap<Children> = {};\n\n\t\tfor (const cachedQueryItemsTypeTuple of cachedQueryItemTypeTuples) {\n\t\t\tconst itemType = cachedQueryItemsTypeTuple.itemType;\n\t\t\tconst cachedQueryItemTuples = cachedQueryItemsTypeTuple.cachedQueryItemTuples;\n\n\t\t\tif (cachedQueryItemTuples.length === 0) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (columnSetMap[itemType] === undefined) {\n\t\t\t\t(columnSetMap as ColumnSetMap<any>)[itemType] = this.constructColumnSet(\n\t\t\t\t\tcachedQueryItemTuples[0],\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tfor (const cachedQueryItemTree of cachedQueryItemTuples) {\n\t\t\t\tconst parentId = cachedQueryItemTree.options.parent!.itemId;\n\n\t\t\t\tif (result[parentId] === undefined) {\n\t\t\t\t\tresult[parentId] = {} as Children;\n\t\t\t\t}\n\n\t\t\t\t(result[parentId]![cachedQueryItemsTypeTuple.itemType] as CollectionResource<any, any, any>) = this.construct(\n\t\t\t\t\tcachedQueryItemTree,\n\t\t\t\t\tparentCollectionResource,\n\t\t\t\t\ttransaction,\n\t\t\t\t\tcolumnSetMap as ColumnSetMap<ApiItemType>,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// We don't have to call `transaction.callInitialChangesListener` here as we handle that in a higher level\n\n\t\treturn result;\n\t}\n\n\tpublic constructColumnSet<ItemTypeType extends ApiItemType> (\n\t\tcachedQueryItemTuple: ParentCachedQueryItemTuple<ItemTypeType>,\n\t): ColumnSet<ItemTypeType> {\n\t\t// `cachedQueryItem[0].requestColumnsTuple.object` will contain more columns, but we only the columns\n\t\t// specified in options need to be included in the column set. (They are mostly used for `RmInput`,\n\t\t// translations, etc.)\n\t\tconst itemType = cachedQueryItemTuple.cachedQueryItem.itemType;\n\t\tconst requestColumns = cachedQueryItemTuple.options.columns;\n\t\tconst columns = this.columnCache.retrieve(\n\t\t\titemType,\n\t\t\trequestColumns,\n\t\t);\n\n\t\tif (\n\t\t\tcolumns.missing === true\n\t\t\t|| columns.missing.length > 0\n\t\t) {\n\t\t\tthis.errorHandler.logWarning(\n\t\t\t\t'Missing columns in when constructing collection resource column set:',\n\t\t\t\tcolumns.missing,\n\t\t\t);\n\t\t}\n\n\t\treturn this.columnSetFactory.construct(\n\t\t\titemType,\n\t\t\trequestColumns,\n\t\t\t// We assume all columns are there since they're fetched when fetching the data for the collection.\n\t\t\tcolumns.cached as ResponseColumnItemTypeMap,\n\t\t);\n\t}\n\n}\n","import { ApiItemType } from '@rentman/backend-types';\nimport { ApiRequestColumns, ColumnExpansion, ColumnInfoFactory, ResponseColumnItemTypeMap } from '../internal';\n\nexport class ColumnExpansionFactory {\n\n\tpublic constructor (\n\t\tprivate columnInfoFactory: ColumnInfoFactory,\n\t) {\n\n\t}\n\n\tpublic construct<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\trequestColumns: ApiRequestColumns<ItemTypeType>,\n\t\tresponseColumns: ResponseColumnItemTypeMap,\n\t): ColumnExpansion<ItemTypeType> {\n\t\treturn new ColumnExpansion(\n\t\t\tthis.columnInfoFactory,\n\t\t\titemType,\n\t\t\trequestColumns,\n\t\t\tresponseColumns,\n\t\t);\n\t}\n\n}\n","import { ApiFields, ApiItemType, GetColumnType } from '@rentman/backend-types';\nimport { ColumnInfo, ItemTypeColumnIds, RootColumnMap } from '../internal';\n\nexport class ColumnInfoFactory {\n\n\tpublic constructor () {\n\t}\n\n\tpublic construct<ItemTypeType extends ApiItemType = any, ColumnId extends keyof ApiFields[ItemTypeType] = any> (\n\t\tapiColumn: GetColumnType<ItemTypeType, ColumnId>,\n\t\tparent: ColumnInfo | null,\n\t): ColumnInfo<ItemTypeType> {\n\t\treturn new ColumnInfo(\n\t\t\tapiColumn,\n\t\t\tparent,\n\t\t);\n\t}\n\n\tpublic constructFromRootMap<ItemTypeType extends ApiItemType = any, ColumnIds extends ItemTypeColumnIds<ItemTypeType> = any> (\n\t\trootColumnMap: RootColumnMap<ItemTypeType, ColumnIds>,\n\t\tparent: ColumnInfo | null = null,\n\t): ColumnInfo<ItemTypeType, ColumnIds[number]>[] {\n\t\tconst result: ColumnInfo<ItemTypeType, ColumnIds[number]>[] = [];\n\n\t\tfor (const columnId in rootColumnMap) {\n\t\t\tconst columnMapEntry = rootColumnMap[columnId];\n\t\t\tconst columnInfo = this.construct<ItemTypeType>(\n\t\t\t\tcolumnMapEntry.apiColumn,\n\t\t\t\tparent,\n\t\t\t);\n\t\t\tconst childColumns = this.constructFromRootMap(\n\t\t\t\tcolumnMapEntry.children,\n\t\t\t\tcolumnInfo,\n\t\t\t);\n\n\t\t\tif (childColumns.length > 0) {\n\t\t\t\tcolumnInfo.setChildren(\n\t\t\t\t\tcolumnInfo.apiColumn.itemType,\n\t\t\t\t\tchildColumns,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tresult.push(\n\t\t\t\tcolumnInfo,\n\t\t\t);\n\t\t}\n\n\t\treturn result;\n\t}\n\n}\n","import { ApiItemType, ResponseColumn, ResponseColumnItem } from '@rentman/backend-types';\nimport { ApiRequestColumn, ApiRequestColumnArray, ApiRequestColumns, ColumnHandler, ColumnInfo, ColumnInfoFactory, ColumnSet, ColumnUtil, ErrorHandlerInterface, hasProperties, ItemTypeMap, ResponseColumnItemTypeMap, RootColumnMap } from '../internal';\n\nexport class ColumnSetFactory {\n\n\tpublic constructor (\n\t\tprivate columnHandler: ColumnHandler,\n\t\tprivate columnInfoFactory: ColumnInfoFactory,\n\t\tprivate errorHandler: ErrorHandlerInterface,\n\t) {\n\t}\n\n\tpublic construct<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\trequestColumns: ApiRequestColumns<ItemTypeType>,\n\t\tresponseColumns: ResponseColumnItemTypeMap,\n\t\tenableCaching?: boolean,\n\t\tincludeIdColumn?: boolean,\n\t): ColumnSet<ItemTypeType> {\n\t\treturn requestColumns === true\n\t\t\t? this.constructFromResponse(\n\t\t\t\titemType,\n\t\t\t\ttrue,\n\t\t\t\tresponseColumns,\n\t\t\t\tenableCaching,\n\t\t\t)\n\t\t\t: this.constructFromRequest(\n\t\t\t\titemType,\n\t\t\t\trequestColumns,\n\t\t\t\tfalse,\n\t\t\t\tresponseColumns,\n\t\t\t\tenableCaching,\n\t\t\t\tincludeIdColumn,\n\t\t\t);\n\t}\n\n\tpublic constructFromRequest<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\trequestColumns: ApiRequestColumnArray<ItemTypeType>,\n\t\trequestColumnsTrue: boolean,\n\t\tresponseColumns: ResponseColumnItemTypeMap,\n\t\tenableCaching: boolean = true,\n\t\tincludeIdColumn: boolean = true,\n\t): ColumnSet<ItemTypeType> {\n\t\tconst rootColumnMap = this.expandRootColumnMap(\n\t\t\trequestColumns,\n\t\t\titemType,\n\t\t\tresponseColumns,\n\t\t\t{},\n\t\t\tenableCaching,\n\t\t);\n\n\t\tif (includeIdColumn) {\n\t\t\tthis.expandRootColumnMap(\n\t\t\t\t[\n\t\t\t\t\t'id',\n\t\t\t\t],\n\t\t\t\titemType,\n\t\t\t\tresponseColumns,\n\t\t\t\trootColumnMap,\n\t\t\t\tenableCaching,\n\t\t\t);\n\t\t}\n\n\t\tconst columnSet = new ColumnSet(\n\t\t\tthis,\n\t\t\titemType,\n\t\t\trequestColumns,\n\t\t\trequestColumnsTrue,\n\t\t\t{} as ResponseColumnItemTypeMap,\n\t\t);\n\n\t\tthis.processColumnInfo(\n\t\t\tcolumnSet,\n\t\t\tthis.columnInfoFactory.constructFromRootMap(\n\t\t\t\trootColumnMap,\n\t\t\t),\n\t\t\titemType,\n\t\t);\n\n\t\treturn columnSet;\n\t}\n\n\tpublic constructFromResponse<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\trequestColumnsTrue: boolean,\n\t\tresponseColumns: ResponseColumnItemTypeMap,\n\t\tenableCaching: boolean = true,\n\t): ColumnSet<ItemTypeType> {\n\t\tconst rootColumnMap = this.expandRootColumnMapFromResponseColumns(\n\t\t\titemType,\n\t\t\tresponseColumns,\n\t\t\t{},\n\t\t\tenableCaching,\n\t\t);\n\n\t\tconst columnSet = new ColumnSet(\n\t\t\tthis,\n\t\t\titemType,\n\t\t\tthis.constructRequestColumnsFromRootColumnMap<ItemTypeType>(\n\t\t\t\trootColumnMap,\n\t\t\t),\n\t\t\trequestColumnsTrue,\n\t\t\tresponseColumns,\n\t\t);\n\n\t\tthis.processColumnInfo(\n\t\t\tcolumnSet,\n\t\t\tthis.columnInfoFactory.constructFromRootMap(\n\t\t\t\trootColumnMap,\n\t\t\t),\n\t\t\titemType,\n\t\t);\n\n\t\treturn columnSet;\n\t}\n\n\tprivate constructRequestColumnsFromRootColumnMap<ItemTypeType extends ApiItemType> (\n\t\trootColumnMap: RootColumnMap<ItemTypeType>,\n\t): ApiRequestColumn<ItemTypeType>[] {\n\t\tconst result: ApiRequestColumn<ItemTypeType>[] = [];\n\n\t\tfor (const columnId in rootColumnMap) {\n\t\t\tconst entry = rootColumnMap[columnId];\n\n\t\t\tif (hasProperties(\n\t\t\t\tentry.children,\n\t\t\t)) {\n\t\t\t\tresult.push(\n\t\t\t\t\t{\n\t\t\t\t\t\t[columnId]: this.constructRequestColumnsFromRootColumnMap(\n\t\t\t\t\t\t\tentry.children,\n\t\t\t\t\t\t),\n\t\t\t\t\t} as unknown as ApiRequestColumn<ItemTypeType>,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tresult.push(\n\t\t\t\t\tcolumnId as ApiRequestColumn<ItemTypeType>,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate expandRootColumnMapFromResponseColumns<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\tresponseColumns: ResponseColumnItemTypeMap,\n\t\trootColumnMap: RootColumnMap,\n\t\tenableCaching: boolean,\n\t\tprocessedItemTypeMap: ItemTypeMap<boolean> = {},\n\t): RootColumnMap {\n\t\tif (processedItemTypeMap[itemType] === true) {\n\t\t\treturn rootColumnMap;\n\t\t}\n\n\t\tprocessedItemTypeMap[itemType] = true;\n\n\t\tfor (const columnId in responseColumns[itemType]) {\n\t\t\tconst responseColumn = responseColumns[itemType][columnId] as unknown as ResponseColumn<ItemTypeType> | undefined;\n\n\t\t\tif (responseColumn === undefined) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (enableCaching) {\n\t\t\t\tthis.columnHandler.setColumn(\n\t\t\t\t\titemType,\n\t\t\t\t\tresponseColumn,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (rootColumnMap[columnId] === undefined) {\n\t\t\t\trootColumnMap[columnId] = {\n\t\t\t\t\tapiColumn: responseColumn,\n\t\t\t\t\tchildren: {},\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\t!ColumnUtil.isItemColumn(\n\t\t\t\t\tresponseColumn,\n\t\t\t\t\tfalse,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst children = responseColumns[(responseColumn as ResponseColumnItem).itemType];\n\n\t\t\tif (\n\t\t\t\tchildren === undefined\n\t\t\t\t|| !hasProperties(\n\t\t\t\t\tchildren,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tthis.expandRootColumnMapFromResponseColumns(\n\t\t\t\t(responseColumn as ResponseColumnItem).itemType,\n\t\t\t\tresponseColumns,\n\t\t\t\trootColumnMap[columnId].children,\n\t\t\t\tenableCaching,\n\t\t\t\tprocessedItemTypeMap,\n\t\t\t);\n\t\t}\n\n\t\treturn rootColumnMap;\n\t}\n\n\tprivate processColumnInfo<ItemTypeType extends ApiItemType> (\n\t\tcolumnSet: ColumnSet<ItemTypeType>,\n\t\tcolumnInfoObjects: ColumnInfo[],\n\t\titemType: ItemTypeType,\n\t): void {\n\t\tconst response = columnSet.response;\n\n\t\tif (response[itemType] === undefined) {\n\t\t\tresponse[itemType] = {} as ResponseColumnItemTypeMap[ItemTypeType];\n\t\t}\n\n\t\tfor (const columnInfo of columnInfoObjects) {\n\t\t\tresponse[itemType][columnInfo.id] = columnInfo.apiColumn;\n\n\t\t\tcolumnSet.groupColumnInfo(\n\t\t\t\tcolumnInfo,\n\t\t\t);\n\n\t\t\tif (!columnInfo.isLeaf) {\n\t\t\t\tthis.processColumnInfo(\n\t\t\t\t\tcolumnSet,\n\t\t\t\t\tcolumnInfo.children,\n\t\t\t\t\tcolumnInfo.itemType,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate expandRootColumnMap<ItemTypeType extends ApiItemType> (\n\t\trequestColumns: ApiRequestColumnArray<ItemTypeType>,\n\t\titemType: ItemTypeType,\n\t\tresponseColumns: ResponseColumnItemTypeMap,\n\t\trootColumnMap: RootColumnMap,\n\t\tenableCaching: boolean,\n\t): RootColumnMap {\n\t\tfor (const requestColumn of requestColumns) {\n\t\t\tconst {\n\t\t\t\tid: columnId,\n\t\t\t\tchildren,\n\t\t\t} = ColumnUtil.parseRequestColumn(\n\t\t\t\trequestColumn,\n\t\t\t);\n\n\t\t\tlet responseColumn = responseColumns[itemType]?.[columnId as string] as ResponseColumn<ItemTypeType> | undefined;\n\n\t\t\tif (responseColumn === undefined) {\n\t\t\t\t// todo[limit] then can happen when 2 different requests with the same query fetch different columns (one will be done more early)\n\t\t\t\t// We should assess if we still want this warning\n\t\t\t\tthis.errorHandler.logWarning(\n\t\t\t\t\t`No api column for request column ${columnId as string} for itemType ${itemType}`,\n\t\t\t\t);\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (enableCaching) {\n\t\t\t\tresponseColumn = this.columnHandler.setColumn(\n\t\t\t\t\titemType,\n\t\t\t\t\tresponseColumn,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (rootColumnMap[columnId as string] === undefined) {\n\t\t\t\trootColumnMap[columnId as string] = {\n\t\t\t\t\tapiColumn: responseColumn,\n\t\t\t\t\tchildren: {},\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (children.length === 0) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tthis.expandRootColumnMap(\n\t\t\t\tchildren,\n\t\t\t\t(responseColumn as ResponseColumnItem<ItemTypeType>).itemType,\n\t\t\t\tresponseColumns,\n\t\t\t\trootColumnMap[columnId as string].children,\n\t\t\t\tenableCaching,\n\t\t\t);\n\t\t}\n\n\t\treturn rootColumnMap;\n\t}\n\n}\n","import { ApiItemType } from '@rentman/backend-types';\nimport { ApiRequestColumns, ColumnCache, RequestColumnsOperationsCache } from '../internal';\n\nexport class RequestColumnsOperationsCacheFactory {\n\n\tpublic constructor (\n\t\tprivate columnCache: ColumnCache,\n\t) {\n\t}\n\n\tpublic construct<ItemTypeType extends ApiItemType> (\n\t\titemType: ItemTypeType,\n\t\trequestColumns: ApiRequestColumns<ItemTypeType>,\n\t): RequestColumnsOperationsCache<ItemTypeType> {\n\t\treturn new RequestColumnsOperationsCache<ItemTypeType>(\n\t\t\titemType,\n\t\t\tthis.columnCache,\n\t\t\trequestColumns,\n\t\t);\n\t}\n\n}\n","import { AbstractCache, ItemCache } from '../internal';\nimport { GraphQueryParserFactory } from './GraphQueryParserFactory';\n\nexport class ItemCacheFactory {\n\n\tpublic constructor (\n\t\tprivate graphQueryParserFactory: GraphQueryParserFactory,\n\t) {\n\t}\n\n\tpublic construct (\n\t\ttransaction: AbstractCache,\n\t): ItemCache {\n\t\treturn new ItemCache(\n\t\t\tthis.graphQueryParserFactory,\n\t\t\ttransaction,\n\t\t);\n\t}\n\n}\n","import { ApiItemType } from '@rentman/backend-types';\nimport { ApiRequestColumns, ChildCollectionResources, ErrorHandlerInterface, ItemEntry, ItemResource, TransactionCache } from '../internal';\n\nexport class ItemResourceFactory {\n\n\tpublic constructor (\n\t\tpublic errorHandler: ErrorHandlerInterface,\n\t) {\n\t}\n\n\tpublic construct<\n\t\tItemTypeType extends ApiItemType,\n\t\tRequestColumns extends ApiRequestColumns<ItemTypeType>,\n\t\tChildren extends ChildCollectionResources | undefined,\n\t> (\n\t\titemEntry: ItemEntry<ItemTypeType>,\n\t\ttransaction: TransactionCache,\n\t\tisNew: boolean = false,\n\t\tabortSignal?: AbortSignal,\n\t): ItemResource<ItemTypeType, RequestColumns, Children> {\n\t\treturn new ItemResource<ItemTypeType, RequestColumns, Children>(\n\t\t\tthis,\n\t\t\titemEntry,\n\t\t\ttransaction,\n\t\t\tisNew,\n\t\t\tabortSignal,\n\t\t);\n\t}\n\n}\n","import { ApiFieldsOnDeleteRule } from '@rentman/backend-types';\nimport { RmCore, ServerCache, ServerCacheDependencyInterface, TransactionCache, TransactionOptions, TransactionValidatorFactory } from '../internal';\n\nexport class TransactionCacheFactory {\n\n\tprivate readonly serverCache: ServerCache;\n\n\tpublic constructor (\n\t\tserverCacheDependencies: ServerCacheDependencyInterface,\n\t\tapiFieldsOnDeleteRule: typeof ApiFieldsOnDeleteRule,\n\t\tcore: RmCore,\n\t) {\n\t\tthis.serverCache = new ServerCache(\n\t\t\tserverCacheDependencies,\n\t\t\tapiFieldsOnDeleteRule,\n\t\t\tcore,\n\t\t);\n\t}\n\n\t/**\n\t * Todo[cache] Store a map of all transactions by transaction id ?\n\t */\n\tpublic getById (\n\t\tid: string,\n\t): TransactionCache | undefined {\n\t\tconst findChild = (\n\t\t\tchildren: TransactionCache[],\n\t\t) => {\n\t\t\tfor (const transaction of children) {\n\t\t\t\tif (transaction.id === id) {\n\t\t\t\t\treturn transaction;\n\t\t\t\t}\n\n\t\t\t\tconst childResult = findChild(\n\t\t\t\t\ttransaction.children,\n\t\t\t\t);\n\n\t\t\t\tif (childResult !== undefined) {\n\t\t\t\t\treturn childResult;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn undefined;\n\t\t};\n\n\t\treturn findChild(\n\t\t\tthis.serverCache.children,\n\t\t);\n\t}\n\n\tpublic construct (\n\t\tid?: string,\n\t\tvalidatorFactory?: TransactionValidatorFactory,\n\t\ttransactionOptions?: TransactionOptions,\n\t): TransactionCache {\n\t\treturn this.serverCache.createChild(\n\t\t\tid,\n\t\t\tvalidatorFactory,\n\t\t\ttransactionOptions,\n\t\t);\n\t}\n\n\t/* @internal*/\n\tpublic getServerCache (): ServerCache {\n\t\treturn this.serverCache;\n\t}\n\n}\n","import { LinkTreeServiceInterface, ModuleChangesCompilation, TransactionCache } from '../internal';\n\nexport class ModuleChangesCompilationFactory {\n\n\tpublic constructor (\n\t\tprivate linkTreeService: LinkTreeServiceInterface,\n\t) {\n\t}\n\n\tpublic construct (\n\t\ttransaction: TransactionCache,\n\t): ModuleChangesCompilation {\n\t\treturn new ModuleChangesCompilation(\n\t\t\tthis.linkTreeService,\n\t\t\ttransaction,\n\t\t);\n\t}\n\n}\n","import { RequestColumnExpansion } from '../internal';\n\nexport class RequestColumnExpansionFactory {\n\n\tpublic construct (): RequestColumnExpansion {\n\t\treturn new RequestColumnExpansion();\n\t}\n\n}\n","import { ApiItemType } from '@rentman/backend-types';\nimport { ApiFormatter, ChangesDelta, ChangesDeltaBase, ChildChangesDelta, ConversionMapService, ErrorHandlerInterface, ItemCreateService, ItemEntryService, ParentChangesDelta } from '../internal';\n\nexport class ChangesDeltaFactory {\n\n\tpublic constructor (\n\t\tprivate conversionMapService: ConversionMapService,\n\t\tprivate errorHandler: ErrorHandlerInterface,\n\t\tprivate itemCreateService: ItemCreateService,\n\t\tprivate itemEntryService: ItemEntryService,\n\t) {\n\n\t}\n\n\tpublic construct (\n\t\tlogMissingColumnErrors: boolean,\n\t\tqueryItemTypes?: Iterable<ApiItemType>,\n\t): ChangesDelta {\n\t\treturn new ChangesDelta(\n\t\t\tlogMissingColumnErrors,\n\t\t\tqueryItemTypes,\n\t\t\tthis.errorHandler,\n\t\t\tthis.itemCreateService,\n\t\t\tthis.itemEntryService,\n\t\t);\n\t}\n\n\tpublic cloneCreatedChanges (\n\t\tsourceChangesDelta: ChangesDelta,\n\t\tdestinationChangesDelta: ChangesDelta = this.construct(\n\t\t\tsourceChangesDelta.logMissingColumnErrors,\n\t\t),\n\t): ChangesDelta {\n\t\tconst conversionMap = {};\n\n\t\tsourceChangesDelta.created.forEach(\n\t\t\t(\n\t\t\t\ttuple,\n\t\t\t\titemType,\n\t\t\t) => {\n\t\t\t\tthis.conversionMapService.expandConversionMap(\n\t\t\t\t\titemType,\n\t\t\t\t\ttuple.itemId,\n\t\t\t\t\tconversionMap,\n\t\t\t\t);\n\t\t\t},\n\t\t);\n\n\t\tsourceChangesDelta.created.forEach(\n\t\t\t(\n\t\t\t\ttuple,\n\t\t\t\titemType,\n\t\t\t) => {\n\t\t\t\tconst fieldsCopy = ApiFormatter.copyFields(\n\t\t\t\t\ttuple.fields,\n\t\t\t\t\t{},\n\t\t\t\t\ttuple.columns.main,\n\t\t\t\t);\n\n\t\t\t\tthis.conversionMapService.updateItemValues(\n\t\t\t\t\tfieldsCopy,\n\t\t\t\t\tfieldsCopy,\n\t\t\t\t\ttuple.columns.item.main,\n\t\t\t\t\tconversionMap,\n\t\t\t\t);\n\n\t\t\t\tdestinationChangesDelta.created.add(\n\t\t\t\t\tconversionMap[itemType][tuple.itemId],\n\t\t\t\t\tfieldsCopy,\n\t\t\t\t\ttuple.columns,\n\t\t\t\t\ttuple.isRoot,\n\t\t\t\t);\n\t\t\t},\n\t\t);\n\n\t\treturn destinationChangesDelta;\n\t}\n\n\t/* @internal*/\n\tpublic constructChildDelta (): ChildChangesDelta {\n\t\treturn new ChildChangesDelta(\n\t\t\tthis.itemEntryService,\n\t\t);\n\t}\n\n\t/* @internal*/\n\tpublic constructParentDelta (\n\t\tquerySource?: ChangesDeltaBase,\n\t): ParentChangesDelta {\n\t\tconst parentChangesDelta = new ParentChangesDelta(\n\t\t\tthis.itemEntryService,\n\t\t\tquerySource?._queryItemTypeSet,\n\t\t);\n\n\t\tif (querySource === undefined) {\n\t\t\treturn parentChangesDelta;\n\t\t}\n\n\t\tfor (const itemType in querySource._queryResults) {\n\t\t\tfor (const queryString in querySource._queryResults[itemType]) {\n\t\t\t\tparentChangesDelta._setQueryResult(\n\t\t\t\t\titemType as ApiItemType,\n\t\t\t\t\tqueryString,\n\t\t\t\t\tquerySource._queryResults[itemType][queryString],\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn parentChangesDelta;\n\t}\n\n}\n","import { ApiItemType, ItemId } from '@rentman/backend-types';\n\nexport class ItemAlreadyExistsException\n\textends Error {\n\n\tpublic constructor (\n\t\titemType: ApiItemType,\n\t\titemId: ItemId,\n\t) {\n\t\tsuper(\n\t\t\t`A local item of type ${itemType} with ID ${itemId} not be created, the ID is already in use`,\n\t\t);\n\t}\n\n}","export class ItemLockedException\n\textends Error {\n\n}\n","export class SavingInProgressException\n\textends Error {\n\n}","import { ApiItemType } from '@rentman/backend-types';\nimport { GraphQueryParser } from '../classes/matcher/GraphQueryParser';\nimport { LeafQueryNode } from '../classes/matcher/QueryNode';\nimport { ErrorHandlerInterface, LinkTreeServiceInterface } from '../internal';\n\nexport class GraphQueryParserFactory {\n\n\tpublic constructor (\n\t\tprivate linkTreeService: LinkTreeServiceInterface,\n\t\tprivate errorHandler: ErrorHandlerInterface,\n\t) {\n\n\t}\n\n\tpublic construct<ItemTypeType extends ApiItemType, QueryId extends LeafQueryNode> (\n\t\titemType: ItemTypeType,\n\t\tqueryId: QueryId,\n\t): GraphQueryParser<ItemTypeType, QueryId> {\n\t\treturn new GraphQueryParser(\n\t\t\titemType,\n\t\t\tqueryId,\n\t\t\tthis.linkTreeService,\n\t\t\tthis.errorHandler,\n\t\t);\n\t}\n\n}\n","declare const __VERSION__: string;\n\nimport { ApiFieldsOnDeleteRule, ItemId } from '@rentman/backend-types';\nimport { ApiRequestService } from './classes/ApiRequestService';\nimport { BusinessLogicManager } from './classes/BusinessLogicManager/BusinessLogicManager';\nimport { BusinessLogicRule } from './classes/BusinessLogicManager/BusinessLogicRule';\nimport { ColumnCache } from './classes/ColumnCache';\nimport { ColumnHandler } from './classes/ColumnHandler';\nimport { ConversionMapService } from './classes/ConversionMapService';\nimport { ItemCreateService } from './classes/ItemCreateService';\nimport { ItemEntryService } from './classes/ItemEntryService';\nimport { LockService } from './classes/LockService';\nimport { QueryService } from './classes/QueryService';\nimport { SocketMessageHandler } from './classes/SocketMessageHandler';\nimport { TemplateCache } from './classes/TemplateCache';\nimport { ApiResponseProcessorFactory } from './factories/ApiResponseProcessorFactory';\nimport { ChangesCompilationFactory } from './factories/ChangesCompilationFactory';\nimport { ChangesDeltaFactory } from './factories/ChangesDeltaFactory';\nimport { CollectionResourceFactory } from './factories/CollectionResourceFactory';\nimport { ColumnExpansionFactory } from './factories/ColumnExpansionFactory';\nimport { ColumnInfoFactory } from './factories/ColumnInfoFactory';\nimport { ColumnSetFactory } from './factories/ColumnSetFactory';\nimport { GraphQueryParserFactory } from './factories/GraphQueryParserFactory';\nimport { ItemCacheFactory } from './factories/ItemCacheFactory';\nimport { ItemResourceFactory } from './factories/ItemResourceFactory';\nimport { ModuleChangesCompilationFactory } from './factories/ModuleChangesCompilationFactory';\nimport { RequestColumnExpansionFactory } from './factories/RequestColumnExpansionFactory';\nimport { RequestColumnsOperationsCacheFactory } from './factories/RequestColumnsOperationsCacheFactory';\nimport { TransactionCacheFactory } from './factories/TransactionCacheFactory';\nimport { ApiRequestServiceInterface } from './interfaces/ApiRequestServiceInterface';\nimport { ErrorHandlerInterface } from './interfaces/ErrorHandlerInterface';\nimport { LinkTreeServiceInterface } from './interfaces/LinkTreeServiceInterface';\n\nexport class RmCore {\n\n\tpublic version: string = __VERSION__;\n\n\t// todo: these probably don't all need to be public\n\tpublic apiRequestService: ApiRequestService;\n\tpublic apiResponseProcessorFactory: ApiResponseProcessorFactory;\n\tpublic changesCompilationFactory: ChangesCompilationFactory;\n\tpublic changesDeltaFactory: ChangesDeltaFactory;\n\tpublic collectionResourceFactory: CollectionResourceFactory;\n\tpublic columnCache: ColumnCache;\n\tpublic columnExpansionFactory: ColumnExpansionFactory;\n\tpublic columnHandler: ColumnHandler;\n\tpublic columnInfoFactory: ColumnInfoFactory;\n\tpublic columnSetFactory: ColumnSetFactory;\n\tpublic requestColumnOperationsCacheFactory: RequestColumnsOperationsCacheFactory;\n\tpublic conversionMapService: ConversionMapService;\n\tpublic itemCacheFactory: ItemCacheFactory;\n\tpublic itemCreateService: ItemCreateService;\n\tpublic itemEntryService: ItemEntryService;\n\tpublic itemResourceFactory: ItemResourceFactory;\n\tpublic lockService: LockService;\n\tpublic moduleChangesCompilationFactory: ModuleChangesCompilationFactory;\n\tpublic queryService: QueryService;\n\tpublic requestColumnExpansionFactory: RequestColumnExpansionFactory;\n\tpublic socketMessageHandler: SocketMessageHandler;\n\tpublic templateCache: TemplateCache;\n\tpublic transactionCacheFactory: TransactionCacheFactory;\n\tpublic businessLogicManager: BusinessLogicManager;\n\n\tpublic constructor (\n\t\tuserId: ItemId,\n\t\t_apiRequestService: ApiRequestServiceInterface,\n\t\terrorHandler: ErrorHandlerInterface,\n\t\tlinkTreeService: LinkTreeServiceInterface,\n\t\tbusinessLogicRuleInstances: BusinessLogicRule<any, any>[],\n\t\t/**\n\t\t * We specify an `apiFieldsOnDeleteRule` parameter in order to easily mock it in unit tests. This prevents\n\t\t * issues where a mocked API response does not contain required fields that are added at a later point in time.\n\t\t */\n\t\tapiFieldsOnDeleteRule: typeof ApiFieldsOnDeleteRule = ApiFieldsOnDeleteRule,\n\t) {\n\t\t// Create variables for each service in order to get a TypeScript error when a dependency hasn't been\n\t\t// initialized yet.\n\t\tconst graphQueryParserFactory = new GraphQueryParserFactory(\n\t\t\tlinkTreeService,\n\t\t\terrorHandler,\n\t\t);\n\n\t\tconst queryService = new QueryService();\n\n\t\tconst requestColumnExpansionFactory = new RequestColumnExpansionFactory();\n\n\t\tconst itemEntryService = new ItemEntryService(\n\t\t\tuserId,\n\t\t\tlinkTreeService,\n\t\t);\n\n\t\tconst apiResponseProcessorFactory = new ApiResponseProcessorFactory();\n\t\tconst apiRequestService = new ApiRequestService(\n\t\t\t_apiRequestService,\n\t\t\tapiResponseProcessorFactory,\n\t\t);\n\n\t\tconst columnCache = new ColumnCache();\n\n\t\tconst columnHandler = new ColumnHandler(\n\t\t\tapiRequestService,\n\t\t\tcolumnCache,\n\t\t);\n\t\tconst columnInfoFactory = new ColumnInfoFactory();\n\t\tconst columnExpansionFactory = new ColumnExpansionFactory(\n\t\t\tcolumnInfoFactory,\n\t\t);\n\n\t\tconst columnSetFactory = new ColumnSetFactory(\n\t\t\tcolumnHandler,\n\t\t\tcolumnInfoFactory,\n\t\t\terrorHandler,\n\t\t);\n\t\tconst requestColumnsOperationsCacheFactory = new RequestColumnsOperationsCacheFactory(\n\t\t\tcolumnCache,\n\t\t);\n\n\t\tconst lockService = new LockService(\n\t\t\tapiRequestService,\n\t\t);\n\t\tconst itemCacheFactory = new ItemCacheFactory(\n\t\t\tgraphQueryParserFactory,\n\t\t);\n\t\tconst itemResourceFactory = new ItemResourceFactory(\n\t\t\terrorHandler,\n\t\t);\n\n\t\tconst templateCache = new TemplateCache(\n\t\t\tapiRequestService,\n\t\t\tcolumnHandler,\n\t\t\tcolumnSetFactory,\n\t\t\trequestColumnExpansionFactory,\n\t\t\tlinkTreeService,\n\t\t\titemEntryService,\n\t\t);\n\n\t\tconst conversionMapService = new ConversionMapService();\n\n\t\tconst itemCreateService = new ItemCreateService(\n\t\t\tconversionMapService,\n\t\t\ttemplateCache,\n\t\t);\n\n\t\tconst changesDeltaFactory = new ChangesDeltaFactory(\n\t\t\tconversionMapService,\n\t\t\terrorHandler,\n\t\t\titemCreateService,\n\t\t\titemEntryService,\n\t\t);\n\n\t\tconst businessLogicManager = new BusinessLogicManager(\n\t\t\terrorHandler,\n\t\t\tbusinessLogicRuleInstances,\n\t\t);\n\n\t\tconst collectionResourceFactory = new CollectionResourceFactory(\n\t\t\terrorHandler,\n\t\t\titemEntryService,\n\t\t\tqueryService,\n\t\t\trequestColumnsOperationsCacheFactory,\n\t\t\tcolumnCache,\n\t\t\tcolumnSetFactory,\n\t\t);\n\n\t\tconst changesCompilationFactory = new ChangesCompilationFactory();\n\n\t\tconst moduleChangesCompilationFactory = new ModuleChangesCompilationFactory(\n\t\t\tlinkTreeService,\n\t\t);\n\n\t\tconst transactionCacheFactory = new TransactionCacheFactory(\n\t\t\t{\n\t\t\t\tapiRequestService,\n\t\t\t\tbusinessLogicManager,\n\t\t\t\tchangesCompilationFactory,\n\t\t\t\tchangesDeltaFactory,\n\t\t\t\tcollectionResourceFactory,\n\t\t\t\tcolumnCache,\n\t\t\t\tcolumnExpansionFactory,\n\t\t\t\tcolumnHandler,\n\t\t\t\tcolumnSetFactory,\n\t\t\t\tconversionMapService,\n\t\t\t\terrorHandler,\n\t\t\t\tgraphQueryParserFactory,\n\t\t\t\titemCacheFactory,\n\t\t\t\titemCreateService,\n\t\t\t\titemEntryService,\n\t\t\t\titemResourceFactory,\n\t\t\t\tlinkTreeService,\n\t\t\t\tlockService,\n\t\t\t\tmoduleChangesCompilationFactory,\n\t\t\t\tqueryService,\n\t\t\t\trequestColumnExpansionFactory,\n\t\t\t\trequestColumnsOperationsCacheFactory,\n\t\t\t\ttemplateCache,\n\t\t\t},\n\t\t\tapiFieldsOnDeleteRule,\n\t\t\tthis,\n\t\t);\n\n\t\tconst socketMessageHandler = new SocketMessageHandler(\n\t\t\tchangesDeltaFactory,\n\t\t\tcolumnCache,\n\t\t\terrorHandler,\n\t\t\trequestColumnExpansionFactory,\n\t\t\ttransactionCacheFactory,\n\t\t\tapiRequestService,\n\t\t\trequestColumnsOperationsCacheFactory,\n\t\t);\n\n\t\tthis.apiRequestService = apiRequestService;\n\t\tthis.apiResponseProcessorFactory = apiResponseProcessorFactory;\n\t\tthis.changesCompilationFactory = changesCompilationFactory;\n\t\tthis.changesDeltaFactory = changesDeltaFactory;\n\t\tthis.collectionResourceFactory = collectionResourceFactory;\n\t\tthis.columnCache = columnCache;\n\t\tthis.columnExpansionFactory = columnExpansionFactory;\n\t\tthis.columnHandler = columnHandler;\n\t\tthis.columnInfoFactory = columnInfoFactory;\n\t\tthis.columnSetFactory = columnSetFactory;\n\t\tthis.requestColumnOperationsCacheFactory = requestColumnsOperationsCacheFactory;\n\t\tthis.conversionMapService = conversionMapService;\n\t\tthis.itemCacheFactory = itemCacheFactory;\n\t\tthis.itemCreateService = itemCreateService;\n\t\tthis.itemEntryService = itemEntryService;\n\t\tthis.itemResourceFactory = itemResourceFactory;\n\t\tthis.lockService = lockService;\n\t\tthis.moduleChangesCompilationFactory = moduleChangesCompilationFactory;\n\t\tthis.queryService = queryService;\n\t\tthis.requestColumnExpansionFactory = requestColumnExpansionFactory;\n\t\tthis.socketMessageHandler = socketMessageHandler;\n\t\tthis.templateCache = templateCache;\n\t\tthis.transactionCacheFactory = transactionCacheFactory;\n\t\tthis.businessLogicManager = businessLogicManager;\n\t}\n\n}\n\nexport function identity<T extends any> (\n\tvalue: T,\n): T {\n\treturn value;\n}\n","import { untracked } from '@angular/core';\nimport moment from 'moment';\nimport { ApiRequestColumnArray, CollectionResource, RmCore } from '../internal';\n\nexport const HOLIDAY_ICON = 'beach_access';\n\nconst holidayColumns = [\n\t'id',\n\t'date',\n\t'name',\n\t'yearly',\n] as const satisfies ApiRequestColumnArray<'Holiday'>;\n\nexport type HolidayFields = {\n\tuid: `hol-${number}` | `hol-${number}-${number}`,\n\tname: string,\n\tdate: moment.Moment,\n};\n\n/**\n * A service handling 'Holiday' items.\n *\n * Note that methods querying the holiday items have a `rmCoreInstance` parameter. This is to accommodate the app, where\n * multiple users can be logged in simultaneously, each having a separate core instance. The `rmCoreInstance` parameter\n * is optional; when absent the first instance will be picked.\n *\n * Warning: for each core instance, the service should be initialized before querying the holiday items. It will throw\n * an exception otherwise.\n */\nexport class RmHolidaysService {\n\n\tprivate holidayCollectionResourcesMap: Map<RmCore, CollectionResource<'Holiday', typeof holidayColumns>> = new Map();\n\n\tpublic rangeContainsHoliday$ (\n\t\tstart: moment.Moment,\n\t\tend: moment.Moment,\n\t\trmCoreInstance?: RmCore,\n\t): boolean {\n\t\treturn !this\n\t\t\t.getHolidaysInDateRangeIterator$(\n\t\t\t\tstart,\n\t\t\t\tend,\n\t\t\t\trmCoreInstance,\n\t\t\t)\n\t\t\t.next()\n\t\t\t.done;\n\t}\n\n\tpublic getHolidaysInDateRange$ (\n\t\tstart: moment.Moment,\n\t\tend: moment.Moment,\n\t\trmCoreInstance?: RmCore,\n\t): HolidayFields[] {\n\t\treturn [\n\t\t\t...this.getHolidaysInDateRangeIterator$(\n\t\t\t\tstart,\n\t\t\t\tend,\n\t\t\t\trmCoreInstance,\n\t\t\t),\n\t\t];\n\t}\n\n\tpublic rangeContainsHoliday (\n\t\tstart: moment.Moment,\n\t\tend: moment.Moment,\n\t\trmCoreInstance?: RmCore,\n\t): boolean {\n\t\treturn untracked(\n\t\t\t() => this.rangeContainsHoliday$(\n\t\t\t\tstart,\n\t\t\t\tend,\n\t\t\t\trmCoreInstance,\n\t\t\t),\n\t\t);\n\t}\n\n\tpublic getHolidaysInDateRange (\n\t\tstart: moment.Moment,\n\t\tend: moment.Moment,\n\t\trmCoreInstance?: RmCore,\n\t): HolidayFields[] {\n\t\treturn untracked(\n\t\t\t() => [\n\t\t\t\t...this.getHolidaysInDateRangeIterator$(\n\t\t\t\t\tstart,\n\t\t\t\t\tend,\n\t\t\t\t\trmCoreInstance,\n\t\t\t\t),\n\t\t\t],\n\t\t);\n\t}\n\n\tpublic async initialize (\n\t\trmCoreInstance: RmCore,\n\t): Promise<void> {\n\t\tconst holidaysCollection = await rmCoreInstance\n\t\t\t.transactionCacheFactory\n\t\t\t.construct(\n\t\t\t\t'rm-holidays-service',\n\t\t\t)\n\t\t\t.getCollection(\n\t\t\t\t'Holiday',\n\t\t\t\t{\n\t\t\t\t\tquery: {},\n\t\t\t\t\tcolumns: holidayColumns,\n\t\t\t\t},\n\t\t\t);\n\n\t\tthis.holidayCollectionResourcesMap.set(\n\t\t\trmCoreInstance,\n\t\t\tholidaysCollection,\n\t\t);\n\t}\n\n\tpublic clear (\n\t\trmCoreInstance: RmCore,\n\t): boolean {\n\t\tthis.holidayCollectionResourcesMap\n\t\t\t.get(\n\t\t\t\trmCoreInstance,\n\t\t\t)\n\t\t\t?.transaction\n\t\t\t.destroy();\n\n\t\treturn this.holidayCollectionResourcesMap.delete(\n\t\t\trmCoreInstance,\n\t\t);\n\t}\n\n\tpublic* getHolidaysInDateRangeIterator$ (\n\t\tstart: moment.Moment,\n\t\tend: moment.Moment,\n\t\trmCoreInstance?: RmCore,\n\t): Generator<HolidayFields> {\n\t\tconst holidayCollection = this.getHolidaysCollection(\n\t\t\trmCoreInstance,\n\t\t);\n\t\t// We can do a fast 'in between' if we set `start` to the start of the day, and `end` to the end of the day,\n\t\t// (we only care whether holidays occur on a certain day).\n\t\tconst startTimestamp = start\n\t\t\t.clone()\n\t\t\t.startOf(\n\t\t\t\t'day',\n\t\t\t)\n\t\t\t.valueOf();\n\t\tconst endTimestamp = end\n\t\t\t.clone()\n\t\t\t.endOf(\n\t\t\t\t'day',\n\t\t\t)\n\t\t\t.valueOf();\n\t\tconst startYear = start.year();\n\t\tconst endYear = end.year();\n\n\t\tfor (const holidayResource of holidayCollection.itemsSignal()) {\n\t\t\tconst holidayId = holidayResource.fieldSignals.id();\n\t\t\tconst holidayDate = holidayResource.fieldSignals.date();\n\t\t\tconst holidayName = holidayResource.fieldSignals.name();\n\n\t\t\tif (!holidayResource.fieldSignals.yearly()) {\n\t\t\t\tif (\n\t\t\t\t\tholidayDate.valueOf() >= startTimestamp\n\t\t\t\t\t&& holidayDate.valueOf() <= endTimestamp\n\t\t\t\t) {\n\t\t\t\t\tyield {\n\t\t\t\t\t\tuid: `hol-${holidayId}`,\n\t\t\t\t\t\tname: holidayName,\n\t\t\t\t\t\tdate: holidayDate.clone(),\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// A range covering multiple years should be very rare, so there's no need to optimize for this.\n\t\t\tfor (let year = startYear; year <= endYear; year++) {\n\t\t\t\tconst holidayYearDate = holidayDate\n\t\t\t\t\t.clone()\n\t\t\t\t\t.set(\n\t\t\t\t\t\t'year',\n\t\t\t\t\t\tyear,\n\t\t\t\t\t);\n\n\t\t\t\tif (\n\t\t\t\t\tholidayYearDate.valueOf() >= startTimestamp\n\t\t\t\t\t&& holidayYearDate.valueOf() <= endTimestamp\n\t\t\t\t) {\n\t\t\t\t\tyield {\n\t\t\t\t\t\tuid: `hol-${holidayId}-${year}`,\n\t\t\t\t\t\tname: holidayName,\n\t\t\t\t\t\tdate: holidayYearDate,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic getHolidaysCollection (\n\t\trmCoreInstance?: RmCore,\n\t): CollectionResource<'Holiday', typeof holidayColumns> {\n\t\treturn rmCoreInstance === undefined\n\t\t\t? this.holidayCollectionResourcesMap\n\t\t\t\t.values()\n\t\t\t\t.next()\n\t\t\t\t.value\n\t\t\t: this.holidayCollectionResourcesMap.get(\n\t\t\t\trmCoreInstance,\n\t\t\t)!;\n\t}\n\n}"],"names":["root","factory","exports","module","require","define","amd","self","__WEBPACK_EXTERNAL_MODULE__174__","__WEBPACK_EXTERNAL_MODULE__860__","__WEBPACK_EXTERNAL_MODULE__416__","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","undefined","__webpack_modules__","n","getter","__esModule","d","a","definition","key","o","Object","defineProperty","enumerable","get","obj","prop","prototype","hasOwnProperty","call","r","Symbol","toStringTag","value","ALL_PERMISSIONS","COLUMN_SEPERATOR","ApiLinkTreeType","ItemEntry","itemType","itemId","columns","static","id","currentId","isLockableSignal","signal","this","isLockable","isLocalSignal","isLocal","outdated","updateId","newItemId","set","isOutdated","markOutdated","markUpToDate","KeyService","isLocalId","toJSON","ItemResource","entry","transaction","_isNew","fields","initial","fieldSignals","children","aggregatedChangesListeners","derivedFieldSignals","__computedFunctions","WeakMap","abortSignal","response","itemHandler","constructInitialProxy","constructFieldsProxy","constructSignalFieldsProxy","onConstruct","aborted","addEventListener","clearResource","computedSignal","functionReference","has","computed","getAggregatedChangesListeners","accumulator","Set","listener","add","clearChildCollections","clearItemResource","deregisterChangesListener","index","indexOf","splice","registerChangesListener","push","setChildCollectionResources","setParentItem","collectFields","setFields","values","columnId","errorHandler","logWarning","changesDelta","createChangesDelta","setItemUpdated","applyChangesDelta","then","copyFields","destination","columnIds","column","main","includes","ApiFormatter","clone","apiColumn","type","lookUpItemField","getParent","fromInitial","compareItemField","previous","Error","compareFields","hasChanges","detectEntryChanges","setTransactionParameters","parameters","createPath","tabRequestParameters","isNew","getDerivedSignal","pathInput","defaultValue","joinedPath","pathArray","split","join","itemEntry","i","length","getItemFieldSignal","resultValueSignal","core","columnCache","getColumn","ColumnUtil","isItemColumn","itemIdSignal","getLocalItemEntryByItemId","getDerivedValue","columnPath","getDerivedValues","CachedQueryItem","query","queryGraph","items","requestColumnsTuple","promise","creation","Date","deferred","promiseCreateDeferred","itemsResolved","resolve","reject","reason","handleMatchedItemEntries","fittingItemEntries","nonFittingItemEntries","fittingItemEntriesCopy","size","delete","fittingItemEntry","newItemEntries","CollectionEntry","queryService","options","parent","containsLocalId","object","expandColumns","columnExpansion","run","merged","request","ItemNotFoundException","itemTypeOrEntryId","super","CollectionResource","parentCollection","itemsSignal","parentItem","itemEntryIdMap","onChangeCallbacks","onAddCallbacks","onRemoveCallbacks","columnSet","registerOptionsChangesListeners","initializeItems","initialItemEntries","childCollectionResourceMap","itemResources","addItemResources","callOnAddWithInitialItems","triggerCollectionChangesListeners","addedItems","removedItems","clearCachedQueryOnTransaction","cachedQuery","cachedQueryHandler","getCachedQueryItem","string","itemResource","childItemType","refresh","transactionChain","getTransactionChain","cachedQueryItem","fetchCachedQuery","itemEntriesToBeRemovedSet","find","addedRemovedItemResources","updateItemsProperty","onAdd","callback","__registerCallback","onChange","onRemove","removeItems","idArray","removedItemEntries","setItemsDeleted","removeItem","addItems","valuesArray","parentFields","itemEntryService","getLinkFieldsByParent","setItemsCreated","addItem","getIdArray","map","getItemById","exception","changedItems","sourceChangesDelta","itemIdConversionMap","isCalledAfterSocketUpdate","isInitialCall","aggregatedListenerChangesAccumulator","collectionResource","error","logError","itemEntries","itemChangesListenerContexts","changedItem","itemEntryId","created","updated","CollectionItemChangesListenerContext","itemChangesListenerContext","changesListenerContext","aggregatedChangesListener","aggregatedChanges","item","collection","forEach","filter","result","first","some","groupBy","argument","itemsResources","Array","reduce","clearCollectionResource","clearChildCollectionResources","itemEntriesToBeAdded","changedItemResources","getCollectionItemEntryChanges","nonFittingItemEntry","removeItemResources","filteredItemResources","removedItemResources","cachedQueryItemTuples","__fetchChildCachedQueryItems","nonIncludedItemEntriesMap","Map","filteredCachedQueryItemTypeTuples","cachedQueryItemTypeTuple","filteredCachedQueryItemTuples","cachedQueryItemTuple","constructChildCollectionResources","childCollections","itemResourcesToBeAdded","createItemResources","__fetchParentItemEntriesByQueryData","requestColumnsOperationsCacheFactory","construct","changesListener","args","arr","compareNumberFn","value1","value2","Number","compareStringFn","localeCompare","getSortCompareFunction","apiType","ApiEnumApiType","TYPE_NUMBER","TYPE_DATETIME","TYPE_TIMESTAMP","TYPE_TIMESTAMP_MS","TYPE_DATE","TYPE_DURATION","TYPE_VOLUME","TYPE_WEIGHT","TYPE_DIMENSION","TYPE_PRICE","TYPE_DOUBLE","TYPE_INT","TYPE_CURRENT","TYPE_POWER","TYPE_DISTANCE","TYPE_ORDER","TYPE_TEXT","TYPE_LONGTEXT","TYPE_HTML","TYPE_TIME","OrderedCollectionResource","sortItemResources","getSortCompareTuple","orderOption","order","compareFunction","field","isDescending","sort","itemResourceA","itemResourceB","compareResult","sortItemEntries","itemEntryA","itemEntryB","LimitedCollectionResource","setLimit","newLimit","previousLimit","limit","increaseItemEntriesToBeAdded","limitItemEntriesToBeAdded","itemEntryChanges","applyAddedRemovedItemEntries","baseItemEntries","updatedItemEntries","slice","newAmount","excessItemEntries","itemEntriesToBeAddedCopy","itemEntriesToBeRemovedCopy","itemEntriesToBeAddedIndex","getDeletedItemsAmount","sortedItemEntries","newItemEntriesToBeAdded","numAdditionalItemsRequired","itemIsDeleted","Template","columnSetFactory","additionalResponseColumns","responseColumns","mergeResponseColumns","fetchColumnsObject","getFields","links","fetchObject","itemTypeColumns","isExpensiveFormat","ApiResponseProcessor","addLazyFormattingFunction","default","formatResponseValue","getLocalDefaultValues","getMainColumnSet","getColumnSet","constructFromResponse","findIndex","haystack","shallowMerge","defaults","hasProperties","getFirstProperty","inArray","needle","hay","pathExists","source","path","p","overwriteDestination","getPath","create","baseExtend","dst","objs","deep","ii","isObject","isFunction","keys","j","jj","src","isDate","valueOf","isRegExp","RegExp","nodeName","cloneNode","isElement","isArray","extend","merge","isBlankObject","getPrototypeOf","isString","isNumber","toString","isPromiseLike","promiseAllObject","promiseObject","promises","Promise","all","resolved","isBoolean","node","attr","isWindow","window","isDefined","equals","o1","o2","t1","keySet","getTime","b","copy","maxDepth","stackSource","stackDest","isValidObjectMaxDepth","NaN","copyRecurse","copyElement","_source","_destination","_maxDepth","needsRecurse","constructor","buffer","byteOffset","copied","ArrayBuffer","byteLength","Uint8Array","re","match","lastIndex","copyType","columnType","formatRequestLocal","readOnly","formatRequestValue","shallowCopyFields","onMissingColumn","desc","getOwnPropertyDescriptor","setDefaultValues","second","compareMomentObjects","compareDurations","compareFloats","absA","Math","abs","absB","diff","EPSILON","MIN_VALUE","min","MAX_VALUE","isValid","isSame","asMilliseconds","formatResponseDate","formatResponseColor","formatResponseDuration","JSON","parse","formatRequestDateTime","formatRequestDate","formatRequestColor","formatRequestDuration","startsWith","format","SERVER_DATETIME_FORMAT","SERVER_DATE_FORMAT","asSeconds","substring","getDefaultValue","hasValue","isNaN","isDefaultValue","cloneDuration","getCloneFunction","cloneDate","identity","duration","date","input","ApiRequestService","externalApiRequestService","apiResponseProcessorFactory","template","params","processResponse","parentType","parentId","uniqueTransactionId","itemIds","updateItems","requestSkeleton","requestCanceler","method","_module","cacheable","columnIndexMap","columnMap","createColumnMaps","replaceTempItemTypeIdsWithLocalIds","initialValue","configurable","fetchColumnObject","fetchDerivedValue","initialItemId","fetchValue","data","fetchColumnArray","fetchDerivedObject","rootColumns","fetchDerivedValues","childColumn","childValue","isLeaf","fetchObjectArray","TempItemTypeWithoutFixedIds","newLocalIds","newLocalItemId","getLocalId","ChangesCompilation","compilation","update","processDelta","getDelta","deleteTuple","getDeleteTuplesIterator","isCascaded","addDeleteEntry","tuple","addCreateEntry","addUpdateEntry","getDefaultParent","createDelta","ChangesProcessor","apiRequestService","changesCompilationFactory","changesDeltaFactory","requestBufferManager","requestColumnExpansionFactory","breakUpByParent","onAfterCreateCallback","serverCache","getServerCache","execute","changesCompilation","suspendRequests","crypto","randomUUID","executeCreateRequests","executeUpdateRequests","executeDeleteRequests","finally","continueRequests","getMapValue","requests","CreateRequest","responses","executeCreateRequest","requestResource","directRequestItemsMap","parseInt","setItemDeleted","localItemEntry","entries","itemChanges","copyTransactionItemEntryChanges","clearByItemId","executeUpdateRequest","requestColumns","formattedValues","formatRequest","itemRequest","expandWithColumnSet","apiRequestColumns","requestItemType","executeDeleteRequest","constructParentDelta","responseIdArray","applyChangesFromParent","ColumnCache","cache","pendingCache","allColumns","setColumn","responseColumn","setColumns","columnFilter","responseType","setPendingColumn","clearPendingColumns","columnIdOrDerivedObject","parsedRequestColumn","parseRequestColumn","setPendingColumns","retrieve","containsAll","cached","getColumns","missing","pending","responseAccumulator","requestAccumulator","pendingAccumulator","retrieveColumns","retrieveColumn","requestColumn","pendingColumnPromise","missingDerived","ColumnExpansion","columnInfoFactory","expansionMap","requestColumnsTrue","requestColumnArray","columnSetId","expand","aggregateRootColumns","rootColumnMap","difference","expandRootColumnMap","constructFromRootMap","ColumnHandler","fetchItemTypeTranslations","itemTypes","fetch","responseColumnArray","name","columnResource","fetchAll","fetchEditableCustomColumns","isCustomColumn","hasLocationProperty","API_COLUMN_LOCATION","EDIT","ColumnInfo","level","tailPath","toRequestColumns","flatMap","c","setChildren","ColumnSet","link","searchable","derived","custom","leaf","filtered","groupColumnInfo","columnInfo","isDerived","targetProp","TYPE_LINK","isFilteredColumn","isSearchableColumn","isSupersetOf","columnsToCompare","columnsToCompareTrue","containsColumn","mergeRequestColumns","mergedRequestColumns","mergedResponseColumns","constructFromRequest","RequestColumnsOperationsCache","aggregateColumnsTuple","expandedRequestColumnsTuple","columnsMergedWithTupleMap","expandedColumnsMergedWithTupleMap","setContainsAllColumnsMap","setContainsAllExpandedColumnsMap","createRequestColumnsTuple","copyRequestColumns","getRequestColumnsTuple","transactionCache","ServerCache","expandColumnsWithRequiredColumns","getAggregateColumns","extractAggregateColumns","hasAggregateColumns","getColumnsMergedWithTuple","requestColumnSetId","mergeColumnsWithTuple","tupleContainsAllColumns","setContainsAllColumns","innerRequestColumnsTuple","mergedColumns","parsedColumn","isAggregateColumn","childAggregateColumns","createRequestColumnSetId","isStringColumn","isFloatColumn","isIntColumn","isNumberColumn","fieldtype","includeId","isDateColumn","isRenderedColumn","generator","location","isEditableColumn","getComparators","columnIndex","findRequestColumn","containsDerivedColumns","responseColumnsAvailable","responseColumnMap","copyRequestColumn","addedColumn","mergeRequestColumn","addedColumns","createRequestColumnId","getRequestColumnId","mergeResult","mergeResponseColumnMap","requestColumnToPath","childRequestColumnSetId","ConversionMapService","createLocalConversionMap","rootItemType","rootLocalItemId","apiResponse","linkItemType","expandLocalConversionMap","expandConversionMap","conversionMap","conversionMapEntry","batchExpandConversionMap","getConversionValue","updateItemValues","itemColumns","newValue","apiItemIds","firstLocalItemId","apiItemId","IS_IN_TEST","breakupByParent","finalizeRequest","setRequestParent","requestEntry","parentMap","initializeRequest","extendRequest","hasParent","validRequest","requestType","itemValues","requestParentId","itemEntryMap","internalCreateDelta","childEntries","childType","childId","ItemCache","graphQueryParserFactory","entriesByEntryId","getByEntryId","containsByEntryId","getByItemType","getByQuery","leafNode","matchesAccumulatorTuple","matchItemsToQueryGraph","from","true","getLocalByQuery","localItemEntries","getByParent","iterator","toArray","contains","updateItemId","oldItemId","entryMap","clear","ItemEntryService","userId","linkTreeService","matchParent","oldParent","newParent","linkTree","linkTreeEntry","itemtype","getParentByFields","DIRECT","getFullName","firstName","infix","lastName","namePart","trim","getTitleField","permissions","creator","getCssKey","NEW_PREFIX","incrementIdCounter","isNewId","idCounter","TransactionEventHandler","callbacks","onBeforeSave","onSaveSuccess","onRootItemDelete","registerCallback","condition","priority","getPriorityLevel","executeCallbacks","closeTab","priorityLevels","chain","priorityLevel","executeCallbacksPriorityLevel","destinationPriority","newPriorityLevel","callbackEntry","e","LockService","lockItems","getLocksSignal","asReadonly","getLocks","untracked","hasLock","lockTokenId","lockItem","isRemoteLock","isLocked","getValue","getMessage","message","fetchLock","lock","requestLock","deleteLock","doDeleteLock","cachedLock","clearLock","resolvedLock","token","Locktoken","setToken","code","isForeign","setPromise","EMPTY_ENTRY","ModuleChangesCompilation","itemsMappedOnParent","process","rootItem","constructChildItemMap","processItems","linkTreeNode","deletedEntries","TransactionCache","deletedItemsIterator","getDeletedItemsIterator","deletedItemEntry","childItemEntries","childItemEntry","linkAccumulator","processItem","childItems","getItemsByParent","hasValues","hasLinks","OPPOSITE_COMPARATOR_MAP","QueryParserBase","normalizeOperator","operator","isLinkedToQuery","linkedTo","isCustomQuery","isSearchQuery","search","isQueryWithConditions","conditions","isSubQuery","parseQuery","subQueryDepth","parseLinkedToQuery","reverse","not","parseCustomQuery","parseSearchQuery","parseComplexQuery","parseSubQuery","queryConditionComparator","_parseSimpleQuery","parseEmptyQuery","comparator","parseInQuery","parseComparatorQuery","QueryNode","TOKEN","addBranchNode","destinationQueryNodeTuple","branchNodeMap","existingNode","copyEdgesFrom","matchQueryNodes","queryNodeTuple","matchKey","getField","parentMatch","matchesAccumulator","leafNodes","maybe","child","cloneQueryNodesInto","sourceQueryNodeTuple","modifyLeafNodeTuple","sourceBranchNodeMap","destinationBranchNodeMap","_updateLocalItemIdReferences","branchNode","updateLocalItemIdReferences","ValuelessEdgeQueryNode","connectedNodesTuple","connectLeafNode","nodeToConnect","connectBranchNode","sourceNode","NonMatchableQueryNode","apiQuery","_parentMatch","CustomQueryNode","unsupportedQueryValue","numberValueTransformer","queryToEdgeValue","queryValue","fieldToEdgeValue","fieldValue","edgeToEdgeCompareValue","edgeValue","stringNullValueTransformer","toLowerCase","numberBooleanNullValueTransformer","dateNowValueTransformer","dateNullValueTransformer","durationValueTransformer","ComparatorQueryNode","valueTransformer","edgeMap","findValueTransformer","valueTransformers","transformedValue","getQueryNodeTuple","sourceEdge","oldValueString","oldValue","edge","getValues","matchUndefinedValue","GreaterSmallerThanComparatorQueryNode","compareValue","getCompareFunction","isSupportedComparator","transformedFieldValue","isComparatorQueryNodeValueTransformers","IsComparatorQueryNode","LinkedToQueryNode","NotIsComparatorQueryNode","RootQueryNode","connectionNodesTuple","doMatch","SearchQueryNode","SubQueryNode","comparatorNodeClasses","GraphQueryParser","queryId","rootNode","parsedQuery","createLinkedToComparatorQueryNode","mainItemType","linkedToItemType","leafNodeTuples","itemComparatorNode","leafNodeTuple","ITEMTABLE","queryNode","comparatorNodeClass","valueTransformerCandidate","every","comparatorQueryNode","rootNodeInstance","branchNodeInstance","parsedSubQuery","parsedConditions","rewriteOrConditions","rewrittenConditions","rewriteAndConditions","newAccumulator","conditionNode","accumulatorNode","filteredConditions","parsedCondition","flat","QueryColumnExtractor","_not","subItemColumns","_value","_query","getColumnsFromLink","_operator","parseConditions","concat","QueryContainsLocalIdParser","_key","_itemType","_field","val","_linkedTo","_reverse","QueryParser","formatStringParameters","formatValue","processedValue","processValue","compareParsedQueries","isLocallyMatchable","formattedValue","parsedParameters","parseCustomParameters","QueryParserIdUpdater","_comparator","queryPart","res","QueryService","addAndCondition","isEmptyQuery","addOrCondition","addParentCondition","linkedToQuery","createNotIn","RequestColumnExpansion","columnSetIdMap","requestColumnSetIdMap","expandWithRequestColumnsTuple","expandWithRequestColumns","SocketMessageHandler","transactionCacheFactory","logPrefix","RequestBufferManager","onMessagesReceived","messages","flushTimeout","changesAccumulator","activeItemEntries","getActiveItemEntries","messageBody","body","eventType","processMessage","handleDelete","processRequests","refreshItemsOfType","allActiveItemEntries","itemEntriesOfType","inactiveItemEntryCount","cachedQueries","getCachedQueryItemsByItemType","activeCachedQueries","inactiveCachedQueryCount","hasActiveCollectionsForQuery","logDebug","expandColumnExpansionWithRequiredColumns","columnsOperationsCache","fetchByIds","fetchByQuery","socketMessageBody","containsLocalItemEntryByItemId","getDeletedItemEntriesIterator","addQueryItemType","itemIdString","logFetchedItems","requestIds","processSocketMessageValues","socketMessageValuesTuples","fieldsArray","socketMessageItem","aggregateCachedRequestColumns","getMergedQueryGraphTuple","mergedQueryGraph","getMergedQueryGraph","uncachedCollectionsIterator","getUncachedCollectionsOnChildTransactionsIterator","uncachedCollectionResourceMap","queryString","collectionResources","collectionResourceMap","matchSocketMessageItems","fieldsToMatch","isCreate","matchedFields","mergedQueryGraphTuple","matchedItemEntries","active","inactive","matchedCachedQueryItems","matchedUncachedCollections","matchesAccumulatorEntry","fieldsSet","cachedQueryItems","uncachedCollections","fieldsArrayTuple","matchedItems","itemUpdateModeMap","processResponseByItemType","inactiveCachedQueryItem","markCachedQueriesOutdatedInAllTransactions","inactiveItemEntry","settledPromises","allSettled","settledPromise","status","nonLocallyMatchableQueryString","_setQueryResult","AbstractCache","dependencies","getDescendantsIterator","onChildDestroy","includeServerCache","transactions","getCurrentItemEntryCache","clearItemEntry","clearLinkedCachedQueryItems","getLocalItemEntryChangesTuple","getLocalItemEntry","changes","getParentFromFields","processCreatedItem","createItemEntry","existingItemEntry","columnExpansionFactory","remove","fetchUpdatedDerivedValuesFromDelta","derivedPromises","changedRootColumns","cachedFieldValue","updatedValue","resolveDerivedValues","handleCascadingDeletes","getDeletedItemTypesIterator","influencedItemTypes","ApiFieldsOnDeleteRule","foreign","deletedItemEntriesIterator","influencedItemType","cascadeDeleteByItemType","linkColumnId","parentItemId","rule","own","onDeleteRule","currentParentItemId","ChangesDelta","ParentChangesDelta","ChildChangesDelta","setItemDeletedCascaded","apiFieldsOnDeleteRule","onDeltaAppliedCallbacks","ServerItemHandler","itemCacheFactory","ServerCachedQueryHandler","onDeltaApplied","createChild","validatorFactory","activeItemResourceTuple","itemResourcesPerEntry","itemResourceRef","deref","collectActiveItemEntriesBasedOnParentEntry","responseItems","convertedItemId","_setItemCreated","requestColumnMap","responseColumnsObject","parentChangesDelta","processUpdatesFromDelta","matchingResults","matchItemsToCollectionQueries","_queryItemTypeSet","applyMatchingResultsToCachedQueries","childTransaction","callOnDeltaAppliedCallbacks","getCollectionChangesRecursively","applyChangesFromChild","depenencies","isEmpty","allChildrenDonePromise","createdEntries","setItemCreated","requestColumnExpansion","uncachedCollectionResources","getColumnIdsWithRelations","onDeleteColumns","delta","itemLikeColumns","activeItemEntryAccumulator","parentColumn","derivedItemId","derivedItemEntry","MatchesAccumulatorMap","ItemMatcherBase","addItemsToMatchingResults","matchingResultsAccumulator","isMatchKey","matchingResultsTuple","itemSet","matchItemsInDeletedChangesDelta","matchingResultsAccumulatorMap","matchesAccumulatorMap","constructGetField","matchesAccumulatorMapEntry","matchEmptyItemsInUpdatedChangesDelta","updatedChangesDelta","matchItemsInUpdatedChangesDelta","current","previousValue","updatedMatchesAccumulatorEntry","updatedMatchesAccumulatorTuple","currentMatchesAccumulatorEntry","currentMatchesAccumulatorTuple","matchItemsInCreatedChangesDelta","createdChangesDelta","fieldsProxyHandler","target","property","getDisplayName","fieldsSignalProxyHandler","ItemHandlerBase","itemFieldSignals","cachedSignal","Proxy","t","refreshAggregateColumns","childItemEntriesPromises","filteredRootColumns","rootColumn","childColumns","itemIdSet","fetchItemEntryData","childItemEntriesArray","childColumnPromises","derivedItem","getDerivedEntry","derivedEntry","getDerivedColumn","createTuple","itemFieldLastModified","modifiedMoment","modified","forceRequest","requestItemIds","isTempItemType","forceFlush","requestItemId","processItemEntryChanges","mode","itemEntryChangesTuple","changedFields","columnExpansions","localChanges","responseModified","fieldLastModified","oldId","CachedQueryHandlerBase","collections","createQuery","limitToItemTypes","processEmptyUpdates","mergedQueryGraphs","limitToItemType","_queryResults","promiseAccumulator","matchingResultsMapEntry","matchingResultsEntry","processMaybeMatches","false","setCachedQuery","getOrCreateCollectionTuple","constructCachedQuery","__fetchCachedQueryItem","createQueryFromOptions","expandColumnsWithQueryColumns","__fetchItemEntriesByQueryData","collectionsforItemType","cloneCachedQuery","clonedCacheQueryItem","clearCachedQueryItem","clearCollectionTupleIfEmpty","linkTreeBranch","linkedItemType","cachedQueriesForItemType","fieldQuery","linkedToQueryString","fieldQueryString","queryResults","queryGraphs","getQueryGraphsForItemType","idQueryNode","getCollectionQueries","getCachedQueryItemIterator","queryIsCacheable","preventCaching","collectionsForItemType","collectionTuple","collectionQueries","queryResult","_getQueryResult","next","createQueryGraph","collectionIterator","getCollectionResources","_collectionResource","invalidateCachedQuery","processChildTransactions","transactionsAccumulator","accumulateTransactions","getUncachedCollectionsIterator","__maybeExpandCachedQuery","batchedLinkedToQuery","collectionQuery","linkCollectionBatchQueryTuple","fakeCachedQuery","batchQuery","batchQueryGraph","TransactionPendingException","TransactionErrorLevel","errors","global","firstError","globalErrors","errorKey","allItemErrors","itemErrors","columnErrors","firstErrorString","rootItemSignal","hasChangesSignal","eventHandler","validator","validatorWithDependencies","changesDeltasBeingApplied","transactionStateSignal","isSavingSignal","isReadySignal","isPendingSignal","isDestroyedSignal","isValidSignal","transparent","TransactionItemHandler","TransactionCachedQueryHandler","isSaving","isReady","attachValidator","ItemChangesListenerContext","addCollection","childCollectionItemType","validate","isPending","setPending","destroy","lockService","isDestroyed","expandCollectionResource","newColumns","expandCollectionResources","optionsTuples","batchQueryTuple","createBatchLinkedToQuery","optionsTuple","registerFieldChangeCallback","logMissingColumnErrors","getFirstErrorString","_setGlobalError","isInvalid","saveButtonErrorTranslationFn","clearGlobalError","_setItemError","fieldErrorTranslationFn","clearItemError","fieldString","newParentChangesDelta","stringOldId","newId","removeFromDeletedItems","collectionResourceChanges","applyMatchingResultsToCollections","runChangesListenersAndValidators","detectChanges","validateTransaction","changesDeltaPromise","doApplyChangesDelta","trackChangesDeltaBeingApplied","getRootTransaction","parentCachedQueryItem","save","_itemIdConversionMap","catch","ItemLockedException","force","clearItem","onRootItemDeleted","getModuleChanges","moduleChangesCompilationFactory","updateItemIdMap","collectionMap","getLinkCollections","linkType","linkIdArray","columnSetMap","collectionResourceFactory","constructColumnSet","cachedQueryItemTree","getCollection","__fetchParentCachedQueryItem","maybeCallInitialChangesListener","getNewResourceWithId","returnLinks","isRoot","changedDeltaResult","childCachedQueryItems","fetchNewItemEntry","mainEntry","linkedEntriesMap","createItemResource","linkedResources","processLinkedItems","linked","getNewResource","getItemsByQuery","getItemsById","fetchItemEntries","fetchItemEntry","fetchTitle","childCachedQueryItem","childChangesDelta","constructChildDelta","getItemEntriesWithChangesIterator","deletedItems","deleteEntry","childCollectionMap","itemResourceFactory","registerItemResource","linkedEntries","businessLogicChangesDelta","businessLogicManager","handleBusinessLogic","expandLocalItemsFromDelta","restored","addToDeletedItems","updateSignals","collectionResourceChangesTuple","signals","validateItem","notifyError","fieldChangeCallbacks","aggregatedListeners","getItemResources","firstItemResource","context","compareField","bind","aggregatedListenerChangesAccumulatorEntry","removedItemResource","itemEntriesPerItemTypeMap","columnsPerItemTypeMap","expandLocalItemEntries","immediatelyCallChangesListener","addCollectionAndChildren","addItemResourceAndChildren","listenerSet","initialProxyHandler","targetItemHandler","WeakRef","cleanUpStaleResources","itemResourceRefs","hasStaleResources","cleanUpItemResourcesForEntry","newRefs","deletedItem","deletedItemsForItemType","createItemChangesIfNoneExist","_","cloneItemEntries","modifyFieldsCallback","conversionMapService","cloneItemEntry","sourceEntry","sourceEntryChanges","fieldsCopy","ItemAlreadyExistsException","defaultValues","templateCache","fetchTemplate","templateOptions","itemCreateService","processTemplate","itemTypeRequestMap","createdItemType","columnItemType","rquestColumnsAndIdsTuple","requestColumnsAndIdsTuple","serverItemCache","itemIdsToDeferToParent","localItemIds","serverItemEntry","fetchLocalItemEntryData","parentItemEntries","parentItemEntry","titleField","columnExpansionResult","deletedEntry","resource","resourceRefsForEntry","newResourceRefsForEntry","resourceRef","previousInherited","isLocalEntry","parentValue","newValueEqualToParentValue","itemEntriesToExpand","columnDifference","columnHandler","collectionResourceRefs","collectionResourceRef","cleanUpQueryString","addCollectionResource","cleanedUpResources","updateQueryLocalItemIdReferences","parentCachedQueryHandler","collectionResourcesIterator","getCollectionResourcesByTuple","newParentId","mergeColumnsAndExpandLocalItems","resolveLocalCachedQueryItem","createdCachedQueryItem","__fetchLinkedCachedQueryItems","linkCollectionOptionsTuple","collectionQueryTuples","collectionQueryTuple","parentItemType","parentItemIds","additionalQuery","processLinkCollectionOptions","firstOptions","clonedOptions","cloneOptions","additionalQueryGraph","childCollectionOptions","childLinkCollectionOptionsItemTypeTuples","linkCollectionOptions","fetchChildCachedQueryItems","resolveParentCachedQueryItems","childrenClone","linkCollectionOptionsItemTypeTuples","cachedQueryItemOptionsTuples","didAlreadyClearResourceRefs","shouldCleanUp","updatedQuery","generationItemIds","generationItemIdsFlat","childCachedQueryItemsItemTypeTuples","childCachedQueryItemsItemTypeTuple","childCachedQueryItemTypeTuples","childCachedQueryItemTypeTuplesIndex","numItemEntries","localCachedQueryItem","syncCachedQueryWithLocalItems","getLocalItemEntries","matchItemEntriesWithChangesToCachedQuery","itemEntriesWithChanges","deletedItemEntries","accumulatorTuple","itemEntriesToAdd","filteredResources","TransactionValidatorBase","lastCallIdMap","_lastCallId","setItemError","hash","getHash","deleteLastCall","lastCallId","setLastCall","isInvalidResult","isLastCall","setGlobalError","newMap","TransactionValidator","hasFields","TransactionValidatorWithDependencies","ChangesDeltaBase","deleted","queryItemTypes","getUpdatedValue","hasDeletedItem","hasUpdatedValue","deletedItemType","deletedMap","deletedTuple","setItemDeletedByTuple","deletedTuples","MissingColumnException","CreatedChangesDelta","getCreatedTuplesIterator","getTuplesIterator","getUpdatedTuplesIterator","otherChangesDelta","newChangesDelta","setItemRestored","createItemsFromValues","setItemCreatedByTuple","itemCreateTuple","updatedFields","entryId","updateDelta","expansion","__isCascaded","isApiResponse","transactionItemEntryChanges","defaultRequestBufferOptions","RequestBufferBase","createdDate","now","flush","onBufferFlushed","executeQuery","getPromise","acceptsRequestColumns","bufferRequestColumns","compareApiRequestLimit","limitA","limitB","RequestBuffer","contents","queries","singleItemIds","constructWithSingleItems","_addSingleItems","constructWithQuery","_addQuery","addSingleItems","addQuery","createAggregateQuery","SingleQueryRequestBuffer","pendingBufferMap","requestsSuspended","flushPendingBuffers","partialOptions","processOptions","pendingBuffers","pendingBuffer","addBuffer","setTimeout","currentDate","remainingPendingBuffers","ItemCreateService","filterItemEntryCallback","itemIdConversion","processTemplateLinkItems","localParentId","createEntries","_parentType","_localParentId","apiParentId","localItemId","tuples","foundTuple","done","tuplesEntry","forEachOfItemType","getTupleByItemId","matchTuplesToQueryGraph","TemplateCache","pendingTemplateBufferMap","templateResponses","templateRequestColumns","entryParentOrParentItemType","templateResponse","hasTemplateOptions","templateResponsePromise","fetchTemplateById","responseItemType","requestColumnItemType","expandWithDefaultRequestColumns","expandWithLinkedItemTypesDefaultColumns","templateRequestColumnItemTypeMap","resolvedColumnsArray","resolvedColumns","childItemTypes","constructTemplateBuffer","previousProxyHandler","ItemChangesListenerContextBase","partialPrevious","_previous","includeItemIdConversion","updatedTuple","BusinessLogicRuleContextBase","previousChangesDelta","mergedChangesDelta","getLatestValue","isUpdatedLatestItem","latestItem","fetchLatestItemsByParent","constructLatestItems","fetchUpdatedLatestItemsById","requestColumnOperationsCacheFactory","fetchLatestItemsById","itemsIdsOnTransaction","createdTuple","BLR_SKIP_RULE","BLR_CONTINUE_WITH_DEFAULTS","BLR_ABANDON_CHANGES","BusinessLogicRule","locals","hasFlag","confirm","postDependencyConfirm","BusinessLogicRuleConditionContext","fieldChanged","getItemIdsWithUpdatedField","updatedIterator","getItemIdsWithFieldUpdatedTo","BusinessLogicRuleApplyContext","destinationChangesDelta","setUpdatedValue","currentValue","businessLogicRule","__name","__decorate","decorators","arguments","Reflect","decorate","dependencyColumns","RecurrentItemRecureindBusinessLogicRule","toField","recurHoeChanged","recurPeriodeChanged","dependency","recurrentItemIds","apply","recurrentItemResources","recurrentItemResource","recurHoe","momentUnit","convertRecurhoeToMomentDuration","recurPeriode","sensibleRecurEind","startOf","isAfter","recureind","recurrenceDurationUnit","AfspraakRecureindBusinessLogicRule","BeschikbaarheidRecureindBusinessLogicRule","ADDRESS_FIELDS","ADDRESS_PREFIXES","ContactAddressBusinessLogicRule","contactIds","prefix","addressField","contactResources","prefixes","contactResource","addressEqualsVisitingAddress","CustomFieldLinkedItemTypeBusinessLogicRule","functionIds","customFieldResources","customFieldResource","defaultvalue","CustomFieldTypeBusinessLogicRule","typeValue","attributes","itemTypeFieldMap","Offerte","opdrachtgever","Contract","Factuur","Project","locatie","Subproject","Inhuur","leverancier","ProjectRequest","aanvrager","DefaultContactPersonUpdateBusinessLogicRule","columnIdMap","conditionResult","mapObj","contactId","contactMap","acc","dependencyResult","personColumnId","contactpersoon","documentTypes","DocumentTemplateBusinessLogicRule","itemIdMap","filename","betreft","ExemplaarAanschafdatumBusinessLogicRule","exemplaarIds","exemplaarResources","exemplaarResource","actief","ExemplaarBarcodeDeleteBusinessLogicRule","barcodeResources","FactuurBetalingsconditieBusinessLogicRule","fieldResult","factuurResources","factuurMap","paymentConditionId","defaultPaymentConditionId","stateResource","betalingsconditie","paymentConditionIds","Betalingsconditie","betalingsconditieResource","deps","factuurResource","newBetalingsConditie","vervaldatum","datum","dagen","FactuurDatumBusinessLogicRule","factuurIds","paymentConditionResources","schemaId","latestTaxSchemaByDateMap","latestTaxSchemasByDateMap","factuurId","taxschema","newDatum","latestBelatingconditie","betalingconditieDays","FactuurNumberseriesBusinessLogicRule","nummer","filesColumns","FilesNameExtensionBusinessLogicRule","getExtension","str","lastIndexOf","fileIds","fileResources","fileResource","previousExtension","newExtension","FunctieNaaminternBusinessLogicRule","functionResources","functionResource","naamintern","FunctieRecureindBusinessLogicRule","FunctieTwowayBusinessLogicRule","afstand","FunctiegroepSubprojectBusinessLogicRule","changedFieldTuple","functiegroep","functionResourcesArray","commonEquipmentColumns","AantalBusinessLogicRuleBase","createChangesTuple","materiaal","updatedItemResources","materiaalIds","materiaalTypeMap","getMateriaalTypeMap","createdTuples","changedResource","newQuantity","isInteger","aantal","ceil","createdItem","equipmentResources","equipmentResource","InhuurmateriaalAantalBusinessLogicRule","CriticalBusinessLogicRuleException","plannedEquipmentColumns","subhireEquipmentColumns","AantaltotaalBusinessLogicRuleBase","_transaction","affectedEquipmentItems","equipmentGroupIdSet","affectedEquipmentItem","groupingProperties","itemsInAffectedGroupsMap","affectedEquipmentItemsById","affectedEquipmentItemsByParent","itemsInAffectedGroups","itemInAffectedGroup","siblingItems","rootItemIds","currentItem","equipmentIsPhysicalMap","fetchEquipmentIsPhysicalMap","rootItemId","updatePlannedEquipmentItem","equipmentIdSet","expandEquipmentIdSet","equipmentId","latestEquipmentItem","is_physical","quantityFactor","newTotalQuantity","newTotalQuantityCeiled","aantaltotaal","newQuantityFactor","InhuurmateriaalAantaltotaalBusinessLogicRule","MateriaalBulkToSerialBusinessLogicRule","remoteMateriaalIds","materiaalId","remoteVoorraadmutatiePromise","materiaalResources","containerContentResources","remoteVoorraadmutaties","equipment","voorraadmutatieTuples","remote","local","MateriaalIsCombinationBusinessLogicRule","equipmentIds","package","setinhoudResource","setinhoudEntries","materiaalColumns","MateriaalIsPhysicalCombinationBulkBusinessLogicRule","can_edit_content_during_planning","MateriaalSerialToBulkBusinessLogicRule","MateriaalToPhysicalBusinessLogicRule","hasFlexibleCombinationInPlanningFlag","materiaalResource","MateriaalToVirtualBusinessLogicRule","MateriaalTypePropertiesBusinessLogicRule","equipmentIsPhysical","MateriaalVerhuurBusinessLogicRule","is_combination","SurfaceArticleSizeBusinessLogicRule","oppervlakteartikel","height","width","newWidth","newHeight","newFields","sizeUnit","units","dimension","findDimensionText","newDimensionText","test","naam","replace","previousSurface","currentSurface","priceColumnId","LINKED_TIME_ITEM_TYPES","nonReferenceProperties","timeColumnDefinitions","schema_gv","TYPE_ITEM","start","opposite","plan","isStart","schema_gt","schema_pv","usage","schema_pt","gebruikvan","scheme","gebruiktot","planvan","plantot","schema_pv_begin","TYPE_BOOL","schema_pt_begin","schema_gv_begin","schema_gt_begin","duur","timeframe","TimeColumnUtil","isTimeColumn","getColumnInstance","columnInstances","columnDefinition","getColumnIdIterator","getColumnIds","getDefaultValues","usageFields","van","tot","planFields","cloneValues","compareValues","fieldsA","fieldsB","LinkedTimeItemBusinessLogicRuleBase","conditionColumns","extractCreatedTuples","extractUpdatedTuples","MateriaalCat","Functie","Functiegroep","extractUpdatedTuplesCondition","fetchLinkedItemResourcesWithColumns","updatedTuples","requestColumnsMap","conditionResultElement","fetchLinkedItemResources","LinkedTimeItemDurationBusinessLogicRule","usageStartValue","usageEndValue","timeScheduleFieldInformation","related_schema_field","related_schema_time_field","timeScheduleFieldInformationColumnIds","changedMateriaalCatResourceColumns","LinkedTimeItemMateriaalCatBusinessLogicRule","changedMateriaalCatItemIds","changedResources","materialCatResource","timeEntryValue","timeEntryItemId","schemeValueColumnIds","schemeValueTimeFrameColumnIds","LinkedTimeItemSubprojectBusinessLogicRule","linkedItemResources","timeItemResources","extractTimeItemIds","validateLinkedTimes","_dependency","linkedTimeItemType","schemeValueColumnIdArrayToFieldMap","invalidTimes","linkedTimeItemResourceMap","createdTupleMap","getInvalidTimeColumnIds","getCreatedItemTimeIdIterator","getUpdatedItemTimeIdIterator","timeSubprojectTuples","timeSubprojectTuple","timeResource","timeId","timeSubproject","subproject","is_absolute_times_substitute","project","projectId","subprojectId","itemResourceMap","timeIdIterator","valueColumnIds","schemeStartColumnIds","timeColumns","LinkedTimeItemTimeSchemeBusinessLogicRule","timeResources","linkedTimeItemResources","getTimeItemIds","columnInstance","schemeStartValue","timeItemId","LinkedTimeItemTimeSchemeStartBusinessLogicRule","schemeValueStartColumnIds","_dependencies","oppositeColumnId","schemeValueEndColumnIds","LinkedTimeItemTimeValueStartBusinessLogicRule","valueStartColumnIds","oppositeColumnInstance","previousOppositeValue","OfferteContractDatumBusinessLogicRule","State","geldigheidofferte","PlanningmateriaalAantalBusinessLogicRule","PlanningmateriaalAantaltotaalBusinessLogicRule","childPlanningmateriaalColumns","changedPlanningMateriaalColumns","PlanningmateriaalOptieBusinessLogicRule","changedPlanningmateriaalIds","changedPlanningmateriaalResources","categoryIdSet","changedPlanningmateriaalResource","categorie","childPlanningmateriaalResourcesInCategories","updatePlanningmateriaalByParent","parentPlanningmateriaalId","planningmateriaalResource","optie","planningmateriaalColumns","setcontent","PlanningmateriaalParentBusinessLogicRule","planningmateriaalIds","planningmateriaalResources","planningMateriaalColumns","projecttype","PlanningmateriaalStaysAtLocationBusinessLogicRule","createdItems","changedPlanningMateriaalResources","stays_at_location","projectType","START","planning","travel","factor","END","TRAVEL_TIME_COLUMNS","geen","heen","terug","retour","PlanningPersoneelTransportBusinessLogicRule","Planningpersoneel","Planningtransport","functionId","functie","planningResource","updatePlanningColumns","vervoer","travelTimeColumns","functionFields","planningTime","projectColumns","subprojectColumns","clientColumns","fieldMap","factuurmoment","personeelkorting","transportkorting","verkoopkorting","verhuurkorting","totaalkorting","verzekering","ProjectClientChangedBusinessLogicRule","clientId","hasEqualValues","valuesEqual","noEqualValuesArray","projectClientIds","projectResource","subprojectCollection","clientResource","setValues","subprojectItem","subprojectItems","clientValues","fieldName","subprojectItemResource","verzekering_aangepast","fieldNames","contactFields","ProjectContactProjectNoteBusinessLogicRule","updatedContactIds","fieldChangedResult","projectTuples","projectIdTuple","Contact","Projectnotitie","projectTuple","projectnotitie_naam","projectnotitie","projectNoteResource","omschrijving","ProjectOneSubLocationAlignBusinessLogicRule","subprojectResources","projectLocatieValue","locatie_persoon","ProjectSubprojectDefaultTimeBusinessLogicRule","dep","allProjects","columnIdToReset","purchaseOrderColumns","PurchaseOrderApprovalStatusBusinessLogicRule","purchaseOrderIds","purchaseOrderResources","purchaseOrderResource","approval_status","PurchaseOrderOwnerBusinessLogicRule","RateUpdatedBusinessLogicRule","updatedGroups","rate","rate_group","ReparatiesExemplaarAantalBusinessLogicRule","reparatieIds","reparatieResources","reparatieResource","ReparatieLostItemExemplaarLocationBusinessLogicRule","exemplaar","exemplaarId","asset_location","RolEditOwnDataBusinessLogicRule","rolIds","rolResources","rolResource","general_eigen_medewerker_edit","rolColumns","RolFileAccessBusinessLogicRule","canCreateInvoices","canCreateQuotes","general_bestanden_downloaden","ownInvoicesPermission","facturen_toegang","facturen_eigen","RolPersoneelsplannerToegangBusinessLogicRule","projecten_toegang","RolProjectenBewerkenBusinessLogicRule","materialen_tijdlijn","RolProjectenToegangBusinessLogicRule","visibility_financials","uren_kosten","roleColumns","RolPurchaseOrderAttachPlanningBusinessLogicRule","purchaseorders_attach_crew_plannings","RolVisibilityFinancialsBusinessLogicRule","projecten_facturen_maken","projecten_offertes_maken","RolWarehouseTrackingLogAccessBusinessLogicRule","roldIds","magazijn_toegang","SetinhoudCreateFixedBusinessLogicRule","equipmentIsCombination","shouldBeFixed","is_fixed","setinhoudColumns","SetinhoudUpdateFixedBusinessLogicRule","Materiaal","Setinhoud","updatedSetinhoudResources","materiaalsSetinhoudResources","materiaalSetinhoudResource","updatedSetinhoudResource","setinhoudResources","equipmentItemEntry","materiaalIsPhysical","materiaalIsCombination","SubprojectInPlanningBusinessLogicRule","updatedTuplesIterator","subprojectInPlanningMap","projectFunctionResources","subprojectFunctionResourceMap","functionMapEntry","inplanning","SubprojectOneSubLocationAlignBusinessLogicRule","subprojectResource","allSubprojectResources","amountOfSubprojects","subprojectLocatieValue","SubprojectOneSubNameAlignBusinessLogicRule","projectIds","projectNameValue","TijdNameChangedBusinessLogicRule","tijdIds","tijdItems","functiegroepen","tijd","tijdId","functiegroepItems","functieGroep","tijdResource","functiegroepResource","tijdFunctiegroepTuples","projectDefaultTimeColumns","TijdSubprojectChangedBusinessLogicRule","timeItemChanges","projectItemIds","timeItemChange","defaultTimeColumnId","registeredBusinessLogicRules","BusinessLogicManager","businessLogicRuleInstances","constructBusinessLogicRules","hasFlagFn","businessLogicRuleClasses","businessLogicRuleConstructor","setBusinessLogicRuleConfirmation","businessLogicRuleClass","confirmFunction","findBusinessLogicRuleInstance","setBusinessLogicRulePostDependencyConfirmation","ruleConditionResultTuples","extractRulesToRun","ruleDependencyResultTuples","waitForRuleDependencies","applyRules","childMerged","instance","ruleApplyOptionsResultTuples","ruleApplyOptionsResultTuple","ruleInstance","confirmResult","ruleDependencyResults","async","ruleTuple","conditionContext","ruleConditionResults","ApiResponseProcessorFactory","ChangesCompilationFactory","CollectionResourceFactory","parentCachedQueryItemTuple","parentCollectionResource","cachedQueryItemTypeTuples","cachedQueryItemsTypeTuple","ColumnExpansionFactory","ColumnInfoFactory","columnMapEntry","ColumnSetFactory","enableCaching","includeIdColumn","processColumnInfo","expandRootColumnMapFromResponseColumns","constructRequestColumnsFromRootColumnMap","processedItemTypeMap","columnInfoObjects","RequestColumnsOperationsCacheFactory","ItemCacheFactory","ItemResourceFactory","TransactionCacheFactory","serverCacheDependencies","getById","findChild","childResult","transactionOptions","ModuleChangesCompilationFactory","RequestColumnExpansionFactory","ChangesDeltaFactory","cloneCreatedChanges","querySource","SavingInProgressException","GraphQueryParserFactory","RmCore","version","socketMessageHandler","_apiRequestService","HOLIDAY_ICON","holidayColumns","RmHolidaysService","holidayCollectionResourcesMap","rangeContainsHoliday$","end","rmCoreInstance","getHolidaysInDateRangeIterator$","getHolidaysInDateRange$","rangeContainsHoliday","getHolidaysInDateRange","initialize","holidaysCollection","holidayCollection","getHolidaysCollection","startTimestamp","endTimestamp","endOf","startYear","year","endYear","holidayResource","holidayId","holidayDate","holidayName","yearly","holidayYearDate","uid"],"sourceRoot":""}