Skip to content

Commit 04590c1

Browse files
committed
graph: Implement custom deserialise logic for Link to enable file link resolver
1 parent b510a8c commit 04590c1

File tree

1 file changed

+71
-15
lines changed

1 file changed

+71
-15
lines changed

graph/src/data/subgraph/mod.rs

Lines changed: 71 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -116,21 +116,24 @@ impl DeploymentHash {
116116
pub fn new(s: impl Into<String>) -> Result<Self, String> {
117117
let s = s.into();
118118

119-
// Enforce length limit
120-
if s.len() > 46 {
121-
return Err(s);
122-
}
119+
// This section is being temporarily commented out. This is to allow file link resolver to work
120+
// TODO(krishna): Figure out how to do this better or remove this check
123121

124-
// Check that the ID contains only allowed characters.
125-
if !s.chars().all(|c| c.is_ascii_alphanumeric() || c == '_') {
126-
return Err(s);
127-
}
122+
// // Enforce length limit
123+
// if s.len() > 46 {
124+
// return Err(s);
125+
// }
128126

129-
// Allow only deployment id's for 'real' subgraphs, not the old
130-
// metadata subgraph.
131-
if s == "subgraphs" {
132-
return Err(s);
133-
}
127+
// // Check that the ID contains only allowed characters.
128+
// if !s.chars().all(|c| c.is_ascii_alphanumeric() || c == '_') {
129+
// return Err(s);
130+
// }
131+
132+
// // Allow only deployment id's for 'real' subgraphs, not the old
133+
// // metadata subgraph.
134+
// if s == "subgraphs" {
135+
// return Err(s);
136+
// }
134137

135138
Ok(DeploymentHash(s))
136139
}
@@ -397,12 +400,65 @@ impl From<HashMap<Word, Value>> for DataSourceContext {
397400
}
398401

399402
/// IPLD link.
400-
#[derive(Clone, Debug, Default, Hash, Eq, PartialEq, Deserialize)]
403+
#[derive(Clone, Debug, Default, Hash, Eq, PartialEq)]
401404
pub struct Link {
402-
#[serde(rename = "/")]
403405
pub link: String,
404406
}
405407

408+
/// Custom deserializer for Link
409+
/// This handles both formats:
410+
/// 1. Simple string: "schema.graphql" or "subgraph.yaml" which is used in [`FileLinkResolver`]
411+
/// FileLinkResolver is used in local development environments
412+
/// 2. IPLD format: { "/": "Qm..." } which is used in [`IpfsLinkResolver`]
413+
impl<'de> de::Deserialize<'de> for Link {
414+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
415+
where
416+
D: de::Deserializer<'de>,
417+
{
418+
struct LinkVisitor;
419+
420+
impl<'de> de::Visitor<'de> for LinkVisitor {
421+
type Value = Link;
422+
423+
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
424+
formatter.write_str("string or map with '/' key")
425+
}
426+
427+
fn visit_str<E>(self, value: &str) -> Result<Link, E>
428+
where
429+
E: de::Error,
430+
{
431+
Ok(Link {
432+
link: value.to_string(),
433+
})
434+
}
435+
436+
fn visit_map<A>(self, mut map: A) -> Result<Link, A::Error>
437+
where
438+
A: de::MapAccess<'de>,
439+
{
440+
let mut link = None;
441+
442+
while let Some(key) = map.next_key::<String>()? {
443+
if key == "/" {
444+
if link.is_some() {
445+
return Err(de::Error::duplicate_field("/"));
446+
}
447+
link = Some(map.next_value()?);
448+
} else {
449+
return Err(de::Error::unknown_field(&key, &["/"]));
450+
}
451+
}
452+
453+
link.map(|l: String| Link { link: l })
454+
.ok_or_else(|| de::Error::missing_field("/"))
455+
}
456+
}
457+
458+
deserializer.deserialize_any(LinkVisitor)
459+
}
460+
}
461+
406462
impl<S: ToString> From<S> for Link {
407463
fn from(s: S) -> Self {
408464
Self {

0 commit comments

Comments
 (0)