Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#137] Add support for multiple schema files #138

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion juniper-from-schema-build-tests/file/build.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
fn main() {
juniper_from_schema_build::configure_for_file("schema.graphql")
juniper_from_schema_build::configure_for_files(vec!["schema/*.graphql"])
.context_type("()")
.error_type("MyError")
.compile()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ schema {
}

type Query {
ping: Boolean!
foo: Foo
}
3 changes: 3 additions & 0 deletions juniper-from-schema-build-tests/file/schema/schema2.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
type Foo {
ping: Boolean!
}
16 changes: 8 additions & 8 deletions juniper-from-schema-build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,19 +73,19 @@ pub fn configure_for_schema_literal(schema: &str) -> CodeGen {
}

/// Simple compilation of a GraphQL schema file.
pub fn compile_file<P: AsRef<Path>>(path: P) -> Result<(), Box<dyn Error>> {
configure_for_file(path).compile()
pub fn compile_files<P: AsRef<Path>>(paths: Vec<P>) -> Result<(), Box<dyn Error>> {
configure_for_files(paths).compile()
}

/// Configure a [`CodeGen`] with a GraphQL schema file.
///
/// [`CodeGen`]: struct.CodeGen.html
pub fn configure_for_file<P: AsRef<Path>>(path: P) -> CodeGen {
pub fn configure_for_files<P: AsRef<Path>>(paths: Vec<P>) -> CodeGen {
let root = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
let path = root.join(path);
let paths = paths.into_iter().map(|path| root.join(path)).collect();

CodeGen {
schema: SchemaLocation::File(path),
schema: SchemaLocation::Files(paths),
context_type: None,
error_type: None,
}
Expand All @@ -101,7 +101,7 @@ pub struct CodeGen {

#[derive(Debug)]
enum SchemaLocation {
File(PathBuf),
Files(Vec<PathBuf>),
Literal(String),
}

Expand Down Expand Up @@ -132,8 +132,8 @@ impl CodeGen {
let dest_path = Path::new(&out_dir).join("juniper_from_schema_graphql_schema.rs");

let mut code_gen = match self.schema {
SchemaLocation::File(path) => {
juniper_from_schema_code_gen::CodeGen::build_from_schema_file(path)
SchemaLocation::Files(paths) => {
juniper_from_schema_code_gen::CodeGen::build_from_schema_files(paths)
}
SchemaLocation::Literal(schema) => {
juniper_from_schema_code_gen::CodeGen::build_from_schema_literal(schema)
Expand Down
1 change: 1 addition & 0 deletions juniper-from-schema-code-gen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ graphql-parser = "0.3"
proc-macro2 = "1"
heck = "0.3"
colored = "1.8"
glob = "0.3"

[dev_dependencies]
version-sync = "0.8"
47 changes: 37 additions & 10 deletions juniper-from-schema-code-gen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ pub struct CodeGen {
}

impl CodeGen {
pub fn build_from_schema_file(path: PathBuf) -> CodeGenBuilder {
pub fn build_from_schema_files(paths: Vec<PathBuf>) -> CodeGenBuilder {
CodeGenBuilder {
schema: SchemaLocation::File(path),
schema: SchemaLocation::Files(paths),
context_type: None,
error_type: None,
}
Expand All @@ -52,12 +52,32 @@ impl CodeGen {
}

pub fn generate_code(self) -> Result<proc_macro2::TokenStream, Error> {
let (schema, schema_path) = match self.schema {
SchemaLocation::File(path) => (
std::fs::read_to_string(&path).map_err(Error::Io)?,
Some(path),
),
SchemaLocation::Literal(schema) => (schema, None),
let (schema, schema_paths) = match self.schema {
SchemaLocation::Files(glob_patterns) => {
// Each input path is a glob pattern, expand each one and concat
// them all together
let mut paths: Vec<PathBuf> = Vec::new();
for path in glob_patterns {
let globbed_paths = glob::glob(
path.to_str()
.expect("Invalid UTF-8 characters in file name"),
)
.map_err(Error::SchemaPathError)?;
for path in globbed_paths {
let path = path.map_err(Error::SchemaGlobError)?;
paths.push(path);
}
}

// Read each schema file and put it all in one string
let schema: String = paths
.iter()
.map(|path| std::fs::read_to_string(&path))
.collect::<Result<_, _>>()
.map_err(Error::Io)?;
(schema, paths)
}
SchemaLocation::Literal(schema) => (schema, Vec::new()),
};

let doc = match parse_schema(&schema) {
Expand All @@ -84,7 +104,8 @@ impl CodeGen {
eprintln!("{}", tokens);
}

if let Some(path) = schema_path {
// Force a Rust recompile whenever the schema changes
for path in schema_paths {
include_literal_schema(&mut tokens, path.as_path());
}

Expand Down Expand Up @@ -118,6 +139,10 @@ fn include_literal_schema(tokens: &mut proc_macro2::TokenStream, schema_path: &P

#[derive(Debug)]
pub enum Error {
/// User passed an invalid glob pattern
SchemaPathError(glob::PatternError),
/// Glob pattern couldn't be expanded (e.g. permission denied)
SchemaGlobError(glob::GlobError),
SchemaParseError(graphql_parser::schema::ParseError),
CodeGenErrors {
errors: Vec<error::Error>,
Expand All @@ -129,6 +154,8 @@ pub enum Error {
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::SchemaPathError(inner) => write!(f, "{}", inner),
Error::SchemaGlobError(inner) => write!(f, "{}", inner),
Error::SchemaParseError(inner) => write!(f, "{}", inner),
Error::CodeGenErrors { errors, schema } => {
assert!(
Expand Down Expand Up @@ -186,7 +213,7 @@ impl CodeGenBuilder {

#[derive(Debug)]
enum SchemaLocation {
File(PathBuf),
Files(Vec<PathBuf>),
Literal(String),
}

Expand Down
4 changes: 2 additions & 2 deletions juniper-from-schema-proc-macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ use parse_input::GraphqlSchemaFromFileInput;
#[proc_macro]
pub fn graphql_schema_from_file(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let GraphqlSchemaFromFileInput {
schema_path,
schema_paths,
context_type,
error_type,
} = match syn::parse::<GraphqlSchemaFromFileInput>(input) {
Ok(p) => p,
Err(e) => return e.to_compile_error().into(),
};

let mut builder = CodeGen::build_from_schema_file(schema_path);
let mut builder = CodeGen::build_from_schema_files(schema_paths);
if let Some(context_type) = context_type {
builder = builder.context_type(context_type);
}
Expand Down
6 changes: 4 additions & 2 deletions juniper-from-schema-proc-macro/src/parse_input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use syn::{

#[derive(Debug)]
pub struct GraphqlSchemaFromFileInput {
pub schema_path: PathBuf,
pub schema_paths: Vec<PathBuf>,
pub error_type: Option<Type>,
pub context_type: Option<Type>,
}
Expand Down Expand Up @@ -56,7 +56,9 @@ impl Parse for GraphqlSchemaFromFileInput {
}

Ok(GraphqlSchemaFromFileInput {
schema_path,
// Only supporting single paths for macro, since long term we're
// moving towards the build.rs style
schema_paths: vec![schema_path],
error_type,
context_type,
})
Expand Down