* 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)
| 1947 | * @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. |
| 1948 | */ |
| 1949 | static async aggregate(attribute, aggregateFunction, options) { |
| 1950 | options = Utils.cloneDeep(options); |
| 1951 | |
| 1952 | class="cm">// We need to preserve attributes here as the `injectScope` call would inject non aggregate columns. |
| 1953 | const prevAttributes = options.attributes; |
| 1954 | this._injectScope(options); |
| 1955 | options.attributes = prevAttributes; |
| 1956 | this._conformIncludes(options, this); |
| 1957 | |
| 1958 | if (options.include) { |
| 1959 | this._expandIncludeAll(options); |
| 1960 | this._validateIncludedElements(options); |
| 1961 | } |
| 1962 | |
| 1963 | const attrOptions = this.rawAttributes[attribute]; |
| 1964 | const field = attrOptions && attrOptions.field || attribute; |
| 1965 | let aggregateColumn = this.sequelize.col(field); |
| 1966 | |
| 1967 | if (options.distinct) { |
| 1968 | aggregateColumn = this.sequelize.fn(class="st">'DISTINCT', aggregateColumn); |
| 1969 | } |
| 1970 | |
| 1971 | let { group } = options; |
| 1972 | if (Array.isArray(group) && Array.isArray(group[0])) { |
| 1973 | noDoubleNestedGroup(); |
| 1974 | group = _.flatten(group); |
| 1975 | } |
| 1976 | options.attributes = _.unionBy( |
| 1977 | options.attributes, |
| 1978 | group, |
| 1979 | [[this.sequelize.fn(aggregateFunction, aggregateColumn), aggregateFunction]], |
| 1980 | a => Array.isArray(a) ? a[1] : a |
| 1981 | ); |
| 1982 | |
| 1983 | if (!options.dataType) { |
| 1984 | if (attrOptions) { |
| 1985 | options.dataType = attrOptions.type; |
| 1986 | } else { |
| 1987 | class="cm">// Use FLOAT as fallback |
| 1988 | options.dataType = new DataTypes.FLOAT(); |
| 1989 | } |
| 1990 | } else { |
| 1991 | options.dataType = this.sequelize.normalizeDataType(options.dataType); |
| 1992 | } |
| 1993 | |
| 1994 | Utils.mapOptionFieldNames(options, this); |
| 1995 | options = this._paranoidClause(this, options); |
| 1996 | |
| 1997 | const value = await this.queryInterface.rawSelect(this.getTableName(options), options, aggregateFunction, this); |
| 1998 | return value; |
| 1999 | } |
| 2000 | |
| 2001 | /** |
| 2002 | * Count the number of records matching the provided where clause. |
no test coverage detected