Skip to content

Commit 45605f3

Browse files
committed
wip(composeWithElastic): Started work under TypeComposer generator from mapping
1 parent 380c73a commit 45605f3

File tree

12 files changed

+272
-128
lines changed

12 files changed

+272
-128
lines changed

src/ElasticApiParser.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ export default class ElasticApiParser {
102102
const searchTyped = {
103103
type,
104104
description,
105+
// $FlowFixMe
105106
resolve: prepareSearchArgs(resolve),
106107
// $FlowFixMe
107108
args: Object.assign({}, args, {
@@ -284,9 +285,9 @@ export default class ElasticApiParser {
284285
// eg '@param {anything} params.operationThreading - ?'
285286
return GraphQLJSON;
286287
default:
287-
console.log(
288+
console.log( // eslint-disable-line
288289
`New type '${paramCfg.type}' in elastic params setting for field ${fieldName}.`
289-
); // eslint-disable-line
290+
);
290291
return GraphQLJSON;
291292
}
292293
}

src/ElasticDSL/SearchBody.js

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@ export function getSearchBodyITC(opts: mixed = {}): InputTypeComposer {
1111
const name = getTypeName('SearchBody', opts);
1212
const description = desc(
1313
`
14-
The search request can be executed with a search DSL, which includes
15-
the [Query DSL](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html),
16-
within its body.
14+
[Request Body Search](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-body.html),
1715
`
1816
);
1917

@@ -26,6 +24,23 @@ export function getSearchBodyITC(opts: mixed = {}): InputTypeComposer {
2624
query: () => getQueryITC(opts),
2725
aggs: () => [getAggBlockITC(opts)],
2826
size: 'Int',
27+
from: 'Int',
28+
sort: 'JSON',
29+
_source: 'JSON',
30+
script_fields: 'JSON',
31+
post_filter: () => getQueryITC(opts),
32+
highlight: 'JSON',
33+
search_after: 'JSON',
34+
35+
explain: 'Boolean',
36+
version: 'Boolean',
37+
indices_boost: 'JSON',
38+
min_score: 'Float',
39+
40+
search_type: 'String',
41+
rescore: 'JSON',
42+
docvalue_fields: '[String]',
43+
stored_fields: '[String]',
2944
},
3045
}));
3146
}
File renamed without changes.

src/__tests__/ElasticApiParser-test.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ describe('ElasticApiParser', () => {
359359
describe('reassembleNestedFields()', () => {
360360
it('should pass single fields', () => {
361361
expect(
362+
// $FlowFixMe
362363
parser.reassembleNestedFields({
363364
field1: { type: GraphQLString },
364365
field2: { type: GraphQLString },
@@ -370,6 +371,7 @@ describe('ElasticApiParser', () => {
370371
});
371372

372373
it('should combine nested field in GraphQLObjectType', () => {
374+
// $FlowFixMe
373375
const reFields = parser.reassembleNestedFields({
374376
'cat.prototype.field1': { type: GraphQLString },
375377
'cat.prototype.field2': { type: GraphQLString },

src/__tests__/PropertiesConverter-test.js renamed to src/__tests__/mappingConverter-test.js

Lines changed: 73 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@ import {
1313

1414
import {
1515
convertToSourceTC,
16-
propertyToGraphQLType,
16+
propertyToSourceGraphQLType,
1717
convertToAggregatableITC,
1818
inputPropertiesToGraphQLTypes,
1919
convertToSearchableITC,
2020
convertToAnalyzedITC,
21-
} from '../PropertiesConverter';
21+
getSubFields,
22+
} from '../mappingConverter';
2223

2324
const mapping = {
2425
properties: {
@@ -84,54 +85,69 @@ describe('PropertiesConverter', () => {
8485
});
8586

8687
it('should make singular and plural fields', () => {
87-
const tc = convertToSourceTC(mapping, 'TestMapping');
88-
const singular: any = tc.getField('name');
88+
const tc1 = convertToSourceTC(mapping, 'TestMapping');
89+
const singular: any = tc1.getField('name');
8990
expect(singular.type).toBe(GraphQLString);
9091

91-
const plural: any = tc.getField('nameA');
92+
const tc2 = convertToSourceTC(mapping, 'TestMapping', {
93+
pluralFields: ['name'],
94+
});
95+
const plural: any = tc2.getField('name');
9296
expect(plural.type).toBeInstanceOf(GraphQLList);
9397
expect(plural.type.ofType).toBe(GraphQLString);
9498
});
9599
});
96100

97-
describe('propertyToGraphQLType()', () => {
101+
describe('propertyToSourceGraphQLType()', () => {
98102
it('should throw error on wrong property config', () => {
99103
expect(() => {
100104
// $FlowFixMe
101-
propertyToGraphQLType();
105+
propertyToSourceGraphQLType();
102106
}).toThrowError('incorrect Elastic property config');
103107
expect(() => {
104-
propertyToGraphQLType({});
108+
propertyToSourceGraphQLType({});
105109
}).toThrowError('incorrect Elastic property config');
106110
});
107111

108112
it('should return GraphQLJSON as fallback for unknown Elastic type', () => {
109-
expect(propertyToGraphQLType({ type: 'strange' })).toEqual(GraphQLJSON);
113+
expect(propertyToSourceGraphQLType({ type: 'strange' })).toEqual(
114+
GraphQLJSON
115+
);
110116
});
111117

112118
it('should return GraphQLInt for int types', () => {
113-
expect(propertyToGraphQLType({ type: 'integer' })).toEqual(GraphQLInt);
114-
expect(propertyToGraphQLType({ type: 'long' })).toEqual(GraphQLInt);
119+
expect(propertyToSourceGraphQLType({ type: 'integer' })).toEqual(
120+
GraphQLInt
121+
);
122+
expect(propertyToSourceGraphQLType({ type: 'long' })).toEqual(GraphQLInt);
115123
});
116124

117125
it('should return GraphQLString for string types', () => {
118-
expect(propertyToGraphQLType({ type: 'text' })).toEqual(GraphQLString);
119-
expect(propertyToGraphQLType({ type: 'keyword' })).toEqual(GraphQLString);
126+
expect(propertyToSourceGraphQLType({ type: 'text' })).toEqual(
127+
GraphQLString
128+
);
129+
expect(propertyToSourceGraphQLType({ type: 'keyword' })).toEqual(
130+
GraphQLString
131+
);
120132
});
121133

122134
it('should return GraphQLFloat for float types', () => {
123-
expect(propertyToGraphQLType({ type: 'float' })).toEqual(GraphQLFloat);
124-
expect(propertyToGraphQLType({ type: 'double' })).toEqual(GraphQLFloat);
135+
expect(propertyToSourceGraphQLType({ type: 'float' })).toEqual(
136+
GraphQLFloat
137+
);
138+
expect(propertyToSourceGraphQLType({ type: 'double' })).toEqual(
139+
GraphQLFloat
140+
);
125141
});
126142

127143
it('should return GraphQLBoolean for float types', () => {
128-
expect(propertyToGraphQLType({ type: 'boolean' })).toEqual(
144+
expect(propertyToSourceGraphQLType({ type: 'boolean' })).toEqual(
129145
GraphQLBoolean
130146
);
131147
});
132148

133149
it('should return GraphQLObjectType for object with subfields', () => {
134-
const type = propertyToGraphQLType(
150+
const type = propertyToSourceGraphQLType(
135151
{
136152
properties: {
137153
big: {
@@ -169,12 +185,13 @@ describe('PropertiesConverter', () => {
169185
() => true,
170186
'lastname'
171187
);
172-
expect(fields.lastname).toEqual(GraphQLString);
188+
expect(fields._all.lastname).toEqual(GraphQLString);
189+
expect(fields.text.lastname).toEqual(GraphQLString);
173190
});
174191

175192
it('should accept mapping', () => {
176193
const fields = inputPropertiesToGraphQLTypes(mapping, () => true);
177-
expect(Object.keys(fields).length).toBeGreaterThan(2);
194+
expect(Object.keys(fields._all).length).toBeGreaterThan(2);
178195
});
179196

180197
it('should convert nested fields', () => {
@@ -194,10 +211,16 @@ describe('PropertiesConverter', () => {
194211
},
195212
() => true
196213
);
197-
expect(Object.keys(fields).length).toEqual(2);
198-
expect(Object.keys(fields)).toEqual(
214+
expect(Object.keys(fields._all).length).toEqual(2);
215+
expect(Object.keys(fields._all)).toEqual(
199216
expect.arrayContaining(['name', 'name__keyword'])
200217
);
218+
expect(Object.keys(fields.keyword)).toEqual(
219+
expect.arrayContaining(['name__keyword'])
220+
);
221+
expect(Object.keys(fields.text)).toEqual(
222+
expect.arrayContaining(['name'])
223+
);
201224
});
202225

203226
it('should use filterFn', () => {
@@ -217,14 +240,18 @@ describe('PropertiesConverter', () => {
217240
},
218241
prop => prop.type !== 'text'
219242
);
220-
expect(Object.keys(fields).length).toEqual(1);
221-
expect(Object.keys(fields)).toEqual(
243+
expect(Object.keys(fields._all).length).toEqual(1);
244+
expect(Object.keys(fields._all)).toEqual(
245+
expect.arrayContaining(['name__keyword'])
246+
);
247+
expect(Object.keys(fields.keyword).length).toEqual(1);
248+
expect(Object.keys(fields.keyword)).toEqual(
222249
expect.arrayContaining(['name__keyword'])
223250
);
224251
});
225252

226253
it('should not return index:false fields', () => {
227-
const itc = convertToSearchableITC(mapping, 'SerachInput');
254+
const itc = convertToSearchableITC(mapping, 'SearchInput');
228255
expect(itc.getFieldNames()).not.toEqual(
229256
expect.arrayContaining(['noIndex'])
230257
);
@@ -243,8 +270,12 @@ describe('PropertiesConverter', () => {
243270
},
244271
prop => prop.type !== 'text'
245272
);
246-
expect(Object.keys(fields).length).toEqual(1);
247-
expect(Object.keys(fields)).toEqual(
273+
expect(Object.keys(fields._all).length).toEqual(1);
274+
expect(Object.keys(fields._all)).toEqual(
275+
expect.arrayContaining(['date'])
276+
);
277+
expect(Object.keys(fields.date).length).toEqual(1);
278+
expect(Object.keys(fields.date)).toEqual(
248279
expect.arrayContaining(['date'])
249280
);
250281
});
@@ -305,14 +336,14 @@ describe('PropertiesConverter', () => {
305336
});
306337

307338
it('should return InputTypeComposer', () => {
308-
const itc = convertToSearchableITC(mapping, 'SerachInput');
339+
const itc = convertToSearchableITC(mapping, 'SearchInput');
309340
expect(itc).toBeInstanceOf(InputTypeComposer);
310-
expect(itc.getTypeName()).toBe('SerachInput');
341+
expect(itc.getTypeName()).toBe('SearchInput');
311342
expect(itc.getFieldNames().length).toBeGreaterThan(1);
312343
});
313344

314345
it('should return array of searchable fields', () => {
315-
const itc = convertToSearchableITC(mapping, 'SerachInput');
346+
const itc = convertToSearchableITC(mapping, 'SearchInput');
316347
expect(itc.getFieldNames()).toEqual(
317348
expect.arrayContaining([
318349
'name__keyword',
@@ -327,7 +358,6 @@ describe('PropertiesConverter', () => {
327358
});
328359
});
329360

330-
331361
describe('convertToAnalyzedITC()', () => {
332362
it('should throw error on empty mapping', () => {
333363
// $FlowFixMe
@@ -360,4 +390,17 @@ describe('PropertiesConverter', () => {
360390
);
361391
});
362392
});
393+
394+
describe('getSubFields()', () => {
395+
it('should return array of sub fields', () => {
396+
expect(
397+
getSubFields('range', ['ok', 'range', 'range.min', 'range.max'])
398+
).toEqual(['min', 'max']);
399+
});
400+
401+
it('should return array for empty/undefined list', () => {
402+
expect(getSubFields('range', null)).toEqual([]);
403+
expect(getSubFields('range')).toEqual([]);
404+
});
405+
});
363406
});

src/__tests__/query-test.js

Lines changed: 0 additions & 42 deletions
This file was deleted.

src/__tests__/typeStorage-test.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ describe('typeStorage', () => {
3030
});
3131

3232
it('should set new type as function and return type, if key not exists', () => {
33-
expect(typeStorage.getOrSet('MyType', () => GraphQLType)).toEqual(GraphQLType);
33+
expect(typeStorage.getOrSet('MyType', () => GraphQLType)).toEqual(
34+
GraphQLType
35+
);
3436
expect(typeStorage.get('MyType')).toEqual(GraphQLType);
3537
});
3638

src/composeWithElastic.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { TypeComposer, InputTypeComposer } from 'graphql-compose';
2+
import {
3+
convertToSourceTC,
4+
inputPropertiesToGraphQLTypes,
5+
} from './mappingConverter';
6+
import type { ElasticMappingT } from './mappingConverter';
7+
8+
export type composeWithElasticOptsT = {
9+
typeName: string,
10+
pluralFields?: string[],
11+
};
12+
13+
export function composeWithElastic(
14+
mapping: ElasticMappingT,
15+
opts: composeWithElasticOptsT = {}
16+
): TypeComposer {
17+
if (!opts) {
18+
throw new Error('Opts is required argument for composeWithElastic()');
19+
}
20+
21+
if (typeof opts.typeName !== 'string' || !opts.typeName) {
22+
throw new Error(
23+
'Opts.typeName is required option for TypeName in composeWithElastic()'
24+
);
25+
}
26+
27+
if (opts.pluralFields && !Array.isArray(opts.pluralFields)) {
28+
throw new Error(
29+
'Opts.pluralFields should be an Array of strings with field names ' +
30+
'which are plural (you may use dot notation for nested fields).'
31+
);
32+
}
33+
34+
const tc = convertToSourceTC(mapping, opts.typeName, opts);
35+
36+
const propsMap = inputPropertiesToGraphQLTypes(mapping);
37+
38+
return tc;
39+
}

0 commit comments

Comments
 (0)