Skip to content

Commit 39b0bff

Browse files
committed
fix(*): resolve fatal issue reconstructing args
+factor original/legacy Upload handler into separate file +use more specific GraphQLNamedType than GraphQLType which could include NotNull or List wrapper types +add test of processTypeArgs function
1 parent a01945c commit 39b0bff

File tree

7 files changed

+135
-68
lines changed

7 files changed

+135
-68
lines changed

.vscode/launch.json

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,25 @@
11
{
2-
// Use IntelliSense to learn about possible attributes.
3-
// Hover to view descriptions of existing attributes.
4-
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5-
"version": "0.2.0",
6-
"configurations": [
7-
{
8-
"type": "node",
9-
"request": "launch",
10-
"name": "AVA",
11-
"program": "${workspaceRoot}/node_modules/ava/profile.js",
12-
"args": ["--serial", "${file}"],
13-
"skipFiles": ["<node_internals>/**/*.js"]
14-
}
15-
]
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{ "type": "node",
8+
"request": "launch",
9+
"name": "Run AVA test",
10+
"program": "${workspaceRoot}/node_modules/ava/profile.js",
11+
"args": [
12+
"--serial",
13+
"${file}"
14+
],
15+
"skipFiles": [
16+
"<node_internals>/**/*.js",
17+
"node_modules/**/*.js"
18+
],
19+
"sourceMaps": true,
20+
"outFiles": [
21+
"${workspaceRoot}/dist/**/*.js"
22+
],
23+
},
24+
]
1625
}

package.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@
1818
"lint": "tslint --project tsconfig.json {src}/**/*.ts && prettier-check --ignore-path .gitignore {src,.}/{*.ts,*.js}",
1919
"test": "npm run lint && npm run build && npm run test-ava",
2020
"test-ava": "ava --verbose",
21-
"semantic-release": "semantic-release"
21+
"semantic-release": "semantic-release",
22+
"pretty": "npx prettier --write --ignore-path .gitignore {src,.}/{*.ts,*.js}"
2223
},
2324
"dependencies": {
24-
"apollo-upload-server": "^5.0.0"
25+
"graphql-middleware": "^1.4.2"
2526
},
2627
"devDependencies": {
2728
"@types/graphql": "0.13.4",
@@ -39,8 +40,8 @@
3940
"typescript": "2.9.2"
4041
},
4142
"peerDependencies": {
42-
"graphql": "^0.13.2",
43-
"graphql-middleware": "^1.4.2"
43+
"apollo-upload-server": "^5.0.0",
44+
"graphql": "^0.13.2"
4445
},
4546
"release": {
4647
"branch": "master"

src/index.ts

Lines changed: 11 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import {
22
GraphQLResolveInfo,
33
GraphQLArgument,
4-
GraphQLField,
54
getNamedType,
6-
GraphQLType,
5+
GraphQLNamedType,
76
} from 'graphql'
87
import { IMiddlewareFunction } from 'graphql-middleware'
98

@@ -56,15 +55,17 @@ function getFieldArguments(info: GraphQLResolveInfo): GraphQLArgument[] {
5655
*
5756
*/
5857
export function findArgumentsOfType(
59-
type: string | GraphQLType,
58+
type: string | GraphQLNamedType,
6059
info: GraphQLResolveInfo,
6160
): Maybe<GraphQLArgument[]> {
6261
const fieldArguments = getFieldArguments(info)
6362
return filterMap((argDef: GraphQLArgument): Maybe<GraphQLArgument> => {
64-
if (
65-
getNamedType(argDef.type).name ===
66-
(typeof type === 'string' ? type : getNamedType(type).name)
67-
) {
63+
const argType = getNamedType(argDef.type)
64+
if (typeof type === 'string') {
65+
if (argType.name === type) {
66+
return argDef
67+
}
68+
} else if (argType.name === type.name) {
6869
return argDef
6970
}
7071

@@ -167,7 +168,7 @@ export declare type ITypeArgumentHandler<V, T> = (
167168
) => Promise<T> // the field resolver expects arg of type T
168169

169170
export interface IConfig<V, T> {
170-
type: string | GraphQLType // name of type or type object describing V
171+
type: string | GraphQLNamedType // name of type or type object describing V
171172
transform: ITypeArgumentHandler<V, T> // value transformation function
172173
}
173174

@@ -200,7 +201,7 @@ export function processTypeArgs<V, T>({
200201
// substitute the transformed values into the args object
201202
.then(result =>
202203
result.reduce(
203-
(args, [name, newValue]) => (args[name] = newValue),
204+
(args, [name, newValue]) => { args[name] = newValue; return args },
204205
args,
205206
),
206207
)
@@ -242,24 +243,4 @@ export function visitAllArgs({ visitor }): IMiddlewareFunction {
242243
}
243244
}
244245

245-
// Preceding revision as a special case --------------------------------------
246-
247-
// this object shape is defined by Apollo Upload Server v5.0.0
248-
export interface IUploadFile {
249-
stream
250-
filename
251-
mimetype
252-
encoding
253-
}
254-
255-
declare type IUploadHandler<T> = (upload: IUploadFile) => Promise<T>
256-
257-
export interface IUploadConfig<T> {
258-
uploadHandler: IUploadHandler<T>
259-
}
260-
261-
export function upload<T>({
262-
uploadHandler,
263-
}: IUploadConfig<T>): IMiddlewareFunction {
264-
return processTypeArgs({ type: 'Upload', transform: uploadHandler })
265-
}
246+
export * from './upload'

src/test/index.test.ts

Lines changed: 60 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,13 @@ import test from 'ava'
22
import { makeExecutableSchema } from 'graphql-tools'
33
import { applyMiddleware } from 'graphql-middleware'
44
import { GraphQLUpload } from 'apollo-upload-server'
5-
import { graphql, GraphQLList, GraphQLString } from 'graphql'
5+
import { graphql, GraphQLList, GraphQLString, GraphQLScalarType } from 'graphql'
66
import {
77
findArgumentsOfType,
88
getArgumentValue,
99
makeArgumentTransform,
10-
} from '../'
11-
12-
// this interface traces to busboy file handling, as used by Apollo Upload Server
13-
interface IUpload {
14-
stream: string
15-
filename: string
16-
mimetype: string
17-
encoding: string
18-
}
10+
processTypeArgs,
11+
} from '../index'
1912

2013
// Helpers
2114

@@ -342,7 +335,7 @@ test('Processor handles multiple files correctly', async t => {
342335
),
343336
)
344337

345-
const file = (x): Promise<IUpload> =>
338+
const file = x =>
346339
new Promise(resolve =>
347340
resolve({
348341
stream: `s${x}`,
@@ -372,7 +365,7 @@ test('Processor handles empty files correctly', async t => {
372365
),
373366
)
374367

375-
const file = (x): Promise<IUpload> =>
368+
const file = x =>
376369
new Promise(resolve =>
377370
resolve({
378371
stream: `s${x}`,
@@ -411,3 +404,58 @@ test('Processor handles no file correctly', async t => {
411404

412405
t.is(res, null)
413406
})
407+
408+
test('processTypeArgs applies a transformations correctly', async t => {
409+
// write a schema, an arg transform, and a query
410+
t.plan(5)
411+
412+
let theValue = "some-random-string"
413+
414+
const typeDefs = `
415+
scalar Custom
416+
417+
type Query {
418+
test(pass: Custom): [String]!
419+
}
420+
`
421+
422+
const resolvers = {
423+
Query: {
424+
test: (parent, args, ctx, infp) => {
425+
t.deepEqual(args, { pass: String('-'+theValue+'-').toUpperCase() })
426+
return String(args.pass).split('-')
427+
}
428+
},
429+
Custom: new GraphQLScalarType({
430+
name: 'Custom',
431+
serialize: x => x,
432+
parseValue: x => x,
433+
parseLiteral: x => {
434+
t.is(x['value'], theValue); return `-${x['value']}-`
435+
}
436+
}),
437+
}
438+
439+
const middleware = {
440+
Query: {
441+
test: processTypeArgs({ type: 'Custom', transform: x=> {
442+
t.is(x, '-'+theValue+'-');
443+
return Promise.resolve(String(x).toUpperCase())
444+
}})
445+
},
446+
}
447+
448+
const schema = makeExecutableSchema({ typeDefs, resolvers })
449+
const schemaWithMiddleware = applyMiddleware(schema, middleware)
450+
451+
const query = `
452+
query {
453+
test(pass: "${theValue}")
454+
}
455+
`
456+
457+
// Execution
458+
const res = await graphql(schema, query)
459+
console.log(res)
460+
t.deepEqual(res.data.test, String('-'+theValue+'-').toUpperCase().split('-'))
461+
})

src/upload.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { GraphQLUpload } from 'apollo-upload-server'
2+
import { processTypeArgs } from './index'
3+
import { IMiddlewareFunction } from 'graphql-middleware'
4+
5+
// this object shape is defined by Apollo Upload Server v5.0.0
6+
export interface IUploadFile {
7+
stream
8+
filename
9+
mimetype
10+
encoding
11+
}
12+
13+
declare type IUploadHandler<T> = (upload: IUploadFile) => Promise<T>
14+
15+
export interface IUploadConfig<T> {
16+
uploadHandler: IUploadHandler<T>
17+
}
18+
19+
export function upload<T>({
20+
uploadHandler,
21+
}: IUploadConfig<T>): IMiddlewareFunction {
22+
return processTypeArgs({ type: GraphQLUpload, transform: uploadHandler })
23+
}

tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"outDir": "./dist",
88
"sourceMap": true,
99
"lib": ["dom", "es2017", "esnext.asynciterable"],
10-
"experimentalDecorators": true
10+
"experimentalDecorators": true,
11+
"watch": true
1112
},
1213
"exclude": ["node_modules"]
1314
}

yarn.lock

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,11 @@
4343
slide "^1.1.5"
4444

4545
"@babel/runtime@^7.0.0-beta.40":
46-
version "7.0.0-beta.51"
47-
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.0.0-beta.51.tgz#48b8ed18307034c6620f643514650ca2ccc0165a"
48-
integrity sha1-SLjtGDBwNMZiD2Q1FGUMoszAFlo=
46+
version "7.1.2"
47+
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.1.2.tgz#81c89935f4647706fc54541145e6b4ecfef4b8e3"
48+
integrity sha512-Y3SCjmhSupzFB6wcv1KmmFucH6gDVnI30WjOcicV10ju0cZjak3Jcs67YLIXBrmZYw1xCrVeJPbycFwrqNyxpg==
4949
dependencies:
50-
core-js "^2.5.7"
51-
regenerator-runtime "^0.11.1"
50+
regenerator-runtime "^0.12.0"
5251

5352
"@concordance/react@^1.0.0":
5453
version "1.0.0"
@@ -1353,7 +1352,7 @@ core-assert@^0.2.0:
13531352
buf-compare "^1.0.0"
13541353
is-error "^2.2.0"
13551354

1356-
core-js@^2.0.0, core-js@^2.4.0, core-js@^2.5.0, core-js@^2.5.7:
1355+
core-js@^2.0.0, core-js@^2.4.0, core-js@^2.5.0:
13571356
version "2.5.7"
13581357
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e"
13591358
integrity sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==
@@ -3962,11 +3961,16 @@ regenerate@^1.2.1:
39623961
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11"
39633962
integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==
39643963

3965-
regenerator-runtime@^0.11.0, regenerator-runtime@^0.11.1:
3964+
regenerator-runtime@^0.11.0:
39663965
version "0.11.1"
39673966
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
39683967
integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
39693968

3969+
regenerator-runtime@^0.12.0:
3970+
version "0.12.1"
3971+
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de"
3972+
integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==
3973+
39703974
regex-cache@^0.4.2:
39713975
version "0.4.4"
39723976
resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd"

0 commit comments

Comments
 (0)