* Run an aggregation method on the specified field * * @param {string} attribute The attribute to aggregate over. Can be a field name or * * @param {string} aggregateFunction The function to use for aggregation, e.g. sum, max etc. * @param {object} [options] Qu
(attribute, aggregateFunction, options)
| 2017 | * @returns {Promise<DataTypes|object>} Returns the aggregate result cast to `options.dataType`, unless `options.plain` is false, in which case the complete data result is returned. |
| 2018 | */ |
| 2019 | static async aggregate(attribute, aggregateFunction, options) { |
| 2020 | options = Utils.cloneDeep(options); |
| 2021 | |
| 2022 | // We need to preserve attributes here as the `injectScope` call would inject non aggregate columns. |
| 2023 | const prevAttributes = options.attributes; |
| 2024 | this._injectScope(options); |
| 2025 | options.attributes = prevAttributes; |
| 2026 | this._conformIncludes(options, this); |
| 2027 | |
| 2028 | if (options.include) { |
| 2029 | this._expandIncludeAll(options); |
| 2030 | this._validateIncludedElements(options); |
| 2031 | } |
| 2032 | |
| 2033 | const attrOptions = this.rawAttributes[attribute]; |
| 2034 | const field = attrOptions && attrOptions.field || attribute; |
| 2035 | let aggregateColumn = this.sequelize.col(field); |
| 2036 | |
| 2037 | if (options.distinct) { |
| 2038 | aggregateColumn = this.sequelize.fn('DISTINCT', aggregateColumn); |
| 2039 | } |
| 2040 | |
| 2041 | let { group } = options; |
| 2042 | if (Array.isArray(group) && Array.isArray(group[0])) { |
| 2043 | noDoubleNestedGroup(); |
| 2044 | group = _.flatten(group); |
| 2045 | } |
| 2046 | options.attributes = _.unionBy( |
| 2047 | options.attributes, |
| 2048 | group, |
| 2049 | [[this.sequelize.fn(aggregateFunction, aggregateColumn), aggregateFunction]], |
| 2050 | a => Array.isArray(a) ? a[1] : a |
| 2051 | ); |
| 2052 | |
| 2053 | if (!options.dataType) { |
| 2054 | if (attrOptions) { |
| 2055 | options.dataType = attrOptions.type; |
| 2056 | } else { |
| 2057 | // Use FLOAT as fallback |
| 2058 | options.dataType = new DataTypes.FLOAT(); |
| 2059 | } |
| 2060 | } else { |
| 2061 | options.dataType = this.sequelize.normalizeDataType(options.dataType); |
| 2062 | } |
| 2063 | |
| 2064 | Utils.mapOptionFieldNames(options, this); |
| 2065 | options = this._paranoidClause(this, options); |
| 2066 | |
| 2067 | const value = await this.queryInterface.rawSelect(this.getTableName(options), options, aggregateFunction, this); |
| 2068 | return value; |
| 2069 | } |
| 2070 | |
| 2071 | /** |
| 2072 | * Count the number of records matching the provided where clause. |
no test coverage detected