diff --git a/aqueduct/lib/src/db/postgresql/postgresql_query_reduce.dart b/aqueduct/lib/src/db/postgresql/postgresql_query_reduce.dart index e250235dd..222bb8ca8 100644 --- a/aqueduct/lib/src/db/postgresql/postgresql_query_reduce.dart +++ b/aqueduct/lib/src/db/postgresql/postgresql_query_reduce.dart @@ -1,52 +1,80 @@ import 'dart:async'; import '../managed/object.dart'; +import '../managed/property_description.dart'; import '../query/query.dart'; +import 'builders/column.dart'; import 'postgresql_persistent_store.dart'; import 'postgresql_query.dart'; import 'query_builder.dart'; +// ignore_for_file: constant_identifier_names +enum _Reducer { + AVG, + COUNT, + MAX, + MIN, + SUM, +} + class PostgresQueryReduce extends QueryReduceOperation { - PostgresQueryReduce(this.query); + PostgresQueryReduce(this.query) : builder = PostgresQueryBuilder(query); final PostgresQuery query; + final PostgresQueryBuilder builder; @override Future average(num selector(T object)) { - return _execute("avg(${_columnName(selector)})::float"); + return _execute( + _Reducer.AVG, query.entity.identifyAttribute(selector)); } @override Future count() { - return _execute("count(*)"); + return _execute(_Reducer.COUNT); } @override Future maximum(U selector(T object)) { - return _execute("max(${_columnName(selector)})"); + return _execute(_Reducer.MAX, query.entity.identifyAttribute(selector)); } @override Future minimum(U selector(T object)) { - return _execute("min(${_columnName(selector)})"); + return _execute(_Reducer.MIN, query.entity.identifyAttribute(selector)); } @override Future sum(U selector(T object)) { - return _execute("sum(${_columnName(selector)})"); + return _execute(_Reducer.SUM, query.entity.identifyAttribute(selector)); } - String _columnName(dynamic selector(T object)) { - return query.entity.identifyAttribute(selector).name; + String _columnName(ManagedAttributeDescription property) { + if (property == null) { + // This should happen only in count + return "*"; + } + final columnBuilder = ColumnBuilder(builder, property); + return columnBuilder.sqlColumnName(withTableNamespace: true); } - Future _execute(String function) async { - final builder = PostgresQueryBuilder(query); + String _function(_Reducer reducer, ManagedAttributeDescription property) { + return "${reducer.toString().split('.').last}" // The aggregation function + "(${_columnName(property)})" // The Column for the aggregation + "${reducer == _Reducer.AVG ? '::float' : ''}"; // Optional cast to float for AVG + } + + Future _execute(_Reducer reducer, + [ManagedAttributeDescription property]) async { final buffer = StringBuffer(); - buffer.write("SELECT $function "); + buffer.write("SELECT ${_function(reducer, property)} "); buffer.write("FROM ${builder.sqlTableName} "); + if (builder.containsJoins) { + buffer.write("${builder.sqlJoin} "); + } + if (builder.sqlWhereClause != null) { buffer.write("WHERE ${builder.sqlWhereClause} "); }