@shko.online/dataverse-odata 0.1.6 → 0.2.1

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.
@@ -1,5 +1,234 @@
1
1
  import { atMostOnce } from './validators/atMostOnce';
2
+ import { hasContent } from './validators/hasContent';
2
3
  const option = '$filter';
4
+ const STANDARD_OPERATORS = ['eq', 'ne', 'gt', 'ge', 'lt', 'le'];
5
+ const QUERY_FUNCTION_OPERATORS = ['contains', 'endswith', 'startswith'];
6
+ function isStandardOperator(s) {
7
+ return STANDARD_OPERATORS.includes(s);
8
+ }
9
+ function isQueryFunctionOperator(s) {
10
+ return QUERY_FUNCTION_OPERATORS.includes(s);
11
+ }
12
+ const GUID_REGEX = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/;
13
+ function tokenize(input) {
14
+ const tokens = [];
15
+ let i = 0;
16
+ while (i < input.length) {
17
+ var _input;
18
+ if (/\s/.test(input[i])) {
19
+ i++;
20
+ continue;
21
+ }
22
+ if (input[i] === '(') {
23
+ tokens.push({
24
+ type: 'lparen',
25
+ value: '('
26
+ });
27
+ i++;
28
+ } else if (input[i] === ')') {
29
+ tokens.push({
30
+ type: 'rparen',
31
+ value: ')'
32
+ });
33
+ i++;
34
+ } else if (input[i] === ',') {
35
+ tokens.push({
36
+ type: 'comma',
37
+ value: ','
38
+ });
39
+ i++;
40
+ } else if (input[i] === "'") {
41
+ let j = i + 1;
42
+ let str = '';
43
+ while (j < input.length) {
44
+ if (input[j] === "'" && j + 1 < input.length && input[j + 1] === "'") {
45
+ str += "'";
46
+ j += 2;
47
+ } else if (input[j] === "'") {
48
+ break;
49
+ } else {
50
+ str += input[j];
51
+ j++;
52
+ }
53
+ }
54
+ tokens.push({
55
+ type: 'string',
56
+ value: str
57
+ });
58
+ i = j + 1;
59
+ } else if (/[0-9a-fA-F]/.test(input[i]) && GUID_REGEX.test(input.slice(i))) {
60
+ tokens.push({
61
+ type: 'string',
62
+ value: input.slice(i, i + 36)
63
+ });
64
+ i += 36;
65
+ } else if (/\d/.test(input[i]) || input[i] === '-' && /\d/.test((_input = input[i + 1]) !== null && _input !== void 0 ? _input : '')) {
66
+ let j = i;
67
+ if (input[j] === '-') j++;
68
+ while (j < input.length && /[0-9.]/.test(input[j])) j++;
69
+ tokens.push({
70
+ type: 'number',
71
+ value: input.slice(i, j)
72
+ });
73
+ i = j;
74
+ } else if (/[a-zA-Z_]/.test(input[i])) {
75
+ let j = i;
76
+ while (j < input.length && /\w/.test(input[j])) j++;
77
+ tokens.push({
78
+ type: 'word',
79
+ value: input.slice(i, j)
80
+ });
81
+ i = j;
82
+ } else {
83
+ i++;
84
+ }
85
+ }
86
+ return tokens;
87
+ }
88
+ class FilterParser {
89
+ constructor(tokens) {
90
+ this.tokens = void 0;
91
+ this.pos = 0;
92
+ this.tokens = tokens;
93
+ }
94
+ peek() {
95
+ var _this$tokens$this$pos;
96
+ return (_this$tokens$this$pos = this.tokens[this.pos]) !== null && _this$tokens$this$pos !== void 0 ? _this$tokens$this$pos : null;
97
+ }
98
+ consume(expected) {
99
+ const token = this.tokens[this.pos++];
100
+ const expectedString = expected ? `, expected ${expected}` : '';
101
+ if (!token) throw new Error(`Unexpected end of filter expression${expectedString}`);
102
+ return token;
103
+ }
104
+ expect(type, value) {
105
+ const valueString = value ? ` '${value}'` : '';
106
+ const token = this.consume(`${type}${valueString}`);
107
+ if (token.type !== type || value !== undefined && token.value !== value) {
108
+ throw new Error(`Expected ${type}${valueString} but got ${token.type} '${token.value}'`);
109
+ }
110
+ return token;
111
+ }
112
+ parse() {
113
+ const expr = this.parseOr();
114
+ if (this.pos < this.tokens.length) {
115
+ throw new Error(`Unexpected token '${this.tokens[this.pos].value}'`);
116
+ }
117
+ return expr;
118
+ }
119
+ parseOr() {
120
+ let left = this.parseAnd();
121
+ while (((_this$peek = this.peek()) === null || _this$peek === void 0 ? void 0 : _this$peek.value) === 'or') {
122
+ var _this$peek;
123
+ this.consume();
124
+ const right = this.parseAnd();
125
+ left = {
126
+ operator: 'or',
127
+ left,
128
+ right
129
+ };
130
+ }
131
+ return left;
132
+ }
133
+ parseAnd() {
134
+ let left = this.parseNot();
135
+ while (((_this$peek2 = this.peek()) === null || _this$peek2 === void 0 ? void 0 : _this$peek2.value) === 'and') {
136
+ var _this$peek2;
137
+ this.consume();
138
+ const right = this.parseNot();
139
+ left = {
140
+ operator: 'and',
141
+ left,
142
+ right
143
+ };
144
+ }
145
+ return left;
146
+ }
147
+ parseNot() {
148
+ var _this$peek3;
149
+ if (((_this$peek3 = this.peek()) === null || _this$peek3 === void 0 ? void 0 : _this$peek3.value) === 'not') {
150
+ this.consume();
151
+ const right = this.parseNot();
152
+ return {
153
+ operator: 'not',
154
+ right
155
+ };
156
+ }
157
+ return this.parsePrimary();
158
+ }
159
+ parsePrimary() {
160
+ const token = this.peek();
161
+ if (!token) throw new Error('Unexpected end of filter expression');
162
+ if (token.type === 'lparen') {
163
+ this.consume();
164
+ const expr = this.parseOr();
165
+ this.expect('rparen');
166
+ return expr;
167
+ }
168
+ if (token.type === 'word' && isQueryFunctionOperator(token.value.toLowerCase())) {
169
+ const func = this.consume().value.toLowerCase();
170
+ this.expect('lparen');
171
+ const left = this.expect('word').value;
172
+ this.expect('comma');
173
+ const right = this.expect('string').value;
174
+ this.expect('rparen');
175
+ return {
176
+ operator: func,
177
+ left,
178
+ right
179
+ };
180
+ }
181
+ if (token.type === 'word') {
182
+ const left = this.consume().value;
183
+ const opToken = this.consume(`a comparison operator`);
184
+ if (!isStandardOperator(opToken.value.toLowerCase())) {
185
+ throw new Error(`Invalid operator '${opToken.value}'`);
186
+ }
187
+ const operator = opToken.value.toLowerCase();
188
+ const right = this.consume(`a value or column name`);
189
+ if (right.type === 'string') {
190
+ return {
191
+ operator,
192
+ left,
193
+ right: right.value
194
+ };
195
+ } else if (right.type === 'number') {
196
+ return {
197
+ operator,
198
+ left,
199
+ right: Number(right.value)
200
+ };
201
+ } else if (right.type === 'word') {
202
+ // Constant keywords stay as StandardOperator; bare identifiers are column comparisons
203
+ const BOOL_CONSTANTS = ['true', 'false'];
204
+ if (BOOL_CONSTANTS.includes(right.value.toLowerCase())) {
205
+ return {
206
+ operator,
207
+ left,
208
+ isBooleanOperation: true,
209
+ right: right.value === 'true'
210
+ };
211
+ } else if (right.value.toLowerCase() === 'null') {
212
+ return {
213
+ operator,
214
+ left,
215
+ isNullOperation: true,
216
+ right: null
217
+ };
218
+ }
219
+ return {
220
+ left,
221
+ operator,
222
+ isColumnOperation: true,
223
+ right: right.value
224
+ };
225
+ } else {
226
+ throw new Error(`Invalid right-hand side value of type '${right.type}' in filter expression`);
227
+ }
228
+ }
229
+ throw new Error(`Unexpected token '${token.value}'`);
230
+ }
231
+ }
3
232
 
4
233
  /**
5
234
  * Parses the {@link ODataFilter.$filter $filter} query
@@ -10,15 +239,19 @@ export const getFilterFromParser = (parser, result) => {
10
239
  if (value.length === 0) {
11
240
  return true;
12
241
  }
13
- if (!atMostOnce(option, value, result)) {
242
+ if (!atMostOnce(option, value, result) || !hasContent(option, value, result)) {
14
243
  return false;
15
244
  }
16
- if (value.length > 0) {
17
- result.$filter = {
18
- operator: 'eq',
19
- left: '',
20
- right: ''
245
+ try {
246
+ const tokens = tokenize(value[0]);
247
+ const p = new FilterParser(tokens);
248
+ result.$filter = p.parse();
249
+ } catch (e) {
250
+ result.error = {
251
+ code: '0x80060888',
252
+ message: `Syntax error in '$filter': ${e.message}`
21
253
  };
254
+ return false;
22
255
  }
23
256
  return true;
24
257
  };
@@ -1,9 +1,9 @@
1
+ export { getAliasedProperty } from './getAliasedProperty';
1
2
  export { getExpandFromParser } from './getExpandFromParser';
2
3
  export { getFetchXmlFromParser } from './getFetchXmlFromParser';
4
+ export { getFilterFromParser } from './getFilterFromParser';
3
5
  export { getOrderByFromParser } from './getOrderByFromParser';
4
6
  export { getSelectFromParser } from './getSelectFromParser';
5
7
  export { getTopFromParser } from './getTopFromParser';
6
8
  export { getXQueryFromParser } from './getXQueryFromParser';
7
- export { parseOData } from './parseOData';
8
- import { parseOData } from './parseOData';
9
- export default parseOData;
9
+ export { parseOData, parseOData as default } from './parseOData';
@@ -33,7 +33,7 @@ interface ODataFilter {
33
33
  */
34
34
  $filter?: FilterOperator;
35
35
  }
36
- type FilterOperator = StandardOperator | ColumnOperator | UnaryOperator | BinaryOperator | QueryFunctionOperator;
36
+ type FilterOperator = StandardOperator | BooleanColumnOperator | NullOperator | ColumnOperator | UnaryOperator | BinaryOperator | QueryFunctionOperator;
37
37
  interface ODataFetch {
38
38
  /**
39
39
  * You can compose a FetchXML query for a specific table.
@@ -101,9 +101,40 @@ type StandardOperators = StandardEqualityOperators | 'gt' | 'ge' | 'lt' | 'le';
101
101
  * * Microsoft Docs: {@link https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/query/filter-rows#column-comparison Column comparison }
102
102
  */
103
103
  interface ColumnOperator {
104
- column: string;
104
+ /**
105
+ * The left side of the 'X' operator must be a property of the entity.
106
+ */
107
+ left: string;
105
108
  operator: StandardOperators;
106
- otherColumn: string;
109
+ isColumnOperation: true;
110
+ /**
111
+ * The right side of the 'X' operator must be a property of the entity.
112
+ */
113
+ right: string;
114
+ }
115
+ interface BooleanColumnOperator {
116
+ /**
117
+ * The left side of the 'X' operator must be a property of the entity.
118
+ */
119
+ left: string;
120
+ operator: StandardOperators;
121
+ isBooleanOperation: true;
122
+ /**
123
+ * The right side of the 'X' operator must be a property of the entity.
124
+ */
125
+ right: boolean;
126
+ }
127
+ interface NullOperator {
128
+ /**
129
+ * The left side of the 'X' operator must be a property of the entity.
130
+ */
131
+ left: string;
132
+ operator: StandardOperators;
133
+ isNullOperation: true;
134
+ /**
135
+ * The right side of the 'X' operator must be null.
136
+ */
137
+ right: null;
107
138
  }
108
139
  interface StandardOperator {
109
140
  operator: StandardOperators;
@@ -138,4 +169,4 @@ interface BinaryOperator {
138
169
  right: FilterOperator;
139
170
  }
140
171
  type ODataQuery = ODataError & ODataExpand & ODataFetch & ODataFilter & ODataOrderBy & ODataSavedQuery & ODataSelect & ODataTop & ODataUserQuery;
141
- export { BinaryOperator, ODataError, ODataExpand, ODataExpandQuery, ODataFetch, ODataFilter, ODataOrderBy, ODataQuery, ODataSavedQuery, ODataSelect, ODataTop, ODataUserQuery, StandardOperator, StandardOperators, UnaryOperator, };
172
+ export { BinaryOperator, ColumnOperator, FilterOperator, ODataError, ODataExpand, ODataExpandQuery, ODataFetch, ODataFilter, ODataOrderBy, ODataQuery, ODataSavedQuery, ODataSelect, ODataTop, ODataUserQuery, QueryFunctionOperator, QueryFunctionOperators, StandardOperator, StandardOperators, UnaryOperator, };
@@ -1,11 +1,11 @@
1
- export { BinaryOperator, ODataError, ODataExpand, ODataExpandQuery, ODataFetch, ODataFilter, ODataQuery, ODataSelect, ODataTop, StandardOperator, StandardOperators, } from './OData.types';
1
+ export { BinaryOperator, ColumnOperator, FilterOperator, ODataError, ODataExpand, ODataExpandQuery, ODataFetch, ODataFilter, ODataOrderBy, ODataQuery, ODataSavedQuery, ODataSelect, ODataTop, ODataUserQuery, QueryFunctionOperator, QueryFunctionOperators, StandardOperator, StandardOperators, UnaryOperator, } from './OData.types';
2
+ export { getAliasedProperty } from './getAliasedProperty';
2
3
  export { getExpandFromParser } from './getExpandFromParser';
3
4
  export { getFetchXmlFromParser } from './getFetchXmlFromParser';
5
+ export { getFilterFromParser } from './getFilterFromParser';
4
6
  export { getOrderByFromParser } from './getOrderByFromParser';
5
7
  export { getSelectFromParser } from './getSelectFromParser';
6
8
  export { getTopFromParser } from './getTopFromParser';
7
9
  export { getXQueryFromParser } from './getXQueryFromParser';
8
- export { parseOData } from './parseOData';
9
- import { parseOData } from './parseOData';
10
- export default parseOData;
10
+ export { parseOData, parseOData as default } from './parseOData';
11
11
  //# sourceMappingURL=index.d.ts.map
@@ -33,7 +33,7 @@ interface ODataFilter {
33
33
  */
34
34
  $filter?: FilterOperator;
35
35
  }
36
- type FilterOperator = StandardOperator | ColumnOperator | UnaryOperator | BinaryOperator | QueryFunctionOperator;
36
+ type FilterOperator = StandardOperator | BooleanColumnOperator | NullOperator | ColumnOperator | UnaryOperator | BinaryOperator | QueryFunctionOperator;
37
37
  interface ODataFetch {
38
38
  /**
39
39
  * You can compose a FetchXML query for a specific table.
@@ -101,9 +101,40 @@ type StandardOperators = StandardEqualityOperators | 'gt' | 'ge' | 'lt' | 'le';
101
101
  * * Microsoft Docs: {@link https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/query/filter-rows#column-comparison Column comparison }
102
102
  */
103
103
  interface ColumnOperator {
104
- column: string;
104
+ /**
105
+ * The left side of the 'X' operator must be a property of the entity.
106
+ */
107
+ left: string;
105
108
  operator: StandardOperators;
106
- otherColumn: string;
109
+ isColumnOperation: true;
110
+ /**
111
+ * The right side of the 'X' operator must be a property of the entity.
112
+ */
113
+ right: string;
114
+ }
115
+ interface BooleanColumnOperator {
116
+ /**
117
+ * The left side of the 'X' operator must be a property of the entity.
118
+ */
119
+ left: string;
120
+ operator: StandardOperators;
121
+ isBooleanOperation: true;
122
+ /**
123
+ * The right side of the 'X' operator must be a property of the entity.
124
+ */
125
+ right: boolean;
126
+ }
127
+ interface NullOperator {
128
+ /**
129
+ * The left side of the 'X' operator must be a property of the entity.
130
+ */
131
+ left: string;
132
+ operator: StandardOperators;
133
+ isNullOperation: true;
134
+ /**
135
+ * The right side of the 'X' operator must be null.
136
+ */
137
+ right: null;
107
138
  }
108
139
  interface StandardOperator {
109
140
  operator: StandardOperators;
@@ -138,4 +169,4 @@ interface BinaryOperator {
138
169
  right: FilterOperator;
139
170
  }
140
171
  type ODataQuery = ODataError & ODataExpand & ODataFetch & ODataFilter & ODataOrderBy & ODataSavedQuery & ODataSelect & ODataTop & ODataUserQuery;
141
- export type { BinaryOperator, ODataError, ODataExpand, ODataExpandQuery, ODataFetch, ODataFilter, ODataOrderBy, ODataQuery, ODataSavedQuery, ODataSelect, ODataTop, ODataUserQuery, StandardOperator, StandardOperators, UnaryOperator, };
172
+ export type { BinaryOperator, ColumnOperator, FilterOperator, ODataError, ODataExpand, ODataExpandQuery, ODataFetch, ODataFilter, ODataOrderBy, ODataQuery, ODataSavedQuery, ODataSelect, ODataTop, ODataUserQuery, QueryFunctionOperator, QueryFunctionOperators, StandardOperator, StandardOperators, UnaryOperator, };
@@ -1,11 +1,11 @@
1
- export type { BinaryOperator, ODataError, ODataExpand, ODataExpandQuery, ODataFetch, ODataFilter, ODataQuery, ODataSelect, ODataTop, StandardOperator, StandardOperators, } from './OData.types';
1
+ export type { BinaryOperator, ColumnOperator, FilterOperator, ODataError, ODataExpand, ODataExpandQuery, ODataFetch, ODataFilter, ODataOrderBy, ODataQuery, ODataSavedQuery, ODataSelect, ODataTop, ODataUserQuery, QueryFunctionOperator, QueryFunctionOperators, StandardOperator, StandardOperators, UnaryOperator, } from './OData.types';
2
+ export { getAliasedProperty } from './getAliasedProperty';
2
3
  export { getExpandFromParser } from './getExpandFromParser';
3
4
  export { getFetchXmlFromParser } from './getFetchXmlFromParser';
5
+ export { getFilterFromParser } from './getFilterFromParser';
4
6
  export { getOrderByFromParser } from './getOrderByFromParser';
5
7
  export { getSelectFromParser } from './getSelectFromParser';
6
8
  export { getTopFromParser } from './getTopFromParser';
7
9
  export { getXQueryFromParser } from './getXQueryFromParser';
8
- export { parseOData } from './parseOData';
9
- import { parseOData } from './parseOData';
10
- export default parseOData;
10
+ export { parseOData, parseOData as default } from './parseOData';
11
11
  //# sourceMappingURL=index.d.ts.map
@@ -37,7 +37,14 @@ interface ODataFilter {
37
37
  $filter?: FilterOperator;
38
38
  }
39
39
 
40
- type FilterOperator = StandardOperator | ColumnOperator | UnaryOperator | BinaryOperator | QueryFunctionOperator;
40
+ type FilterOperator =
41
+ | StandardOperator
42
+ | BooleanColumnOperator
43
+ | NullOperator
44
+ | ColumnOperator
45
+ | UnaryOperator
46
+ | BinaryOperator
47
+ | QueryFunctionOperator;
41
48
 
42
49
  interface ODataFetch {
43
50
  /**
@@ -107,15 +114,47 @@ type StandardEqualityOperators = 'eq' | 'ne';
107
114
  type StandardOperators = StandardEqualityOperators | 'gt' | 'ge' | 'lt' | 'le';
108
115
 
109
116
  /**
110
- *
117
+ *
111
118
  * * Microsoft Docs: {@link https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/query/filter-rows#column-comparison Column comparison }
112
119
  */
113
120
  interface ColumnOperator {
114
- column: string;
121
+ /**
122
+ * The left side of the 'X' operator must be a property of the entity.
123
+ */
124
+ left: string;
125
+ operator: StandardOperators;
126
+ isColumnOperation: true;
127
+ /**
128
+ * The right side of the 'X' operator must be a property of the entity.
129
+ */
130
+ right: string;
131
+ }
132
+
133
+ interface BooleanColumnOperator {
134
+ /**
135
+ * The left side of the 'X' operator must be a property of the entity.
136
+ */
137
+ left: string;
115
138
  operator: StandardOperators;
116
- otherColumn: string;
139
+ isBooleanOperation: true;
140
+ /**
141
+ * The right side of the 'X' operator must be a property of the entity.
142
+ */
143
+ right: boolean;
117
144
  }
118
145
 
146
+ interface NullOperator {
147
+ /**
148
+ * The left side of the 'X' operator must be a property of the entity.
149
+ */
150
+ left: string;
151
+ operator: StandardOperators;
152
+ isNullOperation: true;
153
+ /**
154
+ * The right side of the 'X' operator must be null.
155
+ */
156
+ right: null;
157
+ }
119
158
 
120
159
  interface StandardOperator {
121
160
  operator: StandardOperators;
@@ -166,6 +205,8 @@ type ODataQuery = ODataError &
166
205
 
167
206
  export type {
168
207
  BinaryOperator,
208
+ ColumnOperator,
209
+ FilterOperator,
169
210
  ODataError,
170
211
  ODataExpand,
171
212
  ODataExpandQuery,
@@ -177,7 +218,9 @@ export type {
177
218
  ODataSelect,
178
219
  ODataTop,
179
220
  ODataUserQuery,
221
+ QueryFunctionOperator,
222
+ QueryFunctionOperators,
180
223
  StandardOperator,
181
224
  StandardOperators,
182
- UnaryOperator,
225
+ UnaryOperator,
183
226
  };
@@ -1 +1 @@
1
- {"version":3,"file":"getFilterFromParser.d.ts","sourceRoot":"","sources":["../../src/getFilterFromParser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAe,MAAM,eAAe,CAAC;AAK7D;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAAI,QAAQ,eAAe,EAAE,QAAQ,UAAU,KAAG,OAajF,CAAC"}
1
+ {"version":3,"file":"getFilterFromParser.d.ts","sourceRoot":"","sources":["../../src/getFilterFromParser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAkB,MAAM,eAAe,CAAC;AAyMhE;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAAI,QAAQ,eAAe,EAAE,QAAQ,UAAU,KAAG,OAoBjF,CAAC"}
@@ -1,11 +1,11 @@
1
- export type { BinaryOperator, ODataError, ODataExpand, ODataExpandQuery, ODataFetch, ODataFilter, ODataQuery, ODataSelect, ODataTop, StandardOperator, StandardOperators, } from './OData.types';
1
+ export type { BinaryOperator, ColumnOperator, FilterOperator, ODataError, ODataExpand, ODataExpandQuery, ODataFetch, ODataFilter, ODataOrderBy, ODataQuery, ODataSavedQuery, ODataSelect, ODataTop, ODataUserQuery, QueryFunctionOperator, QueryFunctionOperators, StandardOperator, StandardOperators, UnaryOperator, } from './OData.types';
2
+ export { getAliasedProperty } from './getAliasedProperty';
2
3
  export { getExpandFromParser } from './getExpandFromParser';
3
4
  export { getFetchXmlFromParser } from './getFetchXmlFromParser';
5
+ export { getFilterFromParser } from './getFilterFromParser';
4
6
  export { getOrderByFromParser } from './getOrderByFromParser';
5
7
  export { getSelectFromParser } from './getSelectFromParser';
6
8
  export { getTopFromParser } from './getTopFromParser';
7
9
  export { getXQueryFromParser } from './getXQueryFromParser';
8
- export { parseOData } from './parseOData';
9
- import { parseOData } from './parseOData';
10
- export default parseOData;
10
+ export { parseOData, parseOData as default } from './parseOData';
11
11
  //# sourceMappingURL=index.d.ts.map
@@ -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,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
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACR,cAAc,EACd,cAAc,EACd,cAAc,EACd,UAAU,EACV,WAAW,EACX,gBAAgB,EAChB,UAAU,EACV,WAAW,EACX,YAAY,EACZ,UAAU,EACV,eAAe,EACf,WAAW,EACX,QAAQ,EACR,cAAc,EACd,qBAAqB,EACrB,sBAAsB,EACtB,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,GAChB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,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,UAAU,IAAI,OAAO,EAAE,MAAM,cAAc,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shko.online/dataverse-odata",
3
- "version": "0.1.6",
3
+ "version": "0.2.1",
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 && build-npm-package",
@@ -43,8 +43,8 @@
43
43
  },
44
44
  "homepage": "https://github.com/shko-online/dataverse-odata#readme",
45
45
  "devDependencies": {
46
- "@babel/cli": "^7.20.7",
47
- "@babel/core": "^7.20.12",
46
+ "@babel/cli": "^7.28.6",
47
+ "@babel/core": "^7.29.0",
48
48
  "@babel/plugin-proposal-class-properties": "^7.18.6",
49
49
  "@babel/plugin-proposal-decorators": "^7.20.13",
50
50
  "@babel/plugin-proposal-export-default-from": "^7.18.10",
@@ -53,11 +53,11 @@
53
53
  "@babel/plugin-proposal-private-property-in-object": "^7.20.5",
54
54
  "@babel/plugin-syntax-dynamic-import": "^7.8.3",
55
55
  "@babel/plugin-transform-runtime": "^7.19.6",
56
- "@babel/preset-env": "^7.20.2",
57
- "@babel/preset-flow": "^7.18.6",
58
- "@babel/preset-react": "^7.18.6",
59
- "@babel/preset-typescript": "^7.18.6",
60
- "@emotion/babel-plugin": "^11.10.5",
56
+ "@babel/preset-env": "^7.29.2",
57
+ "@babel/preset-flow": "^7.27.1",
58
+ "@babel/preset-react": "^7.28.5",
59
+ "@babel/preset-typescript": "^7.28.5",
60
+ "@emotion/babel-plugin": "^11.13.5",
61
61
  "@jest/globals": "^29.4.2",
62
62
  "@semantic-release/changelog": "^6.0.3",
63
63
  "@semantic-release/commit-analyzer": "^13.0.1",
@@ -37,7 +37,14 @@ interface ODataFilter {
37
37
  $filter?: FilterOperator;
38
38
  }
39
39
 
40
- type FilterOperator = StandardOperator | ColumnOperator | UnaryOperator | BinaryOperator | QueryFunctionOperator;
40
+ type FilterOperator =
41
+ | StandardOperator
42
+ | BooleanColumnOperator
43
+ | NullOperator
44
+ | ColumnOperator
45
+ | UnaryOperator
46
+ | BinaryOperator
47
+ | QueryFunctionOperator;
41
48
 
42
49
  interface ODataFetch {
43
50
  /**
@@ -107,15 +114,47 @@ type StandardEqualityOperators = 'eq' | 'ne';
107
114
  type StandardOperators = StandardEqualityOperators | 'gt' | 'ge' | 'lt' | 'le';
108
115
 
109
116
  /**
110
- *
117
+ *
111
118
  * * Microsoft Docs: {@link https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/query/filter-rows#column-comparison Column comparison }
112
119
  */
113
120
  interface ColumnOperator {
114
- column: string;
121
+ /**
122
+ * The left side of the 'X' operator must be a property of the entity.
123
+ */
124
+ left: string;
125
+ operator: StandardOperators;
126
+ isColumnOperation: true;
127
+ /**
128
+ * The right side of the 'X' operator must be a property of the entity.
129
+ */
130
+ right: string;
131
+ }
132
+
133
+ interface BooleanColumnOperator {
134
+ /**
135
+ * The left side of the 'X' operator must be a property of the entity.
136
+ */
137
+ left: string;
115
138
  operator: StandardOperators;
116
- otherColumn: string;
139
+ isBooleanOperation: true;
140
+ /**
141
+ * The right side of the 'X' operator must be a property of the entity.
142
+ */
143
+ right: boolean;
117
144
  }
118
145
 
146
+ interface NullOperator {
147
+ /**
148
+ * The left side of the 'X' operator must be a property of the entity.
149
+ */
150
+ left: string;
151
+ operator: StandardOperators;
152
+ isNullOperation: true;
153
+ /**
154
+ * The right side of the 'X' operator must be null.
155
+ */
156
+ right: null;
157
+ }
119
158
 
120
159
  interface StandardOperator {
121
160
  operator: StandardOperators;
@@ -166,6 +205,8 @@ type ODataQuery = ODataError &
166
205
 
167
206
  export type {
168
207
  BinaryOperator,
208
+ ColumnOperator,
209
+ FilterOperator,
169
210
  ODataError,
170
211
  ODataExpand,
171
212
  ODataExpandQuery,
@@ -177,7 +218,9 @@ export type {
177
218
  ODataSelect,
178
219
  ODataTop,
179
220
  ODataUserQuery,
221
+ QueryFunctionOperator,
222
+ QueryFunctionOperators,
180
223
  StandardOperator,
181
224
  StandardOperators,
182
- UnaryOperator,
225
+ UnaryOperator,
183
226
  };
@@ -30,7 +30,7 @@ export const getFetchXmlFromParser = (parser: URLSearchParams, result: ODataQuer
30
30
  const entity = fetchXmlDocument
31
31
  .evaluate('fetch/entity', fetchXmlDocument, null, XPathResult.ANY_TYPE, null)
32
32
  .iterateNext() as Element;
33
- if (fetchXmlDocument.documentElement.children.length != 1 || !entity || !entity.getAttribute('name')) {
33
+ if (fetchXmlDocument.documentElement.children.length != 1 || !entity?.getAttribute('name')) {
34
34
  result.error = {
35
35
  code: '0x80041102',
36
36
  message: 'Entity Name was not specified in FetchXml String.',