234 lines
6.6 KiB
Rust
234 lines
6.6 KiB
Rust
use super::super::schema;
|
|
use crate::{
|
|
db::{Database, DatabaseError},
|
|
graphql::Context,
|
|
};
|
|
use diesel::prelude::*;
|
|
use juniper::{FieldResult, GraphQLEnum};
|
|
use schema::{wordrelation, words, wordlearning};
|
|
use tracing::info;
|
|
use uuid::Uuid;
|
|
|
|
use std::convert::Into;
|
|
|
|
use super::languages::Language;
|
|
|
|
#[derive(diesel_derive_enum::DbEnum, Debug, Clone, PartialEq, Eq)]
|
|
#[DieselTypePath = "crate::db::schema::sql_types::Wordrelationship"]
|
|
pub enum WordRelationship {
|
|
Definition,
|
|
Related,
|
|
}
|
|
|
|
#[derive(diesel_derive_enum::DbEnum, Debug, Clone, PartialEq, Eq, juniper::GraphQLEnum)]
|
|
#[DieselTypePath = "crate::db::schema::sql_types::Wordlearningstatus"]
|
|
pub enum WordLearningStatus {
|
|
Learning,
|
|
Learned
|
|
}
|
|
|
|
#[derive(
|
|
diesel_derive_enum::DbEnum, Debug, Clone, PartialEq, Eq, GraphQLEnum,
|
|
)]
|
|
#[DieselTypePath = "crate::db::schema::sql_types::Partofspeech"]
|
|
pub enum PartOfSpeech {
|
|
Adjective,
|
|
Adposition,
|
|
Adverb,
|
|
Auxilliary,
|
|
#[graphql(name = "COORDINATING_CONJUNCTION")]
|
|
CoordConj,
|
|
Determiner,
|
|
Interjection,
|
|
Noun,
|
|
Numeral,
|
|
Particle,
|
|
Pronoun,
|
|
#[graphql(name = "PROPER_NOUN")]
|
|
ProperNoun,
|
|
Punctuation,
|
|
#[graphql(name = "SUBORDINATING_CONJUNCTION")]
|
|
SubjConj,
|
|
Symbol,
|
|
Verb,
|
|
Other,
|
|
}
|
|
|
|
#[derive(Queryable, Insertable, Debug, Clone, PartialEq, Eq)]
|
|
pub struct Word {
|
|
id: Uuid,
|
|
norm: String,
|
|
native: Option<String>,
|
|
lemma: Option<Uuid>,
|
|
language: uuid::Uuid,
|
|
partofspeech: PartOfSpeech,
|
|
audio: Option<String>,
|
|
video: Option<String>,
|
|
image: Option<String>,
|
|
description: Option<String>,
|
|
etymology: Option<String>,
|
|
lusage: Option<String>,
|
|
morphology: Option<String>,
|
|
}
|
|
|
|
impl Word {
|
|
fn relationship(
|
|
&self,
|
|
db: &Database,
|
|
relationship: WordRelationship,
|
|
) -> Result<Vec<Word>, DatabaseError> {
|
|
use schema::wordrelation::dsl;
|
|
match &mut db.conn() {
|
|
Ok(conn) => Ok(dsl::wordrelation
|
|
.filter(dsl::wordsource.eq(self.id))
|
|
.filter(dsl::relationship.eq(relationship))
|
|
.load::<WordRelation>(conn)
|
|
.map_err(|e| {
|
|
DatabaseError::new(
|
|
format!("Failed to retrieve word relations: {e:?}"),
|
|
"Database reading failed",
|
|
)
|
|
})?
|
|
.into_iter()
|
|
.flat_map(|word| {
|
|
use schema::words::dsl;
|
|
dsl::words.find(word.wordtarget).first::<Word>(conn)
|
|
})
|
|
.collect::<Vec<Word>>()),
|
|
Err(e) => Err(DatabaseError::new(
|
|
format!("Failed to connect to the database: {e:?}"),
|
|
"Database connection error",
|
|
)),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[juniper::graphql_object(Context = Context)]
|
|
impl Word {
|
|
#[graphql(description = "Normal form of the word")]
|
|
fn norm(&self) -> String {
|
|
self.norm.clone()
|
|
}
|
|
|
|
#[graphql(description = "Native representation of the word")]
|
|
fn native(&self) -> Option<String> {
|
|
self.native.clone()
|
|
}
|
|
|
|
#[graphql(description = "Base form of the current word")]
|
|
fn lemma(&self, context: &Context) -> Option<Word> {
|
|
use schema::words::dsl;
|
|
match self.lemma {
|
|
Some(lemma) => match &mut context.db.conn() {
|
|
Ok(conn) => match dsl::words.find(lemma).first::<Word>(conn) {
|
|
Ok(word) => Some(word),
|
|
Err(e) => {
|
|
info!(
|
|
"Failed to retrieve lemma {} of word {}: {:?}",
|
|
lemma, self.norm, e
|
|
);
|
|
None
|
|
}
|
|
},
|
|
Err(e) => {
|
|
info!("Could not connect to the database: {:?}", e);
|
|
None
|
|
}
|
|
},
|
|
None => None,
|
|
}
|
|
}
|
|
|
|
#[graphql(description = "Language to which the word belongs")]
|
|
fn language(&self, context: &Context) -> FieldResult<Language> {
|
|
use schema::languages::dsl;
|
|
use std::convert::Into;
|
|
dsl::languages
|
|
.find(self.language)
|
|
.first::<Language>(&mut context.db.conn()?)
|
|
.map_err(|e| DatabaseError::new(
|
|
format!(
|
|
"Failed to retrieve language {} of word {} from database: {e:?}",
|
|
self.language, self.norm
|
|
),
|
|
"Database Error"
|
|
).into())
|
|
}
|
|
|
|
#[graphql(
|
|
name = "partOfSpeech",
|
|
description = "Part of speech the word belongs to"
|
|
)]
|
|
fn part_of_speech(&self) -> PartOfSpeech {
|
|
self.partofspeech.clone()
|
|
}
|
|
|
|
#[graphql(description = "Link to an audio file related to the word")]
|
|
fn audio(&self) -> Option<String> {
|
|
self.audio.clone()
|
|
}
|
|
|
|
#[graphql(description = "Link to an video file related to the word")]
|
|
fn video(&self) -> Option<String> {
|
|
self.video.clone()
|
|
}
|
|
|
|
#[graphql(description = "Link to an image file related to the word")]
|
|
fn image(&self) -> Option<String> {
|
|
self.image.clone()
|
|
}
|
|
|
|
#[graphql(description = "Etymology of the word, can be in Markdown format")]
|
|
fn etymology(&self) -> Option<String> {
|
|
self.etymology.clone()
|
|
}
|
|
|
|
#[graphql(description = "Usage of the word, can be in Markdown format")]
|
|
fn usage(&self) -> Option<String> {
|
|
self.lusage.clone()
|
|
}
|
|
|
|
#[graphql(
|
|
description = "Morphology of the word, can be in Markdown format"
|
|
)]
|
|
fn morphology(&self) -> Option<String> {
|
|
self.morphology.clone()
|
|
}
|
|
|
|
#[graphql(
|
|
name = "related",
|
|
description = "Words related to the current word"
|
|
)]
|
|
fn related_words(&self, context: &Context) -> FieldResult<Vec<Word>> {
|
|
self.relationship(&context.db, WordRelationship::Related)
|
|
.map_err(Into::into)
|
|
}
|
|
|
|
#[graphql(
|
|
name = "definitions",
|
|
description = "Words that define the current word"
|
|
)]
|
|
fn definitions(&self, context: &Context) -> FieldResult<Vec<Word>> {
|
|
self.relationship(&context.db, WordRelationship::Definition)
|
|
.map_err(Into::into)
|
|
}
|
|
}
|
|
|
|
#[derive(Queryable, Insertable, Debug, Clone, PartialEq, Eq)]
|
|
#[diesel(table_name = wordrelation)]
|
|
pub struct WordRelation {
|
|
id: i32,
|
|
wordsource: Uuid,
|
|
wordtarget: Uuid,
|
|
relationship: WordRelationship,
|
|
}
|
|
|
|
#[derive(Queryable, Insertable, Debug, Clone, PartialEq, Eq)]
|
|
#[diesel(table_name = wordlearning)]
|
|
pub struct WordLearning {
|
|
pub id: i32,
|
|
pub word: Uuid,
|
|
pub userid: String,
|
|
pub status: WordLearningStatus
|
|
}
|