negezor / shikimori-rust

A Rust 🦀 wrapper for Shikimori API
MIT License
1 stars 0 forks source link

cynic::QueryFragment tries to use default schema #1

Open t1ltxz-gxd opened 7 months ago

t1ltxz-gxd commented 7 months ago

Build output:

error: This derive is trying to use the default schema, but it doesn't look like you've registered any schemas.  See the cynic documentation on regsistering schemas if you need help.
  --> shikimori/src/main.rs:20:10
   |
20 | #[derive(cynic::QueryFragment, Debug)]
   |          ^^^^^^^^^^^^^^^^^^^^
   |
   = note: this error originates in the derive macro `cynic::QueryFragment` (in Nightly builds, run with -Z macro-backtrace for more info)
error: This derive is trying to use the default schema, but it doesn't look like you've registered any schemas.  See the cynic documentation on regsistering schemas if you need help.
  --> shikimori/src/main.rs:27:10
   |
27 | #[derive(cynic::QueryFragment, Debug)]
   |          ^^^^^^^^^^^^^^^^^^^^
   |
   = note: this error originates in the derive macro `cynic::QueryFragment` (in Nightly builds, run with -Z macro-backtrace for more info)
   error[E0599]: no function or associated item named `build` found for struct `AnimesQuery` in the current scope
  --> shikimori/src/main.rs:42:29
   |
22 | pub struct AnimesQuery {
   | ---------------------- function or associated item `build` not found for this struct
...
42 |         .query(AnimesQuery::build(AnimesQueryVariables {
   |                             ^^^^^ function or associated item not found in `AnimesQuery`
   |
   = help: items from traits can only be used if the trait is implemented and in scope
   = note: the following traits define an item `build`, perhaps you need to implement one of them:
           candidate #1: `QueryBuilder`
           candidate #2: `MutationBuilder`
           candidate #3: `SubscriptionBuilder`

My code taken from the example use case:

use chrono::{DateTime, Utc};

use shikimori::{client::ClientBuilder,
                cynic,
                graphql::{
                    anime::AnimeKind,
                    types::EntityOrder,
                    scalars::{AnimeStatusString},
                    schema
                }
};

#[derive(cynic::QueryVariables, Debug)]
pub struct AnimesQueryVariables {
    pub page: i32,
    pub status: AnimeStatusString,
    pub order: EntityOrder,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(graphql_type = "Query", variables = "AnimesQueryVariables")]
pub struct AnimesQuery {
    #[arguments(censored: false, page: $page, status: $status, order: $order)]
    pub animes: Vec<Anime>,
}

#[derive(cynic::QueryFragment, Debug)]
pub struct Anime {
    pub id: cynic::Id,
    pub franchise: Option<String>,
    pub episodes: i32,
    pub kind: Option<AnimeKind>,
    pub next_episode_at: Option<DateTime<Utc>>,
    pub url: String,
}

#[tokio::main]
async fn main() {
    let client = ClientBuilder::new().build();

    let response = client
        .query(AnimesQuery::build(AnimesQueryVariables {
            page: 1,
            status: AnimeStatusString::new("ongoing"),
            order: EntityOrder::Popularity,
        }))
        .await;

    dbg!(&response);
}

Here I only changed use scalars::{StatusString} to scalars::{AnimeStatusString}, cause the code was refactored but you forgot to update the example =) img img

negezor commented 7 months ago

The library is trying to simply be representations of the API, which is still unstable. After the changes, does the example work?

t1ltxz-gxd commented 7 months ago

I changed it a little bit and now I have Meitantei Conan as the answer. Below is the code that is currently working

use chrono::{DateTime, Utc};

use shikimori::{client::ClientBuilder,
                cynic,
                cynic::{Id, QueryFragment, QueryVariables, QueryBuilder},
                graphql::{
                    anime::AnimeKind,
                    types::EntityOrder,
                    scalars::{AnimeStatusString},
                    schema
                }
};

#[derive(QueryVariables, Debug)]
pub struct AnimesQueryVariables {
    pub page: i32,
    pub status: AnimeStatusString,
    pub order: EntityOrder,
}

#[derive(QueryFragment, Debug)]
#[cynic(graphql_type = "Query", variables = "AnimesQueryVariables", schema_path = "../schema.graphql")]
pub struct AnimesQuery {
    #[arguments(censored: false, page: $page, status: $status, order: $order)]
    pub animes: Vec<Anime>,
}

#[derive(QueryFragment, Debug)]
#[cynic(graphql_type = "Anime", variables = "AnimesQueryVariables", schema_path = "../schema.graphql")]
pub struct Anime {
    pub id: Id,
    pub franchise: Option<String>,
    pub episodes: i32,
    pub kind: Option<AnimeKind>,
    pub next_episode_at: Option<DateTime<Utc>>,
    pub url: String,
}

#[tokio::main]
async fn main() {
    let client = ClientBuilder::new().build();

    let response = client
        .query(AnimesQuery::build(AnimesQueryVariables {
            page: 1,
            status: AnimeStatusString::new("ongoing"),
            order: EntityOrder::Popularity,
        }))
        .await;

    dbg!(&response);
}

Console log:

Finished dev [unoptimized + debuginfo] target(s) in 0.04s
     Running `target/debug/shikimori`
[shikimori/src/main.rs:51:5] &response = Ok(
    GraphQlResponse {
        data: Some(
            AnimesQuery {
                animes: [
                    Anime {
                        id: Id(
                            "21",
                        ),
                        franchise: Some(
                            "one_piece",
                        ),
                        episodes: 0,
                        kind: Some(
                            Tv,
                        ),
                        next_episode_at: Some(
                            2024-05-05T00:30:00Z,
                        ),
                        url: "https://shikimori.one/animes/21-one-piece",
                    },
                    Anime {
                        id: Id(
                            "235",
                        ),
                        franchise: Some(
                            "detective_conan",
                        ),
                        episodes: 0,
                        kind: Some(
                            Tv,
                        ),
                        next_episode_at: Some(
                            2024-05-04T09:00:00Z,
                        ),
                        url: "https://shikimori.one/animes/z235-meitantei-conan",
                    },
                ],
            },
        ),
        errors: None,
    },
)

Process finished with exit code 0
t1ltxz-gxd commented 7 months ago

I had to download schema.graphql from shikimori to get the code to work

negezor commented 7 months ago

I've been thinking about how to make this point better, but haven't come to a conclusion yet. Maybe I should create a feature that will export the following code:

#[cfg(feature = "codegen")]
pub fn register_schema() {
    cynic_codegen::register_schema("shikimori")
        .from_sdl(include_str!("./schema.graphql"))
        .unwrap()
        .as_default()
        .unwrap();
}
t1ltxz-gxd commented 7 months ago

in my opinion, the build should affect derive so that library users do not need to download the schema for their code to work

t1ltxz-gxd commented 7 months ago

I noticed that r.n. there is a problem with the error Unresolved import: shikimori::graphql::schema [E0432]. Build should generate an exportable module schema for this to solve the problem 🐣

negezor commented 4 months ago

Now you can specify in build-dependencies:

[build-dependencies]
shikimori = { version = "0.4.0", features = ["register-graphql-schema"] }

And then in the build.rs

fn main() {
    shikimori::graphql::register_schema();
}
t1ltxz-gxd commented 4 months ago

smth wrong in the build.rs:

error[E0433]: failed to resolve: use of undeclared crate or module `shikimori`
 --> build.rs:2:5
  |
2 |     shikimori::graphql::register_schema();
  |     ^^^^^^^^^ use of undeclared crate or module `shikimori`
t1ltxz-gxd commented 4 months ago

*missclick

negezor commented 4 months ago

Was a dependency added with the register-graphql-schema feature enabled? It is better to duplicate 2 times for build and common dependencies.

# Cargo.toml

[dependencies]
shikimori = { version = "0.4.0" }

[build-dependencies]
shikimori = { version = "0.4.0", features = ["register-graphql-schema"] }
t1ltxz-gxd commented 4 months ago

Oooops! My bad, I added the feature to dependencies, not to build dependencies, but now I have a new error:

error[E0277]: the trait bound `i32: CoercesTo<std::option::Option<shikimori::graphql::schema::PositiveInt>>` is not satisfied
   --> src/service/external/api/shikimori/query.rs:27:10
    |
27  | #[derive(QueryFragment, Debug)]
    |          ^^^^^^^^^^^^^ the trait `CoercesTo<std::option::Option<shikimori::graphql::schema::PositiveInt>>` is not implemented for `i32`
    |
    = help: the following other types implement trait `CoercesTo<T>`:
              <i32 as CoercesTo<Vec<Vec<i32>>>>
              <i32 as CoercesTo<Vec<i32>>>
              <i32 as CoercesTo<i32>>
              <i32 as CoercesTo<std::option::Option<Vec<i32>>>>
              <i32 as CoercesTo<std::option::Option<Vec<std::option::Option<i32>>>>>
              <i32 as CoercesTo<std::option::Option<i32>>>
              <i32 as CoercesTo<std::option::Option<std::option::Option<i32>>>>
note: required by a bound in `queries::builders::InputBuilder::<'a, SchemaType, VariablesFields>::variable`
   --> /home/t1ltxz-gxd/.cargo/registry/src/index.crates.io-6f17d22bba15001f/cynic-3.7.0/src/queries/builders.rs:274:15
    |
272 |     pub fn variable<Type>(self, def: VariableDefinition<VariablesFields, Type>)
    |            -------- required by a bound in this associated function
273 |     where
274 |         Type: CoercesTo<SchemaType>,
    |               ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `InputBuilder::<'a, SchemaType, VariablesFields>::variable`
    = note: this error originates in the derive macro `QueryFragment` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0277`.

My query with problem:

#[derive(QueryFragment, Debug)] // 27 line
#[cynic(graphql_type = "Query", variables = "MyQueryVariables" )] // 28 line
pub struct MyQuery { // 29 line
    #[arguments(limit: $limit, page: $page, order: $order)] // 30 line
    pub animes: Vec<Anime>, // 31 line
    #[arguments(limit: $limit, page: $page, order: $order)] //32 line
    pub mangas: Vec<Manga>, // 33 line
    #[arguments(limit: $limit, page: $page)] // 34 line
    pub characters: Vec<Character>, // 35 line
} // 36 line

...

#[derive(QueryVariables, Debug)]
pub struct MyQueryVariables {
    pub page: i32,
    pub limit: i32,
    pub order: EntityOrder,
}
negezor commented 4 months ago

Shikimori now requires Scalar PositiveInt for page and limit

# A positive integer (>= 1)
scalar PositiveInt

type Query {
  animes(
    page: PositiveInt = 1

    # Maximum 50
    limit: PositiveInt = 2

    # ...
   ): [Anime!]!
}

You need to modify the query as follows

+ shikimori::graphql::scalars::PositiveInt;

#[derive(QueryFragment, Debug)] // 27 line
#[cynic(graphql_type = "Query", variables = "MyQueryVariables" )] // 28 line
pub struct MyQuery { // 29 line
    #[arguments(limit: $limit, page: $page, order: $order)] // 30 line
    pub animes: Vec<Anime>, // 31 line
    #[arguments(limit: $limit, page: $page, order: $order)] //32 line
    pub mangas: Vec<Manga>, // 33 line
    #[arguments(limit: $limit, page: $page)] // 34 line
    pub characters: Vec<Character>, // 35 line
} // 36 line

...

#[derive(QueryVariables, Debug)]
pub struct MyQueryVariables {
-    pub page: i32,
+    pub page: PositiveInt,
-    pub limit: i32,
+    pub limit: PositiveInt,
    pub order: EntityOrder,
}
MyQueryVariables {
  page: PositiveInt::new(1),
  limit: PositiveInt::new(10),
 // ...
}

P.S. Isn't that too big of a query in GraphQL? It will put a lot of load on the database.

t1ltxz-gxd commented 4 months ago

Ok, then schema can no longer be used for query variable:

error[E0433]: failed to resolve: use of undeclared crate or module `schema`
  --> src/service/external/api/shikimori/query.rs:13:10
   |
13 | #[derive(QueryVariables, Debug)]
   |          ^^^^^^^^^^^^^^ use of undeclared crate or module `schema`
   |
   = note: this error originates in the derive macro `QueryVariables` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing this module
t1ltxz-gxd commented 4 months ago

P.S. Isn't that too big of a query in GraphQL? It will put a lot of load on the database.

Lol, it turns out if you make a large request, the fields description, duration, english, episodes, episodes_aired, franchise, kind, next_episode_at, rating, score, season, status, synonyms in anime and description, english, franchise, kind, score in manga will be NULL

Btw,i split the query into several parts so as not to overload the database 😎

negezor commented 4 months ago

@t1ltxz-gxd Does the example in the README work? Well and I need more context on the query.