Db layers #14
No files matched your search
Generated
+6
-2
@@ -2456,6 +2456,7 @@ dependencies = [
|
|||||||
"hex",
|
"hex",
|
||||||
"iced",
|
"iced",
|
||||||
"iced_core",
|
"iced_core",
|
||||||
|
"litemap",
|
||||||
"log",
|
"log",
|
||||||
"mimalloc",
|
"mimalloc",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
@@ -2739,9 +2740,12 @@ checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "litemap"
|
name = "litemap"
|
||||||
version = "0.8.2"
|
version = "0.8.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0"
|
checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae"
|
||||||
|
dependencies = [
|
||||||
|
"serde_core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "litrs"
|
name = "litrs"
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ parking_lot = "0.12.5"
|
|||||||
env_logger = "0.11.11"
|
env_logger = "0.11.11"
|
||||||
log = "0.4.34"
|
log = "0.4.34"
|
||||||
fsrs = "6.6.1"
|
fsrs = "6.6.1"
|
||||||
|
litemap = { version = "0.8.3", features = ["serde"] }
|
||||||
|
|
||||||
[profile.super-release]
|
[profile.super-release]
|
||||||
inherits = "release"
|
inherits = "release"
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ use rusqlite::Connection;
|
|||||||
pub const USER_FONT: Font = Font::with_name("Noto Sans JP");
|
pub const USER_FONT: Font = Font::with_name("Noto Sans JP");
|
||||||
|
|
||||||
pub fn start() -> iced::Result {
|
pub fn start() -> iced::Result {
|
||||||
|
println!("{}", size_of::<WordData>());
|
||||||
info!("Welcome to JapLearn");
|
info!("Welcome to JapLearn");
|
||||||
iced::application(ScreenState::boot, ScreenState::update, ScreenState::view)
|
iced::application(ScreenState::boot, ScreenState::update, ScreenState::view)
|
||||||
.window(window_settings())
|
.window(window_settings())
|
||||||
|
|||||||
+32
-25
@@ -7,57 +7,64 @@ use std::fmt::{write, Display, Formatter};
|
|||||||
use std::num::ParseIntError;
|
use std::num::ParseIntError;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Hash, Copy, Ord, PartialOrd, Default)]
|
macro_rules! id_impl {
|
||||||
pub struct Id(pub(crate) u32);
|
($id_type:ty, $name:ident, $invalid:ident) => {
|
||||||
pub const INVALID_ID: Id = Id(0);
|
#[derive(Clone, PartialEq, Eq, Debug, Hash, Copy, Ord, PartialOrd, Default)]
|
||||||
impl FromStr for Id {
|
pub struct $name(pub(crate) $id_type);
|
||||||
|
pub const $invalid: $name = $name(0);
|
||||||
|
impl FromStr for $name {
|
||||||
type Err = ParseIntError;
|
type Err = ParseIntError;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
Ok(Id(s.parse::<u32>()?))
|
Ok($name(s.parse::<$id_type>()?))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u32> for Id {
|
|
||||||
fn from(value: u32) -> Self {
|
|
||||||
Id(value)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Id> for u32 {
|
impl From<$id_type> for $name {
|
||||||
fn from(value: Id) -> Self {
|
fn from(value: $id_type) -> Self {
|
||||||
|
$name(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<$name> for $id_type {
|
||||||
|
fn from(value: $name) -> Self {
|
||||||
value.0
|
value.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Display for Id {
|
impl Display for $name {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "{}", self.0)
|
write!(f, "{}", self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromSql for Id {
|
impl FromSql for $name {
|
||||||
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
|
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
|
||||||
match value {
|
match value {
|
||||||
ValueRef::Integer(i) => Ok(Id(i as u32)),
|
ValueRef::Integer(i) => Ok($name(i as $id_type)),
|
||||||
_ => Err(FromSqlError::InvalidType),
|
_ => Err(FromSqlError::InvalidType),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToSql for Id {
|
impl ToSql for $name {
|
||||||
fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
|
fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
|
||||||
Ok(ToSqlOutput::from(self.0 as i64))
|
Ok(ToSqlOutput::from(self.0 as i64))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Id> for String {
|
impl From<$name> for String {
|
||||||
fn from(value: Id) -> Self {
|
fn from(value: $name) -> Self {
|
||||||
value.0.to_string()
|
value.0.to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Id {
|
impl $name {
|
||||||
pub(crate) fn is_valid(self) -> bool {
|
pub(crate) fn is_valid(self) -> bool {
|
||||||
self.0 != 0
|
self.0 != 0
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
id_impl!(u32, Id, INVALID_ID);
|
||||||
|
id_impl!(u16, SmallId, INVALID_SMALL_ID);
|
||||||
+24
-3
@@ -7,18 +7,18 @@ use log::info;
|
|||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use rhai::{Engine, Scope};
|
use rhai::{Engine, Scope};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
use litemap::LiteMap;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct WordData {
|
pub struct WordData {
|
||||||
pub id: Id,
|
pub id: Id,
|
||||||
|
pub group_id: Id,
|
||||||
pub key: String,
|
pub key: String,
|
||||||
pub value: String,
|
pub value: String,
|
||||||
pub tags: String,
|
pub tags: String,
|
||||||
pub additional: HashMap<String, String>,
|
pub additional: LiteMap<String, String>,
|
||||||
pub group_id: Id,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EntityData for WordData {
|
impl EntityData for WordData {
|
||||||
@@ -37,6 +37,16 @@ pub struct WordGroup {
|
|||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl EntityData for WordGroup {
|
||||||
|
fn id(&self) -> Id {
|
||||||
|
self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_id(&mut self, id: Id) {
|
||||||
|
self.id = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl WordData {
|
impl WordData {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -155,6 +165,17 @@ pub struct CardState {
|
|||||||
pub fsrs_memory: Option<MemoryState>,
|
pub fsrs_memory: Option<MemoryState>,
|
||||||
pub fsrs_open_day: NaiveDate,
|
pub fsrs_open_day: NaiveDate,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl EntityData for CardState {
|
||||||
|
fn id(&self) -> Id {
|
||||||
|
self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_id(&mut self, id: Id) {
|
||||||
|
self.id = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl CardState {
|
impl CardState {
|
||||||
pub fn update(&mut self, status: WordOpenMode) {
|
pub fn update(&mut self, status: WordOpenMode) {
|
||||||
match status {
|
match status {
|
||||||
|
|||||||
@@ -65,8 +65,13 @@ pub fn default_connection() -> Connection {
|
|||||||
.execute("PRAGMA foreign_keys = ON;", [])
|
.execute("PRAGMA foreign_keys = ON;", [])
|
||||||
.expect("Failed to set PRAGMA");
|
.expect("Failed to set PRAGMA");
|
||||||
connection
|
connection
|
||||||
.execute("PRAGMA journal_mode = WAL;", [])
|
.query_one("PRAGMA journal_mode = WAL;", [], |row| {
|
||||||
.expect("Failed to set PRAGMA");
|
println!("{:?}", row);
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|e| {
|
||||||
|
println!("{}", e);
|
||||||
|
});
|
||||||
connection
|
connection
|
||||||
.execute("PRAGMA synchronous = NORMAL;", [])
|
.execute("PRAGMA synchronous = NORMAL;", [])
|
||||||
.expect("Failed to set PRAGMA");
|
.expect("Failed to set PRAGMA");
|
||||||
|
|||||||
@@ -1,8 +1,96 @@
|
|||||||
use crate::data::entities::{WordData, WordGroup};
|
use crate::data::entities::{WordData, WordGroup};
|
||||||
|
use crate::data_provider::TableAccessQuerySet;
|
||||||
use crate::notification::NotificationData::{DbLoadError, DbSaveError};
|
use crate::notification::NotificationData::{DbLoadError, DbSaveError};
|
||||||
use crate::notification::{MaybeError, NotificationData};
|
use crate::notification::{MaybeError, NotificationData};
|
||||||
use rusqlite::{Connection, params};
|
use rusqlite::{Connection, Error, Params, Row, params};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use litemap::LiteMap;
|
||||||
|
|
||||||
|
pub struct WordQuerySet;
|
||||||
|
impl TableAccessQuerySet<WordData> for WordQuerySet {
|
||||||
|
fn load() -> &'static str {
|
||||||
|
"SELECT id, key, value, tags, more, group_id FROM words"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn save() -> &'static str {
|
||||||
|
"UPDATE words SET key = ?1, value = ?2, tags = ?3, more = ?4 WHERE id = ?5"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add() -> &'static str {
|
||||||
|
"INSERT INTO words (key, value, tags, more, group_id) VALUES (?1, ?2, ?3, ?4, ?5)"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name() -> &'static str {
|
||||||
|
"words"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_sql(row: &Row) -> Result<WordData, Error> {
|
||||||
|
let additional: String = row.get(4)?;
|
||||||
|
Ok(WordData {
|
||||||
|
id: row.get(0)?,
|
||||||
|
key: row.get(1)?,
|
||||||
|
value: row.get(2)?,
|
||||||
|
tags: row.get(3)?,
|
||||||
|
additional: serde_json::from_str(&additional)
|
||||||
|
.unwrap_or_default(),
|
||||||
|
group_id: row.get(5)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert_params(entity: &WordData) -> impl Params {
|
||||||
|
(
|
||||||
|
&entity.key,
|
||||||
|
&entity.value,
|
||||||
|
&entity.tags,
|
||||||
|
serde_json::to_string(&entity.additional).unwrap_or_default(),
|
||||||
|
entity.group_id,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_params(entity: &WordData) -> impl Params {
|
||||||
|
(
|
||||||
|
&entity.key,
|
||||||
|
&entity.value,
|
||||||
|
&entity.tags,
|
||||||
|
serde_json::to_string(&entity.additional).unwrap_or_default(),
|
||||||
|
entity.id,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct WordGroupQuerySet;
|
||||||
|
impl TableAccessQuerySet<WordGroup> for WordGroupQuerySet {
|
||||||
|
fn load() -> &'static str {
|
||||||
|
"SELECT id, name FROM word_groups"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn save() -> &'static str {
|
||||||
|
"UPDATE word_groups SET name = ?1 WHERE id = ?2"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add() -> &'static str {
|
||||||
|
"INSERT INTO word_groups (name) VALUES (?1)"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name() -> &'static str {
|
||||||
|
"word_groups"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_sql(row: &Row) -> Result<WordGroup, Error> {
|
||||||
|
Ok(WordGroup {
|
||||||
|
id: row.get(0)?,
|
||||||
|
name: row.get(1)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert_params(entity: &WordGroup) -> impl Params {
|
||||||
|
(&entity.name,)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_params(entity: &WordGroup) -> impl Params {
|
||||||
|
(&entity.name, entity.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_word(word: &mut WordData, connection: &Connection) -> MaybeError {
|
pub fn add_word(word: &mut WordData, connection: &Connection) -> MaybeError {
|
||||||
let index : u32 = connection
|
let index : u32 = connection
|
||||||
@@ -99,7 +187,7 @@ pub fn load_words(connection: &Connection) -> Result<Vec<WordData>, Notification
|
|||||||
key: row.get(1)?,
|
key: row.get(1)?,
|
||||||
value: row.get(2)?,
|
value: row.get(2)?,
|
||||||
tags: row.get(3)?,
|
tags: row.get(3)?,
|
||||||
additional: serde_json::from_str::<HashMap<String, String>>(&additional)
|
additional: serde_json::from_str(&additional)
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
group_id: row.get(5)?,
|
group_id: row.get(5)?,
|
||||||
})
|
})
|
||||||
|
|||||||
+2
-2
@@ -139,7 +139,7 @@ impl NotificationManager {
|
|||||||
fn draw_data<'a>(data: &NotificationData) -> Element<'a, NotificationMessage> {
|
fn draw_data<'a>(data: &NotificationData) -> Element<'a, NotificationMessage> {
|
||||||
match data {
|
match data {
|
||||||
NotificationData::DataLoaded => {
|
NotificationData::DataLoaded => {
|
||||||
text!("Данные успешно скачаны")
|
text!("Данные успешно загружены на сервер")
|
||||||
}
|
}
|
||||||
NotificationData::ImportError => {
|
NotificationData::ImportError => {
|
||||||
text!("Ошибка при импорте данных из Anki")
|
text!("Ошибка при импорте данных из Anki")
|
||||||
@@ -154,7 +154,7 @@ impl NotificationManager {
|
|||||||
text!("Не получается подключиться к VoiceVox")
|
text!("Не получается подключиться к VoiceVox")
|
||||||
}
|
}
|
||||||
NotificationData::PermissionDenied => {
|
NotificationData::PermissionDenied => {
|
||||||
text!("У приложение недостаточно прав")
|
text!("У приложение недостаточно прав для доступа в файлам")
|
||||||
}
|
}
|
||||||
NotificationData::WebApiUnavailable => {
|
NotificationData::WebApiUnavailable => {
|
||||||
text!("Не получается подключиться к Api")
|
text!("Не получается подключиться к Api")
|
||||||
|
|||||||
Reference in new issue
Block a user