use url::Url;
pub use whatlang::Lang;
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct Document {
title: String,
body: String,
summary: Option<String>,
created_at: Option<chrono::DateTime<chrono::Utc>>,
updated_at: Option<chrono::DateTime<chrono::Utc>>,
}
impl Document {
pub async fn new<T: IntoDocument>(source: T) -> anyhow::Result<Self> {
source.into_document().await
}
pub fn language(&self) -> Option<whatlang::Lang> {
whatlang::detect_lang(&self.body)
}
pub fn from_parts(title: impl Into<String>, body: impl Into<String>) -> Self {
Self {
title: title.into(),
body: body.into(),
summary: None,
created_at: None,
updated_at: None,
}
}
pub fn set_summary(&mut self, summary: impl Into<String>) {
self.summary = Some(summary.into());
}
pub fn set_created_at(&mut self, created_at: chrono::DateTime<chrono::Utc>) {
self.created_at = Some(created_at);
}
pub fn set_updated_at(&mut self, updated_at: chrono::DateTime<chrono::Utc>) {
self.updated_at = Some(updated_at);
}
pub fn title(&self) -> &str {
&self.title
}
pub fn body(&self) -> &str {
&self.body
}
}
impl std::fmt::Display for Document {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}\n{}", self.title, self.body)
}
}
#[async_trait::async_trait]
pub trait IntoDocument {
async fn into_document(self) -> anyhow::Result<Document>;
}
#[async_trait::async_trait]
impl IntoDocument for String {
async fn into_document(self) -> anyhow::Result<Document> {
Ok(Document::from_parts("", self))
}
}
#[async_trait::async_trait]
impl IntoDocument for &String {
async fn into_document(self) -> anyhow::Result<Document> {
Ok(Document::from_parts("", self.to_string()))
}
}
#[async_trait::async_trait]
impl IntoDocument for &str {
async fn into_document(self) -> anyhow::Result<Document> {
Ok(Document::from_parts("", self.to_string()))
}
}
#[async_trait::async_trait]
impl IntoDocument for Document {
async fn into_document(self) -> anyhow::Result<Document> {
Ok(self)
}
}
#[async_trait::async_trait]
impl IntoDocument for Url {
async fn into_document(self) -> anyhow::Result<Document> {
super::page::get_article(self).await
}
}
#[async_trait::async_trait]
pub trait IntoDocuments {
async fn into_documents(self) -> anyhow::Result<Vec<Document>>;
}
#[async_trait::async_trait]
impl<T: IntoDocument + Send + Sync, I> IntoDocuments for I
where
I: IntoIterator<Item = T> + Send + Sync,
<I as IntoIterator>::IntoIter: Send + Sync,
{
async fn into_documents(self) -> anyhow::Result<Vec<Document>> {
let mut documents = Vec::new();
for document in self {
documents.push(document.into_document().await?);
}
Ok(documents)
}
}