1
1
/* @flow */
2
2
/* eslint-disable no-param-reassign */
3
3
4
- import { Resolver , TypeComposer , isObject } from 'graphql-compose' ;
5
- import type { ResolveParams , ProjectionType } from 'graphql-compose/lib/definition' ;
4
+ import {
5
+ Resolver ,
6
+ TypeComposer ,
7
+ InputTypeComposer ,
8
+ isObject ,
9
+ } from 'graphql-compose' ;
10
+ import type {
11
+ ResolveParams ,
12
+ ProjectionType ,
13
+ } from 'graphql-compose/lib/definition' ;
6
14
import type { FieldsMapByElasticType } from '../mappingConverter' ;
7
15
import ElasticApiParser from '../ElasticApiParser' ;
8
16
import type { ElasticApiVersion } from '../ElasticApiParser' ;
@@ -20,7 +28,7 @@ export type ElasticSearchResolverOpts = {
20
28
21
29
export default function createSearchResolver (
22
30
fieldMap : FieldsMapByElasticType ,
23
- sourceTC ? : TypeComposer ,
31
+ sourceTC : TypeComposer ,
24
32
elasticClient ?: mixed ,
25
33
opts ?: ElasticSearchResolverOpts = { }
26
34
) : Resolver < * , * > {
@@ -43,10 +51,6 @@ export default function createSearchResolver(
43
51
version : opts . elasticApiVersion || '5_0' ,
44
52
prefix,
45
53
} ) ;
46
- const searchFC = parser . generateFieldConfig ( 'search' , {
47
- index : 'cv' ,
48
- type : 'cv' ,
49
- } ) ;
50
54
51
55
const searchITC = getSearchBodyITC ( {
52
56
prefix,
@@ -55,6 +59,11 @@ export default function createSearchResolver(
55
59
56
60
searchITC . removeField ( [ 'size' , 'from' , '_source' , 'explain' , 'version' ] ) ;
57
61
62
+ const searchFC = parser . generateFieldConfig ( 'search' , {
63
+ index : 'cv' ,
64
+ type : 'cv' ,
65
+ } ) ;
66
+
58
67
const argsConfigMap = Object . assign ( { } , searchFC . args , {
59
68
body : {
60
69
type : searchITC . getType ( ) ,
@@ -68,31 +77,69 @@ export default function createSearchResolver(
68
77
delete argsConfigMap . _source ; // added automatically due projection
69
78
delete argsConfigMap . _sourceExclude ; // added automatically due projection
70
79
delete argsConfigMap . _sourceInclude ; // added automatically due projection
80
+ delete argsConfigMap . trackScores ; // added automatically due projection (is _scrore requested with sort)
71
81
72
82
delete argsConfigMap . size ;
73
83
delete argsConfigMap . from ;
84
+ // $FlowFixMe
74
85
argsConfigMap . limit = 'Int' ;
86
+ // $FlowFixMe
75
87
argsConfigMap . skip = 'Int' ;
76
88
77
- const type = getSearchOutputTC ( { prefix, fieldMap, sourceTC } ) ;
78
- // $FlowFixMe
79
- type . addFields ( {
80
- count : 'Int' ,
81
- max_score : 'Float' ,
89
+ const bodyITC = InputTypeComposer . create ( argsConfigMap . body . type ) ;
90
+ argsConfigMap . query = bodyITC . getField ( 'query' ) ;
91
+ argsConfigMap . aggs = bodyITC . getField ( 'aggs' ) ;
92
+ argsConfigMap . highlight = bodyITC . getField ( 'highlight' ) ;
93
+
94
+ const topLevelArgs = [
95
+ 'limit' ,
96
+ 'skip' ,
97
+ 'q' ,
98
+ 'opts' ,
99
+ 'query' ,
100
+ 'aggs' ,
101
+ 'highlight' ,
102
+ ] ;
103
+ argsConfigMap . opts = InputTypeComposer . create ( {
104
+ name : `${ sourceTC . getTypeName ( ) } Opts` ,
105
+ fields : Object . assign ( { } , argsConfigMap ) ,
106
+ } ) . removeField ( topLevelArgs ) ;
107
+ Object . keys ( argsConfigMap ) . forEach ( argKey => {
108
+ if ( ! topLevelArgs . includes ( argKey ) ) {
109
+ delete argsConfigMap [ argKey ] ;
110
+ }
82
111
} ) ;
83
112
113
+ const type = getSearchOutputTC ( { prefix, fieldMap, sourceTC } ) ;
114
+ type
115
+ . addFields ( {
116
+ // $FlowFixMe
117
+ count : 'Int' ,
118
+ // $FlowFixMe
119
+ max_score : 'Float' ,
120
+ // $FlowFixMe
121
+ hits : [ type . get ( 'hits.hits' ) ] ,
122
+ } )
123
+ . reorderFields ( [
124
+ 'hits' ,
125
+ 'count' ,
126
+ 'aggregations' ,
127
+ 'max_score' ,
128
+ 'took' ,
129
+ 'timed_out' ,
130
+ '_shards' ,
131
+ ] ) ;
132
+
84
133
// $FlowFixMe
85
134
return new Resolver ( {
86
135
type,
87
136
name : 'search' ,
88
137
kind : 'query' ,
89
138
args : argsConfigMap ,
90
139
resolve : async ( rp : ResolveParams < * , * > ) => {
91
- const { args = { } , projection = { } } = rp ;
92
-
93
- if ( args . body ) {
94
- args . body = prepareBodyInResolve ( args . body , fieldMap ) ;
95
- }
140
+ let args : Object = rp . args || { } ;
141
+ const projection = rp . projection || { } ;
142
+ if ( ! args . body ) args . body = { } ;
96
143
97
144
if ( { } . hasOwnProperty . call ( args , 'limit' ) ) {
98
145
args . size = args . limit ;
@@ -105,47 +152,78 @@ export default function createSearchResolver(
105
152
}
106
153
107
154
const { hits = { } } = projection ;
108
- // $FlowFixMe
109
- const { hits : hitsHits } = hits ;
110
155
111
- if ( typeof hitsHits === 'object' ) {
156
+ if ( typeof hits === 'object' ) {
112
157
// Turn on explain if in projection requested this fields:
113
- if ( hitsHits . _shard || hitsHits . _node || hitsHits . _explanation ) {
114
- // $FlowFixMe
158
+ if ( hits . _shard || hits . _node || hits . _explanation ) {
115
159
args . body . explain = true ;
116
160
}
117
161
118
- if ( hitsHits . _version ) {
119
- // $FlowFixMe
162
+ if ( hits . _version ) {
120
163
args . body . version = true ;
121
164
}
122
165
123
- if ( ! hitsHits . _source ) {
124
- // $FlowFixMe
166
+ if ( ! hits . _source ) {
125
167
args . body . _source = false ;
126
168
} else {
127
169
// $FlowFixMe
128
- args . body . _source = toDottedList ( hitsHits . _source ) ;
170
+ args . body . _source = toDottedList ( hits . _source ) ;
129
171
}
172
+
173
+ if ( hits . _score ) {
174
+ args . body . track_scores = true ;
175
+ }
176
+ }
177
+
178
+ if ( args . query ) {
179
+ args . body . query = args . query ;
180
+ delete args . query ;
181
+ }
182
+
183
+ if ( args . aggs ) {
184
+ args . body . aggs = args . aggs ;
185
+ delete args . aggs ;
186
+ }
187
+
188
+ if ( args . opts ) {
189
+ args = {
190
+ ...args . opts ,
191
+ ...args ,
192
+ body : { ...args . opts . body , ...args . body } ,
193
+ } ;
194
+ delete args . opts ;
195
+ }
196
+
197
+ if ( args . body ) {
198
+ args . body = prepareBodyInResolve ( args . body , fieldMap ) ;
130
199
}
131
200
132
201
// $FlowFixMe
133
- const res = await searchFC . resolve ( rp . source , args , rp . context , rp . info ) ;
202
+ const res : any = await searchFC . resolve (
203
+ rp . source ,
204
+ args ,
205
+ rp . context ,
206
+ rp . info
207
+ ) ;
134
208
135
209
res . count = res . hits . total ;
136
210
res . max_score = res . hits . max_score ;
211
+ res . hits = res . hits . hits ;
137
212
138
213
return res ;
139
214
} ,
140
- } ) ;
215
+ } ) . reorderArgs ( [ 'q' , 'query' , 'aggs' , 'limit' , 'skip' ] ) ;
141
216
}
142
217
143
- export function toDottedList ( projection : ProjectionType , prev : string [ ] ) : string [ ] | boolean {
218
+ export function toDottedList (
219
+ projection : ProjectionType ,
220
+ prev ?: string [ ]
221
+ ) : string [ ] | boolean {
144
222
let result = [ ] ;
145
223
Object . keys ( projection ) . forEach ( k => {
146
224
if ( isObject ( projection [ k ] ) ) {
147
225
// $FlowFixMe
148
- const tmp = toDottedList ( projection [ k ] , prev ? [ ...prev , k ] : [ k ] ) ;
226
+ const tmp = toDottedList ( projection [ k ] , prev ? [ ...prev , k ] : [ k ] ) ;
149
227
if ( Array . isArray ( tmp ) ) {
150
228
result = result . concat ( tmp ) ;
151
229
return ;
0 commit comments