Packages

Gleam SDK for Dagger — type-safe pipelines via GraphQL codegen

Current section

Files

Jump to
dagger_gleam src dagger interpreter.gleam
Raw

src/dagger/interpreter.gleam

import dagger/client as dagger_client
import dagger/logger.{Debug}
import dagger/types.{
type Client, type DaggerOp, type Try, Fetch, Field, GDeferred, GList, GObject,
GString, Pure,
}
import gleam/dynamic/decode
import gleam/list
import gleam/result
pub fn run(op: DaggerOp(Try(a)), client: Client) -> Try(a) {
case op {
Pure(result) -> result
Fetch(fields, _decoder, next) -> {
let resolved_fields = resolve_fields(fields, client)
let query_string = types.serialize(resolved_fields)
use dynamic_data <- result.try(dagger_client.raw_query(
client,
query_string,
))
use _ <- result.try(check_errors(dynamic_data))
let next_op = next(dynamic_data)
run(next_op, client)
}
}
}
fn check_errors(dyn: decode.Dynamic) -> Result(Nil, types.QueryError) {
let errors_decoder =
decode.at(["errors"], decode.list(decode.at(["message"], decode.string)))
case decode.run(dyn, errors_decoder) {
Ok([_, ..] as msgs) ->
Error(
types.ExecutionError(
list.map(msgs, fn(m) { types.GraphQLError(message: m, path: []) }),
),
)
_ -> Ok(Nil)
}
}
fn resolve_fields(
fields: List(types.Field),
client: Client,
) -> List(types.Field) {
list.map(fields, fn(field) {
Field(
..field,
args: list.map(field.args, fn(arg) {
#(arg.0, resolve_value(arg.1, client))
}),
subfields: resolve_fields(field.subfields, client),
)
})
}
fn resolve_value(val: types.Value, client: Client) -> types.Value {
case val {
GDeferred(op) -> {
let id_op =
types.bind(op, fn(fields) {
Pure(list.append(fields, [Field("id", [], [])]))
})
case run_id_resolver(id_op, client) {
Ok(id) -> GString(id)
Error(_) -> panic as "Fallita risoluzione ID Dagger"
}
}
GList(items) -> GList(list.map(items, resolve_value(_, client)))
GObject(fields) ->
GObject(list.map(fields, fn(f) { #(f.0, resolve_value(f.1, client)) }))
_ -> val
}
}
fn run_id_resolver(
op: DaggerOp(List(types.Field)),
client: Client,
) -> Result(String, types.QueryError) {
let fields = types.get_query(op)
let query_string = types.serialize(fields)
logger.report(Debug("ID RESOLVER: " <> types.serialize(fields)))
use dynamic_data <- result.try(dagger_client.raw_query(client, query_string))
use _ <- result.try(check_errors(dynamic_data))
let path = types.make_path(fields)
decode.run(dynamic_data, decode.at(path, decode.string))
|> result.map_error(fn(_) {
types.DecodingError("Impossibile decodificare ID dall'oggetto")
})
}