Add casting tests

This commit is contained in:
Alexandre Bodin 2021-10-27 14:59:13 +02:00
parent 674acadcc6
commit 4781d44ce8
2 changed files with 116 additions and 18 deletions

View File

@ -60,13 +60,17 @@ const castValue = (value, attribute) => {
return value; return value;
}; };
const processAttributeWhere = (attribute, where, ctx) => { const processAttributeWhere = (attribute, where, operator = '$eq') => {
if (_.isArray(where)) { if (_.isArray(where)) {
return where.map(sub => processAttributeWhere(attribute, sub, ctx)); return where.map(sub => processAttributeWhere(attribute, sub, operator));
} }
if (!_.isPlainObject(where)) { if (!_.isPlainObject(where)) {
return castValue(where, attribute); if (CAST_OPERATORS.includes(operator)) {
return castValue(where, attribute);
}
return where;
} }
const filters = {}; const filters = {};
@ -74,21 +78,11 @@ const processAttributeWhere = (attribute, where, ctx) => {
for (const key in where) { for (const key in where) {
const value = where[key]; const value = where[key];
if (isOperator(key)) { if (!isOperator(key)) {
if (!_.isPlainObject(value)) { throw new Error(`Undefined attribute level operator ${key}`);
if (CAST_OPERATORS.includes(key)) {
filters[key] = castValue(value, attribute);
} else {
filters[key] = value;
}
continue;
}
filters[key] = processAttributeWhere(attribute, value, ctx);
continue;
} }
throw new Error(`Undefined attribute level operator ${key}`); filters[key] = processAttributeWhere(attribute, value, key);
} }
return filters; return filters;
@ -145,7 +139,7 @@ const processWhere = (where, ctx) => {
const attribute = meta.attributes[key]; const attribute = meta.attributes[key];
if (!attribute) { if (!attribute) {
filters[qb.aliasColumn(key, alias)] = processAttributeWhere(null, value, ctx); filters[qb.aliasColumn(key, alias)] = processAttributeWhere(null, value);
continue; continue;
} }
@ -179,7 +173,7 @@ const processWhere = (where, ctx) => {
const columnName = toColumnName(meta, key); const columnName = toColumnName(meta, key);
const aliasedColumnName = qb.aliasColumn(columnName, alias); const aliasedColumnName = qb.aliasColumn(columnName, alias);
filters[aliasedColumnName] = processAttributeWhere(attribute, value, ctx); filters[aliasedColumnName] = processAttributeWhere(attribute, value);
continue; continue;
} }

View File

@ -35,6 +35,9 @@ const product = {
big_rank: { big_rank: {
type: 'biginteger', type: 'biginteger',
}, },
isChecked: {
type: 'boolean',
},
}, },
displayName: 'Product', displayName: 'Product',
singularName: 'product', singularName: 'product',
@ -51,6 +54,7 @@ const productFixtures = [
decimal_field: 42.43, decimal_field: 42.43,
rank: 42, rank: 42,
big_rank: '345678912983', big_rank: '345678912983',
isChecked: true,
}, },
{ {
name: 'Product 2', name: 'Product 2',
@ -59,6 +63,7 @@ const productFixtures = [
decimal_field: 91.22, decimal_field: 91.22,
rank: 82, rank: 82,
big_rank: '926371623421', big_rank: '926371623421',
isChecked: false,
}, },
{ {
name: 'Product 3', name: 'Product 3',
@ -67,6 +72,7 @@ const productFixtures = [
decimal_field: 12.22, decimal_field: 12.22,
rank: 91, rank: 91,
big_rank: '926372323421', big_rank: '926372323421',
isChecked: true,
}, },
{ {
name: 'Product 4', name: 'Product 4',
@ -75,6 +81,7 @@ const productFixtures = [
decimal_field: 12.22, decimal_field: 12.22,
rank: 99, rank: 99,
big_rank: '999999999999', big_rank: '999999999999',
isChecked: false,
}, },
{ {
name: 'Продукт 5, Product 5', name: 'Продукт 5, Product 5',
@ -83,6 +90,7 @@ const productFixtures = [
decimal_field: 142.43, decimal_field: 142.43,
rank: 142, rank: 142,
big_rank: 345678912983, big_rank: 345678912983,
isChecked: true,
}, },
]; ];
@ -1376,4 +1384,100 @@ describe('Filtering API', () => {
expect(res.body.data).toEqual(expect.arrayContaining([data.product[4]])); expect(res.body.data).toEqual(expect.arrayContaining([data.product[4]]));
}); });
}); });
describe('Type casting', () => {
describe('Booleans', () => {
test.each(['1', 'true', true, 't'])('Cast truthy booleans %s', async val => {
const res = await rq({
method: 'GET',
url: '/products',
qs: {
filters: {
isChecked: val,
},
},
});
expect(res.body.data).toEqual(
expect.arrayContaining([data.product[0], data.product[2], data.product[4]])
);
});
test.each(['1', 'true', true, 't'])('Cast truthy booleans nested %s', async val => {
const res = await rq({
method: 'GET',
url: '/products',
qs: {
filters: {
isChecked: {
$eq: val,
},
},
},
});
expect(res.body.data).toEqual(
expect.arrayContaining([data.product[0], data.product[2], data.product[4]])
);
});
test.each(['1', 'true', true, 't'])('Cast truthy booleans in arrays %s', async val => {
const res = await rq({
method: 'GET',
url: '/products',
qs: {
filters: {
isChecked: {
$in: [val],
},
},
},
});
expect(res.body.data).toEqual(
expect.arrayContaining([data.product[0], data.product[2], data.product[4]])
);
});
test.each(['0', 'false', false, 'f'])('Cast truthy booleans %s', async val => {
const res = await rq({
method: 'GET',
url: '/products',
qs: {
filters: {
isChecked: val,
},
},
});
expect(res.body.data).toEqual(expect.arrayContaining([data.product[1], data.product[3]]));
});
test.each(['0', 'false', false, 'f'])('Cast truthy booleans nested %s', async val => {
const res = await rq({
method: 'GET',
url: '/products',
qs: {
filters: {
isChecked: {
$eq: val,
},
},
},
});
expect(res.body.data).toEqual(expect.arrayContaining([data.product[1], data.product[3]]));
});
test.each(['0', 'false', false, 'f'])('Cast truthy booleans in arrays %s', async val => {
const res = await rq({
method: 'GET',
url: '/products',
qs: {
filters: {
isChecked: {
$in: [val],
},
},
},
});
expect(res.body.data).toEqual(expect.arrayContaining([data.product[1], data.product[3]]));
});
});
});
}); });