breeze-client 2.2.2 → 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 +63 -94
  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,2502 @@
1
+ import { core, hasOwnProperty as hasOwnProp, stringStartsWith } from '../core/core.js';
2
+ import { config, setDefaultAdapters } from '../config/config.js';
3
+ import { BreezeEvent } from '../core/event.js';
4
+ import { assertParam, assertConfig } from '../core/assert-param.js';
5
+ import { DataType } from './data-type.js';
6
+ import { EntityAspect, ComplexAspect } from '../entity/entity-aspect.js';
7
+ import { EntityKey } from '../entity/entity-key.js';
8
+ import { Validator } from '../validation/validate.js';
9
+ import { BreezeEnum } from '../core/enum.js';
10
+ import { DataService } from './data-service.js';
11
+ import { NamingConvention } from './naming-convention.js';
12
+ import { LocalQueryComparisonOptions } from './local-query-comparison-options.js';
13
+ import { defaultPropertyInterceptor } from '../entity/default-property-interceptor.js';
14
+ import { ModelLibraryBackingStoreAdapter } from '../adapters/adapter-model-library-backing-store.js';
15
+ /**
16
+ An instance of the MetadataStore contains all of the metadata about a collection of {@link EntityType}'s.
17
+ MetadataStores may be shared across {@link EntityManager}'s. If an EntityManager is created without an
18
+ explicit MetadataStore, the MetadataStore from the MetadataStore.defaultInstance property will be used.
19
+ */
20
+ export class MetadataStore {
21
+ /** @hidden @internal */
22
+ static __id = 0;
23
+ /** @hidden @internal */
24
+ static ANONTYPE_PREFIX = "_IB_";
25
+ /** The version of any MetadataStores created by this class */
26
+ static metadataVersion = '1.0.5';
27
+ /** An optional name for this MetadataStore, set with {@link MetadataStore.setProperties}.
28
+ {@link MetadataStore.exportMetadata} writes it, but {@link MetadataStore.importMetadata} does not
29
+ restore it. When {@link EntityManager.exportEntities} leaves out the metadata it records this name,
30
+ and {@link EntityManager.importEntities} passes it to {@link ImportConfig.metadataVersionFn}. */
31
+ name;
32
+ /** The {@link DataService}s this store has metadata for, one per service name. Entries are added by
33
+ {@link MetadataStore.fetchMetadata}, {@link MetadataStore.importMetadata} and
34
+ {@link MetadataStore.addDataService}. __Read Only__ */
35
+ dataServices;
36
+ /** The {@link NamingConvention} associated with this MetadataStore. __Read Only__ */
37
+ namingConvention;
38
+ /** The {@link LocalQueryComparisonOptions} associated with this MetadataStore. __Read Only__ */
39
+ localQueryComparisonOptions;
40
+ /** A function that customizes how data property values are serialized, both when entities are
41
+ sent to the server in a save and when {@link EntityManager.exportEntities} writes them. It is called
42
+ as `serializerFn(property, value)`; its return value is used in place of `value`, and returning
43
+ `undefined` leaves the property out. Applies to every type in the store that has no
44
+ `serializerFn` of its own (see {@link EntityType.serializerFn}). */
45
+ serializerFn;
46
+ /**
47
+ An {@link BreezeEvent} that fires after a MetadataStore has completed fetching metadata from a remote service.
48
+
49
+ @eventArgs -
50
+ - metadataStore - The MetadataStore into which the metadata was fetched.
51
+ - dataService - The {@link DataService} that metadata was fetched from.
52
+ - rawMetadata - {Object} The raw metadata returned from the service. (It will have already been processed by this point).
53
+ ```ts
54
+ const ms = myEntityManager.metadataStore;
55
+ ms.metadataFetched.subscribe(args => {
56
+ const metadataStore = args.metadataStore;
57
+ const dataService = args.dataService;
58
+ });
59
+ ```
60
+ @event
61
+ */
62
+ metadataFetched;
63
+ /** @hidden @internal */
64
+ _resourceEntityTypeMap;
65
+ /** @hidden @internal */
66
+ _entityTypeResourceMap;
67
+ /** @hidden @internal key is qualified structuraltype name - value is structuralType. ( structural = entityType or complexType). */
68
+ _structuralTypeMap;
69
+ /** @hidden @internal key is shortName, value is qualified name - does not need to be serialized. */
70
+ _shortNameMap;
71
+ /** @hidden @internal key is either short or qual type name - value is ctor; */
72
+ _ctorRegistry;
73
+ /** @hidden @internal key is entityTypeName; value is array of nav props */
74
+ _incompleteTypeMap;
75
+ /** @hidden @internal */
76
+ _incompleteComplexTypeMap;
77
+ /** @hidden @internal { json: any, stype: StructuralType }[] */
78
+ _deferredTypes;
79
+ /** @hidden @internal */
80
+ _id;
81
+ /** @hidden @internal Whether the comparison options were chosen on the client; they then win over imported metadata. */
82
+ _hasClientLqco;
83
+ /**
84
+ Constructs a new MetadataStore.
85
+
86
+ ```ts
87
+ const ms = new MetadataStore();
88
+ ```
89
+
90
+ The store can then be associated with an EntityManager
91
+ ```ts
92
+ const entityManager = new EntityManager({
93
+ serviceName: "breeze/NorthwindIBModel",
94
+ metadataStore: ms
95
+ });
96
+ ```
97
+
98
+ or for an existing EntityManager
99
+ ```ts
100
+ // Assume em1 is an existing EntityManager
101
+ em1.setProperties({ metadataStore: ms });
102
+ ```
103
+
104
+ @param config - Configuration settings .
105
+ - namingConvention - (default=NamingConvention.defaultInstance) NamingConvention to be used in mapping property names
106
+ between client and server. Uses the NamingConvention.defaultInstance if not specified.
107
+ - localQueryComparisonOptions - (default=LocalQueryComparisonOptions.defaultInstance) The LocalQueryComparisonOptions to be
108
+ used when performing "local queries" in order to match the semantics of queries against a remote service. Options passed
109
+ here, or made the default with setAsDefault(), win over any that imported metadata names.
110
+ - serializerFn - A function that is used to mediate the serialization of instances of this type.
111
+ */
112
+ constructor(config) {
113
+ config = config || {};
114
+ assertConfig(config)
115
+ .whereParam("namingConvention").isOptional().isInstanceOf(NamingConvention).withDefault(NamingConvention.defaultInstance)
116
+ .whereParam("localQueryComparisonOptions").isOptional().isInstanceOf(LocalQueryComparisonOptions).withDefault(LocalQueryComparisonOptions.defaultInstance)
117
+ .whereParam("serializerFn").isOptional().isFunction()
118
+ .whereParam("name").isOptional().isString()
119
+ .applyAll(this);
120
+ this.dataServices = []; // array of dataServices;
121
+ this._resourceEntityTypeMap = {}; // key is resource name - value is qualified entityType name
122
+ this._structuralTypeMap = {}; // key is qualified structuraltype name - value is structuralType. ( structural = entityType or complexType).
123
+ this._shortNameMap = new Map(); // key is shortName, value is qualified name - does not need to be serialized.
124
+ this._ctorRegistry = new Map(); // key is either short or qual type name - value is ctor;
125
+ this._incompleteTypeMap = new Map(); // key is entityTypeName; value is array of nav props
126
+ this._incompleteComplexTypeMap = new Map(); // key is complexTypeName; value is array of complexType props
127
+ this._id = MetadataStore.__id++;
128
+ this.metadataFetched = new BreezeEvent("metadataFetched", this);
129
+ // Comparison options passed here, or made the default with setAsDefault(), are a client-side choice:
130
+ // importMetadata keeps them rather than adopting the ones the metadata names.
131
+ this._hasClientLqco = config.localQueryComparisonOptions != null ||
132
+ LocalQueryComparisonOptions.defaultInstance.name !== LocalQueryComparisonOptions.caseInsensitiveSQL.name;
133
+ }
134
+ /** __Dev Only__ - for use when writing a {@link DataServiceAdapter} or {@link JsonResultsAdapter}.
135
+ Converts a type name as a server sends it, such as the .NET `"Northwind.Models.Customer, Northwind"`,
136
+ into Breeze's qualified form, `"Customer:#Northwind.Models"`. Results are cached; a null or empty
137
+ name is returned unchanged. */
138
+ // needs to be made avail to dataService.xxx files
139
+ static normalizeTypeName = core.memoize(function (rawTypeName) {
140
+ return rawTypeName && MetadataStore.parseTypeName(rawTypeName).typeName;
141
+ });
142
+ // for debugging use the line below instead.
143
+ //ctor.normalizeTypeName = function (rawTypeName) { return parseTypeName(rawTypeName).typeName; };
144
+ /**
145
+ General purpose property set method
146
+
147
+ ```ts
148
+ // assume em1 is an EntityManager containing a number of existing entities.
149
+ em1.metadataStore.setProperties({
150
+ name: "Northwind v6.1.3",
151
+ serializerFn: (prop, value) => prop.isUnmapped ? undefined : value
152
+ });
153
+ ```
154
+ @param config - An object containing the selected properties and values to set.
155
+ */
156
+ setProperties(config) {
157
+ assertConfig(config)
158
+ .whereParam("name").isString().isOptional()
159
+ .whereParam("serializerFn").isFunction().isOptional()
160
+ .applyAll(this);
161
+ }
162
+ /**
163
+ Adds a DataService to this MetadataStore. If a DataService with the same serviceName is already
164
+ in the MetadataStore an exception will be thrown.
165
+ @param dataService - The {@link DataService} to add
166
+ @param shouldOverwrite - (default=false) Permit overwrite of existing DataService rather than throw exception
167
+ */
168
+ addDataService(dataService, shouldOverwrite) {
169
+ assertParam(dataService, "dataService").isInstanceOf(DataService).check();
170
+ assertParam(shouldOverwrite, "shouldOverwrite").isBoolean().isOptional().check();
171
+ let ix = this._getDataServiceIndex(dataService.serviceName);
172
+ if (ix >= 0) {
173
+ if (!!shouldOverwrite) {
174
+ this.dataServices[ix] = dataService;
175
+ }
176
+ else {
177
+ throw new Error("A dataService with this name '" + dataService.serviceName + "' already exists in this MetadataStore");
178
+ }
179
+ }
180
+ else {
181
+ this.dataServices.push(dataService);
182
+ }
183
+ }
184
+ /** @hidden @internal */
185
+ _getDataServiceIndex(serviceName) {
186
+ return core.arrayIndexOf(this.dataServices, function (ds) {
187
+ return ds.serviceName === serviceName;
188
+ });
189
+ }
190
+ /**
191
+ Adds an EntityType or ComplexType to this MetadataStore. Properties can still be added to the
192
+ type afterwards, until the first entity of that type is attached to an EntityManager - after
193
+ that the type is frozen.
194
+ @param stype - The EntityType or ComplexType to add
195
+ */
196
+ addEntityType(stype) {
197
+ let structuralType;
198
+ if (stype instanceof EntityType || stype instanceof ComplexType) {
199
+ structuralType = stype;
200
+ }
201
+ else {
202
+ structuralType = stype.isComplexType ? new ComplexType(stype) : new EntityType(stype);
203
+ }
204
+ // if (!structuralType.isComplexType) { // same as below but isn't a 'type guard'
205
+ if (structuralType instanceof EntityType) {
206
+ if (structuralType.baseTypeName && !structuralType.baseEntityType) {
207
+ let baseEntityType = this._getStructuralType(structuralType.baseTypeName, true);
208
+ // safe cast because we know that baseEntityType must be an EntityType if the structuralType is an EntityType
209
+ structuralType._updateFromBase(baseEntityType);
210
+ }
211
+ if (structuralType.keyProperties.length === 0 && !structuralType.isAbstract) {
212
+ throw new Error("Unable to add " + structuralType.name +
213
+ " to this MetadataStore. An EntityType must have at least one property designated as a key property - See the 'DataProperty.isPartOfKey' property.");
214
+ }
215
+ }
216
+ structuralType.metadataStore = this;
217
+ // don't register anon types
218
+ if (!structuralType.isAnonymous) {
219
+ if (this._structuralTypeMap[structuralType.name]) {
220
+ throw new Error("Type " + structuralType.name + " already exists in this MetadataStore.");
221
+ }
222
+ this._structuralTypeMap[structuralType.name] = structuralType;
223
+ this._shortNameMap.set(structuralType.shortName, structuralType.name);
224
+ }
225
+ structuralType.getProperties().forEach(p => {
226
+ structuralType._updateNames(p);
227
+ if (!p.isUnmapped) {
228
+ structuralType._mappedPropertiesCount++;
229
+ }
230
+ });
231
+ structuralType._updateCps();
232
+ // 'isEntityType' is a type guard
233
+ if (structuralType instanceof EntityType) {
234
+ structuralType._updateNps();
235
+ // give the type it's base's resource name if it doesn't have its own.
236
+ let defResourceName = structuralType.defaultResourceName || (structuralType.baseEntityType && structuralType.baseEntityType.defaultResourceName);
237
+ if (defResourceName && !this.getEntityTypeNameForResourceName(defResourceName)) {
238
+ this.setEntityTypeForResourceName(defResourceName, structuralType.name);
239
+ }
240
+ structuralType.defaultResourceName = defResourceName;
241
+ // check if this structural type's name, short version or qualified version has a registered ctor.
242
+ structuralType.getCtor();
243
+ }
244
+ }
245
+ /**
246
+ Exports this MetadataStore to a serialized string appropriate for local storage. This operation is also called
247
+ internally when exporting an EntityManager.
248
+ ```ts
249
+ // assume ms is a previously created MetadataStore
250
+ const metadataAsString = ms.exportMetadata();
251
+ window.localStorage.setItem("metadata", metadataAsString);
252
+ // and later, usually in a different session imported
253
+ const metadataFromStorage = window.localStorage.getItem("metadata");
254
+ const newMetadataStore = new MetadataStore();
255
+ newMetadataStore.importMetadata(metadataFromStorage);
256
+ ```
257
+ @returns A serialized version of this MetadataStore that may be stored locally and later restored.
258
+ */
259
+ exportMetadata() {
260
+ let result = JSON.stringify({
261
+ "metadataVersion": MetadataStore.metadataVersion,
262
+ "name": this.name,
263
+ "namingConvention": this.namingConvention.name,
264
+ "localQueryComparisonOptions": this.localQueryComparisonOptions.name,
265
+ "dataServices": this.dataServices,
266
+ "structuralTypes": core.objectMap(this._structuralTypeMap),
267
+ "resourceEntityTypeMap": this._resourceEntityTypeMap
268
+ }, null, config.stringifyPad);
269
+ return result;
270
+ }
271
+ /**
272
+ Imports a previously exported serialized MetadataStore into this MetadataStore.
273
+
274
+ ```ts
275
+ // assume ms is a previously created MetadataStore
276
+ const metadataAsString = ms.exportMetadata();
277
+ window.localStorage.setItem("metadata", metadataAsString);
278
+ // and later, usually in a different session
279
+ const metadataFromStorage = window.localStorage.getItem("metadata");
280
+ const newMetadataStore = new MetadataStore();
281
+ newMetadataStore.importMetadata(metadataFromStorage);
282
+ ```
283
+
284
+ A type that is already in this store is left as it is unless 'allowMerge' is set, so importing the same metadata
285
+ twice is harmless. A type that is not in the store is created, with or without 'allowMerge', and its metadata must
286
+ include 'dataProperties'. The 'localQueryComparisonOptions' the metadata names are adopted only by an empty store
287
+ whose own options were not chosen on the client (see the constructor).
288
+ @param exportedMetadata - A previously exported MetadataStore.
289
+ @param allowMerge - Allows custom metadata to be merged into existing metadata types.
290
+ @returns This MetadataStore.
291
+ @chainable
292
+ */
293
+ importMetadata(exportedMetadata, allowMerge = false) {
294
+ assertParam(allowMerge, "allowMerge").isOptional().isBoolean().check();
295
+ this._deferredTypes = new Map();
296
+ // insure that we don't mutate incoming exportedMetadata ( if its an object)
297
+ let metadataAsString = (typeof (exportedMetadata) === "string") ? exportedMetadata : JSON.stringify(exportedMetadata);
298
+ const metadataJson = JSON.parse(metadataAsString);
299
+ // CSDL (the OData / EDMX format) has a schema property. 2.x parsed it; v3 does not, and
300
+ // without this check it imported silently as nothing and failed much later.
301
+ if (metadataJson && metadataJson.schema && !metadataJson.structuralTypes) {
302
+ throw new Error("This looks like CSDL (OData / EDMX) metadata, which breeze-client 3 does not read. " +
303
+ "Supply Breeze native JSON metadata instead - see Migrating from 2.x in the Breeze docs.");
304
+ }
305
+ let json = metadataJson;
306
+ if (json.metadataVersion && json.metadataVersion !== MetadataStore.metadataVersion) {
307
+ let msg = core.formatString("Cannot import metadata with a different 'metadataVersion' (%1) than the current 'MetadataStore.metadataVersion' (%2) ", json.metadataVersion, MetadataStore.metadataVersion);
308
+ throw new Error(msg);
309
+ }
310
+ let ncName = json.namingConvention;
311
+ // Comparison options chosen on the client win; the metadata's apply only to a store without its own.
312
+ let lqcoName = this._hasClientLqco ? undefined : json.localQueryComparisonOptions;
313
+ if (this.isEmpty()) {
314
+ this.namingConvention = config._fetchObject(NamingConvention, ncName) || this.namingConvention;
315
+ this.localQueryComparisonOptions = (lqcoName && config._fetchObject(LocalQueryComparisonOptions, lqcoName)) || this.localQueryComparisonOptions;
316
+ }
317
+ else {
318
+ if (ncName && this.namingConvention.name !== ncName) {
319
+ throw new Error("Cannot import metadata with a different 'namingConvention' from the current MetadataStore");
320
+ }
321
+ if (lqcoName && this.localQueryComparisonOptions.name !== lqcoName) {
322
+ throw new Error("Cannot import metadata with different 'localQueryComparisonOptions' from the current MetadataStore");
323
+ }
324
+ }
325
+ //noinspection JSHint
326
+ json.dataServices && json.dataServices.forEach((ds) => {
327
+ let realDs = DataService.fromJSON(ds);
328
+ this.addDataService(realDs, true);
329
+ });
330
+ json.structuralTypes && json.structuralTypes.forEach((stype) => {
331
+ structuralTypeFromJson(this, stype, allowMerge);
332
+ });
333
+ core.extend(this._resourceEntityTypeMap, json.resourceEntityTypeMap);
334
+ // the serialized form is a plain object; the in-memory form is a Map
335
+ if (json.incompleteTypeMap) {
336
+ Object.entries(json.incompleteTypeMap).forEach(([k, v]) => this._incompleteTypeMap.set(k, v));
337
+ }
338
+ return this;
339
+ }
340
+ /**
341
+ Creates a new MetadataStore from a previously exported serialized MetadataStore
342
+ ```ts
343
+ // assume ms is a previously created MetadataStore
344
+ const metadataAsString = ms.exportMetadata();
345
+ window.localStorage.setItem("metadata", metadataAsString);
346
+ // and later, usually in a different session
347
+ const metadataFromStorage = window.localStorage.getItem("metadata");
348
+ const newMetadataStore = MetadataStore.importMetadata(metadataFromStorage);
349
+ ```
350
+ @param exportedString - A previously exported MetadataStore.
351
+ @returns A new MetadataStore.
352
+ */
353
+ static importMetadata(exportedString) {
354
+ let ms = new MetadataStore();
355
+ ms.importMetadata(exportedString);
356
+ return ms;
357
+ }
358
+ /**
359
+ Returns whether Metadata has been retrieved for a specified service name.
360
+ ```ts
361
+ // Assume em1 is an existing EntityManager.
362
+ if (!em1.metadataStore.hasMetadataFor("breeze/NorthwindIBModel")) {
363
+ // do something interesting
364
+ }
365
+ ```
366
+ @param serviceName - The service name.
367
+ @returns Whether metadata has already been retrieved for the specified service name.
368
+ */
369
+ hasMetadataFor(serviceName) {
370
+ return !!this.getDataService(serviceName);
371
+ }
372
+ /**
373
+ Returns the DataService for a specified service name
374
+ ```ts
375
+ // Assume em1 is an existing EntityManager.
376
+ const ds = em1.metadataStore.getDataService("breeze/NorthwindIBModel");
377
+ const adapterName = ds.adapterName; // may be null
378
+ ```
379
+ @param serviceName - The service name.
380
+ @returns The DataService with the specified name.
381
+ */
382
+ getDataService(serviceName) {
383
+ assertParam(serviceName, "serviceName").isString().check();
384
+ serviceName = DataService._normalizeServiceName(serviceName);
385
+ return core.arrayFirst(this.dataServices, function (ds) {
386
+ return ds.serviceName === serviceName;
387
+ });
388
+ }
389
+ /**
390
+ Fetches the metadata for a specified 'service'. This method is automatically called
391
+ internally by an EntityManager before its first query against a new service. __Async__
392
+
393
+ Usually you will not actually process the results of a fetchMetadata call directly, but will instead
394
+ ask for the metadata from the EntityManager after the fetchMetadata call returns.
395
+ ```ts
396
+ const ms = new MetadataStore();
397
+ // or more commonly
398
+ // const ms = anEntityManager.metadataStore;
399
+ const rawMetadata = await ms.fetchMetadata("breeze/NorthwindIBModel");
400
+ // do something with the metadata
401
+ ```
402
+ @param dataService - Either a DataService or just the name of the DataService to fetch metadata for.
403
+ @param callback - Deprecated. Function called on success.
404
+ @param errorCallback - Deprecated. Function called on failure.
405
+ @returns Promise
406
+ */
407
+ fetchMetadata(dataService, callback, errorCallback) {
408
+ try {
409
+ assertParam(dataService, "dataService").isString().or().isInstanceOf(DataService).check();
410
+ assertParam(callback, "callback").isFunction().isOptional().check();
411
+ assertParam(errorCallback, "errorCallback").isFunction().isOptional().check();
412
+ if (typeof dataService === "string") {
413
+ // use the dataService with a matching name or create a new one.
414
+ dataService = this.getDataService(dataService) || new DataService({ serviceName: dataService });
415
+ }
416
+ dataService = DataService.resolve([dataService]);
417
+ if (this.hasMetadataFor(dataService.serviceName)) {
418
+ throw new Error("Metadata for a specific serviceName may only be fetched once per MetadataStore. ServiceName: " + dataService.serviceName);
419
+ }
420
+ return dataService.adapterInstance.fetchMetadata(this, dataService).then((rawMetadata) => {
421
+ this.metadataFetched.publish({ metadataStore: this, dataService: dataService, rawMetadata: rawMetadata });
422
+ if (callback)
423
+ callback(rawMetadata);
424
+ return Promise.resolve(rawMetadata);
425
+ }, function (error) {
426
+ if (errorCallback)
427
+ errorCallback(error);
428
+ return Promise.reject(error);
429
+ });
430
+ }
431
+ catch (e) {
432
+ return Promise.reject(e);
433
+ }
434
+ }
435
+ // TODO: strongly type interceptor below.
436
+ /**
437
+ Used to register a constructor for an EntityType that is not known via standard Metadata discovery;
438
+ i.e. an unmapped type.
439
+ @param entityCtor - The constructor function for the 'unmapped' type.
440
+ @param interceptor - An interceptor function
441
+ */
442
+ trackUnmappedType(entityCtor, interceptor) {
443
+ assertParam(entityCtor, "entityCtor").isFunction().check();
444
+ assertParam(interceptor, "interceptor").isFunction().isOptional().check();
445
+ // TODO: think about adding this to the MetadataStore.
446
+ let entityType = new EntityType(this);
447
+ entityType._setCtor(entityCtor, interceptor);
448
+ }
449
+ /**
450
+ Provides a mechanism to register a 'custom' constructor to be used when creating new instances
451
+ of the specified entity type. If this call is not made, a default constructor is created for
452
+ the entity as needed.
453
+ This call may be made before or after the corresponding EntityType has been discovered via
454
+ Metadata discovery.
455
+ ```ts
456
+ class Customer {
457
+ miscData = "asdf"; // an unmapped property
458
+ doFoo() {
459
+ // ...
460
+ }
461
+ }
462
+ // assume em1 is a preexisting EntityManager;
463
+ em1.metadataStore.registerEntityTypeCtor("Customer", Customer);
464
+ // any queries or createEntity calls from this point on will call the Customer constructor
465
+ // registered above.
466
+ ```
467
+ @param structuralTypeName - The name of the EntityType or ComplexType.
468
+ @param aCtor - The constructor for this EntityType or ComplexType; may be null if all you want to do is set the next parameter.
469
+ @param initFn - A function or the name of a function on the entity that is to be executed immediately after the entity has been created
470
+ and populated with any initial values. Called with 'initFn(entity)'
471
+ @param noTrackingFn - A function that is executed immediately after a noTracking entity has been created and whose return
472
+ value will be used in place of the noTracking entity.
473
+ */
474
+ registerEntityTypeCtor(structuralTypeName, aCtor, initFn, noTrackingFn) {
475
+ assertParam(structuralTypeName, "structuralTypeName").isString().check();
476
+ assertParam(aCtor, "aCtor").isFunction().isOptional().check();
477
+ assertParam(initFn, "initFn").isOptional().isFunction().or().isString().check();
478
+ assertParam(noTrackingFn, "noTrackingFn").isOptional().isFunction().check();
479
+ let qualifiedTypeName = getQualifiedTypeName(this, structuralTypeName, false);
480
+ let typeName = qualifiedTypeName || structuralTypeName;
481
+ if (aCtor) {
482
+ if (aCtor._$typeName && aCtor._$typeName !== typeName) {
483
+ console.warn("Registering a constructor for " + typeName + " that is already used for " + aCtor._$typeName + ".");
484
+ }
485
+ aCtor._$typeName = typeName;
486
+ }
487
+ this._ctorRegistry.set(typeName, { ctor: aCtor, initFn: initFn, noTrackingFn: noTrackingFn });
488
+ if (qualifiedTypeName) {
489
+ let stype = this._structuralTypeMap[qualifiedTypeName];
490
+ stype && stype.getCtor(true); // this will complete the registration if avail now.
491
+ }
492
+ }
493
+ /**
494
+ Returns whether this MetadataStore contains any metadata yet.
495
+ ```ts
496
+ // assume em1 is a preexisting EntityManager;
497
+ if (em1.metadataStore.isEmpty()) {
498
+ // do something interesting
499
+ }
500
+ ```
501
+ */
502
+ isEmpty() {
503
+ return core.isEmpty(this._structuralTypeMap);
504
+ }
505
+ /**
506
+ Returns an {@link EntityType} given a registered class or a type name, or null if there is none
507
+ and `okIfNotFound` is true.
508
+ ```ts
509
+ // assume em1 is a preexisting EntityManager, and OrderDetail is registered with its store
510
+ const odType = em1.metadataStore.getAsEntityType(OrderDetail);
511
+ const sameType = em1.metadataStore.getAsEntityType("OrderDetail");
512
+ ```
513
+
514
+ or to throw an error if the type is not found
515
+ ```ts
516
+ const badType = em1.metadataStore.getAsEntityType("Foo", false);
517
+ // badType will not get set and an exception will be thrown.
518
+ ```
519
+ @param type - A class registered with {@link MetadataStore.registerEntityTypeCtor}, or a type
520
+ name: either the fully qualified name or a short name. If a short name is specified and multiple
521
+ types share that same short name an exception will be thrown.
522
+ @param okIfNotFound - (default=false) Whether to return null, rather than throw, if the EntityType is not found.
523
+ @returns The EntityType, or null if it is not found and `okIfNotFound` is true.
524
+ */
525
+ getAsEntityType(type, okIfNotFound = false) {
526
+ // A class stands for its type name, resolved against this store: a class can be registered
527
+ // with more than one.
528
+ const typeName = typeof type === "function" ? entityTypeForCtor(type).name : type;
529
+ const st = this._getStructuralType(typeName, okIfNotFound);
530
+ if (st instanceof EntityType) {
531
+ return st;
532
+ }
533
+ else if (okIfNotFound) {
534
+ return null;
535
+ }
536
+ else {
537
+ let msg = core.formatString("Unable to locate an 'EntityType' by the name: '%1'. Be sure to execute a query or call fetchMetadata first.", typeName);
538
+ throw new Error(msg);
539
+ }
540
+ }
541
+ /**
542
+ Returns an {@link EntityType} or null given its name.
543
+ ```ts
544
+ // assume em1 is a preexisting EntityManager
545
+ const locType = em1.metadataStore.getAsComplexType("Location");
546
+ ```
547
+
548
+ or to throw an error if the type is not found
549
+ ```ts
550
+ const badType = em1.metadataStore.getAsComplexType("Foo", false);
551
+ // badType will not get set and an exception will be thrown.
552
+ ```
553
+ @param typeName - Either the fully qualified name or a short name may be used. If a short name is specified and multiple types share
554
+ that same short name an exception will be thrown.
555
+ @param okIfNotFound - (default=false) Whether to throw an error if the specified EntityType is not found.
556
+ @returns The EntityType. ComplexType or 'null' if not not found.
557
+ */
558
+ getAsComplexType(typeName, okIfNotFound = false) {
559
+ const st = this._getStructuralType(typeName, okIfNotFound);
560
+ if (st instanceof ComplexType) {
561
+ return st;
562
+ }
563
+ else if (okIfNotFound) {
564
+ return null;
565
+ }
566
+ else {
567
+ let msg = core.formatString("Unable to locate an 'ComplexType' by the name: '%1'. Be sure to execute a query or call fetchMetadata first.", typeName);
568
+ throw new Error(msg);
569
+ }
570
+ }
571
+ /**
572
+ Returns an {@link EntityType} or a {@link ComplexType} given its name.
573
+ @deprecated Misleading name: it returns an EntityType *or* a ComplexType. Use
574
+ {@link MetadataStore.getAsEntityType} or {@link MetadataStore.getAsComplexType} when you know
575
+ which kind you expect, and {@link MetadataStore.getStructuralType} when either will do.
576
+ @param typeName - Either the fully qualified name or a short name may be used. If a short name is specified and multiple types share
577
+ that same short name an exception will be thrown.
578
+ @param okIfNotFound - (default=false) Whether to throw an error if the specified EntityType is not found.
579
+ @returns The EntityType. ComplexType or 'null' if not not found.
580
+ */
581
+ getEntityType(typeName, okIfNotFound = false) {
582
+ return this._getStructuralType(typeName, okIfNotFound);
583
+ }
584
+ /**
585
+ Returns an {@link EntityType} or a {@link ComplexType} given its name.
586
+ ```ts
587
+ // assume em1 is a preexisting EntityManager
588
+ const odType = em1.metadataStore.getStructuralType("OrderDetail");
589
+ ```
590
+
591
+ or to throw an error if the type is not found
592
+ ```ts
593
+ const badType = em1.metadataStore.getStructuralType("Foo", false);
594
+ // badType will not get set and an exception will be thrown.
595
+ ```
596
+ Prefer {@link MetadataStore.getAsEntityType} or {@link MetadataStore.getAsComplexType} when you
597
+ know which kind you expect. This is the lookup for when you do not.
598
+ @param typeName - Either the fully qualified name or a short name may be used. If a short name is specified and multiple types share
599
+ that same short name an exception will be thrown.
600
+ @param okIfNotFound - (default=false) Whether to throw an error if the specified EntityType is not found.
601
+ @returns The EntityType. ComplexType or 'null' if not not found.
602
+ */
603
+ getStructuralType(typeName, okIfNotFound = false) {
604
+ assertParam(typeName, "typeName").isString().check();
605
+ assertParam(okIfNotFound, "okIfNotFound").isBoolean().isOptional().check(false);
606
+ return this._getStructuralType(typeName, okIfNotFound);
607
+ }
608
+ /** @hidden @internal */
609
+ _getStructuralType(typeName, okIfNotFound = false) {
610
+ let qualTypeName = getQualifiedTypeName(this, typeName, false);
611
+ let type = qualTypeName ? this._structuralTypeMap[qualTypeName] : undefined;
612
+ if (!type) {
613
+ if (okIfNotFound)
614
+ return null;
615
+ let msg = core.formatString("Unable to locate a 'Type' by the name: '%1'. Be sure to execute a query or call fetchMetadata first.", typeName);
616
+ throw new Error(msg);
617
+ }
618
+ return type;
619
+ }
620
+ /**
621
+ Returns an array containing all of the {@link EntityType}s or {@link ComplexType}s in this MetadataStore.
622
+ ```ts
623
+ // assume em1 is a preexisting EntityManager
624
+ const allTypes = em1.metadataStore.getEntityTypes();
625
+ ```
626
+ */
627
+ getEntityTypes() {
628
+ return getTypesFromMap(this._structuralTypeMap);
629
+ }
630
+ /**
631
+ Returns the navigation properties whose target {@link EntityType} has not been added to this store
632
+ yet, as one array per missing type. An empty result means every navigation property has been
633
+ resolved; useful for checking metadata that is built by hand or imported in pieces.
634
+ */
635
+ getIncompleteNavigationProperties() {
636
+ return Array.from(this._incompleteTypeMap.values());
637
+ }
638
+ /**
639
+ Returns a fully qualified entityTypeName for a specified resource name. The reverse of this operation
640
+ can be obtained via the {@link EntityType.defaultResourceName} property
641
+ */
642
+ getEntityTypeNameForResourceName(resourceName) {
643
+ assertParam(resourceName, "resourceName").isString().check();
644
+ return this._resourceEntityTypeMap[resourceName];
645
+ }
646
+ /**
647
+ Associates a resourceName with an entityType.
648
+
649
+ This method is only needed in those cases where multiple resources return the same
650
+ entityType. In this case Metadata discovery will only determine a single resource name for
651
+ each entityType.
652
+ @param resourceName - The resource name
653
+ @param entityTypeOrName - If passing a string either the fully qualified name or a short name may be used. If a short name is specified and multiple types share
654
+ that same short name an exception will be thrown. If the entityType has not yet been discovered then a fully qualified name must be used.
655
+ */
656
+ setEntityTypeForResourceName(resourceName, entityTypeOrName) {
657
+ assertParam(resourceName, "resourceName").isString().check();
658
+ assertParam(entityTypeOrName, "entityTypeOrName").isInstanceOf(EntityType).or().isString().check();
659
+ let entityTypeName;
660
+ if (entityTypeOrName instanceof EntityType) {
661
+ entityTypeName = entityTypeOrName.name;
662
+ }
663
+ else {
664
+ entityTypeName = getQualifiedTypeName(this, entityTypeOrName, true);
665
+ }
666
+ this._resourceEntityTypeMap[resourceName] = entityTypeName;
667
+ let entityType = this._getStructuralType(entityTypeName, true);
668
+ if (entityType && entityType instanceof EntityType && !entityType.defaultResourceName) {
669
+ entityType.defaultResourceName = resourceName;
670
+ }
671
+ }
672
+ /** __Dev Only__ - for use when creating a new MetadataParserAdapter */
673
+ static parseTypeName(entityTypeName) {
674
+ let typeParts = entityTypeName.split(":#");
675
+ if (typeParts.length > 1) {
676
+ return MetadataStore.makeTypeHash(typeParts[0], typeParts[1]);
677
+ }
678
+ if (stringStartsWith(entityTypeName, MetadataStore.ANONTYPE_PREFIX)) {
679
+ let typeHash = MetadataStore.makeTypeHash(entityTypeName);
680
+ typeHash.isAnonymous = true;
681
+ return typeHash;
682
+ }
683
+ let entityTypeNameNoAssembly = entityTypeName.split(",")[0];
684
+ typeParts = entityTypeNameNoAssembly.split(".");
685
+ if (typeParts.length > 1) {
686
+ let shortName = typeParts[typeParts.length - 1];
687
+ let namespaceParts = typeParts.slice(0, typeParts.length - 1);
688
+ let ns = namespaceParts.join(".");
689
+ return MetadataStore.makeTypeHash(shortName, ns);
690
+ }
691
+ else {
692
+ return MetadataStore.makeTypeHash(entityTypeName);
693
+ }
694
+ }
695
+ /** __Dev Only__ - for use when creating a new MetadataParserAdapter */
696
+ static makeTypeHash(shortName, ns) {
697
+ return {
698
+ /** The unqualified name, such as `"Customer"`. */
699
+ shortTypeName: shortName,
700
+ /** The namespace, such as `"Northwind.Models"`; undefined if there is none. */
701
+ namespace: ns,
702
+ /** The qualified name, such as `"Customer:#Northwind.Models"`. */
703
+ typeName: qualifyTypeName(shortName, ns)
704
+ };
705
+ }
706
+ // protected methods
707
+ /** @hidden @internal */
708
+ _checkEntityType(entity) {
709
+ if (entity.entityType)
710
+ return;
711
+ let typeName = entity.prototype._$typeName;
712
+ if (!typeName) {
713
+ throw new Error("This entity has not been registered. See the MetadataStore.registerEntityTypeCtor method");
714
+ }
715
+ // we know that it is an EntityType ( as opposed to a ComplexType)
716
+ let entityType = this._getStructuralType(typeName);
717
+ if (entityType) {
718
+ entity.entityType = entityType;
719
+ }
720
+ }
721
+ }
722
+ MetadataStore.prototype._$typeName = "MetadataStore";
723
+ BreezeEvent.bubbleEvent(MetadataStore.prototype);
724
+ // The model library Breeze falls back to when none is registered (see default-adapters.ts).
725
+ // Installed here because a MetadataStore needs one even in a bundle with no EntityManager, and
726
+ // this module is in every bundle that has entity types. A getter, because the adapter's module
727
+ // imports this one: while this module loads, the adapter class may not exist yet.
728
+ setDefaultAdapters({ modelLibrary: { get ctor() { return ModelLibraryBackingStoreAdapter; } } });
729
+ function getTypesFromMap(typeMap) {
730
+ let types = [];
731
+ for (let key in typeMap) {
732
+ let value = typeMap[key];
733
+ // skip 'shortName' entries
734
+ if (key === value.name) {
735
+ types.push(typeMap[key]);
736
+ }
737
+ }
738
+ return types;
739
+ }
740
+ function structuralTypeFromJson(metadataStore, json, allowMerge) {
741
+ let typeName = qualifyTypeName(json.shortName, json.namespace);
742
+ let stype = metadataStore._getStructuralType(typeName, true);
743
+ if (stype) {
744
+ if (allowMerge) {
745
+ return mergeStructuralType(stype, json);
746
+ }
747
+ else {
748
+ // allow it but don't replace anything.
749
+ return stype;
750
+ }
751
+ }
752
+ if (!json.dataProperties) {
753
+ // Creating the type needs its properties. A cut-down custom-metadata object for a type that is not in the store
754
+ // used to fail here with a TypeError.
755
+ const hint = allowMerge ? " allowMerge only merges into types that are already in the store." : "";
756
+ throw new Error("Unable to import type '" + typeName + "': it is not in this MetadataStore and its metadata has no 'dataProperties'." + hint);
757
+ }
758
+ let config = {
759
+ shortName: json.shortName,
760
+ namespace: json.namespace,
761
+ isAbstract: json.isAbstract,
762
+ autoGeneratedKeyType: AutoGeneratedKeyType.fromName(json.autoGeneratedKeyType),
763
+ defaultResourceName: json.defaultResourceName,
764
+ custom: json.custom
765
+ };
766
+ stype = json.isComplexType ? new ComplexType(config) : new EntityType(config);
767
+ // baseType may not have been imported yet so we need to defer handling this type until later.
768
+ if (json.baseTypeName && stype instanceof EntityType) {
769
+ stype.baseTypeName = json.baseTypeName;
770
+ let baseEntityType = metadataStore._getStructuralType(json.baseTypeName, true);
771
+ if (baseEntityType) {
772
+ completeStructuralTypeFromJson(metadataStore, json, stype);
773
+ }
774
+ else {
775
+ core.getMapArray(metadataStore._deferredTypes, json.baseTypeName).push({ json: json, stype: stype });
776
+ }
777
+ }
778
+ else {
779
+ completeStructuralTypeFromJson(metadataStore, json, stype);
780
+ }
781
+ // stype may or may not have been added to the metadataStore at this point.
782
+ return stype;
783
+ }
784
+ function mergeStructuralType(stype, json) {
785
+ if (json.custom) {
786
+ stype.custom = json.custom;
787
+ }
788
+ mergeProps(stype, json.dataProperties);
789
+ mergeProps(stype, json.navigationProperties);
790
+ return stype;
791
+ }
792
+ function mergeProps(stype, jsonProps) {
793
+ if (!jsonProps)
794
+ return;
795
+ jsonProps.forEach((jsonProp) => {
796
+ let propName = jsonProp.name;
797
+ if (!propName) {
798
+ if (jsonProp.nameOnServer) {
799
+ propName = stype.metadataStore.namingConvention.serverPropertyNameToClient(jsonProp.nameOnServer, {});
800
+ }
801
+ else {
802
+ // backslash-quote works around compiler bug
803
+ const msg = "Unable to complete \'importMetadata\' - cannot locate a \'name\' or \'nameOnServer\' for one of the imported property nodes";
804
+ throw new Error(msg);
805
+ }
806
+ }
807
+ if (jsonProp.custom) {
808
+ let prop = stype.getProperty(propName, true);
809
+ prop.custom = jsonProp.custom;
810
+ }
811
+ });
812
+ }
813
+ function completeStructuralTypeFromJson(metadataStore, json, stype) {
814
+ // validators from baseType work because validation walks thru base types
815
+ // so no need to copy down.
816
+ if (json.validators) {
817
+ stype.validators = json.validators.map(Validator.fromJSON);
818
+ }
819
+ json.dataProperties.forEach(function (dp) {
820
+ stype._addPropertyCore(DataProperty.fromJSON(dp));
821
+ });
822
+ let isEntityType = !json.isComplexType;
823
+ if (isEntityType) {
824
+ //noinspection JSHint
825
+ json.navigationProperties && json.navigationProperties.forEach(function (np) {
826
+ stype._addPropertyCore(NavigationProperty.fromJSON(np));
827
+ });
828
+ }
829
+ metadataStore.addEntityType(stype);
830
+ let deferredTypes = metadataStore._deferredTypes;
831
+ let deferrals = deferredTypes.get(stype.name);
832
+ if (deferrals) {
833
+ deferrals.forEach(function (d) {
834
+ completeStructuralTypeFromJson(metadataStore, d.json, d.stype);
835
+ });
836
+ deferredTypes.delete(stype.name);
837
+ }
838
+ }
839
+ function getQualifiedTypeName(metadataStore, structTypeName, throwIfNotFound) {
840
+ if (isQualifiedTypeName(structTypeName))
841
+ return structTypeName;
842
+ let result = metadataStore._shortNameMap.get(structTypeName);
843
+ if (!result && throwIfNotFound) {
844
+ throw new Error("Unable to locate 'entityTypeName' of: " + structTypeName);
845
+ }
846
+ return result;
847
+ }
848
+ /** Container for all of the metadata about a specific type of Entity.
849
+ */
850
+ export class EntityType {
851
+ /** @hidden @internal */
852
+ static __nextAnonIx = 0;
853
+ /** Always false for an EntityType. */
854
+ isComplexType = false;
855
+ /** The {@link MetadataStore} that contains this EntityType. __Read Only__ */
856
+ metadataStore;
857
+ /** The DataProperties (see {@link DataProperty} associated with this EntityType. __Read Only__ */
858
+ dataProperties;
859
+ /** The NavigationProperties (see {@link NavigationProperty} associated with this EntityType. __Read Only__ */
860
+ navigationProperties;
861
+ /**
862
+ The DataProperties associated with this EntityType that make up it's {@link EntityKey}. __Read Only__ */
863
+ keyProperties;
864
+ /** The DataProperties associated with this EntityType that are foreign key properties. __Read Only__ */
865
+ foreignKeyProperties;
866
+ /** The foreign key DataProperties on *other* EntityTypes that refer to this EntityType. When an
867
+ entity's key changes, such as when a temporary key is replaced on save, Breeze uses these to update
868
+ the foreign keys of cached entities it cannot reach through a navigation property. __Read Only__ */
869
+ inverseForeignKeyProperties;
870
+ /** The DataProperties associated with this EntityType that are concurrency properties. __Read Only__ */
871
+ concurrencyProperties;
872
+ /** The DataProperties for this EntityType that contain instances of a {@link ComplexType}. __Read Only__ */
873
+ complexProperties;
874
+ /** The DataProperties associated with this EntityType that are not mapped to any backend datastore. These are effectively free standing
875
+ properties. __Read Only__ */
876
+ unmappedProperties;
877
+ /** The fully qualified name of this EntityType. __Read Only__ */
878
+ name;
879
+ /** The short, unqualified, name for this EntityType. __Read Only__ */
880
+ shortName;
881
+ /** The namespace for this EntityType. __Read Only__ */
882
+ namespace;
883
+ /** The name of this EntityType's base EntityType (if any) */
884
+ baseTypeName;
885
+ /** The base EntityType (if any) for this EntityType. __Read Only__ */
886
+ baseEntityType;
887
+ /** The EntityTypes that derive directly from this one. See {@link EntityType.getSelfAndSubtypes} for
888
+ the whole hierarchy. __Read Only__ */
889
+ subtypes;
890
+ /** Whether this EntityType is abstract. __Read Only__ */
891
+ isAbstract;
892
+ /** Whether this EntityType is anonymous. Anonymous types will never be communicated to or from the server. They are purely for
893
+ client side use and are given an automatically generated name. __Read Only__ */
894
+ isAnonymous;
895
+ /** Whether this EntityType has been 'frozen'. EntityTypes become frozen after the first instance
896
+ of that type has been created and attached to an EntityManager. */
897
+ isFrozen;
898
+ /** The {@link AutoGeneratedKeyType} for this EntityType. __Read Only__ */
899
+ autoGeneratedKeyType;
900
+ /** The default resource name associated with this EntityType. An EntityType may be queried via a variety of 'resource names' but this one
901
+ is used as the default when no resource name is provided. This will occur when calling {@link EntityAspect.loadNavigationProperty}
902
+ or when executing any {@link EntityQuery} that was created via an {@link EntityKey}. __Read Only__ */
903
+ defaultResourceName;
904
+ /** A function that is used to customize the serialization of any EntityProperties of this type. */
905
+ serializerFn;
906
+ /** A free form object that can be used to define any custom metadata for this EntityType. __Read Only__ */
907
+ custom;
908
+ /** The entity level validators associated with this EntityType. Validators can be added and
909
+ removed from this collection. __Read Only__. */
910
+ validators;
911
+ /** Not used by breeze-client 3: always an empty array. In 2.x the CSDL metadata parser recorded
912
+ data types it did not recognize here; v3 reports them with `console.warn` instead. */
913
+ warnings;
914
+ /** The function, or the name of a method on the entity, that is called with each entity of this type
915
+ once it has been created and populated, whether by {@link EntityType.createEntity} or from query
916
+ results. A base type's `initFn` runs first. Set from the `initFn` argument of
917
+ {@link MetadataStore.registerEntityTypeCtor}; applications set it there rather than here. */
918
+ initFn;
919
+ /** The function that a query with {@link EntityQuery.noTracking} enabled calls for each result of this
920
+ type, as `noTrackingFn(node, entityType)`; its return value replaces the result. Set from the
921
+ `noTrackingFn` argument of {@link MetadataStore.registerEntityTypeCtor}; applications set it there
922
+ rather than here. */
923
+ noTrackingFn;
924
+ /** @hidden @internal */
925
+ _extra;
926
+ /** @hidden @internal */
927
+ _ctor;
928
+ /** @hidden @internal */
929
+ _mappedPropertiesCount;
930
+ /**
931
+ @deprecated Use {@link EntityType.getCtor} instead.
932
+ */
933
+ getEntityCtor = this.getCtor;
934
+ /** @hidden @internal */
935
+ static qualifyTypeName = qualifyTypeName;
936
+ /** EntityType constructor
937
+ ```ts
938
+ const entityType = new EntityType({
939
+ shortName: "person",
940
+ namespace: "myAppNamespace"
941
+ });
942
+ ```
943
+ @param config - Configuration settings or a MetadataStore. If this parameter is just a MetadataStore
944
+ then what will be created is an 'anonymous' type that will never be communicated to or from the server. It is purely for
945
+ client side use and will be given an automatically generated name. Normally, however, you will use a configuration object.
946
+ */
947
+ constructor(config) {
948
+ if (arguments.length > 1) {
949
+ throw new Error("The EntityType ctor has a single argument that is either a 'MetadataStore' or a configuration object.");
950
+ }
951
+ // let etConfig = <EntityTypeConfig> <any> undefined;
952
+ let etConfig = undefined;
953
+ if (config._$typeName === "MetadataStore") {
954
+ this.metadataStore = config;
955
+ this.shortName = "Anon_" + (++EntityType.__nextAnonIx);
956
+ this.namespace = "";
957
+ this.isAnonymous = true;
958
+ // etConfig = undefined;
959
+ }
960
+ else {
961
+ etConfig = config;
962
+ assertConfig(config)
963
+ .whereParam("shortName").isNonEmptyString()
964
+ .whereParam("namespace").isString().isOptional().withDefault("")
965
+ .whereParam("baseTypeName").isString().isOptional()
966
+ .whereParam("isAbstract").isBoolean().isOptional().withDefault(false)
967
+ .whereParam("autoGeneratedKeyType").isEnumOf(AutoGeneratedKeyType).isOptional().withDefault(AutoGeneratedKeyType.None)
968
+ .whereParam("defaultResourceName").isNonEmptyString().isOptional().withDefault(null)
969
+ .whereParam("dataProperties").isOptional()
970
+ .whereParam("navigationProperties").isOptional()
971
+ .whereParam("serializerFn").isOptional().isFunction()
972
+ .whereParam("custom").isOptional()
973
+ .applyAll(this);
974
+ }
975
+ this.name = qualifyTypeName(this.shortName, this.namespace);
976
+ // the defaultResourceName may also be set up either via metadata lookup or first query or via the 'setProperties' method
977
+ this.dataProperties = [];
978
+ this.navigationProperties = [];
979
+ this.complexProperties = [];
980
+ this.keyProperties = [];
981
+ this.foreignKeyProperties = [];
982
+ this.inverseForeignKeyProperties = [];
983
+ this.concurrencyProperties = [];
984
+ this.unmappedProperties = []; // will be updated later.
985
+ this.validators = [];
986
+ this.warnings = [];
987
+ this._mappedPropertiesCount = 0;
988
+ this.subtypes = [];
989
+ // now process any data/nav props
990
+ if (etConfig && etConfig.dataProperties) {
991
+ addProperties(this, etConfig.dataProperties, DataProperty);
992
+ }
993
+ if (etConfig && etConfig.navigationProperties) {
994
+ addProperties(this, etConfig.navigationProperties, NavigationProperty);
995
+ }
996
+ }
997
+ /**
998
+ General purpose property set method
999
+ ```ts
1000
+ // assume em1 is an EntityManager containing a number of existing entities.
1001
+ const custType = em1.metadataStore.getAsEntityType("Customer");
1002
+ custType.setProperties({
1003
+ autoGeneratedKeyType: AutoGeneratedKeyType.Identity,
1004
+ defaultResourceName: "CustomersAndIncludedOrders"
1005
+ });
1006
+ ```
1007
+ @param config - a configuration object
1008
+ */
1009
+ setProperties(config) {
1010
+ assertConfig(config)
1011
+ .whereParam("autoGeneratedKeyType").isEnumOf(AutoGeneratedKeyType).isOptional()
1012
+ .whereParam("defaultResourceName").isString().isOptional()
1013
+ .whereParam("serializerFn").isFunction().isOptional()
1014
+ .whereParam("custom").isOptional()
1015
+ .applyAll(this);
1016
+ if (config.defaultResourceName) {
1017
+ this.defaultResourceName = config.defaultResourceName;
1018
+ }
1019
+ }
1020
+ /**
1021
+ Returns whether this type is a subtype of a specified type.
1022
+ */
1023
+ isSubtypeOf(entityType) {
1024
+ assertParam(entityType, "entityType").isInstanceOf(EntityType).check();
1025
+ let baseType = this;
1026
+ do {
1027
+ if (baseType === entityType)
1028
+ return true;
1029
+ baseType = baseType.baseEntityType;
1030
+ } while (baseType);
1031
+ return false;
1032
+ }
1033
+ /**
1034
+ Returns an array containing this type and any/all subtypes of this type down thru the hierarchy.
1035
+ */
1036
+ getSelfAndSubtypes() {
1037
+ let result = [this];
1038
+ this.subtypes.forEach(function (st) {
1039
+ let subtypes = st.getSelfAndSubtypes();
1040
+ result.push.apply(result, subtypes);
1041
+ });
1042
+ return result;
1043
+ }
1044
+ /**
1045
+ Returns the entity level validators that apply to this type: its own {@link EntityType.validators}
1046
+ followed by those of each base type. Returns a new array, so changing it does not change the type.
1047
+ */
1048
+ getAllValidators() {
1049
+ let result = this.validators.slice(0);
1050
+ let bt = this.baseEntityType;
1051
+ while (bt) {
1052
+ result.push.apply(result, bt.validators);
1053
+ bt = bt.baseEntityType;
1054
+ }
1055
+ return result;
1056
+ }
1057
+ /**
1058
+ Adds a {@link DataProperty} or a {@link NavigationProperty} to this EntityType.
1059
+ ```ts
1060
+ // assume myEntityType is a newly constructed EntityType.
1061
+ myEntityType.addProperty(dataProperty1);
1062
+ myEntityType.addProperty(dataProperty2);
1063
+ myEntityType.addProperty(navigationProperty1);
1064
+ ```
1065
+ */
1066
+ addProperty(property) {
1067
+ assertParam(property, "property").isInstanceOf(DataProperty).or().isInstanceOf(NavigationProperty).check();
1068
+ // true is 2nd arg to force resolve of any navigation properties.
1069
+ let newprop = this._addPropertyCore(property, true);
1070
+ if (this.subtypes && this.subtypes.length) {
1071
+ let stype = this;
1072
+ stype.getSelfAndSubtypes().forEach(function (st) {
1073
+ if (st !== stype) {
1074
+ if (property.isNavigationProperty) {
1075
+ st._addPropertyCore(new NavigationProperty(property), true);
1076
+ }
1077
+ else {
1078
+ st._addPropertyCore(new DataProperty(property), true);
1079
+ }
1080
+ }
1081
+ });
1082
+ }
1083
+ return newprop;
1084
+ }
1085
+ /** @hidden @internal */
1086
+ _updateFromBase(baseEntityType) {
1087
+ this.baseEntityType = baseEntityType;
1088
+ if (this.autoGeneratedKeyType === AutoGeneratedKeyType.None) {
1089
+ this.autoGeneratedKeyType = baseEntityType.autoGeneratedKeyType;
1090
+ }
1091
+ baseEntityType.dataProperties.forEach((dp) => {
1092
+ let newDp = new DataProperty(dp);
1093
+ // don't need to copy validators becaue we will walk the hierarchy to find them
1094
+ newDp.validators = [];
1095
+ newDp.baseProperty = dp;
1096
+ this._addPropertyCore(newDp);
1097
+ }, this);
1098
+ baseEntityType.navigationProperties.forEach((np) => {
1099
+ let newNp = new NavigationProperty(np);
1100
+ // don't need to copy validators becaue we will walk the hierarchy to find them
1101
+ newNp.validators = [];
1102
+ newNp.baseProperty = np;
1103
+ this._addPropertyCore(newNp);
1104
+ }, this);
1105
+ baseEntityType.subtypes.push(this);
1106
+ }
1107
+ /** @hidden @internal */
1108
+ _addPropertyCore(property, shouldResolve = false) {
1109
+ if (this.isFrozen) {
1110
+ throw new Error("The '" + this.name + "' EntityType/ComplexType has been frozen. You can only add properties to an EntityType/ComplexType before any instances of that type have been created and attached to an entityManager.");
1111
+ }
1112
+ let parentType = property.parentType;
1113
+ if (parentType) {
1114
+ if (parentType !== this) {
1115
+ throw new Error("This property: " + property.name + " has already been added to " + property.parentType.name);
1116
+ }
1117
+ else {
1118
+ // adding the same property more than once to the same entityType is just ignored.
1119
+ return;
1120
+ }
1121
+ }
1122
+ property.parentType = this;
1123
+ let ms = this.metadataStore;
1124
+ // if (property.isDataProperty) { // modified because doesn't act as a type guard
1125
+ if (property instanceof DataProperty) {
1126
+ this._addDataProperty(property);
1127
+ }
1128
+ else {
1129
+ this._addNavigationProperty(property);
1130
+ // metadataStore can be undefined if this entityType has not yet been added to a MetadataStore.
1131
+ if (shouldResolve && ms) {
1132
+ tryResolveNp(property, ms);
1133
+ }
1134
+ }
1135
+ // unmapped properties can be added AFTER entityType has already resolved all property names.
1136
+ if (ms && !(property.name && property.nameOnServer)) {
1137
+ updateClientServerNames(ms.namingConvention, property, "name");
1138
+ }
1139
+ // props can be added after entity prototype has already been wrapped.
1140
+ if (ms && this._extra) {
1141
+ if (this._extra.alreadyWrappedProps) {
1142
+ let proto = this._ctor.prototype;
1143
+ config.interfaceRegistry.modelLibrary.getDefaultInstance().initializeEntityPrototype(proto);
1144
+ }
1145
+ }
1146
+ }
1147
+ createEntity(initialValues) {
1148
+ // ignore the _$eref once the entity is attached to an entityManager.
1149
+ if (initialValues && initialValues._$eref && !initialValues._$eref.entityAspect.entityManager)
1150
+ return initialValues._$eref;
1151
+ let instance = this._createInstanceCore();
1152
+ if (initialValues) {
1153
+ // only assign an _eref if the object is fully "keyed"
1154
+ if (this.keyProperties.every(function (kp) {
1155
+ return initialValues[kp.name] != null;
1156
+ })) {
1157
+ initialValues._$eref = instance;
1158
+ }
1159
+ this._updateTargetFromRaw(instance, initialValues, getRawValueFromConfig);
1160
+ this.navigationProperties.forEach(function (np) {
1161
+ let relatedEntity;
1162
+ let val = initialValues[np.name];
1163
+ if (val != undefined) {
1164
+ let navEntityType = np.entityType;
1165
+ if (np.isScalar) {
1166
+ relatedEntity = val.entityAspect ? val : navEntityType.createEntity(val);
1167
+ instance.setProperty(np.name, relatedEntity);
1168
+ }
1169
+ else {
1170
+ let relatedEntities = instance.getProperty(np.name);
1171
+ val.forEach((v) => {
1172
+ relatedEntity = v.entityAspect ? v : navEntityType.createEntity(v);
1173
+ relatedEntities.push(relatedEntity);
1174
+ });
1175
+ }
1176
+ }
1177
+ });
1178
+ }
1179
+ this._initializeInstance(instance);
1180
+ return instance;
1181
+ }
1182
+ /** @hidden @internal */
1183
+ _createInstanceCore() {
1184
+ let aCtor = this.getCtor();
1185
+ let instance = new aCtor();
1186
+ new EntityAspect(instance);
1187
+ return instance;
1188
+ }
1189
+ /** @hidden @internal */
1190
+ _initializeInstance(instance) {
1191
+ if (this.baseEntityType) {
1192
+ this.baseEntityType._initializeInstance(instance);
1193
+ }
1194
+ let initFn = this.initFn;
1195
+ if (initFn) {
1196
+ let fn = (typeof initFn === "string") ? instance[initFn] : initFn;
1197
+ fn(instance);
1198
+ }
1199
+ this.complexProperties && this.complexProperties.forEach(function (cp) {
1200
+ let complexType = cp.dataType;
1201
+ let ctInstance = instance.getProperty(cp.name);
1202
+ if (Array.isArray(ctInstance)) {
1203
+ ctInstance.forEach((ctInst) => {
1204
+ complexType._initializeInstance(ctInst);
1205
+ });
1206
+ }
1207
+ else {
1208
+ complexType._initializeInstance(ctInstance);
1209
+ }
1210
+ });
1211
+ // not needed for complexObjects
1212
+ if (instance.entityAspect) {
1213
+ instance.entityAspect._initialized = true;
1214
+ }
1215
+ }
1216
+ /**
1217
+ Returns the constructor for this EntityType.
1218
+ @param forceRefresh - Whether to ignore any cached version of this constructor. (default == false)
1219
+ @returns The constructor for this EntityType.
1220
+ */
1221
+ getCtor(forceRefresh = false) {
1222
+ if (this._ctor && !forceRefresh)
1223
+ return this._ctor;
1224
+ let ctorRegistry = this.metadataStore._ctorRegistry;
1225
+ let r = ctorRegistry.get(this.name) || ctorRegistry.get(this.shortName) || {};
1226
+ let aCtor = r.ctor || this._ctor;
1227
+ let ctorType = aCtor && aCtor.prototype && (aCtor.prototype.entityType || aCtor.prototype.complexType);
1228
+ if (ctorType && ctorType.metadataStore !== this.metadataStore) {
1229
+ // We can't risk a mismatch between the ctor and the type info in a specific metadatastore
1230
+ // because modelLibraries rely on type info to intercept ctor properties
1231
+ throw new Error("Cannot register the same constructor for " + this.name + " in different metadata stores. Please define a separate constructor for each metadata store.");
1232
+ }
1233
+ if (r.ctor && forceRefresh) {
1234
+ this._extra = undefined;
1235
+ }
1236
+ if (!aCtor) {
1237
+ let createCtor = config.interfaceRegistry.modelLibrary.getDefaultInstance().createCtor;
1238
+ aCtor = createCtor ? createCtor(this) : createEmptyCtor(this);
1239
+ }
1240
+ this.initFn = r.initFn;
1241
+ this.noTrackingFn = r.noTrackingFn;
1242
+ aCtor.prototype._$typeName = this.name;
1243
+ this._setCtor(aCtor);
1244
+ return aCtor;
1245
+ }
1246
+ /** @hidden @internal */
1247
+ // May make public later.
1248
+ _setCtor(aCtor, interceptor) {
1249
+ let instanceProto = aCtor.prototype;
1250
+ // place for extra breeze related data
1251
+ this._extra = this._extra || {};
1252
+ let instance = new aCtor();
1253
+ calcUnmappedProperties(this, instance);
1254
+ if (this._$typeName === "EntityType") {
1255
+ // insure that all of the properties are on the 'template' instance before watching the class.
1256
+ instanceProto.entityType = this;
1257
+ }
1258
+ else {
1259
+ instanceProto.complexType = this;
1260
+ }
1261
+ // defaultPropertyInterceptor is a 'global' (but internal to breeze) function;
1262
+ instanceProto._$interceptor = interceptor || defaultPropertyInterceptor;
1263
+ config.interfaceRegistry.modelLibrary.getDefaultInstance().initializeEntityPrototype(instanceProto);
1264
+ this._ctor = aCtor;
1265
+ }
1266
+ /**
1267
+ Adds either an entity or property level validator to this EntityType.
1268
+ ```ts
1269
+ // assume em1 is an EntityManager containing a number of existing entities.
1270
+ const custType = em1.metadataStore.getAsEntityType("Customer");
1271
+ const countryProp = custType.getProperty("country");
1272
+ const valFn = (v: string | null) => v == null || v.startsWith("US");
1273
+ const countryValidator = new Validator("countryIsUS", valFn,
1274
+ { displayName: "Country", messageTemplate: "'%displayName%' must start with 'US'" });
1275
+ custType.addValidator(countryValidator, countryProp);
1276
+ ```
1277
+
1278
+ This is the same as adding an entity level validator via the 'validators' property of DataProperty or NavigationProperty
1279
+ ```ts
1280
+ countryProp.validators.push(countryValidator);
1281
+ ```
1282
+
1283
+ Entity level validators can also be added by omitting the 'property' parameter.
1284
+ ```ts
1285
+ custType.addValidator(someEntityLevelValidator);
1286
+ ```
1287
+
1288
+ or
1289
+ ```ts
1290
+ custType.validators.push(someEntityLevelValidator);
1291
+ ```
1292
+ @param validator - Validator to add.
1293
+ @param property - Property to add this validator to. If omitted, the validator is assumed to be an
1294
+ entity level validator and is added to the EntityType's 'validators'.
1295
+ */
1296
+ addValidator(validator, property) {
1297
+ assertParam(validator, "validator").isInstanceOf(Validator).check();
1298
+ assertParam(property, "property").isOptional().isString().or().isEntityProperty().check();
1299
+ if (property != null) {
1300
+ let prop = (typeof property === 'string') ? this.getProperty(property, true) : property;
1301
+ prop.validators.push(validator);
1302
+ }
1303
+ else {
1304
+ this.validators.push(validator);
1305
+ }
1306
+ }
1307
+ /**
1308
+ Returns all of the properties ( dataProperties and navigationProperties) for this EntityType.
1309
+ ```ts
1310
+ // assume em1 is an EntityManager containing a number of existing entities.
1311
+ const custType = em1.metadataStore.getAsEntityType("Customer");
1312
+ const arrayOfProps = custType.getProperties();
1313
+ ```
1314
+ @returns An array of Data and Navigation properties.
1315
+ */
1316
+ getProperties() {
1317
+ return this.dataProperties.concat(this.navigationProperties);
1318
+ }
1319
+ /**
1320
+ Returns all of the property names ( for both dataProperties and navigationProperties) for this EntityType.
1321
+ ```ts
1322
+ // assume em1 is an EntityManager containing a number of existing entities.
1323
+ const custType = em1.metadataStore.getAsEntityType("Customer");
1324
+ const arrayOfPropNames = custType.getPropertyNames();
1325
+ ```
1326
+ */
1327
+ getPropertyNames() {
1328
+ return this.getProperties().map(core.pluck('name'));
1329
+ }
1330
+ /**
1331
+ Returns a data property with the specified name or null.
1332
+ ```ts
1333
+ // assume em1 is an EntityManager containing a number of existing entities.
1334
+ const custType = em1.metadataStore.getAsEntityType("Customer");
1335
+ const companyNameDataProp = custType.getDataProperty("companyName");
1336
+ ```
1337
+ @returns A DataProperty or null if not found.
1338
+ */
1339
+ getDataProperty(propertyName) {
1340
+ return core.arrayFirst(this.dataProperties, core.propEq('name', propertyName));
1341
+ }
1342
+ /**
1343
+ Returns a navigation property with the specified name or null.
1344
+ ```ts
1345
+ // assume em1 is an EntityManager containing a number of existing entities.
1346
+ const custType = em1.metadataStore.getAsEntityType("Customer");
1347
+ const customerOrdersNavProp = custType.getNavigationProperty("orders");
1348
+ ```
1349
+ @returns A NavigationProperty or null if not found.
1350
+ */
1351
+ getNavigationProperty(propertyName) {
1352
+ return core.arrayFirst(this.navigationProperties, core.propEq('name', propertyName));
1353
+ }
1354
+ /**
1355
+ Returns either a DataProperty or a NavigationProperty with the specified name or null.
1356
+
1357
+ This method also accepts a '.' delimited property path and will return the 'property' at the
1358
+ end of the path.
1359
+ ```ts
1360
+ const custType = em1.metadataStore.getAsEntityType("Customer");
1361
+ const companyNameProp = custType.getProperty("companyName");
1362
+ ```
1363
+
1364
+ This method can also walk a property path to return a property
1365
+ ```ts
1366
+ const orderDetailType = em1.metadataStore.getAsEntityType("OrderDetail");
1367
+ const companyNameProp2 = orderDetailType.getProperty("order.customer.companyName");
1368
+ // companyNameProp === companyNameProp2
1369
+ ```
1370
+ @param [throwIfNotFound=false] {Boolean} Whether to throw an exception if not found.
1371
+ @returns A DataProperty or NavigationProperty or null if not found.
1372
+ */
1373
+ getProperty(propertyPath, throwIfNotFound = false) {
1374
+ let props = this.getPropertiesOnPath(propertyPath, false, throwIfNotFound);
1375
+ return (props && props.length > 0) ? props[props.length - 1] : null;
1376
+ }
1377
+ /** @hidden @internal */
1378
+ // TODO: have this return empty array instead of null and fix consumers.
1379
+ // TODO: think about renaming with '_' prefix.
1380
+ getPropertiesOnPath(propertyPath, useServerName, throwIfNotFound = false) {
1381
+ let propertyNames = (Array.isArray(propertyPath)) ? propertyPath : propertyPath.trim().split('.');
1382
+ let ok = true;
1383
+ let key = useServerName === true ? "nameOnServer" : useServerName === false ? "name" : null;
1384
+ let parentType = this;
1385
+ const getProps = (propName) => {
1386
+ const fn = key === null ? core.propsEq("name", "nameOnServer", propName) : core.propEq(key, propName);
1387
+ let prop = core.arrayFirst(parentType.getProperties(), fn);
1388
+ if (prop) {
1389
+ parentType = (prop instanceof NavigationProperty) ? prop.entityType : prop.dataType;
1390
+ // parentType = prop.isNavigationProperty ? prop.entityType : prop.dataType;
1391
+ }
1392
+ else if (throwIfNotFound) {
1393
+ throw new Error("unable to locate property: " + propName + " on entityType: " + parentType.name);
1394
+ }
1395
+ else {
1396
+ ok = false;
1397
+ }
1398
+ return prop;
1399
+ };
1400
+ let props = propertyNames.map(getProps);
1401
+ return ok ? props : null;
1402
+ }
1403
+ /** Translates a client-side property path into the names the server uses, applying this type's
1404
+ {@link NamingConvention} to each segment: with the default camelCase convention,
1405
+ `"company.companyName"` becomes `"Company.CompanyName"`. A {@link UriBuilderAdapter} uses it to
1406
+ write a query the server can read.
1407
+ @param propertyPath - a path of property names separated by `.`
1408
+ @param delimiter - what to join the server names with. Defaults to `.`
1409
+ @returns The same path in server terms. */
1410
+ clientPropertyPathToServer(propertyPath, delimiter = '.') {
1411
+ let propNames;
1412
+ if (this.isAnonymous) {
1413
+ let fn = this.metadataStore.namingConvention.clientPropertyNameToServer;
1414
+ propNames = propertyPath.split(".").map(function (propName) {
1415
+ return fn(propName);
1416
+ });
1417
+ }
1418
+ else {
1419
+ let props = this.getPropertiesOnPath(propertyPath, false, true);
1420
+ propNames = props.map((prop) => prop.nameOnServer);
1421
+ }
1422
+ return propNames.join(delimiter);
1423
+ }
1424
+ /** Builds the {@link EntityKey} for an entity still in its raw server form, before it has been
1425
+ materialized. A {@link DataServiceAdapter} or {@link JsonResultsAdapter} uses it to find out whether
1426
+ the cache already holds the entity a node describes.
1427
+ @param rawEntity - the untyped node as it arrived from the server
1428
+ @param rawValueFn - reads one {@link DataProperty} off that node. It is given the node and the
1429
+ property, and is what knows whether the node is keyed by client or by server names
1430
+ @returns The key, with each value parsed into its property's {@link DataType}. */
1431
+ getEntityKeyFromRawEntity(rawEntity, rawValueFn) {
1432
+ let keyValues = this.keyProperties.map((dp) => {
1433
+ let val = rawValueFn(rawEntity, dp);
1434
+ return DataType.parseRawValue(val, dp.dataType);
1435
+ });
1436
+ return new EntityKey(this, keyValues);
1437
+ }
1438
+ /** @hidden @internal */
1439
+ _updateTargetFromRaw(target, raw, rawValueFn) {
1440
+ // called recursively for complex properties
1441
+ this.dataProperties.forEach((dp) => {
1442
+ if (!dp.isSettable)
1443
+ return;
1444
+ let rawVal = rawValueFn(raw, dp);
1445
+ if (rawVal === undefined)
1446
+ return;
1447
+ let dataType = dp.dataType; // this will be a complexType when dp is a complexProperty
1448
+ let oldVal;
1449
+ if (dp.isComplexProperty) {
1450
+ let complexType = dp.dataType;
1451
+ if (rawVal === null)
1452
+ return; // rawVal may be null in nosql dbs where it was never defined for the given row.
1453
+ oldVal = target.getProperty(dp.name);
1454
+ if (dp.isScalar) {
1455
+ complexType._updateTargetFromRaw(oldVal, rawVal, rawValueFn);
1456
+ }
1457
+ else {
1458
+ if (Array.isArray(rawVal)) {
1459
+ let newVal = rawVal.map(function (rawCo) {
1460
+ let newCo = complexType._createInstanceCore(target, dp);
1461
+ complexType._updateTargetFromRaw(newCo, rawCo, rawValueFn);
1462
+ complexType._initializeInstance(newCo);
1463
+ return newCo;
1464
+ });
1465
+ if (!core.arrayEquals(oldVal, newVal, coEquals)) {
1466
+ // clear the old array and push new objects into it.
1467
+ oldVal.length = 0;
1468
+ newVal.forEach(function (nv) {
1469
+ oldVal.push(nv);
1470
+ });
1471
+ }
1472
+ }
1473
+ else {
1474
+ oldVal.length = 0;
1475
+ }
1476
+ }
1477
+ }
1478
+ else {
1479
+ if (dp.isScalar) {
1480
+ let newVal = DataType.parseRawValue(rawVal, dataType);
1481
+ target.setProperty(dp.name, newVal);
1482
+ }
1483
+ else {
1484
+ oldVal = target.getProperty(dp.name);
1485
+ if (Array.isArray(rawVal)) {
1486
+ // need to compare values
1487
+ let newVal = rawVal.map((rv) => {
1488
+ return DataType.parseRawValue(rv, dataType);
1489
+ });
1490
+ if (!core.arrayEquals(oldVal, newVal)) {
1491
+ // clear the old array and push new objects into it.
1492
+ oldVal.length = 0;
1493
+ newVal.forEach(function (nv) {
1494
+ oldVal.push(nv);
1495
+ });
1496
+ }
1497
+ }
1498
+ else {
1499
+ oldVal.length = 0;
1500
+ }
1501
+ }
1502
+ }
1503
+ });
1504
+ // if merging from an import then raw will have an entityAspect or a complexAspect
1505
+ let rawAspect = raw.entityAspect || raw.complexAspect;
1506
+ if (rawAspect) {
1507
+ let targetAspect = EntityAspect.isEntity(target) ? target.entityAspect : target.complexAspect;
1508
+ if (rawAspect.originalValuesMap) {
1509
+ targetAspect.originalValues = rawAspect.originalValuesMap;
1510
+ }
1511
+ if (rawAspect.extraMetadata) {
1512
+ targetAspect.extraMetadata = rawAspect.extraMetadata;
1513
+ }
1514
+ }
1515
+ }
1516
+ /**
1517
+ Returns a string representation of this EntityType.
1518
+ */
1519
+ toString() {
1520
+ return this.name;
1521
+ }
1522
+ /**
1523
+ Returns this type's metadata as a plain object in Breeze's native JSON metadata format, leaving out
1524
+ default values and empty arrays. Only the properties this type declares are included, not those it
1525
+ inherits from a base type. `JSON.stringify` calls it when {@link MetadataStore.exportMetadata}
1526
+ serializes the store.
1527
+ */
1528
+ toJSON() {
1529
+ return core.toJson(this, {
1530
+ shortName: null,
1531
+ namespace: null,
1532
+ baseTypeName: null,
1533
+ isAbstract: false,
1534
+ autoGeneratedKeyType: null, // do not suppress default value
1535
+ defaultResourceName: null,
1536
+ dataProperties: localPropsOnly,
1537
+ navigationProperties: localPropsOnly,
1538
+ validators: null,
1539
+ custom: null
1540
+ });
1541
+ }
1542
+ /** @hidden @internal */
1543
+ _updateNames(property) {
1544
+ let nc = this.metadataStore.namingConvention;
1545
+ updateClientServerNames(nc, property, "name");
1546
+ if (property.isNavigationProperty) {
1547
+ updateClientServerNames(nc, property, "foreignKeyNames");
1548
+ updateClientServerNames(nc, property, "invForeignKeyNames");
1549
+ // these will get set later via _updateNps
1550
+ // this.inverse
1551
+ // this.entityType
1552
+ // this.relatedDataProperties
1553
+ // dataProperty.relatedNavigationProperty
1554
+ // dataProperty.inverseNavigationProperty
1555
+ }
1556
+ }
1557
+ /** @hidden @internal */
1558
+ _checkNavProperty(navigationProperty) {
1559
+ // if (navigationProperty.isNavigationProperty) {
1560
+ if (navigationProperty instanceof NavigationProperty) {
1561
+ if (navigationProperty.parentType !== this) {
1562
+ throw new Error(core.formatString("The navigationProperty '%1' is not a property of entity type '%2'", navigationProperty.name, this.name));
1563
+ }
1564
+ return navigationProperty;
1565
+ }
1566
+ if (typeof (navigationProperty) === 'string') {
1567
+ let np = this.getProperty(navigationProperty);
1568
+ // if (np && np.isNavigationProperty) return np;
1569
+ if (np && np instanceof NavigationProperty)
1570
+ return np;
1571
+ }
1572
+ throw new Error("The 'navigationProperty' parameter must either be a NavigationProperty or the name of a NavigationProperty");
1573
+ }
1574
+ /** @hidden @internal */
1575
+ _addDataProperty(dp) {
1576
+ this.dataProperties.push(dp);
1577
+ if (dp.isPartOfKey) {
1578
+ this.keyProperties.push(dp);
1579
+ }
1580
+ if (dp.isComplexProperty) {
1581
+ this.complexProperties.push(dp);
1582
+ }
1583
+ if (dp.concurrencyMode && dp.concurrencyMode !== "None") {
1584
+ this.concurrencyProperties.push(dp);
1585
+ }
1586
+ if (dp.isUnmapped) {
1587
+ this.unmappedProperties.push(dp);
1588
+ }
1589
+ }
1590
+ /** @hidden @internal */
1591
+ _addNavigationProperty(np) {
1592
+ this.navigationProperties.push(np);
1593
+ if (!isQualifiedTypeName(np.entityTypeName)) {
1594
+ np.entityTypeName = qualifyTypeName(np.entityTypeName, this.namespace);
1595
+ }
1596
+ }
1597
+ /** @hidden @internal */
1598
+ _updateCps() {
1599
+ let metadataStore = this.metadataStore;
1600
+ let incompleteTypeMap = metadataStore._incompleteComplexTypeMap;
1601
+ this.complexProperties.forEach(function (cp) {
1602
+ if (cp.complexType)
1603
+ return;
1604
+ if (!resolveCp(cp, metadataStore)) {
1605
+ core.getMapArray(incompleteTypeMap, cp.complexTypeName).push(cp);
1606
+ }
1607
+ });
1608
+ if (this.isComplexType) {
1609
+ (incompleteTypeMap.get(this.name) || []).forEach(function (cp) {
1610
+ resolveCp(cp, metadataStore);
1611
+ });
1612
+ incompleteTypeMap.delete(this.name);
1613
+ }
1614
+ }
1615
+ /** @hidden @internal */
1616
+ _updateNps() {
1617
+ let metadataStore = this.metadataStore;
1618
+ // resolve all navProps for this entityType
1619
+ this.navigationProperties.forEach(function (np) {
1620
+ tryResolveNp(np, metadataStore);
1621
+ });
1622
+ let incompleteTypeMap = metadataStore._incompleteTypeMap;
1623
+ // next resolve all navProp that point to this entityType.
1624
+ (incompleteTypeMap.get(this.name) || []).forEach(function (np) {
1625
+ tryResolveNp(np, metadataStore);
1626
+ });
1627
+ // every navProp that pointed to this type should now be resolved
1628
+ incompleteTypeMap.delete(this.name);
1629
+ }
1630
+ }
1631
+ EntityType.prototype._$typeName = "EntityType";
1632
+ function getRawValueFromConfig(rawEntity, dp) {
1633
+ // 'true' fork can happen if an initializer contains an actaul instance of an already created complex object.
1634
+ return (rawEntity.entityAspect || rawEntity.complexAspect) ? rawEntity.getProperty(dp.name) : rawEntity[dp.name];
1635
+ }
1636
+ function updateClientServerNames(nc, parent, clientPropName) {
1637
+ let serverPropName = clientPropName + "OnServer";
1638
+ let clientName = parent[clientPropName];
1639
+ if (clientName && clientName.length) {
1640
+ // if (parent.isUnmapped) return;
1641
+ let serverNames = core.toArray(clientName).map(function (cName) {
1642
+ let sName = nc.clientPropertyNameToServer(cName, parent);
1643
+ let testName = nc.serverPropertyNameToClient(sName, parent);
1644
+ if (cName !== testName) {
1645
+ throw new Error("NamingConvention for this client property name does not roundtrip properly:" + cName + "-->" + testName);
1646
+ }
1647
+ return sName;
1648
+ });
1649
+ parent[serverPropName] = Array.isArray(clientName) ? serverNames : serverNames[0];
1650
+ }
1651
+ else {
1652
+ let serverName = parent[serverPropName];
1653
+ if ((!serverName) || serverName.length === 0)
1654
+ return;
1655
+ let clientNames = core.toArray(serverName).map(function (sName) {
1656
+ let cName = nc.serverPropertyNameToClient(sName, parent);
1657
+ let testName = nc.clientPropertyNameToServer(cName, parent);
1658
+ if (sName !== testName) {
1659
+ throw new Error("NamingConvention for this server property name does not roundtrip properly:" + sName + "-->" + testName);
1660
+ }
1661
+ return cName;
1662
+ });
1663
+ parent[clientPropName] = Array.isArray(serverName) ? clientNames : clientNames[0];
1664
+ }
1665
+ }
1666
+ function createEmptyCtor(type) {
1667
+ // The only reason this ever built a function from a string was the name: a constructor made
1668
+ // with Function('return function Order(){}')() shows as Order in a debugger. Function.name is
1669
+ // configurable, so it can simply be set - and Breeze then contains no eval and no
1670
+ // new Function, which is what a strict Content Security Policy forbids.
1671
+ const ctor = function () { };
1672
+ Object.defineProperty(ctor, 'name', { value: type.name.replace(/\W/g, '_'), configurable: true });
1673
+ return ctor;
1674
+ }
1675
+ function coEquals(co1, co2) {
1676
+ let complexType = co1.complexAspect.parentProperty.dataType;
1677
+ let dataProps = complexType.dataProperties;
1678
+ let areEqual = dataProps.every(function (dp) {
1679
+ if (!dp.isSettable)
1680
+ return true;
1681
+ let v1 = co1.getProperty(dp.name);
1682
+ let v2 = co2.getProperty(dp.name);
1683
+ if (dp.isComplexProperty && dp.isScalar) {
1684
+ return coEquals(v1, v2);
1685
+ }
1686
+ else if (dp.isComplexProperty && !dp.isScalar) {
1687
+ return core.arrayEquals(v1, v2, coEquals);
1688
+ }
1689
+ else {
1690
+ let dataType = dp.dataType; // this will be a complexType when dp is a complexProperty
1691
+ return (v1 === v2 || (dataType && dataType.normalize && v1 && v2 && dataType.normalize(v1) === dataType.normalize(v2)));
1692
+ }
1693
+ });
1694
+ return areEqual;
1695
+ }
1696
+ function localPropsOnly(props) {
1697
+ return props.filter(function (prop) {
1698
+ return prop.baseProperty == null;
1699
+ });
1700
+ }
1701
+ function resolveCp(cp, metadataStore) {
1702
+ let complexType = metadataStore._getStructuralType(cp.complexTypeName, true);
1703
+ if (!complexType)
1704
+ return false;
1705
+ if (!(complexType instanceof ComplexType)) {
1706
+ throw new Error("Unable to resolve ComplexType with the name: " + cp.complexTypeName + " for the property: " + cp.name);
1707
+ }
1708
+ cp.dataType = complexType;
1709
+ cp.defaultValue = null;
1710
+ return true;
1711
+ }
1712
+ function tryResolveNp(np, metadataStore) {
1713
+ if (np.entityType)
1714
+ return true;
1715
+ let entityType = metadataStore._getStructuralType(np.entityTypeName, true);
1716
+ if (entityType) {
1717
+ np.entityType = entityType;
1718
+ np._resolveNp();
1719
+ // don't bother removing - _updateNps will do it later.
1720
+ // __arrayRemoveItem(incompleteNps, np, false);
1721
+ }
1722
+ else {
1723
+ let incompleteNps = core.getMapArray(metadataStore._incompleteTypeMap, np.entityTypeName);
1724
+ core.arrayAddItemUnique(incompleteNps, np);
1725
+ }
1726
+ return !!entityType;
1727
+ }
1728
+ function calcUnmappedProperties(stype, instance) {
1729
+ let metadataPropNames = stype.getPropertyNames();
1730
+ let modelLib = config.interfaceRegistry.modelLibrary.getDefaultInstance();
1731
+ let trackablePropNames = modelLib.getTrackablePropertyNames(instance);
1732
+ trackablePropNames.forEach(function (pn) {
1733
+ if (metadataPropNames.indexOf(pn) === -1) {
1734
+ let val = instance[pn];
1735
+ try {
1736
+ if (typeof val === "function")
1737
+ val = val();
1738
+ }
1739
+ catch (e) {
1740
+ }
1741
+ let dt = DataType.fromValue(val);
1742
+ let newProp = new DataProperty({
1743
+ name: pn,
1744
+ dataType: dt,
1745
+ isNullable: true,
1746
+ isUnmapped: true
1747
+ });
1748
+ newProp.isSettable = core.isSettable(instance, pn);
1749
+ if (stype instanceof EntityType && stype.subtypes != null && stype.subtypes.length) {
1750
+ stype.getSelfAndSubtypes().forEach((st) => {
1751
+ st._addPropertyCore(new DataProperty(newProp));
1752
+ });
1753
+ }
1754
+ else {
1755
+ stype._addPropertyCore(newProp);
1756
+ }
1757
+ }
1758
+ });
1759
+ }
1760
+ /** Container for all of the metadata about a specific type of Complex object.
1761
+ ```ts
1762
+ const complexType = new ComplexType({
1763
+ shortName: "address",
1764
+ namespace: "myAppNamespace"
1765
+ });
1766
+ ```
1767
+ @param config - Configuration settings
1768
+ */
1769
+ export class ComplexType {
1770
+ /** For polymorphic purpose only - always true here */
1771
+ isComplexType = true;
1772
+ /** The {@link MetadataStore} containing this ComplexType. */
1773
+ metadataStore;
1774
+ /** The fully qualifed name of this ComplexType. __Read Only__ */
1775
+ name;
1776
+ /** The short, unqualified, name for this ComplexType. __Read Only__ */
1777
+ shortName;
1778
+ /** The namespace for this ComplexType. __Read Only__ */
1779
+ namespace;
1780
+ /** The DataProperties (see {@link DataProperty} associated with this ComplexType. __Read Only__ */
1781
+ dataProperties;
1782
+ /** The DataProperties for this ComplexType that contain instances of a {@link ComplexType}. __Read Only__ */
1783
+ complexProperties;
1784
+ /**
1785
+ The entity level validators associated with this ComplexType. Validators can be added and
1786
+ removed from this collection. __Read Only__ */
1787
+ validators;
1788
+ /** For polymorphic purpose only - always empty here */
1789
+ concurrencyProperties;
1790
+ /** The DataProperties associated with this ComplexType that are not mapped to any backend datastore. These are effectively free standing
1791
+ properties. __Read Only__ */
1792
+ unmappedProperties;
1793
+ /** Always empty: a ComplexType has no navigation properties. Present so that code can treat an
1794
+ EntityType and a ComplexType alike. __Read Only__ */
1795
+ // keyProperties and navigationProperties are not used on complexTypes - but here to allow sharing of code between EntityType and ComplexType.
1796
+ navigationProperties;
1797
+ /** Always empty: a ComplexType has no key. Present so that code can treat an EntityType and a
1798
+ ComplexType alike. __Read Only__ */
1799
+ // and may be used later to enforce uniqueness on arrays of complextypes.
1800
+ keyProperties;
1801
+ /** Not used by breeze-client 3, and never set on a ComplexType. See {@link EntityType.warnings}. */
1802
+ warnings;
1803
+ /** A function that customizes how this type's data properties are serialized when an entity holding
1804
+ it is saved; see {@link MetadataStore.serializerFn}, which is used when this is not set. The
1805
+ constructor does not accept it: assign it directly. */
1806
+ serializerFn;
1807
+ /** A free form object that can be used to define any custom metadata for this ComplexType. */
1808
+ custom;
1809
+ /** @hidden @internal */
1810
+ _mappedPropertiesCount;
1811
+ /** @hidden @internal */
1812
+ _extra;
1813
+ // copy entityType methods onto complexType
1814
+ /** See {@link EntityType.getCtor} */
1815
+ getCtor = EntityType.prototype.getCtor;
1816
+ /** Creates a new instance of this ComplexType, optionally setting the property values given in
1817
+ `initialValues`; the ComplexType counterpart of {@link EntityType.createEntity}.
1818
+ ```ts
1819
+ const locType = em1.metadataStore.getAsComplexType("Location");
1820
+ const loc = locType.createInstance<Location>({ city: "Boston" }); // Location, unchecked
1821
+ ```
1822
+ */
1823
+ // note the name change.
1824
+ createInstance = EntityType.prototype.createEntity;
1825
+ /** See [EntityType.addValidator] */
1826
+ addValidator = EntityType.prototype.addValidator;
1827
+ /** Returns the {@link DataProperty} with the specified name, or null. Also accepts a `.` delimited
1828
+ path through nested complex properties. See {@link EntityType.getProperty}. */
1829
+ getProperty = EntityType.prototype.getProperty;
1830
+ /** Returns the properties along a `.` delimited property path, one per segment, or null if a segment
1831
+ is not found (unless `throwIfNotFound` is true, which throws instead). `useServerName` matches
1832
+ segments against `nameOnServer` when true, `name` when false, and either when null. Used by Breeze
1833
+ internally; applications normally use {@link ComplexType.getProperty}. */
1834
+ getPropertiesOnPath = EntityType.prototype.getPropertiesOnPath;
1835
+ /** Returns the names of all of this type's data properties. */
1836
+ getPropertyNames = EntityType.prototype.getPropertyNames;
1837
+ /** @hidden @internal */
1838
+ _addPropertyCore = EntityType.prototype._addPropertyCore;
1839
+ /** @hidden @internal */
1840
+ _addDataProperty = EntityType.prototype._addDataProperty;
1841
+ /** @hidden @internal */
1842
+ _updateNames = EntityType.prototype._updateNames;
1843
+ /** @hidden @internal */
1844
+ _updateCps = EntityType.prototype._updateCps;
1845
+ /** @hidden @internal */
1846
+ _initializeInstance = EntityType.prototype._initializeInstance;
1847
+ /** @hidden @internal */
1848
+ _updateTargetFromRaw = EntityType.prototype._updateTargetFromRaw;
1849
+ /** @hidden @internal */
1850
+ _setCtor = EntityType.prototype._setCtor;
1851
+ /** Creates a ComplexType from a {@link ComplexTypeConfig}. Add it to a {@link MetadataStore}
1852
+ with {@link MetadataStore.addEntityType} before using it. */
1853
+ constructor(config) {
1854
+ if (arguments.length > 1) {
1855
+ throw new Error("The ComplexType ctor has a single argument that is a configuration object.");
1856
+ }
1857
+ assertConfig(config)
1858
+ .whereParam("shortName").isNonEmptyString()
1859
+ .whereParam("namespace").isString().isOptional().withDefault("")
1860
+ .whereParam("dataProperties").isOptional()
1861
+ .whereParam("isComplexType").isOptional().isBoolean() // needed because this ctor can get called from the addEntityType method which needs the isComplexType prop
1862
+ .whereParam("custom").isOptional()
1863
+ .applyAll(this);
1864
+ this.name = qualifyTypeName(this.shortName, this.namespace);
1865
+ this.isComplexType = true;
1866
+ this.dataProperties = [];
1867
+ this.complexProperties = [];
1868
+ this.validators = [];
1869
+ this.concurrencyProperties = [];
1870
+ this.unmappedProperties = [];
1871
+ this._mappedPropertiesCount = 0;
1872
+ // keyProperties and navigationProperties are not used on complexTypes - but here to allow sharing of code between EntityType and ComplexType.
1873
+ this.navigationProperties = [];
1874
+ this.keyProperties = []; // may be used later to enforce uniqueness on arrays of complextypes.
1875
+ if (config.dataProperties) {
1876
+ addProperties(this, config.dataProperties, DataProperty);
1877
+ }
1878
+ }
1879
+ /**
1880
+ General purpose property set method
1881
+ ```ts
1882
+ // assume em1 is an EntityManager
1883
+ const locType = em1.metadataStore.getAsComplexType("Location");
1884
+ locType.setProperties({
1885
+ custom: { foo: 7, bar: "test" }
1886
+ });
1887
+ ```
1888
+ @param config - Custom config object
1889
+ @param config.custom - {Object}
1890
+ */
1891
+ setProperties(config) {
1892
+ assertConfig(config)
1893
+ .whereParam("custom").isOptional()
1894
+ .applyAll(this);
1895
+ }
1896
+ /** Returns the type level validators for this ComplexType: its own {@link ComplexType.validators}
1897
+ array itself, not a copy, since ComplexTypes have no base types. */
1898
+ getAllValidators() {
1899
+ // ComplexType inheritance is not YET supported.
1900
+ return this.validators;
1901
+ }
1902
+ /** @hidden @internal */
1903
+ _createInstanceCore(parent, parentProperty) {
1904
+ let aCtor = this.getCtor();
1905
+ let instance = new aCtor();
1906
+ new ComplexAspect(instance, parent, parentProperty);
1907
+ // initialization occurs during either attach or in createInstance call.
1908
+ return instance;
1909
+ }
1910
+ /** Adds a {@link DataProperty} to this ComplexType.
1911
+ ```ts
1912
+ // assume addressType is a newly constructed ComplexType.
1913
+ addressType.addProperty(new DataProperty({ name: "city", dataType: DataType.String }));
1914
+ ```
1915
+ */
1916
+ addProperty(dataProperty) {
1917
+ assertParam(dataProperty, "dataProperty").isInstanceOf(DataProperty).check();
1918
+ return this._addPropertyCore(dataProperty);
1919
+ }
1920
+ /** Returns all of the properties of this ComplexType: its {@link ComplexType.dataProperties} array
1921
+ itself, not a copy. */
1922
+ getProperties() {
1923
+ return this.dataProperties;
1924
+ }
1925
+ /** Returns this type's metadata as a plain object in Breeze's native JSON metadata format, leaving
1926
+ out default values and empty arrays. `JSON.stringify` calls it when
1927
+ {@link MetadataStore.exportMetadata} serializes the store. */
1928
+ toJSON() {
1929
+ return core.toJson(this, {
1930
+ shortName: null,
1931
+ namespace: null,
1932
+ isComplexType: null,
1933
+ dataProperties: null,
1934
+ validators: null,
1935
+ custom: null
1936
+ });
1937
+ }
1938
+ }
1939
+ ComplexType.prototype._$typeName = "ComplexType";
1940
+ /** Creates an instance of this complexType */
1941
+ ComplexType.prototype.createInstance = EntityType.prototype.createEntity;
1942
+ /**
1943
+ A DataProperty describes the metadata for a single property of an {@link EntityType} that contains simple data.
1944
+
1945
+ Instances of the DataProperty class are constructed automatically during Metadata retrieval. However it is also possible to construct them
1946
+ directly via the constructor.
1947
+ */
1948
+ export class DataProperty {
1949
+ /** Is this a DataProperty? - always true here. Allows polymorphic treatment of DataProperties and NavigationProperties. __Read Only__ */
1950
+ isDataProperty = true;
1951
+ /** Is this a NavigationProperty? - always false here. Allows polymorphic treatment of DataProperties and NavigationProperties. __Read Only__ */
1952
+ isNavigationProperty = false;
1953
+ /** DataProperty constructor
1954
+ ```ts
1955
+ const lastNameProp = new DataProperty({
1956
+ name: "lastName",
1957
+ dataType: DataType.String,
1958
+ isNullable: true,
1959
+ maxLength: 20
1960
+ });
1961
+ // assuming personEntityType is a newly constructed EntityType
1962
+ personEntityType.addProperty(lastNameProp);
1963
+ ```
1964
+ @param config - A configuration Object or a DataProperty
1965
+ */
1966
+ constructor(config) {
1967
+ assertConfig(config)
1968
+ .whereParam("name").isString().isOptional()
1969
+ .whereParam("nameOnServer").isString().isOptional()
1970
+ .whereParam("dataType").isEnumOf(DataType).isOptional().or().isString().or().isInstanceOf(ComplexType)
1971
+ .whereParam("complexTypeName").isOptional()
1972
+ .whereParam("isNullable").isBoolean().isOptional().withDefault(true)
1973
+ .whereParam("isScalar").isOptional().withDefault(true) // will be false for some NoSQL databases.
1974
+ .whereParam("defaultValue").isOptional()
1975
+ .whereParam("isPartOfKey").isBoolean().isOptional()
1976
+ .whereParam("isUnmapped").isBoolean().isOptional()
1977
+ .whereParam("isSettable").isBoolean().isOptional().withDefault(true)
1978
+ .whereParam("concurrencyMode").isString().isOptional()
1979
+ .whereParam("maxLength").isNumber().isOptional()
1980
+ .whereParam("validators").isInstanceOf(Validator).isArray().isOptional().withDefault([])
1981
+ .whereParam("displayName").isOptional()
1982
+ .whereParam("enumType").isOptional()
1983
+ .whereParam("rawTypeName").isOptional() // occurs with undefined datatypes
1984
+ .whereParam("custom").isOptional()
1985
+ .applyAll(this);
1986
+ let hasName = !!(this.name || this.nameOnServer);
1987
+ if (!hasName) {
1988
+ throw new Error("A DataProperty must be instantiated with either a 'name' or a 'nameOnServer' property");
1989
+ }
1990
+ // name/nameOnServer is resolved later when a metadataStore is available.
1991
+ if (this.complexTypeName) {
1992
+ this.isComplexProperty = true;
1993
+ // this.dataType = null; // TODO: would like to remove this line because dataType will be set later.
1994
+ }
1995
+ else if (typeof (this.dataType) === "string") {
1996
+ let dt = DataType.fromName(this.dataType);
1997
+ if (!dt) {
1998
+ throw new Error("Unable to find a DataType enumeration by the name of: " + this.dataType);
1999
+ }
2000
+ this.dataType = dt;
2001
+ }
2002
+ else if (!this.dataType) {
2003
+ this.dataType = DataType.String;
2004
+ }
2005
+ // == as opposed to === is deliberate here.
2006
+ if (this.defaultValue == null) {
2007
+ if (this.isNullable) {
2008
+ this.defaultValue = null;
2009
+ }
2010
+ else {
2011
+ if (this.isComplexProperty) {
2012
+ // what to do? - shouldn't happen from EF - but otherwise ???
2013
+ }
2014
+ else if (this.dataType === DataType.Binary) {
2015
+ this.defaultValue = "AAAAAAAAJ3U="; // hack for all binary fields but value is specifically valid for timestamp fields - arbitrary valid 8 byte base64 value.
2016
+ }
2017
+ else {
2018
+ this.defaultValue = this.dataType.defaultValue;
2019
+ const msg = "A nonnullable DataProperty cannot have a null defaultValue. Name: " + (this.name || this.nameOnServer);
2020
+ if (this.defaultValue === null) {
2021
+ throw new Error(msg); // if defaultValue is explicity set to null, that's an error
2022
+ }
2023
+ else if (this.defaultValue == null) {
2024
+ console.warn(msg); // if defaultValue is not set, that's a warning
2025
+ }
2026
+ }
2027
+ }
2028
+ }
2029
+ else if (this.dataType.isNumeric) {
2030
+ // in case the defaultValue comes in as a string ( which it does in EF6).
2031
+ if (typeof (this.defaultValue) === "string") {
2032
+ this.defaultValue = parseFloat(this.defaultValue);
2033
+ }
2034
+ }
2035
+ if (this.isComplexProperty) {
2036
+ this.isScalar = this.isScalar == null || this.isScalar === true;
2037
+ }
2038
+ }
2039
+ /**
2040
+ Reads a property's value from a raw entity whose keys are server property names, such as a node
2041
+ in query results. Returns the property's `defaultValue` when the node has no value for it; for an
2042
+ unmapped property it reads `nameOnServer`, falling back to `name`, and applies no default. Pass it as
2043
+ the `rawValueFn` of {@link EntityType.getEntityKeyFromRawEntity} when writing an adapter;
2044
+ applications do not normally need it.
2045
+ */
2046
+ static getRawValueFromServer(rawEntity, dp) {
2047
+ if (dp.isUnmapped) {
2048
+ return rawEntity[dp.nameOnServer || dp.name];
2049
+ }
2050
+ else {
2051
+ let val = rawEntity[dp.nameOnServer];
2052
+ return val !== undefined ? val : dp.defaultValue;
2053
+ }
2054
+ }
2055
+ /**
2056
+ Reads a property's value from a raw entity whose keys are client property names, such as an entity
2057
+ in the output of {@link EntityManager.exportEntities}. Returns the property's `defaultValue` when the
2058
+ raw entity has no value for it. The client-name counterpart of
2059
+ {@link DataProperty.getRawValueFromServer}; applications do not normally need it.
2060
+ */
2061
+ static getRawValueFromClient(rawEntity, dp) {
2062
+ let val = rawEntity[dp.name];
2063
+ return val !== undefined ? val : dp.defaultValue;
2064
+ }
2065
+ /**
2066
+ Returns the value of the named field of this property, such as `"displayName"`. If it is null or
2067
+ undefined here, the value is taken from the property this one inherits from on a base type (see
2068
+ {@link DataProperty.baseProperty}), and so on up the hierarchy. Validation uses it to find a
2069
+ property's display name.
2070
+ */
2071
+ resolveProperty(propName) {
2072
+ let result = this[propName];
2073
+ let baseProp = this.baseProperty;
2074
+ while (result == undefined && baseProp != null) {
2075
+ result = baseProp[propName];
2076
+ baseProp = baseProp.baseProperty;
2077
+ }
2078
+ return result;
2079
+ }
2080
+ /** Returns a name that identifies this property across the store: the qualified name of its parent
2081
+ type and the property name, joined by `--`. Breeze uses it in error messages and to generate
2082
+ association names; applications do not normally need it. */
2083
+ formatName() {
2084
+ return this.parentType.name + "--" + this.name;
2085
+ }
2086
+ /**
2087
+ General purpose property set method
2088
+ ```ts
2089
+ // assume myEntityType is an EntityType
2090
+ const prop = myEntityType.getProperty("myProperty");
2091
+ prop.setProperties({
2092
+ custom: { foo: 7, bar: "test" }
2093
+ });
2094
+ ```
2095
+ @param config - A configuration object.
2096
+ */
2097
+ setProperties(config) {
2098
+ assertConfig(config)
2099
+ .whereParam("displayName").isOptional()
2100
+ .whereParam("custom").isOptional()
2101
+ .applyAll(this);
2102
+ }
2103
+ /** Returns the validators that apply to this property: its own {@link DataProperty.validators}
2104
+ followed by those of the properties it inherits from on base types. Returns a new array. */
2105
+ getAllValidators() {
2106
+ let validators = this.validators.slice(0);
2107
+ let baseProp = this.baseProperty;
2108
+ while (baseProp) {
2109
+ validators.push.apply(validators, baseProp.validators);
2110
+ baseProp = baseProp.baseProperty;
2111
+ }
2112
+ return validators;
2113
+ }
2114
+ /** Returns this property's metadata as a plain object in Breeze's native JSON metadata format,
2115
+ leaving out default values; a complex property is described by its `complexTypeName`. Used when
2116
+ {@link MetadataStore.exportMetadata} serializes the store. */
2117
+ toJSON() {
2118
+ // do not serialize dataTypes that are complexTypes
2119
+ return core.toJson(this, {
2120
+ name: null,
2121
+ dataType: function (v) {
2122
+ return (v && v instanceof DataType) ? v.name : undefined;
2123
+ }, // do not serialize dataTypes that are complexTypes
2124
+ complexTypeName: null,
2125
+ isNullable: true,
2126
+ defaultValue: null,
2127
+ isPartOfKey: false,
2128
+ isUnmapped: false,
2129
+ isSettable: true,
2130
+ concurrencyMode: null,
2131
+ maxLength: null,
2132
+ validators: null,
2133
+ displayName: null,
2134
+ enumType: null,
2135
+ rawTypeName: null,
2136
+ isScalar: true,
2137
+ custom: null
2138
+ });
2139
+ }
2140
+ /** Creates a DataProperty from the JSON form that {@link DataProperty.toJSON} produces. Used by
2141
+ {@link MetadataStore.importMetadata}. A `dataType` name the client does not know becomes
2142
+ {@link DataType.Undefined}, with the name kept in `rawTypeName` and a console warning. Modifies the
2143
+ object passed in. */
2144
+ static fromJSON(json) {
2145
+ const typeName = json.dataType;
2146
+ json.dataType = DataType.fromName(typeName);
2147
+ if (typeName && !json.dataType) {
2148
+ // A type the client does not know, from a newer server say. Keep the property, as 'Undefined' with the server's
2149
+ // name in 'rawTypeName' - the way the server itself sends spatial types - rather than pass it off as a String.
2150
+ json.dataType = DataType.Undefined;
2151
+ json.rawTypeName = json.rawTypeName || typeName;
2152
+ warnUnknownDataType(typeName);
2153
+ }
2154
+ // Parse default value into correct data type. (dateTime instances require extra work to deserialize properly.)
2155
+ if (json.defaultValue && json.dataType && json.dataType.parse) {
2156
+ json.defaultValue = json.dataType.parse(json.defaultValue, typeof json.defaultValue);
2157
+ }
2158
+ if (json.validators) {
2159
+ json.validators = json.validators.map(Validator.fromJSON);
2160
+ }
2161
+ return new DataProperty(json);
2162
+ }
2163
+ }
2164
+ DataProperty.prototype._$typeName = "DataProperty";
2165
+ const _unknownDataTypeNames = new Set();
2166
+ function warnUnknownDataType(typeName) {
2167
+ if (_unknownDataTypeNames.has(typeName))
2168
+ return;
2169
+ _unknownDataTypeNames.add(typeName);
2170
+ console.warn("Metadata names a data type the client does not know: '" + typeName +
2171
+ "'. Its properties are imported as DataType.Undefined, with the name in 'rawTypeName'.");
2172
+ }
2173
+ /** A NavigationProperty describes the metadata for a single property of an {@link EntityType} that return instances of other EntityTypes.
2174
+
2175
+ Instances of the NavigationProperty class are constructed automatically during Metadata retrieval. However it is also possible to construct them
2176
+ directly via the constructor.
2177
+ */
2178
+ export class NavigationProperty {
2179
+ /** Is this a DataProperty? - always false here
2180
+ Allows polymorphic treatment of DataProperties and NavigationProperties. __Read Only__ */
2181
+ isDataProperty = false;
2182
+ /** Is this a NavigationProperty? - always true here
2183
+ Allows polymorphic treatment of DataProperties and NavigationProperties. __Read Only__ */
2184
+ isNavigationProperty = true;
2185
+ /** Returns the qualified name of the parent type and the property name, joined by `--`. See
2186
+ {@link DataProperty.formatName}; applications do not normally need it. */
2187
+ formatName = DataProperty.prototype.formatName;
2188
+ /** Returns the validators that apply to this property, including those inherited from base types.
2189
+ See {@link DataProperty.getAllValidators}. */
2190
+ getAllValidators = DataProperty.prototype.getAllValidators;
2191
+ /** Returns the value of the named field of this property, falling back to the property it inherits
2192
+ from on a base type. See {@link DataProperty.resolveProperty}. */
2193
+ resolveProperty = DataProperty.prototype.resolveProperty;
2194
+ /** NavigationProperty constructor
2195
+ ```ts
2196
+ const homeAddressProp = new NavigationProperty({
2197
+ name: "homeAddress",
2198
+ entityTypeName: "Address:#myNamespace",
2199
+ isScalar: true,
2200
+ associationName: "address_person",
2201
+ foreignKeyNames: ["homeAddressId"]
2202
+ });
2203
+ const homeAddressIdProp = new DataProperty({
2204
+ name: "homeAddressId",
2205
+ dataType: DataType.Int32
2206
+ });
2207
+ // assuming personEntityType is a newly constructed EntityType
2208
+ personEntityType.addProperty(homeAddressProp);
2209
+ personEntityType.addProperty(homeAddressIdProp);
2210
+ ```
2211
+ @param config - A configuration object.
2212
+ */
2213
+ constructor(config) {
2214
+ assertConfig(config)
2215
+ .whereParam("name").isString().isOptional()
2216
+ .whereParam("nameOnServer").isString().isOptional()
2217
+ .whereParam("entityTypeName").isString()
2218
+ .whereParam("isScalar").isBoolean().isOptional().withDefault(true)
2219
+ .whereParam("associationName").isString().isOptional()
2220
+ .whereParam("foreignKeyNames").isArray().isString().isOptional().withDefault([])
2221
+ .whereParam("foreignKeyNamesOnServer").isArray().isString().isOptional().withDefault([])
2222
+ .whereParam("invForeignKeyNames").isArray().isString().isOptional().withDefault([])
2223
+ .whereParam("invForeignKeyNamesOnServer").isArray().isString().isOptional().withDefault([])
2224
+ .whereParam("validators").isInstanceOf(Validator).isArray().isOptional().withDefault([])
2225
+ .whereParam("displayName").isOptional()
2226
+ .whereParam("custom").isOptional()
2227
+ .applyAll(this);
2228
+ let hasName = !!(this.name || this.nameOnServer);
2229
+ if (!hasName) {
2230
+ throw new Error("A Navigation property must be instantiated with either a 'name' or a 'nameOnServer' property");
2231
+ }
2232
+ }
2233
+ /**
2234
+ General purpose property set method
2235
+ ```ts
2236
+ // assume myEntityType is an EntityType
2237
+ const prop = myEntityType.getProperty("myProperty");
2238
+ prop.setProperties({
2239
+ custom: { foo: 7, bar: "test" }
2240
+ });
2241
+ ```
2242
+ @param config - A config object
2243
+ */
2244
+ // TODO: create an interface for this.
2245
+ setProperties(config) {
2246
+ if (!this.parentType) {
2247
+ throw new Error("Cannot call NavigationProperty.setProperties until the parent EntityType of the NavigationProperty has been set.");
2248
+ }
2249
+ let inverse = config.inverse;
2250
+ if (inverse)
2251
+ delete config.inverse;
2252
+ assertConfig(config)
2253
+ .whereParam("displayName").isOptional()
2254
+ .whereParam("foreignKeyNames").isArray().isString().isOptional().withDefault([])
2255
+ .whereParam("invForeignKeyNames").isArray().isString().isOptional().withDefault([])
2256
+ .whereParam("custom").isOptional()
2257
+ .applyAll(this);
2258
+ this.parentType._updateNames(this);
2259
+ this._resolveNp();
2260
+ if (inverse) {
2261
+ this.setInverse(inverse);
2262
+ }
2263
+ }
2264
+ /** The inverse of this NavigationProperty. The NavigationProperty that represents a navigation in the opposite direction
2265
+ to this NavigationProperty. May be undefined for a undirectional NavigationProperty. __Read Only__ */
2266
+ get inverse() {
2267
+ return this.getInverse();
2268
+ }
2269
+ /** @hidden @internal */
2270
+ getInverse() {
2271
+ let np = this;
2272
+ while (!np._inverse && np.baseProperty) {
2273
+ np = np.baseProperty;
2274
+ }
2275
+ return np._inverse;
2276
+ }
2277
+ /**
2278
+ Makes the specified navigation property, on the type this property returns, the inverse of this one.
2279
+ Both get the same {@link NavigationProperty.associationName}: this property's if it has one, otherwise
2280
+ the other's, otherwise a generated one. For metadata built by hand; metadata from the server already
2281
+ pairs inverses by association name. Also available as the `inverse` option of
2282
+ {@link NavigationProperty.setProperties}. Both types must already be in the same MetadataStore.
2283
+ @param inverseNp - The inverse NavigationProperty, or its name on the type this property returns.
2284
+ Throws if it is not found, does not point back at this property's parent type, or either property
2285
+ already has an inverse.
2286
+ */
2287
+ setInverse(inverseNp) {
2288
+ // let invNp: NavigationProperty;
2289
+ let invNp = (inverseNp instanceof NavigationProperty) ? inverseNp : this.entityType.getNavigationProperty(inverseNp);
2290
+ if (!invNp) {
2291
+ throw throwSetInverseError(this, "Unable to find inverse property: " + inverseNp);
2292
+ }
2293
+ if (this._inverse || invNp._inverse) {
2294
+ throwSetInverseError(this, "It has already been set on one side or the other.");
2295
+ }
2296
+ if (invNp.entityType !== this.parentType) {
2297
+ throwSetInverseError(this, invNp.formatName() + " is not a valid inverse property for this.");
2298
+ }
2299
+ if (this.associationName) {
2300
+ invNp.associationName = this.associationName;
2301
+ }
2302
+ else {
2303
+ if (!invNp.associationName) {
2304
+ invNp.associationName = this.formatName() + "_" + invNp.formatName();
2305
+ }
2306
+ this.associationName = invNp.associationName;
2307
+ }
2308
+ this._resolveNp();
2309
+ invNp._resolveNp();
2310
+ }
2311
+ // // In progress - will be used for manual metadata config
2312
+ // createInverse(config: any) {
2313
+ // if (!this.entityType) {
2314
+ // throwCreateInverseError(this, "has not yet been defined.");
2315
+ // }
2316
+ // if (this.entityType.isFrozen) {
2317
+ // throwCreateInverseError(this, "is frozen.");
2318
+ // }
2319
+ // let metadataStore = this.entityType.metadataStore;
2320
+ // if (metadataStore == null) {
2321
+ // throwCreateInverseError(this, "has not yet been added to the metadataStore.");
2322
+ // }
2323
+ // config.entityTypeName = this.parentEntityType.name;
2324
+ // config.associationName = this.associationName;
2325
+ // let invNp = new NavigationProperty(config);
2326
+ // this.parentEntityType.addNavigationProperty(invNp);
2327
+ // return invNp;
2328
+ // };
2329
+ /** Returns this property's metadata as a plain object in Breeze's native JSON metadata format,
2330
+ leaving out default values. Only client-side names are written. Used when
2331
+ {@link MetadataStore.exportMetadata} serializes the store. */
2332
+ toJSON() {
2333
+ return core.toJson(this, {
2334
+ name: null,
2335
+ entityTypeName: null,
2336
+ isScalar: null,
2337
+ associationName: null,
2338
+ validators: null,
2339
+ displayName: null,
2340
+ foreignKeyNames: null,
2341
+ invForeignKeyNames: null,
2342
+ custom: null
2343
+ });
2344
+ }
2345
+ /** Creates a NavigationProperty from the JSON form that {@link NavigationProperty.toJSON} produces.
2346
+ Used by {@link MetadataStore.importMetadata}. Modifies the object passed in. */
2347
+ static fromJSON(json) {
2348
+ if (json.validators) {
2349
+ json.validators = json.validators.map(Validator.fromJSON);
2350
+ }
2351
+ return new NavigationProperty(json);
2352
+ }
2353
+ /** @hidden @internal */
2354
+ _resolveNp() {
2355
+ let np = this;
2356
+ let entityType = np.entityType;
2357
+ let invNp = core.arrayFirst(entityType.navigationProperties, (altNp) => {
2358
+ // Can't do this because of possibility of comparing a base class np with a subclass altNp.
2359
+ // return altNp.associationName === np.associationName
2360
+ // && altNp !== np;
2361
+ // So use this instead.
2362
+ return altNp.associationName === np.associationName &&
2363
+ (altNp.name !== np.name || altNp.entityTypeName !== np.entityTypeName);
2364
+ });
2365
+ np._inverse = invNp || undefined;
2366
+ //if (invNp && invNp.inverse == null) {
2367
+ // invNp._resolveNp();
2368
+ //}
2369
+ if (!invNp) {
2370
+ // unidirectional 1-n relationship
2371
+ np.invForeignKeyNames.forEach(function (invFkName) {
2372
+ let fkProp = entityType.getDataProperty(invFkName);
2373
+ if (fkProp == null) {
2374
+ throw new Error("EntityType '" + np.entityTypeName + "' has no foreign key matching '" + invFkName + "'");
2375
+ }
2376
+ let invEntityType = np.parentType;
2377
+ invNp = core.arrayFirst(invEntityType.navigationProperties, (np2) => {
2378
+ return np2.invForeignKeyNames && np2.invForeignKeyNames.indexOf(fkProp.name) >= 0 && np2.entityType === fkProp.parentType;
2379
+ });
2380
+ fkProp.inverseNavigationProperty = invNp || undefined;
2381
+ core.arrayAddItemUnique(entityType.foreignKeyProperties, fkProp);
2382
+ });
2383
+ }
2384
+ resolveRelated(np);
2385
+ }
2386
+ }
2387
+ NavigationProperty.prototype._$typeName = "NavigationProperty";
2388
+ function throwSetInverseError(np, message) {
2389
+ throw new Error("Cannot set the inverse property for: " + np.formatName() + ". " + message);
2390
+ }
2391
+ // Not current used.
2392
+ // function throwCreateInverseError(np: NavigationProperty, message: string) {
2393
+ // throw new Error("Cannot create inverse for: " + np.formatName() + ". The entityType for this navigation property " + message);
2394
+ // }
2395
+ // sets navigation property: relatedDataProperties and dataProperty: relatedNavigationProperty
2396
+ function resolveRelated(np) {
2397
+ let fkNames = np.foreignKeyNames;
2398
+ if (fkNames.length === 0)
2399
+ return;
2400
+ let parentEntityType = np.parentType;
2401
+ let fkProps = fkNames.map(function (fkName) {
2402
+ return parentEntityType.getDataProperty(fkName);
2403
+ });
2404
+ let fkPropCollection = parentEntityType.foreignKeyProperties;
2405
+ fkProps.forEach((dp) => {
2406
+ core.arrayAddItemUnique(fkPropCollection, dp);
2407
+ dp.relatedNavigationProperty = np;
2408
+ // now update the inverse
2409
+ core.arrayAddItemUnique(np.entityType.inverseForeignKeyProperties, dp);
2410
+ if (np.relatedDataProperties) {
2411
+ core.arrayAddItemUnique(np.relatedDataProperties, dp);
2412
+ }
2413
+ else {
2414
+ np.relatedDataProperties = [dp];
2415
+ }
2416
+ });
2417
+ }
2418
+ /**
2419
+ AutoGeneratedKeyType is an 'Enum' containing all of the valid states for an automatically generated key.
2420
+ */
2421
+ export class AutoGeneratedKeyType extends BreezeEnum {
2422
+ /**
2423
+ This entity does not have an autogenerated key.
2424
+ The client must set the key before adding the entity to the EntityManager
2425
+ */
2426
+ static None = new AutoGeneratedKeyType();
2427
+ /**
2428
+ This entity's key is an Identity column and is set by the backend database.
2429
+ Keys for new entities will be temporary until the entities are saved at which point the keys will
2430
+ be converted to their 'real' versions.
2431
+ */
2432
+ static Identity = new AutoGeneratedKeyType();
2433
+ /**
2434
+ This entity's key is generated by a KeyGenerator and is set by the backend database.
2435
+ Keys for new entities will be temporary until the entities are saved at which point the keys will
2436
+ be converted to their 'real' versions.
2437
+ */
2438
+ static KeyGenerator = new AutoGeneratedKeyType();
2439
+ }
2440
+ AutoGeneratedKeyType.prototype._$typeName = "AutoGeneratedKeyType";
2441
+ AutoGeneratedKeyType.resolveSymbols();
2442
+ // functions shared between classes related to Metadata
2443
+ function isQualifiedTypeName(entityTypeName) {
2444
+ return entityTypeName.indexOf(":#") >= 0;
2445
+ }
2446
+ export function qualifyTypeName(shortName, ns) {
2447
+ if (ns && ns.length > 0) {
2448
+ return shortName + ":#" + ns;
2449
+ }
2450
+ else {
2451
+ return shortName;
2452
+ }
2453
+ }
2454
+ /**
2455
+ The {@link EntityType} a constructor stands for.
2456
+
2457
+ {@link MetadataStore.registerEntityTypeCtor} puts the type on the class's prototype, and that is
2458
+ what the constructor-taking overloads of `EntityQuery.from`, `EntityManager.createEntity` and the
2459
+ rest read. A class that was never registered has nothing to read, so this throws rather than
2460
+ letting the caller build a query against `undefined`.
2461
+
2462
+ ```ts
2463
+ em.metadataStore.registerEntityTypeCtor('Customer', Customer);
2464
+ entityTypeForCtor(Customer).defaultResourceName; // 'Customers'
2465
+ ```
2466
+ @param entityCtor - A constructor registered with a MetadataStore.
2467
+ */
2468
+ export function entityTypeForCtor(entityCtor) {
2469
+ const entityType = entityCtor && entityCtor.prototype && entityCtor.prototype.entityType;
2470
+ if (!entityType) {
2471
+ const name = (entityCtor && entityCtor.name) || String(entityCtor);
2472
+ throw new Error(core.formatString("'%1' is not registered with a MetadataStore, so its EntityType is unknown. Call " +
2473
+ "metadataStore.registerEntityTypeCtor('%1', %1) before using the constructor with this API.", name));
2474
+ }
2475
+ return entityType;
2476
+ }
2477
+ // Used by both ComplexType and EntityType
2478
+ function addProperties(entityType, propObj, ctor) {
2479
+ if (propObj == null)
2480
+ return;
2481
+ if (Array.isArray(propObj)) {
2482
+ // Each item is a DataProperty/NavigationProperty, or the config to make one from. (Not
2483
+ // forEach(_addPropertyCore): that passed each item's index as `shouldResolve`.)
2484
+ for (const item of propObj) {
2485
+ entityType._addPropertyCore(item instanceof ctor ? item : new ctor(item));
2486
+ }
2487
+ }
2488
+ else if (typeof (propObj) === 'object') {
2489
+ for (let key in propObj) {
2490
+ if (hasOwnProp(propObj, key)) {
2491
+ // A copy with the name added: the caller's config object is left as it was.
2492
+ let value = propObj[key];
2493
+ let prop = new ctor({ ...value, name: key });
2494
+ entityType._addPropertyCore(prop);
2495
+ }
2496
+ }
2497
+ }
2498
+ else {
2499
+ throw new Error("The 'dataProperties' or 'navigationProperties' values must be either an array of data/nav properties or an object where each property defines a data/nav property");
2500
+ }
2501
+ }
2502
+ //# sourceMappingURL=entity-metadata.js.map