Skip to content

Commit a8191ec

Browse files
Update Juniper to 0.16.1
The update was easier than expected. Here are some of the bigger changes: - Our custom graphql scalars needed some rewriting, as they are defined differently now. - Lots duplicate methods were removed where the main function was defined in a normal `impl` block and the `graphql_object` impl block contained a method with same name and just called the first one. With this update, Juniper automatically adds all methods defined in the special impl block as normal methods, so this dance is not necessary anymore. - This also updates GraphiQL, which looks nicer now. The changelog mentions that this requires websocket integration now, but I can't find any information about this and everything seems to work. - The generated schema seems to have a deterministic order, which is great. - Also see below. I ran `graphql-inspector diff` on schema.graphql and the following changes were printed. For one, that means no one has to manually review schema.graphql: lots of stuff moved around, but hardly anything actually changed. Below I explain every change. ✖ Type DateTimeUtc was removed ✔ Type DateTime was added ✖ Field AuthorizedEvent.created changed type from DateTimeUtc! to DateTime! ✖ Field AuthorizedEvent.tobiraDeletionTimestamp changed type from DateTimeUtc to DateTime ✖ Input field Filters.end changed type from DateTimeUtc to DateTime ✖ Input field Filters.start changed type from DateTimeUtc to DateTime ✖ Field SearchEvent.created changed type from DateTimeUtc! to DateTime! ✖ Field SearchEvent.endTime changed type from DateTimeUtc to DateTime ✖ Field SearchEvent.startTime changed type from DateTimeUtc to DateTime ✖ Field Series.created changed type from DateTimeUtc to DateTime ✖ Field SyncedEventData.endTime changed type from DateTimeUtc to DateTime ✖ Field SyncedEventData.startTime changed type from DateTimeUtc to DateTime ✖ Field SyncedEventData.updated changed type from DateTimeUtc! to DateTime! The integration of `chrono` was slightly adjusted to better comply with public standards. See graphql-rust/juniper#1010 Not really a problem for us, I just adjusted the relay config. ✖ AuthorizedEventData object type no longer implements Node interface ✖ SyncedEventData object type no longer implements Node interface Removed some useless and wrong `impl = NodeValue` attributes, that were ignored before and now error. This was a mistake, those types cannot implement `Node` as they don't have an ID. I am confused how this compiled before. ✖ Type RealmNameSourceBlock was removed ✖ Field RealmNameFromBlock.block changed type from RealmNameSourceBlock! to Block! ✖ PlaylistBlock object type no longer implements RealmNameSourceBlock interface ✖ SeriesBlock object type no longer implements RealmNameSourceBlock interface ✖ VideoBlock object type no longer implements RealmNameSourceBlock interface Removed `RealmNameSourceBlock` interface: it did not serve any practical purpose. It only hinted at the fact that not all blocks can be used as name source, but again, not actually needed for API or type safety. And making it work was annoying. ✖ Type for argument order on field User.myVideos changed from EventSortOrder to EventSortOrder! This is now using a proper "default value" that GraphQL understands. It's `foo: Baz! = ...` which is correct according to the GraphQL spec. The argument can still be omitted, in which case the default is used. Curiously, GraphiQL does not seem to understand that yet. In any case, the runtime behavior did not change. ⚠ AuthorizedPlaylist object implements Node interface ⚠ Series object implements Node interface `Series` and `AuthorizedPlaylist` implement `Node` now. This was just an oversight before and caused compiler errors after the update. ⚠ Default value [] was added to argument newRealms on field Mutation.mountSeries The runtime behavior was like this already, but now it's properly specified in the schema. ✔ Description A string in different languages on type TranslatedString has changed to A string in different languages. Added a '.' at the end.
1 parent fffda02 commit a8191ec

File tree

15 files changed

+724
-897
lines changed

15 files changed

+724
-897
lines changed

backend/Cargo.lock

Lines changed: 34 additions & 89 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ hyper-rustls = { version = "0.26.0", features = ["http2"] }
4242
hyper-util = { version = "0.1.3", features = ["client", "server", "http1", "http2"] }
4343
isahc = { version = "1", features = ["static-ssl"] }
4444
iso8601 = "0.6.1"
45-
juniper = { version = "0.15.10", default-features = false, features = ["chrono", "schema-language"] }
45+
juniper = { version = "0.16.1", default-features = false, features = ["chrono", "schema-language", "anyhow", "backtrace"] }
4646
libz-sys = { version = "1", features = ["static"] }
4747
meilisearch-sdk = "0.24.3"
4848
mime_guess = { version = "2", default-features = false }

backend/src/api/common.rs

Lines changed: 23 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use bincode::Options;
2+
use juniper::{GraphQLScalar, InputValue, ScalarValue};
23
use serde::{Deserialize, Serialize};
34

45
use crate::{
@@ -59,7 +60,11 @@ super::util::impl_object_with_dummy_field!(NotAllowed);
5960
/// serialization format from `bincode`, a compact binary serializer. Of course
6061
/// we could also have serialized it as JSON and base64 encoded it then, but
6162
/// that would be a waste of network bandwidth.
62-
#[derive(Debug, Clone)]
63+
#[derive(Debug, Clone, GraphQLScalar)]
64+
#[graphql(
65+
description = "An opaque cursor used for pagination",
66+
parse_token(String),
67+
)]
6368
pub(crate) struct Cursor(String);
6469

6570
impl Cursor {
@@ -85,39 +90,32 @@ impl Cursor {
8590
.deserialize_from(b64reader)
8691
.map_err(|e| err::invalid_input!("given cursor is invalid: {}", e))
8792
}
88-
}
8993

90-
#[juniper::graphql_scalar(
91-
name = "Cursor",
92-
description = "An opaque cursor used for pagination",
93-
)]
94-
impl<S> GraphQLScalar for Cursor
95-
where
96-
S: juniper::ScalarValue,
97-
{
98-
fn resolve(&self) -> juniper::Value {
94+
fn to_output<S: ScalarValue>(&self) -> juniper::Value<S> {
9995
juniper::Value::scalar(self.0.clone())
10096
}
10197

102-
fn from_input_value(value: &juniper::InputValue) -> Option<Self> {
103-
value.as_string_value().map(|s| Self(s.into()))
104-
}
105-
106-
fn from_str<'a>(value: juniper::ScalarToken<'a>) -> juniper::ParseScalarResult<'a, S> {
107-
<String as juniper::ParseScalarValue<S>>::from_str(value)
98+
fn from_input<S: ScalarValue>(input: &InputValue<S>) -> Result<Self, String> {
99+
let s = input.as_string_value().ok_or("expected string")?;
100+
Ok(Self(s.into()))
108101
}
109102
}
110103

111-
104+
// TODO: This uses `graphql_scalar` instead of `derive(GraphQLScalar)` because
105+
// the type `ExtraMetadata` is defined in the `db` module and adding GraphQL
106+
// code there seems wrong. However, I feel like we should move some types
107+
// around anyway since we encountered problems like this before.
112108
#[juniper::graphql_scalar(
113109
name = "ExtraMetadata",
114110
description = "Arbitrary metadata for events/series. Serialized as JSON object.",
111+
with = Self,
112+
parse_token(String),
115113
)]
116-
impl<S> GraphQLScalar for ExtraMetadata
117-
where
118-
S: juniper::ScalarValue
119-
{
120-
fn resolve(&self) -> juniper::Value {
114+
#[allow(dead_code)]
115+
pub type ApiExtraMetadata = ExtraMetadata;
116+
117+
impl ExtraMetadata {
118+
fn to_output<S: ScalarValue>(&self) -> juniper::Value<S> {
121119
use juniper::Value;
122120

123121
std::iter::once(("dcterms", &self.dcterms))
@@ -138,16 +136,10 @@ where
138136
.pipe(Value::Object)
139137
}
140138

141-
fn from_input_value(value: &juniper::InputValue) -> Option<Self> {
139+
fn from_input<S: ScalarValue>(input: &InputValue<S>) -> Result<Self, String> {
142140
// I did not want to waste time implementing this now, given that we
143141
// likely never use it.
144-
let _ = value;
142+
let _ = input;
145143
todo!("ExtraMetadata cannot be used as input value yet")
146144
}
147-
148-
fn from_str<'a>(value: juniper::ScalarToken<'a>) -> juniper::ParseScalarResult<'a, S> {
149-
// See `from_input_value`
150-
let _ = value;
151-
todo!()
152-
}
153145
}

0 commit comments

Comments
 (0)