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,1149 @@
1
+ import { core, arrayFlatMap, stringStartsWith } from '../core/core.js';
2
+ import { assertParam } from '../core/assert-param.js';
3
+ import { DataType } from '../metadata/data-type.js';
4
+ import { EntityAspect } from '../entity/entity-aspect.js';
5
+ import { EntityKey } from '../entity/entity-key.js';
6
+ import { BreezeEnum } from '../core/enum.js';
7
+ import { DataService } from '../metadata/data-service.js';
8
+ import { EntityType, entityTypeForCtor } from '../metadata/entity-metadata.js';
9
+ import { QueryOptions } from './query-options.js';
10
+ import { Predicate } from './predicate.js';
11
+ /**
12
+ An EntityQuery instance is used to query entities either from a remote datasource or from a local {@link EntityManager}.
13
+
14
+ EntityQueries are immutable - this means that all EntityQuery methods that return an EntityQuery actually create a new EntityQuery. This means that
15
+ EntityQueries can be 'modified' without affecting any current instances.
16
+ */
17
+ export class EntityQuery {
18
+ /** Constructor. Most queries start from the static {@link EntityQuery.from} instead, which takes a
19
+ registered entity class and so gives a typed query:
20
+ ```ts
21
+ const query = EntityQuery.from(Customer); // EntityQuery<Customer>
22
+ ```
23
+
24
+ When a constructor is needed, supply the type argument. As with a type argument on
25
+ `EntityQuery.from(resourceName)`, nothing checks it against the resource name:
26
+ ```ts
27
+ const query = new EntityQuery<Customer>("Customers");
28
+ ```
29
+
30
+ Usually this constructor will be followed by calls to filtering, ordering or selection methods
31
+ ```ts
32
+ const query = new EntityQuery<Customer>("Customers")
33
+ .where("companyName", "startsWith", "C")
34
+ .orderBy("region");
35
+ ```
36
+ @param resourceName - either a resource name or a serialized EntityQuery ( created by {@link EntityQuery.toJSON})
37
+ */
38
+ constructor(resourceName) {
39
+ if (resourceName != null && (typeof resourceName !== 'string')) {
40
+ return fromJSON(this, resourceName);
41
+ }
42
+ // The cast holds for test/tsconfig.json, which checks src/ again with strictNullChecks off;
43
+ // without it the guard above narrows to `string | Object` rather than `string | undefined`.
44
+ this.resourceName = resourceName;
45
+ this.fromEntityType = undefined;
46
+ this.wherePredicate = undefined;
47
+ this.orderByClause = undefined;
48
+ this.selectClause = undefined;
49
+ this.skipCount = undefined;
50
+ this.takeCount = undefined;
51
+ this.expandClause = undefined;
52
+ this.parameters = {};
53
+ this.inlineCountEnabled = false;
54
+ this.noTrackingEnabled = false;
55
+ this.usePostEnabled = false;
56
+ // default is to get queryOptions and dataService from the entityManager.
57
+ // this.queryOptions = new QueryOptions();
58
+ // this.dataService = new DataService();
59
+ this.entityManager = undefined;
60
+ }
61
+ /**
62
+ Specifies the resource to query for this EntityQuery.
63
+ ```ts
64
+ const query = new EntityQuery()
65
+ .from("Customers");
66
+ ```
67
+
68
+ is the same as
69
+ ```ts
70
+ const query = new EntityQuery("Customers");
71
+ ```
72
+
73
+ For a typed query, use the static `EntityQuery.from(Customer)` instead.
74
+ @param resourceName - The resource to query.
75
+ */
76
+ from(resourceName) {
77
+ // TODO: think about allowing entityType as well
78
+ assertParam(resourceName, "resourceName").isString().check();
79
+ return clone(this, "resourceName", resourceName);
80
+ }
81
+ static from(arg) {
82
+ if (typeof arg === 'function') {
83
+ const entityType = entityTypeForCtor(arg);
84
+ if (!entityType.defaultResourceName) {
85
+ throw new Error(`'${entityType.name}' has no defaultResourceName, so a query cannot be built from the constructor. ` +
86
+ `Use EntityQuery.from(resourceName).toType(...) instead, or call metadataStore.setEntityTypeForResourceName.`);
87
+ }
88
+ return new EntityQuery(entityType.defaultResourceName);
89
+ }
90
+ assertParam(arg, "resourceName").isString().check();
91
+ return new EntityQuery(arg);
92
+ }
93
+ toType(entityType) {
94
+ // Naming the type is what `toType` is for, so a registered constructor names it *and* types
95
+ // the query - and unlike a type argument on `from(resourceName)`, this one is checked against
96
+ // the metadata.
97
+ if (typeof entityType === 'function') {
98
+ entityType = entityTypeForCtor(entityType);
99
+ }
100
+ assertParam(entityType, "entityType").isString().or().isInstanceOf(EntityType).check();
101
+ return clone(this, "resultEntityType", entityType);
102
+ }
103
+ /**
104
+ Returns a new query with an added filter criteria; Can be called multiple times which means to 'and' with any existing
105
+ Predicate or can be called with null to clear all predicates.
106
+ ```ts
107
+ const query = EntityQuery.from(Customer)
108
+ .where("companyName", "startsWith", "C");
109
+ ```
110
+
111
+ or in object form
112
+ ```ts
113
+ const query = EntityQuery.from(Customer)
114
+ .where({ companyName: { startsWith: "C" } });
115
+ ```
116
+
117
+ This can also be expressed using an explicit {@link FilterQueryOp} (the operator is then not checked against the property's type) as
118
+ ```ts
119
+ const query = EntityQuery.from(Customer)
120
+ .where("companyName", FilterQueryOp.StartsWith, "C");
121
+ ```
122
+
123
+ or a preconstructed {@link Predicate} may be used
124
+ ```ts
125
+ const p = Predicate.for(Customer);
126
+ const query = EntityQuery.from(Customer).where(p("companyName", "startsWith", "C"));
127
+ ```
128
+
129
+ Predicates are often useful when you want to combine multiple conditions in a single filter, such as
130
+ ```ts
131
+ const pred = p("companyName", "startsWith", "C").and(p("region", "eq", null));
132
+ const query = EntityQuery.from(Customer)
133
+ .where(pred);
134
+ ```
135
+
136
+ More complicated queries can make use of nested property paths
137
+ ```ts
138
+ const query = EntityQuery.from(Product)
139
+ .where("category.categoryName", "startsWith", "S");
140
+ ```
141
+
142
+ or query functions - A list of valid functions can be found within the {@link Predicate} documentation.
143
+
144
+ ```ts
145
+ const query = EntityQuery.from(Customer)
146
+ .where("toLower(companyName)", "startsWith", "c");
147
+ ```
148
+
149
+ or to be even more baroque
150
+ ```ts
151
+ const query = EntityQuery.from(Customer)
152
+ .where("toUpper(substring(companyName, 1, 2))", FilterQueryOp.Equals, "OM");
153
+ ```
154
+ @param predicate - Can be either
155
+ - a single {@link Predicate}
156
+
157
+ - the parameters to create a 'simple' Predicate
158
+ - - a property name, a property path with '.' as path seperators or a property expression {String}
159
+ - - an operator - {@link FilterQueryOp} or it's string representation. Case is ignored
160
+ when if a string is provided and any string that matches one of the FilterQueryOp aliases will be accepted.
161
+ - - a value {Object} - This will be treated as either a property expression or a literal depending on context.
162
+ In general, if the value can be interpreted as a property expression it will be, otherwise it will be treated as a literal.
163
+ In most cases this works well, but you can also force the interpretation by making the value argument itself an object
164
+ with a 'value' property and an 'isLiteral' property set to either true or false.
165
+ Breeze also tries to infer the dataType of any literal based on context, if this fails you can force this inference by making the value argument
166
+ an object with a 'value' property and a 'dataType'property set to one of the DataType enumeration instances.
167
+
168
+ - a null or undefined ( this causes any existing where clause to be removed)
169
+ */
170
+ where(...args) {
171
+ let wherePredicate;
172
+ if (args.length > 0 && args[0] != null) {
173
+ wherePredicate = Predicate.create(...args);
174
+ if (this.fromEntityType)
175
+ wherePredicate._validate(this.fromEntityType);
176
+ if (this.wherePredicate) {
177
+ wherePredicate = this.wherePredicate.and(wherePredicate);
178
+ }
179
+ }
180
+ return clone(this, "wherePredicate", wherePredicate);
181
+ }
182
+ /**
183
+ Returns a new query that orders the results of the query by property name. By default sorting occurs is ascending order, but sorting in descending order is supported as well.
184
+ OrderBy clauses may be chained.
185
+ ```ts
186
+ const query = EntityQuery.from(Customer)
187
+ .orderBy("companyName");
188
+ ```
189
+
190
+ or to sort across multiple properties
191
+ ```ts
192
+ const query = EntityQuery.from(Customer)
193
+ .orderBy(["region", "companyName"]);
194
+ ```
195
+
196
+ A comma-separated string, `"region, companyName"`, is also accepted, but its paths are not checked.
197
+
198
+ Nested property paths are also supported
199
+ ```ts
200
+ const query = EntityQuery.from(Product)
201
+ .orderBy("category.categoryName");
202
+ ```
203
+
204
+ Sorting in descending order is supported via the addition of ' desc' to the end of any property path.
205
+ ```ts
206
+ const query = EntityQuery.from(Customer)
207
+ .orderBy("companyName desc");
208
+ ```
209
+
210
+ or
211
+ ```ts
212
+ const query = EntityQuery.from(Customer)
213
+ .orderBy(["region desc", "companyName desc"]);
214
+ ```
215
+ @param propertyPaths - A comma-separated (',') string of property paths or an array of property paths.
216
+ Each property path can optionally end with " desc" to force a descending sort order. If 'propertyPaths' is either null or omitted then all ordering is removed.
217
+ @param isDescending - If specified, overrides all of the embedded 'desc' tags in the previously specified property paths.
218
+ */
219
+ orderBy(propertyPaths, isDescending) {
220
+ // propertyPaths: can pass in create("A.X,B") or create("A.X desc, B") or create("A.X desc,B", true])
221
+ // isDesc parameter trumps isDesc in propertyName.
222
+ let orderByClause = propertyPaths == null ? null : new OrderByClause(normalizePropertyPaths(propertyPaths), isDescending);
223
+ if (this.orderByClause && orderByClause) {
224
+ orderByClause = new OrderByClause([this.orderByClause, orderByClause]);
225
+ }
226
+ return clone(this, "orderByClause", orderByClause);
227
+ }
228
+ /**
229
+ Returns a new query that orders the results of the query by property name in descending order.
230
+ ```ts
231
+ const query = EntityQuery.from(Customer)
232
+ .orderByDesc("companyName");
233
+ ```
234
+
235
+ or to sort across multiple properties
236
+ ```ts
237
+ const query = EntityQuery.from(Customer)
238
+ .orderByDesc(["region", "companyName"]);
239
+ ```
240
+
241
+ Nested property paths are also supported
242
+ ```ts
243
+ const query = EntityQuery.from(Product)
244
+ .orderByDesc("category.categoryName");
245
+ ```
246
+ @param propertyPaths - A comma-separated (',') string of property paths or an array of property paths.
247
+ If 'propertyPaths' is either null or omitted then all ordering is removed.
248
+ */
249
+ orderByDesc(propertyPaths) {
250
+ return this.orderBy(propertyPaths, true);
251
+ }
252
+ select(propertyPaths) {
253
+ let selectClause = propertyPaths == null ? null : new SelectClause(normalizePropertyPaths(propertyPaths));
254
+ // A projection no longer returns the entity type, so the type parameter is dropped rather
255
+ // than carried forward as something the results will not be.
256
+ return clone(this, "selectClause", selectClause);
257
+ }
258
+ /**
259
+ Returns a new query that skips the specified number of entities when returning results.
260
+ Any existing 'skip' can be cleared by calling 'skip' with no arguments.
261
+ ```ts
262
+ const query = EntityQuery.from(Customer)
263
+ .where("companyName", "startsWith", "C")
264
+ .skip(5);
265
+ ```
266
+ @param count - The number of entities to skip over. If omitted or null any existing skip count on the query is removed.
267
+ */
268
+ skip(count) {
269
+ assertParam(count, "count").isOptional().isNumber().check();
270
+ return clone(this, "skipCount", (count == null) ? null : count);
271
+ }
272
+ /**
273
+ Returns a new query that returns only the specified number of entities when returning results. - Same as 'take'.
274
+ Any existing 'top' can be cleared by calling 'top' with no arguments.
275
+ ```ts
276
+ const query = EntityQuery.from(Customer)
277
+ .top(5);
278
+ ```
279
+ @param count - The number of entities to return.
280
+ If 'count' is either null or omitted then any existing 'top' count on the query is removed.
281
+ */
282
+ top(count) {
283
+ return this.take(count);
284
+ }
285
+ /**
286
+ Returns a new query that returns only the specified number of entities when returning results - Same as 'top'.
287
+ Any existing take can be cleared by calling take with no arguments.
288
+ ```ts
289
+ const query = EntityQuery.from(Customer)
290
+ .take(5);
291
+ ```
292
+ @param count - The number of entities to return.
293
+ If 'count' is either null or omitted then any existing 'take' count on the query is removed.
294
+ */
295
+ take(count) {
296
+ assertParam(count, "count").isOptional().isNumber().check();
297
+ return clone(this, "takeCount", (count == null) ? null : count);
298
+ }
299
+ /**
300
+ Returns a new query that will return related entities nested within its results. The expand method allows you to identify related entities, via navigation property
301
+ names such that a graph of entities may be retrieved with a single request. Any filtering occurs before the results are 'expanded'.
302
+ ```ts
303
+ const query = EntityQuery.from(Customer)
304
+ .where("companyName", "startsWith", "C")
305
+ .expand("orders");
306
+ ```
307
+
308
+ will return the filtered customers each with its "orders" properties fully resolved.
309
+ Multiple paths may be specified in an array
310
+ ```ts
311
+ const query = EntityQuery.from(Order)
312
+ .expand(["customer", "employee"]);
313
+ ```
314
+
315
+ and nested property paths my be specified as well
316
+ ```ts
317
+ const query = EntityQuery.from(Order)
318
+ .expand(["customer", "orderDetails", "orderDetails.product"]);
319
+ ```
320
+
321
+ The paths may also be separated by a ',' in a single string, `"customer, employee"`, but those paths are not checked.
322
+ @param propertyPaths - A comma-separated list of navigation property names or an array of navigation property names. Each Navigation Property name can be followed
323
+ by a '.' and another navigation property name to enable identifying a multi-level relationship.
324
+ If 'propertyPaths' is either null or omitted then any existing 'expand' clause on the query is removed.
325
+ */
326
+ expand(propertyPaths) {
327
+ let expandClause = propertyPaths == null ? null : new ExpandClause(normalizePropertyPaths(propertyPaths));
328
+ return clone(this, "expandClause", expandClause);
329
+ }
330
+ /**
331
+ Returns a new query that includes a collection of parameters to pass to the server.
332
+ ```ts
333
+ const query = EntityQuery.from("EmployeesFilteredByCountryAndBirthdate")
334
+ .toType(Employee)
335
+ .withParameters({ birthDate: "1/1/1960", country: "USA" });
336
+ ```
337
+
338
+ will call the 'EmployeesFilteredByCountryAndBirthdate' method on the server and pass in 2 parameters. This
339
+ query will be uri encoded as
340
+ ```ts
341
+ {serviceApi}/EmployeesFilteredByCountryAndBirthdate?birthDate=1%2F1%2F1960&country=USA
342
+ ```
343
+
344
+ Parameters may also be mixed in with other query criteria.
345
+ ```ts
346
+ const query = EntityQuery.from("EmployeesFilteredByCountryAndBirthdate")
347
+ .toType(Employee)
348
+ .withParameters({ birthDate: "1/1/1960", country: "USA" })
349
+ .where("lastName", "startsWith", "S")
350
+ .orderBy("birthDate");
351
+ ```
352
+ @param parameters - A parameters object where the keys are the parameter names and the values are the parameter values.
353
+ */
354
+ withParameters(parameters) {
355
+ assertParam(parameters, "parameters").isObject().check();
356
+ return clone(this, "parameters", parameters);
357
+ }
358
+ /**
359
+ Returns a query with the `inlineCount` capability either enabled or disabled. With `inlineCount` enabled, an additional 'inlineCount' property
360
+ will be returned with the query results that will contain the number of entities that would have been returned by this
361
+ query with only the 'where'/'filter' clauses applied, i.e. without any 'skip'/'take' operators applied. For local queries this clause is ignored.
362
+ ```ts
363
+ const query = EntityQuery.from(Customer)
364
+ .take(20)
365
+ .orderBy("companyName")
366
+ .inlineCount(true);
367
+ ```
368
+
369
+ will return the first 20 customers as well as a count of _all_ of the customers in the remote store.
370
+ @param enabled - (default = true) Whether or not inlineCount capability should be enabled. If this parameter is omitted, true is assumed.
371
+ */
372
+ inlineCount(enabled) {
373
+ assertParam(enabled, "enabled").isBoolean().isOptional().check();
374
+ enabled = (enabled === undefined) ? true : !!enabled;
375
+ return clone(this, "inlineCountEnabled", enabled);
376
+ }
377
+ /**
378
+ Returns a query whose property paths are the server's names rather than the client's, so Breeze
379
+ sends them as written instead of translating them with the `MetadataStore`'s naming convention.
380
+ ```ts
381
+ EntityQuery.from('Customers').where('CompanyName', 'startsWith', 'A').useNameOnServer();
382
+ ```
383
+ The query is built from a resource name because a typed query, `EntityQuery.from(Customer)`,
384
+ checks its paths against the client's names and would reject `'CompanyName'`.
385
+ Only the query sent to the server is affected: run against the cache, a query works on the
386
+ client's objects and needs the client's names.
387
+ @param usesNameOnServer - (default = true)
388
+ */
389
+ useNameOnServer(usesNameOnServer) {
390
+ assertParam(usesNameOnServer, "usesNameOnServer").isBoolean().isOptional().check();
391
+ usesNameOnServer = (usesNameOnServer === undefined) ? true : !!usesNameOnServer;
392
+ return clone(this, "usesNameOnServer", usesNameOnServer);
393
+ }
394
+ /**
395
+ Returns a query with the `noTracking` capability either enabled or disabled. With `noTracking` enabled, the results of this query
396
+ will not be coerced into entities but will instead look like raw javascript projections. i.e. simple javascript objects.
397
+ ```ts
398
+ const query = EntityQuery.from(Customer)
399
+ .take(20)
400
+ .orderBy("companyName")
401
+ .noTracking(true);
402
+ ```
403
+ @param enabled - (default = true) Whether or not the noTracking capability should be enabled. If this parameter is omitted, true is assumed.
404
+ */
405
+ noTracking(enabled) {
406
+ assertParam(enabled, "enabled").isBoolean().isOptional().check();
407
+ enabled = (enabled === undefined) ? true : !!enabled;
408
+ return clone(this, "noTrackingEnabled", enabled);
409
+ }
410
+ /**
411
+ Returns a query with the `usePost` capability either enabled or disabled. With `usePost` enabled, the query is sent
412
+ as a POST request (instead of GET) and the query expression will be sent as JSON in the body of the post.
413
+ Note that the server must be able to parse the body of the request; otherwise the query expression will be ignored.
414
+ ```ts
415
+ const query = EntityQuery.from(Order)
416
+ .where("freight", "gt", 100)
417
+ .usePost(true);
418
+ ```
419
+ results in a POST request to `{host}/{path}/Orders`
420
+ with body `{"where": {"Freight":{"gt":100}}}`
421
+ @param enabled - (default = true) Whether or not usePost should be enabled. If this parameter is omitted, true is assumed.
422
+ */
423
+ usePost(enabled) {
424
+ assertParam(enabled, "enabled").isBoolean().isOptional().check();
425
+ enabled = (enabled === undefined) ? true : !!enabled;
426
+ return clone(this, "usePostEnabled", enabled);
427
+ }
428
+ /**
429
+ Returns a copy of this EntityQuery with the specified {@link EntityManager}, {@link DataService},
430
+ {@link JsonResultsAdapter}, {@link MergeStrategy} or {@link FetchStrategy} applied.
431
+ ```ts
432
+ // 'using' can be used to return a new query with a specified EntityManager.
433
+ const em = new EntityManager(serviceName);
434
+ const query = EntityQuery.from(Order)
435
+ .using(em);
436
+ ```
437
+
438
+ or with a specified {@link MergeStrategy}
439
+ ```ts
440
+ const query = EntityQuery.from(Order)
441
+ .using(MergeStrategy.PreserveChanges);
442
+ ```
443
+
444
+ or with a specified {@link FetchStrategy}
445
+ ```ts
446
+ const query = EntityQuery.from(Order)
447
+ .using(FetchStrategy.FromLocalCache);
448
+ ```
449
+ @param obj - The object to update in creating a new EntityQuery from an existing one.
450
+ */
451
+ using(obj) {
452
+ if (!obj)
453
+ return this;
454
+ let eq = clone(this);
455
+ processUsing(eq, {
456
+ "entityManager": null,
457
+ "dataService": null,
458
+ "queryOptions": null,
459
+ "fetchStrategy": (eq, val) => {
460
+ eq.queryOptions = (eq.queryOptions || new QueryOptions()).using(val);
461
+ },
462
+ "mergeStrategy": (eq, val) => {
463
+ eq.queryOptions = (eq.queryOptions || new QueryOptions()).using(val);
464
+ },
465
+ "jsonResultsAdapter": (eq, val) => {
466
+ eq.dataService = (eq.dataService || new DataService()).using({ jsonResultsAdapter: val });
467
+ }
468
+ }, obj);
469
+ return eq;
470
+ }
471
+ /**
472
+ Executes this query. This method requires that an EntityManager has been previously specified via the "using" method.
473
+
474
+ It returns a promise:
475
+ ```ts
476
+ const em = new EntityManager(serviceName);
477
+ const query = EntityQuery.from(Order).using(em);
478
+ const data = await query.execute(); // rejects if the query fails
479
+ const orders = data.results; // Order[]
480
+ ```
481
+
482
+ The `callback` and `errorCallback` arguments are deprecated. They still work, but the
483
+ promise is the supported form and the callbacks will be removed in a future major version.
484
+
485
+ This method is the same as calling the EntityManager 'executeQuery' method.
486
+ ```ts
487
+ const em = new EntityManager(serviceName);
488
+ const query = EntityQuery.from(Order);
489
+ const data = await em.executeQuery(query);
490
+ const orders = data.results; // Order[]
491
+ ```
492
+
493
+ @param callback - Deprecated. Function called on success.
494
+ @param errorCallback - Deprecated. Function called on failure.
495
+ @returns Promise
496
+ */
497
+ execute(callback, errorCallback) {
498
+ if (!this.entityManager) {
499
+ throw new Error("An EntityQuery must have its EntityManager property set before calling 'execute'");
500
+ }
501
+ return this.entityManager.executeQuery(this, callback, errorCallback);
502
+ }
503
+ /**
504
+ Executes this query against the local cache. This method requires that an EntityManager have been previously specified via the "using" method.
505
+ ```ts
506
+ // assume em is an entityManager already filled with order entities;
507
+ const query = EntityQuery.from(Order).using(em);
508
+ const orders = query.executeLocally(); // Order[]
509
+ ```
510
+
511
+ Note that calling this method is the same as calling {@link EntityManager.executeQueryLocally}.
512
+ */
513
+ executeLocally() {
514
+ if (!this.entityManager) {
515
+ throw new Error("An EntityQuery must have its EntityManager property set before calling 'executeLocally'");
516
+ }
517
+ return this.entityManager.executeQueryLocally(this);
518
+ }
519
+ /**
520
+ Executes this query against the server and returns only the number of matching entities, without
521
+ materializing any of them. Requires an EntityManager, set via {@link EntityQuery.using}.
522
+ ```ts
523
+ const count = await EntityQuery.from(Order).where("freight", ">", 100).using(em).executeCount();
524
+ ```
525
+
526
+ It is `take(0).inlineCount(true)` and reads `inlineCount` off the result, so the server must
527
+ support inline count.
528
+ */
529
+ async executeCount() {
530
+ if (!this.entityManager) {
531
+ throw new Error("An EntityQuery must have its EntityManager property set before calling 'executeCount'");
532
+ }
533
+ const qr = await this.take(0).inlineCount(true).execute();
534
+ return qr.inlineCount;
535
+ }
536
+ /**
537
+ Returns the serializable form of this query: its resource name, clauses, parameters and options,
538
+ with client property names. `JSON.stringify` calls it, and passing the parsed JSON to the
539
+ `EntityQuery` constructor recreates the query. The `EntityManager` and `DataService` are not
540
+ included.
541
+ */
542
+ toJSON() {
543
+ const json = this.toJSONExt();
544
+ // usePost is not part of the query sent to the server, so toJSONExt leaves it out;
545
+ // it is part of the query itself, and fromJSON reads it back.
546
+ if (this.usePostEnabled)
547
+ json.usePost = true;
548
+ return json;
549
+ }
550
+ /** Typically only for use when building UriBuilderAdapters.
551
+ @hidden @internal
552
+ */
553
+ toJSONExt(context) {
554
+ context = context || {};
555
+ context.entityType = context.entityType || this.fromEntityType;
556
+ // A query written in the server's names (useNameOnServer) is sent as it is.
557
+ if (this.usesNameOnServer)
558
+ context.toNameOnServer = false;
559
+ context.propertyPathFn = context.toNameOnServer ? context.entityType.clientPropertyPathToServer.bind(context.entityType) : core.identity;
560
+ let toJSONExtFn = function (v) {
561
+ return v ? v.toJSONExt(context) : undefined;
562
+ };
563
+ return core.toJson(this, {
564
+ "from,resourceName": null,
565
+ "toType,resultEntityType": function (v) {
566
+ // resultEntityType can be either a string or an entityType
567
+ return v ? (typeof v === 'string' ? v : v.name) : undefined;
568
+ },
569
+ "where,wherePredicate": toJSONExtFn,
570
+ "orderBy,orderByClause": toJSONExtFn,
571
+ "select,selectClause": toJSONExtFn,
572
+ "expand,expandClause": toJSONExtFn,
573
+ "skip,skipCount": null,
574
+ "take,takeCount": null,
575
+ parameters: function (v) {
576
+ return core.isEmpty(v) ? undefined : v;
577
+ },
578
+ "inlineCount,inlineCountEnabled": false,
579
+ "noTracking,noTrackingEnabled": false,
580
+ queryOptions: null
581
+ });
582
+ }
583
+ /**
584
+ Static method that creates an EntityQuery that will allow 'requerying' an entity or a collection of entities by primary key. This can be useful
585
+ to force a requery of selected entities, or to restrict an existing collection of entities according to some filter.
586
+
587
+ Works for a single entity or an array of entities of the SAME type.
588
+ Does not work for an array of entities of different types.
589
+ ```ts
590
+ // assuming 'customers' is an array of 'Customer' entities retrieved earlier.
591
+ const customersQuery = EntityQuery.fromEntities(customers); // EntityQuery<Customer>
592
+ ```
593
+
594
+ The resulting query can, of course, be extended
595
+ ```ts
596
+ // assuming 'customers' is an array of 'Customer' entities retrieved earlier.
597
+ const customersQuery = EntityQuery.fromEntities(customers)
598
+ .where("region", "ne", null);
599
+ ```
600
+
601
+ Single entities can requeried as well.
602
+ ```ts
603
+ // assuming 'customer' is a 'Customer' entity retrieved earlier.
604
+ const customerQuery = EntityQuery.fromEntities(customer);
605
+ ```
606
+
607
+ will create a query that will return an array containing a single customer entity.
608
+ @param entities - The entities for which we want to create an EntityQuery.
609
+ */
610
+ static fromEntities(entities) {
611
+ assertParam(entities, "entities").isEntity().or().isNonEmptyArray().isEntity().check();
612
+ let ents = (Array.isArray(entities)) ? entities : [entities];
613
+ let firstEntity = ents[0];
614
+ let type = firstEntity.entityType;
615
+ if (ents.some(function (e) {
616
+ return e.entityType !== type;
617
+ })) {
618
+ throw new Error("All 'fromEntities' must be the same type; at least one is not of type " +
619
+ type.name);
620
+ }
621
+ let q = new EntityQuery(type.defaultResourceName);
622
+ let preds = ents.map(function (entity) {
623
+ return buildPredicate(entity);
624
+ });
625
+ let pred = Predicate.or(preds);
626
+ q = q.where(pred);
627
+ let em = firstEntity.entityAspect.entityManager;
628
+ if (em) {
629
+ q = q.using(em);
630
+ }
631
+ return q;
632
+ }
633
+ /**
634
+ Creates an EntityQuery for the specified {@link EntityKey}.
635
+ ```ts
636
+ const entityKey = new EntityKey(Employee, 1);
637
+ const query = EntityQuery.fromEntityKey(entityKey);
638
+ ```
639
+
640
+ or
641
+ ```ts
642
+ // 'employee' is a previously queried employee
643
+ const entityKey = employee.entityAspect.getKey();
644
+ const query = EntityQuery.fromEntityKey(entityKey);
645
+ ```
646
+ @param entityKey - The {@link EntityKey} for which a query will be created.
647
+ */
648
+ static fromEntityKey(entityKey) {
649
+ assertParam(entityKey, "entityKey").isInstanceOf(EntityKey).check();
650
+ let q = new EntityQuery(entityKey.entityType.defaultResourceName);
651
+ let pred = buildKeyPredicate(entityKey);
652
+ q = q.where(pred).toType(entityKey.entityType);
653
+ return q;
654
+ }
655
+ /**
656
+ Creates an EntityQuery for the specified entity and {@link NavigationProperty}.
657
+ ```ts
658
+ // 'employee' is a previously queried employee
659
+ const query = EntityQuery.fromEntityNavigation(employee, "orders");
660
+ ```
661
+
662
+ will return a query for the "orders" of the specified 'employee'. The {@link NavigationProperty}
663
+ itself may be passed instead of its name:
664
+ ```ts
665
+ const ordersNavProp = employee.entityType.getNavigationProperty("orders");
666
+ const query = EntityQuery.fromEntityNavigation(employee, ordersNavProp);
667
+ ```
668
+ @param entity - The Entity whose navigation property will be queried.
669
+ @param navigationProperty - The {@link NavigationProperty} or name of the NavigationProperty to be queried.
670
+ */
671
+ static fromEntityNavigation = function (entity, navigationProperty) {
672
+ assertParam(entity, "entity").isEntity().check();
673
+ let navProperty = entity.entityType._checkNavProperty(navigationProperty);
674
+ let q = new EntityQuery(navProperty.entityType.defaultResourceName);
675
+ let pred = buildNavigationPredicate(entity, navProperty);
676
+ if (pred == null) {
677
+ throw new Error("Unable to create a NavigationQuery for navigationProperty: " + navProperty.name);
678
+ }
679
+ q = q.where(pred);
680
+ let em = entity.entityAspect.entityManager;
681
+ return em ? q.using(em) : q;
682
+ };
683
+ // protected methods
684
+ /** @hidden @internal */
685
+ _getFromEntityType(metadataStore, throwErrorIfNotFound) {
686
+ // Uncomment next two lines if we make this method public.
687
+ // assertParam(metadataStore, "metadataStore").isInstanceOf(MetadataStore).check();
688
+ // assertParam(throwErrorIfNotFound, "throwErrorIfNotFound").isBoolean().isOptional().check();
689
+ let entityType = this.fromEntityType;
690
+ if (entityType)
691
+ return entityType;
692
+ let resourceName = this.resourceName;
693
+ if (!resourceName) {
694
+ throw new Error("There is no resourceName for this query");
695
+ }
696
+ if (metadataStore.isEmpty()) {
697
+ if (throwErrorIfNotFound) {
698
+ throw new Error("There is no metadata available for this query. " +
699
+ "Are you querying the local cache before you've fetched metadata?");
700
+ }
701
+ else {
702
+ return undefined;
703
+ }
704
+ }
705
+ let entityTypeName = metadataStore.getEntityTypeNameForResourceName(resourceName);
706
+ if (entityTypeName) {
707
+ entityType = metadataStore._getStructuralType(entityTypeName);
708
+ }
709
+ else {
710
+ entityType = this._getToEntityType(metadataStore, true);
711
+ }
712
+ if (!entityType) {
713
+ if (throwErrorIfNotFound) {
714
+ throw new Error(core.formatString("Cannot find an entityType for resourceName: '%1'. ", resourceName) + core.strings.TO_TYPE);
715
+ }
716
+ else {
717
+ return undefined;
718
+ }
719
+ }
720
+ this.fromEntityType = entityType;
721
+ return entityType;
722
+ }
723
+ /** @hidden @internal */
724
+ _getToEntityType(metadataStore, skipFromCheck) {
725
+ // skipFromCheck is to avoid recursion if called from _getFromEntityType;
726
+ if (this.resultEntityType instanceof EntityType) {
727
+ return this.resultEntityType;
728
+ }
729
+ else if (this.resultEntityType) {
730
+ // resultEntityType is a string
731
+ this.resultEntityType = metadataStore._getStructuralType(this.resultEntityType, false);
732
+ return this.resultEntityType;
733
+ }
734
+ else {
735
+ // resolve it, if possible, via the resourceName
736
+ // do not cache this value in this case
737
+ // cannot determine the resultEntityType if a selectClause is present.
738
+ // return skipFromCheck ? null : (!this.selectClause) && this._getFromEntityType(metadataStore, false);
739
+ if (skipFromCheck || this.selectClause) {
740
+ return undefined;
741
+ }
742
+ else {
743
+ return this._getFromEntityType(metadataStore, false);
744
+ }
745
+ }
746
+ }
747
+ /** @hidden @internal */
748
+ // for testing
749
+ _toUri(em) {
750
+ let ds = DataService.resolve([em.dataService]);
751
+ return ds.uriBuilder.buildUri(this, em.metadataStore);
752
+ }
753
+ }
754
+ EntityQuery.prototype._$typeName = "EntityQuery";
755
+ // private functions
756
+ function fromJSON(eq, json) {
757
+ core.toJson(json, {
758
+ "resourceName,from": null,
759
+ // just the name comes back and will be resolved later
760
+ "resultEntityType,toType": null,
761
+ "wherePredicate,where": function (v) {
762
+ return v ? new Predicate(v) : undefined;
763
+ },
764
+ "orderByClause,orderBy": function (v) {
765
+ return v ? new OrderByClause(v) : undefined;
766
+ },
767
+ "selectClause,select": function (v) {
768
+ return v ? new SelectClause(v) : undefined;
769
+ },
770
+ "expandClause,expand": function (v) {
771
+ return v ? new ExpandClause(v) : undefined;
772
+ },
773
+ "skipCount,skip": null,
774
+ "takeCount,take": null,
775
+ parameters: function (v) {
776
+ return core.isEmpty(v) ? undefined : v;
777
+ },
778
+ "inlineCountEnabled,inlineCount": false,
779
+ "noTrackingEnabled,noTracking": false,
780
+ "usePostEnabled,usePost": false,
781
+ queryOptions: function (v) {
782
+ return v ? QueryOptions.fromJSON(v) : undefined;
783
+ }
784
+ }, eq);
785
+ return eq;
786
+ }
787
+ function clone(eq, propName, value) {
788
+ // immutable queries mean that we don't need to clone if no change in value.
789
+ if (propName) {
790
+ if (eq[propName] === value)
791
+ return eq;
792
+ }
793
+ // copying QueryOptions is safe because they are are immutable;
794
+ let copy = core.extend(new EntityQuery(), eq, [
795
+ "resourceName",
796
+ "fromEntityType",
797
+ "wherePredicate",
798
+ "orderByClause",
799
+ "selectClause",
800
+ "skipCount",
801
+ "takeCount",
802
+ "expandClause",
803
+ "inlineCountEnabled",
804
+ "noTrackingEnabled",
805
+ "usePostEnabled",
806
+ "usesNameOnServer",
807
+ "queryOptions",
808
+ "entityManager",
809
+ "dataService",
810
+ "resultEntityType"
811
+ ]);
812
+ copy.parameters = core.extend({}, eq.parameters);
813
+ if (propName) {
814
+ copy[propName] = value;
815
+ }
816
+ return copy;
817
+ }
818
+ function processUsing(eq, mapArg, value, propertyName) {
819
+ const map = mapArg;
820
+ const eqx = eq;
821
+ let typeName = value._$typeName || ((value instanceof BreezeEnum) && value.constructor.name);
822
+ let key = typeName && typeName.substr(0, 1).toLowerCase() + typeName.substr(1);
823
+ if (propertyName && key !== propertyName) {
824
+ throw new Error("Invalid value for property: " + propertyName);
825
+ }
826
+ if (key) {
827
+ let fn = map[key];
828
+ if (fn === undefined) {
829
+ throw new Error("Invalid config property: " + key);
830
+ }
831
+ else if (fn === null) {
832
+ eqx[key] = value;
833
+ }
834
+ else {
835
+ fn(eq, value);
836
+ }
837
+ }
838
+ else {
839
+ core.objectForEach(value, (propName, val) => {
840
+ processUsing(eq, map, val, propName);
841
+ });
842
+ }
843
+ }
844
+ function normalizePropertyPaths(propertyPaths) {
845
+ assertParam(propertyPaths, "propertyPaths").isOptional().isString().or().isArray().isString().check();
846
+ if (typeof propertyPaths === 'string') {
847
+ propertyPaths = propertyPaths.split(",");
848
+ }
849
+ propertyPaths = propertyPaths.map(function (pp) {
850
+ return pp.trim();
851
+ });
852
+ return propertyPaths;
853
+ }
854
+ function buildPredicate(entity) {
855
+ let entityType = entity.entityType;
856
+ let predParts = entityType.keyProperties.map(function (kp) {
857
+ return Predicate.create(kp.name, FilterQueryOp.Equals, entity.getProperty(kp.name));
858
+ });
859
+ let pred = Predicate.and(predParts);
860
+ return pred;
861
+ }
862
+ function buildKeyPredicate(entityKey) {
863
+ let keyProps = entityKey.entityType.keyProperties;
864
+ let preds = core.arrayZip(keyProps, entityKey.values, function (kp, v) {
865
+ return Predicate.create(kp.name, FilterQueryOp.Equals, v);
866
+ });
867
+ let pred = Predicate.and(preds);
868
+ return pred;
869
+ }
870
+ function buildNavigationPredicate(entity, navigationProperty) {
871
+ if (navigationProperty.isScalar) {
872
+ if (navigationProperty.foreignKeyNames.length === 0)
873
+ return null;
874
+ let relatedKeyValues = navigationProperty.foreignKeyNames.map((fkName) => {
875
+ return entity.getProperty(fkName);
876
+ });
877
+ let entityKey = new EntityKey(navigationProperty.entityType, relatedKeyValues);
878
+ return buildKeyPredicate(entityKey);
879
+ }
880
+ else {
881
+ let inverseNp = navigationProperty.inverse;
882
+ let foreignKeyNames = inverseNp ? inverseNp.foreignKeyNames : navigationProperty.invForeignKeyNames;
883
+ if (foreignKeyNames.length === 0)
884
+ return null;
885
+ let keyValues = entity.entityAspect.getKey().values;
886
+ let predParts = core.arrayZip(foreignKeyNames, keyValues, (fkName, kv) => {
887
+ return Predicate.create(fkName, FilterQueryOp.Equals, kv);
888
+ });
889
+ return Predicate.and(predParts);
890
+ }
891
+ }
892
+ /**
893
+ FilterQueryOp is an 'Enum' containing all of the valid {@link Predicate}
894
+ filter operators for an {@link EntityQuery}.
895
+ */
896
+ export class FilterQueryOp extends BreezeEnum {
897
+ /** Aliases: "eq", "==" */
898
+ static Equals = new FilterQueryOp({ operator: "eq" });
899
+ /** Aliases: "ne", "!=" */
900
+ static NotEquals = new FilterQueryOp({ operator: "ne" });
901
+ /** Aliases: "gt", ">" */
902
+ static GreaterThan = new FilterQueryOp({ operator: "gt" });
903
+ /** Aliases: "lt", "<" */
904
+ static LessThan = new FilterQueryOp({ operator: "lt" });
905
+ /** Aliases: "ge", ">=" */
906
+ static GreaterThanOrEqual = new FilterQueryOp({ operator: "ge" });
907
+ /** Aliases: "le", "<=" */
908
+ static LessThanOrEqual = new FilterQueryOp({ operator: "le" });
909
+ /** String operation: Is a string a substring of another string. Aliases: "substringof" */
910
+ static Contains = new FilterQueryOp({ operator: "contains" });
911
+ /** No aliases */
912
+ static StartsWith = new FilterQueryOp({ operator: "startswith" });
913
+ /** No aliases */
914
+ static EndsWith = new FilterQueryOp({ operator: "endswith" });
915
+ /** Aliases: "some" */
916
+ static Any = new FilterQueryOp({ operator: "any" });
917
+ /** Aliases: "every" */
918
+ static All = new FilterQueryOp({ operator: "all" });
919
+ /** No aliases */
920
+ static In = new FilterQueryOp({ operator: "in" });
921
+ }
922
+ FilterQueryOp.prototype._$typeName = "FilterQueryOp";
923
+ FilterQueryOp.resolveSymbols();
924
+ /**
925
+ BooleanQueryOp is an 'Enum' containing all of the valid boolean
926
+ operators for an {@link EntityQuery}.
927
+ */
928
+ export class BooleanQueryOp extends BreezeEnum {
929
+ static And = new BooleanQueryOp({ operator: "and" });
930
+ static Or = new BooleanQueryOp({ operator: "or" });
931
+ static Not = new BooleanQueryOp({ operator: "not" });
932
+ }
933
+ BooleanQueryOp.prototype._$typeName = "BooleanQueryOp";
934
+ BooleanQueryOp.resolveSymbols();
935
+ /** For use by breeze plugin authors only. The class is used in most {@link UriBuilderAdapter} implementations
936
+ @adapter (see {@link UriBuilderAdapter})
937
+ @hidden
938
+
939
+ An OrderByClause is a description of the properties and direction that the result
940
+ of a query should be sorted in. OrderByClauses are immutable, which means that any
941
+ method that would modify an OrderByClause actually returns a new OrderByClause.
942
+
943
+ For example for an Employee object with properties of 'company' and 'lastName' the following would be valid expressions:
944
+ ```ts
945
+ const obc = new OrderByClause(["company.companyName", "lastName"]);
946
+ ```
947
+
948
+ or
949
+ ```ts
950
+ const obc = new OrderByClause(["company.companyName desc", "lastName"]);
951
+ ```
952
+
953
+ or
954
+ ```ts
955
+ const obc = new OrderByClause(["company.companyName", "lastName"], true);
956
+ ```
957
+ */
958
+ export class OrderByClause {
959
+ /** @hidden @internal */
960
+ items;
961
+ constructor(propertyPaths, isDesc) {
962
+ if (propertyPaths.length === 0) {
963
+ throw new Error("OrderByClause cannot be empty");
964
+ }
965
+ // you can also pass in an array of orderByClauses
966
+ if (propertyPaths[0] instanceof OrderByClause) {
967
+ let clauses = propertyPaths;
968
+ this.items = arrayFlatMap(clauses, c => c.items);
969
+ // this.items = Array.prototype.concat.apply(clauses[0].items, clauses.slice(1).map(core.pluck("items")));
970
+ // this.items = Array.prototype.concat.apply([], clauses.map(core.pluck("items")));
971
+ }
972
+ else {
973
+ this.items = propertyPaths.map(function (pp) {
974
+ return new OrderByItem(pp, isDesc);
975
+ });
976
+ }
977
+ }
978
+ validate(entityType) {
979
+ if (entityType == null || entityType.isAnonymous)
980
+ return;
981
+ this.items.forEach((item) => {
982
+ item.validate(entityType);
983
+ });
984
+ }
985
+ getComparer(entityType) {
986
+ let orderByFuncs = this.items.map(function (obc) {
987
+ return obc.getComparer(entityType);
988
+ });
989
+ return function (entity1, entity2) {
990
+ for (let i = 0; i < orderByFuncs.length; i++) {
991
+ let result = orderByFuncs[i](entity1, entity2);
992
+ if (result !== 0) {
993
+ return result;
994
+ }
995
+ }
996
+ return 0;
997
+ };
998
+ }
999
+ toJSONExt(context) {
1000
+ return this.items.map(function (item) {
1001
+ return context.propertyPathFn(item.propertyPath) + (item.isDesc ? " desc" : "");
1002
+ });
1003
+ }
1004
+ }
1005
+ /** @hidden @internal */
1006
+ export class OrderByItem {
1007
+ propertyPath;
1008
+ isDesc;
1009
+ lastProperty;
1010
+ constructor(propertyPath, isDesc) {
1011
+ if (!(typeof propertyPath === 'string')) {
1012
+ throw new Error("propertyPath is not a string");
1013
+ }
1014
+ propertyPath = propertyPath.trim();
1015
+ let parts = propertyPath.split(' ');
1016
+ // parts[0] is the propertyPath; [1] would be whether descending or not.
1017
+ // if (parts.length > 1 && isDesc !== true && isDesc !== false) {
1018
+ if (parts.length > 1 && isDesc == null) {
1019
+ isDesc = stringStartsWith(parts[1].toLowerCase(), "desc");
1020
+ if (!isDesc) {
1021
+ // isDesc is false but check to make sure its intended.
1022
+ let isAsc = stringStartsWith(parts[1].toLowerCase(), "asc");
1023
+ if (!isAsc) {
1024
+ throw new Error("the second word in the propertyPath must begin with 'desc' or 'asc'");
1025
+ }
1026
+ }
1027
+ }
1028
+ this.propertyPath = parts[0];
1029
+ this.isDesc = isDesc || false;
1030
+ }
1031
+ validate(entityType) {
1032
+ if (entityType == null || entityType.isAnonymous)
1033
+ return;
1034
+ // will throw an exception on bad propertyPath
1035
+ this.lastProperty = entityType.getProperty(this.propertyPath, true);
1036
+ return this.lastProperty;
1037
+ }
1038
+ getComparer(entityType) {
1039
+ let propDataType;
1040
+ let isCaseSensitive;
1041
+ if (!this.lastProperty)
1042
+ this.validate(entityType);
1043
+ if (this.lastProperty) {
1044
+ propDataType = this.lastProperty.dataType;
1045
+ isCaseSensitive = this.lastProperty.parentType.metadataStore.localQueryComparisonOptions.isCaseSensitive;
1046
+ }
1047
+ let propertyPath = this.propertyPath;
1048
+ let isDesc = this.isDesc;
1049
+ return function (entity1, entity2) {
1050
+ let value1 = EntityAspect.getPropertyPathValue(entity1, propertyPath);
1051
+ let value2 = EntityAspect.getPropertyPathValue(entity2, propertyPath);
1052
+ let dataType = propDataType || (value1 && DataType.fromValue(value1)) || DataType.fromValue(value2);
1053
+ if (dataType === DataType.String) {
1054
+ if (isCaseSensitive) {
1055
+ value1 = value1 || "";
1056
+ value2 = value2 || "";
1057
+ }
1058
+ else {
1059
+ value1 = (value1 || "").toLowerCase();
1060
+ value2 = (value2 || "").toLowerCase();
1061
+ }
1062
+ }
1063
+ else {
1064
+ let normalize = DataType.getComparableFn(dataType);
1065
+ value1 = normalize(value1);
1066
+ value2 = normalize(value2);
1067
+ }
1068
+ if (value1 === value2) {
1069
+ return 0;
1070
+ }
1071
+ else if (value1 > value2 || value2 === undefined) {
1072
+ return isDesc ? -1 : 1;
1073
+ }
1074
+ else {
1075
+ return isDesc ? 1 : -1;
1076
+ }
1077
+ };
1078
+ }
1079
+ }
1080
+ /** For use by breeze plugin authors only. The class is used in most {@link UriBuilderAdapter} implementations
1081
+ @adapter (see {@link UriBuilderAdapter})
1082
+ @hidden
1083
+ */
1084
+ export class SelectClause {
1085
+ propertyPaths;
1086
+ /** @hidden @internal */
1087
+ _pathNames;
1088
+ constructor(propertyPaths) {
1089
+ this.propertyPaths = propertyPaths;
1090
+ this._pathNames = propertyPaths.map(function (pp) {
1091
+ // every dot, not just the first: order.customer.companyName -> order_customer_companyName
1092
+ return pp.split(".").join("_");
1093
+ });
1094
+ }
1095
+ validate(entityType) {
1096
+ if (entityType == null || entityType.isAnonymous)
1097
+ return; // can't validate yet
1098
+ // will throw an exception on bad propertyPath
1099
+ this.propertyPaths.forEach(function (path) {
1100
+ entityType.getProperty(path, true);
1101
+ });
1102
+ }
1103
+ /** @hidden @internal
1104
+ The property names of a projected result. Given the queried type, they are the names a
1105
+ remote query's results get: the server names each path by joining the server names of
1106
+ its properties (the ones sent in the select clause) with '_', and the client passes that
1107
+ name through the naming convention, as it does every key of an anonymous result. */
1108
+ _resultNames(entityType) {
1109
+ if (entityType == null || entityType.isAnonymous)
1110
+ return this._pathNames;
1111
+ const et = entityType;
1112
+ const toClient = et.metadataStore.namingConvention.serverPropertyNameToClient;
1113
+ return this.propertyPaths.map(function (pp) {
1114
+ return toClient(et.clientPropertyPathToServer(pp, "_"));
1115
+ });
1116
+ }
1117
+ toFunction(config) {
1118
+ let that = this;
1119
+ let names = this._resultNames(config && config.entityType);
1120
+ return function (entity) {
1121
+ let result = {};
1122
+ that.propertyPaths.forEach(function (path, i) {
1123
+ result[names[i]] = EntityAspect.getPropertyPathValue(entity, path);
1124
+ });
1125
+ return result;
1126
+ };
1127
+ }
1128
+ toJSONExt(context) {
1129
+ return this.propertyPaths.map(function (pp) {
1130
+ return context.propertyPathFn(pp);
1131
+ });
1132
+ }
1133
+ }
1134
+ /** For use by breeze plugin authors only. The class is used in most {@link UriBuilderAdapter} implementations
1135
+ @adapter (see {@link UriBuilderAdapter})
1136
+ @hidden
1137
+ */
1138
+ export class ExpandClause {
1139
+ propertyPaths;
1140
+ constructor(propertyPaths) {
1141
+ this.propertyPaths = propertyPaths;
1142
+ }
1143
+ toJSONExt(context) {
1144
+ return this.propertyPaths.map(function (pp) {
1145
+ return context.propertyPathFn(pp);
1146
+ });
1147
+ }
1148
+ }
1149
+ //# sourceMappingURL=entity-query.js.map