diff --git a/CHANGELOG.md b/CHANGELOG.md index 38ac0832..212d4b6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ ### Added - Line Charts - Support SQLite dialect for groupBy fields. +### Fixed +- Resource Retrieval - Fix the record retrieval for a record having no belongsTo/hasOne for projects using Sequelize 4.8.x. +- Charts - Fix broken charts if they contain relationship filters on model fields that have a different column name. + ## RELEASE 1.3.6 - 2017-09-10 ### Changed - Initialization - Display an explicit error log if a model cannot be loaded properly. diff --git a/services/base-stat-getter.js b/services/base-stat-getter.js new file mode 100644 index 00000000..835f2b03 --- /dev/null +++ b/services/base-stat-getter.js @@ -0,0 +1,42 @@ +'use strict'; +var _ = require('lodash'); +var Interface = require('forest-express'); +var OperatorValueParser = require('./operator-value-parser'); + +function BaseStatGetter(model, params) { + this.model = model; + this.params = params; + + this.getFilters = function () { + var where = {}; + var conditions = []; + var model = this.model; + var params = this.params; + + if (params.filters) { + params.filters.forEach(function (filter) { + var field = filter.field; + if (field.indexOf(':') !== -1) { + var fieldSplited = field.split(':'); + var associationSchema = Interface.Schemas.schemas[fieldSplited[0]]; + var associationField = _.findWhere(associationSchema.fields, { + field: fieldSplited[1] + }); + field = '$' + associationSchema.name + '.' + associationField.columnName + '$'; + } + + var condition = {}; + condition[field] = new OperatorValueParser().perform(model, + filter.field, filter.value, params.timezone); + conditions.push(condition); + }); + } + + if (params.filterType) { + where['$' + params.filterType] = conditions; + } + return where; + }; +} + +module.exports = BaseStatGetter; diff --git a/services/line-stat-getter.js b/services/line-stat-getter.js index 7296a84f..e3a73d8a 100644 --- a/services/line-stat-getter.js +++ b/services/line-stat-getter.js @@ -2,12 +2,14 @@ var _ = require('lodash'); var P = require('bluebird'); var moment = require('moment'); -var OperatorValueParser = require('./operator-value-parser'); +var BaseStatGetter = require('./base-stat-getter'); var Database = require('../utils/database'); var Interface = require('forest-express'); // jshint sub: true function LineStatGetter(model, params, opts) { + BaseStatGetter.call(this, model, params); + var schema = Interface.Schemas.schemas[model.name]; var timeRange = params['time_range'].toLowerCase(); @@ -153,28 +155,6 @@ function LineStatGetter(model, params, opts) { ]; } - function getFilters() { - var where = {}; - var conditions = []; - - if (params.filters) { - params.filters.forEach(function (filter) { - var field = filter.field; - if (field.indexOf(':') !== -1) { - field = '$' + field.replace(':', '.') + '$'; - } - - var condition = {}; - condition[field] = new OperatorValueParser().perform(model, - filter.field, filter.value, params.timezone); - conditions.push(condition); - }); - } - - if (params.filterType) { where['$' + params.filterType] = conditions; } - return where; - } - function getIncludes() { var includes = []; _.values(model.associations).forEach(function (association) { @@ -202,7 +182,7 @@ function LineStatGetter(model, params, opts) { return model.unscoped().findAll({ attributes: [getGroupByDateInterval(), getAggregate()], include: getIncludes(), - where: getFilters(), + where: this.getFilters(), group: getGroupBy(), order: getOrder(), raw: true diff --git a/services/pie-stat-getter.js b/services/pie-stat-getter.js index ea0a7c4c..c17344d6 100644 --- a/services/pie-stat-getter.js +++ b/services/pie-stat-getter.js @@ -3,7 +3,7 @@ var _ = require('lodash'); var P = require('bluebird'); var moment = require('moment'); -var OperatorValueParser = require('./operator-value-parser'); +var BaseStatGetter = require('./base-stat-getter'); var Database = require('../utils/database'); var Interface = require('forest-express'); @@ -12,6 +12,8 @@ var ALIAS_GROUP_BY = 'forest_alias_groupby'; var ALIAS_AGGREGATE = 'forest_alias_aggregate'; function PieStatGetter(model, params, opts) { + BaseStatGetter.call(this, model, params); + var schema = Interface.Schemas.schemas[model.name]; var associationSplit,associationCollection, associationField, associationSchema, field; @@ -48,31 +50,6 @@ function PieStatGetter(model, params, opts) { return schema.name + '.' + fieldName; } - function getFilters() { - var where = {}; - var conditions = []; - - if (params.filters) { - params.filters.forEach(function (filter) { - var field = filter.field; - if (field.indexOf(':') !== -1) { - var fieldSplited = field.split(':'); - var associationTableName = Interface.Schemas.schemas[fieldSplited[0]] - .name; - field = '$' + associationTableName + '.' + fieldSplited[1] + '$'; - } - - var condition = {}; - condition[field] = new OperatorValueParser().perform(model, - filter.field, filter.value, params.timezone); - conditions.push(condition); - }); - } - - if (params.filterType) { where['$' + params.filterType] = conditions; } - return where; - } - function getIncludes() { var includes = []; _.values(model.associations).forEach(function (association) { @@ -129,7 +106,7 @@ function PieStatGetter(model, params, opts) { ] ], include: getIncludes(), - where: getFilters(), + where: this.getFilters(), group: getGroupBy(), order: [[opts.sequelize.literal(ALIAS_AGGREGATE), 'DESC']], raw: true diff --git a/services/resource-finder.js b/services/resource-finder.js index 82981572..b1d336f3 100644 --- a/services/resource-finder.js +++ b/services/resource-finder.js @@ -18,7 +18,11 @@ function ResourceFinder(model, params, withIncludes) { }); } }); - return includes; + + // NOTICE: Avoid to inject an empty "include" array inside conditions + // otherwise Sequelize 4.8.x won't set the WHERE clause in the SQL + // query. + return includes.length === 0 ? null : includes; } this.perform = function () { diff --git a/services/value-stat-getter.js b/services/value-stat-getter.js index 8eee02ca..4893a69d 100644 --- a/services/value-stat-getter.js +++ b/services/value-stat-getter.js @@ -1,11 +1,13 @@ 'use strict'; var _ = require('lodash'); -var OperatorValueParser = require('./operator-value-parser'); +var BaseStatGetter = require('./base-stat-getter'); var OperatorDateIntervalParser = require('./operator-date-interval-parser'); var Interface = require('forest-express'); // jshint sub: true function ValueStatGetter(model, params) { + BaseStatGetter.call(this, model, params); + var schema = Interface.Schemas.schemas[model.name]; function getAggregate() { @@ -20,28 +22,6 @@ function ValueStatGetter(model, params) { return schema.name + '.' + fieldName; } - function getFilters() { - var where = {}; - var conditions = []; - - if (params.filters) { - params.filters.forEach(function (filter) { - var field = filter.field; - if (field.indexOf(':') !== -1) { - field = '$' + field.replace(':', '.') + '$'; - } - - var condition = {}; - condition[field] = new OperatorValueParser().perform(model, - filter.field, filter.value, params.timezone); - conditions.push(condition); - }); - } - - if (params.filterType) { where['$' + params.filterType] = conditions; } - return where; - } - function getIncludes() { var includes = []; _.values(model.associations).forEach(function (association) { @@ -74,7 +54,7 @@ function ValueStatGetter(model, params) { var countCurrent; var aggregateField = getAggregateField(); var aggregate = getAggregate(); - var filters = getFilters(); + var filters = this.getFilters(); var filterDateIntervalForPrevious = getIntervalDateFilterForPrevious(); return model