2
2
/* eslint-disable no-param-reassign, no-use-before-define */
3
3
4
4
import type {
5
- ExtendedResolveParams ,
5
+ ResolveParams ,
6
+ ConnectionResolveParams ,
6
7
composeWithConnectionOpts ,
7
8
connectionSortOpts ,
9
+ CursorDataType ,
10
+ GraphQLConnectionType ,
8
11
} from '../definition' ;
9
12
import { Resolver , TypeComposer } from 'graphql-compose' ;
10
13
import { GraphQLInt } from 'graphql' ;
@@ -25,15 +28,21 @@ export function prepareConnectionResolver(
25
28
+ 'This function returns ID from provided object.' ) ;
26
29
}
27
30
28
- const countResolver = typeComposer . getResolver ( 'count' ) ;
31
+ const countResolver = typeComposer . getResolver ( opts . countResolverName ) ;
29
32
if ( ! countResolver ) {
30
- throw new Error ( `TypeComposer(${ typeComposer . getTypeName ( ) } ) should have 'count' resolver` ) ;
33
+ throw new Error ( `TypeComposer(${ typeComposer . getTypeName ( ) } ) provided to composeWithConnection `
34
+ + `should have resolver with name '${ opts . countResolverName } ' `
35
+ + 'due opts.countResolverName.' ) ;
31
36
}
37
+ const countResolve = countResolver . composeResolve ( ) ;
32
38
33
- const findManyResolver = typeComposer . getResolver ( 'findMany' ) ;
39
+ const findManyResolver = typeComposer . getResolver ( opts . findResolverName ) ;
34
40
if ( ! findManyResolver ) {
35
- throw new Error ( `TypeComposer(${ typeComposer . getTypeName ( ) } ) should have 'findMany' resolver` ) ;
41
+ throw new Error ( `TypeComposer(${ typeComposer . getTypeName ( ) } ) provided to composeWithConnection `
42
+ + `should have resolver with name '${ opts . findResolverName } ' `
43
+ + 'due opts.countResolverName.' ) ;
36
44
}
45
+ const findManyResolve = findManyResolver . composeResolve ( ) ;
37
46
38
47
const additionalArgs = { } ;
39
48
if ( findManyResolver . hasArg ( 'filter' ) ) {
@@ -70,16 +79,17 @@ export function prepareConnectionResolver(
70
79
description : 'Sort argument for data ordering' ,
71
80
} ,
72
81
} ,
73
- resolve : ( resolveParams : ExtendedResolveParams ) => {
82
+ resolve : ( resolveParams : ConnectionResolveParams ) => {
74
83
const { projection = { } , args = { } } = resolveParams ;
75
- const findManyParams = Object . assign ( { } , resolveParams , {
76
- args : { } ,
77
- projection : { } ,
78
- } ) ;
79
- const connSortOpts : connectionSortOpts = resolveParams . args . sort ;
84
+ const findManyParams : ResolveParams = Object . assign (
85
+ { } ,
86
+ resolveParams ,
87
+ { args : { } } // clear this params in copy
88
+ ) ;
89
+ const sortOptions : connectionSortOpts = args . sort ;
80
90
81
- const first = args . first ;
82
- const last = args . last ;
91
+ const first = parseInt ( args . first , 10 ) ;
92
+ const last = parseInt ( args . last , 10 ) ;
83
93
84
94
const limit = last || first ;
85
95
const skip = ( first - last ) || 0 ;
@@ -89,30 +99,40 @@ export function prepareConnectionResolver(
89
99
findManyParams . args . skip = skip ;
90
100
}
91
101
92
- let filter = findManyParams . args . filter ;
102
+ let filter = findManyParams . args . filter || { } ;
93
103
const beginCursorData = cursorToData ( args . after ) ;
94
104
if ( beginCursorData ) {
95
- filter = connSortOpts . cursorToFilter ( beginCursorData , filter ) ;
105
+ filter = sortOptions . cursorToFilter ( beginCursorData , filter ) ;
96
106
}
97
107
const endCursorData = cursorToData ( args . before ) ;
98
108
if ( endCursorData ) {
99
- filter = connSortOpts . cursorToFilter ( endCursorData , filter ) ;
109
+ filter = sortOptions . cursorToFilter ( endCursorData , filter ) ;
100
110
}
101
111
findManyParams . args . filter = filter ;
102
-
103
112
findManyParams . args . skip = skip ;
104
- // findManyParams.args.sort // TODO
105
- // findManyParams.projection // TODO
113
+
114
+ findManyParams . args . sort = sortOptions . sortValue ;
115
+ findManyParams . projection = projection ;
116
+ sortOptions . uniqueFields . forEach ( fieldName => {
117
+ findManyParams . projection [ fieldName ] = true ;
118
+ } ) ;
106
119
107
120
let countPromise ;
108
121
if ( projection . count ) {
109
- countPromise = countResolver ( resolveParams ) ;
122
+ countPromise = countResolve ( resolveParams ) ;
110
123
}
111
- const findManyPromise = findManyResolver ( findManyParams ) ;
112
124
const hasPreviousPage = skip > 0 ;
113
125
let hasNextPage = false ; // will be requested +1 document, to check next page presence
114
126
115
- return findManyPromise
127
+ const filterDataForCursor = ( record ) => {
128
+ const result = { } ;
129
+ sortOptions . uniqueFields . forEach ( fieldName => {
130
+ result [ fieldName ] = record [ fieldName ] ;
131
+ } ) ;
132
+ return result ;
133
+ } ;
134
+
135
+ return findManyResolve ( findManyParams )
116
136
. then ( recordList => {
117
137
const edges = [ ] ;
118
138
// if returned more than `limit` records, strip array and mark that exists next page
@@ -122,9 +142,8 @@ export function prepareConnectionResolver(
122
142
}
123
143
// transform record to object { cursor, node }
124
144
recordList . forEach ( record => {
125
- const id = typeComposer . getRecordId ( record ) ;
126
145
edges . push ( {
127
- cursor : idToCursor ( id ) ,
146
+ cursor : dataToCursor ( filterDataForCursor ( record ) ) ,
128
147
node : record ,
129
148
} ) ;
130
149
} ) ;
@@ -155,41 +174,30 @@ export function prepareConnectionResolver(
155
174
} ) ;
156
175
}
157
176
158
- export function emptyConnection ( ) {
177
+ export function emptyConnection ( ) : GraphQLConnectionType {
159
178
return {
160
179
count : 0 ,
161
180
edges : [ ] ,
162
181
pageInfo : {
163
- startCursor : null ,
164
- endCursor : null ,
182
+ startCursor : '' ,
183
+ endCursor : '' ,
165
184
hasPreviousPage : false ,
166
185
hasNextPage : false ,
167
186
} ,
168
187
} ;
169
188
}
170
189
171
- export function idToCursor ( id : string ) {
172
- return id ;
173
- }
174
-
175
- export function cursorToId ( cursor : string ) {
176
- return cursor ;
177
- }
178
-
179
-
180
-
181
- var PREFIX = 'arrayconnection:' ;
182
-
183
- /**
184
- * Creates the cursor string from an offset.
185
- */
186
- export function offsetToCursor ( offset : number ) : ConnectionCursor {
187
- return base64 ( PREFIX + offset ) ;
190
+ export function cursorToData ( id ?: ?string ) : ?CursorDataType {
191
+ if ( id ) {
192
+ try {
193
+ return JSON . parse ( id ) || null ;
194
+ } catch ( err ) {
195
+ return null ;
196
+ }
197
+ }
198
+ return null ;
188
199
}
189
200
190
- /**
191
- * Rederives the offset from the cursor string.
192
- */
193
- export function cursorToOffset ( cursor : ConnectionCursor ) : number {
194
- return parseInt ( unbase64 ( cursor ) . substring ( PREFIX . length ) , 10 ) ;
201
+ export function dataToCursor ( cursorData : CursorDataType ) : string {
202
+ return JSON . stringify ( cursorData ) ;
195
203
}
0 commit comments