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}