Skip to content

Commit

Permalink
feat: mostly finish kolomoni_seeder crate, implement translation endp…
Browse files Browse the repository at this point in the history
…oints into kolomoni_api_client
  • Loading branch information
simongoricar committed Dec 8, 2024
1 parent 307c3a5 commit 8cada85
Show file tree
Hide file tree
Showing 18 changed files with 796 additions and 685 deletions.
1 change: 1 addition & 0 deletions kolomoni_api_client/src/api/dictionary/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod categories;
pub mod english;
pub mod slovene;
pub mod translation;
211 changes: 211 additions & 0 deletions kolomoni_api_client/src/api/dictionary/translation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
use kolomoni_core::{
api_models::{ErrorReason, TranslationCreationRequest, TranslationsErrorReason},
ids::{EnglishWordMeaningId, SloveneWordMeaningId},
};
use reqwest::StatusCode;
use thiserror::Error;

use crate::{
errors::{ClientError, ClientResult},
macros::{
handle_error_reasons_or_catch_unexpected_status,
handle_unexpected_error_reason,
handle_unexpected_status_code,
handlers,
},
request::RequestBuilder,
AuthenticatedClient,
};


pub struct TranslationRelationshipToCreate {
pub english_word_meaning: EnglishWordMeaningId,
pub slovene_word_meaning: SloveneWordMeaningId,
}


pub struct TranslationRelationshipToDelete {
pub english_word_meaning: EnglishWordMeaningId,
pub slovene_word_meaning: SloveneWordMeaningId,
}



#[derive(Debug, Error)]
pub enum TranslationRelationshipCreationError {
#[error("the provided english word meaning does not exist")]
EnglishWordMeaningNotFound,

#[error("the provided slovene word meaning does not exist")]
SloveneWordMeaningNotFound,

#[error("the corresponding translation relationship already exists")]
RelationshipAlreadyExists,

#[error(transparent)]
ClientError {
#[from]
error: ClientError,
},
}


#[derive(Debug, Error)]
pub enum TranslationRelationshipDeletionError {
#[error("the provided english word meaning does not exist")]
EnglishWordMeaningNotFound,

#[error("the provided slovene word meaning does not exist")]
SloveneWordMeaningNotFound,

#[error("the corresponding translation relationship does not exist")]
RelationshipNotFound,

#[error(transparent)]
ClientError {
#[from]
error: ClientError,
},
}



async fn create_translation_relationship(
client: &AuthenticatedClient,
translation_relationship_to_create: TranslationRelationshipToCreate,
) -> ClientResult<(), TranslationRelationshipCreationError> {
let response = RequestBuilder::post(client)
.endpoint_url("/dictionary/translations")
.json(&TranslationCreationRequest {
english_word_meaning_id: translation_relationship_to_create
.english_word_meaning
.into_uuid(),
slovene_word_meaning_id: translation_relationship_to_create
.slovene_word_meaning
.into_uuid(),
})
.send()
.await?;

let response_status = response.status();


if response_status == StatusCode::OK {
Ok(())
} else if response_status == StatusCode::BAD_REQUEST {
let error_reason = response.error_reason().await?;

match error_reason {
ErrorReason::Translations(translations_error_reason) => {
match translations_error_reason {
TranslationsErrorReason::EnglishWordMeaningNotFound => {
Err(TranslationRelationshipCreationError::EnglishWordMeaningNotFound)
}
TranslationsErrorReason::SloveneWordMeaningNotFound => {
Err(TranslationRelationshipCreationError::SloveneWordMeaningNotFound)
}
_ => handle_unexpected_error_reason!(translations_error_reason, response_status),
}
}
_ => handle_unexpected_error_reason!(error_reason, response_status),
}
} else if response_status == StatusCode::CONFLICT {
let translations_error_reason = response.translations_error_reason().await?;

match translations_error_reason {
TranslationsErrorReason::TranslationRelationshipAlreadyExists => {
Err(TranslationRelationshipCreationError::RelationshipAlreadyExists)
}
_ => handle_unexpected_error_reason!(translations_error_reason, response_status),
}
} else if response_status == StatusCode::FORBIDDEN {
handle_error_reasons_or_catch_unexpected_status!(response, [handlers::MissingPermissions]);
} else {
handle_unexpected_status_code!(response_status);
}
}


async fn delete_translation_relationship(
client: &AuthenticatedClient,
translation_relationship_to_delete: TranslationRelationshipToDelete,
) -> ClientResult<(), TranslationRelationshipDeletionError> {
let response = RequestBuilder::delete(client)
.endpoint_url_with_parameters(
"/dictionary/translations",
[
(
"english_word_meaning_id",
translation_relationship_to_delete
.english_word_meaning
.to_string(),
),
(
"slovene_word_meaning_id",
translation_relationship_to_delete
.slovene_word_meaning
.to_string(),
),
],
)
.send()
.await?;

let response_status = response.status();


if response_status == StatusCode::OK {
Ok(())
} else if response_status == StatusCode::BAD_REQUEST {
let translation_error_reason = response.translations_error_reason().await?;

match translation_error_reason {
TranslationsErrorReason::EnglishWordMeaningNotFound => {
Err(TranslationRelationshipDeletionError::EnglishWordMeaningNotFound)
}
TranslationsErrorReason::SloveneWordMeaningNotFound => {
Err(TranslationRelationshipDeletionError::SloveneWordMeaningNotFound)
}
_ => handle_unexpected_error_reason!(translation_error_reason, response_status),
}
} else if response_status == StatusCode::NOT_FOUND {
let translation_error_reason = response.translations_error_reason().await?;

match translation_error_reason {
TranslationsErrorReason::TranslationRelationshipNotFound => {
Err(TranslationRelationshipDeletionError::RelationshipNotFound)
}
_ => handle_unexpected_error_reason!(translation_error_reason, response_status),
}
} else if response_status == StatusCode::FORBIDDEN {
handle_error_reasons_or_catch_unexpected_status!(response, [handlers::MissingPermissions]);
} else {
handle_unexpected_status_code!(response_status);
}
}


pub struct TranslationsAuthenticatedApi<'c> {
client: &'c AuthenticatedClient,
}

impl<'c> TranslationsAuthenticatedApi<'c> {
pub(crate) const fn new(client: &'c AuthenticatedClient) -> Self {
Self { client }
}


pub async fn create_translation_relationship(
&self,
translation_relationship_to_create: TranslationRelationshipToCreate,
) -> ClientResult<(), TranslationRelationshipCreationError> {
create_translation_relationship(self.client, translation_relationship_to_create).await
}

pub async fn delete_translation_relationship(
&self,
translation_relationship_to_delete: TranslationRelationshipToDelete,
) -> ClientResult<(), TranslationRelationshipDeletionError> {
delete_translation_relationship(self.client, translation_relationship_to_delete).await
}
}
5 changes: 5 additions & 0 deletions kolomoni_api_client/src/clients.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::{
categories::{DictionaryCategoriesApi, DictionaryCategoriesAuthenticatedApi},
english::{EnglishDictionaryApi, EnglishDictionaryAuthenticatedApi},
slovene::{SloveneDictionaryApi, SloveneDictionaryAuthenticatedApi},
translation::TranslationsAuthenticatedApi,
},
health::{HealthApi, HealthAuthenticatedApi},
},
Expand Down Expand Up @@ -191,6 +192,10 @@ impl AuthenticatedClient {
pub fn slovene_dictionary(&self) -> SloveneDictionaryAuthenticatedApi<'_> {
SloveneDictionaryAuthenticatedApi::new(self)
}

pub fn translations(&self) -> TranslationsAuthenticatedApi<'_> {
TranslationsAuthenticatedApi::new(self)
}
}

impl HttpClient for AuthenticatedClient {
Expand Down
2 changes: 1 addition & 1 deletion kolomoni_api_client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub mod api;
pub mod authentication;
mod clients;
pub mod errors;
pub(crate) mod request;
pub mod request;
pub(crate) mod response;
pub use clients::*;
mod server;
Expand Down
26 changes: 25 additions & 1 deletion kolomoni_api_client/src/request/delete.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::borrow::Borrow;

use url::Url;

use super::build_request_url;
use super::{build_request_url, build_request_url_with_parameters};
use crate::{
errors::{ClientError, ClientResult},
response::ServerResponse,
Expand Down Expand Up @@ -38,6 +40,28 @@ where
)),
}
}

pub(crate) fn endpoint_url_with_parameters<U, P, K, V>(
self,
relative_endpoint_url: U,
parameters: P,
) -> DeleteRequestBuilder<'c, HC, true>
where
U: AsRef<str>,
P: IntoIterator,
P::Item: Borrow<(K, V)>,
K: AsRef<str>,
V: AsRef<str>,
{
DeleteRequestBuilder {
client: self.client,
url: Some(build_request_url_with_parameters(
self.client.server(),
relative_endpoint_url.as_ref(),
parameters,
)),
}
}
}

impl<'c, HC> DeleteRequestBuilder<'c, HC, true>
Expand Down
10 changes: 5 additions & 5 deletions kolomoni_api_client/src/request/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ use url::Url;

use crate::{server::ApiServer, HttpClient};

pub(crate) mod delete;
pub(crate) mod get;
pub(crate) mod patch;
pub(crate) mod post;
pub mod delete;
pub mod get;
pub mod patch;
pub mod post;


pub(crate) struct RequestBuilder;
pub struct RequestBuilder;

impl RequestBuilder {
pub(crate) fn get<'c, HC>(client: &'c HC) -> GetRequestBuilder<'c, HC, false>
Expand Down
15 changes: 15 additions & 0 deletions kolomoni_api_client/src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use kolomoni_core::api_models::{
CategoryErrorReason,
ErrorReason,
ResponseWithErrorReason,
TranslationsErrorReason,
WordErrorReason,
};
use reqwest::StatusCode;
Expand Down Expand Up @@ -97,6 +98,20 @@ impl ServerResponse {

Ok(word_error_reason)
}

pub(crate) async fn translations_error_reason(self) -> ClientResult<TranslationsErrorReason> {
let response_status = self.status();
let error_reason = self.error_reason().await?;

let ErrorReason::Translations(translations_error_reason) = error_reason else {
return Err(ClientError::unexpected_error_reason(
error_reason,
response_status,
));
};

Ok(translations_error_reason)
}
}


Expand Down
Loading

0 comments on commit 8cada85

Please sign in to comment.