wikibase 0.7.6

A library to access Wikibase
Documentation
#![deny(
//    missing_docs,
    missing_debug_implementations,
    missing_copy_implementations,
    trivial_casts,
    trivial_numeric_casts,
    unsafe_code,
    unstable_features,
    unused_import_braces,
    unused_qualifications
)]

use crate::error::WikibaseError;
use crate::lexeme::{LexemeForm, LexemeSense};
use crate::locale_string::LocaleString;
use crate::sitelink::SiteLink;
use crate::statement::Statement;

pub trait FromJson {
    /// Serializes an array of locale strings (e.g. aliases)
    ///
    /// # JSON structure:
    ///
    /// {"aliases": {"en", [{"language": "en", "value": "Alias 1"},
    /// {"language": "en", "value": "Alias 2"}, ... ]}}
    fn locale_string_array_from_json(
        item: &serde_json::Value,
        key: &str,
    ) -> Result<Vec<LocaleString>, WikibaseError> {
        let mut aliases = vec![];

        let lang_object = match item[key].as_object() {
            Some(value) => value,
            None => return Err(WikibaseError::Serialization("Locale object".to_string())),
        };

        for (language, string_array_json) in lang_object.iter() {
            let string_array = match string_array_json.as_array() {
                Some(value) => value,
                None => return Err(WikibaseError::Serialization("Locale array".to_string())),
            };

            for item_json in string_array.iter() {
                match item_json["value"].as_str() {
                    Some(value) => {
                        aliases.push(LocaleString::new(language.to_string(), value.to_string()))
                    }
                    None => return Err(WikibaseError::Serialization("Locale value".to_string())),
                }
            }
        }

        Ok(aliases)
    }

    /// Serialize single locale strings from JSON
    ///
    /// Takes a serde-JSON value and returns a vector of locale strings inside
    /// of a result.
    fn locale_strings_from_json(
        item: &serde_json::Value,
        key: &str,
    ) -> Result<Vec<LocaleString>, WikibaseError> {
        let mut labels = vec![];

        let label_object = match item.get(key) {
            Some(value) => match value.as_object() {
                Some(object) => object,
                None => {
                    return Err(WikibaseError::Serialization(
                        "Locale string object not valid".to_string(),
                    ));
                }
            },
            None => {
                return Err(WikibaseError::Serialization(format!(
                    "Key \"{}\" not found in object",
                    key
                )));
            }
        };
        for (_, string_object) in label_object.iter() {
            labels.push(LocaleString::new_from_json(string_object)?);
        }

        Ok(labels)
    }

    /// Serialize statements from JSON
    ///
    /// Function that takes a json value (an object) and deserializes all statements.
    /// The statements are stored under the "claims" key. The first array has
    /// property IDs as keys, with all statements for that property as values.
    fn statements_from_json(item: &serde_json::Value) -> Result<Vec<Statement>, WikibaseError> {
        let statements_array = match item["claims"]
            .as_object()
            .or(item["statements"].as_object())
        {
            Some(value) => value,
            None => {
                /*
                Not all things (eg Lexeme forms) require claims
                return Err(WikibaseError::Serialization(
                    "Key \"claims\" missing in json object".to_string(),
                ));
                */
                return Ok(vec![]);
            }
        };

        let mut statements = vec![];

        for (_, property_statements) in statements_array.iter() {
            let property_statements_array = match property_statements.as_array() {
                Some(value) => value,
                None => return Err(WikibaseError::Serialization("Statement array".to_string())),
            };

            for property_statement in property_statements_array.iter() {
                statements.push(Statement::new_from_json(property_statement)?);
            }
        }

        Ok(statements)
    }

    /// Serialize sitelinks from JSON
    ///
    /// Takes a serde-JSON value and returns a Result that contains either a
    /// error or a Option. Properties for example don't contain sitelinks, so
    /// the option will be None. If a Wikibase-item has sitelinks the Option
    /// will contain a vector of Sitelinks.
    fn sitelinks_from_json(
        item: &serde_json::Value,
    ) -> Result<Option<Vec<SiteLink>>, WikibaseError> {
        let sitelinks_array = match item.get("sitelinks") {
            Some(value) => match value.as_object() {
                Some(value_object) => value_object,
                None => {
                    return Err(WikibaseError::Serialization(
                        "Key \"sitelinks\" missing in json object".to_string(),
                    ));
                }
            },
            None => return Ok(None),
        };

        let mut sitelinks = vec![];

        for (site_id, sitelink_object_json) in sitelinks_array.iter() {
            let sitelink_object = match sitelink_object_json.as_object() {
                Some(value) => value,
                None => {
                    return Err(WikibaseError::Serialization(
                        "Error serializing sitelink object".to_string(),
                    ));
                }
            };

            let title = match sitelink_object["title"].as_str() {
                Some(value) => value,
                None => {
                    return Err(WikibaseError::Serialization(
                        "Error serializing sitelink title".to_string(),
                    ));
                }
            };

            let badges = match sitelink_object["badges"].as_array() {
                Some(value) => Self::string_vector_from_json(value)?,
                None => {
                    return Err(WikibaseError::Serialization(
                        "Error serializing badges array".to_string(),
                    ));
                }
            };

            let sitelink = SiteLink::new(site_id.to_string(), title.to_string(), badges);
            sitelinks.push(sitelink);
        }

        Ok(Some(sitelinks))
    }

    /// Serialize a vector of strings from JSON
    ///
    /// Takes a serde-JSON value and returns a vector of Strings or an error
    /// inside of a Result.
    fn string_vector_from_json(
        json_values: &Vec<serde_json::Value>,
    ) -> Result<Vec<String>, WikibaseError> {
        let mut values = vec![];

        for json_value in json_values {
            let value = match json_value.as_str() {
                Some(value) => value,
                None => {
                    return Err(WikibaseError::Serialization(
                        "Error serializing string vector".to_string(),
                    ));
                }
            };

            values.push(value.to_string());
        }

        Ok(values)
    }

    fn forms_from_json(json: &serde_json::Value) -> Result<Vec<LexemeForm>, WikibaseError> {
        match json["forms"].as_array() {
            Some(forms) => {
                let mut ret = vec![];
                for lexeme_form in forms.iter() {
                    ret.push(LexemeForm::new_from_json(lexeme_form)?)
                }
                Ok(ret)
            }
            None => Ok(vec![]),
        }
    }

    fn senses_from_json(json: &serde_json::Value) -> Result<Vec<LexemeSense>, WikibaseError> {
        match json["senses"].as_array() {
            Some(senses) => {
                let mut ret = vec![];
                for lexeme_sense in senses.iter() {
                    ret.push(LexemeSense::new_from_json(lexeme_sense)?)
                }
                Ok(ret)
            }
            None => Ok(vec![]),
        }
    }
}

pub trait ToJson {
    fn locale_strings_to_json(&self, locale_strings: &[LocaleString]) -> serde_json::Value {
        let mut field = json!({});
        locale_strings
            .iter()
            .for_each(|x| field[x.language()] = json!(x));
        field
    }

    fn aliases_to_json(&self, aliases: &[LocaleString]) -> serde_json::Value {
        let mut field = json!({});
        aliases.iter().for_each(|x| {
            let lang = x.language();
            if field[&lang].as_array_mut().is_none() {
                field[&lang] = json!([])
            };
            field[lang].as_array_mut().unwrap().push(json!(x));
        });
        field
    }

    fn sitelinks_to_json(&self, sitelinks: &Option<Vec<SiteLink>>) -> serde_json::Value {
        let mut field = json!({});
        if let Some(sitelinks) = sitelinks {
            sitelinks.iter().for_each(|x| field[x.site()] = json!(x));
        }
        field
    }

    fn statements_to_json(&self, statements: &[Statement]) -> serde_json::Value {
        let mut field = json!({});
        statements.iter().for_each(|x| {
            let prop = x.main_snak().property();
            if field[&prop].as_array_mut().is_none() {
                field[&prop] = json!([])
            };
            field[prop].as_array_mut().unwrap().push(json!(x));
        });
        field
    }
}