@osdk/client 2.1.1 → 2.2.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 (402) hide show
  1. package/CHANGELOG.md +129 -181
  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/ActionValidationError.js +1 -1
  6. package/build/browser/actions/ActionValidationError.js.map +1 -1
  7. package/build/browser/actions/actions.test.js +164 -87
  8. package/build/browser/actions/actions.test.js.map +1 -1
  9. package/build/browser/actions/applyAction.js +21 -15
  10. package/build/browser/actions/applyAction.js.map +1 -1
  11. package/build/browser/createClient.js +19 -8
  12. package/build/browser/createClient.js.map +1 -1
  13. package/build/browser/createClient.test.js +14 -6
  14. package/build/browser/createClient.test.js.map +1 -1
  15. package/build/browser/createMinimalClient.js +2 -2
  16. package/build/browser/createMinimalClient.js.map +1 -1
  17. package/build/browser/createMinimalClientHelper.js +25 -0
  18. package/build/browser/createMinimalClientHelper.js.map +1 -0
  19. package/build/browser/derivedProperties/createWithPropertiesObjectSet.js +106 -0
  20. package/build/browser/derivedProperties/createWithPropertiesObjectSet.js.map +1 -0
  21. package/build/browser/derivedProperties/createWithPropertiesObjectSet.test.js +100 -0
  22. package/build/browser/derivedProperties/createWithPropertiesObjectSet.test.js.map +1 -0
  23. package/build/browser/fetchMetadata.test.js +11 -9
  24. package/build/browser/fetchMetadata.test.js.map +1 -1
  25. package/build/browser/index.js +1 -0
  26. package/build/browser/index.js.map +1 -1
  27. package/build/browser/intellisense.test.js +5 -1
  28. package/build/browser/intellisense.test.js.map +1 -1
  29. package/build/browser/internal/conversions/modernToLegacyGroupByClause.js +7 -0
  30. package/build/browser/internal/conversions/modernToLegacyGroupByClause.js.map +1 -1
  31. package/build/browser/internal/conversions/modernToLegacyWhereClause.js +1 -1
  32. package/build/browser/internal/conversions/modernToLegacyWhereClause.js.map +1 -1
  33. package/build/browser/logger/BaseLogger.js +53 -0
  34. package/build/browser/logger/BaseLogger.js.map +1 -0
  35. package/build/{esm → browser/logger}/Logger.js.map +1 -1
  36. package/build/browser/logger/MinimalLogger.js +41 -0
  37. package/build/browser/logger/MinimalLogger.js.map +1 -0
  38. package/build/browser/object/AttachmentUpload.js +3 -0
  39. package/build/browser/object/AttachmentUpload.js.map +1 -1
  40. package/build/browser/object/SimpleOsdkProperties.js +2 -0
  41. package/build/browser/object/SimpleOsdkProperties.js.map +1 -0
  42. package/build/browser/object/aggregate.test.js +12 -2
  43. package/build/browser/object/aggregate.test.js.map +1 -1
  44. package/build/browser/object/attachment.test.js +20 -7
  45. package/build/browser/object/attachment.test.js.map +1 -1
  46. package/build/browser/object/convertWireToOsdkObjects/BaseHolder.js +2 -0
  47. package/build/browser/object/convertWireToOsdkObjects/BaseHolder.js.map +1 -0
  48. package/build/browser/object/convertWireToOsdkObjects/InterfaceHolder.js.map +1 -1
  49. package/build/browser/object/convertWireToOsdkObjects/ObjectHolder.js.map +1 -1
  50. package/build/browser/object/convertWireToOsdkObjects/createOsdkInterface.js +25 -0
  51. package/build/browser/object/convertWireToOsdkObjects/createOsdkInterface.js.map +1 -1
  52. package/build/browser/object/convertWireToOsdkObjects/createOsdkObject.js +10 -3
  53. package/build/browser/object/convertWireToOsdkObjects/createOsdkObject.js.map +1 -1
  54. package/build/browser/object/convertWireToOsdkObjects/getDollarAs.js.map +1 -1
  55. package/build/browser/object/convertWireToOsdkObjects/getDollarLink.js.map +1 -1
  56. package/build/browser/object/convertWireToOsdkObjects.js +13 -4
  57. package/build/browser/object/convertWireToOsdkObjects.js.map +1 -1
  58. package/build/browser/object/convertWireToOsdkObjects.test.js +17 -11
  59. package/build/browser/object/convertWireToOsdkObjects.test.js.map +1 -1
  60. package/build/{esm/observable/internal/ChangedObjects.js → browser/object/createObjectSpecifierFromPrimaryKey.js} +3 -7
  61. package/build/browser/object/createObjectSpecifierFromPrimaryKey.js.map +1 -0
  62. package/build/browser/object/fetchPage.js +13 -1
  63. package/build/browser/object/fetchPage.js.map +1 -1
  64. package/build/browser/object/fetchPage.test.js +56 -2
  65. package/build/browser/object/fetchPage.test.js.map +1 -1
  66. package/build/browser/object/geotimeseriesreference.test.js +56 -134
  67. package/build/browser/object/geotimeseriesreference.test.js.map +1 -1
  68. package/build/browser/object/media.test.js +19 -14
  69. package/build/browser/object/media.test.js.map +1 -1
  70. package/build/browser/object/object.test.js +166 -66
  71. package/build/browser/object/object.test.js.map +1 -1
  72. package/build/browser/object/timeseries.test.js +119 -85
  73. package/build/browser/object/timeseries.test.js.map +1 -1
  74. package/build/browser/objectSet/InterfaceObjectSet.test.js +37 -17
  75. package/build/browser/objectSet/InterfaceObjectSet.test.js.map +1 -1
  76. package/build/browser/objectSet/ObjectSet.test.js +313 -79
  77. package/build/browser/objectSet/ObjectSet.test.js.map +1 -1
  78. package/build/browser/objectSet/ObjectSetListenerWebsocket.js +18 -14
  79. package/build/browser/objectSet/ObjectSetListenerWebsocket.js.map +1 -1
  80. package/build/browser/objectSet/ObjectSetListenerWebsocket.test.js +16 -9
  81. package/build/browser/objectSet/ObjectSetListenerWebsocket.test.js.map +1 -1
  82. package/build/browser/objectSet/createObjectSet.js +16 -0
  83. package/build/browser/objectSet/createObjectSet.js.map +1 -1
  84. package/build/browser/observable/ListPayload.js.map +1 -1
  85. package/build/browser/observable/ObjectPayload.js.map +1 -1
  86. package/build/browser/observable/ObservableClient.js.map +1 -1
  87. package/build/browser/observable/OptimisticBuilder.js.map +1 -1
  88. package/build/browser/observable/internal/ActionApplication.js +102 -0
  89. package/build/browser/observable/internal/ActionApplication.js.map +1 -0
  90. package/build/browser/observable/internal/BulkObjectLoader.js +93 -0
  91. package/build/browser/observable/internal/BulkObjectLoader.js.map +1 -0
  92. package/build/browser/observable/internal/BulkObjectLoader.test.js +112 -0
  93. package/build/browser/observable/internal/BulkObjectLoader.test.js.map +1 -0
  94. package/build/browser/observable/internal/CacheKey.js +38 -1
  95. package/build/browser/observable/internal/CacheKey.js.map +1 -1
  96. package/build/browser/observable/internal/CacheKeys.js +4 -4
  97. package/build/browser/observable/internal/CacheKeys.js.map +1 -1
  98. package/build/browser/observable/internal/Changes.js +58 -0
  99. package/build/browser/observable/internal/Changes.js.map +1 -0
  100. package/build/browser/observable/internal/Layer.js +6 -3
  101. package/build/browser/observable/internal/Layer.js.map +1 -1
  102. package/build/browser/observable/internal/ListQuery.js +495 -129
  103. package/build/browser/observable/internal/ListQuery.js.map +1 -1
  104. package/build/browser/observable/internal/ObjectQuery.js +40 -14
  105. package/build/browser/observable/internal/ObjectQuery.js.map +1 -1
  106. package/build/browser/observable/internal/ObservableClientImpl.js +4 -12
  107. package/build/browser/observable/internal/ObservableClientImpl.js.map +1 -1
  108. package/build/browser/observable/internal/OptimisticJob.js +30 -29
  109. package/build/browser/observable/internal/OptimisticJob.js.map +1 -1
  110. package/build/browser/observable/internal/OrderByCanonicalizer.js +73 -0
  111. package/build/browser/observable/internal/OrderByCanonicalizer.js.map +1 -0
  112. package/build/browser/observable/internal/OrderByCanonicalizer.test.js +78 -0
  113. package/build/browser/observable/internal/OrderByCanonicalizer.test.js.map +1 -0
  114. package/build/browser/observable/internal/Query.js +79 -6
  115. package/build/browser/observable/internal/Query.js.map +1 -1
  116. package/build/browser/observable/internal/RefCounts.js +7 -2
  117. package/build/browser/observable/internal/RefCounts.js.map +1 -1
  118. package/build/browser/observable/internal/SimpleWhereClause.js +2 -0
  119. package/build/browser/observable/internal/SimpleWhereClause.js.map +1 -0
  120. package/build/browser/observable/internal/Store.js +138 -188
  121. package/build/browser/observable/internal/Store.js.map +1 -1
  122. package/build/browser/observable/internal/Store.test.js +664 -255
  123. package/build/browser/observable/internal/Store.test.js.map +1 -1
  124. package/build/browser/observable/internal/WhereClauseCanonicalizer.js +11 -3
  125. package/build/browser/observable/internal/WhereClauseCanonicalizer.js.map +1 -1
  126. package/build/browser/observable/internal/objectMatchesWhereClause.js +0 -4
  127. package/build/browser/observable/internal/objectMatchesWhereClause.js.map +1 -1
  128. package/build/browser/observable/internal/objectMatchesWhereClause.test.js.map +1 -1
  129. package/build/browser/observable/internal/testUtils.js +222 -19
  130. package/build/browser/observable/internal/testUtils.js.map +1 -1
  131. package/build/browser/ontology/StandardOntologyProvider.test.js +17 -16
  132. package/build/browser/ontology/StandardOntologyProvider.test.js.map +1 -1
  133. package/build/browser/public/unstable-do-not-use.js.map +1 -1
  134. package/build/browser/queries/applyQuery.js +33 -1
  135. package/build/browser/queries/applyQuery.js.map +1 -1
  136. package/build/browser/queries/queries.test.js +36 -13
  137. package/build/browser/queries/queries.test.js.map +1 -1
  138. package/build/browser/tsserver.js.map +1 -1
  139. package/build/browser/util/UserAgent.js +1 -1
  140. package/build/browser/util/UserAgent.js.map +1 -1
  141. package/build/browser/util/toDataValue.js +10 -2
  142. package/build/browser/util/toDataValue.js.map +1 -1
  143. package/build/browser/util/toDataValue.test.js +37 -16
  144. package/build/browser/util/toDataValue.test.js.map +1 -1
  145. package/build/browser/util/toDataValueQueries.js +27 -2
  146. package/build/browser/util/toDataValueQueries.js.map +1 -1
  147. package/build/cjs/{Client-C8K3E1vH.d.cts → Client-DBTcM9gB.d.cts} +1 -1
  148. package/build/cjs/{chunk-FWVJ2AKD.cjs → chunk-EY52J5Z4.cjs} +25 -15
  149. package/build/cjs/chunk-EY52J5Z4.cjs.map +1 -0
  150. package/build/cjs/{chunk-DLSRNRTA.cjs → chunk-MCQVHD2F.cjs} +155 -42
  151. package/build/cjs/chunk-MCQVHD2F.cjs.map +1 -0
  152. package/build/cjs/chunk-T4NIFYZS.cjs +14 -0
  153. package/build/cjs/chunk-T4NIFYZS.cjs.map +1 -0
  154. package/build/cjs/{graphql-JJX5MZPQ.cjs → graphql-RGM5SRWV.cjs} +43 -2
  155. package/build/cjs/graphql-RGM5SRWV.cjs.map +1 -0
  156. package/build/cjs/index.cjs +265 -94
  157. package/build/cjs/index.cjs.map +1 -1
  158. package/build/cjs/index.d.cts +6 -4
  159. package/build/cjs/public/internal.cjs +6 -6
  160. package/build/cjs/public/internal.d.cts +1 -1
  161. package/build/cjs/public/unstable-do-not-use.cjs +1087 -470
  162. package/build/cjs/public/unstable-do-not-use.cjs.map +1 -1
  163. package/build/cjs/public/unstable-do-not-use.d.cts +37 -27
  164. package/build/esm/Client.js +1 -1
  165. package/build/esm/Client.js.map +1 -1
  166. package/build/esm/MinimalClientContext.js.map +1 -1
  167. package/build/esm/actions/ActionValidationError.js +1 -1
  168. package/build/esm/actions/ActionValidationError.js.map +1 -1
  169. package/build/esm/actions/actions.test.js +164 -87
  170. package/build/esm/actions/actions.test.js.map +1 -1
  171. package/build/esm/actions/applyAction.js +21 -15
  172. package/build/esm/actions/applyAction.js.map +1 -1
  173. package/build/esm/createClient.js +19 -8
  174. package/build/esm/createClient.js.map +1 -1
  175. package/build/esm/createClient.test.js +14 -6
  176. package/build/esm/createClient.test.js.map +1 -1
  177. package/build/esm/createMinimalClient.js +2 -2
  178. package/build/esm/createMinimalClient.js.map +1 -1
  179. package/build/esm/createMinimalClientHelper.js +25 -0
  180. package/build/esm/createMinimalClientHelper.js.map +1 -0
  181. package/build/esm/derivedProperties/createWithPropertiesObjectSet.js +106 -0
  182. package/build/esm/derivedProperties/createWithPropertiesObjectSet.js.map +1 -0
  183. package/build/esm/derivedProperties/createWithPropertiesObjectSet.test.js +100 -0
  184. package/build/esm/derivedProperties/createWithPropertiesObjectSet.test.js.map +1 -0
  185. package/build/esm/fetchMetadata.test.js +11 -9
  186. package/build/esm/fetchMetadata.test.js.map +1 -1
  187. package/build/esm/index.js +1 -0
  188. package/build/esm/index.js.map +1 -1
  189. package/build/esm/intellisense.test.js +5 -1
  190. package/build/esm/intellisense.test.js.map +1 -1
  191. package/build/esm/internal/conversions/modernToLegacyGroupByClause.js +7 -0
  192. package/build/esm/internal/conversions/modernToLegacyGroupByClause.js.map +1 -1
  193. package/build/esm/internal/conversions/modernToLegacyWhereClause.js +1 -1
  194. package/build/esm/internal/conversions/modernToLegacyWhereClause.js.map +1 -1
  195. package/build/esm/logger/BaseLogger.js +53 -0
  196. package/build/esm/logger/BaseLogger.js.map +1 -0
  197. package/build/{browser → esm/logger}/Logger.js.map +1 -1
  198. package/build/esm/logger/MinimalLogger.js +41 -0
  199. package/build/esm/logger/MinimalLogger.js.map +1 -0
  200. package/build/esm/object/AttachmentUpload.js +3 -0
  201. package/build/esm/object/AttachmentUpload.js.map +1 -1
  202. package/build/esm/object/SimpleOsdkProperties.js +2 -0
  203. package/build/esm/object/SimpleOsdkProperties.js.map +1 -0
  204. package/build/esm/object/aggregate.test.js +12 -2
  205. package/build/esm/object/aggregate.test.js.map +1 -1
  206. package/build/esm/object/attachment.test.js +20 -7
  207. package/build/esm/object/attachment.test.js.map +1 -1
  208. package/build/esm/object/convertWireToOsdkObjects/BaseHolder.js +2 -0
  209. package/build/esm/object/convertWireToOsdkObjects/BaseHolder.js.map +1 -0
  210. package/build/esm/object/convertWireToOsdkObjects/InterfaceHolder.js.map +1 -1
  211. package/build/esm/object/convertWireToOsdkObjects/ObjectHolder.js.map +1 -1
  212. package/build/esm/object/convertWireToOsdkObjects/createOsdkInterface.js +25 -0
  213. package/build/esm/object/convertWireToOsdkObjects/createOsdkInterface.js.map +1 -1
  214. package/build/esm/object/convertWireToOsdkObjects/createOsdkObject.js +10 -3
  215. package/build/esm/object/convertWireToOsdkObjects/createOsdkObject.js.map +1 -1
  216. package/build/esm/object/convertWireToOsdkObjects/getDollarAs.js.map +1 -1
  217. package/build/esm/object/convertWireToOsdkObjects/getDollarLink.js.map +1 -1
  218. package/build/esm/object/convertWireToOsdkObjects.js +13 -4
  219. package/build/esm/object/convertWireToOsdkObjects.js.map +1 -1
  220. package/build/esm/object/convertWireToOsdkObjects.test.js +17 -11
  221. package/build/esm/object/convertWireToOsdkObjects.test.js.map +1 -1
  222. package/build/{browser/observable/internal/ChangedObjects.js → esm/object/createObjectSpecifierFromPrimaryKey.js} +3 -7
  223. package/build/esm/object/createObjectSpecifierFromPrimaryKey.js.map +1 -0
  224. package/build/esm/object/fetchPage.js +13 -1
  225. package/build/esm/object/fetchPage.js.map +1 -1
  226. package/build/esm/object/fetchPage.test.js +56 -2
  227. package/build/esm/object/fetchPage.test.js.map +1 -1
  228. package/build/esm/object/geotimeseriesreference.test.js +56 -134
  229. package/build/esm/object/geotimeseriesreference.test.js.map +1 -1
  230. package/build/esm/object/media.test.js +19 -14
  231. package/build/esm/object/media.test.js.map +1 -1
  232. package/build/esm/object/object.test.js +166 -66
  233. package/build/esm/object/object.test.js.map +1 -1
  234. package/build/esm/object/timeseries.test.js +119 -85
  235. package/build/esm/object/timeseries.test.js.map +1 -1
  236. package/build/esm/objectSet/InterfaceObjectSet.test.js +37 -17
  237. package/build/esm/objectSet/InterfaceObjectSet.test.js.map +1 -1
  238. package/build/esm/objectSet/ObjectSet.test.js +313 -79
  239. package/build/esm/objectSet/ObjectSet.test.js.map +1 -1
  240. package/build/esm/objectSet/ObjectSetListenerWebsocket.js +18 -14
  241. package/build/esm/objectSet/ObjectSetListenerWebsocket.js.map +1 -1
  242. package/build/esm/objectSet/ObjectSetListenerWebsocket.test.js +16 -9
  243. package/build/esm/objectSet/ObjectSetListenerWebsocket.test.js.map +1 -1
  244. package/build/esm/objectSet/createObjectSet.js +16 -0
  245. package/build/esm/objectSet/createObjectSet.js.map +1 -1
  246. package/build/esm/observable/ListPayload.js.map +1 -1
  247. package/build/esm/observable/ObjectPayload.js.map +1 -1
  248. package/build/esm/observable/ObservableClient.js.map +1 -1
  249. package/build/esm/observable/OptimisticBuilder.js.map +1 -1
  250. package/build/esm/observable/internal/ActionApplication.js +102 -0
  251. package/build/esm/observable/internal/ActionApplication.js.map +1 -0
  252. package/build/esm/observable/internal/BulkObjectLoader.js +93 -0
  253. package/build/esm/observable/internal/BulkObjectLoader.js.map +1 -0
  254. package/build/esm/observable/internal/BulkObjectLoader.test.js +112 -0
  255. package/build/esm/observable/internal/BulkObjectLoader.test.js.map +1 -0
  256. package/build/esm/observable/internal/CacheKey.js +38 -1
  257. package/build/esm/observable/internal/CacheKey.js.map +1 -1
  258. package/build/esm/observable/internal/CacheKeys.js +4 -4
  259. package/build/esm/observable/internal/CacheKeys.js.map +1 -1
  260. package/build/esm/observable/internal/Changes.js +58 -0
  261. package/build/esm/observable/internal/Changes.js.map +1 -0
  262. package/build/esm/observable/internal/Layer.js +6 -3
  263. package/build/esm/observable/internal/Layer.js.map +1 -1
  264. package/build/esm/observable/internal/ListQuery.js +495 -129
  265. package/build/esm/observable/internal/ListQuery.js.map +1 -1
  266. package/build/esm/observable/internal/ObjectQuery.js +40 -14
  267. package/build/esm/observable/internal/ObjectQuery.js.map +1 -1
  268. package/build/esm/observable/internal/ObservableClientImpl.js +4 -12
  269. package/build/esm/observable/internal/ObservableClientImpl.js.map +1 -1
  270. package/build/esm/observable/internal/OptimisticJob.js +30 -29
  271. package/build/esm/observable/internal/OptimisticJob.js.map +1 -1
  272. package/build/esm/observable/internal/OrderByCanonicalizer.js +73 -0
  273. package/build/esm/observable/internal/OrderByCanonicalizer.js.map +1 -0
  274. package/build/esm/observable/internal/OrderByCanonicalizer.test.js +78 -0
  275. package/build/esm/observable/internal/OrderByCanonicalizer.test.js.map +1 -0
  276. package/build/esm/observable/internal/Query.js +79 -6
  277. package/build/esm/observable/internal/Query.js.map +1 -1
  278. package/build/esm/observable/internal/RefCounts.js +7 -2
  279. package/build/esm/observable/internal/RefCounts.js.map +1 -1
  280. package/build/esm/observable/internal/SimpleWhereClause.js +2 -0
  281. package/build/esm/observable/internal/SimpleWhereClause.js.map +1 -0
  282. package/build/esm/observable/internal/Store.js +138 -188
  283. package/build/esm/observable/internal/Store.js.map +1 -1
  284. package/build/esm/observable/internal/Store.test.js +664 -255
  285. package/build/esm/observable/internal/Store.test.js.map +1 -1
  286. package/build/esm/observable/internal/WhereClauseCanonicalizer.js +11 -3
  287. package/build/esm/observable/internal/WhereClauseCanonicalizer.js.map +1 -1
  288. package/build/esm/observable/internal/objectMatchesWhereClause.js +0 -4
  289. package/build/esm/observable/internal/objectMatchesWhereClause.js.map +1 -1
  290. package/build/esm/observable/internal/objectMatchesWhereClause.test.js.map +1 -1
  291. package/build/esm/observable/internal/testUtils.js +222 -19
  292. package/build/esm/observable/internal/testUtils.js.map +1 -1
  293. package/build/esm/ontology/StandardOntologyProvider.test.js +17 -16
  294. package/build/esm/ontology/StandardOntologyProvider.test.js.map +1 -1
  295. package/build/esm/public/unstable-do-not-use.js.map +1 -1
  296. package/build/esm/queries/applyQuery.js +33 -1
  297. package/build/esm/queries/applyQuery.js.map +1 -1
  298. package/build/esm/queries/queries.test.js +36 -13
  299. package/build/esm/queries/queries.test.js.map +1 -1
  300. package/build/esm/tsserver.js.map +1 -1
  301. package/build/esm/util/UserAgent.js +1 -1
  302. package/build/esm/util/UserAgent.js.map +1 -1
  303. package/build/esm/util/toDataValue.js +10 -2
  304. package/build/esm/util/toDataValue.js.map +1 -1
  305. package/build/esm/util/toDataValue.test.js +37 -16
  306. package/build/esm/util/toDataValue.test.js.map +1 -1
  307. package/build/esm/util/toDataValueQueries.js +27 -2
  308. package/build/esm/util/toDataValueQueries.js.map +1 -1
  309. package/build/types/Client.d.ts +2 -2
  310. package/build/types/Client.d.ts.map +1 -1
  311. package/build/types/MinimalClientContext.d.ts +1 -1
  312. package/build/types/MinimalClientContext.d.ts.map +1 -1
  313. package/build/types/actions/applyAction.d.ts.map +1 -1
  314. package/build/types/createClient.d.ts +1 -1
  315. package/build/types/createClient.d.ts.map +1 -1
  316. package/build/types/createClient.test.d.ts +2 -1
  317. package/build/types/createClient.test.d.ts.map +1 -1
  318. package/build/types/createMinimalClientHelper.d.ts +1 -0
  319. package/build/types/createMinimalClientHelper.d.ts.map +1 -0
  320. package/build/types/derivedProperties/createWithPropertiesObjectSet.d.ts +1 -0
  321. package/build/types/derivedProperties/createWithPropertiesObjectSet.d.ts.map +1 -0
  322. package/build/types/derivedProperties/createWithPropertiesObjectSet.test.d.ts +1 -0
  323. package/build/types/derivedProperties/createWithPropertiesObjectSet.test.d.ts.map +1 -0
  324. package/build/types/index.d.ts +3 -2
  325. package/build/types/index.d.ts.map +1 -1
  326. package/build/types/logger/BaseLogger.d.ts +31 -0
  327. package/build/types/logger/BaseLogger.d.ts.map +1 -0
  328. package/build/types/{Logger.d.ts → logger/Logger.d.ts} +1 -2
  329. package/build/types/logger/Logger.d.ts.map +1 -0
  330. package/build/types/logger/MinimalLogger.d.ts +8 -0
  331. package/build/types/logger/MinimalLogger.d.ts.map +1 -0
  332. package/build/types/object/AttachmentUpload.d.ts +3 -0
  333. package/build/types/object/AttachmentUpload.d.ts.map +1 -1
  334. package/build/types/object/SimpleOsdkProperties.d.ts +1 -0
  335. package/build/types/object/SimpleOsdkProperties.d.ts.map +1 -0
  336. package/build/types/object/convertWireToOsdkObjects/BaseHolder.d.ts +1 -0
  337. package/build/types/object/convertWireToOsdkObjects/BaseHolder.d.ts.map +1 -0
  338. package/build/types/object/convertWireToOsdkObjects.d.ts +8 -1
  339. package/build/types/object/convertWireToOsdkObjects.d.ts.map +1 -1
  340. package/build/types/object/createObjectSpecifierFromPrimaryKey.d.ts +2 -0
  341. package/build/types/object/createObjectSpecifierFromPrimaryKey.d.ts.map +1 -0
  342. package/build/types/object/object.test.d.ts.map +1 -1
  343. package/build/types/objectSet/ObjectSet.test.d.ts.map +1 -1
  344. package/build/types/observable/ListPayload.d.ts +5 -9
  345. package/build/types/observable/ListPayload.d.ts.map +1 -1
  346. package/build/types/observable/ObjectPayload.d.ts +4 -7
  347. package/build/types/observable/ObjectPayload.d.ts.map +1 -1
  348. package/build/types/observable/ObservableClient.d.ts +33 -10
  349. package/build/types/observable/ObservableClient.d.ts.map +1 -1
  350. package/build/types/observable/OptimisticBuilder.d.ts +1 -1
  351. package/build/types/observable/OptimisticBuilder.d.ts.map +1 -1
  352. package/build/types/observable/internal/ActionApplication.d.ts +9 -0
  353. package/build/types/observable/internal/ActionApplication.d.ts.map +1 -0
  354. package/build/types/observable/internal/BulkObjectLoader.d.ts +8 -0
  355. package/build/types/observable/internal/BulkObjectLoader.d.ts.map +1 -0
  356. package/build/types/observable/internal/BulkObjectLoader.test.d.ts +1 -0
  357. package/build/types/observable/internal/BulkObjectLoader.test.d.ts.map +1 -0
  358. package/build/types/observable/internal/CacheKeys.d.ts +2 -1
  359. package/build/types/observable/internal/CacheKeys.d.ts.map +1 -1
  360. package/build/types/observable/internal/Changes.d.ts +15 -0
  361. package/build/types/observable/internal/Changes.d.ts.map +1 -0
  362. package/build/types/observable/internal/Layer.d.ts +2 -1
  363. package/build/types/observable/internal/Layer.d.ts.map +1 -1
  364. package/build/types/observable/internal/ListQuery.d.ts +69 -23
  365. package/build/types/observable/internal/ListQuery.d.ts.map +1 -1
  366. package/build/types/observable/internal/ObjectQuery.d.ts +8 -9
  367. package/build/types/observable/internal/ObjectQuery.d.ts.map +1 -1
  368. package/build/types/observable/internal/OptimisticJob.d.ts +2 -2
  369. package/build/types/observable/internal/OptimisticJob.d.ts.map +1 -1
  370. package/build/types/observable/internal/OrderByCanonicalizer.d.ts +12 -0
  371. package/build/types/observable/internal/OrderByCanonicalizer.d.ts.map +1 -0
  372. package/build/types/observable/internal/OrderByCanonicalizer.test.d.ts +1 -0
  373. package/build/types/observable/internal/OrderByCanonicalizer.test.d.ts.map +1 -0
  374. package/build/types/observable/internal/Query.d.ts +45 -9
  375. package/build/types/observable/internal/Query.d.ts.map +1 -1
  376. package/build/types/observable/internal/RefCounts.d.ts.map +1 -1
  377. package/build/types/observable/internal/SimpleWhereClause.d.ts +2 -0
  378. package/build/types/observable/internal/SimpleWhereClause.d.ts.map +1 -0
  379. package/build/types/observable/internal/Store.d.ts +33 -29
  380. package/build/types/observable/internal/Store.d.ts.map +1 -1
  381. package/build/types/observable/internal/WhereClauseCanonicalizer.d.ts +2 -1
  382. package/build/types/observable/internal/WhereClauseCanonicalizer.d.ts.map +1 -1
  383. package/build/types/observable/internal/objectMatchesWhereClause.d.ts +4 -2
  384. package/build/types/observable/internal/objectMatchesWhereClause.d.ts.map +1 -1
  385. package/build/types/observable/internal/testUtils.d.ts +49 -9
  386. package/build/types/observable/internal/testUtils.d.ts.map +1 -1
  387. package/build/types/public/unstable-do-not-use.d.ts +1 -4
  388. package/build/types/public/unstable-do-not-use.d.ts.map +1 -1
  389. package/build/types/queries/applyQuery.d.ts.map +1 -1
  390. package/build/types/tsserver.d.ts +1 -1
  391. package/build/types/tsserver.d.ts.map +1 -1
  392. package/package.json +18 -14
  393. package/build/browser/observable/internal/ChangedObjects.js.map +0 -1
  394. package/build/cjs/chunk-DLSRNRTA.cjs.map +0 -1
  395. package/build/cjs/chunk-FWVJ2AKD.cjs.map +0 -1
  396. package/build/cjs/graphql-JJX5MZPQ.cjs.map +0 -1
  397. package/build/esm/observable/internal/ChangedObjects.js.map +0 -1
  398. package/build/types/Logger.d.ts.map +0 -1
  399. package/build/types/observable/internal/ChangedObjects.d.ts +0 -7
  400. package/build/types/observable/internal/ChangedObjects.d.ts.map +0 -1
  401. /package/build/browser/{Logger.js → logger/Logger.js} +0 -0
  402. /package/build/esm/{Logger.js → logger/Logger.js} +0 -0
@@ -14,14 +14,21 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
- import { $ontologyRid, createOffice, Employee, Todo } from "@osdk/client.test.ontology";
18
- import { apiServer } from "@osdk/shared.test";
17
+ import { createOffice, Employee, FooInterface, Todo } from "@osdk/client.test.ontology";
18
+ import { wireObjectTypeFullMetadataToSdkObjectMetadata } from "@osdk/generator-converters";
19
+ import { LegacyFauxFoundry, startNodeApiServer, stubData } from "@osdk/shared.test";
20
+ import chalk from "chalk";
19
21
  import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi, vitest } from "vitest";
20
22
  import { createClient } from "../../createClient.js";
23
+ import { createMinimalClient } from "../../createMinimalClient.js";
24
+ import { createObjectSet } from "../../objectSet/createObjectSet.js";
25
+ import { InterfaceDefinitions } from "../../ontology/OntologyProvider.js";
21
26
  import { createOptimisticId } from "./OptimisticId.js";
22
- import { Store } from "./Store.js";
23
- import { applyCustomMatchers, createClientMockHelper, createDefer, expectSingleListCallAndClear, expectSingleObjectCallAndClear, listPayloadContaining, mockListSubCallback, mockSingleSubCallback, objectPayloadContaining, waitForCall } from "./testUtils.js";
27
+ import { runOptimisticJob } from "./OptimisticJob.js";
28
+ import { invalidateList, Store } from "./Store.js";
29
+ import { applyCustomMatchers, createClientMockHelper, createDefer, createTestLogger, expectNoMoreCalls, expectSingleListCallAndClear, expectSingleObjectCallAndClear, getObject, mockListSubCallback, mockSingleSubCallback, objectPayloadContaining, updateList, updateObject, waitForCall } from "./testUtils.js";
24
30
  const defer = createDefer();
31
+ const logger = createTestLogger({});
25
32
  beforeAll(() => {
26
33
  vi.setConfig({
27
34
  fakeTimers: {
@@ -38,6 +45,19 @@ const ANY_INIT_ENTRY = {
38
45
  lastUpdated: 0,
39
46
  status: "init"
40
47
  };
48
+
49
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
50
+ function fullTaskName(task) {
51
+ return task ? `${fullTaskName(task.suite)} > ${task.name}` : "";
52
+ }
53
+ beforeEach(x => {
54
+ console.log(chalk.bgRed(chalk.white(fullTaskName(x.task))));
55
+ });
56
+
57
+ // helper method to make debugging tests easier
58
+ function testStage(s) {
59
+ console.log(chalk.bgYellow(`Test Stage: ${s}`));
60
+ }
41
61
  applyCustomMatchers();
42
62
  describe(Store, () => {
43
63
  describe("with mock server", () => {
@@ -46,44 +66,49 @@ describe(Store, () => {
46
66
  let employeesAsServerReturns;
47
67
  let mutatedEmployees;
48
68
  beforeAll(async () => {
49
- apiServer.listen();
50
- client = createClient("https://stack.palantir.com", $ontologyRid, async () => "myAccessToken");
69
+ const testSetup = startNodeApiServer(new LegacyFauxFoundry(), createClient, {
70
+ logger
71
+ });
72
+ ({
73
+ client
74
+ } = testSetup);
51
75
  employeesAsServerReturns = (await client(Employee).fetchPage()).data;
52
76
  mutatedEmployees = [employeesAsServerReturns[0], employeesAsServerReturns[1].$clone({
53
77
  fullName: "foo"
54
78
  }), ...employeesAsServerReturns.slice(2)];
55
- });
56
- afterAll(() => {
57
- apiServer.close();
79
+ return () => {
80
+ testSetup.apiServer.close();
81
+ };
58
82
  });
59
83
  beforeEach(() => {
60
84
  cache = new Store(client);
61
- });
62
- afterEach(() => {
63
- cache = undefined;
85
+ return () => {
86
+ cache = undefined;
87
+ };
64
88
  });
65
89
  it("basic single object works", async () => {
66
90
  const emp = employeesAsServerReturns[0];
91
+ const cacheKey = cache.getCacheKey("object", "Employee", emp.$primaryKey);
67
92
 
68
93
  // starts empty
69
- expect(cache.getObject(Employee, emp.$primaryKey)).toBeUndefined();
70
- const result = cache.updateObject(Employee, emp);
94
+ expect(cache.getValue(cacheKey)?.value).toBeUndefined();
95
+ const result = updateObject(cache, emp);
71
96
  expect(emp).toBe(result);
72
97
 
73
98
  // getting the object now matches the result
74
- expect(cache.getObject(Employee, emp.$primaryKey)).toEqual(result);
75
- const updatedEmpFromCache = cache.updateObject(Employee, emp.$clone({
99
+ expect(cache.getValue(cacheKey)?.value).toEqual(result);
100
+ const updatedEmpFromCache = updateObject(cache, emp.$clone({
76
101
  fullName: "new name"
77
102
  }));
78
103
  expect(updatedEmpFromCache).not.toBe(emp);
79
104
 
80
105
  // getting it again is the updated object
81
- expect(cache.getObject(Employee, emp.$primaryKey)).toEqual(updatedEmpFromCache);
106
+ expect(cache.getValue(cacheKey)?.value).toEqual(updatedEmpFromCache);
82
107
  });
83
108
  describe("optimistic updates", () => {
84
109
  it("rolls back objects", async () => {
85
110
  const emp = employeesAsServerReturns[0];
86
- cache.updateObject(Employee, emp); // pre-seed the cache with the "real" value
111
+ updateObject(cache, emp); // pre-seed the cache with the "real" value
87
112
 
88
113
  const subFn = mockSingleSubCallback();
89
114
  defer(cache.observeObject(Employee, emp.$primaryKey, {
@@ -92,7 +117,7 @@ describe(Store, () => {
92
117
  expectSingleObjectCallAndClear(subFn, emp, "loaded");
93
118
  const optimisticId = createOptimisticId();
94
119
  // update with an optimistic write
95
- cache.updateObject(Employee, emp.$clone({
120
+ updateObject(cache, emp.$clone({
96
121
  fullName: "new name"
97
122
  }), {
98
123
  optimisticId
@@ -106,10 +131,12 @@ describe(Store, () => {
106
131
  expectSingleObjectCallAndClear(subFn, emp, "loaded");
107
132
  });
108
133
  it("rolls back to an updated real value", async () => {
109
- vi.useFakeTimers();
110
-
111
134
  // pre-seed the cache with the "real" value
112
- cache.updateList(Employee, {}, employeesAsServerReturns);
135
+ updateList(cache, {
136
+ type: Employee,
137
+ where: {},
138
+ orderBy: {}
139
+ }, employeesAsServerReturns);
113
140
  const emp = employeesAsServerReturns[0];
114
141
  const empSubFn = mockSingleSubCallback();
115
142
  defer(cache.observeObject(Employee, emp.$primaryKey, {
@@ -117,88 +144,90 @@ describe(Store, () => {
117
144
  }, empSubFn));
118
145
  expectSingleObjectCallAndClear(empSubFn, emp, "loaded");
119
146
  const listSubFn = mockListSubCallback();
120
- defer(cache.observeList(Employee, {}, {
147
+ defer(cache.observeList({
148
+ type: Employee,
121
149
  mode: "offline"
122
150
  }, listSubFn));
151
+ await waitForCall(listSubFn, 1);
123
152
  expectSingleListCallAndClear(listSubFn, employeesAsServerReturns);
124
153
  const optimisticEmployee = emp.$clone({
125
154
  fullName: "new name"
126
155
  });
127
156
  const optimisticId = createOptimisticId();
157
+ testStage("optimistic update");
158
+ expect(listSubFn.next).not.toHaveBeenCalled();
128
159
 
129
160
  // update with an optimistic write
130
- cache.updateObject(Employee, optimisticEmployee, {
161
+ updateObject(cache, optimisticEmployee, {
131
162
  optimisticId
132
163
  });
164
+ testStage("after optimistic update");
133
165
 
134
166
  // expect optimistic write
135
167
  expectSingleObjectCallAndClear(empSubFn, optimisticEmployee);
136
168
 
137
169
  // expect optimistic write to the list
138
- expectSingleListCallAndClear(listSubFn, [optimisticEmployee, ...employeesAsServerReturns.slice(1)]);
170
+ await waitForCall(listSubFn, 1);
171
+ expectSingleListCallAndClear(listSubFn, [optimisticEmployee, ...employeesAsServerReturns.slice(1)], {
172
+ isOptimistic: true,
173
+ status: "loading"
174
+ });
139
175
 
140
176
  // write the real update, via the earlier list definition
141
177
  const truthUpdatedEmployee = emp.$clone({
142
178
  fullName: "real update"
143
179
  });
144
- cache.updateList(Employee, {}, [truthUpdatedEmployee]);
145
-
146
- // we shouldn't expect an update because the top layer has a value
147
- expect(empSubFn).not.toHaveBeenCalled();
148
-
149
- // we do get an update to the list but we still see the optimistic value
150
- // for the object
151
- expectSingleListCallAndClear(listSubFn, [optimisticEmployee]);
180
+ testStage("write real update");
181
+ updateList(cache, {
182
+ type: Employee,
183
+ where: {},
184
+ orderBy: {}
185
+ }, [truthUpdatedEmployee]);
152
186
 
153
187
  // remove the optimistic write
154
188
  cache.removeLayer(optimisticId);
155
189
 
156
190
  // see the object observation get updated
157
- expectSingleObjectCallAndClear(empSubFn, truthUpdatedEmployee);
191
+ expectSingleObjectCallAndClear(empSubFn, truthUpdatedEmployee, "loaded");
158
192
 
159
193
  // see the list get updated
160
- expectSingleListCallAndClear(listSubFn, [truthUpdatedEmployee]);
161
- vi.useRealTimers();
194
+ await waitForCall(listSubFn, 1);
195
+ expectSingleListCallAndClear(listSubFn, [truthUpdatedEmployee], {
196
+ status: "loaded",
197
+ isOptimistic: false
198
+ });
162
199
  });
163
200
  it("rolls back to an updated real value via list", async () => {
164
201
  const emp = employeesAsServerReturns[0];
165
- cache.updateObject(Employee, emp); // pre-seed the cache with the "real" value
202
+ updateObject(cache, emp); // pre-seed the cache with the "real" value
166
203
 
167
204
  const subFn = mockSingleSubCallback();
168
205
  defer(cache.observeObject(Employee, emp.$primaryKey, {
169
206
  mode: "offline"
170
207
  }, subFn));
171
- expect(subFn).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
172
- object: emp,
173
- status: "loaded"
174
- }));
175
- subFn.mockClear();
208
+ expectSingleObjectCallAndClear(subFn, emp, "loaded");
176
209
  const optimisticEmployee = emp.$clone({
177
210
  fullName: "new name"
178
211
  });
179
212
 
180
213
  // update with an optimistic write
181
214
  const optimisticId = createOptimisticId();
182
- cache.updateObject(Employee, optimisticEmployee, {
215
+ updateObject(cache, optimisticEmployee, {
183
216
  optimisticId
184
217
  });
185
- expect(subFn).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
186
- object: optimisticEmployee
187
- }));
188
- subFn.mockClear();
218
+ expectSingleObjectCallAndClear(subFn, optimisticEmployee);
189
219
  const truthUpdatedEmployee = emp.$clone({
190
220
  fullName: "real update"
191
221
  });
192
- cache.updateObject(Employee, truthUpdatedEmployee);
222
+ updateObject(cache, truthUpdatedEmployee);
193
223
 
194
224
  // we shouldn't expect an update because the top layer has a value
195
- expect(subFn).not.toHaveBeenCalled();
225
+ expect(subFn.next).not.toHaveBeenCalled();
196
226
 
197
227
  // remove the optimistic write
198
228
  cache.removeLayer(optimisticId);
199
- expect(subFn).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
200
- object: truthUpdatedEmployee
201
- }));
229
+ expectSingleObjectCallAndClear(subFn, truthUpdatedEmployee);
230
+ expectNoMoreCalls(subFn);
202
231
  });
203
232
  });
204
233
  describe(".invalidateObject", () => {
@@ -207,29 +236,20 @@ describe(Store, () => {
207
236
  const staleEmp = emp.$clone({
208
237
  fullName: "stale"
209
238
  });
210
- cache.updateObject(Employee, staleEmp);
239
+ updateObject(cache, staleEmp);
211
240
  const subFn = mockSingleSubCallback();
212
241
  defer(cache.observeObject(Employee, emp.$primaryKey, {
213
242
  mode: "offline"
214
243
  }, subFn));
215
- expect(subFn).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
216
- object: staleEmp,
217
- status: "loaded"
218
- }));
219
- subFn.mockClear();
244
+ expectSingleObjectCallAndClear(subFn, staleEmp, "loaded");
220
245
 
221
246
  // invalidate
222
247
  void cache.invalidateObject(Employee, staleEmp.$primaryKey);
223
- await vi.waitFor(() => expect(subFn).toHaveBeenCalled());
224
- expect(subFn).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
225
- object: staleEmp,
226
- status: "loading"
227
- }));
228
- subFn.mockClear();
229
- await vi.waitFor(() => expect(subFn).toHaveBeenCalled());
230
- expect(subFn).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
231
- object: emp
232
- }));
248
+ await waitForCall(subFn);
249
+ expectSingleObjectCallAndClear(subFn, staleEmp, "loading");
250
+ await waitForCall(subFn);
251
+ expectSingleObjectCallAndClear(subFn, emp, "loaded");
252
+ expectNoMoreCalls(subFn);
233
253
  });
234
254
  });
235
255
  describe(".invalidateList", () => {
@@ -244,39 +264,43 @@ describe(Store, () => {
244
264
  const staleEmp = emp.$clone({
245
265
  fullName: "stale"
246
266
  });
247
- cache.updateList(Employee, {}, [staleEmp]);
267
+ updateList(cache, {
268
+ type: Employee,
269
+ where: {},
270
+ orderBy: {}
271
+ }, [staleEmp]);
248
272
  const subFn = mockSingleSubCallback();
249
273
  defer(cache.observeObject(Employee, emp.$primaryKey, {
250
274
  mode: "offline"
251
275
  }, subFn));
252
276
  expectSingleObjectCallAndClear(subFn, staleEmp);
253
277
  const subListFn = mockListSubCallback();
254
- defer(cache.observeList(Employee, {}, {
278
+ defer(cache.observeList({
279
+ type: Employee,
255
280
  mode: "offline"
256
281
  }, subListFn));
257
- await vi.waitFor(() => expect(subListFn).toHaveBeenCalled());
258
- expect(subListFn).toHaveBeenCalledExactlyOnceWith(listPayloadContaining({
259
- resolvedList: [staleEmp],
282
+ await waitForCall(subListFn, 1);
283
+ expectSingleListCallAndClear(subListFn, [staleEmp], {
260
284
  status: "loaded"
261
- }));
262
- subListFn.mockClear();
263
- cache.invalidateList(Employee, {});
264
- await vi.waitFor(() => expect(subListFn).toHaveBeenCalled());
265
- expect(subListFn).toHaveBeenCalledExactlyOnceWith(listPayloadContaining({
266
- resolvedList: [staleEmp],
285
+ });
286
+ testStage("invalidate");
287
+ const invalidateListPromise = invalidateList(cache, {
288
+ type: Employee
289
+ });
290
+ testStage("check invalidate");
291
+ await waitForCall(subListFn, 1);
292
+ expectSingleListCallAndClear(subListFn, [staleEmp], {
267
293
  status: "loading"
268
- }));
269
- subListFn.mockClear();
270
- await vi.waitFor(() => expect(subListFn).toHaveBeenCalled());
271
- expect(subListFn).toHaveBeenCalledExactlyOnceWith(listPayloadContaining({
272
- resolvedList: employeesAsServerReturns
273
- }));
274
- subListFn.mockClear();
275
- await vi.waitFor(() => expect(subFn).toHaveBeenCalled());
276
- expect(subFn).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
277
- status: "loaded",
278
- object: emp
279
- }));
294
+ });
295
+ await waitForCall(subListFn, 1);
296
+ expectSingleListCallAndClear(subListFn, employeesAsServerReturns, {
297
+ status: "loaded"
298
+ });
299
+ await waitForCall(subFn, 1);
300
+ expectSingleObjectCallAndClear(subFn, emp, "loaded");
301
+
302
+ // don't leave promises dangling
303
+ await invalidateListPromise;
280
304
  });
281
305
  });
282
306
  describe(".invalidateObjectType", () => {
@@ -291,47 +315,53 @@ describe(Store, () => {
291
315
  const staleEmp = emp.$clone({
292
316
  fullName: "stale"
293
317
  });
294
- cache.updateList(Employee, {}, [staleEmp]);
318
+ updateList(cache, {
319
+ type: Employee,
320
+ where: {},
321
+ orderBy: {}
322
+ }, [staleEmp]);
295
323
  const subFn = mockSingleSubCallback();
296
324
  defer(cache.observeObject(Employee, emp.$primaryKey, {
297
325
  mode: "offline"
298
326
  }, subFn));
299
327
  expectSingleObjectCallAndClear(subFn, staleEmp);
300
328
  const subListFn = mockListSubCallback();
301
- defer(cache.observeList(Employee, {}, {
329
+ defer(cache.observeList({
330
+ type: Employee,
331
+ where: {},
332
+ orderBy: {},
302
333
  mode: "offline"
303
334
  }, subListFn));
304
- await vi.waitFor(() => expect(subListFn).toHaveBeenCalled());
305
- expect(subListFn).toHaveBeenCalledExactlyOnceWith(listPayloadContaining({
306
- resolvedList: [staleEmp],
335
+ await waitForCall(subListFn, 1);
336
+ expectSingleListCallAndClear(subListFn, [staleEmp], {
307
337
  status: "loaded"
308
- }));
309
- subListFn.mockClear();
310
- cache.invalidateObjectType(Employee);
311
- await vi.waitFor(() => expect(subListFn).toHaveBeenCalled());
312
- expect(subListFn).toHaveBeenCalledExactlyOnceWith(listPayloadContaining({
313
- resolvedList: [staleEmp],
338
+ });
339
+ testStage("invalidate");
340
+ const pInvalidateComplete = cache.invalidateObjectType(Employee, undefined);
341
+ await waitForCall(subListFn, 1);
342
+ expectSingleListCallAndClear(subListFn, [staleEmp], {
314
343
  status: "loading"
315
- }));
316
- subListFn.mockClear();
317
- await vi.waitFor(() => expect(subListFn).toHaveBeenCalled());
318
- expect(subListFn).toHaveBeenCalledExactlyOnceWith(listPayloadContaining({
319
- resolvedList: employeesAsServerReturns
320
- }));
321
- subListFn.mockClear();
322
- await vi.waitFor(() => expect(subFn).toHaveBeenCalled());
323
- expect(subFn).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
324
- status: "loaded",
325
- object: emp
326
- }));
344
+ });
345
+ await waitForCall(subListFn, 1);
346
+ expectSingleListCallAndClear(subListFn, employeesAsServerReturns);
347
+ await waitForCall(subFn, 1);
348
+ expectSingleObjectCallAndClear(subFn, emp, "loaded");
349
+
350
+ // we don't need this value to control the test but we want to make sure we don't have
351
+ // any unhandled exceptions upon test completion
352
+ await pInvalidateComplete;
327
353
  });
328
354
  });
329
355
  describe(".observeObject (force)", () => {
330
356
  const subFn1 = mockSingleSubCallback();
331
357
  const subFn2 = mockSingleSubCallback();
332
358
  beforeEach(async () => {
333
- subFn1.mockClear();
334
- subFn2.mockClear();
359
+ subFn1.complete.mockClear();
360
+ subFn1.next.mockClear();
361
+ subFn1.error.mockClear();
362
+ subFn2.complete.mockClear();
363
+ subFn2.next.mockClear();
364
+ subFn2.error.mockClear();
335
365
  });
336
366
  const likeEmployee50030 = expect.objectContaining({
337
367
  $primaryKey: 50030,
@@ -341,42 +371,36 @@ describe(Store, () => {
341
371
  defer(cache.observeObject(Employee, 50030, {
342
372
  mode: "force"
343
373
  }, subFn1));
344
- expect(subFn1).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
374
+ expect(subFn1.next).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
345
375
  status: "loading",
346
376
  object: undefined,
347
377
  isOptimistic: false
348
378
  }));
349
- subFn1.mockClear();
350
- await vi.waitFor(() => expect(subFn1).toHaveBeenCalled());
351
- expect(subFn1).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
379
+ subFn1.next.mockClear();
380
+ await waitForCall(subFn1);
381
+ expect(subFn1.next).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
352
382
  object: likeEmployee50030,
353
383
  isOptimistic: false
354
384
  }));
355
- const firstLoad = subFn1.mock.lastCall?.[0];
356
- subFn1.mockClear();
385
+ const firstLoad = subFn1.next.mock.lastCall?.[0];
386
+ subFn1.next.mockClear();
357
387
  defer(cache.observeObject(Employee, 50030, {
358
388
  mode: "force"
359
389
  }, subFn2));
360
- expect(subFn1).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
361
- status: "loading"
362
- }));
363
- subFn1.mockClear();
390
+ expectSingleObjectCallAndClear(subFn1, likeEmployee50030, "loading");
364
391
 
365
392
  // should be the earlier results
366
- expect(subFn2).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
367
- status: "loading"
368
- }));
369
- subFn2.mockClear();
393
+ expectSingleObjectCallAndClear(subFn2, likeEmployee50030, "loading");
370
394
 
371
395
  // both will be updated
372
396
  for (const s of [subFn1, subFn2]) {
373
397
  // wait for the result to come in
374
- await vi.waitFor(() => expect(s).toHaveBeenCalled());
375
- expect(s).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
398
+ await waitForCall(s, 1);
399
+ expect(s.next).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
376
400
  ...firstLoad,
377
401
  lastUpdated: expect.toBeGreaterThan(firstLoad.lastUpdated)
378
402
  }));
379
- s.mockClear();
403
+ s.next.mockClear();
380
404
  }
381
405
  });
382
406
  });
@@ -384,152 +408,185 @@ describe(Store, () => {
384
408
  const subFn = mockSingleSubCallback();
385
409
  let sub;
386
410
  beforeEach(() => {
387
- subFn.mockClear();
411
+ subFn.complete.mockClear();
412
+ subFn.next.mockClear();
413
+ subFn.error.mockClear();
388
414
  sub = defer(cache.observeObject(Employee, 50030, {
389
415
  mode: "offline"
390
416
  }, subFn));
391
- expect(subFn).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
392
- status: "init",
393
- object: undefined
394
- }));
395
- subFn.mockClear();
417
+ expectSingleObjectCallAndClear(subFn, undefined, "init");
396
418
  });
397
419
  it("does basic observation and unsubscribe", async () => {
398
420
  const emp = employeesAsServerReturns[0];
399
421
 
400
422
  // force an update
401
- cache.updateObject(Employee, emp);
402
- expect(subFn).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
403
- object: emp
404
- }));
405
- subFn.mockClear();
423
+ updateObject(cache, emp);
424
+ expectSingleObjectCallAndClear(subFn, emp);
406
425
 
407
426
  // force again
408
- cache.updateObject(Employee, emp.$clone({
427
+ updateObject(cache, emp.$clone({
409
428
  fullName: "new name"
410
429
  }));
411
- expect(subFn).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
412
- object: expect.objectContaining({
413
- fullName: "new name"
414
- })
430
+ expectSingleObjectCallAndClear(subFn, emp.$clone({
431
+ fullName: "new name"
415
432
  }));
416
- subFn.mockClear();
417
433
  sub.unsubscribe();
418
434
 
419
435
  // force again but no subscription update
420
- cache.updateObject(Employee, emp.$clone({
436
+ updateObject(cache, emp.$clone({
421
437
  fullName: "new name 2"
422
438
  }));
423
- expect(subFn).not.toHaveBeenCalled();
439
+ expect(subFn.next).not.toHaveBeenCalled();
424
440
  });
425
441
  it("observes with list update", async () => {
426
442
  const emp = employeesAsServerReturns[0];
427
443
 
428
444
  // force an update
429
- cache.updateObject(Employee, emp.$clone({
445
+ updateObject(cache, emp.$clone({
430
446
  fullName: "not the name"
431
447
  }));
432
- expect(subFn).toHaveBeenCalledTimes(1);
433
- cache.updateList(Employee, {}, employeesAsServerReturns);
434
- expect(subFn).toHaveBeenCalledTimes(2);
435
- expect(subFn.mock.calls[1][0]).toEqual(objectPayloadContaining({
448
+ expect(subFn.next).toHaveBeenCalledTimes(1);
449
+ updateList(cache, {
450
+ type: Employee,
451
+ where: {},
452
+ orderBy: {}
453
+ }, employeesAsServerReturns);
454
+ expect(subFn.next).toHaveBeenCalledTimes(2);
455
+ expect(subFn.next.mock.calls[1][0]).toEqual(objectPayloadContaining({
436
456
  object: emp
437
457
  }));
438
458
  });
439
459
  });
440
460
  describe(".observeList", () => {
441
461
  const listSub1 = mockListSubCallback();
462
+ const ifaceSub = mockListSubCallback();
442
463
  beforeEach(() => {
443
464
  vi.useFakeTimers({});
444
- listSub1.mockReset();
465
+ vi.mocked(listSub1.next).mockReset();
466
+ vi.mocked(listSub1.error).mockReset();
467
+ vi.mocked(listSub1.complete).mockReset();
468
+ vi.mocked(ifaceSub.next).mockReset();
469
+ vi.mocked(ifaceSub.error).mockReset();
470
+ vi.mocked(ifaceSub.complete).mockReset();
445
471
  });
446
472
  afterEach(() => {
447
473
  vi.useRealTimers();
448
474
  });
449
475
  describe("mode=force", () => {
450
476
  it("initial load", async () => {
451
- defer(cache.observeList(Employee, {}, {
477
+ defer(cache.observeList({
478
+ type: Employee,
479
+ orderBy: {},
452
480
  mode: "force"
453
481
  }, listSub1));
482
+ defer(cache.observeList({
483
+ type: FooInterface,
484
+ orderBy: {},
485
+ mode: "force"
486
+ }, ifaceSub));
454
487
  vitest.runOnlyPendingTimers();
455
- await vi.waitFor(() => expect(listSub1).toHaveBeenCalled());
456
- expect(listSub1).toHaveBeenCalledExactlyOnceWith(listPayloadContaining({
457
- status: "loading",
458
- resolvedList: []
459
- }));
460
- listSub1.mockClear();
461
- await vi.waitFor(() => expect(listSub1).toHaveBeenCalled());
462
- expect(listSub1).toHaveBeenCalledExactlyOnceWith(listPayloadContaining({
463
- resolvedList: employeesAsServerReturns,
488
+ await waitForCall(listSub1);
489
+ await waitForCall(ifaceSub);
490
+ expectSingleListCallAndClear(listSub1, [], {
491
+ status: "loading"
492
+ });
493
+ expectSingleListCallAndClear(ifaceSub, [], {
494
+ status: "loading"
495
+ });
496
+ await waitForCall(listSub1);
497
+ expectSingleListCallAndClear(listSub1, employeesAsServerReturns, {
464
498
  status: "loaded"
465
- }));
499
+ });
500
+ await waitForCall(ifaceSub);
501
+ expectSingleListCallAndClear(ifaceSub, employeesAsServerReturns, {
502
+ status: "loaded"
503
+ });
504
+ expectNoMoreCalls(listSub1);
505
+ expectNoMoreCalls(ifaceSub);
506
+ expect(listSub1.next).not.toHaveBeenCalled();
507
+ expect(listSub1.error).not.toHaveBeenCalled();
508
+ expect(ifaceSub.next).not.toHaveBeenCalled();
509
+ expect(ifaceSub.error).not.toHaveBeenCalled();
466
510
  });
467
511
  it("subsequent load", async () => {
468
512
  // Pre-seed with data the server doesn't return
469
- cache.updateList(Employee, {}, mutatedEmployees);
470
- defer(cache.observeList(Employee, {}, {
513
+ updateList(cache, {
514
+ type: Employee,
515
+ where: {},
516
+ orderBy: {}
517
+ }, mutatedEmployees);
518
+ defer(cache.observeList({
519
+ type: Employee,
471
520
  mode: "force"
472
521
  }, listSub1));
473
- await vi.waitFor(() => expect(listSub1).toHaveBeenCalled());
474
- expect(listSub1).toHaveBeenCalledExactlyOnceWith(listPayloadContaining({
475
- resolvedList: mutatedEmployees,
522
+ await waitForCall(listSub1, 1);
523
+ const firstLoad = listSub1.next.mock.calls[0][0];
524
+ expectSingleListCallAndClear(listSub1, mutatedEmployees, {
476
525
  status: "loading"
477
- }));
478
- const firstLoad = listSub1.mock.calls[0][0];
479
- listSub1.mockClear();
480
- await vi.waitFor(() => expect(listSub1).toHaveBeenCalled());
481
- expect(listSub1).toHaveBeenCalledExactlyOnceWith(listPayloadContaining({
482
- resolvedList: employeesAsServerReturns,
526
+ });
527
+ await waitForCall(listSub1, 1);
528
+ expectSingleListCallAndClear(listSub1, employeesAsServerReturns, {
483
529
  status: "loaded",
484
530
  lastUpdated: expect.toBeGreaterThan(firstLoad.lastUpdated)
485
- }));
486
- listSub1.mockClear();
531
+ });
487
532
  });
488
533
  });
489
534
  describe("mode = offline", () => {
490
535
  it("updates with list updates", async () => {
491
- defer(cache.observeList(Employee, {}, {
536
+ defer(cache.observeList({
537
+ type: Employee,
538
+ where: {},
539
+ orderBy: {},
492
540
  mode: "offline"
493
541
  }, listSub1));
494
- expect(listSub1).toHaveBeenCalledTimes(0);
495
- cache.updateList(Employee, {}, employeesAsServerReturns);
542
+ expect(listSub1.next).toHaveBeenCalledTimes(0);
543
+ updateList(cache, {
544
+ type: Employee,
545
+ where: {},
546
+ orderBy: {}
547
+ }, employeesAsServerReturns);
496
548
  vitest.runOnlyPendingTimers();
497
- expect(listSub1).toHaveBeenCalledExactlyOnceWith(listPayloadContaining({
498
- resolvedList: employeesAsServerReturns
499
- }));
500
- listSub1.mockClear();
549
+ expectSingleListCallAndClear(listSub1, employeesAsServerReturns);
501
550
 
502
551
  // list is just now one object
503
- cache.updateList(Employee, {}, [employeesAsServerReturns[0]]);
552
+ updateList(cache, {
553
+ type: Employee,
554
+ where: {},
555
+ orderBy: {}
556
+ }, [employeesAsServerReturns[0]]);
504
557
  vitest.runOnlyPendingTimers();
505
- expect(listSub1).toHaveBeenCalledExactlyOnceWith(listPayloadContaining({
506
- resolvedList: [employeesAsServerReturns[0]]
507
- }));
558
+ expectSingleListCallAndClear(listSub1, [employeesAsServerReturns[0]]);
508
559
  });
509
560
  it("updates with different list updates", async () => {
510
- defer(cache.observeList(Employee, {}, {
561
+ defer(cache.observeList({
562
+ type: Employee,
563
+ where: {},
564
+ orderBy: {},
511
565
  mode: "offline"
512
566
  }, listSub1));
513
- expect(listSub1).toHaveBeenCalledTimes(0);
514
- cache.updateList(Employee, {}, employeesAsServerReturns);
567
+ expect(listSub1.next).toHaveBeenCalledTimes(0);
568
+ updateList(cache, {
569
+ type: Employee,
570
+ where: {},
571
+ orderBy: {}
572
+ }, employeesAsServerReturns);
515
573
  vitest.runOnlyPendingTimers();
516
- expect(listSub1).toHaveBeenCalledExactlyOnceWith(listPayloadContaining({
517
- resolvedList: employeesAsServerReturns
518
- }));
519
- listSub1.mockClear();
574
+ expectSingleListCallAndClear(listSub1, employeesAsServerReturns);
520
575
 
521
576
  // new where === different list
522
- cache.updateList(Employee, {
523
- employeeId: {
524
- $gt: 0
525
- }
577
+ updateList(cache, {
578
+ type: Employee,
579
+ where: {
580
+ employeeId: {
581
+ $gt: 0
582
+ }
583
+ },
584
+ orderBy: {}
526
585
  }, mutatedEmployees);
527
586
  vitest.runOnlyPendingTimers();
528
587
 
529
588
  // original list updates still
530
- expect(listSub1).toHaveBeenCalledExactlyOnceWith(listPayloadContaining({
531
- resolvedList: mutatedEmployees
532
- }));
589
+ expectSingleListCallAndClear(listSub1, mutatedEmployees);
533
590
  });
534
591
  });
535
592
  });
@@ -542,57 +599,125 @@ describe(Store, () => {
542
599
  });
543
600
  it("works in the solo case", async () => {
544
601
  const listSub = mockListSubCallback();
545
- defer(cache.observeList(Employee, {}, {
602
+ defer(cache.observeList({
603
+ type: Employee,
604
+ where: {},
605
+ orderBy: {},
546
606
  mode: "force",
547
607
  pageSize: 1
548
608
  }, listSub));
549
- expect(listSub).not.toHaveBeenCalled();
550
- await vi.waitFor(() => expect(listSub).toHaveBeenCalled());
551
- expect(listSub).toHaveBeenCalledExactlyOnceWith(listPayloadContaining({
609
+ expect(listSub.next).not.toHaveBeenCalled();
610
+ await waitForCall(listSub, 1);
611
+ expectSingleListCallAndClear(listSub, [], {
552
612
  status: "loading"
553
- }));
554
- listSub.mockClear();
555
- await vi.waitFor(() => expect(listSub).toHaveBeenCalled());
556
- expect(listSub).toHaveBeenCalledExactlyOnceWith(listPayloadContaining({
557
- resolvedList: employeesAsServerReturns.slice(0, 1),
558
- status: "loaded"
559
- }));
613
+ });
614
+ await waitForCall(listSub, 1);
560
615
  const {
561
616
  fetchMore
562
- } = listSub.mock.calls[0][0];
563
- listSub.mockClear();
617
+ } = listSub.next.mock.calls[0][0];
618
+ expectSingleListCallAndClear(listSub, employeesAsServerReturns.slice(0, 1), {
619
+ status: "loaded"
620
+ });
564
621
  void fetchMore();
565
- await vi.waitFor(() => expect(listSub).toHaveBeenCalledTimes(1));
566
- expect(listSub).toHaveBeenCalledExactlyOnceWith(listPayloadContaining({
567
- resolvedList: employeesAsServerReturns.slice(0, 1),
622
+ await waitForCall(listSub, 1);
623
+ expectSingleListCallAndClear(listSub, employeesAsServerReturns.slice(0, 1), {
568
624
  status: "loading"
569
- }));
570
- listSub.mockClear();
571
- await vi.waitFor(() => expect(listSub).toHaveBeenCalledTimes(1));
572
- expect(listSub).toHaveBeenCalledWith(listPayloadContaining({
573
- resolvedList: employeesAsServerReturns.slice(0, 2),
625
+ });
626
+ await waitForCall(listSub, 1);
627
+ expectSingleListCallAndClear(listSub, employeesAsServerReturns.slice(0, 2), {
574
628
  status: "loaded"
575
- }));
629
+ });
576
630
  });
577
631
  });
578
632
  });
579
633
  describe("with mock client", () => {
580
634
  let client;
581
635
  let mockClient;
582
- let cache;
636
+ let store;
583
637
  beforeEach(async () => {
584
638
  mockClient = createClientMockHelper();
585
639
  client = mockClient.client;
586
- cache = new Store(client);
640
+ store = new Store(client);
641
+ });
642
+ it("properly fires error handler for a list", async () => {
643
+ const error = new Error("A faux error");
644
+ mockClient.mockFetchPageOnce().reject(error);
645
+ const sub = mockListSubCallback();
646
+ store.observeList({
647
+ type: Employee,
648
+ where: {},
649
+ orderBy: {}
650
+ }, sub);
651
+ await waitForCall(sub.error, 1);
652
+ expect(sub.error).toHaveBeenCalled();
653
+ expect(sub.next).not.toHaveBeenCalled();
654
+ });
655
+ describe("batching", () => {
656
+ it("groups requests for single objects", async () => {
657
+ mockClient.mockFetchPageOnce().resolve({
658
+ data: [{
659
+ $apiName: "Employee",
660
+ $objectType: "Employee",
661
+ $primaryKey: 0
662
+ }, {
663
+ $apiName: "Employee",
664
+ $objectType: "Employee",
665
+ $primaryKey: 1
666
+ }],
667
+ nextPageToken: undefined,
668
+ totalCount: "2"
669
+ });
670
+ vi.mocked(client.fetchMetadata).mockReturnValue(Promise.resolve({
671
+ primaryKeyApiName: "id"
672
+ }));
673
+ const a = mockSingleSubCallback();
674
+ const b = mockSingleSubCallback();
675
+ defer(store.observeObject(Employee, 0, {}, a));
676
+ defer(store.observeObject(Employee, 1, {}, b));
677
+ await a.expectLoadingAndLoaded({
678
+ loading: objectPayloadContaining({
679
+ status: "loading",
680
+ object: undefined
681
+ }),
682
+ loaded: objectPayloadContaining({
683
+ object: expect.objectContaining({
684
+ $primaryKey: 0
685
+ })
686
+ })
687
+ });
688
+ await b.expectLoadingAndLoaded({
689
+ loading: objectPayloadContaining({
690
+ status: "loading",
691
+ object: undefined
692
+ }),
693
+ loaded: objectPayloadContaining({
694
+ object: expect.objectContaining({
695
+ $primaryKey: 1
696
+ })
697
+ })
698
+ });
699
+ console.log(client.mock.calls);
700
+ });
587
701
  });
588
702
  describe("actions", () => {
703
+ beforeEach(() => {
704
+ vi.mocked(client.fetchMetadata).mockReturnValue(Promise.resolve({
705
+ primaryKeyApiName: "id"
706
+ }));
707
+ });
589
708
  it("properly invalidates objects", async () => {
590
709
  // after the below `observeObject`, the cache will need to load from the server
591
- mockClient.mockFetchOneOnce().resolve({
592
- $apiName: "Todo"
710
+ // (also the batch loader uses object set to load not fetchOne)
711
+ mockClient.mockFetchPageOnce().resolve({
712
+ data: [{
713
+ $apiName: "Todo",
714
+ $primaryKey: 0
715
+ }],
716
+ nextPageToken: undefined,
717
+ totalCount: "1"
593
718
  });
594
719
  const todoSubFn = mockSingleSubCallback();
595
- defer(cache.observeObject(Todo, 0, {}, todoSubFn));
720
+ defer(store.observeObject(Todo, 0, {}, todoSubFn));
596
721
  await todoSubFn.expectLoadingAndLoaded({
597
722
  loading: objectPayloadContaining({
598
723
  status: "loading",
@@ -614,15 +739,18 @@ describe(Store, () => {
614
739
  });
615
740
 
616
741
  // after we apply the action, the object is invalidated and gets re-requested
617
-
618
- mockClient.mockFetchOneOnce().resolve({
619
- $apiName: "Todo",
620
- text: "hello there kind sir"
742
+ mockClient.mockFetchPageOnce().resolve({
743
+ data: [{
744
+ $primaryKey: 0,
745
+ $apiName: "Todo",
746
+ text: "hello there kind sir"
747
+ }],
748
+ nextPageToken: undefined,
749
+ totalCount: "1"
621
750
  });
622
- const actionPromise = cache.applyAction(createOffice, {
751
+ await store.applyAction(createOffice, {
623
752
  officeId: "whatever"
624
753
  });
625
- await actionPromise;
626
754
  await todoSubFn.expectLoadingAndLoaded({
627
755
  loading: objectPayloadContaining({
628
756
  status: "loading"
@@ -643,9 +771,13 @@ describe(Store, () => {
643
771
  };
644
772
 
645
773
  // after the below `observeObject`, the cache will need to load from the server
646
- mockClient.mockFetchOneOnce().resolve(fauxObject);
774
+ mockClient.mockFetchPageOnce().resolve({
775
+ data: [fauxObject],
776
+ nextPageToken: undefined,
777
+ totalCount: "1"
778
+ });
647
779
  const todoSubFn = mockSingleSubCallback();
648
- defer(cache.observeObject(Todo, 0, {}, todoSubFn));
780
+ defer(store.observeObject(Todo, 0, {}, todoSubFn));
649
781
  await todoSubFn.expectLoadingAndLoaded({
650
782
  loading: objectPayloadContaining({
651
783
  status: "loading",
@@ -661,26 +793,26 @@ describe(Store, () => {
661
793
 
662
794
  // at this point we have an observation properly set up
663
795
  const applyActionResult = mockClient.mockApplyActionOnce();
664
- const actionPromise = cache.applyAction(createOffice, {
796
+ const actionPromise = store.applyAction(createOffice, {
665
797
  officeId: "whatever"
666
798
  }, {
667
799
  optimisticUpdate: ctx => {
668
800
  ctx.updateObject({
669
801
  ...fauxObject,
670
- someValue: "optimistic"
802
+ text: "optimistic"
671
803
  });
672
804
  }
673
805
  });
674
806
  await waitForCall(todoSubFn, 1);
675
- expect(todoSubFn).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
807
+ expect(todoSubFn.next).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
676
808
  object: {
677
809
  ...fauxObject,
678
- someValue: "optimistic"
810
+ text: "optimistic"
679
811
  },
680
812
  status: "loading",
681
813
  isOptimistic: true
682
814
  }));
683
- todoSubFn.mockClear();
815
+ todoSubFn.next.mockClear();
684
816
 
685
817
  // let the action error out
686
818
  applyActionResult.reject("an error thrown");
@@ -688,17 +820,294 @@ describe(Store, () => {
688
820
 
689
821
  // back to the original object
690
822
  await waitForCall(todoSubFn, 1);
691
- expect(todoSubFn).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
823
+ expect(todoSubFn.next).toHaveBeenCalledExactlyOnceWith(objectPayloadContaining({
692
824
  object: fauxObject,
693
825
  status: "loaded",
694
826
  isOptimistic: false
695
827
  }));
696
828
  });
697
829
  });
830
+ describe("orderBy", async () => {
831
+ const ontologyProvider = {
832
+ getObjectDefinition: async () => {
833
+ return {
834
+ ...wireObjectTypeFullMetadataToSdkObjectMetadata(stubData.todoWithLinkTypes, true),
835
+ [InterfaceDefinitions]: {}
836
+ };
837
+ },
838
+ getActionDefinition() {
839
+ throw new Error("not implemented");
840
+ },
841
+ getInterfaceDefinition() {
842
+ throw new Error("not implemented");
843
+ },
844
+ getQueryDefinition() {
845
+ throw new Error("not implemented");
846
+ }
847
+ };
848
+ const minimalClient = createMinimalClient({
849
+ ontologyRid: "ri.whatever"
850
+ }, "https://localhost:8080", () => Promise.resolve("token"), {
851
+ logger
852
+ }, fetch, createObjectSet, () => () => ontologyProvider);
853
+ async function createObject(type, x) {
854
+ return (await minimalClient.objectFactory2(minimalClient, [{
855
+ ...x,
856
+ $apiName: type.apiName,
857
+ $objectType: type.apiName,
858
+ $objectSpecifier: `${type.apiName}:${x.$primaryKey}`
859
+ }], undefined))[0];
860
+ }
861
+ let nextPk = 0;
862
+ const fauxObjectA = await createObject(Todo, {
863
+ $primaryKey: nextPk,
864
+ $title: "a",
865
+ id: nextPk,
866
+ text: "a"
867
+ });
868
+ nextPk++;
869
+ const fauxObjectB = await createObject(Todo, {
870
+ $primaryKey: nextPk,
871
+ $title: "b",
872
+ id: nextPk,
873
+ text: "b"
874
+ });
875
+ nextPk++;
876
+ const fauxObjectC = await createObject(Todo, {
877
+ $primaryKey: nextPk,
878
+ $title: "c",
879
+ id: nextPk,
880
+ text: "c"
881
+ });
882
+ const noWhereNoOrderBy = {
883
+ type: Todo,
884
+ where: {},
885
+ orderBy: {}
886
+ };
887
+ const noWhereOrderByText = {
888
+ type: Todo,
889
+ where: {},
890
+ orderBy: {
891
+ text: "asc"
892
+ }
893
+ };
894
+ const subListUnordered = mockListSubCallback();
895
+ const subListOrdered = mockListSubCallback();
896
+ beforeEach(() => {
897
+ vi.mocked(client.fetchMetadata).mockReturnValue(Promise.resolve({
898
+ primaryKeyApiName: "id"
899
+ }));
900
+ });
901
+ beforeEach(() => {
902
+ defer(store.observeList({
903
+ ...noWhereNoOrderBy,
904
+ mode: "offline"
905
+ }, subListUnordered));
906
+ expect(subListUnordered.next).toHaveBeenCalledTimes(0);
907
+ defer(store.observeList({
908
+ ...noWhereOrderByText,
909
+ mode: "offline"
910
+ }, subListOrdered));
911
+ expect(subListOrdered.next).toHaveBeenCalledTimes(0);
912
+ });
913
+ it("invalidates the correct lists", async () => {
914
+ // for whatever reason, the first list is loaded as [B, A]
915
+ updateList(store, noWhereNoOrderBy, [fauxObjectB, fauxObjectA]);
916
+ await waitForCall(subListUnordered, 1);
917
+ expectSingleListCallAndClear(subListUnordered, [fauxObjectB, fauxObjectA]);
918
+
919
+ // The other list definitely matches on the where clause and we can insert
920
+ // orderBy properly. So this is [A, B]
921
+ await waitForCall(subListOrdered, 1);
922
+ expectSingleListCallAndClear(subListOrdered, [fauxObjectA, fauxObjectB]);
923
+
924
+ // For whatever reason, object B is no longer in the first set (use your imagination)
925
+ // but we have added a C before A. So the first list is [C, A]
926
+ updateList(store, {
927
+ type: Todo,
928
+ where: {},
929
+ orderBy: {}
930
+ }, [fauxObjectC, fauxObjectA]);
931
+ await waitForCall(subListUnordered, 1);
932
+ expectSingleListCallAndClear(subListUnordered, [fauxObjectC, fauxObjectA]);
933
+
934
+ // Nothing told the system that B was deleted so we can presume it still exists
935
+ // and therefore the second list is now [A, B, C]
936
+ await waitForCall(subListOrdered, 1);
937
+ expectSingleListCallAndClear(subListOrdered, [fauxObjectA, fauxObjectB, fauxObjectC]);
938
+ });
939
+ it("produces proper results with optimistic updates and successful action", async () => {
940
+ const optimisticallyMutatedA = await createObject(Todo, {
941
+ ...fauxObjectA,
942
+ text: "optimistic"
943
+ });
944
+ const pkForOptimistic = nextPk++;
945
+ const optimisticallyCreatedObjectD = await createObject(Todo, {
946
+ "$primaryKey": pkForOptimistic,
947
+ "$title": "d",
948
+ "text": "d",
949
+ id: pkForOptimistic
950
+ });
951
+
952
+ // for whatever reason, the first list is loaded as [B, A]
953
+ updateList(store, noWhereNoOrderBy, [fauxObjectB, fauxObjectA]);
954
+ await waitForCall(subListUnordered, 1);
955
+ expectSingleListCallAndClear(subListUnordered, [fauxObjectB, fauxObjectA]);
956
+
957
+ // The other list definitely matches on the where clause and we can insert
958
+ // orderBy properly. So this is [A, B]
959
+ await waitForCall(subListOrdered, 1);
960
+ expectSingleListCallAndClear(subListOrdered, [fauxObjectA, fauxObjectB]);
961
+ testStage("Start");
962
+
963
+ // the optimistic job will call createObject which triggers the `objectFactory2` of the
964
+ // cache context.
965
+ mockClient.mockObjectFactory2Once().resolve([optimisticallyCreatedObjectD]);
966
+
967
+ // Perform something optimistic.
968
+ const removeOptimisticResult = runOptimisticJob(store, b => {
969
+ b.createObject(Todo, pkForOptimistic, {
970
+ id: pkForOptimistic,
971
+ text: "d"
972
+ });
973
+ b.updateObject(optimisticallyMutatedA);
974
+ });
975
+
976
+ // The first list is now [B, A, optimistic]
977
+ await waitForCall(subListUnordered, 1);
978
+ expectSingleListCallAndClear(subListUnordered, [fauxObjectB, optimisticallyMutatedA,
979
+ // same position, new values
980
+ optimisticallyCreatedObjectD], {
981
+ isOptimistic: true
982
+ });
983
+
984
+ // the second list is now [A, B, optimistic]
985
+ await waitForCall(subListOrdered, 1);
986
+ expectSingleListCallAndClear(subListOrdered, [fauxObjectB, optimisticallyCreatedObjectD, optimisticallyMutatedA], {
987
+ isOptimistic: true
988
+ });
989
+
990
+ // Roll back the optimistic update
991
+ await removeOptimisticResult();
992
+
993
+ // The first list is now [B, A]
994
+ await waitForCall(subListUnordered, 1);
995
+ expectSingleListCallAndClear(subListUnordered, [fauxObjectB, fauxObjectA], {
996
+ isOptimistic: false
997
+ });
998
+
999
+ // the second list is now [A, B]
1000
+ await waitForCall(subListOrdered, 1);
1001
+ expectSingleListCallAndClear(subListOrdered, [fauxObjectA, fauxObjectB], {
1002
+ isOptimistic: false
1003
+ });
1004
+ });
1005
+ // I think these are named backwards
1006
+ it("produces proper results with optimistic updates and rollback", async () => {
1007
+ const pkForOptimistic = nextPk++;
1008
+ const optimisticallyCreatedObjectD = await createObject(Todo, {
1009
+ "$primaryKey": pkForOptimistic,
1010
+ "$title": "d",
1011
+ "text": "d",
1012
+ id: pkForOptimistic
1013
+ });
1014
+ const optimisticallyMutatedA = await createObject(Todo, {
1015
+ ...fauxObjectA,
1016
+ text: "optimistic"
1017
+ });
1018
+ testStage("Initial Setup");
1019
+
1020
+ // later we will "create" this object
1021
+ const createdObjectD = await createObject(Todo, {
1022
+ "$primaryKey": 9000,
1023
+ "$title": "d prime",
1024
+ "text": "d prime",
1025
+ id: 9000
1026
+ });
1027
+
1028
+ // for whatever reason, the first list is loaded as [B, A]
1029
+ updateList(store, noWhereNoOrderBy, [fauxObjectB, fauxObjectA]);
1030
+ await waitForCall(subListUnordered, 1);
1031
+ expectSingleListCallAndClear(subListUnordered, [fauxObjectB, fauxObjectA]);
1032
+
1033
+ // The other list definitely matches on the where clause and we can insert
1034
+ // orderBy properly. So this is [A, B]
1035
+ expectSingleListCallAndClear(subListOrdered, [fauxObjectA, fauxObjectB]);
1036
+ testStage("Optimistic Creation");
1037
+
1038
+ // the optimistic job will call createObject which triggers the `objectFactory2` of the
1039
+ // cache context.
1040
+
1041
+ mockClient.mockObjectFactory2Once().resolve([optimisticallyCreatedObjectD]);
1042
+ const mockedApplyAction = mockClient.mockApplyActionOnce();
1043
+ testStage("Apply Action");
1044
+ const actionPromise = store.applyAction(createOffice, {
1045
+ officeId: "5"
1046
+ }, {
1047
+ optimisticUpdate: b => {
1048
+ b.createObject(Todo, optimisticallyCreatedObjectD.$primaryKey, {
1049
+ id: optimisticallyCreatedObjectD.$primaryKey,
1050
+ text: "d"
1051
+ });
1052
+ b.updateObject(optimisticallyMutatedA);
1053
+ }
1054
+ });
1055
+ testStage("Optimistic Updates");
1056
+
1057
+ // The first list is now [B, A, optimistic]
1058
+ await waitForCall(subListUnordered, 1);
1059
+ expectSingleListCallAndClear(subListUnordered, [fauxObjectB, optimisticallyMutatedA,
1060
+ // same position, new values
1061
+ optimisticallyCreatedObjectD], {
1062
+ isOptimistic: true
1063
+ });
1064
+
1065
+ // the second list is now [B, optimistic, optimistic a]
1066
+ await waitForCall(subListOrdered, 1);
1067
+ expectSingleListCallAndClear(subListOrdered, [fauxObjectB, optimisticallyCreatedObjectD, optimisticallyMutatedA], {
1068
+ isOptimistic: true
1069
+ });
1070
+ testStage("Resolve Action");
1071
+ const modifiedObjectA = await createObject(Todo, {
1072
+ ...fauxObjectA,
1073
+ text: "a prime"
1074
+ });
1075
+
1076
+ // The action will complete and then revalidate in order...
1077
+ mockClient.mockFetchPageOnce().resolve({
1078
+ data: [modifiedObjectA, createdObjectD],
1079
+ nextPageToken: undefined,
1080
+ totalCount: "1"
1081
+ });
1082
+ mockedApplyAction.resolve({
1083
+ addedObjects: [{
1084
+ objectType: "Todo",
1085
+ primaryKey: createdObjectD.id
1086
+ }],
1087
+ modifiedObjects: [{
1088
+ objectType: "Todo",
1089
+ primaryKey: fauxObjectA.$primaryKey
1090
+ }]
1091
+ });
1092
+ await actionPromise;
1093
+ await waitForCall(subListUnordered, 1);
1094
+ console.log("=====", subListUnordered.next.mock.calls[0][0]);
1095
+ expectSingleListCallAndClear(subListUnordered, [fauxObjectB,
1096
+ // fauxObjectC,
1097
+ modifiedObjectA, createdObjectD], {
1098
+ isOptimistic: false
1099
+ });
1100
+ await waitForCall(subListOrdered, 1);
1101
+ expectSingleListCallAndClear(subListOrdered, [modifiedObjectA, fauxObjectB, createdObjectD], {
1102
+ isOptimistic: false
1103
+ });
1104
+ });
1105
+ });
698
1106
  });
699
1107
  describe("layers", () => {
700
1108
  it("properly remove", () => {
701
- const store = new Store({});
1109
+ const clientHelper = createClientMockHelper();
1110
+ const store = new Store(clientHelper.client);
702
1111
  const baseObjects = [1, 2].map(i => ({
703
1112
  $primaryKey: i,
704
1113
  $objectType: "Employee",
@@ -709,12 +1118,12 @@ describe(Store, () => {
709
1118
 
710
1119
  // set the truth
711
1120
  for (const obj of baseObjects) {
712
- store.updateObject("Employee", obj);
1121
+ updateObject(store, obj);
713
1122
  }
714
1123
 
715
1124
  // expect the truth
716
1125
  for (const obj of baseObjects) {
717
- expect(store.getObject("Employee", obj.$primaryKey)).toEqual(expect.objectContaining({
1126
+ expect(getObject(store, "Employee", obj.$primaryKey)).toEqual(expect.objectContaining({
718
1127
  $title: `truth ${obj.$primaryKey}`
719
1128
  }));
720
1129
  }
@@ -734,7 +1143,7 @@ describe(Store, () => {
734
1143
 
735
1144
  // expect the optimistic values
736
1145
  for (let i = 0; i < 2; i++) {
737
- expect(store.getObject("Employee", baseObjects[i].$primaryKey)).toEqual(expect.objectContaining({
1146
+ expect(getObject(store, "Employee", baseObjects[i].$primaryKey)).toEqual(expect.objectContaining({
738
1147
  $title: `optimistic ${baseObjects[i].$primaryKey}`
739
1148
  }));
740
1149
  }
@@ -743,10 +1152,10 @@ describe(Store, () => {
743
1152
  store.removeLayer(layerIds[0]);
744
1153
 
745
1154
  // should have truth object 1 and optimistic object 2
746
- expect(store.getObject("Employee", 1)).toEqual(expect.objectContaining({
1155
+ expect(getObject(store, "Employee", 1)).toEqual(expect.objectContaining({
747
1156
  $title: "truth 1"
748
1157
  }));
749
- expect(store.getObject("Employee", 2)).toEqual(expect.objectContaining({
1158
+ expect(getObject(store, "Employee", 2)).toEqual(expect.objectContaining({
750
1159
  $title: "optimistic 2"
751
1160
  }));
752
1161
 
@@ -755,7 +1164,7 @@ describe(Store, () => {
755
1164
 
756
1165
  // should have truth objects
757
1166
  for (const obj of baseObjects) {
758
- expect(store.getObject("Employee", obj.$primaryKey)).toEqual(expect.objectContaining({
1167
+ expect(getObject(store, "Employee", obj.$primaryKey)).toEqual(expect.objectContaining({
759
1168
  $title: `truth ${obj.$primaryKey}`
760
1169
  }));
761
1170
  }