Comments (4)
I'm very much interested in this feature as well. I am currently studying the library codebase with the same exact purpose.
My main use case is I want a resolver to return a Connection of a generic type:
data class Connection<T>(
val totalCount: Int,
val edges: List<Edge<T>>,
val pageInfo: PageInfo
) {
data class Edge<T>(
val node: T,
val cursor: Int
)
data class PageInfo(
val endCursor: Int,
val hasNextPage: Boolean
)
}
I really like the design you're proposing, as a starting point!
In this case, if I wanted a resolver to return a Connection<User>
, two types would be added to the Schema:
- Connection_User
- Edge_User
And eventually, we could add support for multiple generics. Then we could specify the type of cursor with Connection<T, C>
.
Then, we would have these types added to the Schema when returning a Connection<User, Int>
- Connection_User_Int
- Edge_User_Int
- PageInfo_Int
I really, really hope we're able to achieve this 🙂
Edit: Of course the syntax would need to be revised if we wanted to support deeper level generics (e.g. Connection<Entity<User>, Int>>)
, but as a starting point it looks good to me.
from kgraphql.
Progress Update
The main issue is that getting the actual returnType of a KProperty with a generic returnType is not trivial.
e.g.
val kType = typeOf<Connection<Person<String>, Int>>()
println(kType) // Connection<Person<String>, Int> ✅
(kType.classifier as KClass<*>).memberProperties.forEach { property ->
println(property.returnType) // List<Edge<T, K>> ❌ Should be List<Edge<String, Int>>
}
Unfortunately, kotlin reflection is still very limited, and this is something that's not yet supported.
I've been studying how other projects using reflection deal with this issue:
- Jackson: uses TypeReference and TypeFactory
- gson: uses TypeToken.getParameterized (based on Guava)
- Moshi (reflection): Most functional approach: Util.resolve (based on gson and Guava)
These libraries, using java reflection and Super Type Tokens pattern, are able to resolve a ParameterizedType to a java.lang.reflect.Type with the actual type parameters.
I chose to experiment with the Moshi approach, copying everything that was necessary to resolve a property returnType.
Sadly, there is no way to resolve to a KType, only to a java.lang.reflect.Type. All these libraries I studied work exclusively with java.lang.reflect.Type under the hood.
This differs from the KGraphQL library, which associates definitions by KClass<*>
, and relies on KType and KClass in many places to compile a schema. We'll never be able to work with generics while we associate by KClass<*>
, because it doesn't hold information about type parameters. We also can't rely on KType, because for compiling properties with generic returnType, we don't have access to a KType with resolved type parameters (only to a java.lang.reflect.Type with resolved type parameters).
Conclusion: For this to work, internal changes, mainly to the compilation and definitions, need to be done to rely exclusively on java.lang.reflect.Type.
Note: I have tried very hard to find a way to get the properties returnTypes as KType with resolved type parameters, so that we could associate definitions by KType and keep compiling using KType and KClass<*>
, but it's not possible (I'd love for someone to prove me wrong).
I am working on these changes and I've made a quick POF, pushed to this branch. It's still lacking a lot, but I'd say the results are already very promising:
class Connection<T : Any, K : Any>(
val totalCount: Int,
val edges: List<Edge<T, K>>,
val pageInfo: PageInfo<K>
) {
class Edge<T : Any, K: Any>(
val node: T,
val cursor: K
)
class PageInfo<K: Any>(
val endCursor: K,
val hasNextPage: Boolean
)
}
val names = listOf("Kai", "Eliana", "Jayden", "Ezra", "Luca", "Rowan", "Nova", "Amara")
fun main() {
val schema = KGraphQL.schema {
configure {
this.useDefaultPrettyPrinter = true
}
query("names") {
resolver { ->
Connection(
totalCount = names.size,
edges = names.subList(0, 2).mapIndexed { index, name ->
Connection.Edge(
node = name,
cursor = index
)
},
pageInfo = Connection.PageInfo(
endCursor = 1,
hasNextPage = true
)
)
}.returns<Connection<String, Int>>()
}
}
schema.types.forEach { println(it.name) }
println()
println(schema.executeBlocking("{ names { totalCount, edges { node, cursor }, pageInfo { endCursor, hasNextPage } } }"))
Console:
__Schema
__Directive
__InputValue
__Type
__EnumValue
__Field
Connection<String, Integer>
Edge<String, Integer>
PageInfo<Integer>
__TypeKind
__DirectiveLocation
String
Boolean
Float
Short
Int
Long
Query
{
"data" : {
"names" : {
"totalCount" : 8,
"edges" : [ {
"node" : "Kai",
"cursor" : 0
}, {
"node" : "Eliana",
"cursor" : 1
} ],
"pageInfo" : {
"endCursor" : 1,
"hasNextPage" : true
}
}
}
}
from kgraphql.
This would be great to see
from kgraphql.
This would be great to see
I think i could finish this,
But the project looks pretty dead at the moment.
I've been waiting a long time for subscription support which i'm not sure is in development anymore.
If the future looked promising then i would love to assist more,
but as it stands i have started to look into alternatives like ExpediaGroup/graphql-kotlin.
from kgraphql.
Related Issues (20)
- Serialization broken for KTOR 2.0.2 HOT 1
- Getting "This should never happen" error on incorrect fragment name
- Idea: Alternative design for integrating with ktor
- Detect absence of optional input fields HOT 3
- Server crashing when update version from 0.17.14 to 0.17.15
- When using fragments, executor resolves a property that is not going to be returned HOT 1
- Unable to use class that inherits from an interface as an inputType
- Error on Ktor 2.0.x HOT 2
- When I use java.util.Date as a class param, I got an serialization issue. HOT 1
- Ktor authentification blocks all routes while using with
- Using enum as argument HOT 1
- @include and @skip directives should exclude content, but instead it's returning null value (except if the directive is applied to the query)
- Discussion - comparison between ExpediaGroup/graphql-kotlin vs aPureBase/KGraphQL HOT 1
- Property __typename does not exist in Query and Mutation
- Top level fields with skip/include directives ignored for mutations
- SDL Driven Option
- GraphQL Errors don't have correct content type
- Allow wrapping all resolvers
- le v7
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from kgraphql.