Skip to main content

wme_models/
lib.rs

1#![doc = include_str!("../README.md")]
2
3/// Article types including Article and StructuredArticle.
4pub mod article;
5
6/// Content types including ArticleBody, Image, and License.
7pub mod content;
8
9/// Schema envelope for version compatibility.
10pub mod envelope;
11
12/// Error types for model operations.
13pub mod error;
14
15/// Metadata types including EventMetadata, EventType, and identifiers.
16pub mod metadata;
17
18/// Reference and citation types.
19pub mod reference;
20
21/// Structured content types including Infobox, Section, and Table.
22pub mod structured;
23
24/// Version and editor information types.
25pub mod version;
26
27/// Request parameter types for API queries.
28pub mod request;
29
30pub use article::{Article, ProjectRef, StructuredArticle, Visibility};
31pub use content::{ArticleBody, Image, License};
32pub use envelope::ArticleEnvelope;
33pub use error::ModelError;
34pub use metadata::{
35    BatchInfo, ChunkInfo, EventMetadata, EventType, Language, Namespace, Project, ProjectInfo,
36    ProjectType, RealtimeBatchInfo, RealtimeProject, SimplifiedLanguage, SimplifiedNamespace, Size,
37    SnapshotInfo,
38};
39pub use reference::{Citation, Reference};
40pub use request::{Filter, FilterValue, RequestParams};
41pub use structured::{Infobox, Section, Table, TableReference};
42pub use version::{
43    ArticleSize, Editor, MaintenanceTags, PreviousVersion, Protection, ReferenceNeed,
44    ReferenceRisk, RevertRisk, Scores, Version,
45};
46
47use serde::{Deserialize, Serialize};
48
49/// Wikidata entity reference.
50///
51/// # Examples
52///
53/// ```
54/// use wme_models::WikidataEntity;
55///
56/// let entity = WikidataEntity {
57///     identifier: "Q42".to_string(),
58///     url: "https://www.wikidata.org/entity/Q42".to_string(),
59/// };
60///
61/// assert_eq!(entity.identifier, "Q42");
62/// ```
63#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
64pub struct WikidataEntity {
65    /// Entity identifier (e.g., "Q42")
66    pub identifier: String,
67    /// Wikidata URL
68    pub url: String,
69}
70
71/// Wikidata entity reference with aspects (used in Realtime API).
72///
73/// Aspects indicate how the entity is used in the article:
74/// - "S" - Sitelinks are used
75/// - "L" - Label is used
76/// - "D" - Description is used
77/// - "C" - Statements are used
78/// - "X" - All aspects are used
79/// - "O" - Something else is used
80#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
81pub struct RealtimeWikidataEntity {
82    /// Entity identifier (e.g., "Q42")
83    pub identifier: String,
84    /// Wikidata URL
85    pub url: String,
86    /// Usage aspects (e.g., "S", "O", "C")
87    pub aspects: Vec<String>,
88}
89
90/// Wikidata entity usage information.
91///
92/// # Examples
93///
94/// ```
95/// use wme_models::WikidataEntityUsage;
96///
97/// let usage = WikidataEntityUsage {
98///     identifier: "P31".to_string(),
99///     url: "https://www.wikidata.org/entity/P31".to_string(),
100///     aspects: vec!["C".to_string()],
101/// };
102/// ```
103#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
104pub struct WikidataEntityUsage {
105    /// Entity identifier
106    pub identifier: String,
107    /// Wikidata URL
108    pub url: String,
109    /// Usage aspects (e.g., "S", "O", "C")
110    pub aspects: Vec<String>,
111}
112
113/// Category reference.
114///
115/// Categories group articles by topic within Wikimedia projects.
116///
117/// # Examples
118///
119/// ```
120/// use wme_models::Category;
121///
122/// let category = Category {
123///     name: "Category:Mammals".to_string(),
124///     url: "https://en.wikipedia.org/wiki/Category:Mammals".to_string(),
125/// };
126/// ```
127#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
128pub struct Category {
129    /// Category name
130    pub name: String,
131    /// Category URL
132    pub url: String,
133}
134
135/// Template reference.
136///
137/// Templates are reusable wikitext snippets used across articles.
138#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
139pub struct Template {
140    /// Template name
141    pub name: String,
142    /// Template URL
143    pub url: String,
144}
145
146/// Redirect reference.
147///
148/// Redirects are alternative names that point to this article.
149#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
150pub struct Redirect {
151    /// Target article name
152    pub name: String,
153    /// Target URL
154    pub url: String,
155}
156
157/// Link within content.
158///
159/// Links connect articles within and across Wikimedia projects.
160#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
161pub struct Link {
162    /// Link text
163    pub text: String,
164    /// Link URL
165    pub url: String,
166}
167
168/// Snapshot identifier: {language}{project}_namespace_{number}
169///
170/// # Examples
171///
172/// ```
173/// use wme_models::SnapshotIdentifier;
174///
175/// // Create from components
176/// let id = SnapshotIdentifier::new("en", "wiki", 0);
177/// assert_eq!(id.to_string(), "enwiki_namespace_0");
178///
179/// // Parse from string
180/// let id: SnapshotIdentifier = "enwiki_namespace_0".parse().unwrap();
181/// assert_eq!(id.language, "en");
182/// assert_eq!(id.project, "wiki");
183/// assert_eq!(id.namespace, 0);
184///
185/// // Use predefined constants
186/// let enwiki = SnapshotIdentifier::enwiki_namespace_0();
187/// let dewiki = SnapshotIdentifier::dewiki_namespace_0();
188/// ```
189#[derive(Debug, Clone, PartialEq, Eq, Hash)]
190pub struct SnapshotIdentifier {
191    /// Language code (e.g., "en", "de")
192    pub language: String,
193    /// Project code (e.g., "wiki", "wiktionary")
194    pub project: String,
195    /// Namespace number
196    pub namespace: u32,
197}
198
199impl SnapshotIdentifier {
200    /// Create a new snapshot identifier.
201    ///
202    /// # Examples
203    ///
204    /// ```
205    /// use wme_models::SnapshotIdentifier;
206    ///
207    /// let id = SnapshotIdentifier::new("fr", "wiki", 0);
208    /// assert_eq!(id.to_string(), "frwiki_namespace_0");
209    /// ```
210    pub fn new(language: &str, project: &str, namespace: u32) -> Self {
211        Self {
212            language: language.to_string(),
213            project: project.to_string(),
214            namespace,
215        }
216    }
217
218    /// English Wikipedia articles (namespace 0).
219    pub fn enwiki_namespace_0() -> Self {
220        Self::new("en", "wiki", 0)
221    }
222
223    /// German Wikipedia articles.
224    pub fn dewiki_namespace_0() -> Self {
225        Self::new("de", "wiki", 0)
226    }
227}
228
229impl std::str::FromStr for SnapshotIdentifier {
230    type Err = error::ModelError;
231
232    /// Parse from string (e.g., "enwiki_namespace_0").
233    fn from_str(s: &str) -> Result<Self, Self::Err> {
234        let parts: Vec<&str> = s.split("_namespace_").collect();
235        if parts.len() != 2 {
236            return Err(error::ModelError::InvalidSnapshotId(s.to_string()));
237        }
238
239        let namespace = parts[1]
240            .parse::<u32>()
241            .map_err(|_| error::ModelError::InvalidSnapshotId(s.to_string()))?;
242
243        let lang_project = parts[0];
244
245        // Extract language and project by matching known project suffixes
246        // Order matters: check longer names first (wiktionary before wiki)
247        let project_suffixes = [
248            "wiktionary",
249            "wikibooks",
250            "wikinews",
251            "wikiquote",
252            "wikisource",
253            "wikiversity",
254            "wikivoyage",
255            "commons",
256            "wiki",
257        ];
258
259        let (language, project) = project_suffixes
260            .iter()
261            .find_map(|&suffix| {
262                lang_project
263                    .strip_suffix(suffix)
264                    .map(|lang| (lang.to_string(), suffix.to_string()))
265            })
266            .ok_or_else(|| error::ModelError::InvalidSnapshotId(s.to_string()))?;
267
268        Ok(Self {
269            language,
270            project,
271            namespace,
272        })
273    }
274}
275
276impl std::fmt::Display for SnapshotIdentifier {
277    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
278        write!(
279            f,
280            "{}{}_namespace_{}",
281            self.language, self.project, self.namespace
282        )
283    }
284}