Fix word name collision, add two new user-related features
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit changes the primary key of words to a serial number. That way, two words with the same normalized value will not collide with one another. It also adds two new tables in the database: - Users following languages - Users learning words The former can represent two stages of learning a word: - Either the user is currently learning it - Or they consider they know it and don’t need to work on it anymore These two new tables now have their API query available through the GraphQL API. This commit also fixes the issue of word-related tables and types not being dropped when resetting the database.
This commit is contained in:
parent
b5dfdee453
commit
c5f5e770e2
@ -1,4 +1,5 @@
|
|||||||
-- This file should undo anything in `up.sql`
|
-- This file should undo anything in `up.sql`
|
||||||
|
DROP TABLE UserFollowLanguage;
|
||||||
DROP TABLE LangAndAgents;
|
DROP TABLE LangAndAgents;
|
||||||
DROP TABLE LangTranslatesTo;
|
DROP TABLE LangTranslatesTo;
|
||||||
DROP TABLE Languages;
|
DROP TABLE Languages;
|
||||||
|
@ -51,3 +51,17 @@ CREATE TABLE LangAndAgents (
|
|||||||
NOT NULL,
|
NOT NULL,
|
||||||
relationship AgentLanguageRelation NOT NULL
|
relationship AgentLanguageRelation NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE UserFollowLanguage (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
lang UUID
|
||||||
|
REFERENCES Languages(id)
|
||||||
|
ON UPDATE CASCADE
|
||||||
|
ON DELETE CASCADE
|
||||||
|
NOT NULL,
|
||||||
|
userid VARCHAR(31)
|
||||||
|
REFERENCES Users(id)
|
||||||
|
ON UPDATE CASCADE
|
||||||
|
ON DELETE CASCADE
|
||||||
|
NOT NULL
|
||||||
|
);
|
||||||
|
@ -1 +1,7 @@
|
|||||||
-- This file should undo anything in `up.sql`
|
-- This file should undo anything in `up.sql`
|
||||||
|
DROP TABLE WordRelation;
|
||||||
|
DROP TABLE WordLearning;
|
||||||
|
DROP TABLE Words;
|
||||||
|
DROP TYPE WordLearningStatus;
|
||||||
|
DROP TYPE WordRelationship;
|
||||||
|
DROP TYPE PartOfSpeech;
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
-- Your SQL goes here
|
-- Your SQL goes here
|
||||||
CREATE TYPE PartOfSpeech as ENUM ('ADJ', 'ADP', 'ADV', 'AUX', 'CCONJ', 'DET', 'INTJ', 'NOUN', 'NUM', 'PART', 'PRON', 'PROPN', 'PUNCT', 'SCONJ', 'SYM', 'VERB', 'X');
|
CREATE TYPE PartOfSpeech as ENUM ('ADJ', 'ADP', 'ADV', 'AUX', 'CCONJ', 'DET', 'INTJ', 'NOUN', 'NUM', 'PART', 'PRON', 'PROPN', 'PUNCT', 'SCONJ', 'SYM', 'VERB', 'X');
|
||||||
CREATE TYPE WordRelationship as ENUM('def', 'related');
|
CREATE TYPE WordRelationship as ENUM('def', 'related');
|
||||||
|
CREATE TYPE WordLearningStatus as ENUM('learning', 'learned');
|
||||||
|
|
||||||
CREATE TABLE Words (
|
CREATE TABLE Words (
|
||||||
norm VARCHAR(255) PRIMARY KEY, -- normalized word
|
id UUID DEFAULT uuid_generate_v4 () PRIMARY KEY,
|
||||||
|
norm VARCHAR(255) NOT NULL, -- normalized word, generally in latin alphabet
|
||||||
native VARCHAR(255),
|
native VARCHAR(255),
|
||||||
lemma VARCHAR(255)
|
lemma UUID
|
||||||
REFERENCES Words(norm)
|
REFERENCES Words(id)
|
||||||
ON UPDATE CASCADE
|
ON UPDATE CASCADE
|
||||||
ON DELETE SET NULL,
|
ON DELETE SET NULL,
|
||||||
language UUID
|
language UUID
|
||||||
@ -26,15 +28,30 @@ CREATE TABLE Words (
|
|||||||
|
|
||||||
CREATE TABLE WordRelation (
|
CREATE TABLE WordRelation (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
wordsource VARCHAR(255)
|
wordsource UUID
|
||||||
REFERENCES Words(norm)
|
REFERENCES Words(id)
|
||||||
ON UPDATE CASCADE
|
ON UPDATE CASCADE
|
||||||
ON DELETE CASCADE
|
ON DELETE CASCADE
|
||||||
NOT NULL,
|
NOT NULL,
|
||||||
wordtarget VARCHAR(255)
|
wordtarget UUID
|
||||||
REFERENCES Words(norm)
|
REFERENCES Words(id)
|
||||||
ON UPDATE CASCADE
|
ON UPDATE CASCADE
|
||||||
ON DELETE CASCADE
|
ON DELETE CASCADE
|
||||||
NOT NULL,
|
NOT NULL,
|
||||||
relationship WordRelationship NOT NULL
|
relationship WordRelationship NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE WordLearning (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
word UUID
|
||||||
|
REFERENCES Words(id)
|
||||||
|
ON UPDATE CASCADE
|
||||||
|
ON DELETE CASCADE
|
||||||
|
NOT NULL,
|
||||||
|
userid VARCHAR(31)
|
||||||
|
REFERENCES Users(id)
|
||||||
|
ON UPDATE CASCADE
|
||||||
|
ON DELETE CASCADE
|
||||||
|
NOT NULL,
|
||||||
|
status WordLearningStatus DEFAULT 'learning' NOT NULL
|
||||||
|
);
|
||||||
|
@ -219,7 +219,7 @@ impl Database {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn word_id(&self, id: &str) -> Result<Option<Word>, DatabaseError> {
|
pub fn word_id(&self, id: uuid::Uuid) -> Result<Option<Word>, DatabaseError> {
|
||||||
use self::schema::words::dsl;
|
use self::schema::words::dsl;
|
||||||
match dsl::words.find(id).first::<Word>(&mut self.conn()?) {
|
match dsl::words.find(id).first::<Word>(&mut self.conn()?) {
|
||||||
Ok(val) => Ok(Some(val)),
|
Ok(val) => Ok(Some(val)),
|
||||||
|
@ -13,7 +13,7 @@ use super::users::User;
|
|||||||
|
|
||||||
use std::convert::Into;
|
use std::convert::Into;
|
||||||
|
|
||||||
use schema::{langandagents, langtranslatesto, languages};
|
use schema::{langandagents, langtranslatesto, languages, userfollowlanguage};
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
diesel_derive_enum::DbEnum, Debug, Clone, PartialEq, Eq, GraphQLEnum,
|
diesel_derive_enum::DbEnum, Debug, Clone, PartialEq, Eq, GraphQLEnum,
|
||||||
@ -209,7 +209,7 @@ impl Language {
|
|||||||
"Failed to retrieve owner {} of language {}: {e:?}",
|
"Failed to retrieve owner {} of language {}: {e:?}",
|
||||||
self.owner, self.name
|
self.owner, self.name
|
||||||
),
|
),
|
||||||
"Database reading error",
|
"Database error",
|
||||||
)
|
)
|
||||||
})?),
|
})?),
|
||||||
Err(e) => Err(DatabaseError::new(
|
Err(e) => Err(DatabaseError::new(
|
||||||
@ -235,6 +235,42 @@ impl Language {
|
|||||||
self.relationship(&context.db, AgentLanguageRelation::Publisher)
|
self.relationship(&context.db, AgentLanguageRelation::Publisher)
|
||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[graphql(description = "People following the language")]
|
||||||
|
fn followers(&self, context: &Context) -> FieldResult<Vec<User>> {
|
||||||
|
use schema::userfollowlanguage::dsl;
|
||||||
|
match &mut context.db.conn() {
|
||||||
|
Ok(conn) => {
|
||||||
|
Ok(dsl::userfollowlanguage
|
||||||
|
.filter(dsl::lang.eq(self.id))
|
||||||
|
.load::<UserFollowLanguage>(conn)
|
||||||
|
.map_err(|e| {
|
||||||
|
DatabaseError::new(format!("Failed to retrieve language followers for language {}: {e:?}", self.id),
|
||||||
|
"Database error")
|
||||||
|
})?
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|follow| {
|
||||||
|
use schema::users::dsl;
|
||||||
|
match dsl::users
|
||||||
|
.find(follow.userid.clone())
|
||||||
|
.first::<User>(conn) {
|
||||||
|
Ok(user) => Some(user),
|
||||||
|
Err(e) => {
|
||||||
|
info!("Failed to retrieve user {} from database: {e:?}", follow.userid);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<User>>()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Err(e) => Err(DatabaseError::new(
|
||||||
|
format!("Failed to connect to the database: {e:?}"),
|
||||||
|
"Database connection failure",
|
||||||
|
)
|
||||||
|
.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Queryable, Insertable, Debug, Clone, PartialEq, Eq)]
|
#[derive(Queryable, Insertable, Debug, Clone, PartialEq, Eq)]
|
||||||
@ -253,3 +289,11 @@ pub struct LangTranslatesTo {
|
|||||||
langfrom: Uuid,
|
langfrom: Uuid,
|
||||||
langto: Uuid,
|
langto: Uuid,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Queryable, Insertable, Debug, Clone, PartialEq, Eq)]
|
||||||
|
#[diesel(table_name = userfollowlanguage)]
|
||||||
|
pub struct UserFollowLanguage {
|
||||||
|
id: i32,
|
||||||
|
lang: Uuid,
|
||||||
|
userid: String,
|
||||||
|
}
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
use super::super::schema::{userfollows, users};
|
use super::{
|
||||||
|
super::schema,
|
||||||
|
words::{Word, WordLearning, WordLearningStatus},
|
||||||
|
};
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
use juniper::FieldResult;
|
use juniper::FieldResult;
|
||||||
use tracing::debug;
|
use tracing::{debug, info};
|
||||||
|
|
||||||
|
use schema::{userfollows, users};
|
||||||
|
|
||||||
use crate::{db::DatabaseError, graphql::Context};
|
use crate::{db::DatabaseError, graphql::Context};
|
||||||
|
|
||||||
@ -33,8 +38,8 @@ impl User {
|
|||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
Ok(userfollows::dsl::userfollows
|
Ok(userfollows::dsl::userfollows
|
||||||
.filter(userfollows::dsl::follower.eq(self.id.clone()))
|
.filter(userfollows::dsl::follower.eq(self.id.clone()))
|
||||||
.load::<UserFollow>(conn)
|
.load::<UserFollow>(conn)
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
DatabaseError::new(
|
DatabaseError::new(
|
||||||
format!(
|
format!(
|
||||||
@ -62,6 +67,53 @@ impl User {
|
|||||||
})
|
})
|
||||||
.collect::<Vec<User>>())
|
.collect::<Vec<User>>())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[graphql(
|
||||||
|
description = "What words the user is learning or has learned",
|
||||||
|
arguments(status(
|
||||||
|
description = "Display either words being learned or words learned"
|
||||||
|
))
|
||||||
|
)]
|
||||||
|
pub fn words_learning(
|
||||||
|
&self,
|
||||||
|
context: &Context,
|
||||||
|
status: WordLearningStatus,
|
||||||
|
) -> FieldResult<Vec<Word>> {
|
||||||
|
use schema::wordlearning::dsl;
|
||||||
|
let conn = &mut context.db.conn().map_err(|e| {
|
||||||
|
DatabaseError::new(
|
||||||
|
format!("Failed to connect to database: {e:?}"),
|
||||||
|
"Database connection error",
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
Ok(dsl::wordlearning
|
||||||
|
.filter(dsl::userid.eq(self.id.clone()))
|
||||||
|
.filter(dsl::status.eq(status))
|
||||||
|
.load::<WordLearning>(conn)
|
||||||
|
.map_err(|e| {
|
||||||
|
DatabaseError::new(
|
||||||
|
format!(
|
||||||
|
"Failed to retrieve user follows from database: {e:?}"
|
||||||
|
),
|
||||||
|
"Database reading error",
|
||||||
|
)
|
||||||
|
})?
|
||||||
|
.iter()
|
||||||
|
.filter_map(|lang_learn| {
|
||||||
|
use schema::words::dsl;
|
||||||
|
match dsl::words.find(lang_learn.word).first::<Word>(conn) {
|
||||||
|
Ok(word) => Some(word),
|
||||||
|
Err(e) => {
|
||||||
|
info!(
|
||||||
|
"Failed to retrieve word {} from database: {e:?}",
|
||||||
|
lang_learn.word
|
||||||
|
);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<Word>>())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Queryable, Insertable, Debug, Clone, PartialEq, Eq)]
|
#[derive(Queryable, Insertable, Debug, Clone, PartialEq, Eq)]
|
||||||
|
@ -5,8 +5,9 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
use juniper::{FieldResult, GraphQLEnum};
|
use juniper::{FieldResult, GraphQLEnum};
|
||||||
use schema::{wordrelation, words};
|
use schema::{wordrelation, words, wordlearning};
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
use std::convert::Into;
|
use std::convert::Into;
|
||||||
|
|
||||||
@ -19,6 +20,13 @@ pub enum WordRelationship {
|
|||||||
Related,
|
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(
|
#[derive(
|
||||||
diesel_derive_enum::DbEnum, Debug, Clone, PartialEq, Eq, GraphQLEnum,
|
diesel_derive_enum::DbEnum, Debug, Clone, PartialEq, Eq, GraphQLEnum,
|
||||||
)]
|
)]
|
||||||
@ -48,9 +56,10 @@ pub enum PartOfSpeech {
|
|||||||
|
|
||||||
#[derive(Queryable, Insertable, Debug, Clone, PartialEq, Eq)]
|
#[derive(Queryable, Insertable, Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Word {
|
pub struct Word {
|
||||||
|
id: Uuid,
|
||||||
norm: String,
|
norm: String,
|
||||||
native: Option<String>,
|
native: Option<String>,
|
||||||
lemma: Option<String>,
|
lemma: Option<Uuid>,
|
||||||
language: uuid::Uuid,
|
language: uuid::Uuid,
|
||||||
partofspeech: PartOfSpeech,
|
partofspeech: PartOfSpeech,
|
||||||
audio: Option<String>,
|
audio: Option<String>,
|
||||||
@ -71,7 +80,7 @@ impl Word {
|
|||||||
use schema::wordrelation::dsl;
|
use schema::wordrelation::dsl;
|
||||||
match &mut db.conn() {
|
match &mut db.conn() {
|
||||||
Ok(conn) => Ok(dsl::wordrelation
|
Ok(conn) => Ok(dsl::wordrelation
|
||||||
.filter(dsl::wordsource.eq(self.norm.clone()))
|
.filter(dsl::wordsource.eq(self.id))
|
||||||
.filter(dsl::relationship.eq(relationship))
|
.filter(dsl::relationship.eq(relationship))
|
||||||
.load::<WordRelation>(conn)
|
.load::<WordRelation>(conn)
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
@ -81,9 +90,9 @@ impl Word {
|
|||||||
)
|
)
|
||||||
})?
|
})?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|w| {
|
.flat_map(|word| {
|
||||||
use schema::words::dsl;
|
use schema::words::dsl;
|
||||||
dsl::words.find(w.wordtarget).first::<Word>(conn)
|
dsl::words.find(word.wordtarget).first::<Word>(conn)
|
||||||
})
|
})
|
||||||
.collect::<Vec<Word>>()),
|
.collect::<Vec<Word>>()),
|
||||||
Err(e) => Err(DatabaseError::new(
|
Err(e) => Err(DatabaseError::new(
|
||||||
@ -109,20 +118,18 @@ impl Word {
|
|||||||
#[graphql(description = "Base form of the current word")]
|
#[graphql(description = "Base form of the current word")]
|
||||||
fn lemma(&self, context: &Context) -> Option<Word> {
|
fn lemma(&self, context: &Context) -> Option<Word> {
|
||||||
use schema::words::dsl;
|
use schema::words::dsl;
|
||||||
match self.lemma.clone() {
|
match self.lemma {
|
||||||
Some(lemma) => match &mut context.db.conn() {
|
Some(lemma) => match &mut context.db.conn() {
|
||||||
Ok(conn) => {
|
Ok(conn) => match dsl::words.find(lemma).first::<Word>(conn) {
|
||||||
match dsl::words.find(lemma.clone()).first::<Word>(conn) {
|
Ok(word) => Some(word),
|
||||||
Ok(word) => Some(word),
|
Err(e) => {
|
||||||
Err(e) => {
|
info!(
|
||||||
info!(
|
"Failed to retrieve lemma {} of word {}: {:?}",
|
||||||
"Failed to retrieve lemma {} of word {}: {:?}",
|
lemma, self.norm, e
|
||||||
lemma, self.norm, e
|
);
|
||||||
);
|
None
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
info!("Could not connect to the database: {:?}", e);
|
info!("Could not connect to the database: {:?}", e);
|
||||||
None
|
None
|
||||||
@ -211,7 +218,16 @@ impl Word {
|
|||||||
#[diesel(table_name = wordrelation)]
|
#[diesel(table_name = wordrelation)]
|
||||||
pub struct WordRelation {
|
pub struct WordRelation {
|
||||||
id: i32,
|
id: i32,
|
||||||
wordsource: String,
|
wordsource: Uuid,
|
||||||
wordtarget: String,
|
wordtarget: Uuid,
|
||||||
relationship: WordRelationship,
|
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
|
||||||
|
}
|
||||||
|
@ -17,6 +17,10 @@ pub mod sql_types {
|
|||||||
#[diesel(postgres_type(name = "release"))]
|
#[diesel(postgres_type(name = "release"))]
|
||||||
pub struct Release;
|
pub struct Release;
|
||||||
|
|
||||||
|
#[derive(diesel::sql_types::SqlType)]
|
||||||
|
#[diesel(postgres_type(name = "wordlearningstatus"))]
|
||||||
|
pub struct Wordlearningstatus;
|
||||||
|
|
||||||
#[derive(diesel::sql_types::SqlType)]
|
#[derive(diesel::sql_types::SqlType)]
|
||||||
#[diesel(postgres_type(name = "wordrelationship"))]
|
#[diesel(postgres_type(name = "wordrelationship"))]
|
||||||
pub struct Wordrelationship;
|
pub struct Wordrelationship;
|
||||||
@ -63,6 +67,14 @@ diesel::table! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
diesel::table! {
|
||||||
|
userfollowlanguage (id) {
|
||||||
|
id -> Int4,
|
||||||
|
lang -> Uuid,
|
||||||
|
userid -> Varchar,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
userfollows (id) {
|
userfollows (id) {
|
||||||
id -> Int4,
|
id -> Int4,
|
||||||
@ -78,14 +90,26 @@ diesel::table! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
diesel::table! {
|
||||||
|
use diesel::sql_types::*;
|
||||||
|
use super::sql_types::Wordlearningstatus;
|
||||||
|
|
||||||
|
wordlearning (id) {
|
||||||
|
id -> Int4,
|
||||||
|
word -> Uuid,
|
||||||
|
userid -> Varchar,
|
||||||
|
status -> Wordlearningstatus,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
use diesel::sql_types::*;
|
use diesel::sql_types::*;
|
||||||
use super::sql_types::Wordrelationship;
|
use super::sql_types::Wordrelationship;
|
||||||
|
|
||||||
wordrelation (id) {
|
wordrelation (id) {
|
||||||
id -> Int4,
|
id -> Int4,
|
||||||
wordsource -> Varchar,
|
wordsource -> Uuid,
|
||||||
wordtarget -> Varchar,
|
wordtarget -> Uuid,
|
||||||
relationship -> Wordrelationship,
|
relationship -> Wordrelationship,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,10 +118,11 @@ diesel::table! {
|
|||||||
use diesel::sql_types::*;
|
use diesel::sql_types::*;
|
||||||
use super::sql_types::Partofspeech;
|
use super::sql_types::Partofspeech;
|
||||||
|
|
||||||
words (norm) {
|
words (id) {
|
||||||
|
id -> Uuid,
|
||||||
norm -> Varchar,
|
norm -> Varchar,
|
||||||
native -> Nullable<Varchar>,
|
native -> Nullable<Varchar>,
|
||||||
lemma -> Nullable<Varchar>,
|
lemma -> Nullable<Uuid>,
|
||||||
language -> Uuid,
|
language -> Uuid,
|
||||||
partofspeech -> Partofspeech,
|
partofspeech -> Partofspeech,
|
||||||
audio -> Nullable<Varchar>,
|
audio -> Nullable<Varchar>,
|
||||||
@ -113,14 +138,20 @@ diesel::table! {
|
|||||||
diesel::joinable!(langandagents -> languages (language));
|
diesel::joinable!(langandagents -> languages (language));
|
||||||
diesel::joinable!(langandagents -> users (agent));
|
diesel::joinable!(langandagents -> users (agent));
|
||||||
diesel::joinable!(languages -> users (owner));
|
diesel::joinable!(languages -> users (owner));
|
||||||
|
diesel::joinable!(userfollowlanguage -> languages (lang));
|
||||||
|
diesel::joinable!(userfollowlanguage -> users (userid));
|
||||||
|
diesel::joinable!(wordlearning -> users (userid));
|
||||||
|
diesel::joinable!(wordlearning -> words (word));
|
||||||
diesel::joinable!(words -> languages (language));
|
diesel::joinable!(words -> languages (language));
|
||||||
|
|
||||||
diesel::allow_tables_to_appear_in_same_query!(
|
diesel::allow_tables_to_appear_in_same_query!(
|
||||||
langandagents,
|
langandagents,
|
||||||
langtranslatesto,
|
langtranslatesto,
|
||||||
languages,
|
languages,
|
||||||
|
userfollowlanguage,
|
||||||
userfollows,
|
userfollows,
|
||||||
users,
|
users,
|
||||||
|
wordlearning,
|
||||||
wordrelation,
|
wordrelation,
|
||||||
words,
|
words,
|
||||||
);
|
);
|
||||||
|
@ -96,7 +96,14 @@ impl Query {
|
|||||||
arguments(id(description = "Unique identifier of a word"))
|
arguments(id(description = "Unique identifier of a word"))
|
||||||
)]
|
)]
|
||||||
fn word(context: &Context, id: String) -> FieldResult<Option<Word>> {
|
fn word(context: &Context, id: String) -> FieldResult<Option<Word>> {
|
||||||
context.db.word_id(id.as_str()).map_err(Into::into)
|
match Uuid::from_str(&id) {
|
||||||
|
Ok(uuid) => context.db.word_id(uuid).map_err(Into::into),
|
||||||
|
Err(e) => Err(DatabaseError::new(
|
||||||
|
format!("Failed to convert {id} to a UUID: {e:?}"),
|
||||||
|
"Conversion Error",
|
||||||
|
)
|
||||||
|
.into()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[graphql(
|
#[graphql(
|
||||||
|
Loading…
Reference in New Issue
Block a user