Skip to content

Instantly share code, notes, and snippets.

@li1
Last active January 28, 2019 10:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save li1/d69770312e3358ce63236d58c5f6c624 to your computer and use it in GitHub Desktop.
Save li1/d69770312e3358ce63236d58c5f6c624 to your computer and use it in GitHub Desktop.
Transform 3DF pull query to nested graphQL expression
use std::collections::BTreeMap;
use std::hash::Hash;
#[derive(Debug)]
enum NestedVal<T: Eq + Hash> {
Map(BTreeMap<T, NestedVal<T>>),
Arr(Vec<NestedVal<T>>),
Val(T),
}
fn main() {
let data = vec![
vec![
"loans".to_string(),
"3".to_string(),
"amount".to_string(),
"200".to_string(),
],
vec![
"loans".to_string(),
"3".to_string(),
"from".to_string(),
"1".to_string(),
"name".to_string(),
"1".to_string(),
],
vec![
"loans".to_string(),
"3".to_string(),
"obs".to_string(),
"j".to_string(),
],
vec![
"loans".to_string(),
"3".to_string(),
"obs".to_string(),
"a".to_string(),
"10".to_string(),
],
vec![
"loans".to_string(),
"3".to_string(),
"obs".to_string(),
"b".to_string(),
"11".to_string(),
],
vec![
"loans".to_string(),
"3".to_string(),
"obs".to_string(),
"c".to_string(),
"12".to_string(),
],
vec![
"loans".to_string(),
"4".to_string(),
"amount".to_string(),
"300".to_string(),
],
];
let nested = paths_to_nested(data);
println!("{:?}", nested);
dbg!(squash_nested(nested));
}
fn paths_to_nested<T: Eq + Hash + Ord + std::fmt::Debug>(paths: Vec<Vec<T>>) -> NestedVal<T> {
let mut acc: BTreeMap<T, NestedVal<T>> = BTreeMap::new();
for mut path in paths {
let mut current_map = &mut acc;
let last_val = path.pop().unwrap();
let last_key = path.pop().unwrap();
for attribute in path {
let entry = current_map
.entry(attribute)
.or_insert_with(|| NestedVal::Map(BTreeMap::new()));
*entry = match entry {
NestedVal::Val(_) => NestedVal::Map(BTreeMap::new()),
NestedVal::Map(m) => NestedVal::Map(std::mem::replace(m, BTreeMap::new())),
NestedVal::Arr(_) => unreachable!(),
};
match entry {
NestedVal::Map(m) => current_map = m,
NestedVal::Val(_) => unreachable!(),
NestedVal::Arr(_) => unreachable!(),
};
}
current_map.insert(last_key, NestedVal::Val(last_val));
}
NestedVal::Map(acc)
}
fn squash_nested<T: Eq + Hash + Ord + std::fmt::Debug>(nested: NestedVal<T>) -> NestedVal<T> {
if let NestedVal::Map(m) = nested {
let new = m.into_iter().fold(BTreeMap::new(), |mut acc, (k, v)| {
let to_add = if let NestedVal::Map(nested_v) = v {
let nested_squashed_v: Vec<_> = nested_v
.into_iter()
.map(|(_nested_k, nested_v)| squash_nested(nested_v))
.collect();
NestedVal::Arr(nested_squashed_v)
} else {
v
};
acc.insert(k, to_add);
acc
});
NestedVal::Map(new)
} else {
nested
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment