Skip to content

Commit

Permalink
feat: implement server-side separation
Browse files Browse the repository at this point in the history
  • Loading branch information
uhyo committed Dec 31, 2023
1 parent 0f4c702 commit 4b7ea2e
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 36 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions crates/plugin/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ edition = "2021"
nitrogql-ast = { path = "../ast" }
graphql-builtins = { path = "../builtins" }
nitrogql-checker = { path = "../checker" }
nitrogql-config-file = { path = "../config-file" }
nitrogql-error = { path = "../error" }
nitrogql-parser = { path = "../parser" }
nitrogql-printer = { path = "../printer" }
Expand Down
4 changes: 3 additions & 1 deletion crates/plugin/src/model_plugin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use nitrogql_ast::{
value::Value,
TypeSystemDocument,
};
use nitrogql_config_file::TypeTarget;
use nitrogql_printer::{
ts_types::{ts_types_util::ts_union, TSType},
ResolverTypePrinterOptions,
Expand Down Expand Up @@ -167,8 +168,9 @@ directive @model(
let obj_type = TSType::TypeFunc(
Box::new(TSType::TypeVariable("Pick".into())),
vec![
TSType::NamespaceMember(
TSType::NamespaceMember3(
options.schema_root_namespace.clone(),
TypeTarget::ResolverOutput.to_string(),
def.name.name.into(),
),
ts_union(model_field_names.map(|n| TSType::StringLiteral(n.into()))),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import type { GraphQLResolveInfo } from "graphql";
import type * as Schema from "";
type __Resolver<Parent, Args, Context, Result> = (parent: Parent, args: Args, context: Context, info: GraphQLResolveInfo) => Result | Promise<Result>;
type __TypeResolver<Obj, Context, Result> = (object: Obj, context: Context, info: GraphQLResolveInfo) => Result | Promise<Result>;
type Int = Schema.Int;
type Float = Schema.Float;
type String = Schema.String;
type Boolean = Schema.Boolean;
type ID = Schema.ID;
type User = Pick<Schema.User, "id" | "name">;
type Post = Pick<Schema.Post, "id" | "title">;
type Int = Schema.__ResolverOutput.Int;
type Float = Schema.__ResolverOutput.Float;
type String = Schema.__ResolverOutput.String;
type Boolean = Schema.__ResolverOutput.Boolean;
type ID = Schema.__ResolverOutput.ID;
type User = Pick<Schema.__ResolverOutput.User, "id" | "name">;
type Post = Pick<Schema.__ResolverOutput.Post, "id" | "title">;
export type Resolvers<Context> = {
User: {
age: __Resolver<User, {}, Context, Int>;
Expand Down
38 changes: 27 additions & 11 deletions crates/printer/src/resolver_type_printer/printer.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
use std::{borrow::Cow, collections::HashMap};

use graphql_type_system::Schema;
use nitrogql_ast::{base::Pos, type_system::TypeSystemDefinition, TypeSystemDocument};
use nitrogql_ast::{
base::Pos,
type_system::{TypeDefinition, TypeSystemDefinition},
TypeSystemDocument,
};
use nitrogql_semantics::ast_to_type_system;
use sourcemap_writer::SourceMapWriter;

use crate::{
resolver_type_printer::visitor::{get_resolver_type, get_ts_type_for_resolver},
resolver_type_printer::visitor::{get_resolver_type, get_ts_type_for_resolver_output},
ts_types::{ts_types_util::ts_union, ObjectField, ObjectKey, TSType},
};

Expand Down Expand Up @@ -69,7 +73,7 @@ where
.iter()
.filter_map(|type_definition| match type_definition {
TypeSystemDefinition::TypeDefinition(type_definition) => {
let resolver_type = get_ts_type_for_resolver(type_definition, &context);
let resolver_type = get_ts_type_for_resolver_output(type_definition, &context);
Some((type_definition.name().name, resolver_type))
}
_ => None,
Expand All @@ -86,8 +90,14 @@ where
}
});

// Emit each schema type (resolver output variant) as a local type alias.
// This helps users to read generated types.
for type_definition in &document_for_resolvers.definitions {
if let TypeSystemDefinition::TypeDefinition(def) = type_definition {
if matches!(def, TypeDefinition::InputObject(_)) {
// input types can never be resolver outputs.
continue;
}
let ts_type = ts_types.get(def.name().name).unwrap();

self.writer.write("type ");
Expand Down Expand Up @@ -121,7 +131,9 @@ where

let type_names_type = ts_union(document_for_resolvers.definitions.iter().filter_map(
|type_definition| match type_definition {
TypeSystemDefinition::TypeDefinition(type_definition) => {
TypeSystemDefinition::TypeDefinition(type_definition)
if !matches!(type_definition, TypeDefinition::InputObject(_)) =>
{
Some(TSType::StringLiteral(type_definition.name().to_string()))
}
_ => None,
Expand All @@ -132,13 +144,17 @@ where
.definitions
.iter()
.filter_map(|type_definition| match type_definition {
TypeSystemDefinition::TypeDefinition(type_definition) => Some(ObjectField {
key: ObjectKey::from(type_definition.name()),
r#type: TSType::TypeVariable(type_definition.name().into()),
description: None,
readonly: false,
optional: false,
}),
TypeSystemDefinition::TypeDefinition(type_definition)
if !matches!(type_definition, TypeDefinition::InputObject(_)) =>
{
Some(ObjectField {
key: ObjectKey::from(type_definition.name()),
r#type: TSType::TypeVariable(type_definition.name().into()),
description: None,
readonly: false,
optional: false,
})
}
_ => None,
})
.collect(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@ import type { GraphQLResolveInfo } from "graphql";
import type * as Schema from "schema";
type __Resolver<Parent, Args, Context, Result> = (parent: Parent, args: Args, context: Context, info: GraphQLResolveInfo) => Result | Promise<Result>;
type __TypeResolver<Obj, Context, Result> = (object: Obj, context: Context, info: GraphQLResolveInfo) => Result | Promise<Result>;
type User = Omit<Schema.User, "__typename">;
type Bot = Omit<Schema.Bot, "__typename">;
type Post = Omit<Schema.Post, "__typename">;
type Query = Omit<Schema.Query, "__typename">;
type User = Omit<Schema.__ResolverOutput.User, "__typename">;
type Bot = Omit<Schema.__ResolverOutput.Bot, "__typename">;
type Post = Omit<Schema.__ResolverOutput.Post, "__typename">;
type Query = Omit<Schema.__ResolverOutput.Query, "__typename">;
type HasID = User | Bot;
type UserOrBot = User | Bot;
type UserType = Schema.UserType;
type UserSearchQuery = Schema.UserSearchQuery;
type UserType = Schema.__ResolverOutput.UserType;
export type Resolvers<Context> = {
User: {
id: __Resolver<User, {}, Context, ID>;
Expand Down Expand Up @@ -41,7 +40,7 @@ export type Resolvers<Context> = {
__resolveType: __TypeResolver<User | Bot, Context, "User" | "Bot">;
};
};
export type ResolverOutput<T extends "User" | "Bot" | "Post" | "Query" | "HasID" | "UserOrBot" | "UserType" | "UserSearchQuery"> =
export type ResolverOutput<T extends "User" | "Bot" | "Post" | "Query" | "HasID" | "UserOrBot" | "UserType"> =
{
User: User;
Bot: Bot;
Expand All @@ -50,6 +49,5 @@ export type ResolverOutput<T extends "User" | "Bot" | "Post" | "Query" | "HasID"
HasID: HasID;
UserOrBot: UserOrBot;
UserType: UserType;
UserSearchQuery: UserSearchQuery;
}[T];

27 changes: 18 additions & 9 deletions crates/printer/src/resolver_type_printer/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@ use nitrogql_ast::type_system::{
ArgumentsDefinition, InterfaceTypeDefinition, ObjectTypeDefinition, TypeDefinition,
UnionTypeDefinition,
};
use nitrogql_config_file::TypeTarget;

use super::printer::ResolverTypePrinterContext;

pub fn get_ts_type_for_resolver(
pub fn get_ts_type_for_resolver_output(
def: &TypeDefinition<'_>,
context: &ResolverTypePrinterContext,
) -> TSType {
let base_type = TSType::NamespaceMember(
let base_type = TSType::NamespaceMember3(
context.options.schema_root_namespace.clone(),
TypeTarget::ResolverOutput.to_string(),
def.name().name.to_string(),
);
match def {
Expand Down Expand Up @@ -57,17 +59,17 @@ pub fn get_resolver_type(

fn get_object_resolver_type(
def: &ObjectTypeDefinition<'_>,
_context: &ResolverTypePrinterContext,
context: &ResolverTypePrinterContext,
) -> Option<TSType> {
let parent_type = TSType::TypeVariable((&def.name).into());
let fields = def
.fields
.iter()
.map(|field| {
let arguments_type = field
.arguments
.as_ref()
.map_or_else(|| TSType::Object(vec![]), arguments_definition_to_ts);
let arguments_type = field.arguments.as_ref().map_or_else(
|| TSType::Object(vec![]),
|arguments| arguments_definition_to_ts(context, arguments),
);
let result_type = get_ts_type_of_type(&field.r#type, |name| {
TSType::TypeVariable((&name.name).into())
});
Expand Down Expand Up @@ -162,12 +164,19 @@ fn get_union_resolver_type(
Some(TSType::object(vec![("__resolveType", resolver_type, None)]))
}

fn arguments_definition_to_ts(arguments: &ArgumentsDefinition) -> TSType {
fn arguments_definition_to_ts(
context: &ResolverTypePrinterContext,
arguments: &ArgumentsDefinition,
) -> TSType {
TSType::object(arguments.input_values.iter().map(|argument| {
(
ObjectKey::from(&argument.name),
get_ts_type_of_type(&argument.r#type, |name| {
TSType::TypeVariable((&name.name).into())
TSType::NamespaceMember3(
context.options.schema_root_namespace.clone(),
TypeTarget::ResolverInput.to_string(),
name.name.to_string(),
)
}),
argument.description.as_ref().map(|s| s.to_string()),
)
Expand Down

0 comments on commit 4b7ea2e

Please sign in to comment.