diff --git a/README.md b/README.md index f9925f5..45bfaac 100644 --- a/README.md +++ b/README.md @@ -100,11 +100,12 @@ First, let's see what Kraph provides for you. technically no differences, `fieldObject` may be chosen for clarity to indicate that a field must contain another set of nested fields as an argument. Both of them take a `Map` that maps Kotlin data types to the - GraphQL data types for input objects. + GraphQL data types for input objects. You can also specify an alias using `alias` to change + the name of the returned field. ```graphql query { users { - name + nick: name email avatarUrl(size: 100) } @@ -114,7 +115,7 @@ First, let's see what Kraph provides for you. Kraph { query { fieldObject("users") { - field("name") + field("name", alias = "nick") field("email") field("avatarUrl", args = mapOf("size" to 100)) } @@ -122,6 +123,33 @@ First, let's see what Kraph provides for you. } ``` +- `fragment` provides a mechanism for creating GraphQL Fragments. To use a fragment + in a query requires two steps. The first is to define the fragment, letting + Kraph know how to handle it later: + ```graphql + fragment UserFragment on User { + name + email + avatarUrl(size: 100) + } + ``` + ```kotlin + Kraph.defineFragment("UserFragment") { + field("name") + field("email") + field("avatarUrl", mapOf("size" to 100)) + } + ``` + Then, when you are creating your query, you can simply use the fragment and + its fields will be expanded: + ```graphql + query { + users { + ...UserFragment + } + } + ``` + - `fragment` provides a mechanism for creating GraphQL Fragments. To use a fragment in a query requires two steps. The first is to define the fragment, letting Kraph know how to handle it later: diff --git a/core/src/main/kotlin/me/lazmaid/kraph/Kraph.kt b/core/src/main/kotlin/me/lazmaid/kraph/Kraph.kt index 601ac5f..c71e246 100644 --- a/core/src/main/kotlin/me/lazmaid/kraph/Kraph.kt +++ b/core/src/main/kotlin/me/lazmaid/kraph/Kraph.kt @@ -51,12 +51,12 @@ class Kraph(f: Kraph.() -> Unit) { inner open class FieldBuilder { internal val fields = arrayListOf() - fun fieldObject(name: String, args: Map? = null, builder: FieldBlock) { - addField(name, args, builder) + fun fieldObject(name: String, alias: String? = null, args: Map? = null, builder: FieldBlock) { + addField(name, alias, args, builder) } - fun field(name: String, args: Map? = null, builder: FieldBlock? = null) { - addField(name, args, builder) + fun field(name: String, alias: String? = null, args: Map? = null, builder: FieldBlock? = null) { + addField(name, alias, args, builder) } fun fragment(name: String) { @@ -87,16 +87,16 @@ class Kraph(f: Kraph.() -> Unit) { fields += CursorConnection(name, Argument(argsMap), SelectionSet(selection.fields)) } - fun func(name: String, args: Map, builder: FieldBlock) { - fields += Mutation(name, InputArgument(args), createSelectionSet(name, builder)) + fun func(name: String, alias: String? = null, args: Map, builder: FieldBlock) { + fields += Mutation(name, alias, InputArgument(args), createSelectionSet(name, builder)) } - protected fun addField(name: String, args: Map? = null, builder: FieldBlock? = null) { + protected fun addField(name: String, alias: String? = null, args: Map? = null, builder: FieldBlock? = null) { val argNode = args?.let(::Argument) val selectionSet = builder?.let { createSelectionSet(name, builder) } - fields += Field(name, arguments = argNode, selectionSet = selectionSet) + fields += Field(name, alias, arguments = argNode, selectionSet = selectionSet) } } diff --git a/core/src/main/kotlin/me/lazmaid/kraph/lang/Field.kt b/core/src/main/kotlin/me/lazmaid/kraph/lang/Field.kt index d8f408c..6bc795b 100644 --- a/core/src/main/kotlin/me/lazmaid/kraph/lang/Field.kt +++ b/core/src/main/kotlin/me/lazmaid/kraph/lang/Field.kt @@ -6,6 +6,7 @@ package me.lazmaid.kraph.lang internal open class Field( internal val name: String, + internal val alias: String? = null, internal val arguments: Argument? = null, internal var selectionSet: SelectionSet? = null ) : GraphQLNode() { @@ -13,8 +14,9 @@ internal open class Field( format: PrintFormat, previousLevel: Int ): String { + val alias = alias?.let { "$it: " } ?: "" val selectionSetPart = selectionSet?.print(format, previousLevel)?.let{ " $it" } ?: "" val argumentsPart = arguments?.print(format, previousLevel)?.let{ " $it" } ?: "" - return "$name$argumentsPart$selectionSetPart" + return "$alias$name$argumentsPart$selectionSetPart" } } diff --git a/core/src/main/kotlin/me/lazmaid/kraph/lang/relay/Node.kt b/core/src/main/kotlin/me/lazmaid/kraph/lang/relay/Node.kt index 00410ea..f2e3565 100644 --- a/core/src/main/kotlin/me/lazmaid/kraph/lang/relay/Node.kt +++ b/core/src/main/kotlin/me/lazmaid/kraph/lang/relay/Node.kt @@ -8,10 +8,10 @@ import me.lazmaid.kraph.lang.SelectionSet * Created by VerachadW on 10/2/2016 AD. */ -internal class Node(name: String, additionalFields: List) : Field(name) { +internal class Node(name: String, alias: String?, additionalFields: List) : Field(name, alias) { init { selectionSet = SelectionSet(additionalFields.toMutableList().apply { - add(0, Field("id")) + add(0, Field("id")) }) } } \ No newline at end of file diff --git a/core/src/main/kotlin/me/lazmaid/kraph/lang/relay/RelayMutation.kt b/core/src/main/kotlin/me/lazmaid/kraph/lang/relay/RelayMutation.kt index ca1d55f..f88bfe9 100644 --- a/core/src/main/kotlin/me/lazmaid/kraph/lang/relay/RelayMutation.kt +++ b/core/src/main/kotlin/me/lazmaid/kraph/lang/relay/RelayMutation.kt @@ -7,4 +7,4 @@ import me.lazmaid.kraph.lang.SelectionSet * Created by VerachadW on 10/2/2016 AD. */ -internal class Mutation(name: String, arguments: InputArgument, selectionSet: SelectionSet) : Field(name, arguments, selectionSet) +internal class Mutation(name: String, alias: String? = null, arguments: InputArgument, selectionSet: SelectionSet) : Field(name, alias, arguments, selectionSet) diff --git a/core/src/test/kotlin/me/lazmaid/kraph/test/BuilderSpek.kt b/core/src/test/kotlin/me/lazmaid/kraph/test/BuilderSpek.kt index 4c4dad7..22e1414 100644 --- a/core/src/test/kotlin/me/lazmaid/kraph/test/BuilderSpek.kt +++ b/core/src/test/kotlin/me/lazmaid/kraph/test/BuilderSpek.kt @@ -72,6 +72,23 @@ class BuilderSpek : Spek({ assertThat(query.toGraphQueryString(), equalTo("query getAllNotes {\n notes {\n id\n content\n author {\n name\n email\n }\n avatarUrl (size: 100)\n }\n}")) } } + given("sample query with aliases") { + val query = Kraph { + query("getAllNotes") { + fieldObject("notes", alias = "aliasedNotes") { + field("id", alias = "aliasedId") + } + } + } + it("should be able to print the request for network call") { + assertThat( + query.toRequestString(), + equalTo( + "{\"query\": \"query getAllNotes { aliasedNotes: notes { aliasedId: id } }\", \"variables\": null, \"operationName\": \"getAllNotes\"}" + ) + ) + } + } given("sample query with no field in selection set") { it("should throw NoFieldsInSelectionSetException") { assertThat({ @@ -95,7 +112,7 @@ class BuilderSpek : Spek({ given("sample mutation") { val query = Kraph { mutation { - func("registerUser", mapOf("email" to "abcd@efgh.com", "password" to "abcd1234", "age" to 30)) { + func("registerUser", args = mapOf("email" to "abcd@efgh.com", "password" to "abcd1234", "age" to 30)) { field("id") field("token") } @@ -132,6 +149,22 @@ class BuilderSpek : Spek({ assertThat(query.document.operation.selectionSet.fields[0].selectionSet!!.fields[1].name, equalTo("token")) } } + given("sample mutation with alias") { + val query = Kraph { + mutation { + func("registerUser", alias = "aliasedRegisterUser", args = mapOf("email" to "abcd@efgh.com")) { + field("id") + } + } + } + it("should be able to print the request for network call") { + assertThat(query.toRequestString(), + equalTo( + "{\"query\": \"mutation { aliasedRegisterUser: registerUser (input: { email: \\\"abcd@efgh.com\\\" }) { id } }\", \"variables\": null, \"operationName\": null}" + ) + ) + } + } given("sample mutation with no field in selection set") { it("should throw NoFieldsInSelectionSetException") { assertThat({ @@ -205,17 +238,17 @@ class BuilderSpek : Spek({ given("sample query with cursor cursorConnection without arguments") { it("should throw IllegalArgumentException with message \"There must be at least 1 argument for Cursor Connection\"") { assertThat({ - Kraph { - query { - cursorConnection("users") { - edges { - node { - field("title") + Kraph { + query { + cursorConnection("users") { + edges { + node { + field("title") + } } } } } - } }, throws(cursorEmptyArgumentsMessageMatcher)) } } diff --git a/core/src/test/kotlin/me/lazmaid/kraph/test/GraphQLPrintSpek.kt b/core/src/test/kotlin/me/lazmaid/kraph/test/GraphQLPrintSpek.kt index f09aec4..e50701a 100644 --- a/core/src/test/kotlin/me/lazmaid/kraph/test/GraphQLPrintSpek.kt +++ b/core/src/test/kotlin/me/lazmaid/kraph/test/GraphQLPrintSpek.kt @@ -132,7 +132,7 @@ class GraphQLPrintSpek : Spek({ given("name RegisterUser with email and password and type of registrarion as argument and payload contains id and token") { val argNode = InputArgument(mapOf("email" to "abcd@efgh.com", "password" to "abcd1234", "type" to Type.EMAIL)) val setNode = SelectionSet(listOf(Field("id"), Field("token"))) - val node = Mutation("RegisterUser", argNode, setNode) + val node = Mutation("RegisterUser", arguments = argNode, selectionSet = setNode) it("should print correctly in NORMAL mode") { assertThat(node.print(PrintFormat.NORMAL, 0), equalTo("RegisterUser (input: { email: \"abcd@efgh.com\", password: \"abcd1234\", type: EMAIL }) { id token }")) } @@ -148,7 +148,7 @@ class GraphQLPrintSpek : Spek({ val tests = listOf( Triple(Field("id"), "name id", Expectation("id", "id", "id")), Triple( - Field("avatarSize", Argument(mapOf("size" to 20))), + Field("avatarSize", arguments = Argument(mapOf("size" to 20))), "name avatarSize and size argument with value as 20", Expectation( "avatarSize (size: 20)", @@ -166,7 +166,7 @@ class GraphQLPrintSpek : Spek({ ) ), Triple( - Field("user", Argument(mapOf("id" to 10)), SelectionSet(listOf(Field("name"), Field("email")))), + Field("user", arguments = Argument(mapOf("id" to 10)), selectionSet = SelectionSet(listOf(Field("name"), Field("email")))), "name user and id argument with value as 10 and containing name and email", Expectation( "user (id: 10) { name email }", diff --git a/core/src/test/kotlin/me/lazmaid/kraph/test/RequestSpek.kt b/core/src/test/kotlin/me/lazmaid/kraph/test/RequestSpek.kt index d37e915..c45a00e 100644 --- a/core/src/test/kotlin/me/lazmaid/kraph/test/RequestSpek.kt +++ b/core/src/test/kotlin/me/lazmaid/kraph/test/RequestSpek.kt @@ -12,7 +12,7 @@ class RequestSpek : Spek({ describe("Kraph Query Request format printers") { val query = Kraph { query("GetUserId") { - field("user", mapOf("name" to variable("name", "User", "{\"name\": \"UserName\"}"))) { + field("user", args = mapOf("name" to variable("name", "User", "{\"name\": \"UserName\"}"))) { field("id") } } diff --git a/sample/src/main/kotlin/KraphExample.kt b/sample/src/main/kotlin/KraphExample.kt index beb42f0..773953c 100644 --- a/sample/src/main/kotlin/KraphExample.kt +++ b/sample/src/main/kotlin/KraphExample.kt @@ -34,5 +34,23 @@ fun main(args: Array) { println("Query: ${mutation.toGraphQueryString()}") println("Request Body: ${ mutation.toRequestString() }") + // Sample query with alias + val alias = Kraph { + query { + fieldObject("notes", "example") { + field("id") + field("createdDate") + field("content") + fieldObject("author") { + field("name") + field("avatarUrl", args = mapOf("size" to 100)) + } + } + } + } + + println("Query: ${alias.toGraphQueryString()}") + println("Request Body: ${ alias.toRequestString() }") + } \ No newline at end of file