@osdk/client 2.7.1 → 2.8.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (388) hide show
  1. package/CHANGELOG.md +92 -157
  2. package/build/browser/Client.js +1 -1
  3. package/build/browser/Client.js.map +1 -1
  4. package/build/browser/MinimalClientContext.js.map +1 -1
  5. package/build/browser/actions/applyAction.js +5 -0
  6. package/build/browser/actions/applyAction.js.map +1 -1
  7. package/build/browser/createClient.js +2 -1
  8. package/build/browser/createClient.js.map +1 -1
  9. package/build/browser/createMinimalClient.js +1 -0
  10. package/build/browser/createMinimalClient.js.map +1 -1
  11. package/build/browser/derivedProperties/createWithPropertiesObjectSet.js +17 -1
  12. package/build/browser/derivedProperties/createWithPropertiesObjectSet.js.map +1 -1
  13. package/build/browser/derivedProperties/createWithPropertiesObjectSet.test.js +101 -0
  14. package/build/browser/derivedProperties/createWithPropertiesObjectSet.test.js.map +1 -1
  15. package/build/browser/derivedProperties/derivedPropertyDefinitionFactory.js +1 -1
  16. package/build/browser/derivedProperties/derivedPropertyDefinitionFactory.js.map +1 -1
  17. package/build/browser/fetchMetadata.test.js +9 -0
  18. package/build/browser/fetchMetadata.test.js.map +1 -1
  19. package/build/browser/intellisense.test.js +1 -1
  20. package/build/browser/intellisense.test.js.map +1 -1
  21. package/build/browser/internal/conversions/modernToLegacyWhereClause.js +1 -1
  22. package/build/browser/internal/conversions/modernToLegacyWhereClause.js.map +1 -1
  23. package/build/browser/object/aggregate.js +1 -0
  24. package/build/browser/object/aggregate.js.map +1 -1
  25. package/build/browser/object/convertWireToOsdkObjects/BaseHolder.js.map +1 -1
  26. package/build/browser/object/convertWireToOsdkObjects/InternalSymbols.js +3 -0
  27. package/build/browser/object/convertWireToOsdkObjects/InternalSymbols.js.map +1 -1
  28. package/build/browser/object/convertWireToOsdkObjects/createOsdkInterface.js +4 -0
  29. package/build/browser/object/convertWireToOsdkObjects/createOsdkInterface.js.map +1 -1
  30. package/build/browser/object/convertWireToOsdkObjects/createOsdkObject.js +85 -3
  31. package/build/browser/object/convertWireToOsdkObjects/createOsdkObject.js.map +1 -1
  32. package/build/browser/object/convertWireToOsdkObjects.js +4 -4
  33. package/build/browser/object/convertWireToOsdkObjects.js.map +1 -1
  34. package/build/browser/object/convertWireToOsdkObjects.test.js +48 -27
  35. package/build/browser/object/convertWireToOsdkObjects.test.js.map +1 -1
  36. package/build/browser/object/fetchPage.js +18 -5
  37. package/build/browser/object/fetchPage.js.map +1 -1
  38. package/build/browser/object/object.test.js +123 -0
  39. package/build/browser/object/object.test.js.map +1 -1
  40. package/build/browser/objectSet/ObjectSet.test.js +6 -6
  41. package/build/browser/objectSet/ObjectSet.test.js.map +1 -1
  42. package/build/browser/objectSet/ObjectSetListenerWebsocket.js +4 -4
  43. package/build/browser/objectSet/ObjectSetListenerWebsocket.js.map +1 -1
  44. package/build/browser/objectSet/ObjectSetListenerWebsocket.test.js +3 -1
  45. package/build/browser/objectSet/ObjectSetListenerWebsocket.test.js.map +1 -1
  46. package/build/browser/objectSet/createObjectSet.js +0 -4
  47. package/build/browser/objectSet/createObjectSet.js.map +1 -1
  48. package/build/browser/objectSet/fetchLinksPage.js +1 -0
  49. package/build/browser/objectSet/fetchLinksPage.js.map +1 -1
  50. package/build/browser/observable/ObservableClient/ObserveLink.js.map +1 -1
  51. package/build/browser/observable/ObservableClient.js +11 -0
  52. package/build/browser/observable/ObservableClient.js.map +1 -1
  53. package/build/browser/observable/internal/AbstractHelper.js +56 -3
  54. package/build/browser/observable/internal/AbstractHelper.js.map +1 -1
  55. package/build/browser/observable/internal/AbstractHelper.test.js +114 -0
  56. package/build/browser/observable/internal/AbstractHelper.test.js.map +1 -0
  57. package/build/browser/observable/internal/BulkObjectLoader.js +71 -9
  58. package/build/browser/observable/internal/BulkObjectLoader.js.map +1 -1
  59. package/build/browser/observable/internal/BulkObjectLoader.test.js +79 -0
  60. package/build/browser/observable/internal/BulkObjectLoader.test.js.map +1 -1
  61. package/build/browser/observable/internal/CacheKeys.js +19 -8
  62. package/build/browser/observable/internal/CacheKeys.js.map +1 -1
  63. package/build/browser/observable/internal/ListQueryView.js +120 -0
  64. package/build/browser/observable/internal/ListQueryView.js.map +1 -0
  65. package/build/browser/observable/internal/ObservableClientImpl.js +136 -24
  66. package/build/browser/observable/internal/ObservableClientImpl.js.map +1 -1
  67. package/build/browser/observable/internal/PivotCanonicalizer.js +4 -4
  68. package/build/browser/observable/internal/PivotCanonicalizer.js.map +1 -1
  69. package/build/browser/observable/internal/Query.js +7 -5
  70. package/build/browser/observable/internal/Query.js.map +1 -1
  71. package/build/browser/observable/internal/RdpCanonicalizer.test.js +23 -7
  72. package/build/browser/observable/internal/RdpCanonicalizer.test.js.map +1 -1
  73. package/build/browser/observable/internal/Store.js +19 -2
  74. package/build/browser/observable/internal/Store.js.map +1 -1
  75. package/build/browser/observable/internal/Store.test.js +328 -1
  76. package/build/browser/observable/internal/Store.test.js.map +1 -1
  77. package/build/browser/observable/internal/actions/ActionApplication.js +7 -4
  78. package/build/browser/observable/internal/actions/ActionApplication.js.map +1 -1
  79. package/build/browser/observable/internal/actions/OptimisticJob.js +1 -1
  80. package/build/browser/observable/internal/actions/OptimisticJob.js.map +1 -1
  81. package/build/browser/observable/internal/aggregation/AggregationCacheKey.js +5 -3
  82. package/build/browser/observable/internal/aggregation/AggregationCacheKey.js.map +1 -1
  83. package/build/browser/observable/internal/aggregation/AggregationQuery.js +28 -2
  84. package/build/browser/observable/internal/aggregation/AggregationQuery.js.map +1 -1
  85. package/build/browser/observable/internal/aggregation/AggregationsHelper.js +18 -2
  86. package/build/browser/observable/internal/aggregation/AggregationsHelper.js.map +1 -1
  87. package/build/browser/observable/internal/aggregation/AggregationsHelper.test.js +103 -0
  88. package/build/browser/observable/internal/aggregation/AggregationsHelper.test.js.map +1 -0
  89. package/build/browser/observable/internal/aggregation/ObjectAggregationQuery.js +22 -3
  90. package/build/browser/observable/internal/aggregation/ObjectAggregationQuery.js.map +1 -1
  91. package/build/browser/observable/internal/base-list/BaseListQuery.js +73 -6
  92. package/build/browser/observable/internal/base-list/BaseListQuery.js.map +1 -1
  93. package/build/browser/observable/internal/function/FunctionQuery.js +27 -1
  94. package/build/browser/observable/internal/function/FunctionQuery.js.map +1 -1
  95. package/build/browser/observable/internal/function/FunctionsHelper.js +2 -1
  96. package/build/browser/observable/internal/function/FunctionsHelper.js.map +1 -1
  97. package/build/browser/observable/internal/getObjectTypesThatInvalidate.js +2 -2
  98. package/build/browser/observable/internal/getObjectTypesThatInvalidate.js.map +1 -1
  99. package/build/browser/observable/internal/links/LinksHelper.js +3 -2
  100. package/build/browser/observable/internal/links/LinksHelper.js.map +1 -1
  101. package/build/browser/observable/internal/links/SpecificLinkCacheKey.js +7 -5
  102. package/build/browser/observable/internal/links/SpecificLinkCacheKey.js.map +1 -1
  103. package/build/browser/observable/internal/links/SpecificLinkQuery.js +97 -62
  104. package/build/browser/observable/internal/links/SpecificLinkQuery.js.map +1 -1
  105. package/build/browser/observable/internal/list/InterfaceListQuery.js +19 -1
  106. package/build/browser/observable/internal/list/InterfaceListQuery.js.map +1 -1
  107. package/build/browser/observable/internal/list/ListQuery.js +30 -10
  108. package/build/browser/observable/internal/list/ListQuery.js.map +1 -1
  109. package/build/browser/observable/internal/list/ListQuery.test.js +262 -1
  110. package/build/browser/observable/internal/list/ListQuery.test.js.map +1 -1
  111. package/build/browser/observable/internal/list/ListsHelper.js +1 -1
  112. package/build/browser/observable/internal/list/ListsHelper.js.map +1 -1
  113. package/build/browser/observable/internal/list/ObjectListQuery.js +22 -21
  114. package/build/browser/observable/internal/list/ObjectListQuery.js.map +1 -1
  115. package/build/browser/observable/internal/object/ObjectQuery.js +23 -6
  116. package/build/browser/observable/internal/object/ObjectQuery.js.map +1 -1
  117. package/build/browser/observable/internal/object/ObjectsHelper.js +12 -3
  118. package/build/browser/observable/internal/object/ObjectsHelper.js.map +1 -1
  119. package/build/browser/observable/internal/object/ObjectsHelper.test.js +200 -0
  120. package/build/browser/observable/internal/object/ObjectsHelper.test.js.map +1 -0
  121. package/build/browser/observable/internal/objectset/ObjectSetCacheKey.js.map +1 -1
  122. package/build/browser/observable/internal/objectset/ObjectSetHelper.js +3 -2
  123. package/build/browser/observable/internal/objectset/ObjectSetHelper.js.map +1 -1
  124. package/build/browser/observable/internal/objectset/ObjectSetHelper.test.js +94 -0
  125. package/build/browser/observable/internal/objectset/ObjectSetHelper.test.js.map +1 -0
  126. package/build/browser/observable/internal/objectset/ObjectSetQuery.js +4 -1
  127. package/build/browser/observable/internal/objectset/ObjectSetQuery.js.map +1 -1
  128. package/build/browser/observable/internal/testUtils/observeLink/expectStandardObserveLink.js +1 -0
  129. package/build/browser/observable/internal/testUtils/observeLink/expectStandardObserveLink.js.map +1 -1
  130. package/build/browser/observable/internal/testUtils.js.map +1 -1
  131. package/build/browser/observable/internal/utils/rdpFieldOperations.js +7 -2
  132. package/build/browser/observable/internal/utils/rdpFieldOperations.js.map +1 -1
  133. package/build/browser/observable/internal/utils/rdpFieldOperations.test.js +55 -0
  134. package/build/browser/observable/internal/utils/rdpFieldOperations.test.js.map +1 -1
  135. package/build/browser/ontology/loadActionMetadata.js +3 -1
  136. package/build/browser/ontology/loadActionMetadata.js.map +1 -1
  137. package/build/browser/ontology/loadFullObjectMetadata.js +2 -1
  138. package/build/browser/ontology/loadFullObjectMetadata.js.map +1 -1
  139. package/build/browser/ontology/loadInterfaceMetadata.js +2 -1
  140. package/build/browser/ontology/loadInterfaceMetadata.js.map +1 -1
  141. package/build/browser/public/unstable-do-not-use.js +1 -0
  142. package/build/browser/public/unstable-do-not-use.js.map +1 -1
  143. package/build/browser/util/UserAgent.js +2 -2
  144. package/build/browser/util/UserAgent.js.map +1 -1
  145. package/build/browser/util/interfaceUtils.js +7 -0
  146. package/build/browser/util/interfaceUtils.js.map +1 -1
  147. package/build/cjs/{chunk-OVZCGOMG.cjs → chunk-6VOFZIIJ.cjs} +196 -92
  148. package/build/cjs/chunk-6VOFZIIJ.cjs.map +1 -0
  149. package/build/cjs/{chunk-OZNDU7AU.cjs → chunk-YVZM2JPW.cjs} +237 -196
  150. package/build/cjs/chunk-YVZM2JPW.cjs.map +1 -0
  151. package/build/cjs/{createClient-BDmrDOzZ.d.cts → createClient-BPK4om7e.d.cts} +1 -0
  152. package/build/cjs/index.cjs +8 -8
  153. package/build/cjs/index.d.cts +1 -1
  154. package/build/cjs/public/internal.cjs +8 -8
  155. package/build/cjs/public/unstable-do-not-use.cjs +928 -360
  156. package/build/cjs/public/unstable-do-not-use.cjs.map +1 -1
  157. package/build/cjs/public/unstable-do-not-use.d.cts +65 -27
  158. package/build/esm/Client.js +1 -1
  159. package/build/esm/Client.js.map +1 -1
  160. package/build/esm/MinimalClientContext.js.map +1 -1
  161. package/build/esm/actions/applyAction.js +5 -0
  162. package/build/esm/actions/applyAction.js.map +1 -1
  163. package/build/esm/createClient.js +2 -1
  164. package/build/esm/createClient.js.map +1 -1
  165. package/build/esm/createMinimalClient.js +1 -0
  166. package/build/esm/createMinimalClient.js.map +1 -1
  167. package/build/esm/derivedProperties/createWithPropertiesObjectSet.js +17 -1
  168. package/build/esm/derivedProperties/createWithPropertiesObjectSet.js.map +1 -1
  169. package/build/esm/derivedProperties/createWithPropertiesObjectSet.test.js +101 -0
  170. package/build/esm/derivedProperties/createWithPropertiesObjectSet.test.js.map +1 -1
  171. package/build/esm/derivedProperties/derivedPropertyDefinitionFactory.js +1 -1
  172. package/build/esm/derivedProperties/derivedPropertyDefinitionFactory.js.map +1 -1
  173. package/build/esm/fetchMetadata.test.js +9 -0
  174. package/build/esm/fetchMetadata.test.js.map +1 -1
  175. package/build/esm/intellisense.test.js +1 -1
  176. package/build/esm/intellisense.test.js.map +1 -1
  177. package/build/esm/internal/conversions/modernToLegacyWhereClause.js +1 -1
  178. package/build/esm/internal/conversions/modernToLegacyWhereClause.js.map +1 -1
  179. package/build/esm/object/aggregate.js +1 -0
  180. package/build/esm/object/aggregate.js.map +1 -1
  181. package/build/esm/object/convertWireToOsdkObjects/BaseHolder.js.map +1 -1
  182. package/build/esm/object/convertWireToOsdkObjects/InternalSymbols.js +3 -0
  183. package/build/esm/object/convertWireToOsdkObjects/InternalSymbols.js.map +1 -1
  184. package/build/esm/object/convertWireToOsdkObjects/createOsdkInterface.js +4 -0
  185. package/build/esm/object/convertWireToOsdkObjects/createOsdkInterface.js.map +1 -1
  186. package/build/esm/object/convertWireToOsdkObjects/createOsdkObject.js +85 -3
  187. package/build/esm/object/convertWireToOsdkObjects/createOsdkObject.js.map +1 -1
  188. package/build/esm/object/convertWireToOsdkObjects.js +4 -4
  189. package/build/esm/object/convertWireToOsdkObjects.js.map +1 -1
  190. package/build/esm/object/convertWireToOsdkObjects.test.js +48 -27
  191. package/build/esm/object/convertWireToOsdkObjects.test.js.map +1 -1
  192. package/build/esm/object/fetchPage.js +18 -5
  193. package/build/esm/object/fetchPage.js.map +1 -1
  194. package/build/esm/object/object.test.js +123 -0
  195. package/build/esm/object/object.test.js.map +1 -1
  196. package/build/esm/objectSet/ObjectSet.test.js +6 -6
  197. package/build/esm/objectSet/ObjectSet.test.js.map +1 -1
  198. package/build/esm/objectSet/ObjectSetListenerWebsocket.js +4 -4
  199. package/build/esm/objectSet/ObjectSetListenerWebsocket.js.map +1 -1
  200. package/build/esm/objectSet/ObjectSetListenerWebsocket.test.js +3 -1
  201. package/build/esm/objectSet/ObjectSetListenerWebsocket.test.js.map +1 -1
  202. package/build/esm/objectSet/createObjectSet.js +0 -4
  203. package/build/esm/objectSet/createObjectSet.js.map +1 -1
  204. package/build/esm/objectSet/fetchLinksPage.js +1 -0
  205. package/build/esm/objectSet/fetchLinksPage.js.map +1 -1
  206. package/build/esm/observable/ObservableClient/ObserveLink.js.map +1 -1
  207. package/build/esm/observable/ObservableClient.js +11 -0
  208. package/build/esm/observable/ObservableClient.js.map +1 -1
  209. package/build/esm/observable/internal/AbstractHelper.js +56 -3
  210. package/build/esm/observable/internal/AbstractHelper.js.map +1 -1
  211. package/build/esm/observable/internal/AbstractHelper.test.js +114 -0
  212. package/build/esm/observable/internal/AbstractHelper.test.js.map +1 -0
  213. package/build/esm/observable/internal/BulkObjectLoader.js +71 -9
  214. package/build/esm/observable/internal/BulkObjectLoader.js.map +1 -1
  215. package/build/esm/observable/internal/BulkObjectLoader.test.js +79 -0
  216. package/build/esm/observable/internal/BulkObjectLoader.test.js.map +1 -1
  217. package/build/esm/observable/internal/CacheKeys.js +19 -8
  218. package/build/esm/observable/internal/CacheKeys.js.map +1 -1
  219. package/build/esm/observable/internal/ListQueryView.js +120 -0
  220. package/build/esm/observable/internal/ListQueryView.js.map +1 -0
  221. package/build/esm/observable/internal/ObservableClientImpl.js +136 -24
  222. package/build/esm/observable/internal/ObservableClientImpl.js.map +1 -1
  223. package/build/esm/observable/internal/PivotCanonicalizer.js +4 -4
  224. package/build/esm/observable/internal/PivotCanonicalizer.js.map +1 -1
  225. package/build/esm/observable/internal/Query.js +7 -5
  226. package/build/esm/observable/internal/Query.js.map +1 -1
  227. package/build/esm/observable/internal/RdpCanonicalizer.test.js +23 -7
  228. package/build/esm/observable/internal/RdpCanonicalizer.test.js.map +1 -1
  229. package/build/esm/observable/internal/Store.js +19 -2
  230. package/build/esm/observable/internal/Store.js.map +1 -1
  231. package/build/esm/observable/internal/Store.test.js +328 -1
  232. package/build/esm/observable/internal/Store.test.js.map +1 -1
  233. package/build/esm/observable/internal/actions/ActionApplication.js +7 -4
  234. package/build/esm/observable/internal/actions/ActionApplication.js.map +1 -1
  235. package/build/esm/observable/internal/actions/OptimisticJob.js +1 -1
  236. package/build/esm/observable/internal/actions/OptimisticJob.js.map +1 -1
  237. package/build/esm/observable/internal/aggregation/AggregationCacheKey.js +5 -3
  238. package/build/esm/observable/internal/aggregation/AggregationCacheKey.js.map +1 -1
  239. package/build/esm/observable/internal/aggregation/AggregationQuery.js +28 -2
  240. package/build/esm/observable/internal/aggregation/AggregationQuery.js.map +1 -1
  241. package/build/esm/observable/internal/aggregation/AggregationsHelper.js +18 -2
  242. package/build/esm/observable/internal/aggregation/AggregationsHelper.js.map +1 -1
  243. package/build/esm/observable/internal/aggregation/AggregationsHelper.test.js +103 -0
  244. package/build/esm/observable/internal/aggregation/AggregationsHelper.test.js.map +1 -0
  245. package/build/esm/observable/internal/aggregation/ObjectAggregationQuery.js +22 -3
  246. package/build/esm/observable/internal/aggregation/ObjectAggregationQuery.js.map +1 -1
  247. package/build/esm/observable/internal/base-list/BaseListQuery.js +73 -6
  248. package/build/esm/observable/internal/base-list/BaseListQuery.js.map +1 -1
  249. package/build/esm/observable/internal/function/FunctionQuery.js +27 -1
  250. package/build/esm/observable/internal/function/FunctionQuery.js.map +1 -1
  251. package/build/esm/observable/internal/function/FunctionsHelper.js +2 -1
  252. package/build/esm/observable/internal/function/FunctionsHelper.js.map +1 -1
  253. package/build/esm/observable/internal/getObjectTypesThatInvalidate.js +2 -2
  254. package/build/esm/observable/internal/getObjectTypesThatInvalidate.js.map +1 -1
  255. package/build/esm/observable/internal/links/LinksHelper.js +3 -2
  256. package/build/esm/observable/internal/links/LinksHelper.js.map +1 -1
  257. package/build/esm/observable/internal/links/SpecificLinkCacheKey.js +7 -5
  258. package/build/esm/observable/internal/links/SpecificLinkCacheKey.js.map +1 -1
  259. package/build/esm/observable/internal/links/SpecificLinkQuery.js +97 -62
  260. package/build/esm/observable/internal/links/SpecificLinkQuery.js.map +1 -1
  261. package/build/esm/observable/internal/list/InterfaceListQuery.js +19 -1
  262. package/build/esm/observable/internal/list/InterfaceListQuery.js.map +1 -1
  263. package/build/esm/observable/internal/list/ListQuery.js +30 -10
  264. package/build/esm/observable/internal/list/ListQuery.js.map +1 -1
  265. package/build/esm/observable/internal/list/ListQuery.test.js +262 -1
  266. package/build/esm/observable/internal/list/ListQuery.test.js.map +1 -1
  267. package/build/esm/observable/internal/list/ListsHelper.js +1 -1
  268. package/build/esm/observable/internal/list/ListsHelper.js.map +1 -1
  269. package/build/esm/observable/internal/list/ObjectListQuery.js +22 -21
  270. package/build/esm/observable/internal/list/ObjectListQuery.js.map +1 -1
  271. package/build/esm/observable/internal/object/ObjectQuery.js +23 -6
  272. package/build/esm/observable/internal/object/ObjectQuery.js.map +1 -1
  273. package/build/esm/observable/internal/object/ObjectsHelper.js +12 -3
  274. package/build/esm/observable/internal/object/ObjectsHelper.js.map +1 -1
  275. package/build/esm/observable/internal/object/ObjectsHelper.test.js +200 -0
  276. package/build/esm/observable/internal/object/ObjectsHelper.test.js.map +1 -0
  277. package/build/esm/observable/internal/objectset/ObjectSetCacheKey.js.map +1 -1
  278. package/build/esm/observable/internal/objectset/ObjectSetHelper.js +3 -2
  279. package/build/esm/observable/internal/objectset/ObjectSetHelper.js.map +1 -1
  280. package/build/esm/observable/internal/objectset/ObjectSetHelper.test.js +94 -0
  281. package/build/esm/observable/internal/objectset/ObjectSetHelper.test.js.map +1 -0
  282. package/build/esm/observable/internal/objectset/ObjectSetQuery.js +4 -1
  283. package/build/esm/observable/internal/objectset/ObjectSetQuery.js.map +1 -1
  284. package/build/esm/observable/internal/testUtils/observeLink/expectStandardObserveLink.js +1 -0
  285. package/build/esm/observable/internal/testUtils/observeLink/expectStandardObserveLink.js.map +1 -1
  286. package/build/esm/observable/internal/testUtils.js.map +1 -1
  287. package/build/esm/observable/internal/utils/rdpFieldOperations.js +7 -2
  288. package/build/esm/observable/internal/utils/rdpFieldOperations.js.map +1 -1
  289. package/build/esm/observable/internal/utils/rdpFieldOperations.test.js +55 -0
  290. package/build/esm/observable/internal/utils/rdpFieldOperations.test.js.map +1 -1
  291. package/build/esm/ontology/loadActionMetadata.js +3 -1
  292. package/build/esm/ontology/loadActionMetadata.js.map +1 -1
  293. package/build/esm/ontology/loadFullObjectMetadata.js +2 -1
  294. package/build/esm/ontology/loadFullObjectMetadata.js.map +1 -1
  295. package/build/esm/ontology/loadInterfaceMetadata.js +2 -1
  296. package/build/esm/ontology/loadInterfaceMetadata.js.map +1 -1
  297. package/build/esm/public/unstable-do-not-use.js +1 -0
  298. package/build/esm/public/unstable-do-not-use.js.map +1 -1
  299. package/build/esm/util/UserAgent.js +2 -2
  300. package/build/esm/util/UserAgent.js.map +1 -1
  301. package/build/esm/util/interfaceUtils.js +7 -0
  302. package/build/esm/util/interfaceUtils.js.map +1 -1
  303. package/build/types/Client.d.ts +1 -1
  304. package/build/types/MinimalClientContext.d.ts +1 -1
  305. package/build/types/actions/applyAction.d.ts.map +1 -1
  306. package/build/types/createClient.d.ts +1 -0
  307. package/build/types/createClient.d.ts.map +1 -1
  308. package/build/types/object/convertWireToOsdkObjects/InternalSymbols.d.ts +2 -0
  309. package/build/types/object/convertWireToOsdkObjects/InternalSymbols.d.ts.map +1 -1
  310. package/build/types/object/convertWireToOsdkObjects.d.ts +4 -4
  311. package/build/types/object/convertWireToOsdkObjects.d.ts.map +1 -1
  312. package/build/types/object/fetchPage.d.ts.map +1 -1
  313. package/build/types/object/object.test.d.ts.map +1 -1
  314. package/build/types/objectSet/createObjectSet.d.ts +5 -14
  315. package/build/types/objectSet/createObjectSet.d.ts.map +1 -1
  316. package/build/types/objectSet/fetchLinksPage.d.ts +1 -9
  317. package/build/types/objectSet/fetchLinksPage.d.ts.map +1 -1
  318. package/build/types/observable/ObservableClient/ObserveLink.d.ts +2 -1
  319. package/build/types/observable/ObservableClient/ObserveLink.d.ts.map +1 -1
  320. package/build/types/observable/ObservableClient.d.ts +71 -25
  321. package/build/types/observable/ObservableClient.d.ts.map +1 -1
  322. package/build/types/observable/internal/AbstractHelper.d.ts +1 -1
  323. package/build/types/observable/internal/AbstractHelper.d.ts.map +1 -1
  324. package/build/types/observable/internal/AbstractHelper.test.d.ts +1 -0
  325. package/build/types/observable/internal/AbstractHelper.test.d.ts.map +1 -0
  326. package/build/types/observable/internal/BulkObjectLoader.d.ts +2 -1
  327. package/build/types/observable/internal/BulkObjectLoader.d.ts.map +1 -1
  328. package/build/types/observable/internal/CacheKeys.d.ts +5 -0
  329. package/build/types/observable/internal/CacheKeys.d.ts.map +1 -1
  330. package/build/types/observable/internal/ListQueryView.d.ts +21 -0
  331. package/build/types/observable/internal/ListQueryView.d.ts.map +1 -0
  332. package/build/types/observable/internal/PivotCanonicalizer.d.ts +2 -2
  333. package/build/types/observable/internal/PivotCanonicalizer.d.ts.map +1 -1
  334. package/build/types/observable/internal/Query.d.ts.map +1 -1
  335. package/build/types/observable/internal/Store.d.ts.map +1 -1
  336. package/build/types/observable/internal/Store.test.d.ts.map +1 -1
  337. package/build/types/observable/internal/actions/ActionApplication.d.ts.map +1 -1
  338. package/build/types/observable/internal/actions/OptimisticJob.d.ts.map +1 -1
  339. package/build/types/observable/internal/aggregation/AggregationCacheKey.d.ts +6 -4
  340. package/build/types/observable/internal/aggregation/AggregationCacheKey.d.ts.map +1 -1
  341. package/build/types/observable/internal/aggregation/AggregationQuery.d.ts +8 -3
  342. package/build/types/observable/internal/aggregation/AggregationQuery.d.ts.map +1 -1
  343. package/build/types/observable/internal/aggregation/AggregationsHelper.d.ts +19 -14
  344. package/build/types/observable/internal/aggregation/AggregationsHelper.d.ts.map +1 -1
  345. package/build/types/observable/internal/aggregation/AggregationsHelper.test.d.ts +1 -0
  346. package/build/types/observable/internal/aggregation/AggregationsHelper.test.d.ts.map +1 -0
  347. package/build/types/observable/internal/aggregation/ObjectAggregationQuery.d.ts.map +1 -1
  348. package/build/types/observable/internal/base-list/BaseListQuery.d.ts +47 -2
  349. package/build/types/observable/internal/base-list/BaseListQuery.d.ts.map +1 -1
  350. package/build/types/observable/internal/function/FunctionQuery.d.ts +1 -1
  351. package/build/types/observable/internal/function/FunctionQuery.d.ts.map +1 -1
  352. package/build/types/observable/internal/function/FunctionsHelper.d.ts +1 -0
  353. package/build/types/observable/internal/function/FunctionsHelper.d.ts.map +1 -1
  354. package/build/types/observable/internal/links/LinksHelper.d.ts +5 -5
  355. package/build/types/observable/internal/links/LinksHelper.d.ts.map +1 -1
  356. package/build/types/observable/internal/links/SpecificLinkCacheKey.d.ts +8 -6
  357. package/build/types/observable/internal/links/SpecificLinkCacheKey.d.ts.map +1 -1
  358. package/build/types/observable/internal/links/SpecificLinkQuery.d.ts +3 -4
  359. package/build/types/observable/internal/links/SpecificLinkQuery.d.ts.map +1 -1
  360. package/build/types/observable/internal/list/InterfaceListQuery.d.ts.map +1 -1
  361. package/build/types/observable/internal/list/ListQuery.d.ts +0 -3
  362. package/build/types/observable/internal/list/ListQuery.d.ts.map +1 -1
  363. package/build/types/observable/internal/list/ListsHelper.d.ts +4 -4
  364. package/build/types/observable/internal/list/ListsHelper.d.ts.map +1 -1
  365. package/build/types/observable/internal/list/ObjectListQuery.d.ts.map +1 -1
  366. package/build/types/observable/internal/object/ObjectQuery.d.ts +2 -1
  367. package/build/types/observable/internal/object/ObjectQuery.d.ts.map +1 -1
  368. package/build/types/observable/internal/object/ObjectsHelper.d.ts +8 -4
  369. package/build/types/observable/internal/object/ObjectsHelper.d.ts.map +1 -1
  370. package/build/types/observable/internal/object/ObjectsHelper.test.d.ts +1 -0
  371. package/build/types/observable/internal/object/ObjectsHelper.test.d.ts.map +1 -0
  372. package/build/types/observable/internal/objectset/ObjectSetCacheKey.d.ts +2 -1
  373. package/build/types/observable/internal/objectset/ObjectSetCacheKey.d.ts.map +1 -1
  374. package/build/types/observable/internal/objectset/ObjectSetHelper.d.ts +3 -1
  375. package/build/types/observable/internal/objectset/ObjectSetHelper.d.ts.map +1 -1
  376. package/build/types/observable/internal/objectset/ObjectSetHelper.test.d.ts +1 -0
  377. package/build/types/observable/internal/objectset/ObjectSetHelper.test.d.ts.map +1 -0
  378. package/build/types/observable/internal/objectset/ObjectSetQuery.d.ts +2 -0
  379. package/build/types/observable/internal/objectset/ObjectSetQuery.d.ts.map +1 -1
  380. package/build/types/observable/internal/testUtils.d.ts +2 -2
  381. package/build/types/observable/internal/testUtils.d.ts.map +1 -1
  382. package/build/types/public/unstable-do-not-use.d.ts +1 -0
  383. package/build/types/public/unstable-do-not-use.d.ts.map +1 -1
  384. package/build/types/util/interfaceUtils.d.ts +2 -1
  385. package/build/types/util/interfaceUtils.d.ts.map +1 -1
  386. package/package.json +15 -14
  387. package/build/cjs/chunk-OVZCGOMG.cjs.map +0 -1
  388. package/build/cjs/chunk-OZNDU7AU.cjs.map +0 -1
@@ -37,36 +37,50 @@ export class BulkObjectLoader {
37
37
  this.#maxWait = maxWait;
38
38
  this.#maxEntries = maxEntries;
39
39
  }
40
- async fetch(apiName, primaryKey) {
40
+ async fetch(apiName, primaryKey, defType = "object") {
41
41
  const deferred = pDefer();
42
42
  const entry = this.#m.get(apiName);
43
43
  entry.data.push({
44
44
  primaryKey: primaryKey,
45
45
  deferred
46
46
  });
47
+ if (entry.defType === undefined) {
48
+ entry.defType = defType;
49
+ } else if (entry.defType !== defType) {
50
+ deferred.reject(new PalantirApiError(`Conflicting defType for ${apiName}: existing=${entry.defType}, new=${defType}`));
51
+ return deferred.promise;
52
+ }
47
53
  if (!entry.timer) {
48
54
  entry.timer = setTimeout(() => {
49
- this.#loadObjects(apiName, entry.data);
55
+ this.#loadObjects(apiName, entry.data, entry.defType ?? "object");
50
56
  }, this.#maxWait);
51
57
  }
52
58
  if (entry.data.length >= this.#maxEntries) {
53
59
  clearTimeout(entry.timer);
54
- this.#loadObjects(apiName, entry.data);
60
+ this.#loadObjects(apiName, entry.data, entry.defType ?? "object");
55
61
  }
56
62
  return await deferred.promise;
57
63
  }
58
- #loadObjects(apiName, arr) {
64
+ #loadObjects(apiName, arr, defType) {
59
65
  this.#m.delete(apiName);
60
- this.#reallyLoadObjects(apiName, arr).catch(e => {
66
+ const loadFn = defType === "interface" ? this.#loadInterfaceObjects(apiName, arr) : this.#loadObjectTypeObjects(apiName, arr);
67
+ loadFn.catch(e => {
61
68
  this.#logger?.error("Unhandled exception", e);
69
+ for (const {
70
+ primaryKey,
71
+ deferred
72
+ } of arr) {
73
+ const errorMessage = e instanceof Error ? e.message : String(e);
74
+ deferred.reject(new PalantirApiError(`Failed to load ${apiName} with pk ${primaryKey}: ${errorMessage}`));
75
+ }
62
76
  });
63
77
  }
64
- async #reallyLoadObjects(apiName, arr) {
65
- const miniDef = {
78
+ async #loadObjectTypeObjects(apiName, arr) {
79
+ const objectDef = {
66
80
  type: "object",
67
81
  apiName
68
82
  };
69
- const objMetadata = await this.#client.fetchMetadata(miniDef);
83
+ const objMetadata = await this.#client.fetchMetadata(objectDef);
70
84
  const pks = arr.map(x => x.primaryKey);
71
85
 
72
86
  // Use $eq for single object fetches (this is for public app compatibility)
@@ -82,7 +96,7 @@ export class BulkObjectLoader {
82
96
  };
83
97
  const {
84
98
  data
85
- } = await this.#client(miniDef).where(whereClause).fetchPage({
99
+ } = await this.#client(objectDef).where(whereClause).fetchPage({
86
100
  $pageSize: pks.length,
87
101
  $includeRid: true
88
102
  });
@@ -98,5 +112,53 @@ export class BulkObjectLoader {
98
112
  }
99
113
  }
100
114
  }
115
+ async #loadInterfaceObjects(apiName, arr) {
116
+ const pks = arr.map(x => x.primaryKey);
117
+ const interfaceMetadata = await this.#client.fetchMetadata({
118
+ type: "interface",
119
+ apiName
120
+ });
121
+ const implementingTypes = interfaceMetadata.implementedBy ?? [];
122
+ const foundObjects = new Map();
123
+ for (const objectTypeName of implementingTypes) {
124
+ const objectDef = {
125
+ type: "object",
126
+ apiName: objectTypeName
127
+ };
128
+ const objMetadata = await this.#client.fetchMetadata(objectDef);
129
+ const remainingPks = pks.filter(pk => !foundObjects.has(pk));
130
+ if (remainingPks.length === 0) {
131
+ break;
132
+ }
133
+ const whereClause = remainingPks.length === 1 ? {
134
+ [objMetadata.primaryKeyApiName]: {
135
+ $eq: remainingPks[0]
136
+ }
137
+ } : {
138
+ [objMetadata.primaryKeyApiName]: {
139
+ $in: remainingPks
140
+ }
141
+ };
142
+ const {
143
+ data
144
+ } = await this.#client(objectDef).where(whereClause).fetchPage({
145
+ $pageSize: remainingPks.length
146
+ });
147
+ for (const obj of data) {
148
+ foundObjects.set(obj.$primaryKey, obj);
149
+ }
150
+ }
151
+ for (const {
152
+ primaryKey,
153
+ deferred
154
+ } of arr) {
155
+ const object = foundObjects.get(primaryKey);
156
+ if (object) {
157
+ deferred.resolve(object);
158
+ } else {
159
+ deferred.reject(new PalantirApiError(`Interface ${apiName} object not found: ${primaryKey}`));
160
+ }
161
+ }
162
+ }
101
163
  }
102
164
  //# sourceMappingURL=BulkObjectLoader.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"BulkObjectLoader.js","names":["PalantirApiError","DefaultMap","DefaultWeakMap","pDefer","additionalContext","weakCache","c","BulkObjectLoader","getBulkObjectLoader","client","get","m","data","timer","undefined","logger","maxWait","maxEntries","constructor","fetch","apiName","primaryKey","deferred","entry","push","setTimeout","loadObjects","length","clearTimeout","promise","#loadObjects","arr","delete","reallyLoadObjects","catch","e","error","#reallyLoadObjects","miniDef","type","objMetadata","fetchMetadata","pks","map","x","whereClause","primaryKeyApiName","$eq","$in","where","fetchPage","$pageSize","$includeRid","object","find","$primaryKey","resolve","reject"],"sources":["BulkObjectLoader.ts"],"sourcesContent":["/*\n * Copyright 2025 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { Logger, ObjectTypeDefinition } from \"@osdk/api\";\nimport { PalantirApiError } from \"@osdk/shared.net.errors\";\nimport { DefaultMap, DefaultWeakMap } from \"mnemonist\";\nimport type { DeferredPromise } from \"p-defer\";\nimport pDefer from \"p-defer\";\nimport { additionalContext, type Client } from \"../../Client.js\";\nimport type {\n ObjectHolder,\n} from \"../../object/convertWireToOsdkObjects/ObjectHolder.js\";\n\ninterface InternalValue {\n primaryKey: string;\n deferred: DeferredPromise<ObjectHolder>;\n}\n\ninterface Accumulator {\n data: InternalValue[];\n timer?: ReturnType<typeof setTimeout>;\n}\n\nconst weakCache = new DefaultWeakMap<Client, BulkObjectLoader>(c =>\n new BulkObjectLoader(c)\n);\n\nexport function getBulkObjectLoader(client: Client): BulkObjectLoader {\n return weakCache.get(client);\n}\n\nexport class BulkObjectLoader {\n #client: Client;\n\n #m = new DefaultMap<string, Accumulator>(() => ({\n data: [],\n timer: undefined,\n }));\n #logger: Logger | undefined;\n #maxWait: number;\n #maxEntries: number;\n\n constructor(client: Client, maxWait = 25, maxEntries = 100) {\n this.#client = client;\n this.#logger = client[additionalContext].logger;\n this.#maxWait = maxWait;\n this.#maxEntries = maxEntries;\n }\n\n public async fetch(\n apiName: string,\n primaryKey: string | number | boolean,\n ): Promise<ObjectHolder> {\n const deferred = pDefer<ObjectHolder>();\n\n const entry = this.#m.get(apiName);\n entry.data.push({\n primaryKey: primaryKey as string,\n deferred,\n });\n\n if (!entry.timer) {\n entry.timer = setTimeout(() => {\n this.#loadObjects(apiName, entry.data);\n }, this.#maxWait);\n }\n\n if (entry.data.length >= this.#maxEntries) {\n clearTimeout(entry.timer);\n this.#loadObjects(apiName, entry.data);\n }\n\n return await deferred.promise;\n }\n\n #loadObjects(apiName: string, arr: InternalValue[]) {\n this.#m.delete(apiName);\n\n this.#reallyLoadObjects(apiName, arr).catch((e: unknown) => {\n this.#logger?.error(\"Unhandled exception\", e);\n });\n }\n\n async #reallyLoadObjects(apiName: string, arr: InternalValue[]) {\n const miniDef = { type: \"object\", apiName } as ObjectTypeDefinition;\n const objMetadata = await this.#client.fetchMetadata(miniDef);\n\n const pks = arr.map(x => x.primaryKey);\n\n // Use $eq for single object fetches (this is for public app compatibility)\n // Use $in for batch fetches\n const whereClause = pks.length === 1\n ? { [objMetadata.primaryKeyApiName]: { $eq: pks[0] } }\n : { [objMetadata.primaryKeyApiName]: { $in: pks } };\n\n const { data } = await this.#client(miniDef)\n .where(whereClause).fetchPage({\n $pageSize: pks.length,\n $includeRid: true,\n });\n\n for (const { primaryKey, deferred } of arr) {\n const object = data.find(x => x.$primaryKey === primaryKey) as\n | ObjectHolder\n | undefined;\n if (object) {\n deferred.resolve(object);\n } else {\n deferred.reject(\n new PalantirApiError(`Object not found: ${primaryKey}`),\n );\n }\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"BulkObjectLoader.js","names":["PalantirApiError","DefaultMap","DefaultWeakMap","pDefer","additionalContext","weakCache","c","BulkObjectLoader","getBulkObjectLoader","client","get","m","data","timer","undefined","logger","maxWait","maxEntries","constructor","fetch","apiName","primaryKey","defType","deferred","entry","push","reject","promise","setTimeout","loadObjects","length","clearTimeout","#loadObjects","arr","delete","loadFn","loadInterfaceObjects","loadObjectTypeObjects","catch","e","error","errorMessage","Error","message","String","#loadObjectTypeObjects","objectDef","type","objMetadata","fetchMetadata","pks","map","x","whereClause","primaryKeyApiName","$eq","$in","where","fetchPage","$pageSize","$includeRid","object","find","$primaryKey","resolve","#loadInterfaceObjects","interfaceMetadata","implementingTypes","implementedBy","foundObjects","Map","objectTypeName","remainingPks","filter","pk","has","obj","set"],"sources":["BulkObjectLoader.ts"],"sourcesContent":["/*\n * Copyright 2025 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n InterfaceDefinition,\n Logger,\n ObjectTypeDefinition,\n} from \"@osdk/api\";\nimport { PalantirApiError } from \"@osdk/shared.net.errors\";\nimport { DefaultMap, DefaultWeakMap } from \"mnemonist\";\nimport type { DeferredPromise } from \"p-defer\";\nimport pDefer from \"p-defer\";\nimport { additionalContext, type Client } from \"../../Client.js\";\nimport type {\n ObjectHolder,\n} from \"../../object/convertWireToOsdkObjects/ObjectHolder.js\";\nimport type { DefType } from \"../../util/interfaceUtils.js\";\n\ninterface InternalValue {\n primaryKey: string;\n deferred: DeferredPromise<ObjectHolder>;\n}\n\ninterface Accumulator {\n data: InternalValue[];\n timer?: ReturnType<typeof setTimeout>;\n defType?: DefType;\n}\n\nconst weakCache = new DefaultWeakMap<Client, BulkObjectLoader>(c =>\n new BulkObjectLoader(c)\n);\n\nexport function getBulkObjectLoader(client: Client): BulkObjectLoader {\n return weakCache.get(client);\n}\n\nexport class BulkObjectLoader {\n #client: Client;\n\n #m = new DefaultMap<string, Accumulator>(() => ({\n data: [],\n timer: undefined,\n }));\n #logger: Logger | undefined;\n #maxWait: number;\n #maxEntries: number;\n\n constructor(client: Client, maxWait = 25, maxEntries = 100) {\n this.#client = client;\n this.#logger = client[additionalContext].logger;\n this.#maxWait = maxWait;\n this.#maxEntries = maxEntries;\n }\n\n public async fetch(\n apiName: string,\n primaryKey: string | number | boolean,\n defType: DefType = \"object\",\n ): Promise<ObjectHolder> {\n const deferred = pDefer<ObjectHolder>();\n\n const entry = this.#m.get(apiName);\n entry.data.push({\n primaryKey: primaryKey as string,\n deferred,\n });\n\n if (entry.defType === undefined) {\n entry.defType = defType;\n } else if (entry.defType !== defType) {\n deferred.reject(\n new PalantirApiError(\n `Conflicting defType for ${apiName}: existing=${entry.defType}, new=${defType}`,\n ),\n );\n return deferred.promise;\n }\n\n if (!entry.timer) {\n entry.timer = setTimeout(() => {\n this.#loadObjects(apiName, entry.data, entry.defType ?? \"object\");\n }, this.#maxWait);\n }\n\n if (entry.data.length >= this.#maxEntries) {\n clearTimeout(entry.timer);\n this.#loadObjects(apiName, entry.data, entry.defType ?? \"object\");\n }\n\n return await deferred.promise;\n }\n\n #loadObjects(\n apiName: string,\n arr: InternalValue[],\n defType: DefType,\n ) {\n this.#m.delete(apiName);\n\n const loadFn = defType === \"interface\"\n ? this.#loadInterfaceObjects(apiName, arr)\n : this.#loadObjectTypeObjects(apiName, arr);\n\n loadFn.catch((e: unknown) => {\n this.#logger?.error(\"Unhandled exception\", e);\n for (const { primaryKey, deferred } of arr) {\n const errorMessage = e instanceof Error ? e.message : String(e);\n deferred.reject(\n new PalantirApiError(\n `Failed to load ${apiName} with pk ${primaryKey}: ${errorMessage}`,\n ),\n );\n }\n });\n }\n\n async #loadObjectTypeObjects(apiName: string, arr: InternalValue[]) {\n const objectDef = { type: \"object\", apiName } as ObjectTypeDefinition;\n const objMetadata = await this.#client.fetchMetadata(objectDef);\n\n const pks = arr.map(x => x.primaryKey);\n\n // Use $eq for single object fetches (this is for public app compatibility)\n // Use $in for batch fetches\n const whereClause = pks.length === 1\n ? { [objMetadata.primaryKeyApiName]: { $eq: pks[0] } }\n : { [objMetadata.primaryKeyApiName]: { $in: pks } };\n\n const { data } = await this.#client(objectDef)\n .where(whereClause).fetchPage({\n $pageSize: pks.length,\n $includeRid: true,\n });\n\n for (const { primaryKey, deferred } of arr) {\n const object = data.find(x => x.$primaryKey === primaryKey) as\n | ObjectHolder\n | undefined;\n if (object) {\n deferred.resolve(object);\n } else {\n deferred.reject(\n new PalantirApiError(`Object not found: ${primaryKey}`),\n );\n }\n }\n }\n\n async #loadInterfaceObjects(apiName: string, arr: InternalValue[]) {\n const pks = arr.map(x => x.primaryKey);\n\n const interfaceDef = {\n type: \"interface\",\n apiName,\n } as InterfaceDefinition;\n\n const interfaceMetadata = await this.#client.fetchMetadata(interfaceDef);\n const implementingTypes = interfaceMetadata.implementedBy ?? [];\n\n const foundObjects = new Map<string | number, ObjectHolder>();\n\n for (const objectTypeName of implementingTypes) {\n const objectDef = {\n type: \"object\",\n apiName: objectTypeName,\n } as ObjectTypeDefinition;\n const objMetadata = await this.#client.fetchMetadata(objectDef);\n\n const remainingPks = pks.filter(pk => !foundObjects.has(pk));\n if (remainingPks.length === 0) {\n break;\n }\n\n const whereClause = remainingPks.length === 1\n ? { [objMetadata.primaryKeyApiName]: { $eq: remainingPks[0] } }\n : { [objMetadata.primaryKeyApiName]: { $in: remainingPks } };\n\n const { data } = await this.#client(objectDef)\n .where(whereClause).fetchPage({\n $pageSize: remainingPks.length,\n });\n\n for (const obj of data) {\n foundObjects.set(obj.$primaryKey, obj as ObjectHolder);\n }\n }\n\n for (const { primaryKey, deferred } of arr) {\n const object = foundObjects.get(primaryKey);\n if (object) {\n deferred.resolve(object);\n } else {\n deferred.reject(\n new PalantirApiError(\n `Interface ${apiName} object not found: ${primaryKey}`,\n ),\n );\n }\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -156,5 +156,84 @@ describe(BulkObjectLoader, () => {
156
156
  });
157
157
  vi.useRealTimers();
158
158
  });
159
+ describe("interface loading", () => {
160
+ const mockObjectSet = data => {
161
+ const os = {
162
+ where: () => os,
163
+ fetchPage: vi.fn().mockResolvedValue({
164
+ data
165
+ })
166
+ };
167
+ return os;
168
+ };
169
+ it("loads interface objects by querying implementing types", async () => {
170
+ const loader = new BulkObjectLoader(client, 25, 100);
171
+ vi.useFakeTimers();
172
+
173
+ // eslint-disable-next-line @typescript-eslint/unbound-method
174
+ vi.mocked(client.fetchMetadata).mockResolvedValueOnce({
175
+ type: "interface",
176
+ implementedBy: ["Employee"],
177
+ links: {},
178
+ apiName: "FooInterface",
179
+ displayName: "FooInterface",
180
+ description: undefined,
181
+ properties: {},
182
+ rid: "ri.test"
183
+ }).mockResolvedValueOnce({
184
+ primaryKeyApiName: "employeeId"
185
+ });
186
+ client.mockReturnValueOnce(mockObjectSet([{
187
+ $apiName: "Employee",
188
+ $objectType: "Employee",
189
+ $primaryKey: 1
190
+ }]));
191
+ const loadPromise = loader.fetch("FooInterface", 1, "interface");
192
+ vi.advanceTimersByTime(26);
193
+ await expect(loadPromise).resolves.toMatchObject({
194
+ $primaryKey: 1
195
+ });
196
+ vi.useRealTimers();
197
+ });
198
+ it("rejects when interface object is not found in any implementing type", async () => {
199
+ const loader = new BulkObjectLoader(client, 25, 100);
200
+ vi.useFakeTimers();
201
+
202
+ // eslint-disable-next-line @typescript-eslint/unbound-method
203
+ vi.mocked(client.fetchMetadata).mockResolvedValueOnce({
204
+ type: "interface",
205
+ implementedBy: ["Employee"],
206
+ links: {},
207
+ apiName: "FooInterface",
208
+ displayName: "FooInterface",
209
+ description: undefined,
210
+ properties: {},
211
+ rid: "ri.test"
212
+ }).mockResolvedValueOnce({
213
+ primaryKeyApiName: "employeeId"
214
+ });
215
+ client.mockReturnValueOnce(mockObjectSet([]));
216
+ const loadPromise = loader.fetch("FooInterface", 1, "interface");
217
+ vi.advanceTimersByTime(26);
218
+ await expect(loadPromise).rejects.toThrow("Interface FooInterface object not found: 1");
219
+ vi.useRealTimers();
220
+ });
221
+ it("loads object type when defType='object' (default)", async () => {
222
+ const loader = new BulkObjectLoader(client, 25, 100);
223
+ vi.useFakeTimers();
224
+ const firstRequest = mockClient.mockFetchPageOnce();
225
+ const loadPromise = loader.fetch("Employee", 1);
226
+ vi.advanceTimersByTime(26);
227
+ firstRequest.resolve({
228
+ data: [employees[1]],
229
+ nextPageToken: undefined,
230
+ totalCount: "1"
231
+ });
232
+ await expect(loadPromise).resolves.toMatchObject({
233
+ $primaryKey: 1
234
+ });
235
+ vi.useRealTimers();
236
+ });
237
+ });
159
238
  });
160
239
  //# sourceMappingURL=BulkObjectLoader.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"BulkObjectLoader.test.js","names":["beforeEach","describe","expect","it","vi","BulkObjectLoader","createClientMockHelper","client","mockClient","mocked","fetchMetadata","mockReturnValue","Promise","resolve","primaryKeyApiName","employees","$apiName","$objectType","$primaryKey","loader","firstRequest","mockFetchPageOnce","secondRequest","load0","fetch","load1","load2","data","nextPageToken","undefined","totalCount","resolves","toMatchObject","mock","fn","then","not","toHaveBeenCalled","useFakeTimers","advanceTimersByTime","runOnlyPendingTimers","mockThen","useRealTimers","whereClauses","mockObjectSet","where","clause","push","fetchPage","mockResolvedValue","mockReturnValueOnce","toEqual","id","$eq","length","mockObjectSet2","all","$in"],"sources":["BulkObjectLoader.test.ts"],"sourcesContent":["/*\n * Copyright 2025 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n ObjectMetadata,\n ObjectSet,\n ObjectTypeDefinition,\n WhereClause,\n} from \"@osdk/api\";\nimport type { Mock } from \"vitest\";\nimport { beforeEach, describe, expect, it, vi } from \"vitest\";\nimport type { Client } from \"../../Client.js\";\nimport { BulkObjectLoader } from \"./BulkObjectLoader.js\";\nimport { createClientMockHelper, type MockClientHelper } from \"./testUtils.js\";\n\ndescribe(BulkObjectLoader, () => {\n let client: Mock<Client> & Client;\n let mockClient: MockClientHelper;\n\n beforeEach(async () => {\n mockClient = createClientMockHelper();\n client = mockClient.client;\n\n // eslint-disable-next-line @typescript-eslint/unbound-method\n vi.mocked(client.fetchMetadata).mockReturnValue(\n Promise.resolve(\n {\n primaryKeyApiName: \"id\",\n } satisfies Pick<ObjectMetadata, \"primaryKeyApiName\"> as ObjectMetadata,\n ),\n );\n });\n\n const employees = [\n {\n $apiName: \"Employee\",\n $objectType: \"Employee\",\n $primaryKey: 0,\n },\n {\n $apiName: \"Employee\",\n $objectType: \"Employee\",\n $primaryKey: 1,\n },\n {\n $apiName: \"Employee\",\n $objectType: \"Employee\",\n $primaryKey: 2,\n },\n ];\n\n it(\"splits up work by count\", async () => {\n const loader = new BulkObjectLoader(client, 25, /*ms*/ 2 /*entries*/);\n\n const firstRequest = mockClient.mockFetchPageOnce();\n const secondRequest = mockClient.mockFetchPageOnce();\n\n const load0 = loader.fetch(\"Employee\", 0);\n const load1 = loader.fetch(\"Employee\", 1);\n const load2 = loader.fetch(\"Employee\", 2);\n\n firstRequest.resolve({\n data: [employees[0], employees[1]],\n nextPageToken: undefined,\n totalCount: \"2\",\n });\n\n await expect(load0).resolves.toMatchObject({\n $primaryKey: 0,\n });\n\n await expect(load1).resolves.toMatchObject({\n $primaryKey: 1,\n });\n\n const mock = vi.fn();\n void load2.then(mock);\n expect(mock).not.toHaveBeenCalled();\n\n secondRequest.resolve({\n data: [employees[2]],\n nextPageToken: undefined,\n totalCount: \"1\",\n });\n\n await expect(load2).resolves.toMatchObject({\n $primaryKey: 2,\n });\n\n expect(mock).toHaveBeenCalled();\n });\n\n it(\"splits up work by time\", async () => {\n const loader = new BulkObjectLoader(client, /*ms*/ 25, /*entries*/ 100);\n\n const firstRequest = mockClient.mockFetchPageOnce();\n const secondRequest = mockClient.mockFetchPageOnce();\n\n vi.useFakeTimers();\n\n const load0 = loader.fetch(\"Employee\", 0);\n\n vi.advanceTimersByTime(26);\n\n const load1 = loader.fetch(\"Employee\", 1);\n const load2 = loader.fetch(\"Employee\", 2);\n\n firstRequest.resolve({\n data: [employees[0]],\n nextPageToken: undefined,\n totalCount: \"1\",\n });\n\n vi.runOnlyPendingTimers();\n\n await expect(load0).resolves.toMatchObject({\n $primaryKey: 0,\n });\n\n const mockThen = vi.fn();\n void load2.then(mockThen);\n\n expect(mockThen).not.toHaveBeenCalled();\n\n secondRequest.resolve({\n data: [\n employees[1],\n employees[2],\n ],\n nextPageToken: undefined,\n totalCount: \"2\",\n });\n\n await expect(load1).resolves.toMatchObject({\n $primaryKey: 1,\n });\n\n await expect(load2).resolves.toMatchObject({\n $primaryKey: 2,\n });\n\n expect(mockThen).toHaveBeenCalled();\n\n vi.useRealTimers();\n });\n\n it(\"uses $eq for single object and $in for multiple objects\", async () => {\n const loader = new BulkObjectLoader(client, 25, 100);\n\n vi.useFakeTimers();\n\n const whereClauses: WhereClause<ObjectTypeDefinition>[] = [];\n\n const mockObjectSet: ObjectSet<ObjectTypeDefinition> = {\n where: (clause) => {\n whereClauses.push(clause);\n return mockObjectSet;\n },\n fetchPage: vi.fn().mockResolvedValue({\n data: [employees[0]],\n nextPageToken: undefined,\n totalCount: \"1\",\n }),\n } as Pick<\n ObjectSet<ObjectTypeDefinition>,\n \"fetchPage\" | \"where\"\n > as ObjectSet<ObjectTypeDefinition>;\n\n client.mockReturnValueOnce(mockObjectSet);\n const load0 = loader.fetch(\"Employee\", 0);\n\n vi.advanceTimersByTime(26);\n\n await load0;\n\n expect(whereClauses[0]).toEqual({\n id: { $eq: 0 },\n });\n\n whereClauses.length = 0;\n\n const mockObjectSet2: ObjectSet<ObjectTypeDefinition> = {\n where: (clause) => {\n whereClauses.push(clause);\n return mockObjectSet2;\n },\n fetchPage: vi.fn().mockResolvedValue({\n data: [employees[1], employees[2]],\n nextPageToken: undefined,\n totalCount: \"2\",\n }),\n } as Pick<\n ObjectSet<ObjectTypeDefinition>,\n \"fetchPage\" | \"where\"\n > as ObjectSet<ObjectTypeDefinition>;\n\n client.mockReturnValueOnce(mockObjectSet2);\n\n const load1 = loader.fetch(\"Employee\", 1);\n const load2 = loader.fetch(\"Employee\", 2);\n\n vi.advanceTimersByTime(26);\n\n await Promise.all([load1, load2]);\n\n expect(whereClauses[0]).toEqual({\n id: { $in: [1, 2] },\n });\n\n vi.useRealTimers();\n });\n});\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AASA,SAASA,UAAU,EAAEC,QAAQ,EAAEC,MAAM,EAAEC,EAAE,EAAEC,EAAE,QAAQ,QAAQ;AAE7D,SAASC,gBAAgB,QAAQ,uBAAuB;AACxD,SAASC,sBAAsB,QAA+B,gBAAgB;AAE9EL,QAAQ,CAACI,gBAAgB,EAAE,MAAM;EAC/B,IAAIE,MAA6B;EACjC,IAAIC,UAA4B;EAEhCR,UAAU,CAAC,YAAY;IACrBQ,UAAU,GAAGF,sBAAsB,CAAC,CAAC;IACrCC,MAAM,GAAGC,UAAU,CAACD,MAAM;;IAE1B;IACAH,EAAE,CAACK,MAAM,CAACF,MAAM,CAACG,aAAa,CAAC,CAACC,eAAe,CAC7CC,OAAO,CAACC,OAAO,CACb;MACEC,iBAAiB,EAAE;IACrB,CACF,CACF,CAAC;EACH,CAAC,CAAC;EAEF,MAAMC,SAAS,GAAG,CAChB;IACEC,QAAQ,EAAE,UAAU;IACpBC,WAAW,EAAE,UAAU;IACvBC,WAAW,EAAE;EACf,CAAC,EACD;IACEF,QAAQ,EAAE,UAAU;IACpBC,WAAW,EAAE,UAAU;IACvBC,WAAW,EAAE;EACf,CAAC,EACD;IACEF,QAAQ,EAAE,UAAU;IACpBC,WAAW,EAAE,UAAU;IACvBC,WAAW,EAAE;EACf,CAAC,CACF;EAEDf,EAAE,CAAC,yBAAyB,EAAE,YAAY;IACxC,MAAMgB,MAAM,GAAG,IAAId,gBAAgB,CAACE,MAAM,EAAE,EAAE,EAAE,MAAO,CAAC,CAAC,WAAW,CAAC;IAErE,MAAMa,YAAY,GAAGZ,UAAU,CAACa,iBAAiB,CAAC,CAAC;IACnD,MAAMC,aAAa,GAAGd,UAAU,CAACa,iBAAiB,CAAC,CAAC;IAEpD,MAAME,KAAK,GAAGJ,MAAM,CAACK,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC;IACzC,MAAMC,KAAK,GAAGN,MAAM,CAACK,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC;IACzC,MAAME,KAAK,GAAGP,MAAM,CAACK,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC;IAEzCJ,YAAY,CAACP,OAAO,CAAC;MACnBc,IAAI,EAAE,CAACZ,SAAS,CAAC,CAAC,CAAC,EAAEA,SAAS,CAAC,CAAC,CAAC,CAAC;MAClCa,aAAa,EAAEC,SAAS;MACxBC,UAAU,EAAE;IACd,CAAC,CAAC;IAEF,MAAM5B,MAAM,CAACqB,KAAK,CAAC,CAACQ,QAAQ,CAACC,aAAa,CAAC;MACzCd,WAAW,EAAE;IACf,CAAC,CAAC;IAEF,MAAMhB,MAAM,CAACuB,KAAK,CAAC,CAACM,QAAQ,CAACC,aAAa,CAAC;MACzCd,WAAW,EAAE;IACf,CAAC,CAAC;IAEF,MAAMe,IAAI,GAAG7B,EAAE,CAAC8B,EAAE,CAAC,CAAC;IACpB,KAAKR,KAAK,CAACS,IAAI,CAACF,IAAI,CAAC;IACrB/B,MAAM,CAAC+B,IAAI,CAAC,CAACG,GAAG,CAACC,gBAAgB,CAAC,CAAC;IAEnCf,aAAa,CAACT,OAAO,CAAC;MACpBc,IAAI,EAAE,CAACZ,SAAS,CAAC,CAAC,CAAC,CAAC;MACpBa,aAAa,EAAEC,SAAS;MACxBC,UAAU,EAAE;IACd,CAAC,CAAC;IAEF,MAAM5B,MAAM,CAACwB,KAAK,CAAC,CAACK,QAAQ,CAACC,aAAa,CAAC;MACzCd,WAAW,EAAE;IACf,CAAC,CAAC;IAEFhB,MAAM,CAAC+B,IAAI,CAAC,CAACI,gBAAgB,CAAC,CAAC;EACjC,CAAC,CAAC;EAEFlC,EAAE,CAAC,wBAAwB,EAAE,YAAY;IACvC,MAAMgB,MAAM,GAAG,IAAId,gBAAgB,CAACE,MAAM,EAAE,MAAO,EAAE,EAAE,WAAY,GAAG,CAAC;IAEvE,MAAMa,YAAY,GAAGZ,UAAU,CAACa,iBAAiB,CAAC,CAAC;IACnD,MAAMC,aAAa,GAAGd,UAAU,CAACa,iBAAiB,CAAC,CAAC;IAEpDjB,EAAE,CAACkC,aAAa,CAAC,CAAC;IAElB,MAAMf,KAAK,GAAGJ,MAAM,CAACK,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC;IAEzCpB,EAAE,CAACmC,mBAAmB,CAAC,EAAE,CAAC;IAE1B,MAAMd,KAAK,GAAGN,MAAM,CAACK,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC;IACzC,MAAME,KAAK,GAAGP,MAAM,CAACK,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC;IAEzCJ,YAAY,CAACP,OAAO,CAAC;MACnBc,IAAI,EAAE,CAACZ,SAAS,CAAC,CAAC,CAAC,CAAC;MACpBa,aAAa,EAAEC,SAAS;MACxBC,UAAU,EAAE;IACd,CAAC,CAAC;IAEF1B,EAAE,CAACoC,oBAAoB,CAAC,CAAC;IAEzB,MAAMtC,MAAM,CAACqB,KAAK,CAAC,CAACQ,QAAQ,CAACC,aAAa,CAAC;MACzCd,WAAW,EAAE;IACf,CAAC,CAAC;IAEF,MAAMuB,QAAQ,GAAGrC,EAAE,CAAC8B,EAAE,CAAC,CAAC;IACxB,KAAKR,KAAK,CAACS,IAAI,CAACM,QAAQ,CAAC;IAEzBvC,MAAM,CAACuC,QAAQ,CAAC,CAACL,GAAG,CAACC,gBAAgB,CAAC,CAAC;IAEvCf,aAAa,CAACT,OAAO,CAAC;MACpBc,IAAI,EAAE,CACJZ,SAAS,CAAC,CAAC,CAAC,EACZA,SAAS,CAAC,CAAC,CAAC,CACb;MACDa,aAAa,EAAEC,SAAS;MACxBC,UAAU,EAAE;IACd,CAAC,CAAC;IAEF,MAAM5B,MAAM,CAACuB,KAAK,CAAC,CAACM,QAAQ,CAACC,aAAa,CAAC;MACzCd,WAAW,EAAE;IACf,CAAC,CAAC;IAEF,MAAMhB,MAAM,CAACwB,KAAK,CAAC,CAACK,QAAQ,CAACC,aAAa,CAAC;MACzCd,WAAW,EAAE;IACf,CAAC,CAAC;IAEFhB,MAAM,CAACuC,QAAQ,CAAC,CAACJ,gBAAgB,CAAC,CAAC;IAEnCjC,EAAE,CAACsC,aAAa,CAAC,CAAC;EACpB,CAAC,CAAC;EAEFvC,EAAE,CAAC,yDAAyD,EAAE,YAAY;IACxE,MAAMgB,MAAM,GAAG,IAAId,gBAAgB,CAACE,MAAM,EAAE,EAAE,EAAE,GAAG,CAAC;IAEpDH,EAAE,CAACkC,aAAa,CAAC,CAAC;IAElB,MAAMK,YAAiD,GAAG,EAAE;IAE5D,MAAMC,aAA8C,GAAG;MACrDC,KAAK,EAAGC,MAAM,IAAK;QACjBH,YAAY,CAACI,IAAI,CAACD,MAAM,CAAC;QACzB,OAAOF,aAAa;MACtB,CAAC;MACDI,SAAS,EAAE5C,EAAE,CAAC8B,EAAE,CAAC,CAAC,CAACe,iBAAiB,CAAC;QACnCtB,IAAI,EAAE,CAACZ,SAAS,CAAC,CAAC,CAAC,CAAC;QACpBa,aAAa,EAAEC,SAAS;QACxBC,UAAU,EAAE;MACd,CAAC;IACH,CAGoC;IAEpCvB,MAAM,CAAC2C,mBAAmB,CAACN,aAAa,CAAC;IACzC,MAAMrB,KAAK,GAAGJ,MAAM,CAACK,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC;IAEzCpB,EAAE,CAACmC,mBAAmB,CAAC,EAAE,CAAC;IAE1B,MAAMhB,KAAK;IAEXrB,MAAM,CAACyC,YAAY,CAAC,CAAC,CAAC,CAAC,CAACQ,OAAO,CAAC;MAC9BC,EAAE,EAAE;QAAEC,GAAG,EAAE;MAAE;IACf,CAAC,CAAC;IAEFV,YAAY,CAACW,MAAM,GAAG,CAAC;IAEvB,MAAMC,cAA+C,GAAG;MACtDV,KAAK,EAAGC,MAAM,IAAK;QACjBH,YAAY,CAACI,IAAI,CAACD,MAAM,CAAC;QACzB,OAAOS,cAAc;MACvB,CAAC;MACDP,SAAS,EAAE5C,EAAE,CAAC8B,EAAE,CAAC,CAAC,CAACe,iBAAiB,CAAC;QACnCtB,IAAI,EAAE,CAACZ,SAAS,CAAC,CAAC,CAAC,EAAEA,SAAS,CAAC,CAAC,CAAC,CAAC;QAClCa,aAAa,EAAEC,SAAS;QACxBC,UAAU,EAAE;MACd,CAAC;IACH,CAGoC;IAEpCvB,MAAM,CAAC2C,mBAAmB,CAACK,cAAc,CAAC;IAE1C,MAAM9B,KAAK,GAAGN,MAAM,CAACK,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC;IACzC,MAAME,KAAK,GAAGP,MAAM,CAACK,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC;IAEzCpB,EAAE,CAACmC,mBAAmB,CAAC,EAAE,CAAC;IAE1B,MAAM3B,OAAO,CAAC4C,GAAG,CAAC,CAAC/B,KAAK,EAAEC,KAAK,CAAC,CAAC;IAEjCxB,MAAM,CAACyC,YAAY,CAAC,CAAC,CAAC,CAAC,CAACQ,OAAO,CAAC;MAC9BC,EAAE,EAAE;QAAEK,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;MAAE;IACpB,CAAC,CAAC;IAEFrD,EAAE,CAACsC,aAAa,CAAC,CAAC;EACpB,CAAC,CAAC;AACJ,CAAC,CAAC","ignoreList":[]}
1
+ {"version":3,"file":"BulkObjectLoader.test.js","names":["beforeEach","describe","expect","it","vi","BulkObjectLoader","createClientMockHelper","client","mockClient","mocked","fetchMetadata","mockReturnValue","Promise","resolve","primaryKeyApiName","employees","$apiName","$objectType","$primaryKey","loader","firstRequest","mockFetchPageOnce","secondRequest","load0","fetch","load1","load2","data","nextPageToken","undefined","totalCount","resolves","toMatchObject","mock","fn","then","not","toHaveBeenCalled","useFakeTimers","advanceTimersByTime","runOnlyPendingTimers","mockThen","useRealTimers","whereClauses","mockObjectSet","where","clause","push","fetchPage","mockResolvedValue","mockReturnValueOnce","toEqual","id","$eq","length","mockObjectSet2","all","$in","os","mockResolvedValueOnce","type","implementedBy","links","apiName","displayName","description","properties","rid","loadPromise","rejects","toThrow"],"sources":["BulkObjectLoader.test.ts"],"sourcesContent":["/*\n * Copyright 2025 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n InterfaceMetadata,\n ObjectMetadata,\n ObjectSet,\n ObjectTypeDefinition,\n WhereClause,\n} from \"@osdk/api\";\nimport type { Mock } from \"vitest\";\nimport { beforeEach, describe, expect, it, vi } from \"vitest\";\nimport type { Client } from \"../../Client.js\";\nimport { BulkObjectLoader } from \"./BulkObjectLoader.js\";\nimport { createClientMockHelper, type MockClientHelper } from \"./testUtils.js\";\n\ndescribe(BulkObjectLoader, () => {\n let client: Mock<Client> & Client;\n let mockClient: MockClientHelper;\n\n beforeEach(async () => {\n mockClient = createClientMockHelper();\n client = mockClient.client;\n\n // eslint-disable-next-line @typescript-eslint/unbound-method\n vi.mocked(client.fetchMetadata).mockReturnValue(\n Promise.resolve(\n {\n primaryKeyApiName: \"id\",\n } satisfies Pick<ObjectMetadata, \"primaryKeyApiName\"> as ObjectMetadata,\n ),\n );\n });\n\n const employees = [\n {\n $apiName: \"Employee\",\n $objectType: \"Employee\",\n $primaryKey: 0,\n },\n {\n $apiName: \"Employee\",\n $objectType: \"Employee\",\n $primaryKey: 1,\n },\n {\n $apiName: \"Employee\",\n $objectType: \"Employee\",\n $primaryKey: 2,\n },\n ];\n\n it(\"splits up work by count\", async () => {\n const loader = new BulkObjectLoader(client, 25, /*ms*/ 2 /*entries*/);\n\n const firstRequest = mockClient.mockFetchPageOnce();\n const secondRequest = mockClient.mockFetchPageOnce();\n\n const load0 = loader.fetch(\"Employee\", 0);\n const load1 = loader.fetch(\"Employee\", 1);\n const load2 = loader.fetch(\"Employee\", 2);\n\n firstRequest.resolve({\n data: [employees[0], employees[1]],\n nextPageToken: undefined,\n totalCount: \"2\",\n });\n\n await expect(load0).resolves.toMatchObject({\n $primaryKey: 0,\n });\n\n await expect(load1).resolves.toMatchObject({\n $primaryKey: 1,\n });\n\n const mock = vi.fn();\n void load2.then(mock);\n expect(mock).not.toHaveBeenCalled();\n\n secondRequest.resolve({\n data: [employees[2]],\n nextPageToken: undefined,\n totalCount: \"1\",\n });\n\n await expect(load2).resolves.toMatchObject({\n $primaryKey: 2,\n });\n\n expect(mock).toHaveBeenCalled();\n });\n\n it(\"splits up work by time\", async () => {\n const loader = new BulkObjectLoader(client, /*ms*/ 25, /*entries*/ 100);\n\n const firstRequest = mockClient.mockFetchPageOnce();\n const secondRequest = mockClient.mockFetchPageOnce();\n\n vi.useFakeTimers();\n\n const load0 = loader.fetch(\"Employee\", 0);\n\n vi.advanceTimersByTime(26);\n\n const load1 = loader.fetch(\"Employee\", 1);\n const load2 = loader.fetch(\"Employee\", 2);\n\n firstRequest.resolve({\n data: [employees[0]],\n nextPageToken: undefined,\n totalCount: \"1\",\n });\n\n vi.runOnlyPendingTimers();\n\n await expect(load0).resolves.toMatchObject({\n $primaryKey: 0,\n });\n\n const mockThen = vi.fn();\n void load2.then(mockThen);\n\n expect(mockThen).not.toHaveBeenCalled();\n\n secondRequest.resolve({\n data: [\n employees[1],\n employees[2],\n ],\n nextPageToken: undefined,\n totalCount: \"2\",\n });\n\n await expect(load1).resolves.toMatchObject({\n $primaryKey: 1,\n });\n\n await expect(load2).resolves.toMatchObject({\n $primaryKey: 2,\n });\n\n expect(mockThen).toHaveBeenCalled();\n\n vi.useRealTimers();\n });\n\n it(\"uses $eq for single object and $in for multiple objects\", async () => {\n const loader = new BulkObjectLoader(client, 25, 100);\n\n vi.useFakeTimers();\n\n const whereClauses: WhereClause<ObjectTypeDefinition>[] = [];\n\n const mockObjectSet: ObjectSet<ObjectTypeDefinition> = {\n where: (clause) => {\n whereClauses.push(clause);\n return mockObjectSet;\n },\n fetchPage: vi.fn().mockResolvedValue({\n data: [employees[0]],\n nextPageToken: undefined,\n totalCount: \"1\",\n }),\n } as Pick<\n ObjectSet<ObjectTypeDefinition>,\n \"fetchPage\" | \"where\"\n > as ObjectSet<ObjectTypeDefinition>;\n\n client.mockReturnValueOnce(mockObjectSet);\n const load0 = loader.fetch(\"Employee\", 0);\n\n vi.advanceTimersByTime(26);\n\n await load0;\n\n expect(whereClauses[0]).toEqual({\n id: { $eq: 0 },\n });\n\n whereClauses.length = 0;\n\n const mockObjectSet2: ObjectSet<ObjectTypeDefinition> = {\n where: (clause) => {\n whereClauses.push(clause);\n return mockObjectSet2;\n },\n fetchPage: vi.fn().mockResolvedValue({\n data: [employees[1], employees[2]],\n nextPageToken: undefined,\n totalCount: \"2\",\n }),\n } as Pick<\n ObjectSet<ObjectTypeDefinition>,\n \"fetchPage\" | \"where\"\n > as ObjectSet<ObjectTypeDefinition>;\n\n client.mockReturnValueOnce(mockObjectSet2);\n\n const load1 = loader.fetch(\"Employee\", 1);\n const load2 = loader.fetch(\"Employee\", 2);\n\n vi.advanceTimersByTime(26);\n\n await Promise.all([load1, load2]);\n\n expect(whereClauses[0]).toEqual({\n id: { $in: [1, 2] },\n });\n\n vi.useRealTimers();\n });\n\n describe(\"interface loading\", () => {\n const mockObjectSet = (data: unknown[]) => {\n const os: ObjectSet<ObjectTypeDefinition> = {\n where: () => os,\n fetchPage: vi.fn().mockResolvedValue({ data }),\n } as Pick<\n ObjectSet<ObjectTypeDefinition>,\n \"fetchPage\" | \"where\"\n > as ObjectSet<ObjectTypeDefinition>;\n return os;\n };\n\n it(\"loads interface objects by querying implementing types\", async () => {\n const loader = new BulkObjectLoader(client, 25, 100);\n vi.useFakeTimers();\n\n // eslint-disable-next-line @typescript-eslint/unbound-method\n vi.mocked(client.fetchMetadata)\n .mockResolvedValueOnce(\n {\n type: \"interface\",\n implementedBy: [\"Employee\"],\n links: {},\n apiName: \"FooInterface\",\n displayName: \"FooInterface\",\n description: undefined,\n properties: {},\n rid: \"ri.test\",\n } satisfies InterfaceMetadata,\n )\n .mockResolvedValueOnce(\n { primaryKeyApiName: \"employeeId\" } as ObjectMetadata,\n );\n\n const fullObj = {\n $apiName: \"Employee\",\n $objectType: \"Employee\",\n $primaryKey: 1,\n };\n\n client.mockReturnValueOnce(mockObjectSet([fullObj]));\n\n const loadPromise = loader.fetch(\"FooInterface\", 1, \"interface\");\n vi.advanceTimersByTime(26);\n\n await expect(loadPromise).resolves.toMatchObject({ $primaryKey: 1 });\n vi.useRealTimers();\n });\n\n it(\"rejects when interface object is not found in any implementing type\", async () => {\n const loader = new BulkObjectLoader(client, 25, 100);\n vi.useFakeTimers();\n\n // eslint-disable-next-line @typescript-eslint/unbound-method\n vi.mocked(client.fetchMetadata)\n .mockResolvedValueOnce(\n {\n type: \"interface\",\n implementedBy: [\"Employee\"],\n links: {},\n apiName: \"FooInterface\",\n displayName: \"FooInterface\",\n description: undefined,\n properties: {},\n rid: \"ri.test\",\n } satisfies InterfaceMetadata,\n )\n .mockResolvedValueOnce(\n { primaryKeyApiName: \"employeeId\" } as ObjectMetadata,\n );\n\n client.mockReturnValueOnce(mockObjectSet([]));\n\n const loadPromise = loader.fetch(\"FooInterface\", 1, \"interface\");\n vi.advanceTimersByTime(26);\n\n await expect(loadPromise).rejects.toThrow(\n \"Interface FooInterface object not found: 1\",\n );\n vi.useRealTimers();\n });\n\n it(\"loads object type when defType='object' (default)\", async () => {\n const loader = new BulkObjectLoader(client, 25, 100);\n vi.useFakeTimers();\n\n const firstRequest = mockClient.mockFetchPageOnce();\n\n const loadPromise = loader.fetch(\"Employee\", 1);\n vi.advanceTimersByTime(26);\n\n firstRequest.resolve({\n data: [employees[1]],\n nextPageToken: undefined,\n totalCount: \"1\",\n });\n\n await expect(loadPromise).resolves.toMatchObject({ $primaryKey: 1 });\n vi.useRealTimers();\n });\n });\n});\n"],"mappings":"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","ignoreList":[]}
@@ -65,17 +65,11 @@ export class CacheKeys {
65
65
  });
66
66
  }
67
67
  get(type, ...args) {
68
- // Normalize trailing undefined values to ensure consistent cache key creation
69
- // This makes get("object", "Foo", 1, undefined) === get("object", "Foo", 1)
70
- const normalizedArgs = [...args];
71
- while (normalizedArgs.length > 0 && normalizedArgs[normalizedArgs.length - 1] === undefined) {
72
- normalizedArgs.pop();
73
- }
74
- const cacheKeyArgs = [type, ...normalizedArgs];
68
+ const cacheKeyArgs = this.#normalizeArgs(type, args);
75
69
  if (process.env.NODE_ENV !== "production" && DEBUG_CACHE_KEYS) {
76
70
  // eslint-disable-next-line no-console
77
71
  console.debug(`CacheKeys.get([${type},
78
- ${normalizedArgs.map(x => JSON.stringify(x)).join(", ")}]) - already exists? `, this.#cacheKeys.peekArray(cacheKeyArgs) != null);
72
+ ${cacheKeyArgs.slice(1).map(x => JSON.stringify(x)).join(", ")}]) - already exists? `, this.#cacheKeys.peekArray(cacheKeyArgs) != null);
79
73
  }
80
74
  const cacheKey = this.#cacheKeys.lookupArray(cacheKeyArgs);
81
75
 
@@ -84,6 +78,23 @@ export class CacheKeys {
84
78
  this.#refCounts.register(cacheKey);
85
79
  return cacheKey;
86
80
  }
81
+
82
+ /**
83
+ * Look up an existing cache key without creating or registering it.
84
+ * Returns undefined if the key does not exist in the trie.
85
+ */
86
+ peek(type, ...args) {
87
+ return this.#cacheKeys.peekArray(this.#normalizeArgs(type, args));
88
+ }
89
+ #normalizeArgs(type, args) {
90
+ // Normalize trailing undefined values to ensure consistent cache key lookup
91
+ // This makes ("object", "Foo", 1, undefined) equivalent to ("object", "Foo", 1)
92
+ const normalizedArgs = [...args];
93
+ while (normalizedArgs.length > 0 && normalizedArgs[normalizedArgs.length - 1] === undefined) {
94
+ normalizedArgs.pop();
95
+ }
96
+ return [type, ...normalizedArgs];
97
+ }
87
98
  retain(cacheKey) {
88
99
  this.#refCounts.retain(cacheKey);
89
100
  }
@@ -1 +1 @@
1
- {"version":3,"file":"CacheKeys.js","names":["Trie","DEBUG_CACHE_KEYS","DEBUG_REFCOUNTS","RefCounts","CacheKeys","cacheKeys","keys","cacheKey","type","otherKeys","slice","onCreate","console","log","JSON","stringify","finalizationRegistry","register","refCounts","k","cleanupCacheKey","onDestroy","constructor","setInterval","gc","FinalizationRegistry","cleanupCallback","e","error","get","args","normalizedArgs","length","undefined","pop","cacheKeyArgs","process","env","NODE_ENV","debug","map","x","join","peekArray","lookupArray","retain","release","remove","#remove","key"],"sources":["CacheKeys.ts"],"sourcesContent":["/*\n * Copyright 2025 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Trie } from \"@wry/trie\";\nimport { DEBUG_CACHE_KEYS, DEBUG_REFCOUNTS } from \"../DebugFlags.js\";\nimport type { CacheKey } from \"./CacheKey.js\";\nimport { RefCounts } from \"./RefCounts.js\";\n\n/**\n * Cache key management with canonicalization.\n * - Uses Trie structure for efficient storage and lookup\n */\nexport class CacheKeys<TCacheKey extends CacheKey> {\n #cacheKeys = new Trie<TCacheKey>(false, (keys) => {\n const cacheKey = {\n type: keys[0],\n otherKeys: keys.slice(1),\n } as unknown as TCacheKey;\n this.#onCreate?.(cacheKey);\n\n if (DEBUG_REFCOUNTS) {\n // eslint-disable-next-line no-console\n console.log(\n `CacheKeys.onCreate(${cacheKey.type}, ${\n JSON.stringify(cacheKey.otherKeys)\n })`,\n );\n\n this.#finalizationRegistry.register(cacheKey, () => {\n // eslint-disable-next-line no-console\n console.log(\n `CacheKey Finalization(${cacheKey.type}, ${\n JSON.stringify(cacheKey.otherKeys)\n })`,\n );\n });\n }\n return cacheKey;\n });\n\n #refCounts = new RefCounts<TCacheKey>(\n DEBUG_REFCOUNTS ? 15_000 : 60_000,\n (k) => this.#cleanupCacheKey(k),\n );\n\n // we are currently only using this for debug logging and should just remove it in the future if that\n // continues to be true\n #finalizationRegistry: FinalizationRegistry<() => void>;\n\n #onCreate?: (cacheKey: TCacheKey) => void;\n #onDestroy?: (cacheKey: TCacheKey) => void;\n\n constructor(\n { onCreate, onDestroy }: {\n onCreate?: (cacheKey: TCacheKey) => void;\n onDestroy?: (cacheKey: TCacheKey) => void;\n },\n ) {\n this.#onCreate = onCreate;\n this.#onDestroy = onDestroy;\n\n setInterval(() => {\n this.#refCounts.gc();\n }, 1000);\n\n this.#finalizationRegistry = new FinalizationRegistry<() => void>(\n (cleanupCallback) => {\n try {\n cleanupCallback();\n } catch (e) {\n // eslint-disable-next-line no-console\n console.error(\n \"Caught an error while running a finalization callback\",\n e,\n );\n }\n },\n );\n }\n\n get<K extends TCacheKey>(\n type: K[\"type\"],\n ...args: K[\"__cacheKey\"][\"args\"]\n ): K {\n // Normalize trailing undefined values to ensure consistent cache key creation\n // This makes get(\"object\", \"Foo\", 1, undefined) === get(\"object\", \"Foo\", 1)\n const normalizedArgs = [...args];\n while (\n normalizedArgs.length > 0\n && normalizedArgs[normalizedArgs.length - 1] === undefined\n ) {\n normalizedArgs.pop();\n }\n\n const cacheKeyArgs = [type, ...normalizedArgs];\n if (process.env.NODE_ENV !== \"production\" && DEBUG_CACHE_KEYS) {\n // eslint-disable-next-line no-console\n console.debug(\n `CacheKeys.get([${type},\n ${\n normalizedArgs.map(x => JSON.stringify(x)).join(\", \")\n }]) - already exists? `,\n this.#cacheKeys.peekArray(cacheKeyArgs) != null,\n );\n }\n\n const cacheKey = this.#cacheKeys.lookupArray(\n cacheKeyArgs,\n ) as K;\n\n // This is an idempotent call that ensures the cache key is registered for\n // cleanup. If already registered, this does nothing.\n this.#refCounts.register(cacheKey);\n\n return cacheKey;\n }\n\n retain(cacheKey: TCacheKey): void {\n this.#refCounts.retain(cacheKey);\n }\n\n release(cacheKey: TCacheKey): void {\n this.#refCounts.release(cacheKey);\n }\n\n #remove<K extends TCacheKey>(cacheKey: K): void {\n this.#cacheKeys.remove(cacheKey.type, ...cacheKey.otherKeys);\n }\n\n /**\n * Called after a key is no longer retained and the timeout has elapsed\n * @param key\n */\n #cleanupCacheKey = (key: TCacheKey) => {\n this.#onDestroy?.(key);\n this.#remove(key);\n };\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"CacheKeys.js","names":["Trie","DEBUG_CACHE_KEYS","DEBUG_REFCOUNTS","RefCounts","CacheKeys","cacheKeys","keys","cacheKey","type","otherKeys","slice","onCreate","console","log","JSON","stringify","finalizationRegistry","register","refCounts","k","cleanupCacheKey","onDestroy","constructor","setInterval","gc","FinalizationRegistry","cleanupCallback","e","error","get","args","cacheKeyArgs","normalizeArgs","process","env","NODE_ENV","debug","map","x","join","peekArray","lookupArray","peek","#normalizeArgs","normalizedArgs","length","undefined","pop","retain","release","remove","#remove","key"],"sources":["CacheKeys.ts"],"sourcesContent":["/*\n * Copyright 2025 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Trie } from \"@wry/trie\";\nimport { DEBUG_CACHE_KEYS, DEBUG_REFCOUNTS } from \"../DebugFlags.js\";\nimport type { CacheKey } from \"./CacheKey.js\";\nimport { RefCounts } from \"./RefCounts.js\";\n\n/**\n * Cache key management with canonicalization.\n * - Uses Trie structure for efficient storage and lookup\n */\nexport class CacheKeys<TCacheKey extends CacheKey> {\n #cacheKeys = new Trie<TCacheKey>(false, (keys) => {\n const cacheKey = {\n type: keys[0],\n otherKeys: keys.slice(1),\n } as unknown as TCacheKey;\n this.#onCreate?.(cacheKey);\n\n if (DEBUG_REFCOUNTS) {\n // eslint-disable-next-line no-console\n console.log(\n `CacheKeys.onCreate(${cacheKey.type}, ${\n JSON.stringify(cacheKey.otherKeys)\n })`,\n );\n\n this.#finalizationRegistry.register(cacheKey, () => {\n // eslint-disable-next-line no-console\n console.log(\n `CacheKey Finalization(${cacheKey.type}, ${\n JSON.stringify(cacheKey.otherKeys)\n })`,\n );\n });\n }\n return cacheKey;\n });\n\n #refCounts = new RefCounts<TCacheKey>(\n DEBUG_REFCOUNTS ? 15_000 : 60_000,\n (k) => this.#cleanupCacheKey(k),\n );\n\n // we are currently only using this for debug logging and should just remove it in the future if that\n // continues to be true\n #finalizationRegistry: FinalizationRegistry<() => void>;\n\n #onCreate?: (cacheKey: TCacheKey) => void;\n #onDestroy?: (cacheKey: TCacheKey) => void;\n\n constructor(\n { onCreate, onDestroy }: {\n onCreate?: (cacheKey: TCacheKey) => void;\n onDestroy?: (cacheKey: TCacheKey) => void;\n },\n ) {\n this.#onCreate = onCreate;\n this.#onDestroy = onDestroy;\n\n setInterval(() => {\n this.#refCounts.gc();\n }, 1000);\n\n this.#finalizationRegistry = new FinalizationRegistry<() => void>(\n (cleanupCallback) => {\n try {\n cleanupCallback();\n } catch (e) {\n // eslint-disable-next-line no-console\n console.error(\n \"Caught an error while running a finalization callback\",\n e,\n );\n }\n },\n );\n }\n\n get<K extends TCacheKey>(\n type: K[\"type\"],\n ...args: K[\"__cacheKey\"][\"args\"]\n ): K {\n const cacheKeyArgs = this.#normalizeArgs(type, args);\n if (process.env.NODE_ENV !== \"production\" && DEBUG_CACHE_KEYS) {\n // eslint-disable-next-line no-console\n console.debug(\n `CacheKeys.get([${type},\n ${\n cacheKeyArgs.slice(1).map(x => JSON.stringify(x)).join(\", \")\n }]) - already exists? `,\n this.#cacheKeys.peekArray(cacheKeyArgs) != null,\n );\n }\n\n const cacheKey = this.#cacheKeys.lookupArray(\n cacheKeyArgs,\n ) as K;\n\n // This is an idempotent call that ensures the cache key is registered for\n // cleanup. If already registered, this does nothing.\n this.#refCounts.register(cacheKey);\n\n return cacheKey;\n }\n\n /**\n * Look up an existing cache key without creating or registering it.\n * Returns undefined if the key does not exist in the trie.\n */\n peek<K extends TCacheKey>(\n type: K[\"type\"],\n ...args: K[\"__cacheKey\"][\"args\"]\n ): K | undefined {\n return this.#cacheKeys.peekArray(\n this.#normalizeArgs(type, args),\n ) as K | undefined;\n }\n\n #normalizeArgs(\n type: TCacheKey[\"type\"],\n args: unknown[],\n ): unknown[] {\n // Normalize trailing undefined values to ensure consistent cache key lookup\n // This makes (\"object\", \"Foo\", 1, undefined) equivalent to (\"object\", \"Foo\", 1)\n const normalizedArgs = [...args];\n while (\n normalizedArgs.length > 0\n && normalizedArgs[normalizedArgs.length - 1] === undefined\n ) {\n normalizedArgs.pop();\n }\n return [type, ...normalizedArgs];\n }\n\n retain(cacheKey: TCacheKey): void {\n this.#refCounts.retain(cacheKey);\n }\n\n release(cacheKey: TCacheKey): void {\n this.#refCounts.release(cacheKey);\n }\n\n #remove<K extends TCacheKey>(cacheKey: K): void {\n this.#cacheKeys.remove(cacheKey.type, ...cacheKey.otherKeys);\n }\n\n /**\n * Called after a key is no longer retained and the timeout has elapsed\n * @param key\n */\n #cleanupCacheKey = (key: TCacheKey) => {\n this.#onDestroy?.(key);\n this.#remove(key);\n };\n}\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,120 @@
1
+ /*
2
+ * Copyright 2025 Palantir Technologies, Inc. All rights reserved.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ /**
18
+ * Interface for the query methods that ListQueryView needs.
19
+ * This allows ListQueryView to work with any query that supports these operations.
20
+ */
21
+
22
+ /**
23
+ * A view into a shared ListQuery cache.
24
+ *
25
+ * Each subscriber gets their own View instance that tracks how much of the
26
+ * shared cache they want to see (viewLimit). This allows multiple components
27
+ * with different pageSize requirements to share the same underlying cache.
28
+ *
29
+ * The View:
30
+ * - Slices the shared data to the subscriber's viewLimit
31
+ * - Provides a fetchMore that increments viewLimit and fetches if needed
32
+ * - Reports hasMore based on both local viewLimit and server pagination
33
+ */
34
+ let viewIdCounter = 0;
35
+ export class ListQueryView {
36
+ #query;
37
+ #viewLimit;
38
+ #pageSize;
39
+ #viewId;
40
+ #hasAutoFetch;
41
+ #fetchMore;
42
+ #pendingFetchMore;
43
+ #lastPayload;
44
+ #observer;
45
+ constructor(query, pageSize, autoFetchMore) {
46
+ this.#query = query;
47
+ this.#pageSize = pageSize;
48
+ this.#viewId = `view_${++viewIdCounter}`;
49
+
50
+ // With autoFetchMore, subscriber sees all loaded data (no view limit)
51
+ // Otherwise, limit to their pageSize
52
+ this.#hasAutoFetch = autoFetchMore === true || typeof autoFetchMore === "number" && autoFetchMore > 0;
53
+ this.#viewLimit = this.#hasAutoFetch ? Number.MAX_SAFE_INTEGER : pageSize;
54
+
55
+ // Memoize fetchMore to maintain stable function identity
56
+ this.#fetchMore = this.#createFetchMore();
57
+
58
+ // Tell the query to fetch with at least this pageSize
59
+ query.registerFetchPageSize(this.#viewId, pageSize);
60
+ }
61
+ subscribe(observer) {
62
+ this.#observer = observer;
63
+ const sub = this.#query.subscribe({
64
+ next: payload => {
65
+ this.#lastPayload = payload;
66
+ observer.next?.(this.#transformPayload(payload));
67
+ if (!this.#hasAutoFetch && payload.status === "loaded" && payload.resolvedList.length < this.#viewLimit && this.#query.hasMorePages()) {
68
+ void this.#query.fetchMore();
69
+ }
70
+ },
71
+ error: err => observer.error?.(err),
72
+ complete: () => observer.complete?.()
73
+ });
74
+
75
+ // Cleanup: unregister pageSize when subscriber unsubscribes
76
+ sub.add(() => {
77
+ this.#query.unregisterFetchPageSize(this.#viewId);
78
+ this.#observer = undefined;
79
+ this.#lastPayload = undefined;
80
+ });
81
+ return sub;
82
+ }
83
+ #reEmitWithNewViewLimit() {
84
+ if (this.#lastPayload && this.#observer) {
85
+ this.#observer.next?.(this.#transformPayload(this.#lastPayload));
86
+ }
87
+ }
88
+ #transformPayload(payload) {
89
+ const loadedCount = payload.resolvedList.length;
90
+ return {
91
+ ...payload,
92
+ resolvedList: payload.resolvedList.slice(0, this.#viewLimit),
93
+ hasMore: this.#viewLimit < loadedCount || payload.hasMore,
94
+ fetchMore: this.#fetchMore,
95
+ status: loadedCount >= this.#viewLimit && payload.status === "loading" ? "loaded" : payload.status
96
+ };
97
+ }
98
+ #createFetchMore() {
99
+ return () => {
100
+ if (this.#pendingFetchMore) {
101
+ return this.#pendingFetchMore;
102
+ }
103
+ this.#viewLimit += this.#pageSize;
104
+ const loadedCount = this.#query.getLoadedCount();
105
+ const hasMoreOnServer = this.#query.hasMorePages();
106
+ if (this.#viewLimit > loadedCount && hasMoreOnServer) {
107
+ // Need to fetch more data from server
108
+ this.#pendingFetchMore = this.#query.fetchMore().finally(() => {
109
+ this.#pendingFetchMore = undefined;
110
+ });
111
+ return this.#pendingFetchMore;
112
+ }
113
+
114
+ // We have enough data in cache, just re-emit with new viewLimit (sync)
115
+ this.#reEmitWithNewViewLimit();
116
+ return Promise.resolve();
117
+ };
118
+ }
119
+ }
120
+ //# sourceMappingURL=ListQueryView.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ListQueryView.js","names":["viewIdCounter","ListQueryView","query","viewLimit","pageSize","viewId","hasAutoFetch","fetchMore","pendingFetchMore","lastPayload","observer","constructor","autoFetchMore","Number","MAX_SAFE_INTEGER","createFetchMore","registerFetchPageSize","subscribe","sub","next","payload","transformPayload","status","resolvedList","length","hasMorePages","error","err","complete","add","unregisterFetchPageSize","undefined","reEmitWithNewViewLimit","#reEmitWithNewViewLimit","#transformPayload","loadedCount","slice","hasMore","#createFetchMore","getLoadedCount","hasMoreOnServer","finally","Promise","resolve"],"sources":["ListQueryView.ts"],"sourcesContent":["/*\n * Copyright 2025 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { Subscription } from \"rxjs\";\nimport type { Observer } from \"../ObservableClient/common.js\";\nimport type { BaseListPayloadShape } from \"./base-list/BaseListQuery.js\";\n\n/**\n * Interface for the query methods that ListQueryView needs.\n * This allows ListQueryView to work with any query that supports these operations.\n */\nexport interface ListQueryViewTarget<PAYLOAD extends BaseListPayloadShape> {\n subscribe(observer: Observer<PAYLOAD>): Subscription;\n registerFetchPageSize(viewId: string, pageSize: number): void;\n unregisterFetchPageSize(viewId: string): void;\n getLoadedCount(): number;\n hasMorePages(): boolean;\n notifySubscribers(): void;\n fetchMore(): Promise<void>;\n}\n\n/**\n * A view into a shared ListQuery cache.\n *\n * Each subscriber gets their own View instance that tracks how much of the\n * shared cache they want to see (viewLimit). This allows multiple components\n * with different pageSize requirements to share the same underlying cache.\n *\n * The View:\n * - Slices the shared data to the subscriber's viewLimit\n * - Provides a fetchMore that increments viewLimit and fetches if needed\n * - Reports hasMore based on both local viewLimit and server pagination\n */\nlet viewIdCounter = 0;\n\nexport class ListQueryView<PAYLOAD extends BaseListPayloadShape> {\n #query: ListQueryViewTarget<PAYLOAD>;\n #viewLimit: number;\n #pageSize: number;\n #viewId: string;\n #hasAutoFetch: boolean;\n #fetchMore: () => Promise<void>;\n #pendingFetchMore: Promise<void> | undefined;\n #lastPayload: PAYLOAD | undefined;\n #observer: Observer<PAYLOAD> | undefined;\n\n constructor(\n query: ListQueryViewTarget<PAYLOAD>,\n pageSize: number,\n autoFetchMore?: boolean | number,\n ) {\n this.#query = query;\n this.#pageSize = pageSize;\n this.#viewId = `view_${++viewIdCounter}`;\n\n // With autoFetchMore, subscriber sees all loaded data (no view limit)\n // Otherwise, limit to their pageSize\n this.#hasAutoFetch = autoFetchMore === true\n || (typeof autoFetchMore === \"number\" && autoFetchMore > 0);\n this.#viewLimit = this.#hasAutoFetch ? Number.MAX_SAFE_INTEGER : pageSize;\n\n // Memoize fetchMore to maintain stable function identity\n this.#fetchMore = this.#createFetchMore();\n\n // Tell the query to fetch with at least this pageSize\n query.registerFetchPageSize(this.#viewId, pageSize);\n }\n\n subscribe(observer: Observer<PAYLOAD>): Subscription {\n this.#observer = observer;\n const sub = this.#query.subscribe({\n next: (payload) => {\n this.#lastPayload = payload;\n observer.next?.(this.#transformPayload(payload));\n\n if (\n !this.#hasAutoFetch\n && payload.status === \"loaded\"\n && payload.resolvedList.length < this.#viewLimit\n && this.#query.hasMorePages()\n ) {\n void this.#query.fetchMore();\n }\n },\n error: (err) => observer.error?.(err),\n complete: () => observer.complete?.(),\n });\n\n // Cleanup: unregister pageSize when subscriber unsubscribes\n sub.add(() => {\n this.#query.unregisterFetchPageSize(this.#viewId);\n this.#observer = undefined;\n this.#lastPayload = undefined;\n });\n\n return sub;\n }\n\n #reEmitWithNewViewLimit(): void {\n if (this.#lastPayload && this.#observer) {\n this.#observer.next?.(this.#transformPayload(this.#lastPayload));\n }\n }\n\n #transformPayload(payload: PAYLOAD): PAYLOAD {\n const loadedCount = payload.resolvedList.length;\n\n return {\n ...payload,\n resolvedList: payload.resolvedList.slice(0, this.#viewLimit),\n hasMore: this.#viewLimit < loadedCount || payload.hasMore,\n fetchMore: this.#fetchMore,\n status: loadedCount >= this.#viewLimit && payload.status === \"loading\"\n ? \"loaded\"\n : payload.status,\n };\n }\n\n #createFetchMore(): () => Promise<void> {\n return () => {\n if (this.#pendingFetchMore) {\n return this.#pendingFetchMore;\n }\n\n this.#viewLimit += this.#pageSize;\n\n const loadedCount = this.#query.getLoadedCount();\n const hasMoreOnServer = this.#query.hasMorePages();\n\n if (this.#viewLimit > loadedCount && hasMoreOnServer) {\n // Need to fetch more data from server\n this.#pendingFetchMore = this.#query.fetchMore().finally(() => {\n this.#pendingFetchMore = undefined;\n });\n return this.#pendingFetchMore;\n }\n\n // We have enough data in cache, just re-emit with new viewLimit (sync)\n this.#reEmitWithNewViewLimit();\n return Promise.resolve();\n };\n }\n}\n"],"mappings":"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","ignoreList":[]}