segments: Joi.func(),
order: Joi.array().items(Joi.object().keys({
member: Joi.func().required(),
direction: Joi.any().valid('asc', 'desc').required()
})),
filters: Joi.array().items(Joi.object().keys({
member: Joi.func().required(),
operator: Joi.any().valid('contains', 'notContains', 'equals', 'set', 'notSet', 'gt', 'gte', 'lt', 'lte'),
params: Joi.array().items(Joi.string().allow('').optional())
})),
timeDimension: Joi.object().keys({
dimension: Joi.func().required(),
dateRange: Joi.string().required(),
granularity: Joi.any().valid('hour', 'day', 'week', 'month', 'year', null)
}),
visualization: Joi.object().keys({
type: Joi.any().valid('bar', 'line', 'table', 'area', 'singleValue', 'pie').required(),
autoScale: Joi.boolean(),
showTotal: Joi.boolean(),
}),
layout: Joi.object().keys({
w: Joi.any().valid(...Array(19).fill(0).map((_, i) => i + 6)).required(),
h: Joi.any().valid(...Array(47).fill(0).map((_, i) => i + 4)).required(),
x: Joi.any().valid(...Array(24).fill(0).map((_, i) => i)).required(),
y: Joi.number().required()
}).required()
})