Created
February 26, 2025 10:35
-
-
Save otobrglez/5625ef89bb932401b071cfed05ca3741 to your computer and use it in GitHub Desktop.
GraphQL in Scala 3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package si.ogrodje.flow.gql | |
import scala.annotation.targetName | |
object GQL: | |
private type Name = String | |
private type Arguments = Map[Name, Value] | |
private val emptyArguments: Arguments = Map.empty | |
private type Fields = List[Field] | |
private val emptyFields: Fields = List.empty | |
extension (arguments: Arguments) | |
def render: String = | |
Option | |
.when(arguments.nonEmpty)(arguments.map((k, v) => s"$k: ${v.render}").mkString("(", ", ", ")")) | |
.getOrElse("") | |
enum Value: | |
case StringValue(value: String) extends Value | |
case IntValue(value: Int) extends Value | |
case FloatValue(value: Float) extends Value | |
case BooleanValue(value: Boolean) extends Value | |
case ListValue(value: List[Value]) extends Value | |
case Obj(fields: Map[Name, Value] = Map.empty) extends Value | |
case Literal(value: String) extends Value | |
case NullValue extends Value | |
final def render: String = this match | |
case StringValue(value) => s""""$value"""" | |
case IntValue(value) => value.toString | |
case FloatValue(value) => value.toString | |
case BooleanValue(value) => value.toString | |
case Value.ListValue(value) => value.map(_.render).mkString("[", ", ", "]") | |
case Obj(value) => value.map((k, v) => s"$k: ${v.render}").mkString("{", ", ", "}") | |
case Literal(value) => value | |
case NullValue => "null" | |
import Value.* | |
final protected case class Field( | |
name: Name, | |
arguments: Arguments = emptyArguments, | |
fields: Fields = emptyFields | |
): | |
def render(indent: Int = 0): String = | |
val indentStr = " " * indent | |
val subFields = Option | |
.when(fields.nonEmpty)(fields.map(_.render(indent + 1)).mkString(" {\n", "\n", s"\n$indentStr}")) | |
.getOrElse("") | |
indentStr + name + arguments.render + subFields | |
def field(name: Name): Field = Field(name) | |
def field(name: Name, fields: Field*): Field = Field(name, fields = fields.toList) | |
def field(name: Name, fields: List[Field]): Field = Field(name, fields = fields) | |
def field(name: Name, arguments: Arguments, fields: Field*): Field = Field(name, arguments, fields.toList) | |
def field(name: Name, arguments: Arguments, fields: List[Field]): Field = Field(name, arguments, fields = fields) | |
def argument[V <: Value](name: Name, value: V): Arguments = emptyArguments ++ Map(name -> value) | |
def argument[V <: Value](kv: (Name, Value)*): Arguments = emptyArguments ++ kv.toMap | |
@targetName("argumentInt") | |
def argument(kv: (Name, Int)*): Arguments = emptyArguments ++ kv.map((k, v) => k -> IntValue(v)) | |
@targetName("argumentString") | |
def argument(kv: (Name, String)*): Arguments = emptyArguments ++ kv.map((k, v) => k -> StringValue(v)) | |
def arguments(kv: (Name, Value)*): Arguments = emptyArguments ++ kv.toMap | |
@targetName("argumentsString") | |
def arguments(kv: (Name, String)*): Arguments = emptyArguments ++ kv.map((k, v) => k -> StringValue(v)) | |
@targetName("argumentsInt") | |
def arguments(kv: (Name, Int)*): Arguments = emptyArguments ++ kv.map((k, v) => k -> IntValue(v)) | |
extension (field: Field) def ++(other: Field): List[Field] = List(field, other) | |
final class Query private ( | |
name: Name, | |
arguments: Map[Name, Value] = Map.empty, | |
fields: List[Field] = List.empty | |
): | |
def render: String = | |
val fieldsPart = fields.map(_.render()).mkString("\n\n") | |
s"query $name${arguments.render} {\n$fieldsPart\n}" | |
object Query: | |
def apply(name: Name): Query = new Query(name) | |
def apply(name: Name, fields: Field*): Query = new Query(name, fields = fields.toList) | |
def apply(name: Name, fields: List[Field]): Query = new Query(name, fields = fields) | |
def apply(name: Name, arguments: Arguments, fields: Field*): Query = new Query(name, arguments, fields.toList) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment