breeze-client 2.2.1 → 3.0.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 (299) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +83 -63
  3. package/adapters/abstract-data-service-adapter.d.ts +120 -0
  4. package/adapters/abstract-data-service-adapter.js +395 -0
  5. package/adapters/abstract-data-service-adapter.js.map +1 -0
  6. package/adapters/adapter-ajax-fetch.d.ts +12 -0
  7. package/adapters/adapter-ajax-fetch.js +13 -0
  8. package/adapters/adapter-ajax-fetch.js.map +1 -0
  9. package/{adapter-ajax-post → adapters}/adapter-ajax-post.d.ts +40 -36
  10. package/{fesm2022/breeze-client-adapter-ajax-post.mjs → adapters/adapter-ajax-post.js} +80 -82
  11. package/adapters/adapter-ajax-post.js.map +1 -0
  12. package/{adapter-ajax-fetch → adapters}/adapter-core.d.ts +4 -4
  13. package/{fesm2022/breeze-client-adapter-uri-builder-json.mjs → adapters/adapter-core.js} +48 -91
  14. package/adapters/adapter-core.js.map +1 -0
  15. package/adapters/adapter-data-service-webapi.d.ts +9 -0
  16. package/{fesm2022/breeze-client-adapter-data-service-webapi.mjs → adapters/adapter-data-service-webapi.js} +105 -107
  17. package/adapters/adapter-data-service-webapi.js.map +1 -0
  18. package/adapters/adapter-model-library-backing-store.d.ts +32 -0
  19. package/adapters/adapter-model-library-backing-store.js +321 -0
  20. package/adapters/adapter-model-library-backing-store.js.map +1 -0
  21. package/adapters/adapter-uri-builder-json.d.ts +11 -0
  22. package/adapters/adapter-uri-builder-json.js +40 -0
  23. package/adapters/adapter-uri-builder-json.js.map +1 -0
  24. package/adapters/http.d.ts +52 -0
  25. package/adapters/http.js +202 -0
  26. package/adapters/http.js.map +1 -0
  27. package/angular/adapter-angular-httpclient.d.ts +21 -0
  28. package/angular/adapter-angular-httpclient.js +70 -0
  29. package/angular/adapter-angular-httpclient.js.map +1 -0
  30. package/breeze.d.ts +215 -0
  31. package/breeze.js +141 -0
  32. package/breeze.js.map +1 -0
  33. package/config/config.d.ts +212 -0
  34. package/config/config.js +392 -0
  35. package/config/config.js.map +1 -0
  36. package/config/configure.d.ts +66 -0
  37. package/config/configure.js +46 -0
  38. package/config/configure.js.map +1 -0
  39. package/config/default-adapters.d.ts +1 -0
  40. package/config/default-adapters.js +40 -0
  41. package/config/default-adapters.js.map +1 -0
  42. package/config/interface-registry.d.ts +191 -0
  43. package/config/interface-registry.js +5 -0
  44. package/config/interface-registry.js.map +1 -0
  45. package/{src → core}/assert-param.d.ts +52 -60
  46. package/core/assert-param.js +390 -0
  47. package/core/assert-param.js.map +1 -0
  48. package/core/core.d.ts +285 -0
  49. package/core/core.js +772 -0
  50. package/core/core.js.map +1 -0
  51. package/core/enum.d.ts +116 -0
  52. package/core/enum.js +167 -0
  53. package/core/enum.js.map +1 -0
  54. package/core/event.d.ts +169 -0
  55. package/core/event.js +338 -0
  56. package/core/event.js.map +1 -0
  57. package/entity/array.d.ts +3 -0
  58. package/entity/array.js +4 -0
  59. package/entity/array.js.map +1 -0
  60. package/entity/complex-array.d.ts +17 -0
  61. package/entity/complex-array.js +104 -0
  62. package/entity/complex-array.js.map +1 -0
  63. package/entity/default-property-interceptor.d.ts +1 -0
  64. package/entity/default-property-interceptor.js +496 -0
  65. package/entity/default-property-interceptor.js.map +1 -0
  66. package/{src → entity}/entity-action.d.ts +36 -42
  67. package/entity/entity-action.js +45 -0
  68. package/entity/entity-action.js.map +1 -0
  69. package/entity/entity-aspect.d.ts +457 -0
  70. package/entity/entity-aspect.js +1262 -0
  71. package/entity/entity-aspect.js.map +1 -0
  72. package/entity/entity-base.d.ts +55 -0
  73. package/entity/entity-base.js +41 -0
  74. package/entity/entity-base.js.map +1 -0
  75. package/entity/entity-group.d.ts +1 -0
  76. package/entity/entity-group.js +224 -0
  77. package/entity/entity-group.js.map +1 -0
  78. package/entity/entity-key.d.ts +95 -0
  79. package/entity/entity-key.js +189 -0
  80. package/entity/entity-key.js.map +1 -0
  81. package/{src → entity}/entity-state.d.ts +112 -84
  82. package/entity/entity-state.js +135 -0
  83. package/entity/entity-state.js.map +1 -0
  84. package/entity/key-generator.d.ts +57 -0
  85. package/entity/key-generator.js +155 -0
  86. package/entity/key-generator.js.map +1 -0
  87. package/entity/observable-array.d.ts +25 -0
  88. package/entity/observable-array.js +230 -0
  89. package/entity/observable-array.js.map +1 -0
  90. package/entity/primitive-array.d.ts +12 -0
  91. package/entity/primitive-array.js +71 -0
  92. package/entity/primitive-array.js.map +1 -0
  93. package/entity/relation-array.d.ts +24 -0
  94. package/entity/relation-array.js +176 -0
  95. package/entity/relation-array.js.map +1 -0
  96. package/entity/unattached-children-map.d.ts +1 -0
  97. package/entity/unattached-children-map.js +105 -0
  98. package/entity/unattached-children-map.js.map +1 -0
  99. package/generate-entity-classes.js +1176 -0
  100. package/manager/entity-manager.d.ts +801 -0
  101. package/manager/entity-manager.js +2395 -0
  102. package/manager/entity-manager.js.map +1 -0
  103. package/{src → manager}/save-options.d.ts +48 -42
  104. package/manager/save-options.js +51 -0
  105. package/manager/save-options.js.map +1 -0
  106. package/{src → metadata}/data-service.d.ts +229 -184
  107. package/metadata/data-service.js +246 -0
  108. package/metadata/data-service.js.map +1 -0
  109. package/metadata/data-type.d.ts +122 -0
  110. package/metadata/data-type.js +465 -0
  111. package/metadata/data-type.js.map +1 -0
  112. package/metadata/entity-metadata.d.ts +1193 -0
  113. package/metadata/entity-metadata.js +2502 -0
  114. package/metadata/entity-metadata.js.map +1 -0
  115. package/{src → metadata}/local-query-comparison-options.d.ts +65 -59
  116. package/metadata/local-query-comparison-options.js +69 -0
  117. package/metadata/local-query-comparison-options.js.map +1 -0
  118. package/{src → metadata}/naming-convention.d.ts +75 -72
  119. package/metadata/naming-convention.js +97 -0
  120. package/metadata/naming-convention.js.map +1 -0
  121. package/mixins/mixin-get-entity-graph.d.ts +63 -0
  122. package/{fesm2022/breeze-client-mixin-get-entity-graph.mjs → mixins/mixin-get-entity-graph.js} +331 -253
  123. package/mixins/mixin-get-entity-graph.js.map +1 -0
  124. package/mixins/mixin-save-queuing.d.ts +98 -0
  125. package/{fesm2022/breeze-client-mixin-save-queuing.mjs → mixins/mixin-save-queuing.js} +493 -365
  126. package/mixins/mixin-save-queuing.js.map +1 -0
  127. package/package.json +62 -93
  128. package/query/entity-query.d.ts +521 -0
  129. package/query/entity-query.js +1149 -0
  130. package/query/entity-query.js.map +1 -0
  131. package/{src → query}/mapping-context.d.ts +44 -46
  132. package/query/mapping-context.js +412 -0
  133. package/query/mapping-context.js.map +1 -0
  134. package/query/predicate.d.ts +394 -0
  135. package/query/predicate.js +1294 -0
  136. package/query/predicate.js.map +1 -0
  137. package/query/property-path.d.ts +252 -0
  138. package/query/property-path.js +2 -0
  139. package/query/property-path.js.map +1 -0
  140. package/{src → query}/query-options.d.ts +143 -119
  141. package/query/query-options.js +180 -0
  142. package/query/query-options.js.map +1 -0
  143. package/rxjs/breeze-rxjs.d.ts +72 -0
  144. package/rxjs/breeze-rxjs.js +117 -0
  145. package/rxjs/breeze-rxjs.js.map +1 -0
  146. package/validation/validate.d.ts +583 -0
  147. package/validation/validate.js +961 -0
  148. package/validation/validate.js.map +1 -0
  149. package/{src → validation}/validation-options.d.ts +67 -63
  150. package/validation/validation-options.js +70 -0
  151. package/validation/validation-options.js.map +1 -0
  152. package/adapter-ajax-angularjs/adapter-ajax-angularjs.d.ts +0 -17
  153. package/adapter-ajax-angularjs/adapter-core.d.ts +0 -4
  154. package/adapter-ajax-angularjs/index.d.ts +0 -5
  155. package/adapter-ajax-fetch/adapter-ajax-fetch.d.ts +0 -18
  156. package/adapter-ajax-fetch/index.d.ts +0 -5
  157. package/adapter-ajax-httpclient/adapter-ajax-httpclient.d.ts +0 -13
  158. package/adapter-ajax-httpclient/adapter-core.d.ts +0 -4
  159. package/adapter-ajax-httpclient/index.d.ts +0 -5
  160. package/adapter-ajax-jquery/adapter-ajax-jquery.d.ts +0 -15
  161. package/adapter-ajax-jquery/index.d.ts +0 -5
  162. package/adapter-ajax-post/index.d.ts +0 -5
  163. package/adapter-data-service-odata/adapter-core.d.ts +0 -4
  164. package/adapter-data-service-odata/adapter-data-service-odata.d.ts +0 -17
  165. package/adapter-data-service-odata/index.d.ts +0 -5
  166. package/adapter-data-service-webapi/adapter-data-service-webapi.d.ts +0 -15
  167. package/adapter-data-service-webapi/index.d.ts +0 -5
  168. package/adapter-model-library-backing-store/adapter-model-library-backing-store.d.ts +0 -10
  169. package/adapter-model-library-backing-store/index.d.ts +0 -5
  170. package/adapter-model-library-ko/adapter-model-library-ko.d.ts +0 -10
  171. package/adapter-model-library-ko/index.d.ts +0 -5
  172. package/adapter-uri-builder-json/adapter-core.d.ts +0 -4
  173. package/adapter-uri-builder-json/adapter-uri-builder-json.d.ts +0 -8
  174. package/adapter-uri-builder-json/index.d.ts +0 -5
  175. package/adapter-uri-builder-odata/adapter-core.d.ts +0 -4
  176. package/adapter-uri-builder-odata/adapter-uri-builder-odata.d.ts +0 -8
  177. package/adapter-uri-builder-odata/index.d.ts +0 -5
  178. package/esm2022/adapter-ajax-angularjs/adapter-ajax-angularjs.mjs +0 -135
  179. package/esm2022/adapter-ajax-angularjs/adapter-core.mjs +0 -49
  180. package/esm2022/adapter-ajax-angularjs/breeze-client-adapter-ajax-angularjs.mjs +0 -5
  181. package/esm2022/adapter-ajax-fetch/adapter-ajax-fetch.mjs +0 -135
  182. package/esm2022/adapter-ajax-fetch/adapter-core.mjs +0 -49
  183. package/esm2022/adapter-ajax-fetch/breeze-client-adapter-ajax-fetch.mjs +0 -5
  184. package/esm2022/adapter-ajax-httpclient/adapter-ajax-httpclient.mjs +0 -139
  185. package/esm2022/adapter-ajax-httpclient/adapter-core.mjs +0 -49
  186. package/esm2022/adapter-ajax-httpclient/breeze-client-adapter-ajax-httpclient.mjs +0 -5
  187. package/esm2022/adapter-ajax-jquery/adapter-ajax-jquery.mjs +0 -107
  188. package/esm2022/adapter-ajax-jquery/breeze-client-adapter-ajax-jquery.mjs +0 -5
  189. package/esm2022/adapter-ajax-post/adapter-ajax-post.mjs +0 -77
  190. package/esm2022/adapter-ajax-post/breeze-client-adapter-ajax-post.mjs +0 -5
  191. package/esm2022/adapter-data-service-odata/adapter-core.mjs +0 -49
  192. package/esm2022/adapter-data-service-odata/adapter-data-service-odata.mjs +0 -461
  193. package/esm2022/adapter-data-service-odata/breeze-client-adapter-data-service-odata.mjs +0 -5
  194. package/esm2022/adapter-data-service-webapi/adapter-data-service-webapi.mjs +0 -100
  195. package/esm2022/adapter-data-service-webapi/breeze-client-adapter-data-service-webapi.mjs +0 -5
  196. package/esm2022/adapter-model-library-backing-store/adapter-model-library-backing-store.mjs +0 -269
  197. package/esm2022/adapter-model-library-backing-store/breeze-client-adapter-model-library-backing-store.mjs +0 -5
  198. package/esm2022/adapter-model-library-ko/adapter-model-library-ko.mjs +0 -241
  199. package/esm2022/adapter-model-library-ko/breeze-client-adapter-model-library-ko.mjs +0 -5
  200. package/esm2022/adapter-uri-builder-json/adapter-core.mjs +0 -49
  201. package/esm2022/adapter-uri-builder-json/adapter-uri-builder-json.mjs +0 -37
  202. package/esm2022/adapter-uri-builder-json/breeze-client-adapter-uri-builder-json.mjs +0 -5
  203. package/esm2022/adapter-uri-builder-odata/adapter-core.mjs +0 -49
  204. package/esm2022/adapter-uri-builder-odata/adapter-uri-builder-odata.mjs +0 -191
  205. package/esm2022/adapter-uri-builder-odata/breeze-client-adapter-uri-builder-odata.mjs +0 -5
  206. package/esm2022/breeze-client.mjs +0 -5
  207. package/esm2022/index.mjs +0 -2
  208. package/esm2022/mixin-get-entity-graph/breeze-client-mixin-get-entity-graph.mjs +0 -5
  209. package/esm2022/mixin-get-entity-graph/mixin-get-entity-graph.mjs +0 -269
  210. package/esm2022/mixin-save-queuing/breeze-client-mixin-save-queuing.mjs +0 -5
  211. package/esm2022/mixin-save-queuing/mixin-save-queuing.mjs +0 -421
  212. package/esm2022/src/abstract-data-service-adapter.mjs +0 -325
  213. package/esm2022/src/array.mjs +0 -4
  214. package/esm2022/src/assert-param.mjs +0 -330
  215. package/esm2022/src/breeze.mjs +0 -85
  216. package/esm2022/src/complex-array.mjs +0 -117
  217. package/esm2022/src/config.mjs +0 -232
  218. package/esm2022/src/core.mjs +0 -712
  219. package/esm2022/src/csdl-metadata-parser.mjs +0 -385
  220. package/esm2022/src/data-service.mjs +0 -221
  221. package/esm2022/src/data-type.mjs +0 -510
  222. package/esm2022/src/default-property-interceptor.mjs +0 -460
  223. package/esm2022/src/entity-action.mjs +0 -45
  224. package/esm2022/src/entity-aspect.mjs +0 -897
  225. package/esm2022/src/entity-group.mjs +0 -192
  226. package/esm2022/src/entity-key.mjs +0 -125
  227. package/esm2022/src/entity-manager.mjs +0 -2163
  228. package/esm2022/src/entity-metadata.mjs +0 -2242
  229. package/esm2022/src/entity-query.mjs +0 -1024
  230. package/esm2022/src/entity-state.mjs +0 -107
  231. package/esm2022/src/enum.mjs +0 -143
  232. package/esm2022/src/event.mjs +0 -264
  233. package/esm2022/src/interface-registry.mjs +0 -39
  234. package/esm2022/src/key-generator.mjs +0 -110
  235. package/esm2022/src/local-query-comparison-options.mjs +0 -65
  236. package/esm2022/src/mapping-context.mjs +0 -411
  237. package/esm2022/src/naming-convention.mjs +0 -92
  238. package/esm2022/src/observable-array.mjs +0 -183
  239. package/esm2022/src/predicate.mjs +0 -1259
  240. package/esm2022/src/primitive-array.mjs +0 -85
  241. package/esm2022/src/query-options.mjs +0 -152
  242. package/esm2022/src/relation-array.mjs +0 -173
  243. package/esm2022/src/save-options.mjs +0 -41
  244. package/esm2022/src/unattached-children-map.mjs +0 -56
  245. package/esm2022/src/validate.mjs +0 -995
  246. package/esm2022/src/validation-options.mjs +0 -64
  247. package/fesm2022/breeze-client-adapter-ajax-angularjs.mjs +0 -190
  248. package/fesm2022/breeze-client-adapter-ajax-angularjs.mjs.map +0 -1
  249. package/fesm2022/breeze-client-adapter-ajax-fetch.mjs +0 -190
  250. package/fesm2022/breeze-client-adapter-ajax-fetch.mjs.map +0 -1
  251. package/fesm2022/breeze-client-adapter-ajax-httpclient.mjs +0 -194
  252. package/fesm2022/breeze-client-adapter-ajax-httpclient.mjs.map +0 -1
  253. package/fesm2022/breeze-client-adapter-ajax-jquery.mjs +0 -114
  254. package/fesm2022/breeze-client-adapter-ajax-jquery.mjs.map +0 -1
  255. package/fesm2022/breeze-client-adapter-ajax-post.mjs.map +0 -1
  256. package/fesm2022/breeze-client-adapter-data-service-odata.mjs +0 -516
  257. package/fesm2022/breeze-client-adapter-data-service-odata.mjs.map +0 -1
  258. package/fesm2022/breeze-client-adapter-data-service-webapi.mjs.map +0 -1
  259. package/fesm2022/breeze-client-adapter-model-library-backing-store.mjs +0 -276
  260. package/fesm2022/breeze-client-adapter-model-library-backing-store.mjs.map +0 -1
  261. package/fesm2022/breeze-client-adapter-model-library-ko.mjs +0 -248
  262. package/fesm2022/breeze-client-adapter-model-library-ko.mjs.map +0 -1
  263. package/fesm2022/breeze-client-adapter-uri-builder-json.mjs.map +0 -1
  264. package/fesm2022/breeze-client-adapter-uri-builder-odata.mjs +0 -246
  265. package/fesm2022/breeze-client-adapter-uri-builder-odata.mjs.map +0 -1
  266. package/fesm2022/breeze-client-mixin-get-entity-graph.mjs.map +0 -1
  267. package/fesm2022/breeze-client-mixin-save-queuing.mjs.map +0 -1
  268. package/fesm2022/breeze-client.mjs +0 -14144
  269. package/fesm2022/breeze-client.mjs.map +0 -1
  270. package/index.d.ts +0 -1
  271. package/mixin-get-entity-graph/index.d.ts +0 -5
  272. package/mixin-get-entity-graph/mixin-get-entity-graph.d.ts +0 -31
  273. package/mixin-save-queuing/index.d.ts +0 -5
  274. package/mixin-save-queuing/mixin-save-queuing.d.ts +0 -32
  275. package/src/abstract-data-service-adapter.d.ts +0 -84
  276. package/src/array.d.ts +0 -3
  277. package/src/breeze.d.ts +0 -139
  278. package/src/complex-array.d.ts +0 -13
  279. package/src/config.d.ts +0 -104
  280. package/src/core.d.ts +0 -164
  281. package/src/csdl-metadata-parser.d.ts +0 -7
  282. package/src/data-type.d.ts +0 -89
  283. package/src/default-property-interceptor.d.ts +0 -4
  284. package/src/entity-aspect.d.ts +0 -332
  285. package/src/entity-group.d.ts +0 -28
  286. package/src/entity-key.d.ts +0 -77
  287. package/src/entity-manager.d.ts +0 -680
  288. package/src/entity-metadata.d.ts +0 -988
  289. package/src/entity-query.d.ts +0 -444
  290. package/src/enum.d.ts +0 -100
  291. package/src/event.d.ts +0 -142
  292. package/src/interface-registry.d.ts +0 -150
  293. package/src/key-generator.d.ts +0 -12
  294. package/src/observable-array.d.ts +0 -52
  295. package/src/predicate.d.ts +0 -376
  296. package/src/primitive-array.d.ts +0 -7
  297. package/src/relation-array.d.ts +0 -18
  298. package/src/unattached-children-map.d.ts +0 -19
  299. package/src/validate.d.ts +0 -650
@@ -0,0 +1,57 @@
1
+ import { EntityType } from '../metadata/entity-metadata.js';
2
+ import { EntityKey } from './entity-key.js';
3
+ /** Generates temporary key values for new entities - one added with an unset key when its type's
4
+ `autoGeneratedKeyType` is not `None`, or one passed to {@link EntityManager.generateTempKeyValue} -
5
+ and keeps a record of the temporary values the manager's entities hold, so that an import cannot
6
+ give a second entity one of them. Each {@link EntityManager} has its own, as
7
+ {@link EntityManager.keyGenerator}, and replaces it when cleared. To supply your own, pass a
8
+ subclass's constructor as `keyGeneratorCtor` in the {@link EntityManagerConfig}, and have its
9
+ `generateTempKeyValue` pass the value it makes to `super.generateTempKeyValue` as `valueIfAvail`,
10
+ so that the value is recorded; Breeze calls only {@link KeyGenerator.generateTempKeyValue}. */
11
+ export declare class KeyGenerator {
12
+ /** Creates a generator that has handed out no values. An {@link EntityManager} creates its own
13
+ from {@link EntityManagerConfig.keyGeneratorCtor}. */
14
+ constructor();
15
+ /**
16
+ Returns a unique 'temporary' id for the specified {@link EntityType}.
17
+ Uniqueness is defined for this purpose as being unique within each instance of a KeyGenerator. This is sufficient
18
+ because each EntityManager will have its own instance of a KeyGenerator and any entities imported into
19
+ the EntityManager with temporary keys will have them regenerated and remapped on import.
20
+
21
+ The return value of this method must be of the correct type as determined by the keyProperties of the
22
+ specified EntityType
23
+ @example
24
+ // Assume em1 is a preexisting EntityManager, and the server generates Order keys
25
+ const order1 = em1.createEntity(Order);
26
+ // next line calls em1.keyGenerator.generateTempKeyValue(order1.entityType),
27
+ // sets order1's 'orderID' property to the result, and returns it
28
+ const oid1 = em1.generateTempKeyValue(order1);
29
+ const saveResult = await em1.saveChanges();
30
+ const sameOrder1 = saveResult.entities[0];
31
+ // order1 === sameOrder1;
32
+ // but order1.orderID != oid1
33
+ // because the server will have generated a new id
34
+ // and the client will have been updated with this
35
+ // new id.
36
+ @param entityType - The type to generate a key for. Its key must be a single property.
37
+ @param valueIfAvail - A key value to use if no entity in the manager holds it. When entities with
38
+ temporary keys are imported, the manager passes each one's key here, so that the key survives the
39
+ import where it can; a subclass passes the value it made. If the value is taken, or omitted, a new
40
+ one is generated. Either way, the value returned is recorded as held.
41
+ @returns The key value, of the key property's data type.
42
+ */
43
+ generateTempKeyValue(entityType: EntityType, valueIfAvail?: any): any;
44
+ /** Returns an {@link EntityKey} for each temporary key value the manager's entities hold: the
45
+ values this generator handed out or recorded, less those released when an entity was saved and
46
+ given the server's key, or detached.
47
+ @deprecated Ask the entities instead:
48
+ `em.getEntities().filter(e => e.entityAspect.hasTempKey).map(e => e.entityAspect.getKey())`.
49
+ Breeze does not call it. It still works; it is not scheduled for removal. */
50
+ getTempKeys(): EntityKey[];
51
+ /** Whether `entityKey`'s value is a temporary key an entity in the manager holds - one of the
52
+ values {@link KeyGenerator.getTempKeys} returns. Always false for a multipart key.
53
+ @deprecated Ask the entity instead: `em.getEntityByKey(key)?.entityAspect.hasTempKey`, or
54
+ {@link EntityAspect.hasTempKey} when you have the entity. Breeze does not call it. It still
55
+ works; it is not scheduled for removal. */
56
+ isTempKey(entityKey: EntityKey): boolean;
57
+ }
@@ -0,0 +1,155 @@
1
+ import { EntityKey } from './entity-key.js';
2
+ import { config } from '../config/config.js';
3
+ /** Generates temporary key values for new entities - one added with an unset key when its type's
4
+ `autoGeneratedKeyType` is not `None`, or one passed to {@link EntityManager.generateTempKeyValue} -
5
+ and keeps a record of the temporary values the manager's entities hold, so that an import cannot
6
+ give a second entity one of them. Each {@link EntityManager} has its own, as
7
+ {@link EntityManager.keyGenerator}, and replaces it when cleared. To supply your own, pass a
8
+ subclass's constructor as `keyGeneratorCtor` in the {@link EntityManagerConfig}, and have its
9
+ `generateTempKeyValue` pass the value it makes to `super.generateTempKeyValue` as `valueIfAvail`,
10
+ so that the value is recorded; Breeze calls only {@link KeyGenerator.generateTempKeyValue}. */
11
+ /*
12
+ @class KeyGenerator
13
+ */
14
+ export class KeyGenerator {
15
+ /** @hidden @internal */
16
+ _tempIdMap;
17
+ /** Creates a generator that has handed out no values. An {@link EntityManager} creates its own
18
+ from {@link EntityManagerConfig.keyGeneratorCtor}. */
19
+ constructor() {
20
+ // key is dataProperty.name + || + entityType.name, value is propEntry
21
+ // propEntry = { entityType, propertyName, keyMap }
22
+ // keyMap has key of the actual value ( as a string) and a value of null or the real id.
23
+ this._tempIdMap = new Map();
24
+ }
25
+ /**
26
+ Returns a unique 'temporary' id for the specified {@link EntityType}.
27
+ Uniqueness is defined for this purpose as being unique within each instance of a KeyGenerator. This is sufficient
28
+ because each EntityManager will have its own instance of a KeyGenerator and any entities imported into
29
+ the EntityManager with temporary keys will have them regenerated and remapped on import.
30
+
31
+ The return value of this method must be of the correct type as determined by the keyProperties of the
32
+ specified EntityType
33
+ @example
34
+ // Assume em1 is a preexisting EntityManager, and the server generates Order keys
35
+ const order1 = em1.createEntity(Order);
36
+ // next line calls em1.keyGenerator.generateTempKeyValue(order1.entityType),
37
+ // sets order1's 'orderID' property to the result, and returns it
38
+ const oid1 = em1.generateTempKeyValue(order1);
39
+ const saveResult = await em1.saveChanges();
40
+ const sameOrder1 = saveResult.entities[0];
41
+ // order1 === sameOrder1;
42
+ // but order1.orderID != oid1
43
+ // because the server will have generated a new id
44
+ // and the client will have been updated with this
45
+ // new id.
46
+ @param entityType - The type to generate a key for. Its key must be a single property.
47
+ @param valueIfAvail - A key value to use if no entity in the manager holds it. When entities with
48
+ temporary keys are imported, the manager passes each one's key here, so that the key survives the
49
+ import where it can; a subclass passes the value it made. If the value is taken, or omitted, a new
50
+ one is generated. Either way, the value returned is recorded as held.
51
+ @returns The key value, of the key property's data type.
52
+ */
53
+ generateTempKeyValue(entityType, valueIfAvail) {
54
+ let keyProps = entityType.keyProperties;
55
+ if (keyProps.length > 1) {
56
+ throw new Error("Ids can not be autogenerated for entities with multipart keys");
57
+ }
58
+ let keyProp = keyProps[0];
59
+ let propEntry = this._getPropEntry(keyProp, true);
60
+ let nextId;
61
+ if (valueIfAvail != null) {
62
+ if (!propEntry.keyMap.has(valueIfAvail.toString())) {
63
+ nextId = valueIfAvail;
64
+ }
65
+ }
66
+ if (nextId === undefined) {
67
+ let dataType = keyProp.dataType;
68
+ let getNextFn = dataType.getNext;
69
+ if (getNextFn) {
70
+ nextId = getNextFn(this);
71
+ // need to watch out for collision with previously imported ids that might also get generated.
72
+ while (propEntry.keyMap.has(nextId.toString())) {
73
+ nextId = getNextFn(this);
74
+ }
75
+ }
76
+ else {
77
+ throw new Error("Cannot use a property with a dataType of: " + dataType.toString() + " for id generation");
78
+ }
79
+ }
80
+ propEntry.keyMap.add(nextId.toString());
81
+ return nextId;
82
+ }
83
+ /** Returns an {@link EntityKey} for each temporary key value the manager's entities hold: the
84
+ values this generator handed out or recorded, less those released when an entity was saved and
85
+ given the server's key, or detached.
86
+ @deprecated Ask the entities instead:
87
+ `em.getEntities().filter(e => e.entityAspect.hasTempKey).map(e => e.entityAspect.getKey())`.
88
+ Breeze does not call it. It still works; it is not scheduled for removal. */
89
+ getTempKeys() {
90
+ let results = [];
91
+ //noinspection JSHint
92
+ this._tempIdMap.forEach(propEntry => {
93
+ const entityType = propEntry.entityType;
94
+ propEntry.keyMap.forEach(keyValue => {
95
+ results.push(new EntityKey(entityType, [keyValue]));
96
+ });
97
+ });
98
+ return results;
99
+ }
100
+ // proto methods below are not part of the KeyGenerator interface.
101
+ /** Whether `entityKey`'s value is a temporary key an entity in the manager holds - one of the
102
+ values {@link KeyGenerator.getTempKeys} returns. Always false for a multipart key.
103
+ @deprecated Ask the entity instead: `em.getEntityByKey(key)?.entityAspect.hasTempKey`, or
104
+ {@link EntityAspect.hasTempKey} when you have the entity. Breeze does not call it. It still
105
+ works; it is not scheduled for removal. */
106
+ isTempKey(entityKey) {
107
+ let keyProps = entityKey.entityType.keyProperties;
108
+ if (keyProps.length > 1)
109
+ return false;
110
+ let keyProp = keyProps[0];
111
+ let propEntry = this._getPropEntry(keyProp);
112
+ if (!propEntry) {
113
+ return false;
114
+ }
115
+ return propEntry.keyMap.has(entityKey.values[0].toString());
116
+ }
117
+ /**
118
+ Forgets a temporary key value that no entity holds any longer: the manager calls it when an
119
+ entity with a temporary key is saved, and the server's key replaces it, or is detached. The value
120
+ is then free for an import to keep. Without this the generator remembered every value it had
121
+ ever handed out, for the life of the manager.
122
+ @hidden @internal
123
+ */
124
+ _releaseTempKeyValue(entityType, value) {
125
+ const keyProps = entityType.keyProperties;
126
+ if (keyProps.length !== 1 || value == null)
127
+ return;
128
+ this._getPropEntry(keyProps[0])?.keyMap.delete(value.toString());
129
+ }
130
+ /**
131
+ Records a temporary key value this generator did not hand out, or has forgotten: the manager
132
+ calls it when an entity that already has a temporary key is attached - one detached earlier, or
133
+ one from another manager - so that an import cannot give a second entity the same key.
134
+ @hidden @internal
135
+ */
136
+ _reserveTempKeyValue(entityType, value) {
137
+ const keyProps = entityType.keyProperties;
138
+ if (keyProps.length !== 1 || value == null)
139
+ return;
140
+ this._getPropEntry(keyProps[0], true).keyMap.add(value.toString());
141
+ }
142
+ _getPropEntry(keyProp, createIfMissing = false) {
143
+ let key = keyProp.name + ".." + keyProp.parentType.name;
144
+ let propEntry = this._tempIdMap.get(key);
145
+ if (!propEntry) {
146
+ if (createIfMissing) {
147
+ propEntry = { entityType: keyProp.parentType, propertyName: keyProp.name, keyMap: new Set() };
148
+ this._tempIdMap.set(key, propEntry);
149
+ }
150
+ }
151
+ return propEntry;
152
+ }
153
+ }
154
+ config.registerType(KeyGenerator, "KeyGenerator");
155
+ //# sourceMappingURL=key-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"key-generator.js","sourceRoot":"","sources":["../../src/entity/key-generator.ts"],"names":[],"mappings":"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","sourcesContent":["import { EntityType, DataProperty } from '../metadata/entity-metadata.js';\r\nimport { EntityKey } from './entity-key.js';\r\nimport { config } from '../config/config.js';\r\n\r\ninterface IPropEntry {\r\n entityType: EntityType;\r\n propertyName: string;\r\n /** Keys are generated id values as strings. A Set: it records which ids are taken. */\r\n keyMap: Set<string>;\r\n}\r\n\r\ntype ITempIdMap = Map<string, IPropEntry>;\r\n\r\n/** Generates temporary key values for new entities - one added with an unset key when its type's\r\n`autoGeneratedKeyType` is not `None`, or one passed to {@link EntityManager.generateTempKeyValue} -\r\nand keeps a record of the temporary values the manager's entities hold, so that an import cannot\r\ngive a second entity one of them. Each {@link EntityManager} has its own, as\r\n{@link EntityManager.keyGenerator}, and replaces it when cleared. To supply your own, pass a\r\nsubclass's constructor as `keyGeneratorCtor` in the {@link EntityManagerConfig}, and have its\r\n`generateTempKeyValue` pass the value it makes to `super.generateTempKeyValue` as `valueIfAvail`,\r\nso that the value is recorded; Breeze calls only {@link KeyGenerator.generateTempKeyValue}. */\r\n/*\r\n @class KeyGenerator\r\n */\r\nexport class KeyGenerator {\r\n /** @hidden @internal */\r\n private _tempIdMap: ITempIdMap;\r\n\r\n\r\n /** Creates a generator that has handed out no values. An {@link EntityManager} creates its own\r\n from {@link EntityManagerConfig.keyGeneratorCtor}. */\r\n constructor() {\r\n // key is dataProperty.name + || + entityType.name, value is propEntry\r\n // propEntry = { entityType, propertyName, keyMap }\r\n // keyMap has key of the actual value ( as a string) and a value of null or the real id.\r\n this._tempIdMap = new Map();\r\n }\r\n\r\n\r\n /**\r\n Returns a unique 'temporary' id for the specified {@link EntityType}.\r\n Uniqueness is defined for this purpose as being unique within each instance of a KeyGenerator. This is sufficient\r\n because each EntityManager will have its own instance of a KeyGenerator and any entities imported into\r\n the EntityManager with temporary keys will have them regenerated and remapped on import.\r\n\r\n The return value of this method must be of the correct type as determined by the keyProperties of the\r\n specified EntityType\r\n @example\r\n // Assume em1 is a preexisting EntityManager, and the server generates Order keys\r\n const order1 = em1.createEntity(Order);\r\n // next line calls em1.keyGenerator.generateTempKeyValue(order1.entityType),\r\n // sets order1's 'orderID' property to the result, and returns it\r\n const oid1 = em1.generateTempKeyValue(order1);\r\n const saveResult = await em1.saveChanges();\r\n const sameOrder1 = saveResult.entities[0];\r\n // order1 === sameOrder1;\r\n // but order1.orderID != oid1\r\n // because the server will have generated a new id\r\n // and the client will have been updated with this\r\n // new id.\r\n @param entityType - The type to generate a key for. Its key must be a single property.\r\n @param valueIfAvail - A key value to use if no entity in the manager holds it. When entities with\r\n temporary keys are imported, the manager passes each one's key here, so that the key survives the\r\n import where it can; a subclass passes the value it made. If the value is taken, or omitted, a new\r\n one is generated. Either way, the value returned is recorded as held.\r\n @returns The key value, of the key property's data type.\r\n */\r\n generateTempKeyValue(entityType: EntityType, valueIfAvail?: any): any {\r\n let keyProps = entityType.keyProperties;\r\n if (keyProps.length > 1) {\r\n throw new Error(\"Ids can not be autogenerated for entities with multipart keys\");\r\n }\r\n let keyProp = keyProps[0];\r\n let propEntry = this._getPropEntry(keyProp, true);\r\n let nextId: any;\r\n if (valueIfAvail != null) {\r\n if (!propEntry.keyMap.has(valueIfAvail.toString())) {\r\n nextId = valueIfAvail;\r\n }\r\n }\r\n\r\n if (nextId === undefined) {\r\n let dataType = keyProp.dataType;\r\n let getNextFn = (dataType as any).getNext;\r\n if (getNextFn) {\r\n nextId = getNextFn(this);\r\n // need to watch out for collision with previously imported ids that might also get generated.\r\n while (propEntry.keyMap.has(nextId.toString())) {\r\n nextId = getNextFn(this);\r\n }\r\n } else {\r\n throw new Error(\"Cannot use a property with a dataType of: \" + dataType.toString() + \" for id generation\");\r\n }\r\n }\r\n\r\n propEntry.keyMap.add(nextId.toString());\r\n return nextId;\r\n }\r\n\r\n /** Returns an {@link EntityKey} for each temporary key value the manager's entities hold: the\r\n values this generator handed out or recorded, less those released when an entity was saved and\r\n given the server's key, or detached.\r\n @deprecated Ask the entities instead:\r\n `em.getEntities().filter(e => e.entityAspect.hasTempKey).map(e => e.entityAspect.getKey())`.\r\n Breeze does not call it. It still works; it is not scheduled for removal. */\r\n getTempKeys() {\r\n let results: EntityKey[] = [];\r\n //noinspection JSHint\r\n this._tempIdMap.forEach(propEntry => {\r\n const entityType = propEntry.entityType;\r\n propEntry.keyMap.forEach(keyValue => {\r\n results.push(new EntityKey(entityType, [keyValue]));\r\n });\r\n });\r\n return results;\r\n }\r\n\r\n\r\n // proto methods below are not part of the KeyGenerator interface.\r\n\r\n /** Whether `entityKey`'s value is a temporary key an entity in the manager holds - one of the\r\n values {@link KeyGenerator.getTempKeys} returns. Always false for a multipart key.\r\n @deprecated Ask the entity instead: `em.getEntityByKey(key)?.entityAspect.hasTempKey`, or\r\n {@link EntityAspect.hasTempKey} when you have the entity. Breeze does not call it. It still\r\n works; it is not scheduled for removal. */\r\n isTempKey(entityKey: EntityKey) {\r\n let keyProps = entityKey.entityType.keyProperties;\r\n if (keyProps.length > 1) return false;\r\n let keyProp = keyProps[0];\r\n let propEntry = this._getPropEntry(keyProp);\r\n if (!propEntry) {\r\n return false;\r\n }\r\n return propEntry.keyMap.has(entityKey.values[0].toString());\r\n }\r\n\r\n /**\r\n Forgets a temporary key value that no entity holds any longer: the manager calls it when an\r\n entity with a temporary key is saved, and the server's key replaces it, or is detached. The value\r\n is then free for an import to keep. Without this the generator remembered every value it had\r\n ever handed out, for the life of the manager.\r\n @hidden @internal\r\n */\r\n _releaseTempKeyValue(entityType: EntityType, value: any) {\r\n const keyProps = entityType.keyProperties;\r\n if (keyProps.length !== 1 || value == null) return;\r\n this._getPropEntry(keyProps[0])?.keyMap.delete(value.toString());\r\n }\r\n\r\n /**\r\n Records a temporary key value this generator did not hand out, or has forgotten: the manager\r\n calls it when an entity that already has a temporary key is attached - one detached earlier, or\r\n one from another manager - so that an import cannot give a second entity the same key.\r\n @hidden @internal\r\n */\r\n _reserveTempKeyValue(entityType: EntityType, value: any) {\r\n const keyProps = entityType.keyProperties;\r\n if (keyProps.length !== 1 || value == null) return;\r\n this._getPropEntry(keyProps[0], true).keyMap.add(value.toString());\r\n }\r\n\r\n /** @hidden @internal */\r\n private _getPropEntry(keyProp: DataProperty, createIfMissing: true): IPropEntry;\r\n private _getPropEntry(keyProp: DataProperty, createIfMissing?: boolean): IPropEntry | undefined;\r\n private _getPropEntry(keyProp: DataProperty, createIfMissing = false) {\r\n let key = keyProp.name + \"..\" + keyProp.parentType.name;\r\n let propEntry = this._tempIdMap.get(key);\r\n if (!propEntry) {\r\n if (createIfMissing) {\r\n propEntry = { entityType: keyProp.parentType as EntityType, propertyName: keyProp.name, keyMap: new Set() };\r\n this._tempIdMap.set(key, propEntry);\r\n }\r\n }\r\n return propEntry;\r\n }\r\n\r\n}\r\n\r\nconfig.registerType(KeyGenerator, \"KeyGenerator\");\r\n\r\n"]}
@@ -0,0 +1,25 @@
1
+ import { BreezeEvent } from '../core/event.js';
2
+ import type { DataProperty } from '../metadata/entity-metadata.js';
3
+ /** The argument to the `arrayChanged` event of a relation, complex or primitive array. */
4
+ export interface ArrayChangedArgs {
5
+ /** The array that changed. */
6
+ array: any[];
7
+ /** The items added. Undefined when the event reports removals: each change raises its own event,
8
+ so a `splice` that both removes and adds raises one for the removals, then one for the additions.
9
+ While a query or import is loading, the changes to an array are collected into a single event
10
+ that can carry both, as the net change: an item added and removed again during the load is in
11
+ neither list. */
12
+ added?: any[];
13
+ /** The items removed. Undefined when the event reports only additions. */
14
+ removed?: any[];
15
+ }
16
+ /**
17
+ * A real array - every Array method is the native one - plus change notification and the links
18
+ * back to the entity that owns it. Only the five mutators are replaced.
19
+ * @hidden
20
+ */
21
+ export interface ObservableArray<T = any> extends Array<T> {
22
+ arrayChanged: BreezeEvent<ArrayChangedArgs>;
23
+ parent?: Object;
24
+ parentProperty?: DataProperty;
25
+ }
@@ -0,0 +1,230 @@
1
+ // --- the five mutators -----------------------------------------------------------------------
2
+ // Shared function objects: every array gets the same five, so the only per-array cost is the
3
+ // property slot. Each one reads its behaviour from `this._obs.ops`.
4
+ function push(...items) {
5
+ const state = this._obs;
6
+ if (state.inProgress) {
7
+ return -1;
8
+ }
9
+ const goodAdds = state.ops.getGoodAdds(this, items);
10
+ if (!goodAdds.length) {
11
+ return this.length;
12
+ }
13
+ state.ops.beforeChange(this);
14
+ const result = Array.prototype.push.apply(this, goodAdds);
15
+ processAdds(this, goodAdds);
16
+ return result;
17
+ }
18
+ function unshift(...items) {
19
+ const state = this._obs;
20
+ const goodAdds = state.ops.getGoodAdds(this, items);
21
+ if (!goodAdds.length) {
22
+ return this.length;
23
+ }
24
+ state.ops.beforeChange(this);
25
+ const result = Array.prototype.unshift.apply(this, goodAdds);
26
+ processAdds(this, goodAdds);
27
+ return result;
28
+ }
29
+ // An empty array removes nothing, so there is nothing to tell the kind about and nothing to
30
+ // publish. Without this the kinds are handed `[undefined]`: a relation array dereferences it and
31
+ // throws, where a plain array would just return undefined.
32
+ function pop() {
33
+ if (this.length === 0)
34
+ return undefined;
35
+ const state = this._obs;
36
+ state.ops.beforeChange(this);
37
+ const result = Array.prototype.pop.call(this);
38
+ processRemoves(this, [result]);
39
+ return result;
40
+ }
41
+ function shift() {
42
+ if (this.length === 0)
43
+ return undefined;
44
+ const state = this._obs;
45
+ state.ops.beforeChange(this);
46
+ const result = Array.prototype.shift.call(this);
47
+ processRemoves(this, [result]);
48
+ return result;
49
+ }
50
+ function splice(...args) {
51
+ const state = this._obs;
52
+ const goodAdds = state.ops.getGoodAdds(this, args.slice(2));
53
+ const newArgs = args.slice(0, 2).concat(goodAdds);
54
+ state.ops.beforeChange(this);
55
+ const result = Array.prototype.splice.apply(this, newArgs);
56
+ processRemoves(this, result);
57
+ if (goodAdds.length) {
58
+ processAdds(this, goodAdds);
59
+ }
60
+ return result;
61
+ }
62
+ function getEventParent() {
63
+ return this._obs.ops.getEventParent(this);
64
+ }
65
+ // --- shared machinery ------------------------------------------------------------------------
66
+ /**
67
+ * Adds items without asking the kind whether it wants them. The merge path has already decided,
68
+ * and re-checking would attach the same entities a second time.
69
+ */
70
+ function pushUnchecked(arr, ...items) {
71
+ const state = arr._obs;
72
+ if (state.inProgress) {
73
+ return -1;
74
+ }
75
+ state.ops.beforeChange(arr);
76
+ const result = Array.prototype.push.apply(arr, items);
77
+ processAdds(arr, items);
78
+ return result;
79
+ }
80
+ function processAdds(arr, adds) {
81
+ arr._obs.ops.processAdds(arr, adds);
82
+ publish(arr, "arrayChanged", { array: arr, added: adds });
83
+ }
84
+ function processRemoves(arr, removes) {
85
+ arr._obs.ops.processRemoves(arr, removes);
86
+ publish(arr, "arrayChanged", { array: arr, removed: removes });
87
+ }
88
+ /**
89
+ * Publishes now, or - while an EntityManager is loading - queues one event per array and folds
90
+ * later changes into it, so that a query produces a single arrayChanged per collection.
91
+ */
92
+ function publish(publisher, eventName, eventArgs) {
93
+ const state = publisher._obs;
94
+ const pendingPubs = state.ops.getPendingPubs(publisher);
95
+ if (pendingPubs) {
96
+ if (!state.pendingArgs) {
97
+ state.pendingArgs = { array: eventArgs.array };
98
+ combineArgs(state.pendingArgs, eventArgs);
99
+ pendingPubs.push(function () {
100
+ const args = state.pendingArgs;
101
+ state.pendingArgs = null;
102
+ // Changes that cancelled out leave empty lists, which are left off; none at all, no event.
103
+ if (!args.added?.length)
104
+ delete args.added;
105
+ if (!args.removed?.length)
106
+ delete args.removed;
107
+ if (args.added || args.removed)
108
+ publisher[eventName].publish(args);
109
+ });
110
+ }
111
+ else {
112
+ combineArgs(state.pendingArgs, eventArgs);
113
+ }
114
+ }
115
+ else {
116
+ publisher[eventName].publish(eventArgs);
117
+ }
118
+ }
119
+ /** The aspect of the entity that owns this array, whether directly or through a complex object. */
120
+ function getEntityAspect(arr) {
121
+ const parent = arr.parent;
122
+ return parent.entityAspect || parent.complexAspect.getEntityAspect();
123
+ }
124
+ /** Marks the owning entity Modified, and keeps a copy of the contents the first time. */
125
+ function updateEntityState(arr) {
126
+ const entityAspect = getEntityAspect(arr);
127
+ if (entityAspect.entityState.isUnchanged()) {
128
+ entityAspect.setModified();
129
+ }
130
+ const state = arr._obs;
131
+ if (entityAspect.entityState.isModified() && !state.origValues) {
132
+ state.origValues = arr.slice(0);
133
+ }
134
+ }
135
+ /**
136
+ * Empty the array in one go, running `onRemove` for each item first.
137
+ *
138
+ * The obvious spelling - let each item take itself out - is quadratic. Nulling a child's
139
+ * reference to its parent makes the interceptor splice that child out of this very array, and a
140
+ * splice from the front shifts everything after it, so emptying n children moves n²/2 elements.
141
+ * Detaching a customer with 16,000 orders spent 239ms doing that, and published 16,000
142
+ * arrayChanged events for what is one change to the collection.
143
+ *
144
+ * So `isClearing` is set while `onRemove` runs. The interceptor sees it and skips its splice -
145
+ * everything else it does for the child, nulling the navigation property and clearing the
146
+ * foreign key, still happens. The array is then truncated at once and one event is published
147
+ * carrying everything that was in it, which is what the batched query and import paths already
148
+ * do for a collection that changes wholesale.
149
+ */
150
+ function clearAll(arr, onRemove) {
151
+ const removed = arr.slice(0);
152
+ if (!removed.length)
153
+ return removed;
154
+ const state = arr._obs;
155
+ if (onRemove) {
156
+ state.isClearing = true;
157
+ try {
158
+ for (const item of removed)
159
+ onRemove(item);
160
+ }
161
+ finally {
162
+ state.isClearing = false;
163
+ }
164
+ }
165
+ arr.length = 0;
166
+ publish(arr, "arrayChanged", { array: arr, removed: removed });
167
+ return removed;
168
+ }
169
+ /**
170
+ * True while `clearAll` is emptying this array, meaning it will remove its own contents and
171
+ * publish for them; anything that would otherwise splice one item out should leave it alone.
172
+ */
173
+ function isClearing(arr) {
174
+ return !!(arr && arr._obs && arr._obs.isClearing);
175
+ }
176
+ /**
177
+ * Folds one change into the batched event, as a net change: an item added and then removed in the
178
+ * same batch - or removed and then added - drops out of both lists, so applying the event's
179
+ * removals and additions in either order gives the right result. `target` owns its lists; the
180
+ * source's are only read.
181
+ *
182
+ * It used to copy only keys the target already had, so a batch that started with an addition
183
+ * lost every later removal, and the reverse.
184
+ */
185
+ function combineArgs(target, source) {
186
+ const pairs = [["added", "removed"], ["removed", "added"]];
187
+ for (const [key, opposite] of pairs) {
188
+ for (const item of source[key] ?? []) {
189
+ const undone = target[opposite]?.indexOf(item) ?? -1;
190
+ if (undone >= 0) {
191
+ target[opposite].splice(undone, 1);
192
+ }
193
+ else {
194
+ (target[key] ??= []).push(item);
195
+ }
196
+ }
197
+ }
198
+ }
199
+ /**
200
+ * Turns a plain array into an observable one: the five mutators, the event-parent hook and the
201
+ * single state property. Anything else a kind needs belongs in its `ops` or in its state.
202
+ */
203
+ function initialize(arr, ops, state) {
204
+ arr.push = push;
205
+ arr.unshift = unshift;
206
+ arr.pop = pop;
207
+ arr.shift = shift;
208
+ arr.splice = splice;
209
+ arr._getEventParent = getEventParent;
210
+ arr._obs = Object.assign({ ops: ops }, state);
211
+ }
212
+ /** @hidden @internal */
213
+ export const observableArray = {
214
+ initialize: initialize,
215
+ updateEntityState: updateEntityState,
216
+ publish: publish,
217
+ getEntityAspect: getEntityAspect,
218
+ pushUnchecked: pushUnchecked,
219
+ clearAll: clearAll,
220
+ isClearing: isClearing,
221
+ /** Puts back the contents the owning entity had before its changes. */
222
+ rejectChanges: (arr) => arr._obs.ops.rejectChanges?.(arr),
223
+ /** Forgets the saved contents: what was changed is now what is stored. */
224
+ acceptChanges: (arr) => arr._obs.ops.acceptChanges?.(arr),
225
+ /** True once the array has been changed away from what the server sent. */
226
+ hasOriginalValues: (arr) => !!arr._obs?.origValues,
227
+ /** The contents the array had before its entity was changed, or null if it has not been. */
228
+ originalContents: (arr) => arr?._obs?.origValues ?? null,
229
+ };
230
+ //# sourceMappingURL=observable-array.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observable-array.js","sourceRoot":"","sources":["../../src/entity/observable-array.ts"],"names":[],"mappings":"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","sourcesContent":["import { BreezeEvent } from '../core/event.js';\r\nimport type { EntityAspect } from './entity-aspect.js';\r\nimport type { DataProperty } from '../metadata/entity-metadata.js';\r\n\r\n/*\r\n * The observable arrays - relation, complex and primitive - are real arrays, and have to be:\r\n * applications index them, iterate them, spread them and `JSON.stringify` them, and every one of\r\n * those is the engine's fast path only while the object stays a plain array with\r\n * `Array.prototype`. That rules out both of the tidier-looking alternatives: a subclass or a\r\n * swapped prototype costs about 20x on `forEach`/`map`/`filter`, and a `Proxy` about 400x on\r\n * reads.\r\n *\r\n * What is *not* free is the number of own properties. Past roughly a dozen, V8 moves the array\r\n * to dictionary properties and indexed reads get about 90x slower. 2.x copied sixteen functions\r\n * onto every array and paid exactly that.\r\n *\r\n * So only the five mutators live on the instance - they have to, to be intercepted - plus\r\n * `_getEventParent`, which BreezeEvent looks for on the publisher itself. Everything else, the\r\n * per-kind behaviour and the bookkeeping, hangs off one `_obs` property.\r\n * `test/unit/observable-array.spec.ts` pins the count so this cannot drift back.\r\n */\r\n\r\n/** The argument to the `arrayChanged` event of a relation, complex or primitive array. */\r\nexport interface ArrayChangedArgs {\r\n /** The array that changed. */\r\n array: any[];\r\n /** The items added. Undefined when the event reports removals: each change raises its own event,\r\n so a `splice` that both removes and adds raises one for the removals, then one for the additions.\r\n While a query or import is loading, the changes to an array are collected into a single event\r\n that can carry both, as the net change: an item added and removed again during the load is in\r\n neither list. */\r\n added?: any[];\r\n /** The items removed. Undefined when the event reports only additions. */\r\n removed?: any[];\r\n}\r\n\r\n/**\r\n * What differs between a relation, complex and primitive array. One shared instance per kind,\r\n * reached through `arr._obs.ops`, so that none of it sits on the array itself.\r\n * @hidden @internal\r\n */\r\nexport interface ObservableArrayOps {\r\n /** The subset of `adds` that should actually be added. */\r\n getGoodAdds(arr: any, adds: any[]): any[];\r\n processAdds(arr: any, adds: any[]): void;\r\n processRemoves(arr: any, removes: any[]): void;\r\n /** Runs before any mutation; where an array marks its owning entity modified. */\r\n beforeChange(arr: any): void;\r\n getEventParent(arr: any): Object;\r\n getPendingPubs(arr: any): any[] | undefined;\r\n rejectChanges?(arr: any): void;\r\n acceptChanges?(arr: any): void;\r\n}\r\n\r\n/**\r\n * Per-array bookkeeping: one object, one own property on the array.\r\n * @hidden @internal\r\n */\r\nexport interface ObservableArrayState {\r\n ops: ObservableArrayOps;\r\n /** The contents before the first change, once the owning entity is Modified. */\r\n origValues?: any[] | null;\r\n /** Set while an arrayChanged event is queued behind an EntityManager's pending publications. */\r\n pendingArgs?: any;\r\n /** Relation arrays: the adds being processed, which stops relationship fixup recursing. */\r\n addsInProcess?: any[];\r\n /** Relation arrays: set while attaching an entity, so a re-entrant push is ignored. */\r\n inProgress?: boolean;\r\n /** Set while `clearAll` is emptying the array; see there. */\r\n isClearing?: boolean;\r\n}\r\n\r\n/**\r\n * A real array - every Array method is the native one - plus change notification and the links\r\n * back to the entity that owns it. Only the five mutators are replaced.\r\n * @hidden\r\n */\r\nexport interface ObservableArray<T = any> extends Array<T> {\r\n arrayChanged: BreezeEvent<ArrayChangedArgs>;\r\n parent?: Object;\r\n parentProperty?: DataProperty;\r\n\r\n /** @hidden @internal */\r\n _obs: ObservableArrayState;\r\n /** @hidden @internal BreezeEvent reads this off the publisher to walk the enable/disable chain. */\r\n _getEventParent(): Object;\r\n}\r\n\r\n// --- the five mutators -----------------------------------------------------------------------\r\n// Shared function objects: every array gets the same five, so the only per-array cost is the\r\n// property slot. Each one reads its behaviour from `this._obs.ops`.\r\n\r\nfunction push(this: any, ...items: any[]): number {\r\n const state = this._obs as ObservableArrayState;\r\n if (state.inProgress) {\r\n return -1;\r\n }\r\n const goodAdds = state.ops.getGoodAdds(this, items);\r\n if (!goodAdds.length) {\r\n return this.length;\r\n }\r\n state.ops.beforeChange(this);\r\n const result = Array.prototype.push.apply(this, goodAdds);\r\n processAdds(this, goodAdds);\r\n return result;\r\n}\r\n\r\nfunction unshift(this: any, ...items: any[]): number {\r\n const state = this._obs as ObservableArrayState;\r\n const goodAdds = state.ops.getGoodAdds(this, items);\r\n if (!goodAdds.length) {\r\n return this.length;\r\n }\r\n state.ops.beforeChange(this);\r\n const result = Array.prototype.unshift.apply(this, goodAdds);\r\n processAdds(this, goodAdds);\r\n return result;\r\n}\r\n\r\n// An empty array removes nothing, so there is nothing to tell the kind about and nothing to\r\n// publish. Without this the kinds are handed `[undefined]`: a relation array dereferences it and\r\n// throws, where a plain array would just return undefined.\r\n\r\nfunction pop(this: any): any {\r\n if (this.length === 0) return undefined;\r\n const state = this._obs as ObservableArrayState;\r\n state.ops.beforeChange(this);\r\n const result = Array.prototype.pop.call(this);\r\n processRemoves(this, [result]);\r\n return result;\r\n}\r\n\r\nfunction shift(this: any): any {\r\n if (this.length === 0) return undefined;\r\n const state = this._obs as ObservableArrayState;\r\n state.ops.beforeChange(this);\r\n const result = Array.prototype.shift.call(this);\r\n processRemoves(this, [result]);\r\n return result;\r\n}\r\n\r\nfunction splice(this: any, ...args: any[]): any[] {\r\n const state = this._obs as ObservableArrayState;\r\n const goodAdds = state.ops.getGoodAdds(this, args.slice(2));\r\n const newArgs = args.slice(0, 2).concat(goodAdds);\r\n state.ops.beforeChange(this);\r\n const result = Array.prototype.splice.apply(this, newArgs as [number, number, ...any[]]);\r\n processRemoves(this, result);\r\n if (goodAdds.length) {\r\n processAdds(this, goodAdds);\r\n }\r\n return result;\r\n}\r\n\r\nfunction getEventParent(this: any): Object {\r\n return (this._obs as ObservableArrayState).ops.getEventParent(this);\r\n}\r\n\r\n// --- shared machinery ------------------------------------------------------------------------\r\n\r\n/**\r\n * Adds items without asking the kind whether it wants them. The merge path has already decided,\r\n * and re-checking would attach the same entities a second time.\r\n */\r\nfunction pushUnchecked(arr: any, ...items: any[]): number {\r\n const state = arr._obs as ObservableArrayState;\r\n if (state.inProgress) {\r\n return -1;\r\n }\r\n state.ops.beforeChange(arr);\r\n const result = Array.prototype.push.apply(arr, items);\r\n processAdds(arr, items);\r\n return result;\r\n}\r\n\r\nfunction processAdds(arr: any, adds: any[]): void {\r\n (arr._obs as ObservableArrayState).ops.processAdds(arr, adds);\r\n publish(arr, \"arrayChanged\", { array: arr, added: adds });\r\n}\r\n\r\nfunction processRemoves(arr: any, removes: any[]): void {\r\n (arr._obs as ObservableArrayState).ops.processRemoves(arr, removes);\r\n publish(arr, \"arrayChanged\", { array: arr, removed: removes });\r\n}\r\n\r\n/**\r\n * Publishes now, or - while an EntityManager is loading - queues one event per array and folds\r\n * later changes into it, so that a query produces a single arrayChanged per collection.\r\n */\r\nfunction publish(publisher: any, eventName: string, eventArgs: any): void {\r\n const state = publisher._obs as ObservableArrayState;\r\n const pendingPubs = state.ops.getPendingPubs(publisher);\r\n if (pendingPubs) {\r\n if (!state.pendingArgs) {\r\n state.pendingArgs = { array: eventArgs.array };\r\n combineArgs(state.pendingArgs, eventArgs);\r\n pendingPubs.push(function () {\r\n const args = state.pendingArgs;\r\n state.pendingArgs = null;\r\n // Changes that cancelled out leave empty lists, which are left off; none at all, no event.\r\n if (!args.added?.length) delete args.added;\r\n if (!args.removed?.length) delete args.removed;\r\n if (args.added || args.removed) publisher[eventName].publish(args);\r\n });\r\n } else {\r\n combineArgs(state.pendingArgs, eventArgs);\r\n }\r\n } else {\r\n publisher[eventName].publish(eventArgs);\r\n }\r\n}\r\n\r\n/** The aspect of the entity that owns this array, whether directly or through a complex object. */\r\nfunction getEntityAspect(arr: any): EntityAspect {\r\n const parent = arr.parent;\r\n return parent.entityAspect || parent.complexAspect.getEntityAspect();\r\n}\r\n\r\n/** Marks the owning entity Modified, and keeps a copy of the contents the first time. */\r\nfunction updateEntityState(arr: any): void {\r\n const entityAspect = getEntityAspect(arr);\r\n if (entityAspect.entityState.isUnchanged()) {\r\n entityAspect.setModified();\r\n }\r\n const state = arr._obs as ObservableArrayState;\r\n if (entityAspect.entityState.isModified() && !state.origValues) {\r\n state.origValues = arr.slice(0);\r\n }\r\n}\r\n\r\n/**\r\n * Empty the array in one go, running `onRemove` for each item first.\r\n *\r\n * The obvious spelling - let each item take itself out - is quadratic. Nulling a child's\r\n * reference to its parent makes the interceptor splice that child out of this very array, and a\r\n * splice from the front shifts everything after it, so emptying n children moves n²/2 elements.\r\n * Detaching a customer with 16,000 orders spent 239ms doing that, and published 16,000\r\n * arrayChanged events for what is one change to the collection.\r\n *\r\n * So `isClearing` is set while `onRemove` runs. The interceptor sees it and skips its splice -\r\n * everything else it does for the child, nulling the navigation property and clearing the\r\n * foreign key, still happens. The array is then truncated at once and one event is published\r\n * carrying everything that was in it, which is what the batched query and import paths already\r\n * do for a collection that changes wholesale.\r\n */\r\nfunction clearAll(arr: any, onRemove?: (item: any) => void): any[] {\r\n const removed = arr.slice(0);\r\n if (!removed.length) return removed;\r\n\r\n const state = arr._obs as ObservableArrayState;\r\n if (onRemove) {\r\n state.isClearing = true;\r\n try {\r\n for (const item of removed) onRemove(item);\r\n } finally {\r\n state.isClearing = false;\r\n }\r\n }\r\n arr.length = 0;\r\n publish(arr, \"arrayChanged\", { array: arr, removed: removed });\r\n return removed;\r\n}\r\n\r\n/**\r\n * True while `clearAll` is emptying this array, meaning it will remove its own contents and\r\n * publish for them; anything that would otherwise splice one item out should leave it alone.\r\n */\r\nfunction isClearing(arr: any): boolean {\r\n return !!(arr && arr._obs && (arr._obs as ObservableArrayState).isClearing);\r\n}\r\n\r\n/**\r\n * Folds one change into the batched event, as a net change: an item added and then removed in the\r\n * same batch - or removed and then added - drops out of both lists, so applying the event's\r\n * removals and additions in either order gives the right result. `target` owns its lists; the\r\n * source's are only read.\r\n *\r\n * It used to copy only keys the target already had, so a batch that started with an addition\r\n * lost every later removal, and the reverse.\r\n */\r\nfunction combineArgs(target: ArrayChangedArgs, source: ArrayChangedArgs): void {\r\n const pairs = [[\"added\", \"removed\"], [\"removed\", \"added\"]] as const;\r\n for (const [key, opposite] of pairs) {\r\n for (const item of source[key] ?? []) {\r\n const undone = target[opposite]?.indexOf(item) ?? -1;\r\n if (undone >= 0) {\r\n target[opposite]!.splice(undone, 1);\r\n } else {\r\n (target[key] ??= []).push(item);\r\n }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Turns a plain array into an observable one: the five mutators, the event-parent hook and the\r\n * single state property. Anything else a kind needs belongs in its `ops` or in its state.\r\n */\r\nfunction initialize(arr: any, ops: ObservableArrayOps, state?: Partial<ObservableArrayState>): void {\r\n arr.push = push;\r\n arr.unshift = unshift;\r\n arr.pop = pop;\r\n arr.shift = shift;\r\n arr.splice = splice;\r\n arr._getEventParent = getEventParent;\r\n arr._obs = Object.assign({ ops: ops }, state) as ObservableArrayState;\r\n}\r\n\r\n/** @hidden @internal */\r\nexport const observableArray = {\r\n initialize: initialize,\r\n updateEntityState: updateEntityState,\r\n publish: publish,\r\n getEntityAspect: getEntityAspect,\r\n pushUnchecked: pushUnchecked,\r\n clearAll: clearAll,\r\n isClearing: isClearing,\r\n /** Puts back the contents the owning entity had before its changes. */\r\n rejectChanges: (arr: any) => (arr._obs as ObservableArrayState).ops.rejectChanges?.(arr),\r\n /** Forgets the saved contents: what was changed is now what is stored. */\r\n acceptChanges: (arr: any) => (arr._obs as ObservableArrayState).ops.acceptChanges?.(arr),\r\n /** True once the array has been changed away from what the server sent. */\r\n hasOriginalValues: (arr: any) => !!(arr._obs as ObservableArrayState)?.origValues,\r\n /** The contents the array had before its entity was changed, or null if it has not been. */\r\n originalContents: (arr: any): any[] | null => (arr?._obs as ObservableArrayState | undefined)?.origValues ?? null,\r\n};\r\n"]}
@@ -0,0 +1,12 @@
1
+ import { ObservableArray } from './observable-array.js';
2
+ import type { StructuralObject } from './entity-aspect.js';
3
+ import type { DataProperty } from '../metadata/entity-metadata.js';
4
+ export interface PrimitiveArray extends ObservableArray<any> {
5
+ parent?: StructuralObject;
6
+ parentProperty?: DataProperty;
7
+ }
8
+ /** For use by breeze plugin authors only. The class is for use in building a {@link ModelLibraryAdapter} implementation.
9
+ @adapter (see {@link ModelLibraryAdapter})
10
+ @hidden
11
+ */
12
+ export declare function makePrimitiveArray(arr: any[], parent: StructuralObject, parentProperty: DataProperty): PrimitiveArray;
@@ -0,0 +1,71 @@
1
+ import { BreezeEvent } from '../core/event.js';
2
+ import { observableArray } from './observable-array.js';
3
+ /*
4
+ Primitive arrays are not a class: they are real arrays whose mutating methods are replaced, so
5
+ that changing one updates the entity that owns it. A primitive array is a collection of primitive
6
+ values associated with a data property on a single entity or complex object, i.e.
7
+ customer.invoiceNumbers.
8
+ @class {primitiveArray}
9
+ */
10
+ /*
11
+ An {@link BreezeEvent} that fires whenever the contents of this array changed. This event
12
+ is fired any time a new entity is attached or added to the EntityManager and happens to belong to this collection.
13
+ Adds that occur as a result of query or import operations are batched so that all of the adds or removes to any individual
14
+ collections are collected into a single notification event for each relation array.
15
+ @example
16
+ // assume order is an order entity attached to an EntityManager.
17
+ orders.arrayChanged.subscribe(
18
+ function (arrayChangedArgs) {
19
+ let addedEntities = arrayChangedArgs.added;
20
+ let removedEntities = arrayChanged.removed;
21
+ });
22
+ @event arrayChanged
23
+ @param added {Array of Primitives} An array of all of the items added to this collection.
24
+ @param removed {Array of Primitives} An array of all of the items removed from this collection.
25
+ @readOnly
26
+ */
27
+ const primitiveArrayOps = {
28
+ // every value is welcome: there is nothing to attach, and no duplicate to guard against
29
+ getGoodAdds: function (arr, adds) {
30
+ return adds;
31
+ },
32
+ beforeChange: function (arr) {
33
+ observableArray.updateEntityState(arr);
34
+ },
35
+ processAdds: function (arr, adds) {
36
+ // nothing needed
37
+ },
38
+ processRemoves: function (arr, removes) {
39
+ // nothing needed
40
+ },
41
+ getEventParent: function (arr) {
42
+ return observableArray.getEntityAspect(arr);
43
+ },
44
+ getPendingPubs: function (arr) {
45
+ const em = observableArray.getEntityAspect(arr).entityManager;
46
+ return em && em._pendingPubs;
47
+ },
48
+ rejectChanges: function (arr) {
49
+ const origValues = arr._obs.origValues;
50
+ if (!origValues)
51
+ return;
52
+ arr.length = 0;
53
+ Array.prototype.push.apply(arr, origValues);
54
+ },
55
+ acceptChanges: function (arr) {
56
+ arr._obs.origValues = null;
57
+ }
58
+ };
59
+ /** For use by breeze plugin authors only. The class is for use in building a {@link ModelLibraryAdapter} implementation.
60
+ @adapter (see {@link ModelLibraryAdapter})
61
+ @hidden
62
+ */
63
+ export function makePrimitiveArray(arr, parent, parentProperty) {
64
+ const arrX = arr;
65
+ arrX.parent = parent;
66
+ arrX.parentProperty = parentProperty;
67
+ arrX.arrayChanged = new BreezeEvent("arrayChanged", arrX);
68
+ observableArray.initialize(arrX, primitiveArrayOps);
69
+ return arrX;
70
+ }
71
+ //# sourceMappingURL=primitive-array.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"primitive-array.js","sourceRoot":"","sources":["../../src/entity/primitive-array.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAuC,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAS7F;;;;;;GAMG;AAEH;;;;;;;;;;;;;;;;EAgBE;AAEF,MAAM,iBAAiB,GAAuB;IAE5C,wFAAwF;IACxF,WAAW,EAAE,UAAU,GAAmB,EAAE,IAAW;QACrD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,YAAY,EAAE,UAAU,GAAmB;QACzC,eAAe,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC;IACzC,CAAC;IAED,WAAW,EAAE,UAAU,GAAmB,EAAE,IAAW;QACrD,iBAAiB;IACnB,CAAC;IAED,cAAc,EAAE,UAAU,GAAmB,EAAE,OAAc;QAC3D,iBAAiB;IACnB,CAAC;IAED,cAAc,EAAE,UAAU,GAAmB;QAC3C,OAAO,eAAe,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;IAC9C,CAAC;IAED,cAAc,EAAE,UAAU,GAAmB;QAC3C,MAAM,EAAE,GAAG,eAAe,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,aAAa,CAAC;QAC9D,OAAO,EAAE,IAAK,EAAU,CAAC,YAAY,CAAC;IACxC,CAAC;IAED,aAAa,EAAE,UAAU,GAAmB;QAC1C,MAAM,UAAU,GAAG,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC;QACvC,IAAI,CAAC,UAAU;YAAE,OAAO;QACxB,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;QACf,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;IAC9C,CAAC;IAED,aAAa,EAAE,UAAU,GAAmB;QAC1C,GAAG,CAAC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;IAC7B,CAAC;CACF,CAAC;AAEF;;;EAGE;AACF,MAAM,UAAU,kBAAkB,CAAC,GAAU,EAAE,MAAwB,EAAE,cAA4B;IACnG,MAAM,IAAI,GAAG,GAAU,CAAC;IACxB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACrB,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;IACrC,IAAI,CAAC,YAAY,GAAG,IAAI,WAAW,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC;IAC1D,eAAe,CAAC,UAAU,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC;IACpD,OAAO,IAAsB,CAAC;AAChC,CAAC","sourcesContent":["import { BreezeEvent } from '../core/event.js';\nimport { ObservableArray, ObservableArrayOps, observableArray } from './observable-array.js';\nimport type { StructuralObject } from './entity-aspect.js';\nimport type { DataProperty } from '../metadata/entity-metadata.js';\n\nexport interface PrimitiveArray extends ObservableArray<any> {\n parent?: StructuralObject;\n parentProperty?: DataProperty;\n}\n\n/*\n Primitive arrays are not a class: they are real arrays whose mutating methods are replaced, so\n that changing one updates the entity that owns it. A primitive array is a collection of primitive\n values associated with a data property on a single entity or complex object, i.e.\n customer.invoiceNumbers.\n @class {primitiveArray}\n */\n\n/*\nAn {@link BreezeEvent} that fires whenever the contents of this array changed. This event\nis fired any time a new entity is attached or added to the EntityManager and happens to belong to this collection.\nAdds that occur as a result of query or import operations are batched so that all of the adds or removes to any individual\ncollections are collected into a single notification event for each relation array.\n@example\n // assume order is an order entity attached to an EntityManager.\n orders.arrayChanged.subscribe(\n function (arrayChangedArgs) {\n let addedEntities = arrayChangedArgs.added;\n let removedEntities = arrayChanged.removed;\n });\n@event arrayChanged\n@param added {Array of Primitives} An array of all of the items added to this collection.\n@param removed {Array of Primitives} An array of all of the items removed from this collection.\n@readOnly\n*/\n\nconst primitiveArrayOps: ObservableArrayOps = {\n\n // every value is welcome: there is nothing to attach, and no duplicate to guard against\n getGoodAdds: function (arr: PrimitiveArray, adds: any[]) {\n return adds;\n },\n\n beforeChange: function (arr: PrimitiveArray) {\n observableArray.updateEntityState(arr);\n },\n\n processAdds: function (arr: PrimitiveArray, adds: any[]) {\n // nothing needed\n },\n\n processRemoves: function (arr: PrimitiveArray, removes: any[]) {\n // nothing needed\n },\n\n getEventParent: function (arr: PrimitiveArray) {\n return observableArray.getEntityAspect(arr);\n },\n\n getPendingPubs: function (arr: PrimitiveArray) {\n const em = observableArray.getEntityAspect(arr).entityManager;\n return em && (em as any)._pendingPubs;\n },\n\n rejectChanges: function (arr: PrimitiveArray) {\n const origValues = arr._obs.origValues;\n if (!origValues) return;\n arr.length = 0;\n Array.prototype.push.apply(arr, origValues);\n },\n\n acceptChanges: function (arr: PrimitiveArray) {\n arr._obs.origValues = null;\n }\n};\n\n/** For use by breeze plugin authors only. The class is for use in building a {@link ModelLibraryAdapter} implementation.\n@adapter (see {@link ModelLibraryAdapter})\n@hidden\n*/\nexport function makePrimitiveArray(arr: any[], parent: StructuralObject, parentProperty: DataProperty): PrimitiveArray {\n const arrX = arr as any;\n arrX.parent = parent;\n arrX.parentProperty = parentProperty;\n arrX.arrayChanged = new BreezeEvent(\"arrayChanged\", arrX);\n observableArray.initialize(arrX, primitiveArrayOps);\n return arrX as PrimitiveArray;\n}\n"]}