apollo-rs icon indicating copy to clipboard operation
apollo-rs copied to clipboard

Extend compiler values with custom data types

Open allancalix opened this issue 1 year ago • 0 comments

Description

I'm interested in what the current thinking is on how apollo-compiler handles custom scalars. Is there any interest in the compiler providing a mechanism for extending the compiler with their custom scalar types (beyond the primitives like String, Int, etc)?

I know the compiler already supports finding custom scalars and the specifiedBy directive but does not provide any ability to parse/handle scalar types outside of the primitives.

At a high-level I'm thinking that apollo-compiler will expose a trait as an extension point: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=3c1c35224adb1f75486f97d6dfd8812e

use std::collections::HashMap;
use chrono::DateTime;

struct DateScalar {}

struct DateParser {}

struct DateTimeScalar {}

struct DateTimeParser {}

enum CustomScalar {
    DateTime(chrono::DateTime<chrono::offset::FixedOffset>),
    Date(DateScalar),
}

trait ScalarProvider<T> {
    fn parse(&self, input: &str) -> Result<T, Box<dyn std::error::Error>>;
}

impl ScalarProvider<CustomScalar> for DateTimeParser {
    fn parse(&self, input: &str) -> Result<CustomScalar, Box<dyn std::error::Error>> {
        Ok(CustomScalar::DateTime(DateTime::parse_from_rfc3339(input)?))
    }
}

impl ScalarProvider<CustomScalar> for DateParser {
    fn parse(&self, input: &str) -> Result<CustomScalar, Box<dyn std::error::Error>> {
        Ok(CustomScalar::Date(DateScalar{}))
    }
}

The compiler would then provide an interface along the lines of:

compiler.add_custom_scalar_provider(provider);

Then ideally values could be typed by a convenient method like what exists for fields:

// on fields
pub fn ty(&self, db: &dyn HirDatabase) -> Option<Type>

// for arguments: https://docs.rs/apollo-compiler/0.9.2/apollo_compiler/database/hir/struct.Argument.html#method.value
// lookup the primitive value + typename
// try and find a provider for type
// parse and return the highest fidelity version possible for the value (falling back to primitive scalar)
pub fn typed_value(&self, db: &dyn HirDatabase) -> Option<ExtendedValue>

allancalix avatar May 31 '23 23:05 allancalix