1
1
import _ from 'lodash' ;
2
2
import { Schemas } from 'forest-express' ;
3
3
import Orm from '../utils/orm' ;
4
+ import { InvalidParameterError } from './errors' ;
4
5
6
+ function getAggregateField ( {
7
+ aggregateField, schemaRelationship, modelRelationship,
8
+ } ) {
9
+ // NOTICE: As MySQL cannot support COUNT(table_name.*) syntax, fieldName cannot be '*'.
10
+ const fieldName = aggregateField
11
+ || schemaRelationship . primaryKeys [ 0 ]
12
+ || schemaRelationship . fields [ 0 ] . field ;
13
+ return `${ modelRelationship . name } .${ Orm . getColumnName ( schemaRelationship , fieldName ) } ` ;
14
+ }
15
+
16
+ /**
17
+ * @param {import('sequelize').Model } model
18
+ * @param {import('sequelize').Model } modelRelationship
19
+ * @param {{
20
+ * label_field: string;
21
+ * aggregate: string;
22
+ * aggregate_field: string;
23
+ * }} params
24
+ * @param {* } options
25
+ */
5
26
function LeaderboardStatGetter ( model , modelRelationship , params , options ) {
6
27
const labelField = params . label_field ;
7
28
const aggregate = params . aggregate . toUpperCase ( ) ;
8
- const aggregateField = params . aggregate_field ;
9
29
const { limit } = params ;
10
30
const schema = Schemas . schemas [ model . name ] ;
11
31
const schemaRelationship = Schemas . schemas [ modelRelationship . name ] ;
@@ -15,50 +35,52 @@ function LeaderboardStatGetter(model, modelRelationship, params, options) {
15
35
( association ) => association . target . name === model . name ,
16
36
) ;
17
37
18
- if ( associationFound && associationFound . as ) {
19
- associationAs = associationFound . as ;
20
- }
21
-
22
- const groupBy = `" ${ associationAs } "." ${ labelField } "` ;
38
+ const aggregateField = getAggregateField ( {
39
+ aggregateField : params . aggregate_field ,
40
+ schemaRelationship ,
41
+ modelRelationship ,
42
+ } ) ;
23
43
24
- function getAggregateField ( ) {
25
- // NOTICE: As MySQL cannot support COUNT(table_name.*) syntax, fieldName cannot be '*'.
26
- const fieldName = aggregateField
27
- || schemaRelationship . primaryKeys [ 0 ]
28
- || schemaRelationship . fields [ 0 ] . field ;
29
- return `"${ modelRelationship . tableName } "."${ Orm . getColumnName ( schema , fieldName ) } "` ;
44
+ if ( ! associationFound ) {
45
+ throw new InvalidParameterError ( `Association ${ model . name } not found` ) ;
30
46
}
31
47
32
- let joinQuery ;
33
- if ( associationFound . associationType === 'BelongsToMany' ) {
34
- const joinTableName = associationFound . through . model . tableName ;
35
- joinQuery = `INNER JOIN "${ joinTableName } "
36
- ON "${ modelRelationship . tableName } "."${ associationFound . sourceKeyField } " = "${ joinTableName } "."${ associationFound . foreignKey } "
37
- INNER JOIN "${ model . tableName } " AS "${ associationAs } "
38
- ON "${ associationAs } "."${ associationFound . targetKeyField } " = "${ joinTableName } "."${ associationFound . otherKey } "
39
- ` ;
40
- } else {
41
- const foreignKeyField = associationFound . source
42
- . rawAttributes [ associationFound . foreignKey ] . field ;
43
- joinQuery = `INNER JOIN "${ model . tableName } " AS "${ associationAs } "
44
- ON "${ associationAs } "."${ associationFound . targetKeyField } " = "${ modelRelationship . tableName } "."${ foreignKeyField } "
45
- ` ;
48
+ if ( associationFound . as ) {
49
+ associationAs = associationFound . as ;
46
50
}
47
51
48
- const query = `
49
- SELECT ${ aggregate } (${ getAggregateField ( ) } ) as "value", ${ groupBy } as "key"
50
- FROM "${ modelRelationship . tableName } "
51
- ${ joinQuery }
52
- GROUP BY ${ groupBy }
53
- ORDER BY "value" DESC
54
- LIMIT ${ limit }
55
- ` ;
52
+ const labelColumn = Orm . getColumnName ( schema , labelField ) ;
53
+ const groupBy = `${ associationAs } .${ labelColumn } ` ;
56
54
55
+ this . perform = async ( ) => {
56
+ const records = await modelRelationship
57
+ . unscoped ( )
58
+ . findAll ( {
59
+ attributes : [
60
+ [ options . sequelize . col ( groupBy ) , 'key' ] ,
61
+ [ options . sequelize . fn ( aggregate , options . sequelize . col ( aggregateField ) ) , 'value' ] ,
62
+ ] ,
63
+ includeIgnoreAttributes : false ,
64
+ include : [ {
65
+ model,
66
+ attributes : [ labelField ] ,
67
+ as : associationAs ,
68
+ required : true ,
69
+ } ] ,
70
+ subQuery : false ,
71
+ group : groupBy ,
72
+ order : [ [ options . sequelize . literal ( 'value' ) , 'DESC' ] ] ,
73
+ limit,
74
+ raw : true ,
75
+ } ) ;
57
76
58
- this . perform = ( ) => options . connections [ 0 ] . query ( query , {
59
- type : model . sequelize . QueryTypes . SELECT ,
60
- } )
61
- . then ( ( records ) => ( { value : records } ) ) ;
77
+ return {
78
+ value : records . map ( ( data ) => ( {
79
+ key : data . key ,
80
+ value : Number ( data . value ) ,
81
+ } ) ) ,
82
+ } ;
83
+ } ;
62
84
}
63
85
64
86
module . exports = LeaderboardStatGetter ;
0 commit comments