Skip to content

Commit d8b2240

Browse files
committed
Kobby Server Draft
1 parent 680a1aa commit d8b2240

57 files changed

Lines changed: 2028 additions & 93 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cinema-api/build.gradle.kts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,9 @@ dependencies {
1515

1616
// Add this dependency to enable default Ktor adapters generation
1717
compileOnly("io.ktor:ktor-client-cio:2.3.13")
18+
19+
// todo
20+
compileOnly("com.graphql-java:graphql-java:24.3")
21+
compileOnly("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1")
22+
compileOnly("org.jetbrains.kotlinx:kotlinx-coroutines-reactive:1.8.1")
1823
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
@file:Suppress("UNCHECKED_CAST")
2+
3+
package io.github.ermadmi78.kobby.cinema.api.kobby.server
4+
5+
import graphql.Scalars
6+
import graphql.schema.DataFetchingEnvironment
7+
import graphql.schema.GraphQLCodeRegistry
8+
import graphql.schema.GraphQLScalarType
9+
import graphql.schema.GraphQLSchema
10+
import io.github.ermadmi78.kobby.cinema.api.kobby.server.model.resolver.FilmResolutionModel
11+
import io.github.ermadmi78.kobby.cinema.api.kobby.server.model.resolver.MutationResolutionModel
12+
import io.github.ermadmi78.kobby.cinema.api.kobby.server.model.resolver.QueryResolutionModel
13+
import io.github.ermadmi78.kobby.cinema.api.kobby.server.model.resolver.SubscriptionResolutionModel
14+
import io.github.ermadmi78.kobby.cinema.api.kobby.server.runtime.DEFAULT_CONTEXT_PROVIDER
15+
import io.github.ermadmi78.kobby.cinema.api.kobby.server.runtime.DEFAULT_RESOLUTION_ASPECT
16+
import io.github.ermadmi78.kobby.cinema.api.kobby.server.runtime.ResolutionAspect
17+
import io.github.ermadmi78.kobby.cinema.api.kobby.server.specification.DEDAULT_ID_SCALAR
18+
import io.github.ermadmi78.kobby.cinema.api.kobby.server.specification.program.code.*
19+
import io.github.ermadmi78.kobby.cinema.api.kobby.server.specification.program.type.*
20+
import kotlin.coroutines.CoroutineContext
21+
22+
/**
23+
* Created on 07.02.2026
24+
*
25+
* @author Dmitry Ermakov (ermadmi78@gmail.com)
26+
*/
27+
28+
fun buildCinemaSchemaUsingProgram(
29+
queryResolver: QueryResolutionModel,
30+
mutationResolver: MutationResolutionModel,
31+
subscriptionResolver: SubscriptionResolutionModel,
32+
filmResolver: FilmResolutionModel,
33+
scalarID: GraphQLScalarType = DEDAULT_ID_SCALAR,
34+
scalarString: GraphQLScalarType = Scalars.GraphQLString,
35+
aspect: ResolutionAspect = DEFAULT_RESOLUTION_ASPECT,
36+
coroutineContextProvider: (DataFetchingEnvironment) -> CoroutineContext = DEFAULT_CONTEXT_PROVIDER
37+
): GraphQLSchema {
38+
require(scalarID.name == "ID") {
39+
"For scalarID expected scalar with name 'ID', but found '${scalarID.name}'"
40+
}
41+
require(scalarString.name == "String") {
42+
"For scalarString expected scalar with name 'String', but found '${scalarString.name}'"
43+
}
44+
45+
val codeRegistry: GraphQLCodeRegistry.Builder = GraphQLCodeRegistry.newCodeRegistry()
46+
QueryCode.register(codeRegistry, queryResolver, aspect, coroutineContextProvider)
47+
MutationCode.register(codeRegistry, mutationResolver, aspect, coroutineContextProvider)
48+
SubscriptionCode.register(codeRegistry, subscriptionResolver, aspect, coroutineContextProvider)
49+
FilmCode.register(codeRegistry, filmResolver, aspect, coroutineContextProvider)
50+
ActorCode.register(codeRegistry)
51+
52+
return GraphQLSchema.newSchema()
53+
.additionalType(scalarID)
54+
.additionalType(scalarString)
55+
.query(QueryType.build())
56+
.mutation(MutationType.build())
57+
.subscription(SubscriptionType.build())
58+
.additionalType(FilmType.build())
59+
.additionalType(ActorType.build())
60+
.codeRegistry(codeRegistry.build())
61+
.build()
62+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package io.github.ermadmi78.kobby.cinema.api.kobby.server
2+
3+
import graphql.Scalars
4+
import graphql.schema.DataFetchingEnvironment
5+
import graphql.schema.GraphQLScalarType
6+
import graphql.schema.GraphQLSchema
7+
import graphql.schema.idl.RuntimeWiring
8+
import graphql.schema.idl.SchemaGenerator
9+
import graphql.schema.idl.SchemaParser
10+
import graphql.schema.idl.TypeDefinitionRegistry
11+
import io.github.ermadmi78.kobby.cinema.api.kobby.server.model.resolver.FilmResolutionModel
12+
import io.github.ermadmi78.kobby.cinema.api.kobby.server.model.resolver.MutationResolutionModel
13+
import io.github.ermadmi78.kobby.cinema.api.kobby.server.model.resolver.QueryResolutionModel
14+
import io.github.ermadmi78.kobby.cinema.api.kobby.server.model.resolver.SubscriptionResolutionModel
15+
import io.github.ermadmi78.kobby.cinema.api.kobby.server.runtime.DEFAULT_CONTEXT_PROVIDER
16+
import io.github.ermadmi78.kobby.cinema.api.kobby.server.runtime.DEFAULT_RESOLUTION_ASPECT
17+
import io.github.ermadmi78.kobby.cinema.api.kobby.server.runtime.ResolutionAspect
18+
import io.github.ermadmi78.kobby.cinema.api.kobby.server.specification.DEDAULT_ID_SCALAR
19+
import io.github.ermadmi78.kobby.cinema.api.kobby.server.specification.sdl.*
20+
import java.io.Reader
21+
import kotlin.coroutines.CoroutineContext
22+
23+
/**
24+
* Created on 15.02.2026
25+
*
26+
* @author Dmitry Ermakov (ermadmi78@gmail.com)
27+
*/
28+
29+
fun buildCinemaSchemaUsingSDL(
30+
schemas: Sequence<Reader>,
31+
queryResolver: QueryResolutionModel,
32+
mutationResolver: MutationResolutionModel,
33+
subscriptionResolver: SubscriptionResolutionModel,
34+
filmResolver: FilmResolutionModel,
35+
scalarID: GraphQLScalarType = DEDAULT_ID_SCALAR,
36+
scalarString: GraphQLScalarType = Scalars.GraphQLString,
37+
aspect: ResolutionAspect = DEFAULT_RESOLUTION_ASPECT,
38+
coroutineContextProvider: (DataFetchingEnvironment) -> CoroutineContext = DEFAULT_CONTEXT_PROVIDER
39+
): GraphQLSchema {
40+
val schemaParser = SchemaParser()
41+
val registry = TypeDefinitionRegistry()
42+
for (schema in schemas) {
43+
registry.merge(schemaParser.parse(schema))
44+
}
45+
46+
val wiring = RuntimeWiring.newRuntimeWiring().also {
47+
wireCinemaSchemaRuntime(
48+
it,
49+
queryResolver,
50+
mutationResolver,
51+
subscriptionResolver,
52+
filmResolver,
53+
scalarID,
54+
scalarString,
55+
aspect,
56+
coroutineContextProvider
57+
)
58+
}.build()
59+
60+
return SchemaGenerator().makeExecutableSchema(registry, wiring)
61+
}
62+
63+
fun wireCinemaSchemaRuntime(
64+
runtimeWiring: RuntimeWiring.Builder,
65+
queryResolver: QueryResolutionModel,
66+
mutationResolver: MutationResolutionModel,
67+
subscriptionResolver: SubscriptionResolutionModel,
68+
filmResolver: FilmResolutionModel,
69+
scalarID: GraphQLScalarType = DEDAULT_ID_SCALAR,
70+
scalarString: GraphQLScalarType = Scalars.GraphQLString,
71+
aspect: ResolutionAspect = DEFAULT_RESOLUTION_ASPECT,
72+
coroutineContextProvider: (DataFetchingEnvironment) -> CoroutineContext = DEFAULT_CONTEXT_PROVIDER
73+
) {
74+
require(scalarID.name == "ID") {
75+
"For scalarID expected scalar with name 'ID', but found '${scalarID.name}'"
76+
}
77+
require(scalarString.name == "String") {
78+
"For scalarString expected scalar with name 'String', but found '${scalarString.name}'"
79+
}
80+
81+
runtimeWiring
82+
.strictMode(false)
83+
.scalar(scalarID)
84+
.scalar(scalarString)
85+
86+
QueryWiring.register(runtimeWiring, queryResolver, aspect, coroutineContextProvider)
87+
MutationWiring.register(runtimeWiring, mutationResolver, aspect, coroutineContextProvider)
88+
SubscriptionWiring.register(runtimeWiring, subscriptionResolver, aspect, coroutineContextProvider)
89+
FilmWiring.register(runtimeWiring, filmResolver, aspect, coroutineContextProvider)
90+
ActorWiring.register(runtimeWiring)
91+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package io.github.ermadmi78.kobby.cinema.api.kobby.server.model
2+
3+
/**
4+
* Created on 16.02.2026
5+
*
6+
* @author Dmitry Ermakov (ermadmi78@gmail.com)
7+
*/
8+
interface CinemaData {
9+
operator fun get(property: String): Any?
10+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package io.github.ermadmi78.kobby.cinema.api.kobby.server.model.data
2+
3+
import io.github.ermadmi78.kobby.cinema.api.kobby.server.model.CinemaData
4+
5+
/**
6+
* Created on 07.02.2026
7+
*
8+
* @author Dmitry Ermakov (ermadmi78@gmail.com)
9+
*/
10+
data class ActorData(
11+
val id: Long? = null,
12+
val firstName: String? = null,
13+
val lastName: String? = null,
14+
val __localContext: Map<String, Any?> = emptyMap()
15+
) : CinemaData {
16+
override operator fun get(property: String): Any? =
17+
__localContext[property]
18+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package io.github.ermadmi78.kobby.cinema.api.kobby.server.model.data
2+
3+
import io.github.ermadmi78.kobby.cinema.api.kobby.server.model.CinemaData
4+
5+
/**
6+
* Created on 07.02.2026
7+
*
8+
* @author Dmitry Ermakov (ermadmi78@gmail.com)
9+
*/
10+
data class FilmData(
11+
val id: Long? = null,
12+
val title: String? = null,
13+
val __localContext: Map<String, Any?> = emptyMap()
14+
) : CinemaData {
15+
override operator fun get(property: String): Any? =
16+
__localContext[property]
17+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package io.github.ermadmi78.kobby.cinema.api.kobby.server.model.resolver
2+
3+
import io.github.ermadmi78.kobby.cinema.api.kobby.server.model.data.ActorData
4+
import io.github.ermadmi78.kobby.cinema.api.kobby.server.model.data.FilmData
5+
6+
/**
7+
* Created on 07.02.2026
8+
*
9+
* @author Dmitry Ermakov (ermadmi78@gmail.com)
10+
*/
11+
interface FilmResolutionModel {
12+
suspend fun actors(source: FilmData): List<ActorData>
13+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package io.github.ermadmi78.kobby.cinema.api.kobby.server.model.resolver
2+
3+
import io.github.ermadmi78.kobby.cinema.api.kobby.server.model.data.FilmData
4+
5+
/**
6+
* Created on 07.02.2026
7+
*
8+
* @author Dmitry Ermakov (ermadmi78@gmail.com)
9+
*/
10+
interface MutationResolutionModel {
11+
suspend fun createFilm(title: String): FilmData
12+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package io.github.ermadmi78.kobby.cinema.api.kobby.server.model.resolver
2+
3+
import io.github.ermadmi78.kobby.cinema.api.kobby.server.model.data.FilmData
4+
5+
/**
6+
* Created on 07.02.2026
7+
*
8+
* @author Dmitry Ermakov (ermadmi78@gmail.com)
9+
*/
10+
interface QueryResolutionModel {
11+
suspend fun film(id: Long): FilmData?
12+
13+
suspend fun films(): List<FilmData>
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package io.github.ermadmi78.kobby.cinema.api.kobby.server.model.resolver
2+
3+
import io.github.ermadmi78.kobby.cinema.api.kobby.server.model.data.FilmData
4+
import kotlinx.coroutines.flow.Flow
5+
6+
/**
7+
* Created on 07.02.2026
8+
*
9+
* @author Dmitry Ermakov (ermadmi78@gmail.com)
10+
*/
11+
interface SubscriptionResolutionModel {
12+
suspend fun filmCreated(): Flow<FilmData>
13+
}

0 commit comments

Comments
 (0)