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,1294 @@
1
+ import { core, arraySlice, hasOwnProperty as hasOwnProp, stringStartsWith as strStartsWith, stringEndsWith as strEndsWith } from '../core/core.js';
2
+ import { EntityType, DataProperty } from '../metadata/entity-metadata.js';
3
+ import { DataType } from '../metadata/data-type.js';
4
+ import { EntityAspect } from '../entity/entity-aspect.js';
5
+ /**
6
+ Used to define a 'where' predicate for an {@link EntityQuery}. Predicates are immutable, which means that any
7
+ method that would modify a Predicate actually returns a new Predicate.
8
+ ```ts
9
+ const p = Predicate.for(Order);
10
+ const p1 = p("freight", ">", 100);
11
+ const p2 = p1.and(p("shipCity", "startsWith", "C"));
12
+ const query = EntityQuery.from(Order).where(p2);
13
+ ```
14
+ */
15
+ export class Predicate {
16
+ /**
17
+ Predicate constructor. The compiler checks nothing it is given; for that, build the Predicate with
18
+ {@link Predicate.for} or {@link Predicate.create} and a type argument instead.
19
+ ```ts
20
+ const p1 = new Predicate("companyName", "startsWith", "B");
21
+ const query = EntityQuery.from(Customer).where(p1);
22
+ ```
23
+
24
+ or
25
+ ```ts
26
+ const p2 = new Predicate("region", FilterQueryOp.Equals, null);
27
+ const query = EntityQuery.from(Customer).where(p2);
28
+ ```
29
+ @param args - `property, operator, value`, in that order:
30
+ - **property**: A property name, a nested property name or an expression involving a property name.
31
+ - **operator**: the filter query operator.
32
+ - **value**: This will be treated as either a property expression or a literal depending on context. In general,
33
+ if the value can be interpreted as a property expression it will be, otherwise it will be treated as a literal.
34
+ In most cases this works well, but you can also force the interpretation by making the value argument itself an object with a 'value'
35
+ property and an 'isLiteral' property set to either true or false. Breeze also tries to infer the dataType of any
36
+ literal based on context, if this fails you can force this inference by making the value argument an object with a
37
+ 'value' property and a 'dataType' property set to one of the breeze.DataType enumeration instances.
38
+ */
39
+ constructor(...args) {
40
+ if (args.length === 0)
41
+ return;
42
+ if (!(this instanceof Predicate)) {
43
+ return new Predicate(...args);
44
+ }
45
+ return Predicate.create(...args);
46
+ }
47
+ /**
48
+ Same as using the ctor, except that given the entity type as a type argument, the compiler checks
49
+ the predicate against that type - everything in the object form, the property path in the
50
+ three-argument form:
51
+ ```ts
52
+ const p1 = Predicate.create<Order>({ freight: { gt: 100 } });
53
+ const p2 = Predicate.create<Order>("freight", ">", 100);
54
+ ```
55
+
56
+ Without one, nothing is checked, and
57
+ ```ts
58
+ const p3 = Predicate.create("freight", ">", 100);
59
+ // is the same as
60
+ const p4 = new Predicate("freight", ">", 100);
61
+ ```
62
+ @param args - `property, operator, value`, in that order:
63
+ - **property**: A property name, a nested property name or an expression involving a property name.
64
+ - **operator**: the filter query operator.
65
+ - **value**: This will be treated as either a property expression or a literal depending on context. In general,
66
+ if the value can be interpreted as a property expression it will be, otherwise it will be treated as a literal.
67
+ In most cases this works well, but you can also force the interpretation by making the value argument itself an object with a 'value'
68
+ property and an 'isLiteral' property set to either true or false. Breeze also tries to infer the dataType of any
69
+ literal based on context, if this fails you can force this inference by making the value argument an object with a
70
+ 'value' property and a 'dataType' property set to one of the breeze.DataType enumeration instances.
71
+ */
72
+ static create(...args) {
73
+ // can be called from std javascript without new ( legacy )
74
+ // empty ctor is used by all subclasses.
75
+ if (args.length === 0)
76
+ return new Predicate();
77
+ if (args.length === 1) {
78
+ // possibilities:
79
+ // Predicate([ aPredicate ]) or Predicate(["freight", ">", 100]) - an array
80
+ // Predicate(aPredicate) - a predicate
81
+ // Predicate( "freight gt 100" } // passthru ( i.e. a raw filter string) - a string
82
+ // Predicate( { freight: { ">": 100 } }) - an object
83
+ let arg = arguments[0];
84
+ if (Array.isArray(arg)) {
85
+ if (arg.length === 1) {
86
+ // recurse
87
+ return new Predicate(arg[0]);
88
+ }
89
+ else {
90
+ return createPredicateFromArray(arg);
91
+ }
92
+ }
93
+ else if (arg instanceof Predicate) {
94
+ return arg;
95
+ }
96
+ else if (typeof arg === 'string') {
97
+ return new PassthruPredicate(arg);
98
+ }
99
+ else {
100
+ return createPredicateFromObject(arg);
101
+ }
102
+ }
103
+ else {
104
+ // 2 possibilities
105
+ // Predicate("freight", ">", 100");
106
+ // Predicate("orders", "any", "freight", ">", 950);
107
+ return createPredicateFromArray(args);
108
+ }
109
+ }
110
+ /** @hidden @internal */
111
+ _validate(entityType, usesNameOnServer) {
112
+ // noop here;
113
+ }
114
+ static and(...args) {
115
+ return new AndOrPredicate("and", args);
116
+ }
117
+ static or(...args) {
118
+ return new AndOrPredicate("or", args);
119
+ }
120
+ /**
121
+ Creates a 'composite' Predicate by 'negating' a specified predicate.
122
+ ```ts
123
+ const p1 = Predicate.create<Order>({ freight: { gt: 100 } });
124
+ const not_p1 = Predicate.not(p1);
125
+ ```
126
+
127
+ This can also be accomplished using the 'instance' version of the 'not' method
128
+ ```ts
129
+ const not_p1 = p1.not();
130
+ ```
131
+
132
+ Both of which would be the same as
133
+ ```ts
134
+ const not_p1 = Predicate.create<Order>({ freight: { le: 100 } });
135
+ ```
136
+ */
137
+ static not(pred) {
138
+ return pred.not();
139
+ }
140
+ /**
141
+ Builds Predicates checked against one entity type.
142
+ ```ts
143
+ const p = Predicate.for(Customer);
144
+ const pred = p("companyName", "startsWith", "C").and(p("city", "eq", "Vienna"));
145
+ ```
146
+
147
+ A standalone Predicate has no query to take an entity type from, so on its own
148
+ {@link Predicate.create} cannot check anything. Naming the type supplies what is missing, the
149
+ same way {@link EntityQuery.from} does for a query - and from a constructor rather than a type
150
+ argument, so the type is written once.
151
+
152
+ The constructor is read for its type only; nothing about it is kept. The predicates are ordinary
153
+ Predicates at run time, typed `Predicate<U>`, so that what they are combined with, and the query
154
+ they are used in, is checked too. The constructor does not have to be registered with a MetadataStore for this - though
155
+ if it is not, nothing validates the path against the metadata either, exactly as before.
156
+ @param ctor - The entity class to check property paths against.
157
+ @returns A factory that builds Predicates for that type.
158
+ */
159
+ static for(ctor) {
160
+ return ((...args) => Predicate.create(...args));
161
+ }
162
+ /**
163
+ Adds functions that predicates can call, such as `toupper` in `Predicate.create<Customer>("toupper(companyName)", "==", "ACME")`,
164
+ or replaces existing ones. Each entry maps a function name to `fn`, which evaluates it in local
165
+ queries, and the {@link DataType} it returns. A server query sends the call by name, so the
166
+ server must support the function too.
167
+ ```ts
168
+ Predicate.extendFuncMap({
169
+ initial: { fn: (s: string) => s.charAt(0), dataType: DataType.String }
170
+ });
171
+ ```
172
+ @param funcMap - The functions to add, keyed by name. Write names in lower case: Breeze lower-cases a
173
+ function name when it parses a predicate.
174
+ */
175
+ static extendFuncMap(funcMap) {
176
+ for (let func in (funcMap || {})) {
177
+ let config = funcMap[func];
178
+ FnExpr._funcMap.set(func, config);
179
+ }
180
+ }
181
+ ;
182
+ /**
183
+ 'And's this Predicate with one or more other Predicates and returns a new 'composite' Predicate
184
+ ```ts
185
+ const p = Predicate.for(Order);
186
+ const dt = new Date(1988, 9, 12);
187
+ const p1 = p("orderDate", "ne", dt);
188
+ const p2 = p("shipCity", "startsWith", "C");
189
+ const p3 = p("freight", ">", 100);
190
+ const newPred = p1.and(p2, p3);
191
+ ```
192
+
193
+ or
194
+ ```ts
195
+ const preds = [p2, p3];
196
+ const newPred = p1.and(preds);
197
+ ```
198
+
199
+ The 'and' method is also used to write "fluent" expressions
200
+ ```ts
201
+ const p4 = p("shipCity", "startsWith", "F")
202
+ .and(p("freight", "gt", 2000));
203
+ ```
204
+
205
+ It also takes the arguments of {@link Predicate.create} in place of a Predicate - such as
206
+ `.and("freight", "gt", 2000)` - checked against the Predicate's entity type, as
207
+ {@link EntityQuery.where} checks them against the query's.
208
+ @param args - multiple Predicates or an array of Predicates.
209
+ Any null or undefined values passed in will be automatically filtered out before constructing the composite predicate.
210
+ */
211
+ and(...args) {
212
+ return new AndOrPredicate("and", argsForAndOrPredicates(this, args));
213
+ }
214
+ /**
215
+ 'Or's this Predicate with one or more other Predicates and returns a new 'composite' Predicate
216
+ ```ts
217
+ const p = Predicate.for(Order);
218
+ const dt = new Date(1988, 9, 12);
219
+ const p1 = p("orderDate", "ne", dt);
220
+ const p2 = p("shipCity", "startsWith", "C");
221
+ const p3 = p("freight", ">", 100);
222
+ const newPred = p1.or(p2, p3);
223
+ ```
224
+
225
+ or
226
+ ```ts
227
+ const preds = [p2, p3];
228
+ const newPred = p1.or(preds);
229
+ ```
230
+
231
+ The 'or' method is also used to write "fluent" expressions
232
+ ```ts
233
+ const p4 = p("shipCity", "startsWith", "F")
234
+ .or(p("freight", "gt", 2000));
235
+ ```
236
+
237
+ It also takes the arguments of {@link Predicate.create} in place of a Predicate - such as
238
+ `.or("freight", "gt", 2000)` - checked against the Predicate's entity type, as
239
+ {@link EntityQuery.where} checks them against the query's.
240
+ @param args - multiple Predicates or an array of Predicates.
241
+ Any null or undefined values passed in will be automatically filtered out before constructing the composite predicate.
242
+ */
243
+ or(...args) {
244
+ return new AndOrPredicate("or", argsForAndOrPredicates(this, args));
245
+ }
246
+ /**
247
+ Returns the 'negated' version of this Predicate
248
+ ```ts
249
+ const p1 = Predicate.create<Order>({ freight: { gt: 100 } });
250
+ const not_p1 = p1.not();
251
+ ```
252
+
253
+ This can also be accomplished using the 'static' version of the 'not' method
254
+ ```ts
255
+ const not_p1 = Predicate.not(p1);
256
+ ```
257
+
258
+ which would be the same as
259
+ ```ts
260
+ const not_p1 = Predicate.create<Order>({ freight: { le: 100 } });
261
+ ```
262
+ */
263
+ not() {
264
+ return new UnaryPredicate("not", this);
265
+ }
266
+ /**
267
+ Returns this predicate in Breeze's JSON query syntax, with property paths as written - the object
268
+ form that {@link Predicate.create} and {@link EntityQuery.where} also accept, such as
269
+ `{ freight: { gt: 100 } }`. `JSON.stringify` calls it.
270
+ */
271
+ //
272
+ toJSON() {
273
+ // toJSON ( part of js standard - takes a single parameter
274
+ // that is either "" or the name of the property being serialized.
275
+ return this.toJSONExt({ entityType: this._entityType });
276
+ }
277
+ /** For use by breeze plugin authors only. The class is for use in building a {@link UriBuilderAdapter} implementation.
278
+ @adapter (see {@link UriBuilderAdapter})
279
+ @hidden @internal
280
+ */
281
+ toJSONExt(context) {
282
+ return this.visit(context, toJSONVisitor);
283
+ }
284
+ /** For use by breeze plugin authors only. The class is for use in building a {@link UriBuilderAdapter} implementation.
285
+ @adapter (see {@link UriBuilderAdapter})
286
+ @hidden @internal
287
+ */
288
+ toFunction(context) {
289
+ return this.visit(context, toFunctionVisitor);
290
+ }
291
+ /** Returns this predicate as a JSON string: `JSON.stringify` of {@link Predicate.toJSON}. Useful for logging and debugging. */
292
+ toString() {
293
+ return JSON.stringify(this);
294
+ }
295
+ /** For use by breeze plugin authors only. The class is for use in building a {@link UriBuilderAdapter} implementation.
296
+ @adapter (see {@link UriBuilderAdapter})
297
+ @hidden @internal
298
+ */
299
+ visit(context, visitor) {
300
+ if (core.isEmpty(context)) {
301
+ context = { entityType: undefined };
302
+ }
303
+ else if (context instanceof EntityType) {
304
+ context = { entityType: context };
305
+ }
306
+ else if (!hasOwnProp(context, "entityType")) {
307
+ throw new Error("All visitor methods must be called with a context object containing at least an 'entityType' property");
308
+ }
309
+ if (visitor) {
310
+ context.visitor = visitor;
311
+ }
312
+ let tVisitor = visitor || context.visitor;
313
+ let fn = tVisitor[this.visitorMethodName];
314
+ if (fn == null) {
315
+ throw new Error("Unable to locate method: " + this.visitorMethodName + " on visitor");
316
+ }
317
+ let entityType = context.entityType;
318
+ // don't bother validating if already done so ( or if no _validate method
319
+ if (this._validate && (entityType == null || this._entityType !== entityType)) {
320
+ // don't need to capture return value because validation fn doesn't have one.
321
+ this._validate(entityType, context.toNameOnServer);
322
+ this._entityType = entityType;
323
+ }
324
+ return fn.call(this, context);
325
+ }
326
+ /** @hidden @internal */
327
+ _initialize(visitorMethodName, opMap = {}) {
328
+ this.visitorMethodName = visitorMethodName;
329
+ let aliasMap = this.aliasMap = {};
330
+ for (let op in opMap) {
331
+ updateAliasMap(aliasMap, op, opMap[op]);
332
+ }
333
+ }
334
+ /** @hidden @internal */
335
+ _resolveOp(op, okIfNotFound) {
336
+ let opStr = (typeof op === "string") ? op : op.operator;
337
+ let result = this.aliasMap[opStr.toLowerCase()];
338
+ if (!result && !okIfNotFound) {
339
+ throw new Error("Unable to resolve operator: " + opStr);
340
+ }
341
+ return result;
342
+ }
343
+ }
344
+ function createPredicateFromArray(arr) {
345
+ // TODO: assert that length of the array should be > 3
346
+ // Needs to handle:
347
+ // [ "freight", ">", 100"];
348
+ // [ "orders", "any", "freight", ">", 950 ]
349
+ // [ "orders", "and", anotherPred ]
350
+ // [ "orders", "and", [ "freight, ">", 950 ]]
351
+ let json = {};
352
+ let value = {};
353
+ json[arr[0]] = value;
354
+ let op = arr[1];
355
+ op = op.operator || op; // incoming op will be either a string or a FilterQueryOp
356
+ if (arr.length === 3) {
357
+ value[op] = arr[2];
358
+ }
359
+ else {
360
+ value[op] = createPredicateFromArray(arr.splice(2));
361
+ }
362
+ return createPredicateFromObject(json);
363
+ }
364
+ function createPredicateFromObject(obj) {
365
+ if (obj instanceof Predicate)
366
+ return obj;
367
+ if (typeof obj !== 'object') {
368
+ throw new Error("Unable to convert to a Predicate: " + obj);
369
+ }
370
+ let keys = Object.keys(obj);
371
+ let preds = keys.map(function (key) {
372
+ return createPredicateFromKeyValue(key, obj[key]);
373
+ });
374
+ return (preds.length === 1) ? preds[0] : new AndOrPredicate("and", preds);
375
+ }
376
+ function createPredicateFromKeyValue(key, value) {
377
+ // { and: [a,b] } key='and', value = [a,b]
378
+ if (AndOrPredicate.prototype._resolveOp(key, true)) {
379
+ return new AndOrPredicate(key, value);
380
+ }
381
+ // { not: a } key= 'not', value = a
382
+ if (UnaryPredicate.prototype._resolveOp(key, true)) {
383
+ return new UnaryPredicate(key, value);
384
+ }
385
+ if ((typeof value !== 'object') || value == null || core.isDate(value)) {
386
+ // { foo: bar } key='foo', value = bar ( where bar is a literal i.e. a string, a number, a boolean or a date.
387
+ return new BinaryPredicate("eq", key, value);
388
+ }
389
+ else if (hasOwnProp(value, 'value')) {
390
+ // { foo: { value: bar, dataType: xxx} } key='foo', value = bar ( where bar is an object representing a literal
391
+ return new BinaryPredicate("eq", key, value);
392
+ }
393
+ if (Array.isArray(value)) {
394
+ throw new Error("Unable to resolve predicate after the phrase: " + key);
395
+ }
396
+ let expr = key;
397
+ let keys = Object.keys(value);
398
+ let preds = keys.map(function (op) {
399
+ // { a: { any: b } op = 'any', expr=a, value[op] = b
400
+ if (AnyAllPredicate.prototype._resolveOp(op, true)) {
401
+ return new AnyAllPredicate(op, expr, value[op]);
402
+ }
403
+ if (BinaryPredicate.prototype._resolveOp(op, true)) {
404
+ // { a: { ">": b }} op = ">", expr=a, value[op] = b
405
+ return new BinaryPredicate(op, expr, value[op]);
406
+ }
407
+ else if (hasOwnProp(value[op], 'value')) {
408
+ // { a: { ">": { value: b, dataType: 'Int32' }} expr = a value[op] = { value: b, dataType: 'Int32' }
409
+ return new BinaryPredicate("eq", expr, value[op]);
410
+ }
411
+ let msg = core.formatString("Unable to resolve predicate after the phrase: '%1' for operator: '%2' and value: '%3'", expr, op, value[op]);
412
+ throw new Error(msg);
413
+ });
414
+ return (preds.length === 1) ? preds[0] : new AndOrPredicate("and", preds);
415
+ }
416
+ function argsForAndOrPredicates(obj, args) {
417
+ let preds = args[0];
418
+ if (preds instanceof Predicate) {
419
+ preds = arraySlice(args);
420
+ }
421
+ else if (!Array.isArray(preds)) {
422
+ preds = [new Predicate(arraySlice(args))];
423
+ }
424
+ return [obj].concat(preds);
425
+ }
426
+ function updateAliasMap(aliasMap, opStr, op) {
427
+ let key = opStr.toLowerCase();
428
+ op.key = key;
429
+ aliasMap[key] = op;
430
+ op.aliases && op.aliases.forEach((alias) => {
431
+ aliasMap[alias.toLowerCase()] = op;
432
+ });
433
+ }
434
+ /** For use by breeze plugin authors only. The class is for use in building a {@link UriBuilderAdapter} implementation.
435
+ @adapter (see {@link UriBuilderAdapter})
436
+ @hidden @internal
437
+ */
438
+ class PassthruPredicate extends Predicate {
439
+ value;
440
+ constructor(value) {
441
+ super();
442
+ this.value = value;
443
+ }
444
+ }
445
+ PassthruPredicate.prototype._initialize('passthruPredicate');
446
+ /** For use by breeze plugin authors only. The class is for use in building a {@link UriBuilderAdapter} implementation.
447
+ @adapter (see {@link UriBuilderAdapter})
448
+ @hidden
449
+ */
450
+ export class UnaryPredicate extends Predicate {
451
+ pred;
452
+ constructor(op, ...args) {
453
+ super();
454
+ this.op = this._resolveOp(op);
455
+ this.pred = new Predicate(args);
456
+ }
457
+ _validate(entityType, usesNameOnServer) {
458
+ this.pred._validate(entityType, usesNameOnServer);
459
+ }
460
+ }
461
+ UnaryPredicate.prototype._initialize('unaryPredicate', {
462
+ 'not': { aliases: ['!', '~'] },
463
+ });
464
+ /** For use by breeze plugin authors only. The class is for use in building a {@link UriBuilderAdapter} implementation.
465
+ @adapter (see {@link UriBuilderAdapter})
466
+ @hidden
467
+ */
468
+ export class BinaryPredicate extends Predicate {
469
+ expr1Source;
470
+ expr2Source;
471
+ expr1;
472
+ expr2;
473
+ constructor(op, expr1, expr2) {
474
+ super();
475
+ // 5 public props op, expr1Source, expr2Source, expr1, expr2
476
+ this.op = this._resolveOp(op);
477
+ this.expr1Source = expr1;
478
+ this.expr2Source = expr2;
479
+ // this.expr1 and this.expr2 won't be
480
+ // determined until validate is run
481
+ }
482
+ _validate(entityType, usesNameOnServer) {
483
+ let expr1Context = { entityType: entityType, usesNameOnServer: usesNameOnServer };
484
+ this.expr1 = createExpr(this.expr1Source, expr1Context);
485
+ if (this.expr1 == null) {
486
+ throw new Error("Unable to validate 1st expression: " + this.expr1Source);
487
+ }
488
+ if (this.expr1 instanceof LitExpr) {
489
+ // lhs must be either a property or a function.
490
+ throw new Error("The left hand side of a binary predicate cannot be a literal expression, it must be a valid property or functional predicate expression: " + this.expr1Source);
491
+ }
492
+ if (this.op.key === 'in' && !Array.isArray(this.expr2Source)) {
493
+ throw new Error("The 'in' operator requires that its right hand argument be an array");
494
+ }
495
+ let expr2Context = core.extend(expr1Context, { isRHS: true, dataType: this.expr1.dataType });
496
+ this.expr2 = createExpr(this.expr2Source, expr2Context);
497
+ if (this.expr2 == null) {
498
+ throw new Error("Unable to validate 2nd expression: " + this.expr2Source);
499
+ }
500
+ if (this.expr1.dataType == null) {
501
+ this.expr1.dataType = this.expr2.dataType;
502
+ }
503
+ }
504
+ }
505
+ BinaryPredicate.prototype._initialize('binaryPredicate', {
506
+ 'eq': {
507
+ aliases: ["==", "equals", "equal"]
508
+ },
509
+ 'ne': {
510
+ aliases: ["!=", "~=", "notequals", "notequal"]
511
+ },
512
+ 'lt': {
513
+ aliases: ["<", "lessthan"]
514
+ },
515
+ 'le': {
516
+ aliases: ["<=", "lessthanorequal"]
517
+ },
518
+ 'gt': {
519
+ aliases: [">", "greaterthan"]
520
+ },
521
+ 'ge': {
522
+ aliases: [">=", "greaterthanorequal"]
523
+ },
524
+ 'startswith': {
525
+ isFunction: true
526
+ },
527
+ 'endswith': {
528
+ isFunction: true
529
+ },
530
+ 'contains': {
531
+ aliases: ["substringof"],
532
+ isFunction: true
533
+ },
534
+ 'in': {}
535
+ });
536
+ /** For use by breeze plugin authors only. The class is for use in building a {@link UriBuilderAdapter} implementation.
537
+ @adapter (see {@link UriBuilderAdapter})
538
+ @hidden
539
+ */
540
+ export class AndOrPredicate extends Predicate {
541
+ preds;
542
+ constructor(op, preds) {
543
+ super();
544
+ this.op = this._resolveOp(op);
545
+ if (preds.length === 1 && Array.isArray(preds[0])) {
546
+ preds = preds[0];
547
+ }
548
+ this.preds = preds.filter(function (pred) {
549
+ return pred != null;
550
+ }).map(function (pred) {
551
+ return new Predicate(pred);
552
+ });
553
+ if (this.preds.length === 1) {
554
+ return this.preds[0]; // HACK: this.preds[0] is actually NOT a AndOrPredicate but some other kind of pred.
555
+ }
556
+ }
557
+ _validate(entityType, usesNameOnServer) {
558
+ this.preds.forEach((pred) => {
559
+ pred._validate(entityType, usesNameOnServer);
560
+ });
561
+ }
562
+ }
563
+ AndOrPredicate.prototype._initialize("andOrPredicate", {
564
+ 'and': { aliases: ['&&'] },
565
+ 'or': { aliases: ['||'] }
566
+ });
567
+ /** For use by breeze plugin authors only. The class is for use in building a {@link UriBuilderAdapter} implementation.
568
+ @adapter (see {@link UriBuilderAdapter})
569
+ @hidden
570
+ */
571
+ export class AnyAllPredicate extends Predicate {
572
+ /** @internal */
573
+ expr;
574
+ exprSource;
575
+ pred;
576
+ // 4 public props: op, exprSource, expr, pred
577
+ constructor(op, expr, pred) {
578
+ super();
579
+ this.op = this._resolveOp(op);
580
+ this.exprSource = expr;
581
+ // this.expr will not be resolved until validate is called
582
+ this.pred = new Predicate(pred);
583
+ }
584
+ _validate(entityType, usesNameOnServer) {
585
+ this.expr = createExpr(this.exprSource, { entityType: entityType, usesNameOnServer: usesNameOnServer });
586
+ // can't really know the predicateEntityType unless the original entity type was known.
587
+ if (entityType == null || entityType.isAnonymous) {
588
+ this.expr.dataType = undefined;
589
+ }
590
+ this.pred._validate(this.expr.dataType, usesNameOnServer);
591
+ }
592
+ }
593
+ AnyAllPredicate.prototype._initialize("anyAllPredicate", {
594
+ 'any': { aliases: ['some'] },
595
+ 'all': { aliases: ["every"] }
596
+ });
597
+ /** @hidden */
598
+ export class PredicateExpression {
599
+ visitorMethodName;
600
+ visit; // TODO
601
+ dataType;
602
+ constructor(visitorMethodName) {
603
+ this.visitorMethodName = visitorMethodName;
604
+ // give expressions the Predicate prototype method
605
+ this.visit = Predicate.prototype.visit;
606
+ }
607
+ // default impls - may/will be overridden be subclass expressions
608
+ _validate(entityType, usesNameOnServer) {
609
+ // noop;
610
+ }
611
+ }
612
+ /** For use by breeze plugin authors only. The class is for use in building a {@link UriBuilderAdapter} implementation.
613
+ @adapter (see {@link UriBuilderAdapter})
614
+ @hidden
615
+ */
616
+ export class LitExpr extends PredicateExpression {
617
+ value;
618
+ hasExplicitDataType;
619
+ // 2 public props: value, dataType
620
+ constructor(value, dataType, hasExplicitDataType) {
621
+ super("litExpr");
622
+ // dataType may come is an a string
623
+ let dt1 = resolveDataType(dataType);
624
+ // if the DataType comes in as Undefined this means
625
+ // that we should NOT attempt to parse it but just leave it alone
626
+ // for now - this is usually because it is part of a Func expr.
627
+ // The cast holds for test/tsconfig.json, which checks src/ again with strictNullChecks off;
628
+ // `resolveDataType` returns `DataType | string | undefined`, and only the strict pass drops
629
+ // the `string` here.
630
+ let dt2 = (dt1 || DataType.fromValue(value));
631
+ if (dt2.parse) {
632
+ if (Array.isArray(value)) {
633
+ this.value = value.map((v) => { return dt2.parse(v, typeof v); });
634
+ }
635
+ else {
636
+ this.value = dt2.parse(value, typeof value);
637
+ }
638
+ }
639
+ else {
640
+ this.value = value;
641
+ }
642
+ this.dataType = dt2;
643
+ this.hasExplicitDataType = !!hasExplicitDataType;
644
+ }
645
+ toString() {
646
+ return " LitExpr - value: " + this.value.toString() + " dataType: " + this.dataType.toString();
647
+ }
648
+ }
649
+ function resolveDataType(dataType) {
650
+ if (dataType == null)
651
+ return dataType;
652
+ // if (DataType.contains(dataType)) {
653
+ if (dataType instanceof DataType) {
654
+ return dataType;
655
+ }
656
+ if (typeof dataType === 'string') {
657
+ let dt = DataType.fromName(dataType);
658
+ if (dt)
659
+ return dt;
660
+ throw new Error("Unable to resolve a dataType named: " + dataType);
661
+ }
662
+ throw new Error("The dataType parameter passed into this literal expression is not a 'DataType'" + dataType);
663
+ }
664
+ /** For use by breeze plugin authors only. The class is for use in building a {@link UriBuilderAdapter} implementation.
665
+ @adapter (see {@link UriBuilderAdapter})
666
+ @hidden
667
+ */
668
+ export class PropExpr extends PredicateExpression {
669
+ propertyPath;
670
+ // two public props: propertyPath, dateType
671
+ constructor(propertyPath) {
672
+ super('propExpr');
673
+ this.propertyPath = propertyPath;
674
+ //this.dataType = DataType.Undefined;
675
+ // this.dataType resolved after validate ( if not on an anon type }
676
+ }
677
+ toString() {
678
+ return " PropExpr - " + this.propertyPath;
679
+ }
680
+ _validate(entityType, usesNameOnServer) {
681
+ if (entityType == null || entityType.isAnonymous)
682
+ return;
683
+ let props = entityType.getPropertiesOnPath(this.propertyPath, null, false);
684
+ if (!props) {
685
+ let msg = core.formatString("Unable to resolve propertyPath. EntityType: '%1' PropertyPath: '%2'", entityType.name, this.propertyPath);
686
+ throw new Error(msg);
687
+ }
688
+ // get the last property
689
+ let prop = props[props.length - 1];
690
+ if (prop instanceof DataProperty) {
691
+ this.dataType = prop.dataType;
692
+ }
693
+ else {
694
+ this.dataType = prop.entityType;
695
+ }
696
+ }
697
+ }
698
+ /** For use by breeze plugin authors only. The class is for use in building a {@link UriBuilderAdapter} implementation.
699
+ @adapter (see {@link UriBuilderAdapter})
700
+ @hidden
701
+ */
702
+ export class FnExpr extends PredicateExpression {
703
+ fnName;
704
+ exprs;
705
+ localFn; // TODO:
706
+ constructor(fnName, exprs) {
707
+ super('fnExpr');
708
+ // 4 public props: fnName, exprs, localFn, dataType
709
+ this.fnName = fnName;
710
+ this.exprs = exprs;
711
+ let qf = FnExpr._funcMap.get(fnName);
712
+ if (qf == null) {
713
+ throw new Error("Unknown function: " + fnName);
714
+ }
715
+ this.localFn = qf.fn;
716
+ this.dataType = qf.dataType;
717
+ }
718
+ toString() {
719
+ let exprStr = this.exprs.map(function (expr) {
720
+ expr.toString();
721
+ }).toString();
722
+ return "FnExpr - " + this.fnName + "(" + exprStr + ")";
723
+ }
724
+ _validate(entityType, usesNameOnServer) {
725
+ this.exprs.forEach(function (expr) {
726
+ expr._validate(entityType, usesNameOnServer);
727
+ });
728
+ }
729
+ static _funcMap = new Map(Object.entries({
730
+ toupper: {
731
+ fn: function (source) {
732
+ return source.toUpperCase();
733
+ }, dataType: DataType.String
734
+ },
735
+ tolower: {
736
+ fn: function (source) {
737
+ return source.toLowerCase();
738
+ }, dataType: DataType.String
739
+ },
740
+ substring: {
741
+ // As on the server (.NET String.Substring(startIndex, length)), the third argument is
742
+ // a length, not an end index. Function arguments arrive unparsed, often as strings.
743
+ fn: function (source, pos, length) {
744
+ const start = Number(pos);
745
+ return length == null ? source.substring(start) : source.substring(start, start + Number(length));
746
+ }, dataType: DataType.String
747
+ },
748
+ substringof: {
749
+ fn: function (find, source) {
750
+ return source.indexOf(find) >= 0;
751
+ }, dataType: DataType.Boolean
752
+ },
753
+ length: {
754
+ fn: function (source) {
755
+ return source.length;
756
+ }, dataType: DataType.Int32
757
+ },
758
+ trim: {
759
+ fn: function (source) {
760
+ return source.trim();
761
+ }, dataType: DataType.String
762
+ },
763
+ concat: {
764
+ fn: function (s1, s2) {
765
+ return s1.concat(s2);
766
+ }, dataType: DataType.String
767
+ },
768
+ replace: {
769
+ fn: function (source, find, replace) {
770
+ return source.replace(find, replace);
771
+ }, dataType: DataType.String
772
+ },
773
+ startswith: {
774
+ fn: function (source, find) {
775
+ return strStartsWith(source, find);
776
+ }, dataType: DataType.Boolean
777
+ },
778
+ endswith: {
779
+ fn: function (source, find) {
780
+ return strEndsWith(source, find);
781
+ }, dataType: DataType.Boolean
782
+ },
783
+ indexof: {
784
+ fn: function (source, find) {
785
+ return source.indexOf(find);
786
+ }, dataType: DataType.Int32
787
+ },
788
+ round: {
789
+ fn: function (source) {
790
+ return Math.round(source);
791
+ }, dataType: DataType.Int32
792
+ },
793
+ ceiling: {
794
+ fn: function (source) {
795
+ return Math.ceil(source);
796
+ }, dataType: DataType.Int32
797
+ },
798
+ floor: {
799
+ fn: function (source) {
800
+ return Math.floor(source);
801
+ }, dataType: DataType.Int32
802
+ },
803
+ second: {
804
+ fn: function (source) {
805
+ return source.getSeconds();
806
+ }, dataType: DataType.Int32
807
+ },
808
+ minute: {
809
+ fn: function (source) {
810
+ return source.getMinutes();
811
+ }, dataType: DataType.Int32
812
+ },
813
+ hour: {
814
+ fn: function (source) {
815
+ return source.getHours();
816
+ }, dataType: DataType.Int32
817
+ },
818
+ day: {
819
+ fn: function (source) {
820
+ return source.getDate();
821
+ }, dataType: DataType.Int32
822
+ },
823
+ month: {
824
+ fn: function (source) {
825
+ return source.getMonth() + 1;
826
+ }, dataType: DataType.Int32
827
+ },
828
+ year: {
829
+ fn: function (source) {
830
+ return source.getFullYear();
831
+ }, dataType: DataType.Int32
832
+ }
833
+ }));
834
+ }
835
+ // TODO: add dataTypes for the args next - will help to infer other dataTypes.
836
+ let RX_IDENTIFIER = /^[a-z_][\w.$]*$/i;
837
+ // comma delimited expressions ignoring commas inside of both single and double quotes.
838
+ let RX_COMMA_DELIM1 = /('[^']*'|[^,]+)/g;
839
+ let RX_COMMA_DELIM2 = /("[^"]*"|[^,]+)/g;
840
+ let DELIM = String.fromCharCode(191);
841
+ function createExpr(source, exprContext) {
842
+ let entityType = exprContext.entityType;
843
+ // the right hand side of an 'in' clause
844
+ if (Array.isArray(source)) {
845
+ if (!exprContext.isRHS) {
846
+ throw new Error("Array expressions are only permitted on the right hand side of a BinaryPredicate");
847
+ }
848
+ return new LitExpr(source, exprContext.dataType);
849
+ }
850
+ if (!(typeof source === 'string')) {
851
+ if (source != null && typeof source === 'object' && !source.toISOString) {
852
+ // source is an object but not a Date-like thing such as a JS or MomentJS Date
853
+ if (source.value === undefined) {
854
+ throw new Error("Unable to resolve an expression for: " + source + " on entityType: " + (entityType ? entityType.name : 'null'));
855
+ }
856
+ // { value, isProperty: true } or { value, isLiteral: false } forces a property;
857
+ // anything else (including { value, isLiteral: true }) is a literal.
858
+ if (source.isProperty || source.isLiteral === false) {
859
+ return new PropExpr(source.value);
860
+ }
861
+ else {
862
+ // we want to insure that any LitExpr created this way is tagged with 'hasExplicitDataType: true'
863
+ // because we want to insure that if we roundtrip thru toJSON that we don't
864
+ // accidentally reinterpret this node as a PropExpr.
865
+ // return new LitExpr(source.value, source.dataType || context.dataType, !!source.dataType);
866
+ return new LitExpr(source.value, source.dataType || exprContext.dataType, true);
867
+ }
868
+ }
869
+ else {
870
+ return new LitExpr(source, exprContext.dataType);
871
+ }
872
+ }
873
+ if (exprContext.isRHS) {
874
+ if (entityType == null || entityType.isAnonymous) {
875
+ // if entityType is unknown then assume that the rhs is a literal
876
+ return new LitExpr(source, exprContext.dataType);
877
+ }
878
+ else {
879
+ return parseLitOrPropExpr(source, exprContext);
880
+ }
881
+ }
882
+ else {
883
+ let regex = /\([^()]*\)/;
884
+ let m;
885
+ let tokens = [];
886
+ let i = 0;
887
+ while (m = regex.exec(source)) {
888
+ let token = m[0];
889
+ tokens.push(token);
890
+ let repl = DELIM + i++;
891
+ source = source.replace(token, repl);
892
+ }
893
+ let expr = parseExpr(source, tokens, exprContext);
894
+ expr._validate(entityType, exprContext.usesNameOnServer);
895
+ return expr;
896
+ }
897
+ }
898
+ function parseExpr(source, tokens, exprContext) {
899
+ let parts = source.split(DELIM);
900
+ if (parts.length === 1) {
901
+ return parseLitOrPropExpr(parts[0], exprContext);
902
+ }
903
+ else {
904
+ return parseFnExpr(source, parts, tokens, exprContext);
905
+ }
906
+ }
907
+ function parseLitOrPropExpr(value, exprContext) {
908
+ value = value.trim();
909
+ // value is either a string, a quoted string, a number, a bool value, or a date
910
+ // if a string ( not a quoted string) then this represents a property name ( 1st ) or a lit string ( 2nd)
911
+ let firstChar = value.substr(0, 1);
912
+ let isQuoted = (firstChar === "'" || firstChar === '"') && value.length > 1 && value.substr(value.length - 1) === firstChar;
913
+ if (isQuoted) {
914
+ let unquotedValue = value.substr(1, value.length - 2);
915
+ return new LitExpr(unquotedValue, exprContext.dataType || DataType.String);
916
+ }
917
+ else {
918
+ let entityType = exprContext.entityType;
919
+ // TODO: get rid of isAnonymous below when we get the chance.
920
+ if (entityType == null || entityType.isAnonymous) {
921
+ // this fork will only be reached on the LHS of an BinaryPredicate -
922
+ // a RHS expr cannot get here with an anon type
923
+ return new PropExpr(value);
924
+ }
925
+ else {
926
+ let mayBeIdentifier = RX_IDENTIFIER.test(value);
927
+ if (mayBeIdentifier) {
928
+ // if (entityType.getProperty(value, false) != null) {
929
+ if (entityType.getPropertiesOnPath(value, null, false) != null) {
930
+ return new PropExpr(value);
931
+ }
932
+ }
933
+ }
934
+ // we don't really know the datatype here because even though it comes in as a string
935
+ // its usually a string BUT it might be a number i.e. the "1" or the "2" from an expr
936
+ // like "toUpper(substring(companyName, 1, 2))"
937
+ return new LitExpr(value, exprContext.dataType);
938
+ }
939
+ }
940
+ function parseFnExpr(source, parts, tokens, exprContext) {
941
+ let fnName = parts[0].trim().toLowerCase();
942
+ let argSource = tokens[parts[1]].trim();
943
+ if (argSource.substr(0, 1) === "(") {
944
+ argSource = argSource.substr(1, argSource.length - 2);
945
+ }
946
+ let commaMatchStr = source.indexOf("'") >= 0 ? RX_COMMA_DELIM1 : RX_COMMA_DELIM2;
947
+ let args = argSource.match(commaMatchStr);
948
+ let newContext = core.extend({}, exprContext);
949
+ // a dataType of Undefined on a context basically means not to try parsing
950
+ // the value if the expr is a literal
951
+ newContext.dataType = DataType.Undefined;
952
+ newContext.isFnArg = true;
953
+ let exprs = args.map(function (a) {
954
+ return parseExpr(a, tokens, newContext);
955
+ });
956
+ return new FnExpr(fnName, exprs);
957
+ }
958
+ // toFunctionVisitor
959
+ let toFunctionVisitor = {
960
+ isExtended: false,
961
+ passthruPredicate: function () {
962
+ throw new Error("Cannot execute an PassthruPredicate expression against the local cache: " + this.value);
963
+ },
964
+ unaryPredicate: function (context) {
965
+ let predFn = this.pred.visit(context);
966
+ switch (this.op.key) {
967
+ case "not":
968
+ return function (entity) {
969
+ return !predFn(entity);
970
+ };
971
+ default:
972
+ throw new Error("Invalid unary operator:" + this.op.key);
973
+ }
974
+ },
975
+ binaryPredicate: function (context) {
976
+ let expr1Fn = this.expr1.visit(context);
977
+ let expr2Fn = this.expr2.visit(context);
978
+ let dataType = this.expr1.dataType || this.expr2.dataType;
979
+ let lqco = context.entityType.metadataStore.localQueryComparisonOptions;
980
+ let predFn = getBinaryPredicateFn(this, dataType, lqco);
981
+ if (predFn == null) {
982
+ throw new Error("Invalid binaryPredicate operator:" + this.op.key);
983
+ }
984
+ return function (entity) {
985
+ return predFn(expr1Fn(entity), expr2Fn(entity));
986
+ };
987
+ },
988
+ andOrPredicate: function (context) {
989
+ let predFns = this.preds.map((pred) => {
990
+ return pred.visit(context);
991
+ });
992
+ switch (this.op.key) {
993
+ case "and":
994
+ return function (entity) {
995
+ let result = predFns.reduce(function (prev, cur) {
996
+ return prev && cur(entity);
997
+ }, true);
998
+ return result;
999
+ };
1000
+ case "or":
1001
+ return function (entity) {
1002
+ let result = predFns.reduce(function (prev, cur) {
1003
+ return prev || cur(entity);
1004
+ }, false);
1005
+ return result;
1006
+ };
1007
+ default:
1008
+ throw new Error("Invalid boolean operator:" + this.op.key);
1009
+ }
1010
+ },
1011
+ anyAllPredicate: function (context) {
1012
+ let exprFn = this.expr.visit(context);
1013
+ let newContext = core.extend({}, context);
1014
+ newContext.entityType = this.expr.dataType;
1015
+ let predFn = this.pred.visit(newContext);
1016
+ let anyAllPredFn = getAnyAllPredicateFn(this.op);
1017
+ return function (entity) {
1018
+ return anyAllPredFn(exprFn(entity), predFn);
1019
+ };
1020
+ },
1021
+ litExpr: function () {
1022
+ let value = this.value;
1023
+ return function (entity) {
1024
+ return value;
1025
+ };
1026
+ },
1027
+ propExpr: function () {
1028
+ let propertyPath = this.propertyPath;
1029
+ let properties = propertyPath.split('.');
1030
+ if (properties.length === 1) {
1031
+ return function (entity) {
1032
+ return entity.getProperty(propertyPath);
1033
+ };
1034
+ }
1035
+ else {
1036
+ return function (entity) {
1037
+ return EntityAspect.getPropertyPathValue(entity, properties);
1038
+ };
1039
+ }
1040
+ },
1041
+ fnExpr: function (context) {
1042
+ let exprFns = this.exprs.map(function (expr) {
1043
+ return expr.visit(context);
1044
+ });
1045
+ let that = this;
1046
+ return function (entity) {
1047
+ let values = exprFns.map(function (exprFn) {
1048
+ let value = exprFn(entity);
1049
+ return value;
1050
+ });
1051
+ let result = that.localFn.apply(null, values);
1052
+ return result;
1053
+ };
1054
+ }
1055
+ };
1056
+ function getAnyAllPredicateFn(op) {
1057
+ switch (op.key) {
1058
+ case "any":
1059
+ return function (v1, v2) {
1060
+ return v1.some(function (v) {
1061
+ return v2(v);
1062
+ });
1063
+ };
1064
+ case "all":
1065
+ return function (v1, v2) {
1066
+ return v1.every(function (v) {
1067
+ return v2(v);
1068
+ });
1069
+ };
1070
+ default:
1071
+ throw new Error("Unknown operator: " + op.key);
1072
+ }
1073
+ }
1074
+ function getBinaryPredicateFn(binaryPredicate, dataType, lqco) {
1075
+ let op = binaryPredicate.op;
1076
+ let mc = DataType.getComparableFn(dataType);
1077
+ let predFn;
1078
+ switch (op.key) {
1079
+ case 'eq':
1080
+ predFn = function (v1, v2) {
1081
+ if (v1 && typeof v1 === 'string') {
1082
+ return stringEquals(v1, v2, lqco);
1083
+ }
1084
+ else {
1085
+ return mc(v1) === mc(v2);
1086
+ }
1087
+ };
1088
+ break;
1089
+ case 'ne':
1090
+ predFn = function (v1, v2) {
1091
+ if (v1 && typeof v1 === 'string') {
1092
+ return !stringEquals(v1, v2, lqco);
1093
+ }
1094
+ else {
1095
+ return mc(v1) !== mc(v2);
1096
+ }
1097
+ };
1098
+ break;
1099
+ case 'gt':
1100
+ predFn = function (v1, v2) {
1101
+ return mc(v1) > mc(v2);
1102
+ };
1103
+ break;
1104
+ case 'ge':
1105
+ predFn = function (v1, v2) {
1106
+ return mc(v1) >= mc(v2);
1107
+ };
1108
+ break;
1109
+ case 'lt':
1110
+ predFn = function (v1, v2) {
1111
+ return mc(v1) < mc(v2);
1112
+ };
1113
+ break;
1114
+ case 'le':
1115
+ predFn = function (v1, v2) {
1116
+ return mc(v1) <= mc(v2);
1117
+ };
1118
+ break;
1119
+ case 'startswith':
1120
+ predFn = function (v1, v2) {
1121
+ return stringStartsWith(v1, v2, lqco);
1122
+ };
1123
+ break;
1124
+ case 'endswith':
1125
+ predFn = function (v1, v2) {
1126
+ return stringEndsWith(v1, v2, lqco);
1127
+ };
1128
+ break;
1129
+ case 'contains':
1130
+ predFn = function (v1, v2) {
1131
+ return stringContains(v1, v2, lqco);
1132
+ };
1133
+ break;
1134
+ case 'in':
1135
+ predFn = function (v1, v2) {
1136
+ v1 = mc(v1);
1137
+ v2 = v2.map(function (v) { return mc(v); });
1138
+ return v2.indexOf(v1) >= 0;
1139
+ };
1140
+ break;
1141
+ default:
1142
+ return null;
1143
+ }
1144
+ return predFn;
1145
+ }
1146
+ function stringEquals(a, b, lqco) {
1147
+ if (b == null)
1148
+ return false;
1149
+ if (typeof b !== 'string') {
1150
+ b = b.toString();
1151
+ }
1152
+ if (lqco.usesSql92CompliantStringComparison) {
1153
+ a = (a || "").trim();
1154
+ b = (b || "").trim();
1155
+ }
1156
+ if (!lqco.isCaseSensitive) {
1157
+ a = (a || "").toLowerCase();
1158
+ b = (b || "").toLowerCase();
1159
+ }
1160
+ return a === b;
1161
+ }
1162
+ function stringStartsWith(a, b, lqco) {
1163
+ if (!lqco.isCaseSensitive) {
1164
+ a = (a || "").toLowerCase();
1165
+ b = (b || "").toLowerCase();
1166
+ }
1167
+ return strStartsWith(a, b);
1168
+ }
1169
+ function stringEndsWith(a, b, lqco) {
1170
+ if (!lqco.isCaseSensitive) {
1171
+ a = (a || "").toLowerCase();
1172
+ b = (b || "").toLowerCase();
1173
+ }
1174
+ return strEndsWith(a, b);
1175
+ }
1176
+ function stringContains(a, b, lqco) {
1177
+ if (!lqco.isCaseSensitive) {
1178
+ a = (a || "").toLowerCase();
1179
+ b = (b || "").toLowerCase();
1180
+ }
1181
+ return a.indexOf(b) >= 0;
1182
+ }
1183
+ // toJSONVisitor
1184
+ let toJSONVisitor = {
1185
+ passthruPredicate: function () {
1186
+ return this.value;
1187
+ },
1188
+ unaryPredicate: function (context) {
1189
+ let predVal = this.pred.visit(context);
1190
+ let json = {};
1191
+ json[this.op.key] = predVal;
1192
+ return json;
1193
+ },
1194
+ binaryPredicate: function (context) {
1195
+ let expr1Val = this.expr1.visit(context);
1196
+ let expr2Val = this.expr2.visit(context);
1197
+ let json = {};
1198
+ if (this.expr2 instanceof PropExpr) {
1199
+ expr2Val = { value: expr2Val, isProperty: true };
1200
+ }
1201
+ if (this.op.key === "eq") {
1202
+ json[expr1Val] = expr2Val;
1203
+ }
1204
+ else {
1205
+ let value = {};
1206
+ json[expr1Val] = value;
1207
+ value[this.op.key] = expr2Val;
1208
+ }
1209
+ return json;
1210
+ },
1211
+ andOrPredicate: function (context) {
1212
+ let predVals = this.preds.map(function (pred) {
1213
+ return pred.visit(context);
1214
+ });
1215
+ if (!predVals || !predVals.length) {
1216
+ return {};
1217
+ }
1218
+ let json;
1219
+ // normalizeAnd clauses if possible.
1220
+ // passthru predicate will appear as string and their 'ands' can't be 'normalized'
1221
+ if (this.op.key === 'and' && predVals.length === 2 && !predVals.some((v) => v.or || typeof (v) === 'string')) {
1222
+ // normalize 'and' clauses - will return null if can't be combined.
1223
+ json = predVals.reduce(combine);
1224
+ }
1225
+ if (json == null) {
1226
+ json = {};
1227
+ json[this.op.key] = predVals;
1228
+ }
1229
+ return json;
1230
+ },
1231
+ anyAllPredicate: function (context) {
1232
+ let exprVal = this.expr.visit(context);
1233
+ let newContext = core.extend({}, context);
1234
+ newContext.entityType = this.expr.dataType;
1235
+ let predVal = this.pred.visit(newContext);
1236
+ let json = {};
1237
+ let value = {};
1238
+ value[this.op.key] = predVal;
1239
+ json[exprVal] = value;
1240
+ return json;
1241
+ },
1242
+ litExpr: function (context) {
1243
+ // special handling for DateOnly because it serializes improperly
1244
+ const value = (this.dataType === DataType.DateOnly) ? DataType.toDateOnlyString(this.value) : this.value;
1245
+ if (this.hasExplicitDataType || context.useExplicitDataType) {
1246
+ return { value: value, dataType: this.dataType.name };
1247
+ }
1248
+ else {
1249
+ return value;
1250
+ }
1251
+ },
1252
+ propExpr: function (context) {
1253
+ if (context.toNameOnServer) {
1254
+ if (!context.entityType) {
1255
+ console.warn(`No EntityType for propertyPath "${this.propertyPath}". ${core.strings.TO_TYPE}`);
1256
+ return this.propertyPath;
1257
+ }
1258
+ return context.entityType.clientPropertyPathToServer(this.propertyPath);
1259
+ }
1260
+ else {
1261
+ return this.propertyPath;
1262
+ }
1263
+ },
1264
+ fnExpr: function (context) {
1265
+ let exprVals = this.exprs.map(function (expr) {
1266
+ return expr.visit(context);
1267
+ });
1268
+ return this.fnName + "(" + exprVals.join(",") + ")";
1269
+ }
1270
+ };
1271
+ function combine(j1, j2) {
1272
+ const a = j1, b = j2;
1273
+ let ok = Object.keys(b).every(function (key) {
1274
+ if (a.hasOwnProperty(key)) {
1275
+ if (typeof (b[key]) !== 'object') {
1276
+ // exit and indicate that we can't combine
1277
+ return false;
1278
+ }
1279
+ if (combine(a[key], b[key]) == null) {
1280
+ return false;
1281
+ }
1282
+ }
1283
+ else if (typeof (a) !== 'object') {
1284
+ // cannot assign to j1[key]
1285
+ return false;
1286
+ }
1287
+ else {
1288
+ a[key] = b[key];
1289
+ }
1290
+ return true;
1291
+ });
1292
+ return ok ? j1 : null;
1293
+ }
1294
+ //# sourceMappingURL=predicate.js.map