wikibase 0.7.6

A library to access Wikibase
Documentation
use serde_json::{json, Value};
use wiremock::matchers::query_param;
use wiremock::{Mock, MockServer, ResponseTemplate};

/// Minimal Wikidata siteinfo response for a mock server.
/// Sets wikibase-conceptbaseuri and wikibase-sparql to mock server URLs.
pub fn wikidata_siteinfo(server_uri: &str) -> Value {
    let sparql_url = format!("{}/sparql", server_uri);
    let conceptbaseuri = format!("{}/entity/", server_uri);
    json!({
        "batchcomplete": "",
        "query": {
            "general": {
                "sitename": "Wikidata",
                "dbname": "wikidatawiki",
                "wikibase-conceptbaseuri": conceptbaseuri,
                "wikibase-sparql": sparql_url
            },
            "namespaces": {
                "0":  {"id": 0,  "case": "first-letter", "content": "", "*": ""},
                "1":  {"id": 1,  "case": "first-letter", "*": "Talk", "canonical": "Talk"},
                "-1": {"id": -1, "case": "first-letter", "*": "Special", "canonical": "Special"}
            },
            "namespacealiases": [],
            "libraries": [],
            "extensions": [],
            "statistics": {}
        }
    })
}

/// Start a mock server responding to siteinfo requests with Wikidata-like data.
/// The conceptbaseuri and sparql endpoint are set to the mock server's own URI.
pub async fn start_wikidata_mock() -> MockServer {
    let server = MockServer::start().await;
    let siteinfo = wikidata_siteinfo(&server.uri());
    Mock::given(query_param("meta", "siteinfo"))
        .respond_with(ResponseTemplate::new(200).set_body_json(siteinfo))
        .mount(&server)
        .await;
    server
}

/// Minimal valid item JSON for a given ID.
pub fn minimal_item(id: &str) -> Value {
    json!({
        "type": "item",
        "id": id,
        "labels": {},
        "descriptions": {},
        "aliases": {},
        "sitelinks": {},
        "claims": {}
    })
}

/// Missing entity JSON for a given ID.
pub fn missing_entity(id: &str) -> Value {
    json!({"id": id, "missing": ""})
}

/// Minimal valid property JSON for a given ID.
pub fn minimal_property(id: &str) -> Value {
    json!({
        "type": "property",
        "id": id,
        "labels": {},
        "descriptions": {},
        "aliases": {},
        "claims": {},
        "datatype": "string"
    })
}

/// Build a wbgetentities API response wrapping a list of entity JSON values.
pub fn wbgetentities_response(entities: Vec<Value>) -> Value {
    let mut map = serde_json::Map::new();
    for entity in entities {
        let id = entity["id"].as_str().unwrap().to_string();
        map.insert(id, entity);
    }
    json!({"entities": Value::Object(map), "success": 1})
}

/// Q12345 entity (Count von Count) with the specific fields asserted by entity_serialization test.
pub fn q12345_entity() -> Value {
    json!({
        "type": "item",
        "id": "Q12345",
        "labels": {"en": {"language": "en", "value": "Count von Count"}},
        "descriptions": {"en": {"language": "en", "value": "character on Sesame Street"}},
        "aliases": {"en": [{"language": "en", "value": "The Count"}]},
        "sitelinks": {"enwiki": {"site": "enwiki", "title": "Count von Count", "badges": []}},
        "claims": {
            "P3478": [{
                "mainsnak": {
                    "snaktype": "value",
                    "property": "P3478",
                    "datavalue": {"value": "850116", "type": "string"}
                },
                "type": "statement",
                "rank": "normal"
            }]
        }
    })
}

/// Q42 entity (minimal).
pub fn q42_entity() -> Value {
    minimal_item("Q42")
}

/// L2 lexeme entity.
pub fn l2_entity() -> Value {
    json!({
        "type": "lexeme",
        "id": "L2",
        "lemmas": {"en": {"language": "en", "value": "the"}},
        "language": "Q1860",
        "lexicalCategory": "Q1084",
        "forms": [],
        "senses": [],
        "claims": {}
    })
}

/// Build a wbgetentities response for Q1-Q150 with Q10, Q20, ..., Q140 marked missing (14 missing, 136 valid).
pub fn q1_to_q150_response() -> Value {
    let missing_ids: std::collections::HashSet<usize> = (1..=14).map(|i| i * 10).collect();
    let mut entities = serde_json::Map::new();
    for n in 1..=150 {
        let id = format!("Q{}", n);
        let entity = if missing_ids.contains(&n) {
            missing_entity(&id)
        } else {
            minimal_item(&id)
        };
        entities.insert(id, entity);
    }
    json!({"entities": Value::Object(entities), "success": 1})
}

/// Build a wbgetentities response containing Q42 (valid), Q12345 (valid), Q50 (missing).
pub fn q42_q12345_q50_response() -> Value {
    wbgetentities_response(vec![
        q42_entity(),
        q12345_entity(),
        missing_entity("Q50"),
    ])
}