Skip to content

Commit

Permalink
initial setup for Relay Resolvers
Browse files Browse the repository at this point in the history
  • Loading branch information
zth committed Jun 19, 2024
1 parent 9296f0c commit 557dfe5
Show file tree
Hide file tree
Showing 15 changed files with 507 additions and 67 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
use std::fmt::Write;

use common::SourceLocationKey;
use docblock_shared::RELAY_RESOLVER_WEAK_OBJECT_DIRECTIVE;
use graphql_ir::reexport::Intern;
use relay_config::ProjectConfig;
use relay_transforms::relay_resolvers::get_resolver_info;
use common::NamedItem;
use relay_transforms::Programs;
use relay_transforms::is_operation_preloadable;
use relay_transforms::RESOLVER_BELONGS_TO_BASE_SCHEMA_DIRECTIVE;
use relay_typegen::rescript::NullabilityMode;
use relay_typegen::rescript_utils::capitalize_string;
use relay_typegen::rescript_utils::get_safe_key;
use relay_typegen::rescript_utils::print_type_reference;
use relay_typegen::rescript_utils::uncapitalize_string;
use schema::SDLSchema;
use schema::Schema;
use schema::TypeReference;
Expand Down Expand Up @@ -53,6 +57,7 @@ pub(crate) fn rescript_generate_extra_artifacts(
.filter_map(|artifact| artifact)
.collect();

// Schema assets file
let dummy_source_file = SourceLocationKey::Generated;

let mut content = String::from("/* @generated */\n@@warning(\"-30\")\n\n");
Expand Down Expand Up @@ -290,5 +295,101 @@ pub(crate) fn rescript_generate_extra_artifacts(

extra_artifacts.push(schema_assets_artifact);

// Relay Resolvers
for object in schema.get_objects() {
let mut has_resolvers = false;
let mut c = String::from("/* @generated */\n@@warning(\"-30\")\n\n");

for field in object.fields.iter().map(|field_id| schema.field(*field_id)) {
if let Some(Ok(resolver_info)) = get_resolver_info(schema, field, field.name.location)
{
if field
.directives
.named(*RESOLVER_BELONGS_TO_BASE_SCHEMA_DIRECTIVE)
.is_some() || field.name.item.to_string().starts_with("__relay_")
{
continue;
}

has_resolvers = true;

if !&field.arguments.is_empty() {
// Write args type
write!(c, "type {}ResolverArgs = {{\n", uncapitalize_string(&field.name.item.to_string())).unwrap();
field.arguments.iter().for_each(|argument| {
let (key, maybe_original_key) = get_safe_key(&argument.name.item.to_string());

writeln!(
c,
" {}{}: {},",
(match maybe_original_key {
Some(original_key) => format!("@as(\"{}\") ", original_key),
None => String::from(""),
}),
key,
print_type_reference(
&argument.type_,
&schema,
&project_config.typegen_config.custom_scalar_types,
true,
false,
&NullabilityMode::Option,
true
)
)
.unwrap();
});
write!(c, "}}\n").unwrap();
}

write!(c, "type {}Resolver = (", uncapitalize_string(&field.name.item.to_string())).unwrap();

// Case when the field is on a client extension type
if object.is_extension {
write!(c, "Relay{}Model.t, ", &object.name.item.to_string()).unwrap();

// Case @weak object
let _is_weak_object = object.directives.named(*RELAY_RESOLVER_WEAK_OBJECT_DIRECTIVE).is_some();
}

if !&field.arguments.is_empty() {
write!(c, "{}ResolverArgs", uncapitalize_string(&field.name.item.to_string())).unwrap();
}

let is_live = resolver_info.live;
let return_type = print_type_reference(
&field.type_,
&schema,
&project_config.typegen_config.custom_scalar_types,
true,
false,
&NullabilityMode::Option,
true
);
write!(
c, ") => {}\n\n",
if is_live {
format!("RescriptRelay.liveState<{}>", return_type)
} else {
return_type
}
).unwrap();
}
}

if has_resolvers {
let relay_resolvers_assets_artifact = Artifact {
artifact_source_keys: vec![],
path: project_config.create_path_for_artifact(dummy_source_file, format!("{}_relayResolvers_graphql.res", object.name.item.0)),
source_file: dummy_source_file,
content: crate::ArtifactContent::Generic {
content: c.as_bytes().to_vec(),
},
};

extra_artifacts.push(relay_resolvers_assets_artifact);
}
}

extra_artifacts
}
4 changes: 2 additions & 2 deletions compiler/crates/relay-transforms/src/relay_resolvers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ pub enum FragmentDataInjectionMode {
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
struct RelayResolverFieldMetadata {
pub struct RelayResolverFieldMetadata {
field_parent_type: StringKey,
import_path: StringKey,
import_name: Option<StringKey>,
Expand Down Expand Up @@ -610,7 +610,7 @@ pub struct ResolverInfo {
fragment_data_injection_mode: Option<FragmentDataInjectionMode>,
pub import_path: StringKey,
pub import_name: Option<StringKey>,
live: bool,
pub live: bool,
has_output_type: bool,
}

Expand Down
4 changes: 4 additions & 0 deletions compiler/crates/relay-typegen/src/rescript.rs
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,10 @@ fn ast_to_prop_value(
// These are ignored for now, but might be supported in the future.
None
}
AST::AssertFunctionType(a) => {
log::info!("fn type: {:#?}", a);
None
},
_ => None,
}
}
Expand Down
15 changes: 15 additions & 0 deletions compiler/crates/relay-typegen/src/rescript_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::ops::Add;

use common::ScalarName;
use common::WithLocation;
use docblock_shared::RELAY_RESOLVER_WEAK_OBJECT_DIRECTIVE;
use graphql_ir::reexport::Intern;
use graphql_ir::reexport::StringKey;
use graphql_ir::Argument;
Expand Down Expand Up @@ -510,6 +511,20 @@ pub fn print_type_reference(
}
}
),
Type::Object(id) => {
let object = schema.object(*id);
let weak = object.directives.iter().find(|d| {
d.name == *RELAY_RESOLVER_WEAK_OBJECT_DIRECTIVE
}).is_some();

if weak {
format!("Relay{}Model.t", object.name.item)
} else if object.is_extension {
format!("RescriptRelay.dataIdObject")
} else {
format!("RescriptRelay.dataId")
}
},
_ => String::from("RescriptRelay.any"),
},
nullable,
Expand Down
1 change: 1 addition & 0 deletions compiler/test-project-res/src/RelayUserModel.res
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
type t = {name: string}
50 changes: 50 additions & 0 deletions compiler/test-project-res/src/TestRelayResolverMulti.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* @RelayResolver UserMeta
* @weak
*/
type userMeta = {
name: string,
age: int,
}

/**
* @RelayResolver LocalUser
*/
let localUser = dataId => {
UserService.getById(dataId)
}

/**
* @RelayResolver Query.time(now: Boolean): String
*/
let time = () => "hello"

/**
* @RelayResolver LocalUser.bestFriend(from: Timestamp): LocalUser
*/
let bestFriend = () => "hello"

/**
* @RelayResolver UserMeta.greeting(show: Boolean!): String
*/
let greeting = () => "hello"

/**
* @RelayResolver User.meta(status: OnlineStatus!): UserMeta
*/
let meta = () => "hello"

/**
* @RelayResolver LocalUser.favoriteColors: [String!]
*/
let favoriteColors = user => {
[]
}

/**
* @RelayResolver User.friendCount: Int
* @live
*/
let friendCount = user => {
1
}
1 change: 1 addition & 0 deletions compiler/test-project-res/src/Test_query.res
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module Query = %relay(`
query TestQuery($status: OnlineStatus) {
time
users(status: $status) {
edges {
node {
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 557dfe5

Please sign in to comment.