>::Engine>,
) -> sqlx::Result<()>
where
- A: ItemMod + AttachmentItemMod,
+ A: ItemMod + AttachmentItemMod
,
P: Item,
{
for attached in self.attached.iter() {
@@ -124,29 +126,31 @@ pub trait CompareAttachable, A: ItemMod
}
}
-impl CompareAttachable for KonsepItem {
+impl CompareAttachable for KonsepItem {
fn items(&self) -> Vec {
Vec::clone(&self.cakupans)
}
}
-impl CompareAttachable for KonsepItem {
+impl CompareAttachable for KonsepItem {
fn items(&self) -> Vec {
Vec::clone(&self.kata_asing)
}
}
-impl CompareAttachable for LemmaItem {
- fn items(&self) -> Vec {
+impl
+ CompareAttachable, KonsepItemMod> for LemmaItem
+{
+ fn items(&self) -> Vec> {
Vec::clone(&self.konseps)
}
- fn find_attached(&self, other: &Vec) -> Vec {
+ fn find_attached(&self, other: &Vec>) -> Vec> {
Vec::clone(other)
.into_iter()
.filter(|item| item.id == AutoGen::Unknown)
.map(|item| KonsepItemMod::from_item(&item))
.collect_vec()
}
- fn find_detached(&self, other: &Vec) -> Vec {
+ fn find_detached(&self, other: &Vec>) -> Vec> {
let other_ids = Vec::clone(other)
.into_iter()
.filter(|item| item.id != AutoGen::Unknown)
@@ -158,7 +162,7 @@ impl CompareAttachable for LemmaItem {
.map(|item| KonsepItemMod::from_item(&item))
.collect_vec()
}
- fn find_modified(&self, other: &Vec) -> Vec {
+ fn find_modified(&self, other: &Vec>) -> Vec> {
let detached_id = self
.find_detached(other)
.iter()
diff --git a/backend/database/src/data/items/cakupan.rs b/backend/database/src/data/items/cakupan.rs
index 49b0261..63b6683 100644
--- a/backend/database/src/data/items/cakupan.rs
+++ b/backend/database/src/data/items/cakupan.rs
@@ -1,5 +1,7 @@
//! Contains the [CakupanItem].
+use std::fmt::{Debug, Display};
+
use crate::io::interface::{AttachmentItemMod, FromView, Item, ItemMod, SubmitItem};
use crate::prelude::*;
use tracing::instrument;
@@ -91,12 +93,15 @@ impl From for CakupanItem {
#[cfg(feature = "sqlite")]
#[async_trait::async_trait]
-impl AttachmentItemMod for CakupanItem {
+impl AttachmentItemMod>
+ for CakupanItem
+{
+ type Engine = sqlx::Sqlite;
#[instrument(skip_all)]
async fn submit_attachment_to(
&self,
- parent: &KonsepItem,
- pool: &sqlx::Pool,
+ parent: &KonsepItem,
+ pool: &sqlx::Pool,
) -> sqlx::Result<()> {
tracing::trace!(
"Attaching to <{}:{}>",
@@ -123,8 +128,8 @@ impl AttachmentItemMod for CakupanItem {
}
async fn submit_detachment_from(
&self,
- parent: &KonsepItem,
- pool: &sqlx::Pool,
+ parent: &KonsepItem,
+ pool: &sqlx::Pool,
) -> sqlx::Result<()> {
tracing::trace!(
"Detaching from <{}:{}>",
@@ -150,8 +155,90 @@ impl AttachmentItemMod for CakupanItem {
async fn submit_modification_with(
&self,
- parent: &KonsepItem,
- _pool: &sqlx::Pool,
+ parent: &KonsepItem,
+ _pool: &sqlx::Pool,
+ ) -> sqlx::Result<()> {
+ tracing::trace!(
+ "Modifying with <{}:{}>",
+ self.0,
+ parent.id,
+ parent.keterangan
+ );
+ todo!()
+ }
+}
+
+#[cfg(feature = "postgres")]
+#[async_trait::async_trait]
+impl AttachmentItemMod>
+ for CakupanItem
+{
+ type Engine = sqlx::Postgres;
+ #[instrument(skip_all)]
+ async fn submit_attachment_to(
+ &self,
+ parent: &KonsepItem,
+ pool: &sqlx::Pool,
+ ) -> sqlx::Result<()> {
+ tracing::trace!(
+ "Attaching to <{}:{}>",
+ self.0,
+ parent.id,
+ parent.keterangan
+ );
+ sqlx::query! {
+ r#"INSERT INTO cakupan (nama) VALUES ($1) ON CONFLICT (nama) DO NOTHING;"#,
+ self.0
+ }
+ .execute(pool)
+ .await
+ .expect("Error attaching cakupan to konsep");
+
+ sqlx::query! {
+ r#"INSERT INTO cakupan_x_konsep (cakupan_id, konsep_id)
+ VALUES (
+ (SELECT id FROM cakupan WHERE cakupan.nama = $1),
+ (SELECT id FROM konsep WHERE konsep.keterangan = $2)
+ ) ON CONFLICT (cakupan_id, konsep_id) DO NOTHING;"#,
+ self.0,
+ parent.keterangan
+ }
+ .execute(pool)
+ .await
+ .expect("Error attaching cakupan to konsep");
+ Ok(())
+ }
+ async fn submit_detachment_from(
+ &self,
+ parent: &KonsepItem,
+ pool: &sqlx::Pool,
+ ) -> sqlx::Result<()> {
+ tracing::trace!(
+ "Detaching from <{}:{}>",
+ self.0,
+ parent.id,
+ parent.keterangan
+ );
+ sqlx::query! {
+ r#" DELETE FROM cakupan_x_konsep AS cxk
+ WHERE (
+ cxk.cakupan_id = (SELECT id FROM cakupan WHERE cakupan.nama = $1)
+ AND
+ cxk.konsep_id = (SELECT id FROM konsep WHERE konsep.keterangan = $2)
+ );"#,
+ self.0,
+ parent.keterangan
+ }
+ .execute(pool)
+ .await
+ .expect("Error detaching cakupan from konsep");
+ Ok(())
+ }
+
+ async fn submit_modification_with(
+ &self,
+ parent: &KonsepItem,
+ _pool: &sqlx::Pool,
) -> sqlx::Result<()> {
tracing::trace!(
"Modifying with <{}:{}>",
diff --git a/backend/database/src/data/items/kata_asing.rs b/backend/database/src/data/items/kata_asing.rs
index 633bc58..ad40a42 100644
--- a/backend/database/src/data/items/kata_asing.rs
+++ b/backend/database/src/data/items/kata_asing.rs
@@ -1,5 +1,7 @@
//! Contains struct [KataAsingItem] which map a foreign word with its language of origin.
+use std::fmt::Display;
+
use crate::io::interface::{AttachmentItemMod, FromView, Item, ItemMod, SubmitItem};
use crate::prelude::*;
@@ -97,11 +99,15 @@ impl SubmitItem for KataAsingItem {
#[cfg(feature = "sqlite")]
#[async_trait::async_trait]
-impl AttachmentItemMod for KataAsingItem {
+impl AttachmentItemMod>
+ for KataAsingItem
+{
+ type Engine = sqlx::Sqlite;
+
async fn submit_attachment_to(
&self,
- parent: &KonsepItem,
- pool: &sqlx::Pool,
+ parent: &KonsepItem,
+ pool: &sqlx::Pool,
) -> sqlx::Result<()> {
tracing::trace!(
"Attaching to <{}:{}>",
@@ -130,8 +136,8 @@ impl AttachmentItemMod for KataAsingItem {
}
async fn submit_detachment_from(
&self,
- parent: &KonsepItem,
- pool: &sqlx::Pool,
+ parent: &KonsepItem,
+ pool: &sqlx::Pool,
) -> sqlx::Result<()> {
tracing::trace!(
"Detaching from <{}:{}>",
@@ -159,8 +165,90 @@ impl AttachmentItemMod for KataAsingItem {
async fn submit_modification_with(
&self,
- parent: &KonsepItem,
- _pool: &sqlx::Pool,
+ parent: &KonsepItem,
+ _pool: &sqlx::Pool,
+ ) -> sqlx::Result<()> {
+ tracing::trace!(
+ "Modifying with <{}:{}>",
+ self.bahasa,
+ self.nama,
+ parent.id,
+ parent.keterangan
+ );
+ todo!()
+ }
+}
+
+#[cfg(feature = "postgres")]
+#[async_trait::async_trait]
+impl AttachmentItemMod>
+ for KataAsingItem
+{
+ type Engine = sqlx::Postgres;
+
+ async fn submit_attachment_to(
+ &self,
+ parent: &KonsepItem,
+ pool: &sqlx::Pool,
+ ) -> sqlx::Result<()> {
+ tracing::trace!(
+ "Attaching to <{}:{}>",
+ self.bahasa,
+ self.nama,
+ parent.id,
+ parent.keterangan
+ );
+ sqlx::query! {
+ r#"INSERT INTO kata_asing (nama, bahasa) VALUES ($1,$2) ON CONFLICT (nama, bahasa) DO NOTHING;"#, self.nama, self.bahasa
+ }.execute(pool).await.expect("Error attaching kata_asing to konsep");
+ sqlx::query! {
+ r#"INSERT INTO kata_asing_x_konsep (kata_asing_id, konsep_id)
+ VALUES (
+ (SELECT id FROM kata_asing WHERE kata_asing.nama = $1 AND kata_asing.bahasa = $2),
+ (SELECT id FROM konsep WHERE konsep.keterangan = $3)
+ ) ON CONFLICT (kata_asing_id, konsep_id) DO NOTHING;"#,
+ self.nama,
+ self.bahasa,
+ parent.keterangan
+ }
+ .execute(pool)
+ .await
+ .expect("Error attaching kata_asing to konsep");
+ Ok(())
+ }
+ async fn submit_detachment_from(
+ &self,
+ parent: &KonsepItem,
+ pool: &sqlx::Pool,
+ ) -> sqlx::Result<()> {
+ tracing::trace!(
+ "Detaching from <{}:{}>",
+ self.bahasa,
+ self.nama,
+ parent.id,
+ parent.keterangan
+ );
+ sqlx::query! {
+ r#"DELETE FROM kata_asing_x_konsep AS kaxk
+ WHERE (
+ kaxk.kata_asing_id = (SELECT id FROM kata_asing WHERE kata_asing.nama = $1 AND kata_asing.bahasa = $2)
+ AND
+ kaxk.konsep_id = (SELECT id FROM konsep WHERE konsep.keterangan = $3)
+ );"#,
+ self.nama,
+ self.bahasa,
+ parent.keterangan
+ }
+ .execute(pool)
+ .await
+ .expect("Error detaching cakupan from konsep");
+ Ok(())
+ }
+
+ async fn submit_modification_with(
+ &self,
+ parent: &KonsepItem,
+ _pool: &sqlx::Pool,
) -> sqlx::Result<()> {
tracing::trace!(
"Modifying with <{}:{}>",
diff --git a/backend/database/src/data/items/konsep.rs b/backend/database/src/data/items/konsep.rs
index bde4276..8c3520d 100644
--- a/backend/database/src/data/items/konsep.rs
+++ b/backend/database/src/data/items/konsep.rs
@@ -4,6 +4,7 @@ use crate::changes::{AttachmentMod, CompareAttachable, FieldMod};
use crate::io::interface::{AttachmentItemMod, FromView, FromViewMap, Item, ItemMod};
use crate::prelude::*;
use std::collections::HashMap;
+use std::fmt::{Debug, Display};
use tracing::instrument;
use crate::data::items::cakupan::CakupanItem;
@@ -19,10 +20,10 @@ use crate::data::items::lemma::LemmaItem;
/// The following are the tags implemented in this struct:
/// - [cakupans](KonsepItem#structfield.cakupans): the communication contexts of the definition.
/// - [kata_asing](KonsepItem#structfield.kata_asing): words with equivalent meaning in other languages.
-#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ts_rs::TS)]
+#[derive(Clone, serde::Serialize, serde::Deserialize, ts_rs::TS)]
#[ts(export, export_to = "../../src/bindings/")]
-pub struct KonsepItem {
- pub id: AutoGen,
+pub struct KonsepItem {
+ pub id: AutoGen,
pub keterangan: String,
pub golongan_kata: String,
#[ts(type = "Array")]
@@ -30,20 +31,44 @@ pub struct KonsepItem {
pub kata_asing: Vec,
}
+impl Debug for KonsepItem {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("KonsepItem")
+ .field("id", &self.id)
+ .field("keterangan", &self.keterangan)
+ .field("golongan_kata", &self.golongan_kata)
+ .field("cakupans", &self.cakupans)
+ .field("kata_asing", &self.kata_asing)
+ .finish()
+ }
+}
+
/// A modified [KonsepItem].
///
/// Its usage is similar to [LemmaItemMod](crate::data::LemmaItemMod).
-#[derive(Debug, Clone, PartialEq)]
-pub struct KonsepItemMod {
- pub id: AutoGen,
+#[derive(Clone, PartialEq)]
+pub struct KonsepItemMod {
+ pub id: AutoGen,
pub keterangan: FieldMod,
pub golongan_kata: FieldMod,
pub cakupans: AttachmentMod,
pub kata_asing: AttachmentMod,
}
-impl ItemMod for KonsepItemMod {
- type FromItem = KonsepItem;
+impl Debug for KonsepItemMod {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("KonsepItemMod")
+ .field("id", &self.id)
+ .field("keterangan", &self.keterangan)
+ .field("golongan_kata", &self.golongan_kata)
+ .field("cakupans", &self.cakupans)
+ .field("kata_asing", &self.kata_asing)
+ .finish()
+ }
+}
+
+impl ItemMod for KonsepItemMod {
+ type FromItem = KonsepItem;
fn from_item(value: &Self::FromItem) -> Self {
Self {
@@ -55,10 +80,10 @@ impl ItemMod for KonsepItemMod {
}
}
}
-impl KonsepItem {
+impl KonsepItem {
pub fn null() -> Self {
Self {
- id: AutoGen::Unknown,
+ id: AutoGen::::Unknown,
keterangan: "".into(),
golongan_kata: "".into(),
cakupans: vec![],
@@ -67,7 +92,7 @@ impl KonsepItem {
}
}
-impl PartialEq for KonsepItem {
+impl PartialEq for KonsepItem {
fn eq(&self, other: &Self) -> bool {
self.keterangan == other.keterangan
&& self.golongan_kata == other.golongan_kata
@@ -89,12 +114,14 @@ impl PartialEq for KonsepItem {
#[cfg(feature = "sqlite")]
#[async_trait::async_trait]
-impl AttachmentItemMod for KonsepItemMod {
+impl AttachmentItemMod> for KonsepItemMod {
+ type Engine = sqlx::Sqlite;
+
#[instrument(skip_all)]
async fn submit_attachment_to(
&self,
- parent: &LemmaItem,
- pool: &sqlx::Pool,
+ parent: &LemmaItem,
+ pool: &sqlx::Pool,
) -> sqlx::Result<()> {
let konsep = KonsepItem::partial_from_mod(self);
tracing::trace!(
@@ -124,8 +151,8 @@ impl AttachmentItemMod for KonsepItemMod {
}
async fn submit_detachment_from(
&self,
- parent: &LemmaItem,
- pool: &sqlx::Pool,
+ parent: &LemmaItem,
+ pool: &sqlx::Pool,
) -> sqlx::Result<()> {
tracing::trace!(
"Detaching <{}:{}> from <{}:{}>",
@@ -146,8 +173,8 @@ impl AttachmentItemMod for KonsepItemMod {
async fn submit_modification_with(
&self,
- parent: &LemmaItem,
- pool: &sqlx::Pool,
+ parent: &LemmaItem,
+ pool: &sqlx::Pool,
) -> sqlx::Result<()> {
let konsep = KonsepItem::partial_from_mod(self);
tracing::trace!(
@@ -179,16 +206,119 @@ impl AttachmentItemMod for KonsepItemMod {
}
}
-type Key = (i64, Option, Option);
+#[cfg(feature = "postgres")]
+#[async_trait::async_trait]
+impl AttachmentItemMod> for KonsepItemMod {
+ type Engine = sqlx::Postgres;
+
+ #[instrument(skip_all)]
+ async fn submit_attachment_to(
+ &self,
+ parent: &LemmaItem,
+ pool: &sqlx::Pool,
+ ) -> sqlx::Result<()> {
+ let konsep = KonsepItem::partial_from_mod(self);
+ tracing::trace!(
+ "Attaching <{}:{}> to <{}:{}>",
+ konsep.id,
+ konsep.keterangan,
+ parent.id,
+ parent.lemma
+ );
+ sqlx::query! {
+ r#" INSERT INTO konsep (keterangan, lemma_id, golongan_id)
+ VALUES (
+ $1,
+ (SELECT id FROM lemma WHERE lemma.nama = $2),
+ (SELECT id FROM golongan_kata WHERE golongan_kata.nama = $3)
+ ) ON CONFLICT (id) DO NOTHING
+ "#,
+ konsep.keterangan,
+ parent.lemma,
+ konsep.golongan_kata
+ }
+ .execute(pool)
+ .await?;
+ self.cakupans.submit_changes_with(&konsep, pool).await?;
+ self.kata_asing.submit_changes_with(&konsep, pool).await?;
+ Ok(())
+ }
+ async fn submit_detachment_from(
+ &self,
+ parent: &LemmaItem,
+ pool: &sqlx::Pool,
+ ) -> sqlx::Result<()> {
+ tracing::trace!(
+ "Detaching <{}:{}> from <{}:{}>",
+ self.id,
+ self.keterangan.value(),
+ parent.id,
+ parent.lemma
+ );
+ match (self.id, parent.id) {
+ (AutoGen::Known(i), AutoGen::Known(p)) => {
+ sqlx::query! {
+ r#" DELETE FROM konsep WHERE (id = $1 AND lemma_id = $2)"#,
+ i,
+ p
+ }
+ .execute(pool)
+ .await?
+ }
+ (_, _) => todo!(),
+ };
+ Ok(())
+ }
+
+ async fn submit_modification_with(
+ &self,
+ parent: &LemmaItem,
+ pool: &sqlx::Pool,
+ ) -> sqlx::Result<()> {
+ let konsep = KonsepItem::partial_from_mod(self);
+ tracing::trace!(
+ "Modifying <{}:{}> with <{}:{}>",
+ konsep.id,
+ konsep.keterangan,
+ parent.id,
+ parent.lemma
+ );
+ match (konsep.id, parent.id) {
+ (AutoGen::Known(i), AutoGen::Known(p)) => sqlx::query! {
+ r#" UPDATE konsep
+ SET keterangan = $1, golongan_id = (SELECT id FROM golongan_kata WHERE golongan_kata.nama = $2)
+ WHERE (
+ id = $3
+ AND
+ lemma_id = $4
+ )
+ "#,
+ konsep.keterangan,
+ konsep.golongan_kata,
+ i,
+ p,
+ }
+ .execute(pool)
+ .await?,
+ (_,_) => todo!()
+ };
+ self.cakupans.submit_changes_with(&konsep, pool).await?;
+ self.kata_asing.submit_changes_with(&konsep, pool).await?;
+ Ok(())
+ }
+}
+
+type Key = (I, Option, Option);
type Value = Vec;
-pub(crate) type KonsepHashMap = HashMap;
+pub(crate) type KonsepHashMap = HashMap, Value>;
-impl Item for KonsepItem {
- type IntoMod = KonsepItemMod;
+impl Item for KonsepItem {
+ type IntoMod = KonsepItemMod;
fn modify_into(&self, other: &Self) -> Result {
if self.id != other.id {
return Err(BackendError {
- message: format!("ID Assertion error, {} != {}", self.id, other.id),
+ // message: format!("ID Assertion error, {} != {}", self.id, other.id),
+ message: format!("ID Assertion error"),
});
}
Ok(KonsepItemMod {
@@ -214,10 +344,10 @@ impl Item for KonsepItem {
}
}
-impl FromViewMap for KonsepItem {
- type KEY = Key;
+impl FromViewMap for KonsepItem {
+ type KEY = Key;
type VALUE = Value;
- fn from_viewmap(value: &KonsepHashMap) -> Vec {
+ fn from_viewmap(value: &KonsepHashMap) -> Vec {
let mut data = Vec::new();
for (konsep, views) in value.iter().filter(|((_, kon, _), _)| kon.is_some()) {
data.push(KonsepItem {
diff --git a/backend/database/src/data/items/lemma.rs b/backend/database/src/data/items/lemma.rs
index 028fe0a..b804043 100644
--- a/backend/database/src/data/items/lemma.rs
+++ b/backend/database/src/data/items/lemma.rs
@@ -10,7 +10,7 @@ use crate::{
};
use crate::io::interface::SubmitMod;
-use std::collections::HashMap;
+use std::{collections::HashMap, fmt::Display};
use tracing::instrument;
use super::konsep::KonsepHashMap;
@@ -42,10 +42,10 @@ use super::konsep::KonsepHashMap;
/// ```
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ts_rs::TS)]
#[ts(export, export_to = "../../src/bindings/")]
-pub struct LemmaItem {
- pub id: AutoGen,
+pub struct LemmaItem {
+ pub id: AutoGen,
pub lemma: String,
- pub konseps: Vec,
+ pub konseps: Vec>,
}
/// A modified [LemmaItem].
@@ -131,14 +131,14 @@ pub struct LemmaItem {
/// assert_eq!(lemma_modded.konseps.detached, vec![]);
/// ```
#[derive(Debug, Clone)]
-pub struct LemmaItemMod {
- pub id: AutoGen,
+pub struct LemmaItemMod {
+ pub id: AutoGen,
pub lemma: FieldMod,
- pub konseps: AttachmentMod,
+ pub konseps: AttachmentMod>,
}
-impl Item for LemmaItem {
- type IntoMod = LemmaItemMod;
+impl Item for LemmaItem {
+ type IntoMod = LemmaItemMod;
fn modify_into(&self, other: &Self) -> Result {
if self.id != other.id {
Err(BackendError {
@@ -153,7 +153,7 @@ impl Item for LemmaItem {
}
}
- fn partial_from_mod(other: &LemmaItemMod) -> Self {
+ fn partial_from_mod(other: &LemmaItemMod) -> Self {
LemmaItem {
id: other.id,
lemma: other.lemma.value().to_string(),
@@ -162,8 +162,8 @@ impl Item for LemmaItem {
}
}
-impl ItemMod for LemmaItemMod {
- type FromItem = LemmaItem;
+impl ItemMod for LemmaItemMod {
+ type FromItem = LemmaItem;
fn from_item(value: &Self::FromItem) -> Self {
Self {
@@ -176,7 +176,7 @@ impl ItemMod for LemmaItemMod {
#[cfg(feature = "sqlite")]
#[async_trait::async_trait]
-impl SubmitMod for LemmaItemMod {
+impl SubmitMod for LemmaItemMod {
type Engine = sqlx::Sqlite;
#[instrument(skip_all)]
async fn submit_mod(&self, pool: &sqlx::Pool) -> sqlx::Result<()> {
@@ -188,7 +188,7 @@ impl SubmitMod for LemmaItemMod {
}
}
-impl PartialEq for LemmaItem {
+impl PartialEq for LemmaItem {
fn eq(&self, other: &Self) -> bool {
let konseps = Vec::from_iter(self.konseps.clone());
self.lemma == other.lemma
@@ -203,7 +203,7 @@ impl PartialEq for LemmaItem {
#[cfg(feature = "sqlite")]
#[async_trait::async_trait]
-impl SubmitItem for LemmaItem {
+impl SubmitItem for LemmaItem {
type Engine = sqlx::Sqlite;
async fn submit_full(&self, pool: &sqlx::Pool) -> sqlx::Result<()> {
let _ = self.submit_partial(pool).await?;
@@ -244,7 +244,7 @@ impl SubmitItem for LemmaItem {
#[cfg(feature = "postgres")]
#[async_trait::async_trait]
-impl SubmitItem for LemmaItem {
+impl SubmitItem for LemmaItem {
type Engine = sqlx::Postgres;
async fn submit_full(&self, pool: &sqlx::Pool) -> sqlx::Result<()> {
@@ -258,10 +258,16 @@ impl SubmitItem for LemmaItem {
}
async fn submit_partial(&self, pool: &sqlx::Pool) -> sqlx::Result<()> {
- sqlx::query! {
- r#"INSERT or IGNORE INTO lemma (id, nama) VALUES (?, ?)"#,
- self.id,
- self.lemma
+ match self.id {
+ AutoGen::Known(i) => sqlx::query! {
+ r#"INSERT INTO lemma (id, nama) VALUES ($1, $2) ON CONFLICT (id, nama) DO NOTHING;"#,
+ i,
+ self.lemma
+ },
+ AutoGen::Unknown => sqlx::query!{
+ r#"INSERT INTO lemma (nama) VALUES ($1);"#,
+ self.lemma
+ }
}
.execute(pool)
.await?;
@@ -273,23 +279,28 @@ impl SubmitItem for LemmaItem {
}
async fn submit_partial_removal(&self, pool: &sqlx::Pool) -> sqlx::Result<()> {
- sqlx::query! {
- r#"DELETE FROM lemma WHERE (lemma.id = ? AND lemma.nama = ?)"#,
- self.id,
- self.lemma
- }
- .execute(pool)
- .await?;
+ match self.id {
+ AutoGen::Known(i) => {
+ sqlx::query! {
+ r#"DELETE FROM lemma WHERE (lemma.id = $1 AND lemma.nama = $2)"#,
+ i,
+ self.lemma
+ }
+ .execute(pool)
+ .await?
+ }
+ AutoGen::Unknown => todo!(),
+ };
Ok(())
}
}
-impl FromViewMap for LemmaItem {
+impl FromViewMap for LemmaItem {
type KEY = (i64, String);
- type VALUE = KonsepHashMap;
+ type VALUE = KonsepHashMap;
- fn from_viewmap(value: &HashMap) -> Vec {
- let mut data = Vec::::new();
+ fn from_viewmap(value: &HashMap) -> Vec> {
+ let mut data = Vec::>::new();
for (lemma, konsep_map) in value.iter() {
data.push(LemmaItem {
id: AutoGen::Known(lemma.0),
@@ -300,10 +311,33 @@ impl FromViewMap for LemmaItem {
data
}
}
-impl FromView for LemmaItem {
+impl FromViewMap for LemmaItem {
+ type KEY = (i32, String);
+ type VALUE = KonsepHashMap;
+
+ fn from_viewmap(value: &HashMap) -> Vec> {
+ let mut data = Vec::>::new();
+ for (lemma, konsep_map) in value.iter() {
+ data.push(LemmaItem {
+ id: AutoGen::Known(lemma.0),
+ lemma: lemma.1.clone(),
+ konseps: KonsepItem::from_viewmap(konsep_map),
+ })
+ }
+ data
+ }
+}
+// impl FromView for LemmaItem {
+// type VIEW = LemmaWithKonsepView;
+
+// fn from_views(views: &Vec) -> Vec> {
+// Self::from_viewmap(&(views.clone().into_viewmap()))
+// }
+// }
+impl FromView for LemmaItem {
type VIEW = LemmaWithKonsepView;
- fn from_views(views: &Vec) -> Vec {
+ fn from_views(views: &Vec) -> Vec> {
Self::from_viewmap(&(views.clone().into_viewmap()))
}
}
diff --git a/backend/database/src/io/interface.rs b/backend/database/src/io/interface.rs
index 0d73d48..82cd55b 100644
--- a/backend/database/src/io/interface.rs
+++ b/backend/database/src/io/interface.rs
@@ -13,7 +13,7 @@ pub trait View {
}
/// A trait to convert Vec<[View]> into Vec<[Item]>
-pub trait FromView: Item {
+pub trait FromView: Sized {
/// The view that is to be converted
type VIEW;
@@ -22,7 +22,7 @@ pub trait FromView: Item {
}
/// A trait that converts [HashMap] into Vec<[Item]>.
-pub trait FromViewMap: Item {
+pub trait FromViewMap: Sized {
/// Keys of the input [HashMap], typically the ID but can also be a tuple of identifiers.
type KEY;
/// The value of the input [HashMap].
@@ -52,7 +52,7 @@ pub trait IntoViewMap: IntoIterator- {
/// A [View] handles the querying from SQL which contains flat tabular data.
/// While and [Item] represents the intended data which is often nested.
/// Traits like [FromView] and [FromViewMap] provides the translation layer between [View] and [Item].
-pub trait Item: Sized {
+pub trait Item {
/// The Modified version of [Self].
type IntoMod: ItemMod;
@@ -69,7 +69,7 @@ pub trait Item: Sized {
/// A trait which allows item data to be submitted into SQL databases.
#[async_trait::async_trait]
-pub trait SubmitItem: Item {
+pub trait SubmitItem {
type Engine: sqlx::Database;
/// Inserts item with corresponding children.
async fn submit_full(&self, pool: &sqlx::Pool) -> sqlx::Result<()>;
@@ -103,14 +103,27 @@ pub trait SubmitMod: ItemMod {
/// A trait which allows attachment items to be submitted into SQL database as [ItemMod].
#[async_trait::async_trait]
-pub trait AttachmentItemMod: ItemMod {
+pub trait AttachmentItemMod: ItemMod {
+ type Engine: sqlx::Database;
+
/// Submit [Self] to parent item.
- async fn submit_attachment_to(&self, parent: &P, pool: &sqlx::Pool) -> sqlx::Result<()>;
+ async fn submit_attachment_to(
+ &self,
+ parent: &P,
+ pool: &sqlx::Pool,
+ ) -> sqlx::Result<()>;
/// Detaches [Self] to parent item.
- async fn submit_detachment_from(&self, parent: &P, pool: &sqlx::Pool) -> sqlx::Result<()>;
+ async fn submit_detachment_from(
+ &self,
+ parent: &P,
+ pool: &sqlx::Pool,
+ ) -> sqlx::Result<()>;
/// Modifies [Self].
- async fn submit_modification_with(&self, parent: &P, pool: &sqlx::Pool)
- -> sqlx::Result<()>;
+ async fn submit_modification_with(
+ &self,
+ parent: &P,
+ pool: &sqlx::Pool,
+ ) -> sqlx::Result<()>;
}
diff --git a/backend/database/src/states.rs b/backend/database/src/states.rs
index 67f3070..0d73434 100644
--- a/backend/database/src/states.rs
+++ b/backend/database/src/states.rs
@@ -2,33 +2,30 @@
use sqlx::migrate::MigrateDatabase;
use sqlx::migrate::{Migrate, MigrateError};
+use sqlx::FromRow;
use crate::errors::Result;
use crate::prelude::BackendError;
-pub use sqlx::Pool;
-#[cfg(feature = "sqlite")]
-pub use sqlx::Sqlite;
-
// TODO: Refactor this module
/// Connection to database
#[derive(Debug, Clone)]
pub struct Connection {
#[allow(missing_docs)]
- pub pool: Pool,
+ pub pool: sqlx::Pool,
}
/// Counts of selected items.
#[allow(missing_docs)]
#[derive(Debug, Clone, Default, serde::Serialize, PartialEq, ts_rs::TS)]
#[ts(export, export_to = "../../src/bindings/")]
-pub struct Counts {
- lemmas: i32,
- konseps: i32,
- golongan_katas: i32,
- cakupans: i32,
- kata_asings: i32,
+pub struct Counts {
+ lemmas: I,
+ konseps: I,
+ golongan_katas: I,
+ cakupans: I,
+ kata_asings: I,
}
/// A helper struct for when a single string value is queried.
@@ -37,6 +34,41 @@ pub struct StringItem {
pub item: String,
}
+impl Counts