@@ -4,21 +4,21 @@ import graphql.execution.DataFetcherResult
44import graphql.execution.batched.Batched
55import graphql.language.ObjectValue
66import graphql.language.StringValue
7- import graphql.schema.Coercing
8- import graphql.schema.DataFetchingEnvironment
9- import graphql.schema.GraphQLScalarType
7+ import graphql.schema.*
108import kotlinx.coroutines.CompletableDeferred
119import kotlinx.coroutines.channels.Channel
1210import kotlinx.coroutines.channels.ReceiveChannel
1311import kotlinx.coroutines.coroutineScope
1412import org.reactivestreams.Publisher
13+ import java.io.InputStream
1514import java.util.*
1615import java.util.concurrent.CompletableFuture
16+ import javax.servlet.http.Part
1717
1818fun createSchema () = SchemaParser .newParser()
1919 .schemaString(schemaDefinition)
20- .resolvers(Query (), Mutation (), Subscription (), ItemResolver (), UnusedRootResolver (), UnusedResolver ())
21- .scalars(customScalarUUID, customScalarMap, customScalarId)
20+ .resolvers(Query (), Mutation (), Subscription (), ItemResolver (), UnusedRootResolver (), UnusedResolver (), EchoFilesResolver () )
21+ .scalars(customScalarUUID, customScalarMap, customScalarId, uploadScalar )
2222 .dictionary(" OtherItem" , OtherItemWithWrongName ::class )
2323 .dictionary(" ThirdItem" , ThirdItem ::class )
2424 .dictionary(" ComplexMapItem" , ComplexMapItem ::class )
@@ -31,6 +31,7 @@ val schemaDefinition = """
3131## Private comment!
3232scalar UUID
3333scalar customScalarMap
34+ scalar Upload
3435
3536type Query {
3637 # Check if items list is empty
@@ -108,6 +109,7 @@ input ComplexInputTypeTwo {
108109
109110type Mutation {
110111 addItem(newItem: NewItemInput!): Item!
112+ echoFiles(fileParts: [Upload!]!): [String!]!
111113}
112114
113115type Subscription {
@@ -353,6 +355,10 @@ class ItemResolver : GraphQLResolver<Item> {
353355 }
354356}
355357
358+ class EchoFilesResolver : GraphQLMutationResolver {
359+ fun echoFiles (fileParts : List <Part >): List <String > = fileParts.map { String (it.inputStream.readBytes()) }
360+ }
361+
356362interface ItemInterface {
357363 val name: String
358364 val type: Type
@@ -373,6 +379,18 @@ data class ComplexNullable(val first: String, val second: String, val third: Str
373379data class ComplexInputType (val first : String , val second : List <List <ComplexInputTypeTwo >? >? )
374380data class ComplexInputTypeTwo (val first : String )
375381data class ItemWithGenericProperties (val keys : List <String >)
382+ class MockPart (private val name : String , private val content : String ):Part{
383+ override fun getSubmittedFileName (): String = name
384+ override fun getName (): String = name
385+ override fun write (fileName : String? ) = throw IllegalArgumentException (" Not supported" )
386+ override fun getHeader (name : String ): String? = null
387+ override fun getSize (): Long = content.toByteArray().size.toLong()
388+ override fun getContentType (): String? = null
389+ override fun getHeaders (name : String? ): Collection <String > = listOf ()
390+ override fun getHeaderNames (): Collection <String > = listOf ()
391+ override fun getInputStream (): InputStream = content.byteInputStream()
392+ override fun delete () = throw IllegalArgumentException (" Not supported" )
393+ }
376394
377395val customScalarId = GraphQLScalarType .newScalar()
378396 .name(" ID" )
@@ -427,3 +445,33 @@ val customScalarMap = GraphQLScalarType.newScalar()
427445 override fun parseLiteral (input : Any? ): Map <String , Any > = (input as ObjectValue ).objectFields.associateBy { it.name }.mapValues { (it.value.value as StringValue ).value }
428446 })
429447 .build()
448+
449+ // Definition from https://github.com/graphql-java-kickstart/graphql-java-servlet/blob/master/src/main/java/graphql/servlet/core/ApolloScalars.java
450+ val uploadScalar: GraphQLScalarType = GraphQLScalarType .newScalar()
451+ .name(" Upload" )
452+ .description(" A file part in a multipart request" )
453+ .coercing(object : Coercing <Part ?, Void ?> {
454+ override fun serialize (dataFetcherResult : Any ): Void ? {
455+ throw CoercingSerializeException (" Upload is an input-only type" )
456+ }
457+
458+ override fun parseValue (input : Any? ): Part ? {
459+ return when (input) {
460+ is Part -> {
461+ input
462+ }
463+ null -> {
464+ null
465+ }
466+ else -> {
467+ throw CoercingParseValueException (" Expected type ${Part ::class .java.name} but was ${input.javaClass.name} " )
468+ }
469+ }
470+ }
471+
472+ override fun parseLiteral (input : Any ): Part ? {
473+ throw CoercingParseLiteralException (
474+ " Must use variables to specify Upload values" )
475+ }
476+ }).build()
477+
0 commit comments