remult 0.21.1 → 0.22.0

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 (451) hide show
  1. package/README.md +47 -46
  2. package/SseSubscriptionServer.js +9 -9
  3. package/ably.js +1 -1
  4. package/esm/SseSubscriptionServer.js +11 -11
  5. package/esm/ably.js +2 -2
  6. package/esm/angular/interfaces/index.d.ts +1 -0
  7. package/esm/angular/interfaces/index.js +1 -0
  8. package/esm/angular/interfaces/src/column-collection.d.ts +70 -0
  9. package/esm/angular/interfaces/src/column-collection.js +341 -0
  10. package/esm/angular/interfaces/src/data-area-settings.d.ts +15 -0
  11. package/esm/angular/interfaces/src/data-area-settings.js +35 -0
  12. package/esm/angular/interfaces/src/data-control-interfaces.d.ts +36 -0
  13. package/esm/angular/interfaces/src/data-control-interfaces.js +57 -0
  14. package/esm/angular/interfaces/src/dataList.d.ts +13 -0
  15. package/esm/angular/interfaces/src/dataList.js +42 -0
  16. package/esm/angular/interfaces/src/filter-helper.d.ts +13 -0
  17. package/esm/angular/interfaces/src/filter-helper.js +59 -0
  18. package/esm/angular/interfaces/src/grid-settings.d.ts +145 -0
  19. package/esm/angular/interfaces/src/grid-settings.js +387 -0
  20. package/esm/angular/interfaces/src/public_api.d.ts +4 -0
  21. package/esm/angular/interfaces/src/public_api.js +4 -0
  22. package/esm/angular/src/angular/RemultAngularPluginsService.d.ts +4 -0
  23. package/esm/angular/src/angular/RemultAngularPluginsService.js +3 -0
  24. package/esm/angular/src/angular/data-control/data-control2.component.d.ts +49 -0
  25. package/esm/angular/src/angular/data-control/data-control2.component.js +138 -0
  26. package/esm/core/SseSubscriptionServer.d.ts +33 -0
  27. package/esm/core/SseSubscriptionServer.js +107 -0
  28. package/esm/core/assign.d.ts +1 -0
  29. package/esm/core/assign.js +5 -0
  30. package/esm/core/classType.d.ts +3 -0
  31. package/esm/core/classType.js +1 -0
  32. package/esm/core/index.d.ts +27 -0
  33. package/esm/core/index.js +25 -0
  34. package/esm/core/inputTypes.d.ts +9 -0
  35. package/esm/core/inputTypes.js +9 -0
  36. package/esm/core/live-query/data-provider-live-query-storage.d.ts +22 -0
  37. package/esm/core/live-query/data-provider-live-query-storage.js +71 -0
  38. package/esm/core/postgres/index.d.ts +2 -0
  39. package/esm/core/postgres/index.js +2 -0
  40. package/esm/core/postgres/postgres-data-provider.d.ts +36 -0
  41. package/esm/core/postgres/postgres-data-provider.js +120 -0
  42. package/esm/core/postgres/schema-builder.d.ts +17 -0
  43. package/esm/core/postgres/schema-builder.js +153 -0
  44. package/esm/core/remult-fresh.d.ts +17 -0
  45. package/esm/core/remult-fresh.js +29 -0
  46. package/esm/core/remult-knex/index.d.ts +30 -0
  47. package/esm/core/remult-knex/index.js +446 -0
  48. package/esm/core/remult-mongo.d.ts +24 -0
  49. package/esm/core/remult-mongo.js +254 -0
  50. package/esm/core/server/JsonEntityFileStorage.d.ts +10 -0
  51. package/esm/core/server/JsonEntityFileStorage.js +25 -0
  52. package/esm/core/server/core.d.ts +4 -0
  53. package/esm/core/server/core.js +4 -0
  54. package/esm/core/server/expressBridge.d.ts +182 -0
  55. package/esm/core/server/expressBridge.js +938 -0
  56. package/esm/core/server/index.d.ts +6 -0
  57. package/esm/core/server/index.js +9 -0
  58. package/esm/core/server/initAsyncHooks.d.ts +1 -0
  59. package/esm/core/server/initAsyncHooks.js +9 -0
  60. package/esm/core/server/initDataProvider.d.ts +2 -0
  61. package/esm/core/server/initDataProvider.js +14 -0
  62. package/esm/core/src/__EntityValueProvider.d.ts +11 -0
  63. package/esm/core/src/__EntityValueProvider.js +1 -0
  64. package/esm/core/src/__RowsOfDataForTesting.d.ts +3 -0
  65. package/esm/core/src/__RowsOfDataForTesting.js +1 -0
  66. package/esm/core/src/backend-tests/backend-database-test-setup.backend-spec.d.ts +6 -0
  67. package/esm/core/src/backend-tests/backend-database-test-setup.backend-spec.js +147 -0
  68. package/esm/core/src/backend-tests/my-test.backend-spec.d.ts +1 -0
  69. package/esm/core/src/backend-tests/my-test.backend-spec.js +197 -0
  70. package/esm/core/src/backend-tests/test-http-server.backend-spec.d.ts +1 -0
  71. package/esm/core/src/backend-tests/test-http-server.backend-spec.js +167 -0
  72. package/esm/core/src/buildRestDataProvider.d.ts +31 -0
  73. package/esm/core/src/buildRestDataProvider.js +113 -0
  74. package/esm/core/src/column-interfaces.d.ts +154 -0
  75. package/esm/core/src/column-interfaces.js +7 -0
  76. package/esm/core/src/column.d.ts +58 -0
  77. package/esm/core/src/column.js +174 -0
  78. package/esm/core/src/context.d.ts +134 -0
  79. package/esm/core/src/context.js +286 -0
  80. package/esm/core/src/data-api.d.ts +39 -0
  81. package/esm/core/src/data-api.js +279 -0
  82. package/esm/core/src/data-interfaces.d.ts +41 -0
  83. package/esm/core/src/data-interfaces.js +12 -0
  84. package/esm/core/src/data-providers/array-entity-data-provider.d.ts +22 -0
  85. package/esm/core/src/data-providers/array-entity-data-provider.js +252 -0
  86. package/esm/core/src/data-providers/in-memory-database.d.ts +9 -0
  87. package/esm/core/src/data-providers/in-memory-database.js +14 -0
  88. package/esm/core/src/data-providers/json-data-provider.d.ts +12 -0
  89. package/esm/core/src/data-providers/json-data-provider.js +55 -0
  90. package/esm/core/src/data-providers/rest-data-provider.d.ts +49 -0
  91. package/esm/core/src/data-providers/rest-data-provider.js +256 -0
  92. package/esm/core/src/data-providers/sql-database.d.ts +33 -0
  93. package/esm/core/src/data-providers/sql-database.js +384 -0
  94. package/esm/core/src/data-providers/web-sql-data-provider.d.ts +24 -0
  95. package/esm/core/src/data-providers/web-sql-data-provider.js +143 -0
  96. package/esm/core/src/entity.d.ts +91 -0
  97. package/esm/core/src/entity.js +1 -0
  98. package/esm/core/src/filter/filter-consumer-bridge-to-sql-request.d.ts +50 -0
  99. package/esm/core/src/filter/filter-consumer-bridge-to-sql-request.js +150 -0
  100. package/esm/core/src/filter/filter-consumer-bridge-to-url-builder.d.ts +1 -0
  101. package/esm/core/src/filter/filter-consumer-bridge-to-url-builder.js +1 -0
  102. package/esm/core/src/filter/filter-interfaces.d.ts +85 -0
  103. package/esm/core/src/filter/filter-interfaces.js +477 -0
  104. package/esm/core/src/live-query/LiveQueryClient.d.ts +20 -0
  105. package/esm/core/src/live-query/LiveQueryClient.js +188 -0
  106. package/esm/core/src/live-query/SseSubscriptionClient.d.ts +5 -0
  107. package/esm/core/src/live-query/SseSubscriptionClient.js +86 -0
  108. package/esm/core/src/live-query/SubscriptionChannel.d.ts +72 -0
  109. package/esm/core/src/live-query/SubscriptionChannel.js +123 -0
  110. package/esm/core/src/live-query/SubscriptionServer.d.ts +53 -0
  111. package/esm/core/src/live-query/SubscriptionServer.js +111 -0
  112. package/esm/core/src/live-query/live-query-tests.spec.d.ts +6 -0
  113. package/esm/core/src/live-query/live-query-tests.spec.js +952 -0
  114. package/esm/core/src/remult-proxy.d.ts +35 -0
  115. package/esm/core/src/remult-proxy.js +113 -0
  116. package/esm/core/src/remult3/DecoratorReplacer.d.ts +10 -0
  117. package/esm/core/src/remult3/DecoratorReplacer.js +20 -0
  118. package/esm/core/src/remult3/RepositoryImplementation.d.ts +355 -0
  119. package/esm/core/src/remult3/RepositoryImplementation.js +2109 -0
  120. package/esm/core/src/remult3/index.d.ts +2 -0
  121. package/esm/core/src/remult3/index.js +2 -0
  122. package/esm/core/src/remult3/remult3.d.ts +395 -0
  123. package/esm/core/src/remult3/remult3.js +2 -0
  124. package/esm/core/src/server-action.d.ts +81 -0
  125. package/esm/core/src/server-action.js +394 -0
  126. package/esm/core/src/shared-tests/db-tests-setup.d.ts +32 -0
  127. package/esm/core/src/shared-tests/db-tests-setup.js +78 -0
  128. package/esm/core/src/shared-tests/db-tests.db-tests.d.ts +25 -0
  129. package/esm/core/src/shared-tests/db-tests.db-tests.js +810 -0
  130. package/esm/core/src/shared-tests/deleteAll.d.ts +2 -0
  131. package/esm/core/src/shared-tests/deleteAll.js +4 -0
  132. package/esm/core/src/shared-tests/entityWithValidations.d.ts +14 -0
  133. package/esm/core/src/shared-tests/entityWithValidations.js +43 -0
  134. package/esm/core/src/shared-tests/index.d.ts +4 -0
  135. package/esm/core/src/shared-tests/index.js +4 -0
  136. package/esm/core/src/shared-tests/test-custom-id-column.spec.d.ts +1 -0
  137. package/esm/core/src/shared-tests/test-custom-id-column.spec.js +67 -0
  138. package/esm/core/src/shared-tests/test-special-value.spec.d.ts +10 -0
  139. package/esm/core/src/shared-tests/test-special-value.spec.js +73 -0
  140. package/esm/core/src/shared-tests/test-update-with-null.spec.d.ts +1 -0
  141. package/esm/core/src/shared-tests/test-update-with-null.spec.js +31 -0
  142. package/esm/core/src/sort.d.ts +16 -0
  143. package/esm/core/src/sort.js +103 -0
  144. package/esm/core/src/sql-command.d.ts +19 -0
  145. package/esm/core/src/sql-command.js +1 -0
  146. package/esm/core/src/test.d.ts +3 -0
  147. package/esm/core/src/test.js +12 -0
  148. package/esm/core/src/tests/Done.d.ts +5 -0
  149. package/esm/core/src/tests/Done.js +9 -0
  150. package/esm/core/src/tests/RowProvider.spec.d.ts +16 -0
  151. package/esm/core/src/tests/RowProvider.spec.js +631 -0
  152. package/esm/core/src/tests/TestDataApiResponse.d.ts +10 -0
  153. package/esm/core/src/tests/TestDataApiResponse.js +22 -0
  154. package/esm/core/src/tests/basicRowFunctionality.spec.d.ts +8 -0
  155. package/esm/core/src/tests/basicRowFunctionality.spec.js +2103 -0
  156. package/esm/core/src/tests/c.d.ts +8 -0
  157. package/esm/core/src/tests/c.js +13 -0
  158. package/esm/core/src/tests/createData.d.ts +7 -0
  159. package/esm/core/src/tests/createData.js +22 -0
  160. package/esm/core/src/tests/d.d.ts +6 -0
  161. package/esm/core/src/tests/d.js +11 -0
  162. package/esm/core/src/tests/dWithPrefilter.d.ts +7 -0
  163. package/esm/core/src/tests/dWithPrefilter.js +18 -0
  164. package/esm/core/src/tests/entityForCustomFilter.d.ts +16 -0
  165. package/esm/core/src/tests/entityForCustomFilter.js +33 -0
  166. package/esm/core/src/tests/entityWithValidationsOnColumn.d.ts +5 -0
  167. package/esm/core/src/tests/entityWithValidationsOnColumn.js +13 -0
  168. package/esm/core/src/tests/frontend-database-tests-setup.spec.d.ts +4 -0
  169. package/esm/core/src/tests/frontend-database-tests-setup.spec.js +37 -0
  170. package/esm/core/src/tests/h.d.ts +6 -0
  171. package/esm/core/src/tests/h.js +24 -0
  172. package/esm/core/src/tests/remult-3-basic-tests.spec.d.ts +1 -0
  173. package/esm/core/src/tests/remult-3-basic-tests.spec.js +236 -0
  174. package/esm/core/src/tests/remult-3-entities.d.ts +23 -0
  175. package/esm/core/src/tests/remult-3-entities.js +39 -0
  176. package/esm/core/src/tests/tasks.d.ts +6 -0
  177. package/esm/core/src/tests/tasks.js +10 -0
  178. package/esm/core/src/tests/test-context-as-storage.spec.d.ts +0 -0
  179. package/esm/core/src/tests/test-context-as-storage.spec.js +1 -0
  180. package/esm/core/src/tests/test-data-api/predefined-filter.spec.d.ts +1 -0
  181. package/esm/core/src/tests/test-data-api/predefined-filter.spec.js +389 -0
  182. package/esm/core/src/tests/test-data-api/test-put-with-validation.spec.d.ts +5 -0
  183. package/esm/core/src/tests/test-data-api/test-put-with-validation.spec.js +152 -0
  184. package/esm/core/src/tests/test-decorator-precedence.spec.d.ts +1 -0
  185. package/esm/core/src/tests/test-decorator-precedence.spec.js +38 -0
  186. package/esm/core/src/tests/test-default-value.spec.d.ts +1 -0
  187. package/esm/core/src/tests/test-default-value.spec.js +33 -0
  188. package/esm/core/src/tests/test-entity-inheritance.spec.d.ts +14 -0
  189. package/esm/core/src/tests/test-entity-inheritance.spec.js +82 -0
  190. package/esm/core/src/tests/test-exceptions.spec.d.ts +1 -0
  191. package/esm/core/src/tests/test-exceptions.spec.js +375 -0
  192. package/esm/core/src/tests/test-json.spec.d.ts +1 -0
  193. package/esm/core/src/tests/test-json.spec.js +115 -0
  194. package/esm/core/src/tests/test-many-to-one-relation-in-entity.spec.d.ts +9 -0
  195. package/esm/core/src/tests/test-many-to-one-relation-in-entity.spec.js +809 -0
  196. package/esm/core/src/tests/test-non-active-record.spec.d.ts +1 -0
  197. package/esm/core/src/tests/test-non-active-record.spec.js +66 -0
  198. package/esm/core/src/tests/test-object-column.spec.d.ts +1 -0
  199. package/esm/core/src/tests/test-object-column.spec.js +189 -0
  200. package/esm/core/src/tests/test-paged-foreach.spec.d.ts +1 -0
  201. package/esm/core/src/tests/test-paged-foreach.spec.js +328 -0
  202. package/esm/core/src/tests/test-remult-angular.spec.d.ts +1 -0
  203. package/esm/core/src/tests/test-remult-angular.spec.js +23 -0
  204. package/esm/core/src/tests/test-server-controller.spec.d.ts +7 -0
  205. package/esm/core/src/tests/test-server-controller.spec.js +489 -0
  206. package/esm/core/src/tests/test-server-expressions.spec.d.ts +1 -0
  207. package/esm/core/src/tests/test-server-expressions.spec.js +178 -0
  208. package/esm/core/src/tests/test-server-method-on-entity.spec.d.ts +1 -0
  209. package/esm/core/src/tests/test-server-method-on-entity.spec.js +306 -0
  210. package/esm/core/src/tests/test-sql-expression.spec.d.ts +5 -0
  211. package/esm/core/src/tests/test-sql-expression.spec.js +205 -0
  212. package/esm/core/src/tests/test-sql.spec.d.ts +1 -0
  213. package/esm/core/src/tests/test-sql.spec.js +170 -0
  214. package/esm/core/src/tests/test-subscribe.spec.d.ts +1 -0
  215. package/esm/core/src/tests/test-subscribe.spec.js +135 -0
  216. package/esm/core/src/tests/test-type-recovery.spec.d.ts +1 -0
  217. package/esm/core/src/tests/test-type-recovery.spec.js +49 -0
  218. package/esm/core/src/tests/test-where-api.spec.d.ts +1 -0
  219. package/esm/core/src/tests/test-where-api.spec.js +434 -0
  220. package/esm/core/src/tests/testHelper.spec.d.ts +36 -0
  221. package/esm/core/src/tests/testHelper.spec.js +226 -0
  222. package/esm/core/src/tests/testModel/models.d.ts +16 -0
  223. package/esm/core/src/tests/testModel/models.js +25 -0
  224. package/esm/core/src/validators.d.ts +14 -0
  225. package/esm/core/src/validators.js +33 -0
  226. package/esm/core/src/valueConverters.d.ts +13 -0
  227. package/esm/core/src/valueConverters.js +197 -0
  228. package/esm/core/urlBuilder.d.ts +6 -0
  229. package/esm/core/urlBuilder.js +20 -0
  230. package/esm/graphql.js +194 -73
  231. package/esm/index.d.ts +10 -10
  232. package/esm/index.js +8 -8
  233. package/esm/inputTypes.js +1 -1
  234. package/esm/live-query/data-provider-live-query-storage.d.ts +3 -3
  235. package/esm/live-query/data-provider-live-query-storage.js +12 -9
  236. package/esm/myLog.js +2 -2
  237. package/esm/postgres/postgres-data-provider.d.ts +2 -2
  238. package/esm/postgres/postgres-data-provider.js +20 -14
  239. package/esm/postgres/schema-builder.d.ts +1 -1
  240. package/esm/postgres/schema-builder.js +28 -21
  241. package/esm/remult-express.js +2 -2
  242. package/esm/remult-fastify.js +9 -7
  243. package/esm/remult-fresh.d.ts +1 -1
  244. package/esm/remult-fresh.js +5 -8
  245. package/esm/remult-knex/index.d.ts +4 -4
  246. package/esm/remult-knex/index.js +75 -59
  247. package/esm/remult-mongo.js +36 -27
  248. package/esm/remult-next.d.ts +3 -3
  249. package/esm/remult-next.js +17 -11
  250. package/esm/remult-sveltekit.js +10 -10
  251. package/esm/server/JsonEntityFileStorage.js +3 -1
  252. package/esm/server/core.d.ts +2 -2
  253. package/esm/server/core.js +2 -2
  254. package/esm/server/expressBridge.d.ts +3 -12
  255. package/esm/server/expressBridge.js +265 -278
  256. package/esm/server/index.d.ts +2 -2
  257. package/esm/server/index.js +5 -2
  258. package/esm/server/initAsyncHooks.js +1 -1
  259. package/esm/server/initDataProvider.js +1 -1
  260. package/esm/src/backend-tests/backend-database-test-setup.backend-spec.d.ts +1 -1
  261. package/esm/src/backend-tests/backend-database-test-setup.backend-spec.js +47 -38
  262. package/esm/src/buildRestDataProvider.d.ts +1 -1
  263. package/esm/src/buildRestDataProvider.js +21 -13
  264. package/esm/src/column-interfaces.d.ts +9 -9
  265. package/esm/src/column.d.ts +4 -0
  266. package/esm/src/column.js +23 -11
  267. package/esm/src/context.d.ts +20 -8
  268. package/esm/src/context.js +65 -24
  269. package/esm/src/data-api.d.ts +0 -1
  270. package/esm/src/data-api.js +38 -37
  271. package/esm/src/data-interfaces.d.ts +1 -1
  272. package/esm/src/data-interfaces.js +1 -1
  273. package/esm/src/data-providers/array-entity-data-provider.js +9 -9
  274. package/esm/src/data-providers/in-memory-database.d.ts +1 -1
  275. package/esm/src/data-providers/in-memory-database.js +3 -1
  276. package/esm/src/data-providers/json-data-provider.js +8 -8
  277. package/esm/src/data-providers/rest-data-provider.d.ts +1 -1
  278. package/esm/src/data-providers/rest-data-provider.js +52 -36
  279. package/esm/src/data-providers/sql-database.d.ts +5 -5
  280. package/esm/src/data-providers/sql-database.js +53 -36
  281. package/esm/src/data-providers/web-sql-data-provider.d.ts +4 -4
  282. package/esm/src/data-providers/web-sql-data-provider.js +15 -13
  283. package/esm/src/entity.d.ts +24 -24
  284. package/esm/src/filter/filter-consumer-bridge-to-sql-request.d.ts +4 -4
  285. package/esm/src/filter/filter-consumer-bridge-to-sql-request.js +35 -20
  286. package/esm/src/filter/filter-interfaces.d.ts +7 -7
  287. package/esm/src/filter/filter-interfaces.js +108 -88
  288. package/esm/src/live-query/LiveQueryClient.js +37 -29
  289. package/esm/src/live-query/SseSubscriptionClient.d.ts +1 -1
  290. package/esm/src/live-query/SseSubscriptionClient.js +14 -14
  291. package/esm/src/live-query/SubscriptionChannel.d.ts +3 -3
  292. package/esm/src/live-query/SubscriptionChannel.js +27 -25
  293. package/esm/src/live-query/SubscriptionServer.js +24 -20
  294. package/esm/src/remult-proxy.d.ts +1 -1
  295. package/esm/src/remult-proxy.js +87 -29
  296. package/esm/src/remult3/DecoratorReplacer.d.ts +2 -2
  297. package/esm/src/remult3/RepositoryImplementation.d.ts +51 -41
  298. package/esm/src/remult3/RepositoryImplementation.js +336 -206
  299. package/esm/src/remult3/remult3.d.ts +56 -51
  300. package/esm/src/remult3/remult3.js +0 -1
  301. package/esm/src/server-action.d.ts +12 -5
  302. package/esm/src/server-action.js +79 -53
  303. package/esm/src/shared-tests/db-tests-setup.d.ts +8 -8
  304. package/esm/src/shared-tests/db-tests-setup.js +10 -10
  305. package/esm/src/shared-tests/db-tests.db-tests.d.ts +1 -1
  306. package/esm/src/shared-tests/db-tests.db-tests.js +279 -177
  307. package/esm/src/shared-tests/deleteAll.d.ts +1 -1
  308. package/esm/src/shared-tests/deleteAll.js +1 -1
  309. package/esm/src/shared-tests/entityWithValidations.js +1 -1
  310. package/esm/src/shared-tests/test-custom-id-column.spec.js +4 -4
  311. package/esm/src/shared-tests/test-special-value.spec.js +12 -12
  312. package/esm/src/shared-tests/test-update-with-null.spec.js +10 -6
  313. package/esm/src/sort.d.ts +2 -2
  314. package/esm/src/sort.js +12 -10
  315. package/esm/src/tests/TestDataApiResponse.d.ts +1 -1
  316. package/esm/src/tests/TestDataApiResponse.js +3 -4
  317. package/esm/src/tests/createData.js +2 -2
  318. package/esm/src/tests/d.js +1 -1
  319. package/esm/src/tests/dWithPrefilter.js +1 -1
  320. package/esm/src/tests/entityForCustomFilter.d.ts +4 -4
  321. package/esm/src/tests/entityForCustomFilter.js +12 -4
  322. package/esm/src/tests/entityWithValidationsOnColumn.js +1 -1
  323. package/esm/src/tests/frontend-database-tests-setup.spec.d.ts +1 -1
  324. package/esm/src/tests/frontend-database-tests-setup.spec.js +14 -14
  325. package/esm/src/tests/h.js +4 -4
  326. package/esm/src/tests/remult-3-entities.d.ts +2 -2
  327. package/esm/src/tests/remult-3-entities.js +6 -6
  328. package/esm/src/tests/testHelper.spec.d.ts +7 -7
  329. package/esm/src/tests/testHelper.spec.js +50 -39
  330. package/esm/src/tests/testModel/models.js +4 -4
  331. package/esm/src/validators.d.ts +1 -1
  332. package/esm/src/validators.js +10 -7
  333. package/esm/src/valueConverters.d.ts +1 -1
  334. package/esm/src/valueConverters.js +68 -55
  335. package/esm/test-servers/shared/Task.d.ts +9 -0
  336. package/esm/test-servers/shared/Task.js +32 -0
  337. package/esm/test.d.ts +5 -0
  338. package/esm/test.js +6 -0
  339. package/graphql.js +157 -45
  340. package/index.d.ts +10 -10
  341. package/inputTypes.js +1 -1
  342. package/live-query/data-provider-live-query-storage.d.ts +3 -3
  343. package/live-query/data-provider-live-query-storage.js +7 -4
  344. package/myLog.js +2 -2
  345. package/package.json +2 -2
  346. package/postgres/postgres-data-provider.d.ts +2 -2
  347. package/postgres/postgres-data-provider.js +21 -16
  348. package/postgres/schema-builder.d.ts +1 -1
  349. package/postgres/schema-builder.js +22 -15
  350. package/remult-express.js +1 -1
  351. package/remult-fastify.js +7 -7
  352. package/remult-fresh.d.ts +1 -1
  353. package/remult-fresh.js +1 -4
  354. package/remult-knex/index.d.ts +4 -4
  355. package/remult-knex/index.js +50 -35
  356. package/remult-mongo.js +33 -23
  357. package/remult-next.d.ts +3 -3
  358. package/remult-next.js +15 -11
  359. package/remult-sveltekit.js +14 -15
  360. package/server/core.d.ts +2 -2
  361. package/server/expressBridge.d.ts +3 -12
  362. package/server/expressBridge.js +278 -279
  363. package/server/index.d.ts +2 -2
  364. package/server/index.js +5 -2
  365. package/server/initAsyncHooks.js +2 -2
  366. package/server/initDataProvider.js +1 -1
  367. package/src/backend-tests/backend-database-test-setup.backend-spec.d.ts +1 -1
  368. package/src/backend-tests/backend-database-test-setup.backend-spec.js +40 -31
  369. package/src/buildRestDataProvider.d.ts +1 -1
  370. package/src/buildRestDataProvider.js +18 -10
  371. package/src/column-interfaces.d.ts +9 -9
  372. package/src/column.d.ts +4 -0
  373. package/src/column.js +20 -8
  374. package/src/context.d.ts +20 -8
  375. package/src/context.js +61 -18
  376. package/src/data-api.d.ts +0 -1
  377. package/src/data-api.js +40 -43
  378. package/src/data-interfaces.d.ts +1 -1
  379. package/src/data-providers/array-entity-data-provider.js +2 -2
  380. package/src/data-providers/in-memory-database.d.ts +1 -1
  381. package/src/data-providers/in-memory-database.js +3 -1
  382. package/src/data-providers/json-data-provider.js +33 -15
  383. package/src/data-providers/rest-data-provider.d.ts +1 -1
  384. package/src/data-providers/rest-data-provider.js +47 -32
  385. package/src/data-providers/sql-database.d.ts +5 -5
  386. package/src/data-providers/sql-database.js +41 -24
  387. package/src/data-providers/web-sql-data-provider.d.ts +4 -4
  388. package/src/data-providers/web-sql-data-provider.js +10 -8
  389. package/src/entity.d.ts +24 -24
  390. package/src/filter/filter-consumer-bridge-to-sql-request.d.ts +4 -4
  391. package/src/filter/filter-consumer-bridge-to-sql-request.js +34 -17
  392. package/src/filter/filter-interfaces.d.ts +7 -7
  393. package/src/filter/filter-interfaces.js +73 -47
  394. package/src/live-query/LiveQueryClient.js +35 -25
  395. package/src/live-query/SseSubscriptionClient.d.ts +1 -1
  396. package/src/live-query/SseSubscriptionClient.js +80 -76
  397. package/src/live-query/SubscriptionChannel.d.ts +3 -3
  398. package/src/live-query/SubscriptionChannel.js +26 -18
  399. package/src/live-query/SubscriptionServer.js +23 -17
  400. package/src/remult-proxy.d.ts +1 -1
  401. package/src/remult-proxy.js +84 -35
  402. package/src/remult3/DecoratorReplacer.d.ts +2 -2
  403. package/src/remult3/RepositoryImplementation.d.ts +51 -41
  404. package/src/remult3/RepositoryImplementation.js +402 -257
  405. package/src/remult3/remult3.d.ts +56 -51
  406. package/src/remult3/remult3.js +0 -1
  407. package/src/server-action.d.ts +12 -5
  408. package/src/server-action.js +78 -48
  409. package/src/shared-tests/db-tests-setup.d.ts +8 -8
  410. package/src/shared-tests/db-tests-setup.js +6 -6
  411. package/src/shared-tests/db-tests.db-tests.d.ts +1 -1
  412. package/src/shared-tests/db-tests.db-tests.js +350 -153
  413. package/src/shared-tests/deleteAll.d.ts +1 -1
  414. package/src/shared-tests/entityWithValidations.js +1 -1
  415. package/src/shared-tests/test-custom-id-column.spec.js +4 -4
  416. package/src/shared-tests/test-special-value.spec.js +9 -9
  417. package/src/shared-tests/test-update-with-null.spec.js +8 -4
  418. package/src/sort.d.ts +2 -2
  419. package/src/sort.js +9 -7
  420. package/src/tests/TestDataApiResponse.d.ts +1 -1
  421. package/src/tests/TestDataApiResponse.js +3 -4
  422. package/src/tests/createData.js +1 -1
  423. package/src/tests/d.js +1 -1
  424. package/src/tests/dWithPrefilter.js +1 -1
  425. package/src/tests/entityForCustomFilter.d.ts +4 -4
  426. package/src/tests/entityForCustomFilter.js +16 -6
  427. package/src/tests/entityWithValidationsOnColumn.js +1 -1
  428. package/src/tests/frontend-database-tests-setup.spec.d.ts +1 -1
  429. package/src/tests/frontend-database-tests-setup.spec.js +8 -8
  430. package/src/tests/h.js +3 -3
  431. package/src/tests/remult-3-entities.d.ts +2 -2
  432. package/src/tests/remult-3-entities.js +8 -4
  433. package/src/tests/testHelper.spec.d.ts +7 -7
  434. package/src/tests/testHelper.spec.js +38 -27
  435. package/src/tests/testModel/models.js +3 -3
  436. package/src/validators.d.ts +1 -1
  437. package/src/validators.js +18 -9
  438. package/src/valueConverters.d.ts +1 -1
  439. package/src/valueConverters.js +38 -21
  440. package/esm/remult-svletekit.d.ts +0 -3
  441. package/esm/remult-svletekit.js +0 -83
  442. package/esm/src/id-entity.d.ts +0 -4
  443. package/esm/src/id-entity.js +0 -8
  444. package/esm/src/remult3/getId.d.ts +0 -2
  445. package/esm/src/remult3/getId.js +0 -7
  446. package/postgres/getEntityTypescriptPostgres.d.ts +0 -1
  447. package/postgres/getEntityTypescriptPostgres.js +0 -125
  448. package/src/id-entity.d.ts +0 -4
  449. package/src/id-entity.js +0 -17
  450. package/src/remult3/getId.d.ts +0 -2
  451. package/src/remult3/getId.js +0 -11
@@ -0,0 +1,952 @@
1
+ import { queryConfig, Remult } from "../context";
2
+ import { DataApi } from "../data-api";
3
+ import { InMemoryDataProvider } from "../data-providers/in-memory-database";
4
+ import { Entity, Fields, getEntityRef } from "../remult3";
5
+ import { actionInfo } from "../server-action";
6
+ import { createMockHttpDataProvider } from "../tests/testHelper.spec";
7
+ import { SubscriptionChannel } from "./SubscriptionChannel";
8
+ import { LiveQueryClient } from "./LiveQueryClient";
9
+ import { LiveQueryPublisher, InMemoryLiveQueryStorage } from "./SubscriptionServer";
10
+ import { findOptionsFromJson, findOptionsToJson } from "../data-providers/rest-data-provider";
11
+ import { remult } from "../remult-proxy";
12
+ const joc = jasmine.objectContaining;
13
+ @Entity("event-test", { allowApiCrud: true })
14
+ export class eventTestEntity {
15
+ @Fields.integer()
16
+ id = 0;
17
+ @Fields.string()
18
+ title;
19
+ @Fields.string((o, remult) => o.serverExpression = () => remult.user.name)
20
+ selectUser = '';
21
+ @Fields.date()
22
+ birthDate = new Date(1976, 5, 16);
23
+ }
24
+ async function setup1() {
25
+ const mem = new InMemoryDataProvider();
26
+ const serverRemult = new Remult(mem);
27
+ serverRemult.user = ({ id: 'server', name: 'server', roles: [] });
28
+ const serverRepo = serverRemult.repo(eventTestEntity);
29
+ const items = [
30
+ { id: 1, title: 'noam' },
31
+ { id: 2, title: 'yael' },
32
+ { id: 3, title: 'yoni' },
33
+ { id: 4, title: 'maayan' },
34
+ { id: 5, title: 'itamar' },
35
+ { id: 6, title: 'ofri' }
36
+ ];
37
+ await serverRepo.insert(items);
38
+ const remult = new Remult(mem);
39
+ remult.user = ({ id: clientId1, name: clientId1, roles: [] });
40
+ const clientRepo = remult.repo(eventTestEntity);
41
+ const messages = [];
42
+ serverRemult.subscriptionServer = {
43
+ publishMessage: async (c, m) => { messages.push(...m); },
44
+ };
45
+ serverRemult.liveQueryStorage = new InMemoryLiveQueryStorage();
46
+ const qm = new LiveQueryPublisher(() => (serverRemult.subscriptionServer), () => serverRemult.liveQueryStorage, async (_, _1, c) => c(clientRepo));
47
+ let p = new PromiseResolver(qm);
48
+ serverRemult.liveQueryPublisher = qm;
49
+ await serverRemult.liveQueryStorage.add({
50
+ entityKey: clientRepo.metadata.key,
51
+ data: {
52
+ findOptionsJson: {},
53
+ requestJson: {},
54
+ lastIds: items.map(x => x.id),
55
+ },
56
+ id: "xxx"
57
+ });
58
+ expect(messages.length).toBe(0);
59
+ return { serverRepo, messages, flush: () => p.flush() };
60
+ }
61
+ const clientId1 = "clientId1";
62
+ describe("Live Query", () => {
63
+ beforeEach(() => { actionInfo.runningOnServer = true; });
64
+ afterEach(() => { actionInfo.runningOnServer = false; });
65
+ it("test that data is sent with correct remult user", async () => {
66
+ const { serverRepo, messages, flush } = await setup1();
67
+ const row = await serverRepo.findId(1);
68
+ row.title += '1';
69
+ await serverRepo.save(row);
70
+ await flush();
71
+ expect(messages).toEqual([joc({
72
+ type: 'replace',
73
+ data: joc({
74
+ oldId: 1,
75
+ item: joc({ selectUser: clientId1 })
76
+ })
77
+ })]);
78
+ });
79
+ it("test that id change is supported", async () => {
80
+ const { serverRepo, messages, flush } = await setup1();
81
+ const row = await serverRepo.findId(1);
82
+ row.id = 99;
83
+ await serverRepo.save(row);
84
+ await flush();
85
+ expect(messages).toEqual([joc({
86
+ type: 'replace',
87
+ data: joc({
88
+ oldId: 1,
89
+ item: joc({
90
+ id: 99,
91
+ selectUser: clientId1
92
+ })
93
+ })
94
+ })
95
+ ]);
96
+ });
97
+ it("new row is reported", async () => {
98
+ const { serverRepo, messages, flush } = await setup1();
99
+ const row = await serverRepo.insert([{ id: 9, title: 'david' }]);
100
+ await flush();
101
+ expect(messages).toEqual([joc({
102
+ type: 'add',
103
+ data: joc({
104
+ item: joc({
105
+ id: 9,
106
+ selectUser: clientId1
107
+ })
108
+ })
109
+ })
110
+ ]);
111
+ });
112
+ it("removed row is reported", async () => {
113
+ const { serverRepo, messages, flush } = await setup1();
114
+ await serverRepo.delete((await serverRepo.findFirst({ id: 1 })));
115
+ await flush();
116
+ expect(messages).toEqual([joc({
117
+ type: 'remove',
118
+ data: { id: 1 }
119
+ })]);
120
+ });
121
+ });
122
+ function createTestPromise() {
123
+ let resume;
124
+ const r = new Promise(r => {
125
+ resume = () => r({});
126
+ });
127
+ return Object.assign(r, { resume });
128
+ }
129
+ class PromiseResolver {
130
+ promises = [];
131
+ constructor(...who) {
132
+ for (const w of who) {
133
+ w.runPromise = p => {
134
+ this.promises.push(p);
135
+ return p;
136
+ };
137
+ }
138
+ }
139
+ async flush() {
140
+ while (this.promises.length > 0) {
141
+ let p = this.promises;
142
+ this.promises = [];
143
+ await Promise.all(p).catch(err => { });
144
+ }
145
+ }
146
+ }
147
+ describe("Live Query Client", () => {
148
+ it("registers once", async () => {
149
+ let open = 0;
150
+ let get = 0;
151
+ let sendMessage = x => { };
152
+ const lqc = new LiveQueryClient(() => ({
153
+ subscriptionClient: {
154
+ async openConnection(onMessage) {
155
+ open++;
156
+ return {
157
+ close() {
158
+ open--;
159
+ },
160
+ async subscribe(channel, onMessage) {
161
+ sendMessage = x => onMessage([x]);
162
+ return () => {
163
+ };
164
+ },
165
+ };
166
+ },
167
+ },
168
+ httpClient: {
169
+ get: async (url) => {
170
+ get++;
171
+ return [{
172
+ id: 1,
173
+ title: 'noam'
174
+ }];
175
+ },
176
+ put: () => undefined,
177
+ post: async () => { },
178
+ delete: () => undefined
179
+ }
180
+ }), () => serverRemult.user?.id);
181
+ let p = new PromiseResolver(lqc);
182
+ const serverRemult = new Remult(new InMemoryDataProvider());
183
+ serverRemult.liveQuerySubscriber = lqc;
184
+ const serverRepo = serverRemult.repo(eventTestEntity);
185
+ let closeSub1;
186
+ let closeSub2;
187
+ let result1;
188
+ let result2;
189
+ closeSub1 = serverRepo.liveQuery().subscribe(({ applyChanges: reducer }) => {
190
+ result1 = reducer(result1);
191
+ });
192
+ closeSub2 = serverRepo.liveQuery().subscribe(({ applyChanges: reducer }) => {
193
+ result2 = reducer(result2);
194
+ });
195
+ await p.flush();
196
+ expect(open).toBe(1);
197
+ expect(get).toBe(1);
198
+ expect(result1[0].title).toBe("noam");
199
+ expect(result2[0].title).toBe("noam");
200
+ sendMessage({
201
+ type: "replace",
202
+ data: {
203
+ oldId: 1,
204
+ item: {
205
+ id: 1,
206
+ title: 'noam1'
207
+ }
208
+ }
209
+ });
210
+ await p.flush();
211
+ expect(result1[0].title).toBe("noam1");
212
+ expect(result2[0].title).toBe("noam1");
213
+ closeSub1();
214
+ await p.flush();
215
+ sendMessage({
216
+ type: "replace",
217
+ data: {
218
+ oldId: 1,
219
+ item: {
220
+ id: 1,
221
+ title: 'noam2'
222
+ }
223
+ }
224
+ });
225
+ await p.flush();
226
+ expect(result1[0].title).toBe("noam1");
227
+ expect(result2[0].title).toBe("noam2");
228
+ closeSub2();
229
+ await p.flush();
230
+ expect(open).toBe(0);
231
+ get = 0;
232
+ closeSub1 = lqc.subscribe(serverRepo, {}, {
233
+ complete: () => { },
234
+ error: () => { },
235
+ next: ({ applyChanges: reducer }) => {
236
+ result1 = reducer(result1);
237
+ }
238
+ });
239
+ await p.flush();
240
+ expect(open).toBe(1);
241
+ expect(get).toBe(1);
242
+ closeSub1();
243
+ await p.flush();
244
+ expect(open).toBe(0);
245
+ });
246
+ });
247
+ describe("test live query full cycle", () => {
248
+ beforeEach(() => {
249
+ queryConfig.defaultPageSize = 100;
250
+ });
251
+ afterEach(() => {
252
+ queryConfig.defaultPageSize = 2;
253
+ });
254
+ function setup2() {
255
+ const mem = new InMemoryDataProvider();
256
+ const remult = new Remult(mem);
257
+ const repo = remult.repo(eventTestEntity);
258
+ const remult2 = new Remult(mem);
259
+ const repo2 = remult2.repo(eventTestEntity);
260
+ const mh = [];
261
+ let messageCount = 0;
262
+ remult.liveQueryStorage = new InMemoryLiveQueryStorage();
263
+ remult.subscriptionServer = {
264
+ async publishMessage(channel, message) {
265
+ mh.forEach(x => x(channel, message));
266
+ }
267
+ };
268
+ const qm = new LiveQueryPublisher(() => (remult.subscriptionServer), () => remult.liveQueryStorage, async (_, _1, c) => c(repo));
269
+ remult.liveQueryPublisher = qm;
270
+ var dataApi = new DataApi(repo, remult);
271
+ const clientStatus = {
272
+ connected: true,
273
+ reconnect: () => { }
274
+ };
275
+ let unsubscribeCount = 0;
276
+ const buildLqc = () => {
277
+ return new LiveQueryClient(() => ({
278
+ subscriptionClient: {
279
+ async openConnection(onReconnect) {
280
+ clientStatus.connected = true;
281
+ clientStatus.reconnect = () => {
282
+ onReconnect();
283
+ clientStatus.connected = true;
284
+ };
285
+ const channels = [];
286
+ return {
287
+ close() {
288
+ },
289
+ async subscribe(channel, onMessage) {
290
+ channels.push(channel);
291
+ mh.push((c, message) => {
292
+ if (clientStatus.connected)
293
+ if (channels.includes(c) && c == channel) {
294
+ messageCount++;
295
+ onMessage(message);
296
+ }
297
+ });
298
+ return () => {
299
+ unsubscribeCount++;
300
+ channels.splice(channels.indexOf(channel), 1);
301
+ };
302
+ },
303
+ };
304
+ },
305
+ }, httpClient: createMockHttpDataProvider(dataApi)
306
+ }), () => remult.user?.id);
307
+ };
308
+ const lqc1 = buildLqc();
309
+ const lqc2 = buildLqc();
310
+ var pm = new PromiseResolver(lqc1, lqc2, qm);
311
+ remult.liveQuerySubscriber = lqc1;
312
+ remult2.liveQuerySubscriber = lqc2;
313
+ remult.liveQueryPublisher = qm;
314
+ remult2.liveQueryPublisher = qm;
315
+ return {
316
+ repo, pm, repo2, messageCount: () => messageCount, clientStatus, qm: remult.liveQueryStorage, testApi: () => createMockHttpDataProvider(dataApi), remult,
317
+ unsubscribeCount() {
318
+ return unsubscribeCount;
319
+ }
320
+ };
321
+ }
322
+ it("integration test 1", async () => {
323
+ var { repo, pm, repo2 } = setup2();
324
+ let result1 = [];
325
+ const u = repo.liveQuery().subscribe(({ applyChanges: reducer }) => result1 = reducer(result1));
326
+ await pm.flush();
327
+ expect(result1.length).toBe(0);
328
+ await repo.insert({ id: 1, title: "noam" });
329
+ await repo2.insert({ id: 2, title: "yael" });
330
+ await pm.flush();
331
+ expect(result1.length).toBe(2);
332
+ result1[0] = { ...result1[0], title: 'noam1' };
333
+ await repo2.save({ ...result1[1], title: 'yael2' });
334
+ await pm.flush();
335
+ expect(result1.length).toBe(2);
336
+ expect(result1[0].title).toBe('noam1');
337
+ expect(result1[0].birthDate.getFullYear()).toBe(1976);
338
+ expect(result1[1].title).toBe('yael2');
339
+ await repo.save(result1[0]);
340
+ u();
341
+ });
342
+ it("integration test 2", async () => {
343
+ var { repo, pm, repo2 } = setup2();
344
+ let result1 = [];
345
+ await repo.insert({ id: 1, title: "noam" });
346
+ const u = repo.liveQuery().subscribe(({ applyChanges: reducer }) => result1 = reducer(result1));
347
+ await pm.flush();
348
+ expect(result1[0].title).toBe('noam');
349
+ expect(result1[0].birthDate.getFullYear()).toBe(1976);
350
+ u();
351
+ });
352
+ it("test delete works", async () => {
353
+ var { repo, pm, repo2 } = setup2();
354
+ let result1 = [];
355
+ const u = repo.liveQuery().subscribe(({ applyChanges: reducer }) => result1 = reducer(result1));
356
+ await pm.flush();
357
+ await repo.insert({ id: 1, title: "noam" });
358
+ await repo2.insert({ id: 2, title: "yael" });
359
+ await pm.flush();
360
+ await repo.delete(result1[1]);
361
+ await pm.flush();
362
+ expect(result1.length).toBe(1);
363
+ u();
364
+ });
365
+ it("test sort works", async () => {
366
+ var { repo, pm, repo2 } = setup2();
367
+ let result1 = [];
368
+ let items = [];
369
+ const u = repo.liveQuery({
370
+ orderBy: { title: "desc" }
371
+ }).subscribe((info) => {
372
+ result1 = info.applyChanges(result1);
373
+ items = info.items;
374
+ });
375
+ await pm.flush();
376
+ await repo.insert({ id: 1, title: "noam" });
377
+ await pm.flush();
378
+ await repo2.insert({ id: 2, title: "yael" });
379
+ await pm.flush();
380
+ expect(result1.map(r => r.id)).toEqual([1, 2]);
381
+ expect(items.map(r => r.id)).toEqual([2, 1]);
382
+ u();
383
+ });
384
+ it("test add works if item already in array", async () => {
385
+ var { repo, pm, repo2 } = setup2();
386
+ let result1 = [];
387
+ const u = repo.liveQuery().subscribe(({ applyChanges: reducer }) => result1 = reducer(result1));
388
+ await pm.flush();
389
+ result1 = [await repo.insert({ id: 1, title: "noam" })];
390
+ await pm.flush();
391
+ expect(result1.length).toBe(1);
392
+ u();
393
+ });
394
+ it("test add works if item already in array", async () => {
395
+ var { repo, pm, repo2 } = setup2();
396
+ let result1 = [];
397
+ const u = repo.liveQuery().subscribe(({ applyChanges: reducer }) => result1 = reducer(result1));
398
+ await pm.flush();
399
+ await repo.insert({ id: 1, title: "noam" });
400
+ await pm.flush();
401
+ expect(result1.length).toBe(1);
402
+ u();
403
+ });
404
+ it("test quick unsubscribe before subscribe completes", async () => {
405
+ const serverRemult = new Remult(new InMemoryDataProvider());
406
+ const serverRepo = serverRemult.repo(eventTestEntity);
407
+ var dataApi = new DataApi(serverRepo, serverRemult);
408
+ var remult = new Remult();
409
+ var dp = createMockHttpDataProvider(dataApi);
410
+ let waitForUnsubscribe = createTestPromise();
411
+ let waitForSubscribe = createTestPromise();
412
+ let stats = {
413
+ sub: 0,
414
+ unSub: 0,
415
+ query: 0
416
+ };
417
+ remult.apiClient.httpClient = {
418
+ post: (a, b) => dp.post(a, b),
419
+ put: (a, b) => dp.put(a, b),
420
+ delete: a => dp.delete(a),
421
+ get: async (url) => {
422
+ stats.query++;
423
+ return dp.get(url);
424
+ }
425
+ };
426
+ let mh = [];
427
+ serverRemult.subscriptionServer = {
428
+ publishMessage: async (c, m) => mh.forEach(x => x(c, m))
429
+ };
430
+ serverRemult.liveQueryStorage = new InMemoryLiveQueryStorage();
431
+ serverRemult.liveQueryPublisher = new LiveQueryPublisher(() => serverRemult.subscriptionServer, () => serverRemult.liveQueryStorage, async (_, _1, c) => c(serverRemult.repo(eventTestEntity)));
432
+ remult.apiClient.subscriptionClient = {
433
+ openConnection: async () => {
434
+ return {
435
+ subscribe: async (a, handler) => {
436
+ waitForUnsubscribe.resume();
437
+ await waitForSubscribe;
438
+ stats.sub++;
439
+ mh.push((c, m) => {
440
+ handler(m);
441
+ });
442
+ return () => {
443
+ stats.unSub++;
444
+ mh = mh.filter(h => h !== handler);
445
+ };
446
+ },
447
+ close: () => {
448
+ }
449
+ };
450
+ }
451
+ };
452
+ var pm = new PromiseResolver(remult.liveQuerySubscriber, serverRemult.liveQueryPublisher);
453
+ const repo = remult.repo(eventTestEntity);
454
+ let result1 = [];
455
+ let u = repo.liveQuery().subscribe({
456
+ next: ({ applyChanges: reducer }) => result1 = reducer(result1),
457
+ error: err => {
458
+ throw err;
459
+ }
460
+ });
461
+ await waitForUnsubscribe;
462
+ u();
463
+ waitForSubscribe.resume();
464
+ await pm.flush();
465
+ await repo.insert({ id: 1, title: "noam" });
466
+ await pm.flush();
467
+ expect(result1.length).toBe(0);
468
+ expect(stats.sub).toBe(1);
469
+ expect(stats.unSub).toBe(1);
470
+ expect(stats.query).toBe(0);
471
+ });
472
+ it("test quick unsubscribe before query completes", async () => {
473
+ const serverRemult = new Remult(new InMemoryDataProvider());
474
+ const serverRepo = serverRemult.repo(eventTestEntity);
475
+ var dataApi = new DataApi(serverRepo, serverRemult);
476
+ var remult = new Remult();
477
+ var dp = createMockHttpDataProvider(dataApi);
478
+ let waitForUnsubscribe = createTestPromise();
479
+ let waitForGet = createTestPromise();
480
+ remult.apiClient.httpClient = {
481
+ post: (a, b) => dp.post(a, b),
482
+ put: (a, b) => dp.put(a, b),
483
+ delete: a => dp.delete(a),
484
+ get: async (url) => {
485
+ waitForUnsubscribe.resume();
486
+ await waitForGet;
487
+ return dp.get(url);
488
+ }
489
+ };
490
+ let mh = [];
491
+ serverRemult.subscriptionServer = {
492
+ publishMessage: async (c, m) => mh.forEach(x => x(c, m))
493
+ };
494
+ serverRemult.liveQueryStorage = new InMemoryLiveQueryStorage();
495
+ serverRemult.liveQueryPublisher = new LiveQueryPublisher(() => serverRemult.subscriptionServer, () => serverRemult.liveQueryStorage, async (_, _1, c) => c(serverRemult.repo(eventTestEntity)));
496
+ let stats = {
497
+ sub: 0,
498
+ unSub: 0
499
+ };
500
+ remult.apiClient.subscriptionClient = {
501
+ openConnection: async () => {
502
+ return {
503
+ subscribe: async (a, handler) => {
504
+ stats.sub++;
505
+ mh.push((c, m) => {
506
+ handler(m);
507
+ });
508
+ return () => {
509
+ stats.unSub++;
510
+ mh = mh.filter(h => h !== handler);
511
+ };
512
+ },
513
+ close: () => {
514
+ }
515
+ };
516
+ }
517
+ };
518
+ var pm = new PromiseResolver(remult.liveQuerySubscriber, serverRemult.liveQueryPublisher);
519
+ const repo = remult.repo(eventTestEntity);
520
+ let result1 = [];
521
+ let u = repo.liveQuery().subscribe({
522
+ next: ({ applyChanges: reducer }) => result1 = reducer(result1),
523
+ error: err => {
524
+ throw err;
525
+ }
526
+ });
527
+ await waitForUnsubscribe;
528
+ u();
529
+ waitForGet.resume();
530
+ await pm.flush();
531
+ await repo.insert({ id: 1, title: "noam" });
532
+ await pm.flush();
533
+ expect(result1.length).toBe(0);
534
+ expect(stats.sub).toBe(1);
535
+ expect(stats.unSub).toBe(1);
536
+ });
537
+ it("test quick unsubscribe and subscribe", async () => {
538
+ const serverRemult = new Remult(new InMemoryDataProvider());
539
+ const serverRepo = serverRemult.repo(eventTestEntity);
540
+ var dataApi = new DataApi(serverRepo, serverRemult);
541
+ var remult = new Remult();
542
+ var dp = createMockHttpDataProvider(dataApi);
543
+ let stats = {
544
+ sub: 0,
545
+ unSub: 0,
546
+ get: 0,
547
+ post: 0
548
+ };
549
+ remult.apiClient.httpClient = {
550
+ post: (a, b) => {
551
+ stats.post++;
552
+ return dp.post(a, b);
553
+ },
554
+ put: (a, b) => dp.put(a, b),
555
+ delete: a => dp.delete(a),
556
+ get: async (url) => {
557
+ stats.get++;
558
+ return dp.get(url);
559
+ }
560
+ };
561
+ let mh = [];
562
+ serverRemult.subscriptionServer = {
563
+ publishMessage: async (c, m) => mh.forEach(x => x(c, m))
564
+ };
565
+ serverRemult.liveQueryStorage = new InMemoryLiveQueryStorage();
566
+ serverRemult.liveQueryPublisher = new LiveQueryPublisher(() => serverRemult.subscriptionServer, () => serverRemult.liveQueryStorage, async (_, _1, c) => c(serverRemult.repo(eventTestEntity)));
567
+ remult.apiClient.subscriptionClient = {
568
+ openConnection: async () => {
569
+ return {
570
+ subscribe: async (a, handler) => {
571
+ stats.sub++;
572
+ mh.push((c, m) => {
573
+ handler(m);
574
+ });
575
+ return () => {
576
+ stats.unSub++;
577
+ mh = mh.filter(h => h !== handler);
578
+ };
579
+ },
580
+ close: () => {
581
+ }
582
+ };
583
+ }
584
+ };
585
+ var pm = new PromiseResolver(remult.liveQuerySubscriber, serverRemult.liveQueryPublisher);
586
+ const repo = remult.repo(eventTestEntity);
587
+ let result1 = [];
588
+ let u = repo.liveQuery().subscribe({
589
+ next: ({ applyChanges: reducer }) => result1 = reducer(result1),
590
+ error: err => {
591
+ throw err;
592
+ }
593
+ });
594
+ await pm.flush();
595
+ u();
596
+ u = repo.liveQuery().subscribe({
597
+ next: ({ applyChanges: reducer }) => result1 = reducer(result1),
598
+ error: err => {
599
+ throw err;
600
+ }
601
+ });
602
+ await pm.flush();
603
+ expect(result1.length).toBe(0);
604
+ expect(stats.sub).toBe(2);
605
+ expect(stats.unSub).toBe(1);
606
+ expect(stats.get).toBe(2);
607
+ u();
608
+ });
609
+ it("test unsubscribe works", async () => {
610
+ var { repo, pm, messageCount, qm, unsubscribeCount, remult } = setup2();
611
+ let result1 = [];
612
+ const unsubscribe = repo.liveQuery().subscribe(({ applyChanges: reducer }) => result1 = reducer(result1));
613
+ await pm.flush();
614
+ await repo.insert({ id: 1, title: "noam" });
615
+ await pm.flush();
616
+ expect(result1.length).toBe(1);
617
+ expect(messageCount()).toBe(1);
618
+ expect(qm.queries.length).toBe(1);
619
+ unsubscribe();
620
+ await pm.flush();
621
+ await repo.insert({ id: 2, title: 'noam' });
622
+ await pm.flush();
623
+ expect(qm.queries.length).toBe(0);
624
+ expect(messageCount()).toBe(1);
625
+ expect(unsubscribeCount()).toBe(1);
626
+ expect(remult.liveQueryStorage.removeCountForTesting).toBe(1);
627
+ unsubscribe();
628
+ await pm.flush();
629
+ expect(unsubscribeCount()).toBe(1);
630
+ expect(remult.liveQueryStorage.removeCountForTesting).toBe(1);
631
+ });
632
+ it("test unsubscribe works after subscribe and unsubscribe", async () => {
633
+ var { repo, pm, messageCount, qm, unsubscribeCount, remult } = setup2();
634
+ let result1 = [];
635
+ let unsubscribe = repo.liveQuery().subscribe(({ applyChanges: reducer }) => result1 = reducer(result1));
636
+ await pm.flush();
637
+ unsubscribe();
638
+ await pm.flush();
639
+ unsubscribe = repo.liveQuery().subscribe(({ applyChanges: reducer }) => result1 = reducer(result1));
640
+ await pm.flush();
641
+ unsubscribe();
642
+ await pm.flush();
643
+ expect(unsubscribeCount()).toBe(2);
644
+ expect(remult.liveQueryStorage.removeCountForTesting).toBe(2);
645
+ });
646
+ it("test unsubscribe works after a quick subscribe and unsubscribe", async () => {
647
+ var { repo, pm, messageCount, qm, unsubscribeCount, remult } = setup2();
648
+ let result1 = [];
649
+ let unsubscribe = repo.liveQuery().subscribe(({ applyChanges: reducer }) => result1 = reducer(result1));
650
+ unsubscribe();
651
+ await pm.flush();
652
+ unsubscribe = repo.liveQuery().subscribe(({ applyChanges: reducer }) => result1 = reducer(result1));
653
+ await pm.flush();
654
+ unsubscribe();
655
+ await pm.flush();
656
+ expect(unsubscribeCount()).toBe(1);
657
+ expect(remult.liveQueryStorage.removeCountForTesting).toBe(1);
658
+ });
659
+ it("test disconnect and reconnect scenario", async () => {
660
+ var { repo, pm, clientStatus } = setup2();
661
+ let result1 = [];
662
+ const u = repo.liveQuery().subscribe(reducer => result1 = reducer.applyChanges(result1));
663
+ await pm.flush();
664
+ await repo.insert({ id: 1, title: "noam" });
665
+ await pm.flush();
666
+ expect(result1.length).toBe(1);
667
+ clientStatus.connected = false;
668
+ await repo.insert({ id: 2, title: "yael" });
669
+ await pm.flush();
670
+ expect(result1.length).toBe(1);
671
+ clientStatus.reconnect();
672
+ expect(clientStatus.connected).toBe(true);
673
+ await pm.flush();
674
+ expect(result1.length).toBe(2);
675
+ u();
676
+ });
677
+ it("expect pure json object, from live query", async () => {
678
+ var { testApi, repo } = setup2();
679
+ await repo.insert({ title: 'a' });
680
+ const r = await testApi().get('/api/tasks?__action=liveQuery|123');
681
+ expect(getEntityRef(r[0], false)).toBe(undefined);
682
+ });
683
+ it("test 2 subscriptions work", async () => {
684
+ var { repo, pm } = setup2();
685
+ await repo.insert({ title: 'a' });
686
+ await repo.insert({ title: 'b' });
687
+ let arr1 = [];
688
+ let arr2 = [];
689
+ const u1 = repo.liveQuery().subscribe(y => arr1 = y.applyChanges(arr1));
690
+ await pm.flush();
691
+ const u2 = repo.liveQuery().subscribe(y => {
692
+ arr2 = y.applyChanges(arr2);
693
+ expect(y.items.length).toBe(2);
694
+ });
695
+ await pm.flush();
696
+ expect(arr1.length).toBe(arr2.length);
697
+ u1();
698
+ u2();
699
+ });
700
+ it("test subscription leak", async () => {
701
+ var { repo, pm } = setup2();
702
+ await repo.insert({ title: 'a1', id: 1 });
703
+ await repo.insert({ title: 'a2', id: 2 });
704
+ await repo.insert({ title: 'b1', id: 3 });
705
+ await repo.insert({ title: 'b2', id: 4 });
706
+ let arr1 = [];
707
+ let arr2 = [];
708
+ let arr1Items = [];
709
+ let arr1Messages = [];
710
+ let arr2Messages = [];
711
+ const u1 = repo.liveQuery({ where: { title: { $contains: "a" } } }).subscribe(y => {
712
+ arr1 = y.applyChanges(arr1);
713
+ arr1Items.push([...y.items]);
714
+ arr1Messages.push(y.changes);
715
+ });
716
+ await pm.flush();
717
+ let done = false;
718
+ const u2 = repo.liveQuery({ where: { title: { $contains: "b" } } }).subscribe({
719
+ next: y => {
720
+ arr2 = y.applyChanges(arr2);
721
+ arr2Messages.push(y.changes);
722
+ },
723
+ complete: () => done = true
724
+ });
725
+ await pm.flush();
726
+ await repo.insert({ title: 'a3', id: 5 });
727
+ await pm.flush();
728
+ expect(arr1.length).toBe(3);
729
+ expect(arr2.length).toBe(2);
730
+ expect(arr1Items.length).toBe(2);
731
+ expect(arr1Messages.length).toBe(2);
732
+ expect(arr2Messages.length).toBe(1);
733
+ expect(arr1Items[0].length).toBe(2);
734
+ expect(arr1Items[1].length).toBe(3);
735
+ expect(arr1Messages[0].length).toBe(1);
736
+ expect(arr1Messages[1][0].type).toBe("add");
737
+ u1();
738
+ expect(done).toBe(false);
739
+ u2();
740
+ await pm.flush();
741
+ ;
742
+ expect(done).toBe(true);
743
+ });
744
+ it("error on channel open", async () => {
745
+ let { remult } = await setup2();
746
+ remult.apiClient.subscriptionClient = {
747
+ openConnection: async () => {
748
+ return {
749
+ subscribe(channel, onMessage) {
750
+ throw "the error";
751
+ },
752
+ close() {
753
+ }
754
+ };
755
+ }
756
+ };
757
+ remult.liveQuerySubscriber = new LiveQueryClient(() => remult.apiClient, () => remult.user?.id);
758
+ let pm = new PromiseResolver(remult.liveQuerySubscriber);
759
+ let error = false;
760
+ let u = remult.repo(eventTestEntity).liveQuery().subscribe({
761
+ error: er => {
762
+ error = true;
763
+ }
764
+ });
765
+ await pm.flush();
766
+ expect(error).toBe(true);
767
+ u();
768
+ });
769
+ it("error on channel open", async () => {
770
+ let { remult } = await setup2();
771
+ remult.apiClient.subscriptionClient = {
772
+ openConnection: async () => {
773
+ return {
774
+ async subscribe(channel, onMessage, onError) {
775
+ onError("had error");
776
+ return () => { };
777
+ },
778
+ close() {
779
+ }
780
+ };
781
+ }
782
+ };
783
+ remult.liveQuerySubscriber = new LiveQueryClient(() => remult.apiClient, () => remult.user?.id);
784
+ let pm = new PromiseResolver(remult.liveQuerySubscriber);
785
+ let error = false;
786
+ let u = remult.repo(eventTestEntity).liveQuery().subscribe({
787
+ error: er => {
788
+ error = true;
789
+ }
790
+ });
791
+ await pm.flush();
792
+ expect(error).toBe(true);
793
+ u();
794
+ });
795
+ });
796
+ it("Serialize Find Options", async () => {
797
+ const r = new Remult().repo(eventTestEntity);
798
+ const findOptions = {
799
+ limit: 3,
800
+ page: 2,
801
+ where: {
802
+ $and: [{
803
+ title: 'noam'
804
+ }]
805
+ },
806
+ orderBy: {
807
+ title: "desc"
808
+ }
809
+ };
810
+ const z = findOptionsToJson(findOptions, r.metadata);
811
+ const res = findOptionsFromJson(z, r.metadata);
812
+ expect(res).toEqual(findOptions);
813
+ });
814
+ it("Serialize Find Options1", async () => {
815
+ const r = new Remult().repo(eventTestEntity);
816
+ const findOptions = {
817
+ where: {
818
+ $and: [{
819
+ title: 'noam'
820
+ }]
821
+ },
822
+ orderBy: {
823
+ title: "desc"
824
+ },
825
+ };
826
+ const z = findOptionsToJson(findOptions, r.metadata);
827
+ const res = findOptionsFromJson(JSON.parse(JSON.stringify(z)), r.metadata);
828
+ expect(res).toEqual(findOptions);
829
+ });
830
+ it("Serialize Find Options2", async () => {
831
+ const r = new Remult().repo(eventTestEntity);
832
+ const findOptions = {
833
+ where: {
834
+ $and: [{
835
+ title: 'noam'
836
+ }]
837
+ },
838
+ orderBy: {
839
+ title: "desc"
840
+ },
841
+ load: x => [x.title, x.birthDate]
842
+ };
843
+ const z = findOptionsToJson(findOptions, r.metadata);
844
+ const res = findOptionsFromJson(JSON.parse(JSON.stringify(z)), r.metadata);
845
+ expect(res.load(r.fields).map(f => f.key)).toEqual(["title", "birthDate"]);
846
+ });
847
+ it("test channel subscribe", async () => {
848
+ const mc = new SubscriptionChannel("zxcvz");
849
+ let sub = 0;
850
+ let close = 0;
851
+ remult.apiClient.subscriptionClient = {
852
+ openConnection: async () => {
853
+ return {
854
+ subscribe: async (what) => {
855
+ sub++;
856
+ return () => {
857
+ sub--;
858
+ };
859
+ },
860
+ close() {
861
+ close++;
862
+ },
863
+ };
864
+ }
865
+ };
866
+ let pr = new PromiseResolver(remult.liveQuerySubscriber);
867
+ let r = await mc.subscribe(() => { });
868
+ let r2 = await mc.subscribe(() => { });
869
+ await pr.flush();
870
+ expect(sub).toBe(1);
871
+ r();
872
+ await pr.flush();
873
+ expect(sub).toBe(1);
874
+ r2();
875
+ await pr.flush();
876
+ expect(sub).toBe(0);
877
+ r();
878
+ r2();
879
+ await pr.flush();
880
+ expect(sub).toBe(0);
881
+ expect(close).toBe(1);
882
+ });
883
+ describe("test failure", () => {
884
+ it("error on subscribe query", async () => {
885
+ let r = new Remult(new InMemoryDataProvider());
886
+ r.apiClient.subscriptionClient = {
887
+ openConnection: async () => {
888
+ return {
889
+ subscribe(channel, onMessage) {
890
+ throw "the error";
891
+ },
892
+ close() {
893
+ }
894
+ };
895
+ }
896
+ };
897
+ let pm = new PromiseResolver(r.liveQuerySubscriber);
898
+ let error = false;
899
+ let u = r.repo(eventTestEntity).liveQuery().subscribe({ error: er => { error = true; } });
900
+ await pm.flush();
901
+ expect(error).toBe(true);
902
+ u();
903
+ });
904
+ it("error on subscribe", async () => {
905
+ let r = new Remult(new InMemoryDataProvider());
906
+ r.liveQueryStorage = new InMemoryLiveQueryStorage();
907
+ await r.repo(eventTestEntity).insert({ id: 1, title: "a" });
908
+ expect(await r.repo(eventTestEntity).count()).toBe(1);
909
+ let items;
910
+ let error = false;
911
+ var cr = new Remult(createMockHttpDataProvider(new DataApi(r.repo(eventTestEntity), r)));
912
+ cr.apiClient.subscriptionClient = {
913
+ openConnection: async () => {
914
+ return {
915
+ subscribe(channel, onMessage) {
916
+ throw "the error";
917
+ },
918
+ close() {
919
+ }
920
+ };
921
+ }
922
+ };
923
+ let pm = new PromiseResolver(cr.liveQuerySubscriber);
924
+ expect(await cr.repo(eventTestEntity).count()).toBe(1);
925
+ let u = cr.repo(eventTestEntity).liveQuery().subscribe({ error: er => { error = true; }, next: x => items = x.items });
926
+ await pm.flush();
927
+ expect(error).toBe(true);
928
+ expect(items).toBeUndefined();
929
+ u();
930
+ });
931
+ it("Error on open connection", async () => {
932
+ let r = new Remult(new InMemoryDataProvider());
933
+ r.liveQueryStorage = new InMemoryLiveQueryStorage();
934
+ await r.repo(eventTestEntity).insert({ id: 1, title: "a" });
935
+ expect(await r.repo(eventTestEntity).count()).toBe(1);
936
+ let items;
937
+ let error = false;
938
+ var cr = new Remult(createMockHttpDataProvider(new DataApi(r.repo(eventTestEntity), r)));
939
+ cr.apiClient.subscriptionClient = {
940
+ openConnection: async () => {
941
+ throw "open connection error";
942
+ }
943
+ };
944
+ let pm = new PromiseResolver(cr.liveQuerySubscriber);
945
+ expect(await cr.repo(eventTestEntity).count()).toBe(1);
946
+ let u = cr.repo(eventTestEntity).liveQuery().subscribe({ error: er => { error = true; }, next: x => items = x.items });
947
+ await pm.flush();
948
+ expect(error).toBe(true);
949
+ expect(items).toBeUndefined();
950
+ u();
951
+ });
952
+ });