@@ -165,6 +165,10 @@ const transformDotField = (fieldName) => {
165165 return name ;
166166}
167167
168+ const transformAggregateField = ( fieldName ) => {
169+ return fieldName . substr ( 1 ) ;
170+ }
171+
168172const validateKeys = ( object ) => {
169173 if ( typeof object == 'object' ) {
170174 for ( const key in object ) {
@@ -1366,6 +1370,140 @@ export class PostgresStorageAdapter {
13661370 } ) ;
13671371 }
13681372
1373+ distinct ( className , schema , query , fieldName ) {
1374+ debug ( 'distinct' , className , query ) ;
1375+ let field = fieldName ;
1376+ let column = fieldName ;
1377+ if ( fieldName . indexOf ( '.' ) >= 0 ) {
1378+ field = transformDotFieldToComponents ( fieldName ) . join ( '->' ) ;
1379+ column = fieldName . split ( '.' ) [ 0 ] ;
1380+ }
1381+ const isArrayField = schema . fields
1382+ && schema . fields [ fieldName ]
1383+ && schema . fields [ fieldName ] . type === 'Array' ;
1384+ const values = [ field , column , className ] ;
1385+ const where = buildWhereClause ( { schema, query, index : 4 } ) ;
1386+ values . push ( ...where . values ) ;
1387+
1388+ const wherePattern = where . pattern . length > 0 ? `WHERE ${ where . pattern } ` : '' ;
1389+ let qs = `SELECT DISTINCT ON ($1:raw) $2:raw FROM $3:name ${ wherePattern } ` ;
1390+ if ( isArrayField ) {
1391+ qs = `SELECT distinct jsonb_array_elements($1:raw) as $2:raw FROM $3:name ${ wherePattern } ` ;
1392+ }
1393+ debug ( qs , values ) ;
1394+ return this . _client . any ( qs , values )
1395+ . catch ( ( ) => [ ] )
1396+ . then ( ( results ) => {
1397+ if ( fieldName . indexOf ( '.' ) === - 1 ) {
1398+ return results . map ( object => object [ field ] ) ;
1399+ }
1400+ const child = fieldName . split ( '.' ) [ 1 ] ;
1401+ return results . map ( object => object [ column ] [ child ] ) ;
1402+ } ) ;
1403+ }
1404+
1405+ aggregate ( className , pipeline ) {
1406+ debug ( 'aggregate' , className , pipeline ) ;
1407+ const values = [ className ] ;
1408+ let columns = [ ] ;
1409+ let countField = null ;
1410+ let wherePattern = '' ;
1411+ let limitPattern = '' ;
1412+ let skipPattern = '' ;
1413+ let sortPattern = '' ;
1414+ let groupPattern = '' ;
1415+ for ( let i = 0 ; i < pipeline . length ; i += 1 ) {
1416+ const stage = pipeline [ i ] ;
1417+ if ( stage . $group ) {
1418+ for ( const field in stage . $group ) {
1419+ const value = stage . $group [ field ] ;
1420+ if ( value === null || value === undefined ) {
1421+ continue ;
1422+ }
1423+ if ( field === '_id' ) {
1424+ columns . push ( `${ transformAggregateField ( value ) } AS "objectId"` ) ;
1425+ groupPattern = `GROUP BY ${ transformAggregateField ( value ) } ` ;
1426+ continue ;
1427+ }
1428+ if ( value . $sum ) {
1429+ if ( typeof value . $sum === 'string' ) {
1430+ columns . push ( `SUM(${ transformAggregateField ( value . $sum ) } ) AS "${ field } "` ) ;
1431+ } else {
1432+ countField = field ;
1433+ columns . push ( `COUNT(*) AS "${ field } "` ) ;
1434+ }
1435+ }
1436+ if ( value . $max ) {
1437+ columns . push ( `MAX(${ transformAggregateField ( value . $max ) } ) AS "${ field } "` ) ;
1438+ }
1439+ if ( value . $min ) {
1440+ columns . push ( `MIN(${ transformAggregateField ( value . $min ) } ) AS "${ field } "` ) ;
1441+ }
1442+ if ( value . $avg ) {
1443+ columns . push ( `AVG(${ transformAggregateField ( value . $avg ) } ) AS "${ field } "` ) ;
1444+ }
1445+ }
1446+ columns . join ( ',' ) ;
1447+ } else {
1448+ columns . push ( '*' ) ;
1449+ }
1450+ if ( stage . $project ) {
1451+ if ( columns . includes ( '*' ) ) {
1452+ columns = [ ] ;
1453+ }
1454+ for ( const field in stage . $project ) {
1455+ const value = stage . $project [ field ] ;
1456+ if ( ( value === 1 || value === true ) ) {
1457+ columns . push ( field ) ;
1458+ }
1459+ }
1460+ }
1461+ if ( stage . $match ) {
1462+ const patterns = [ ] ;
1463+ for ( const field in stage . $match ) {
1464+ const value = stage . $match [ field ] ;
1465+ Object . keys ( ParseToPosgresComparator ) . forEach ( cmp => {
1466+ if ( value [ cmp ] ) {
1467+ const pgComparator = ParseToPosgresComparator [ cmp ] ;
1468+ patterns . push ( `${ field } ${ pgComparator } ${ value [ cmp ] } ` ) ;
1469+ }
1470+ } ) ;
1471+ }
1472+ wherePattern = patterns . length > 0 ? `WHERE ${ patterns . join ( ' ' ) } ` : '' ;
1473+ }
1474+ if ( stage . $limit ) {
1475+ limitPattern = `LIMIT ${ stage . $limit } ` ;
1476+ }
1477+ if ( stage . $skip ) {
1478+ skipPattern = `OFFSET ${ stage . $skip } ` ;
1479+ }
1480+ if ( stage . $sort ) {
1481+ const sort = stage . $sort ;
1482+ const sorting = Object . keys ( sort ) . map ( ( key ) => {
1483+ if ( sort [ key ] === 1 ) {
1484+ return `"${ key } " ASC` ;
1485+ }
1486+ return `"${ key } " DESC` ;
1487+ } ) . join ( ',' ) ;
1488+ sortPattern = sort !== undefined && Object . keys ( sort ) . length > 0 ? `ORDER BY ${ sorting } ` : '' ;
1489+ }
1490+ }
1491+
1492+ const qs = `SELECT ${ columns } FROM $1:name ${ wherePattern } ${ sortPattern } ${ limitPattern } ${ skipPattern } ${ groupPattern } ` ;
1493+ debug ( qs , values ) ;
1494+ return this . _client . any ( qs , values ) . then ( results => {
1495+ if ( countField ) {
1496+ results [ 0 ] [ countField ] = parseInt ( results [ 0 ] [ countField ] , 10 ) ;
1497+ }
1498+ results . forEach ( result => {
1499+ if ( ! result . hasOwnProperty ( 'objectId' ) ) {
1500+ result . objectId = null ;
1501+ }
1502+ } ) ;
1503+ return results ;
1504+ } ) ;
1505+ }
1506+
13691507 performInitialization ( { VolatileClassesSchemas } ) {
13701508 debug ( 'performInitialization' ) ;
13711509 const promises = VolatileClassesSchemas . map ( ( schema ) => {
0 commit comments