Skip to content

Commit a3b4cd6

Browse files
committed
fix: Invalid query format: \"filters[0]\" does not match any of the allowed types for or query
1 parent 5da5e61 commit a3b4cd6

File tree

2 files changed

+56
-22
lines changed

2 files changed

+56
-22
lines changed

packages/cubejs-api-gateway/src/query.js

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ const oneFilter = Joi.object().keys({
7070
dimension: id,
7171
member: id,
7272
operator: Joi.valid(...operators).required(),
73-
values: Joi.array().items(Joi.string().allow('', null), Joi.link('...'), Joi.number(), Joi.boolean())
73+
values: Joi.array().items(Joi.string().allow('', null), Joi.number(), Joi.boolean(), Joi.link('...'))
7474
}).xor('dimension', 'member');
7575

7676
const oneCondition = Joi.object().keys({
@@ -118,15 +118,16 @@ const normalizeQueryOrder = order => {
118118

119119
const DateRegex = /^\d\d\d\d-\d\d-\d\d$/;
120120

121-
const checkQueryFilters = (filter) => {
122-
filter.find(f => {
121+
const normalizeQueryFilters = (filter) => (
122+
filter.map(f => {
123+
const res = { ...f };
123124
if (f.or) {
124-
checkQueryFilters(f.or);
125-
return false;
125+
res.or = normalizeQueryFilters(f.or);
126+
return res;
126127
}
127128
if (f.and) {
128-
checkQueryFilters(f.and);
129-
return false;
129+
res.and = normalizeQueryFilters(f.and);
130+
return res;
130131
}
131132

132133
if (!f.operator) {
@@ -137,18 +138,27 @@ const checkQueryFilters = (filter) => {
137138
throw new UserError(`Operator ${f.operator} not supported for filter: ${JSON.stringify(f)}`);
138139
}
139140

140-
if (!f.values && ['set', 'notSet', 'measureFilter'].indexOf(f.operator) === -1) {
141+
if ((!f.values || f.values.length === 0) && ['set', 'notSet', 'measureFilter'].indexOf(f.operator) === -1) {
141142
throw new UserError(`Values required for filter: ${JSON.stringify(f)}`);
142143
}
143-
return false;
144-
});
145144

146-
return true;
147-
};
145+
if (f.values) {
146+
res.values = f.values.map(v => (v != null ? v.toString() : v));
147+
}
148+
149+
if (f.dimension) {
150+
res.member = f.dimension;
151+
delete res.dimension;
152+
}
153+
154+
return res;
155+
})
156+
);
148157

149158
/**
150159
* Normalize incoming network query.
151160
* @param {Query} query
161+
* @param {boolean} persistent
152162
* @throws {UserError}
153163
* @returns {NormalizedQuery}
154164
*/
@@ -166,8 +176,6 @@ const normalizeQuery = (query, persistent) => {
166176
);
167177
}
168178

169-
checkQueryFilters(query.filters || []);
170-
171179
const regularToTimeDimension = (query.dimensions || []).filter(d => d.split('.').length === 3).map(d => ({
172180
dimension: d.split('.').slice(0, 2).join('.'),
173181
granularity: d.split('.')[2]
@@ -198,14 +206,7 @@ const normalizeQuery = (query, persistent) => {
198206
limit: newLimit,
199207
timezone,
200208
order: normalizeQueryOrder(query.order),
201-
filters: (query.filters || []).map(f => {
202-
const { dimension, member, ...filter } = f;
203-
return {
204-
...filter,
205-
member: member || dimension,
206-
values: filter.values?.map(v => (v != null ? v.toString() : v))
207-
};
208-
}),
209+
filters: normalizeQueryFilters(query.filters || []),
209210
dimensions: (query.dimensions || []).filter(d => d.split('.').length !== 3),
210211
timeDimensions: (query.timeDimensions || []).map(td => {
211212
let dateRange;

packages/cubejs-api-gateway/test/index.test.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,16 @@ describe('API Gateway', () => {
297297
member: 'Foo.bar',
298298
operator: 'gte',
299299
values: [0]
300+
}, {
301+
or: [{
302+
member: 'Foo.bar',
303+
operator: 'gte',
304+
values: [10.5]
305+
}, {
306+
member: 'Foo.bar',
307+
operator: 'gte',
308+
values: [0]
309+
}]
300310
}]
301311
};
302312

@@ -317,6 +327,16 @@ describe('API Gateway', () => {
317327
member: 'Foo.bar',
318328
operator: 'gte',
319329
values: ['0']
330+
}, {
331+
or: [{
332+
member: 'Foo.bar',
333+
operator: 'gte',
334+
values: ['10.5']
335+
}, {
336+
member: 'Foo.bar',
337+
operator: 'gte',
338+
values: ['0']
339+
}]
320340
}],
321341
rowLimit: 10000,
322342
limit: 10000,
@@ -329,6 +349,19 @@ describe('API Gateway', () => {
329349
);
330350
});
331351

352+
test('normalize empty filters', async () => {
353+
const { app } = createApiGateway();
354+
355+
const res = await request(app)
356+
.get(
357+
'/cubejs-api/v1/load?query={"measures":["Foo.bar"],"filters":[{"member":"Foo.bar","operator":"equals","values":[]}]}'
358+
)
359+
.set('Authorization', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.t-IDcSemACt8x4iTMCda8Yhe3iZaWbvV5XKSTbuAn0M')
360+
.expect(400);
361+
console.log(res.body);
362+
expect(res.body.error).toMatch(/Values required for filter/);
363+
});
364+
332365
test('normalize queryRewrite limit', async () => {
333366
const { app } = createApiGateway(
334367
new AdapterApiMock(),

0 commit comments

Comments
 (0)