1
1
var util = require ( './util.js' )
2
2
3
- function convertRecur ( fieldName , input ) {
3
+ // TODO (ensure multi-level inside array projections work)
4
+ function convertRecur ( fieldName , input , arrayFields , prefix , prefixStrip ) {
4
5
if ( typeof input === 'string' ) {
5
- return util . pathToText ( [ fieldName ] . concat ( input . split ( '.' ) ) , false )
6
+ return util . pathToText ( [ fieldName ] . concat ( input . replace ( new RegExp ( '^' + prefixStrip ) , '' ) . split ( '.' ) ) , false )
6
7
} else {
7
8
var entries = [ ]
8
9
for ( var key in input ) {
9
10
entries . push ( '\'' + key + '\'' )
10
- entries . push ( convertRecur ( fieldName , input [ key ] ) )
11
+ if ( ! arrayFields [ key ] ) {
12
+ entries . push ( convertRecur ( fieldName , input [ key ] , arrayFields [ key ] || { } , prefix + key + '.' , prefixStrip ) )
13
+ } else {
14
+ const obj = convertRecur ( 'value' , input [ key ] , arrayFields [ key ] || { } , prefix + key + '.' , prefix + key + '.' )
15
+ entries . push ( '(SELECT jsonb_agg(r) FROM (SELECT ' + obj + ' as r ' +
16
+ 'FROM jsonb_array_elements(data->\'arr\') as value) AS obj)' )
17
+ }
11
18
}
12
19
return 'jsonb_build_object(' + entries . join ( ', ' ) + ')'
13
20
}
14
21
}
15
22
16
- var convert = function ( fieldName , projection ) {
17
- // Empty projection returns full document
18
- if ( ! projection ) {
19
- return fieldName
20
- }
21
- //var output = '';
23
+ function convertToShellDoc ( projection , prefix = '' ) {
22
24
var shellDoc = { }
23
25
var removals = [ ]
24
26
Object . keys ( projection ) . forEach ( function ( field ) {
@@ -31,19 +33,35 @@ var convert = function (fieldName, projection) {
31
33
current [ key ] = current [ key ] || { }
32
34
current = current [ key ]
33
35
} else {
34
- current [ key ] = field
36
+ current [ key ] = prefix + field
35
37
}
36
38
}
37
39
} else if ( projection [ field ] === 0 ) {
38
40
if ( field !== '_id' ) {
39
41
removals . push ( '#- ' + util . toPostgresPath ( path ) )
40
42
}
43
+ } else if ( typeof projection [ field ] === 'object' && ! Array . isArray ( projection [ field ] ) ) {
44
+ const { shellDoc : subShellDoc , removals : subRemovals } =
45
+ convertToShellDoc ( projection [ field ] , prefix + field + '.' )
46
+ shellDoc [ field ] = subShellDoc
47
+ removals = removals . concat ( subRemovals )
41
48
} else {
42
49
console . error ( `unexpected projection value ${ projection [ field ] } for ${ field } ` )
43
50
}
44
- //output += util.convertDotNotation(fieldName, field)
45
- //output +=
46
51
} )
52
+ return { shellDoc, removals }
53
+ }
54
+
55
+ var convert = function ( fieldName , projection , arrayFields ) {
56
+ // Empty projection returns full document
57
+ if ( ! projection ) {
58
+ return fieldName
59
+ }
60
+ //var output = '';
61
+ let { shellDoc, removals } = convertToShellDoc ( projection )
62
+
63
+ //output += util.convertDotNotation(fieldName, field)
64
+ //output +=
47
65
if ( Object . keys ( shellDoc ) . length > 0 && typeof projection [ '_id' ] === 'undefined' ) {
48
66
shellDoc [ '_id' ] = '_id'
49
67
}
@@ -54,7 +72,7 @@ var convert = function (fieldName, projection) {
54
72
throw new Error ( 'Projection cannot have a mix of inclusion and exclusion.' )
55
73
}
56
74
57
- var out = Object . keys ( shellDoc ) . length > 0 ? convertRecur ( fieldName , shellDoc ) : fieldName
75
+ var out = Object . keys ( shellDoc ) . length > 0 ? convertRecur ( fieldName , shellDoc , arrayFields || { } , '' , '' ) : fieldName
58
76
if ( removals . length ) {
59
77
out += ' ' + removals . join ( ' ' )
60
78
}
0 commit comments