graphql-client icon indicating copy to clipboard operation
graphql-client copied to clipboard

Error in importing .graphql files generated in the build process

Open noritada opened this issue 5 years ago • 6 comments

I am trying to use a .graphql file generated in the build process using build.rs instead of a static one.

However, changing lines

#[derive(GraphQLQuery)]
#[graphql(
    schema_path = "src/schema.graphql",
    query_path = "src/query.graphql",
)]
struct Something;

into

#[derive(GraphQLQuery)]
#[graphql(
    schema_path = concat!(env!("OUT_DIR"), "/schema.graphql"),
    query_path = "src/query.graphql",
)]
struct Something;

results in a following error (and subsequent errors).

error: proc-macro derive panicked
 --> src/main.rs:8:10
  |
8 | #[derive(GraphQLQuery)]
  |          ^^^^^^^^^^^^
  |
  = help: message: Attribute is well formatted: Error("expected literal")

(Is this a limitation of this library or a syntactic limitation of Rust?)

IMHO generating and importing .graphql files is not a rare case and it would be nice if we can have such code or some other alternative options. (If graphql-rust already have some ways to do this, sorry.)

Many thanks,

noritada avatar Aug 10 '20 14:08 noritada

Hi there! This is indeed not supported, but this is an interesting use case. I will mark this as a feature, and let's keep this issue as the place to discuss this use case.

tomhoule avatar Aug 10 '20 15:08 tomhoule

One question we should clarify: do build scripts run before proc macros? I m pretty sure it happens in this order but I'm not 100% sure.

tomhoule avatar Aug 10 '20 15:08 tomhoule

@tomhoule Thank you very much!

Yes. Build scripts run before normal compilation process of .rs files including proc macros. My build.rs is just as simple as following code (just a downloader) and this creates target/debug/build/<package>-<hash>/out/schema.graphql correctly before cargo aborts with the error reported above.

use anyhow::*;

fn main() -> std::result::Result<(), anyhow::Error> {
    let url = "https://example.com/path/to/schema.graphql";

    let mut resp = reqwest::get(url)?;

    let out_dir = std::env::var_os("OUT_DIR").unwrap();
    let schema_file_path = std::path::Path::new(&out_dir).join("schema.graphql");
    let mut schema_file = std::fs::File::create(schema_file_path)?;
    resp.copy_to(&mut schema_file)?;

    println!("cargo:rerun-if-changed=build.rs");

    Ok(())
}

noritada avatar Aug 10 '20 16:08 noritada

Yes it seems to me like we could support this. Unfortunately I personally don't have a lot of time to work on graphql-client these days, but I would be happy to review a PR :) I'll post here if I find the time to work on this myself.

tomhoule avatar Aug 10 '20 20:08 tomhoule

Maybe something like a special variable that we would detect in the attributes, something like:

#[derive(GraphQLQuery)]
#[graphql(
    schema_path = "${OUT_DIR}/union_schema.graphql",
    query_path = "${OUT_DIR}/union_query.graphql",
)]
pub struct UnionQuery;

(or something less ugly)

tomhoule avatar Aug 10 '20 20:08 tomhoule

In Rust 1.54.0, function-like macros become able to be used in attributes like this:

#[path = concat!(env!("OUT_DIR"), "/generated.rs")]
mod generated;

So, how about syntax like this (as I showed in this issue first)?

#[derive(GraphQLQuery)]
#[graphql(
    schema_path = concat!(env!("OUT_DIR"), "/union_schema.graphql"),
    query_path = concat!(env!("OUT_DIR"), "/union_query.graphql"),
)]
pub struct UnionQuery;

This notation is more verbose than an idea in the above comment, but is flexible and compatible with the notation that can be used for attributes included in Rust itself. If it is good, I would like to try to implement.

noritada avatar Jul 29 '21 18:07 noritada