Skip to content

Commit

Permalink
fix!: Limit built-in scalars to the ones defined by the spec
Browse files Browse the repository at this point in the history
Partially resolves #83 by splitting up the current `BuiltInScalars`
into two:

- The actual built-in scalars as defined by the spec
- Some extended scalars supported by KGraphQL

BREAKING CHANGE: Those extended scalars are no longer automatically
added to a schema but must be manually included using `extendedScalars()`
if needed.
  • Loading branch information
stuebingerb committed Jan 12, 2025
1 parent 725260b commit 2331c76
Show file tree
Hide file tree
Showing 8 changed files with 42 additions and 12 deletions.
3 changes: 3 additions & 0 deletions docs/content/Reference/Type System/scalars.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,6 @@ stringScalar<UUID> {
}
}
```

In addition to the built-in types, KGraphQL provides support for `Long` and `Short` which can be added to a schema
using `extendedScalars()`.
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.apurebase.kgraphql.schema

import com.apurebase.kgraphql.request.isIntrospectionType
import com.apurebase.kgraphql.schema.builtin.BuiltInScalars
import com.apurebase.kgraphql.schema.directive.Directive
import com.apurebase.kgraphql.schema.introspection.TypeKind
import com.apurebase.kgraphql.schema.introspection.__Described
Expand Down Expand Up @@ -30,6 +29,8 @@ data class SchemaPrinterConfig(
)

class SchemaPrinter(private val config: SchemaPrinterConfig = SchemaPrinterConfig()) {
private val builtInScalarNames = setOf("Int", "Float", "String", "Boolean", "ID")

/**
* Returns the given [schema] in schema definition language (SDL). Types and fields are sorted
* ascending by their name and appear in order of their corresponding spec section, i.e.
Expand Down Expand Up @@ -229,7 +230,7 @@ class SchemaPrinter(private val config: SchemaPrinterConfig = SchemaPrinterConfi
private fun __Directive.isBuiltIn(): Boolean =
name in setOf(Directive.DEPRECATED.name, Directive.INCLUDE.name, Directive.SKIP.name)

private fun __Type.isBuiltInScalar(): Boolean = name in BuiltInScalars.entries.map { it.typeDef.name }
private fun __Type.isBuiltInScalar(): Boolean = name in builtInScalarNames

private fun __Type.implements(): String =
interfaces
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,20 @@ private const val BOOLEAN_DESCRIPTION =
"The Boolean scalar type represents true or false"

/**
* These scalars are created only for sake of documentation in introspection, not during execution
*
* https://spec.graphql.org/October2021/#sec-Scalars.Built-in-Scalars
*/
enum class BuiltInScalars(val typeDef: TypeDef.Scalar<*>) {
STRING(TypeDef.Scalar(String::class.defaultKQLTypeName(), String::class, STRING_COERCION, STRING_DESCRIPTION)),
SHORT(TypeDef.Scalar(Short::class.defaultKQLTypeName(), Short::class, SHORT_COERCION, SHORT_DESCRIPTION)),
INT(TypeDef.Scalar(Int::class.defaultKQLTypeName(), Int::class, INT_COERCION, INT_DESCRIPTION)),

// GraphQL does not differentiate between float and double, treat double like float
DOUBLE(TypeDef.Scalar(Float::class.defaultKQLTypeName(), Double::class, DOUBLE_COERCION, FLOAT_DESCRIPTION)),
FLOAT(TypeDef.Scalar(Float::class.defaultKQLTypeName(), Float::class, FLOAT_COERCION, FLOAT_DESCRIPTION)),
BOOLEAN(TypeDef.Scalar(Boolean::class.defaultKQLTypeName(), Boolean::class, BOOLEAN_COERCION, BOOLEAN_DESCRIPTION)),
}

enum class ExtendedBuiltInScalars(val typeDef: TypeDef.Scalar<*>) {
SHORT(TypeDef.Scalar(Short::class.defaultKQLTypeName(), Short::class, SHORT_COERCION, SHORT_DESCRIPTION)),
LONG(TypeDef.Scalar(Long::class.defaultKQLTypeName(), Long::class, LONG_COERCION, LONG_DESCRIPTION))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.apurebase.kgraphql.schema.dsl
import com.apurebase.kgraphql.schema.Publisher
import com.apurebase.kgraphql.schema.Schema
import com.apurebase.kgraphql.schema.SchemaException
import com.apurebase.kgraphql.schema.builtin.ExtendedBuiltInScalars
import com.apurebase.kgraphql.schema.dsl.operations.MutationDSL
import com.apurebase.kgraphql.schema.dsl.operations.QueryDSL
import com.apurebase.kgraphql.schema.dsl.operations.SubscriptionDSL
Expand Down Expand Up @@ -140,6 +141,12 @@ class SchemaBuilder internal constructor() {
booleanScalar(T::class, block)
}

fun extendedScalars() {
ExtendedBuiltInScalars.values().forEach {
model.addScalar(it.typeDef)
}
}

//================================================================================
// TYPE
//================================================================================
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,35 @@ class LongScalarTest {
@Test
fun testLongField() {
val schema = defaultSchema {
extendedScalars()
query("long") {
resolver { -> Long.MAX_VALUE }
}
}

val response = schema.executeBlocking("{long}")
val response = schema.executeBlocking("{ long }")
val long = deserialize(response).extract<Long>("data/long")
assertThat(long, equalTo(Long.MAX_VALUE))
}

@Test
fun testLongArgument() {
val schema = defaultSchema {
extendedScalars()
query("isLong") {
resolver { long: Long -> if (long > Int.MAX_VALUE) "YES" else "NO" }
resolver { long: Long ->
if (long > Int.MAX_VALUE) {
"YES"
} else {
"NO"
}
}
}
}

val isLong =
deserialize(schema.executeBlocking("{isLong(long: ${Int.MAX_VALUE.toLong() + 1})}")).extract<String>("data/isLong")
val isLong = deserialize(
schema.executeBlocking("{ isLong(long: ${Int.MAX_VALUE.toLong() + 1}) }")
).extract<String>("data/isLong")
assertThat(isLong, equalTo("YES"))
}

Expand All @@ -52,7 +61,7 @@ class LongScalarTest {
}

val value = Int.MAX_VALUE.toLong() + 2
val response = deserialize(schema.executeBlocking("{number(number: $value)}"))
val response = deserialize(schema.executeBlocking("{ number(number: $value) }"))
assertThat(response.extract<Long>("data/number"), equalTo(value))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ class GitHubIssue75 {
useDefaultPrettyPrinter = true
}

extendedScalars()

query("findTrace") {
resolver { traceID: String ->
Trace(
Expand Down Expand Up @@ -132,6 +134,6 @@ class GitHubIssue75 {
}
}
""", "{\"traceID\": \"646851f15cb2dad1\"}"
).let(::println)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -750,12 +750,12 @@ class SchemaBuilderTest {
@Test
fun `Short int types are mapped to Short Scalar`() {
val schema = defaultSchema {
extendedScalars()
query("shortQuery") {
resolver { -> 1.toShort() }
}
}


val typesIntrospection = deserialize(schema.executeBlocking("{__schema{types{name}}}"))
val types = typesIntrospection.extract<List<Map<String, String>>>("data/__schema/types")
val names = types.map { it["name"] }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,7 @@ class SchemaPrinterTest {
@Test
fun `schema with descriptions should be printed as expected if descriptions are included`() {
val schema = KGraphQL.schema {
extendedScalars()
type<TestObject> {
property(TestObject::name) {
description = "This is the name"
Expand Down Expand Up @@ -582,6 +583,12 @@ class SchemaPrinterTest {
subscription: Subscription
}
"The Long scalar type represents a signed 64-bit numeric non-fractional value"
scalar Long
"The Short scalar type represents a signed 16-bit numeric non-fractional value"
scalar Short
"Mutation object"
type Mutation {
"Add a test object"
Expand Down

0 comments on commit 2331c76

Please sign in to comment.