Type cast filters

This commit is contained in:
Alexandre Bodin 2021-10-27 10:03:09 +02:00
parent 74919aafee
commit f73d302129
2 changed files with 51 additions and 33 deletions

View File

@ -8,16 +8,6 @@ class Field {
this.config = config; this.config = config;
} }
// TODO: impl
validate() {
// // use config validators directly
// if (this.config.validators) {
// this.config.validators.forEach(validator => {
// validator(value)
// })
// }
}
toDB(value) { toDB(value) {
return value; return value;
} }

View File

@ -3,6 +3,7 @@
const _ = require('lodash/fp'); const _ = require('lodash/fp');
const types = require('../../types'); const types = require('../../types');
const { createField } = require('../../fields');
const { createJoin } = require('./join'); const { createJoin } = require('./join');
const { toColumnName } = require('./transform'); const { toColumnName } = require('./transform');
@ -32,6 +33,45 @@ const ARRAY_OPERATORS = ['$in', '$notIn', '$between'];
const isOperator = key => OPERATORS.includes(key); const isOperator = key => OPERATORS.includes(key);
const castValue = (value, attribute) => {
if (!attribute) {
return value;
}
if (types.isScalar(attribute.type)) {
const field = createField(attribute);
return value === null ? null : field.toDB(value);
}
return value;
};
const processAttributeWhere = (attribute, where, ctx) => {
if (_.isArray(where)) {
return where.map(sub => processAttributeWhere(attribute, sub, ctx));
}
if (!_.isPlainObject(where)) {
return castValue(where, attribute);
}
const filters = {};
for (const key in where) {
const value = where[key];
if (isOperator(key)) {
filters[key] = processAttributeWhere(attribute, value, ctx);
continue;
}
throw new Error(`Undefined attribute level operator ${key}`);
}
return filters;
};
/** /**
* Process where parameter * Process where parameter
* @param {Object} where * @param {Object} where
@ -39,7 +79,7 @@ const isOperator = key => OPERATORS.includes(key);
* @param {number} depth * @param {number} depth
* @returns {Object} * @returns {Object}
*/ */
const processWhere = (where, ctx, depth = 0) => { const processWhere = (where, ctx) => {
if (!_.isArray(where) && !_.isPlainObject(where)) { if (!_.isArray(where) && !_.isPlainObject(where)) {
throw new Error('Where must be an array or an object'); throw new Error('Where must be an array or an object');
} }
@ -53,7 +93,7 @@ const processWhere = (where, ctx, depth = 0) => {
return where; return where;
} }
return processWhere(where, ctx, depth + 1); return processWhere(where, ctx);
}; };
const { db, uid, qb, alias } = ctx; const { db, uid, qb, alias } = ctx;
@ -64,7 +104,6 @@ const processWhere = (where, ctx, depth = 0) => {
// for each key in where // for each key in where
for (const key in where) { for (const key in where) {
const value = where[key]; const value = where[key];
const attribute = meta.attributes[key];
// if operator $and $or then loop over them // if operator $and $or then loop over them
if (GROUP_OPERATORS.includes(key)) { if (GROUP_OPERATORS.includes(key)) {
@ -78,28 +117,17 @@ const processWhere = (where, ctx, depth = 0) => {
} }
if (isOperator(key)) { if (isOperator(key)) {
if (depth == 0) { throw new Error(`Only $and, $or and $not can by used as root level operators. Found ${key}.`);
throw new Error(
`Only $and, $or and $not can by used as root level operators. Found ${key}.`
);
}
filters[key] = processNested(value, ctx);
continue;
} }
const attribute = meta.attributes[key];
if (!attribute) { if (!attribute) {
filters[qb.aliasColumn(key, alias)] = processNested(value, ctx); filters[qb.aliasColumn(key, alias)] = processAttributeWhere(null, value, ctx);
continue; continue;
// throw new Error(`Attribute ${key} not found on model ${uid}`);
} }
// move to if else to check for scalar / relation / components & throw for other types if (types.isRelation(attribute.type)) {
if (attribute.type === 'relation') {
// TODO: pass down some filters (e.g published at)
// attribute // attribute
const subAlias = createJoin(ctx, { const subAlias = createJoin(ctx, {
alias: alias || qb.alias, alias: alias || qb.alias,
@ -127,9 +155,10 @@ const processWhere = (where, ctx, depth = 0) => {
if (types.isScalar(attribute.type)) { if (types.isScalar(attribute.type)) {
const columnName = toColumnName(meta, key); const columnName = toColumnName(meta, key);
const aliasedColumnName = qb.aliasColumn(columnName, alias);
filters[aliasedColumnName] = processAttributeWhere(attribute, value, ctx);
// TODO: cast to DB type
filters[qb.aliasColumn(columnName, alias)] = processNested(value, ctx);
continue; continue;
} }
@ -253,7 +282,7 @@ const applyOperator = (qb, column, operator, value) => {
// TODO: relational operators every/some/exists/size ... // TODO: relational operators every/some/exists/size ...
default: { default: {
throw new Error(`Undefined operator ${operator}`); throw new Error(`Undefined attribute level operator ${operator}`);
} }
} }
}; };
@ -267,7 +296,6 @@ const applyWhereToColumn = (qb, column, columnWhere) => {
return qb.where(column, columnWhere); return qb.where(column, columnWhere);
} }
// TODO: handle casing
Object.keys(columnWhere).forEach(operator => { Object.keys(columnWhere).forEach(operator => {
const value = columnWhere[operator]; const value = columnWhere[operator];