@shko.online/dataverse-odata 0.1.1 → 0.1.3

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 (98) hide show
  1. package/.eslintrc.json +59 -0
  2. package/.prettierrc.json +8 -0
  3. package/CHANGELOG.md +14 -0
  4. package/lib/cjs/getExpandFromParser.js +15 -15
  5. package/lib/cjs/getFetchXmlFromParser.js +13 -6
  6. package/lib/cjs/getOrderByFromParser.js +44 -0
  7. package/lib/cjs/getSelectFromParser.js +3 -3
  8. package/lib/cjs/getTopFromParser.js +9 -5
  9. package/lib/cjs/getXQueryFromParser.js +35 -0
  10. package/lib/cjs/index.js +42 -0
  11. package/lib/cjs/parseOData.js +11 -4
  12. package/lib/cjs/validateNotEmpty.js +17 -0
  13. package/lib/esm/getExpandFromParser.js +15 -15
  14. package/lib/esm/getFetchXmlFromParser.js +13 -6
  15. package/lib/esm/getOrderByFromParser.js +37 -0
  16. package/lib/esm/getSelectFromParser.js +3 -3
  17. package/lib/esm/getTopFromParser.js +10 -5
  18. package/lib/esm/getXQueryFromParser.js +28 -0
  19. package/lib/esm/index.js +6 -0
  20. package/lib/esm/parseOData.js +11 -4
  21. package/lib/esm/validateNotEmpty.js +10 -0
  22. package/lib/modern/getExpandFromParser.js +15 -15
  23. package/lib/modern/getFetchXmlFromParser.js +13 -6
  24. package/lib/modern/getOrderByFromParser.js +38 -0
  25. package/lib/modern/getSelectFromParser.js +3 -3
  26. package/lib/modern/getTopFromParser.js +10 -5
  27. package/lib/modern/getXQueryFromParser.js +28 -0
  28. package/lib/modern/index.js +6 -0
  29. package/lib/modern/parseOData.js +11 -4
  30. package/lib/modern/validateNotEmpty.js +10 -0
  31. package/lib/ts3.4/OData.types.d.ts +118 -0
  32. package/lib/ts3.4/getExpandFromParser.d.ts +2 -2
  33. package/lib/ts3.4/getFetchXmlFromParser.d.ts +2 -2
  34. package/lib/ts3.4/getOrderByFromParser.d.ts +7 -0
  35. package/lib/ts3.4/getSelectFromParser.d.ts +2 -2
  36. package/lib/ts3.4/getTopFromParser.d.ts +2 -2
  37. package/lib/ts3.4/getXQueryFromParser.d.ts +8 -0
  38. package/lib/ts3.4/index.d.ts +6 -0
  39. package/lib/ts3.4/validateNotEmpty.d.ts +3 -0
  40. package/lib/ts3.9/OData.types.d.ts +154 -0
  41. package/lib/ts3.9/getExpandFromParser.d.ts +2 -2
  42. package/lib/ts3.9/getFetchXmlFromParser.d.ts +2 -2
  43. package/lib/ts3.9/getFetchXmlFromParser.d.ts.map +1 -1
  44. package/lib/ts3.9/getOrderByFromParser.d.ts +7 -0
  45. package/lib/ts3.9/getOrderByFromParser.d.ts.map +1 -0
  46. package/lib/ts3.9/getSelectFromParser.d.ts +2 -2
  47. package/lib/ts3.9/getSelectFromParser.d.ts.map +1 -1
  48. package/lib/ts3.9/getTopFromParser.d.ts +2 -2
  49. package/lib/ts3.9/getTopFromParser.d.ts.map +1 -1
  50. package/lib/ts3.9/getXQueryFromParser.d.ts +8 -0
  51. package/lib/ts3.9/getXQueryFromParser.d.ts.map +1 -0
  52. package/lib/ts3.9/index.d.ts +6 -0
  53. package/lib/ts3.9/index.d.ts.map +1 -1
  54. package/lib/ts3.9/parseOData.d.ts.map +1 -1
  55. package/lib/ts3.9/validateNotEmpty.d.ts +3 -0
  56. package/lib/ts3.9/validateNotEmpty.d.ts.map +1 -0
  57. package/package.json +1 -1
  58. package/src/OData.types.d.ts +107 -14
  59. package/src/getExpandFromParser.ts +15 -15
  60. package/src/getFetchXmlFromParser.ts +15 -7
  61. package/src/getOrderByFromParser.ts +42 -0
  62. package/src/getSelectFromParser.ts +4 -4
  63. package/src/getTopFromParser.ts +11 -7
  64. package/src/getXQueryFromParser.ts +34 -0
  65. package/src/index.ts +7 -0
  66. package/src/parseOData.ts +11 -4
  67. package/src/validateNotEmpty.ts +12 -0
  68. package/tsconfig.build.json +3 -0
  69. package/tsconfig.json +2 -5
  70. package/jest.config.ts +0 -12
  71. package/lib/getExpandFromParser.d.ts +0 -7
  72. package/lib/getExpandFromParser.d.ts.map +0 -1
  73. package/lib/getExpandFromParser.js +0 -97
  74. package/lib/getExpandFromParser.js.map +0 -1
  75. package/lib/getFetchXmlFromParser.d.ts +0 -7
  76. package/lib/getFetchXmlFromParser.d.ts.map +0 -1
  77. package/lib/getFetchXmlFromParser.js +0 -41
  78. package/lib/getFetchXmlFromParser.js.map +0 -1
  79. package/lib/getSelectFromParser.d.ts +0 -7
  80. package/lib/getSelectFromParser.d.ts.map +0 -1
  81. package/lib/getSelectFromParser.js +0 -12
  82. package/lib/getSelectFromParser.js.map +0 -1
  83. package/lib/getTopFromParser.d.ts +0 -7
  84. package/lib/getTopFromParser.d.ts.map +0 -1
  85. package/lib/getTopFromParser.js +0 -27
  86. package/lib/getTopFromParser.js.map +0 -1
  87. package/lib/index.d.ts +0 -5
  88. package/lib/index.d.ts.map +0 -1
  89. package/lib/index.js +0 -4
  90. package/lib/index.js.map +0 -1
  91. package/lib/parseOData.d.ts +0 -3
  92. package/lib/parseOData.d.ts.map +0 -1
  93. package/lib/parseOData.js +0 -22
  94. package/lib/parseOData.js.map +0 -1
  95. package/tests/OData-Parser.$expand.test.ts +0 -39
  96. package/tests/OData-Parser.$top.test.ts +0 -36
  97. package/tests/OData-Parser.fetchXml.test.ts +0 -62
  98. package/tests/OData-Parser.test.ts +0 -17
@@ -0,0 +1,154 @@
1
+ interface ODataError {
2
+ error?: {
3
+ code: string;
4
+ message: string;
5
+ };
6
+ }
7
+
8
+ interface ODataExpand {
9
+ /**
10
+ * Use the {@link ODataExpand.$expand $expand} system query option in the navigation properties
11
+ * to control what data from related entities is returned.
12
+ * There are two types of navigation properties:
13
+ * * Single-valued navigation properties correspond to Lookup attributes that support many-to-one
14
+ * relationships and allow setting a reference to another entity.
15
+ * * Collection-valued navigation properties correspond to one-to-many or many-to-many relationships.
16
+ *
17
+ * If you include only the name of the navigation property, you'll receive all the properties for
18
+ * related records. You can limit the properties returned for related records using the
19
+ * {@link ODataSelect.$select $select} system query option in parentheses after the navigation
20
+ * property name. Use this for both single-valued and collection-valued navigation properties.
21
+ *
22
+ * * Microsoft Docs: {@link https://learn.microsoft.com/power-apps/developer/data-platform/webapi/retrieve-related-entities-query?WT.mc_id=DX-MVP-5004767 Retrieve related table records with a query }
23
+ */
24
+ $expand?: {
25
+ [relationship: string]: ODataExpandQuery;
26
+ };
27
+ }
28
+
29
+ type ODataExpandQuery = ODataSelect & ODataExpand;
30
+
31
+ interface ODataFilter {
32
+ /**
33
+ * Use the {@link ODataFilter.$filter $filter} system query option to set criteria for which rows will be returned.
34
+ *
35
+ * * Microsoft Docs: {@link https://learn.microsoft.com/power-apps/developer/data-platform/webapi/query-data-web-api?WT.mc_id=DX-MVP-5004767#filter-results Filter results }
36
+ */
37
+ $filter?: StandardOperator;
38
+ }
39
+
40
+ interface ODataFetch {
41
+ /**
42
+ * You can compose a FetchXML query for a specific table.
43
+ * Then, URL-encode the XML and pass it to the entity set
44
+ * using the {@link ODataFetch.fetchXml fetchXml} query string parameter.
45
+ *
46
+ * * Microsoft Docs: {@link https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/use-fetchxml-web-api?WT.mc_id=DX-MVP-5004767 Use FetchXml with Web API }
47
+ */
48
+ fetchXml?: XMLDocument;
49
+ }
50
+
51
+ interface ODataOrderBy {
52
+ /**
53
+ * Specify the order in which items are returned using the {@link ODataOrderBy.$orderby $orderby}
54
+ * system query option. Use the asc or desc suffix to specify ascending or descending order
55
+ * respectively. The default is ascending if the suffix isn't applied.
56
+ *
57
+ * * Microsoft Docs: {@link https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/query-data-web-api?WT.mc_id=DX-MVP-5004767#order-results Order results }
58
+ */
59
+ $orderby?: { column: string; asc: boolean }[];
60
+ }
61
+
62
+ interface ODataSavedQuery {
63
+ /**
64
+ * You can use the `savedqueryid` value and pass it as the value to the {@link ODataSavedQuery.savedQuery savedQuery}
65
+ * parameter to the entity set that matches the corresponding `returnedtypecode` of the saved query.
66
+ *
67
+ * * Microsoft Docs: {@link https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/retrieve-and-execute-predefined-queries?WT.mc_id=DX-MVP-5004767#predefined-queries Retrieve and execute predefined queries }
68
+ */
69
+ savedQuery?: string;
70
+ }
71
+
72
+ interface ODataSelect {
73
+ /**
74
+ * Use the {@link ODataSelect.$select $select} system query option to limit the properties returned.
75
+ *
76
+ * This is a performance best practice. If properties aren't specified using
77
+ * {@link ODataSelect.$select $select}, all properties will be returned.
78
+ *
79
+ * * Microsoft Docs: {@link https://learn.microsoft.com/power-apps/developer/data-platform/webapi/query-data-web-api?WT.mc_id=DX-MVP-5004767#request-specific-properties Request specific properties }
80
+ */
81
+ $select?: string[];
82
+ }
83
+
84
+ interface ODataTop {
85
+ /**
86
+ * You can limit the number of results returned by using the {@link ODataTop.$top $top} system query option.
87
+ *
88
+ * * Microsoft Docs: {@link https://learn.microsoft.com/power-apps/developer/data-platform/webapi/query-data-web-api?WT.mc_id=DX-MVP-5004767#use-top-query-option Use $top query option }
89
+ */
90
+ $top?: number;
91
+ }
92
+
93
+ interface ODataUserQuery {
94
+ /**
95
+ * You can use the `userqueryid` value and pass it as the value to the {@link OdataUserQuery.userQuery userQuery}
96
+ * parameter to the entity set that matches the corresponding `returnedtypecode` of the user query.
97
+ *
98
+ * * Microsoft Docs: {@link https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/retrieve-and-execute-predefined-queries?WT.mc_id=DX-MVP-5004767#predefined-queries Retrieve and execute predefined queries }
99
+ */
100
+ userQuery?: string;
101
+ }
102
+
103
+ type StandardOperators = 'eq' | 'ne' | 'gt' | 'ge' | 'lt' | 'le';
104
+
105
+ interface StandardOperator {
106
+ operator: StandardOperators;
107
+ /**
108
+ * The left side of the 'X' operator must be a property of the entity.
109
+ */
110
+ left: string;
111
+ /**
112
+ * The right side of the 'X' operator must be a constant value.
113
+ */
114
+ right: string | number;
115
+ }
116
+
117
+ interface UnaryOperator {
118
+ operator: 'not';
119
+ right: StandardOperator;
120
+ }
121
+
122
+ interface BinaryOperator {
123
+ operator: 'and' | 'or';
124
+ left: StandardOperator;
125
+ right: StandardOperator;
126
+ }
127
+
128
+ type ODataQuery = ODataError &
129
+ ODataExpand &
130
+ ODataFetch &
131
+ ODataFilter &
132
+ ODataOrderBy &
133
+ ODataSavedQuery &
134
+ ODataSelect &
135
+ ODataTop &
136
+ ODataUserQuery;
137
+
138
+ export type {
139
+ BinaryOperator,
140
+ ODataError,
141
+ ODataExpand,
142
+ ODataExpandQuery,
143
+ ODataFetch,
144
+ ODataFilter,
145
+ ODataOrderBy,
146
+ ODataQuery,
147
+ ODataSavedQuery,
148
+ ODataSelect,
149
+ ODataTop,
150
+ ODataUserQuery,
151
+ StandardOperator,
152
+ StandardOperators,
153
+ UnaryOperator,
154
+ };
@@ -1,7 +1,7 @@
1
1
  import type { ODataQuery } from './OData.types';
2
2
  /**
3
- * Parses the $expand query
4
- * @returns Returns true when the parse has an error
3
+ * Parses the {@link ODataExpand.$expand $expand} query
4
+ * @returns Returns `false` when the parse has an error
5
5
  */
6
6
  export declare const getExpandFromParser: (parser: URLSearchParams, result: ODataQuery) => boolean;
7
7
  //# sourceMappingURL=getExpandFromParser.d.ts.map
@@ -1,7 +1,7 @@
1
1
  import type { ODataQuery } from './OData.types';
2
2
  /**
3
- * Parses the fetchXml query
4
- * @returns Returns true when the parse has an error
3
+ * Parses the {@link ODataFetch.fetchXml fetchXml} query
4
+ * @returns Returns `false` when the parse has an error
5
5
  */
6
6
  export declare const getFetchXmlFromParser: (parser: URLSearchParams, result: ODataQuery) => boolean;
7
7
  //# sourceMappingURL=getFetchXmlFromParser.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"getFetchXmlFromParser.d.ts","sourceRoot":"","sources":["../../src/getFetchXmlFromParser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD;;;GAGG;AACH,eAAO,MAAM,qBAAqB,WAAY,eAAe,UAAU,UAAU,KAAG,OAyCnF,CAAC"}
1
+ {"version":3,"file":"getFetchXmlFromParser.d.ts","sourceRoot":"","sources":["../../src/getFetchXmlFromParser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,eAAe,CAAC;AAE5D;;;GAGG;AACH,eAAO,MAAM,qBAAqB,WAAY,eAAe,UAAU,UAAU,KAAG,OAiDnF,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { ODataQuery } from './OData.types';
2
+ /**
3
+ * Parses the {@link ODataOrderBy.$orderby $orderby} query
4
+ * @returns Returns `false` when the parse has an error
5
+ */
6
+ export declare const getOrderByFromParser: (parser: URLSearchParams, result: ODataQuery) => boolean;
7
+ //# sourceMappingURL=getOrderByFromParser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getOrderByFromParser.d.ts","sourceRoot":"","sources":["../../src/getOrderByFromParser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAgB,MAAM,eAAe,CAAC;AAK9D;;;GAGG;AACH,eAAO,MAAM,oBAAoB,WAAY,eAAe,UAAU,UAAU,KAAG,OAgClF,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import type { ODataQuery } from './OData.types';
2
2
  /**
3
- * Parses the $select query
4
- * @returns Returns true when the parse has an error
3
+ * Parses the {@link ODataSelect.$select $select} query
4
+ * @returns Returns `false` when the parse has an error
5
5
  */
6
6
  export declare const getSelectFromParser: (parser: URLSearchParams, result: ODataQuery) => boolean;
7
7
  //# sourceMappingURL=getSelectFromParser.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"getSelectFromParser.d.ts","sourceRoot":"","sources":["../../src/getSelectFromParser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD;;;GAGG;AACH,eAAO,MAAM,mBAAmB,WAAY,eAAe,UAAU,UAAU,KAAG,OAMjF,CAAC"}
1
+ {"version":3,"file":"getSelectFromParser.d.ts","sourceRoot":"","sources":["../../src/getSelectFromParser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAe,MAAM,eAAe,CAAC;AAE7D;;;GAGG;AACH,eAAO,MAAM,mBAAmB,WAAY,eAAe,UAAU,UAAU,KAAG,OAMjF,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import type { ODataQuery } from './OData.types';
2
2
  /**
3
- * Parses the $top query
4
- * @returns Returns true when the parse has an error
3
+ * Parses the {@link ODataTop.$top $top} query
4
+ * @returns Returns `false` when the parse has an error
5
5
  */
6
6
  export declare const getTopFromParser: (parser: URLSearchParams, result: ODataQuery) => boolean;
7
7
  //# sourceMappingURL=getTopFromParser.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"getTopFromParser.d.ts","sourceRoot":"","sources":["../../src/getTopFromParser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD;;;GAGG;AACH,eAAO,MAAM,gBAAgB,WAAY,eAAe,UAAU,UAAU,KAAG,OAoB9E,CAAC"}
1
+ {"version":3,"file":"getTopFromParser.d.ts","sourceRoot":"","sources":["../../src/getTopFromParser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAY,MAAM,eAAe,CAAC;AAG1D;;;GAGG;AACH,eAAO,MAAM,gBAAgB,WAAY,eAAe,UAAU,UAAU,KAAG,OAuB9E,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { ODataQuery } from './OData.types';
2
+ /**
3
+ * Parses the {@link ODataSavedQuery.savedQuery savedQuery} or
4
+ * {@link ODataUserQuery.userQuery userQuery} query
5
+ * @returns Returns `false` when the parse has an error
6
+ */
7
+ export declare const getXQueryFromParser: (X: 'savedQuery' | 'userQuery', parser: URLSearchParams, result: ODataQuery) => boolean;
8
+ //# sourceMappingURL=getXQueryFromParser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getXQueryFromParser.d.ts","sourceRoot":"","sources":["../../src/getXQueryFromParser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAmC,MAAM,eAAe,CAAC;AAIjF;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,MACzB,YAAY,GAAG,WAAW,UACrB,eAAe,UACf,UAAU,KACnB,OAoBF,CAAC"}
@@ -1,4 +1,10 @@
1
1
  export type { BinaryOperator, ODataError, ODataExpand, ODataExpandQuery, ODataFetch, ODataFilter, ODataQuery, ODataSelect, ODataTop, StandardOperator, StandardOperators, } from './OData.types';
2
+ export { getExpandFromParser } from './getExpandFromParser';
3
+ export { getFetchXmlFromParser } from './getFetchXmlFromParser';
4
+ export { getOrderByFromParser } from './getOrderByFromParser';
5
+ export { getSelectFromParser } from './getSelectFromParser';
6
+ export { getTopFromParser } from './getTopFromParser';
7
+ export { getXQueryFromParser } from './getXQueryFromParser';
2
8
  export { parseOData } from './parseOData';
3
9
  import { parseOData } from './parseOData';
4
10
  export default parseOData;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACR,cAAc,EACd,UAAU,EACV,WAAW,EACX,gBAAgB,EAChB,UAAU,EACV,WAAW,EACX,UAAU,EACV,WAAW,EACX,QAAQ,EACR,gBAAgB,EAChB,iBAAiB,GACpB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACR,cAAc,EACd,UAAU,EACV,WAAW,EACX,gBAAgB,EAChB,UAAU,EACV,WAAW,EACX,UAAU,EACV,WAAW,EACX,QAAQ,EACR,gBAAgB,EAChB,iBAAiB,GACpB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,eAAe,UAAU,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"parseOData.d.ts","sourceRoot":"","sources":["../../src/parseOData.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAOhD;;;;GAIG;AACH,eAAO,MAAM,UAAU,UAAW,MAAM,eAgBvC,CAAC"}
1
+ {"version":3,"file":"parseOData.d.ts","sourceRoot":"","sources":["../../src/parseOData.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAQhD;;;;GAIG;AACH,eAAO,MAAM,UAAU,UAAW,MAAM,eAsBvC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ODataQuery } from './OData.types';
2
+ export declare const validateNotEmpty: (query: string, value: string, result: ODataQuery) => boolean;
3
+ //# sourceMappingURL=validateNotEmpty.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validateNotEmpty.d.ts","sourceRoot":"","sources":["../../src/validateNotEmpty.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,eAAO,MAAM,gBAAgB,UAAW,MAAM,SAAS,MAAM,UAAU,UAAU,YAShF,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shko.online/dataverse-odata",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "This package will help parse OData strings (only the Microsoft Dataverse subset). It can be used as a validator, or you can build some javascript library which consumes the output of this library.",
5
5
  "scripts": {
6
6
  "build": "npm run lint && node ../scripts/build.js",
@@ -1,41 +1,108 @@
1
- export interface ODataError {
1
+ interface ODataError {
2
2
  error?: {
3
3
  code: string;
4
4
  message: string;
5
5
  };
6
6
  }
7
7
 
8
- export interface ODataExpand {
8
+ interface ODataExpand {
9
+ /**
10
+ * Use the {@link ODataExpand.$expand $expand} system query option in the navigation properties
11
+ * to control what data from related entities is returned.
12
+ * There are two types of navigation properties:
13
+ * * Single-valued navigation properties correspond to Lookup attributes that support many-to-one
14
+ * relationships and allow setting a reference to another entity.
15
+ * * Collection-valued navigation properties correspond to one-to-many or many-to-many relationships.
16
+ *
17
+ * If you include only the name of the navigation property, you'll receive all the properties for
18
+ * related records. You can limit the properties returned for related records using the
19
+ * {@link ODataSelect.$select $select} system query option in parentheses after the navigation
20
+ * property name. Use this for both single-valued and collection-valued navigation properties.
21
+ *
22
+ * * Microsoft Docs: {@link https://learn.microsoft.com/power-apps/developer/data-platform/webapi/retrieve-related-entities-query?WT.mc_id=DX-MVP-5004767 Retrieve related table records with a query }
23
+ */
9
24
  $expand?: {
10
25
  [relationship: string]: ODataExpandQuery;
11
26
  };
12
27
  }
13
28
 
14
- export type ODataExpandQuery = ODataSelect & ODataExpand;
29
+ type ODataExpandQuery = ODataSelect & ODataExpand;
15
30
 
16
- export interface ODataFilter {
31
+ interface ODataFilter {
32
+ /**
33
+ * Use the {@link ODataFilter.$filter $filter} system query option to set criteria for which rows will be returned.
34
+ *
35
+ * * Microsoft Docs: {@link https://learn.microsoft.com/power-apps/developer/data-platform/webapi/query-data-web-api?WT.mc_id=DX-MVP-5004767#filter-results Filter results }
36
+ */
17
37
  $filter?: StandardOperator;
18
38
  }
19
39
 
20
- export interface ODataFetch {
40
+ interface ODataFetch {
41
+ /**
42
+ * You can compose a FetchXML query for a specific table.
43
+ * Then, URL-encode the XML and pass it to the entity set
44
+ * using the {@link ODataFetch.fetchXml fetchXml} query string parameter.
45
+ *
46
+ * * Microsoft Docs: {@link https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/use-fetchxml-web-api?WT.mc_id=DX-MVP-5004767 Use FetchXml with Web API }
47
+ */
21
48
  fetchXml?: XMLDocument;
22
49
  }
23
50
 
24
- export interface ODataSelect {
51
+ interface ODataOrderBy {
25
52
  /**
26
- * Attributes to select.
27
- * Empty array equals to all Attributes.
53
+ * Specify the order in which items are returned using the {@link ODataOrderBy.$orderby $orderby}
54
+ * system query option. Use the asc or desc suffix to specify ascending or descending order
55
+ * respectively. The default is ascending if the suffix isn't applied.
56
+ *
57
+ * * Microsoft Docs: {@link https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/query-data-web-api?WT.mc_id=DX-MVP-5004767#order-results Order results }
58
+ */
59
+ $orderby?: { column: string; asc: boolean }[];
60
+ }
61
+
62
+ interface ODataSavedQuery {
63
+ /**
64
+ * You can use the `savedqueryid` value and pass it as the value to the {@link ODataSavedQuery.savedQuery savedQuery}
65
+ * parameter to the entity set that matches the corresponding `returnedtypecode` of the saved query.
66
+ *
67
+ * * Microsoft Docs: {@link https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/retrieve-and-execute-predefined-queries?WT.mc_id=DX-MVP-5004767#predefined-queries Retrieve and execute predefined queries }
68
+ */
69
+ savedQuery?: string;
70
+ }
71
+
72
+ interface ODataSelect {
73
+ /**
74
+ * Use the {@link ODataSelect.$select $select} system query option to limit the properties returned.
75
+ *
76
+ * This is a performance best practice. If properties aren't specified using
77
+ * {@link ODataSelect.$select $select}, all properties will be returned.
78
+ *
79
+ * * Microsoft Docs: {@link https://learn.microsoft.com/power-apps/developer/data-platform/webapi/query-data-web-api?WT.mc_id=DX-MVP-5004767#request-specific-properties Request specific properties }
28
80
  */
29
81
  $select?: string[];
30
82
  }
31
83
 
32
- export interface ODataTop {
84
+ interface ODataTop {
85
+ /**
86
+ * You can limit the number of results returned by using the {@link ODataTop.$top $top} system query option.
87
+ *
88
+ * * Microsoft Docs: {@link https://learn.microsoft.com/power-apps/developer/data-platform/webapi/query-data-web-api?WT.mc_id=DX-MVP-5004767#use-top-query-option Use $top query option }
89
+ */
33
90
  $top?: number;
34
91
  }
35
92
 
36
- export type StandardOperators = 'eq' | 'ne' | 'gt' | 'ge' | 'lt' | 'le';
93
+ interface ODataUserQuery {
94
+ /**
95
+ * You can use the `userqueryid` value and pass it as the value to the {@link OdataUserQuery.userQuery userQuery}
96
+ * parameter to the entity set that matches the corresponding `returnedtypecode` of the user query.
97
+ *
98
+ * * Microsoft Docs: {@link https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/retrieve-and-execute-predefined-queries?WT.mc_id=DX-MVP-5004767#predefined-queries Retrieve and execute predefined queries }
99
+ */
100
+ userQuery?: string;
101
+ }
37
102
 
38
- export interface StandardOperator {
103
+ type StandardOperators = 'eq' | 'ne' | 'gt' | 'ge' | 'lt' | 'le';
104
+
105
+ interface StandardOperator {
39
106
  operator: StandardOperators;
40
107
  /**
41
108
  * The left side of the 'X' operator must be a property of the entity.
@@ -47,15 +114,41 @@ export interface StandardOperator {
47
114
  right: string | number;
48
115
  }
49
116
 
50
- export interface UnaryOperator {
117
+ interface UnaryOperator {
51
118
  operator: 'not';
52
119
  right: StandardOperator;
53
120
  }
54
121
 
55
- export interface BinaryOperator {
122
+ interface BinaryOperator {
56
123
  operator: 'and' | 'or';
57
124
  left: StandardOperator;
58
125
  right: StandardOperator;
59
126
  }
60
127
 
61
- export type ODataQuery = ODataError & ODataExpand & ODataFilter & ODataSelect & ODataTop & ODataFetch;
128
+ type ODataQuery = ODataError &
129
+ ODataExpand &
130
+ ODataFetch &
131
+ ODataFilter &
132
+ ODataOrderBy &
133
+ ODataSavedQuery &
134
+ ODataSelect &
135
+ ODataTop &
136
+ ODataUserQuery;
137
+
138
+ export type {
139
+ BinaryOperator,
140
+ ODataError,
141
+ ODataExpand,
142
+ ODataExpandQuery,
143
+ ODataFetch,
144
+ ODataFilter,
145
+ ODataOrderBy,
146
+ ODataQuery,
147
+ ODataSavedQuery,
148
+ ODataSelect,
149
+ ODataTop,
150
+ ODataUserQuery,
151
+ StandardOperator,
152
+ StandardOperators,
153
+ UnaryOperator,
154
+ };
@@ -3,19 +3,19 @@ import type { ODataError, ODataExpand, ODataExpandQuery, ODataQuery } from './OD
3
3
  import { getSelectFromParser } from './getSelectFromParser';
4
4
 
5
5
  /**
6
- * Parses the $expand query
7
- * @returns Returns true when the parse has an error
6
+ * Parses the {@link ODataExpand.$expand $expand} query
7
+ * @returns Returns `false` when the parse has an error
8
8
  */
9
9
  export const getExpandFromParser = (parser: URLSearchParams, result: ODataQuery): boolean => {
10
10
  const $expand = parser.get('$expand');
11
11
  if ($expand !== null) {
12
12
  result.$expand = {};
13
13
 
14
- if (extractExpand($expand, result)) {
15
- return true;
14
+ if (!extractExpand($expand, result)) {
15
+ return false;
16
16
  }
17
17
  }
18
- return false;
18
+ return true;
19
19
  };
20
20
 
21
21
  const extractExpand = (value: string, $expand: ODataExpand & ODataError) => {
@@ -29,7 +29,7 @@ const extractExpand = (value: string, $expand: ODataExpand & ODataError) => {
29
29
  code: '0x0',
30
30
  message: 'invalid expand expression',
31
31
  };
32
- return true;
32
+ return false;
33
33
  }
34
34
  let matchSeparator = match[3];
35
35
  let matchLength = match[0].length;
@@ -44,23 +44,23 @@ const extractExpand = (value: string, $expand: ODataExpand & ODataError) => {
44
44
  code: '0x0',
45
45
  message: error,
46
46
  };
47
- return true;
47
+ return false;
48
48
  }
49
49
 
50
50
  if ($expand.$expand !== undefined) {
51
51
  const innerExpand = {} as ODataExpandQuery & ODataError;
52
52
  const parser = new URLSearchParams('?' + value.substring(matchLength, matchLength + index));
53
- if (getSelectFromParser(parser, innerExpand)) {
53
+ if (!getSelectFromParser(parser, innerExpand)) {
54
54
  $expand.error = innerExpand.error;
55
- return true;
55
+ return false;
56
56
  }
57
- if (getExpandFromParser(parser, innerExpand)) {
57
+ if (!getExpandFromParser(parser, innerExpand)) {
58
58
  $expand.error = innerExpand.error;
59
- return true;
59
+ return false;
60
60
  }
61
61
  if (innerExpand.$expand === undefined && innerExpand.$select === undefined) {
62
62
  $expand.error = { code: '0x0', message: 'Empty expand' };
63
- return true;
63
+ return false;
64
64
  }
65
65
  $expand.$expand[match[1]] = innerExpand;
66
66
  }
@@ -76,12 +76,12 @@ const extractExpand = (value: string, $expand: ODataExpand & ODataError) => {
76
76
  }
77
77
 
78
78
  if (matchSeparator === ',') {
79
- if (extractExpand(value.substring(matchLength), $expand)) {
80
- return true;
79
+ if (!extractExpand(value.substring(matchLength), $expand)) {
80
+ return false;
81
81
  }
82
82
  }
83
83
 
84
- return false;
84
+ return true;
85
85
  };
86
86
 
87
87
  const getClosingBracket = (value: string): { index: number; error?: string } => {
@@ -1,12 +1,20 @@
1
- import type { ODataQuery } from './OData.types';
1
+ import type { ODataQuery, ODataFetch } from './OData.types';
2
2
 
3
3
  /**
4
- * Parses the fetchXml query
5
- * @returns Returns true when the parse has an error
4
+ * Parses the {@link ODataFetch.fetchXml fetchXml} query
5
+ * @returns Returns `false` when the parse has an error
6
6
  */
7
7
  export const getFetchXmlFromParser = (parser: URLSearchParams, result: ODataQuery): boolean => {
8
8
  const fetchXml = parser.get('fetchXml');
9
9
  if (fetchXml !== null) {
10
+ if (fetchXml === '') {
11
+ result.error = {
12
+ code: '0x80040203',
13
+ message: 'Expected non-empty string.',
14
+ };
15
+ return false;
16
+ }
17
+
10
18
  const serializer = new DOMParser();
11
19
  const fetchXmlDocument = serializer.parseFromString(fetchXml, 'text/xml');
12
20
  if (fetchXmlDocument.documentElement.tagName === 'parsererror') {
@@ -14,7 +22,7 @@ export const getFetchXmlFromParser = (parser: URLSearchParams, result: ODataQuer
14
22
  code: '0x80040201',
15
23
  message: 'Invalid XML.',
16
24
  };
17
- return true;
25
+ return false;
18
26
  }
19
27
  const entity = fetchXmlDocument
20
28
  .evaluate('fetch/entity', fetchXmlDocument, null, XPathResult.ANY_TYPE, null)
@@ -24,7 +32,7 @@ export const getFetchXmlFromParser = (parser: URLSearchParams, result: ODataQuer
24
32
  code: '0x80041102',
25
33
  message: 'Entity Name was not specified in FetchXml String.',
26
34
  };
27
- return true;
35
+ return false;
28
36
  }
29
37
  const invalidAttribute = fetchXmlDocument
30
38
  .evaluate(
@@ -40,9 +48,9 @@ export const getFetchXmlFromParser = (parser: URLSearchParams, result: ODataQuer
40
48
  code: '0x8004111c',
41
49
  message: `Invalid Child Node, valid nodes are filter, order, link-entity, attribute, all-attributes, no-attrs. NodeName = ${invalidAttribute.tagName} NodeXml = ${invalidAttribute.outerHTML}`,
42
50
  };
43
- return true;
51
+ return false;
44
52
  }
45
53
  result.fetchXml = fetchXmlDocument;
46
54
  }
47
- return false;
55
+ return true;
48
56
  };
@@ -0,0 +1,42 @@
1
+ import type { ODataQuery, ODataOrderBy } from './OData.types';
2
+ import { validateNotEmpty } from './validateNotEmpty';
3
+
4
+ const edmProperty = /\w{1-255}/gi;
5
+
6
+ /**
7
+ * Parses the {@link ODataOrderBy.$orderby $orderby} query
8
+ * @returns Returns `false` when the parse has an error
9
+ */
10
+ export const getOrderByFromParser = (parser: URLSearchParams, result: ODataQuery): boolean => {
11
+ let $orderby = parser.get('$orderby');
12
+ if ($orderby !== null) {
13
+ if (!validateNotEmpty('$orderby', $orderby, result)) {
14
+ return false;
15
+ }
16
+ $orderby = $orderby.trimEnd();
17
+ const orderByArray: ODataOrderBy['$orderby'] = [];
18
+ for (let i = 0; i < $orderby.length; i++) {
19
+ if (false /* syntax error */) {
20
+ result.error = {
21
+ code: '0x0',
22
+ message: `Syntax error at position ${i} in '${$orderby}'.`,
23
+ };
24
+
25
+ return false;
26
+ }
27
+ }
28
+
29
+ orderByArray.forEach((orderBy) => {
30
+ if (!orderBy.column?.match(edmProperty)) {
31
+ result.error = {
32
+ code: '0x80060888',
33
+ message: 'Order By Property must be of type EdmProperty',
34
+ };
35
+ return false;
36
+ }
37
+ });
38
+
39
+ result.$orderby = orderByArray;
40
+ }
41
+ return true;
42
+ };
@@ -1,13 +1,13 @@
1
- import type { ODataQuery } from './OData.types';
1
+ import type { ODataQuery, ODataSelect } from './OData.types';
2
2
 
3
3
  /**
4
- * Parses the $select query
5
- * @returns Returns true when the parse has an error
4
+ * Parses the {@link ODataSelect.$select $select} query
5
+ * @returns Returns `false` when the parse has an error
6
6
  */
7
7
  export const getSelectFromParser = (parser: URLSearchParams, result: ODataQuery): boolean => {
8
8
  const $select = parser.get('$select');
9
9
  if ($select !== null) {
10
10
  result.$select = $select.split(',');
11
11
  }
12
- return false;
12
+ return true;
13
13
  };