From c9225680c3075c8230b02b2cb5436d5318e4745e Mon Sep 17 00:00:00 2001 From: Chris Cochrun Date: Tue, 12 Nov 2024 06:29:24 -0600 Subject: [PATCH] adding all of our core sql systems --- .envrc | 1 - ...97d4c604fe7b755fdcb6773692c813b5e1d4b.json | 38 ++ ...887be69527e6fda128b11a6279cd8cf410918.json | 32 ++ ...ec9c68244defd5ea85764979535e1b2267496.json | 32 ++ ...f28a36ef703387d3f9eace9f51f102b1ed6da.json | 50 ++ ...cf79915ef389eedb009daef3be737709266f8.json | 50 ++ Cargo.lock | 540 +++++++++++++++++- Cargo.toml | 3 + flake.nix | 2 + migrations/20241112030535_initial.sql | 43 ++ migrations/20241112120121_alter_columns.sql | 33 ++ rustfmt.toml | 3 + src/core/images.rs | 64 ++- src/core/kinds.rs | 19 +- src/core/mod.rs | 7 + src/core/model.rs | 63 +- src/core/presentations.rs | 68 ++- src/core/service_items.rs | 20 +- src/core/songs.rs | 150 +++-- src/core/videos.rs | 64 +-- 20 files changed, 1055 insertions(+), 227 deletions(-) create mode 100644 .sqlx/query-7ace613c138f874198ea8e5f72697d4c604fe7b755fdcb6773692c813b5e1d4b.json create mode 100644 .sqlx/query-8cc171f2be70148e4178fa23d34887be69527e6fda128b11a6279cd8cf410918.json create mode 100644 .sqlx/query-aa01b675a8e40d152144b3b6a11ec9c68244defd5ea85764979535e1b2267496.json create mode 100644 .sqlx/query-d4b324ece51b3a314367f570bb7f28a36ef703387d3f9eace9f51f102b1ed6da.json create mode 100644 .sqlx/query-f6c1c41a68b04f939301d6bb897cf79915ef389eedb009daef3be737709266f8.json create mode 100644 migrations/20241112030535_initial.sql create mode 100644 migrations/20241112120121_alter_columns.sql create mode 100644 rustfmt.toml diff --git a/.envrc b/.envrc index ca8cc5d..0707511 100644 --- a/.envrc +++ b/.envrc @@ -1,4 +1,3 @@ -export DATABASE_URL=sqlite://~/.local/share/lumina/library-db.sqlite3 use flake . --impure # eval $(guix shell -D --search-paths) diff --git a/.sqlx/query-7ace613c138f874198ea8e5f72697d4c604fe7b755fdcb6773692c813b5e1d4b.json b/.sqlx/query-7ace613c138f874198ea8e5f72697d4c604fe7b755fdcb6773692c813b5e1d4b.json new file mode 100644 index 0000000..5757ece --- /dev/null +++ b/.sqlx/query-7ace613c138f874198ea8e5f72697d4c604fe7b755fdcb6773692c813b5e1d4b.json @@ -0,0 +1,38 @@ +{ + "db_name": "SQLite", + "query": "SELECT id as \"id: i32\", title, file_path as \"path\", html from presentations", + "describe": { + "columns": [ + { + "name": "id: i32", + "ordinal": 0, + "type_info": "Integer" + }, + { + "name": "title", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "path", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "html", + "ordinal": 3, + "type_info": "Bool" + } + ], + "parameters": { + "Right": 0 + }, + "nullable": [ + false, + false, + false, + false + ] + }, + "hash": "7ace613c138f874198ea8e5f72697d4c604fe7b755fdcb6773692c813b5e1d4b" +} diff --git a/.sqlx/query-8cc171f2be70148e4178fa23d34887be69527e6fda128b11a6279cd8cf410918.json b/.sqlx/query-8cc171f2be70148e4178fa23d34887be69527e6fda128b11a6279cd8cf410918.json new file mode 100644 index 0000000..a8dbdd4 --- /dev/null +++ b/.sqlx/query-8cc171f2be70148e4178fa23d34887be69527e6fda128b11a6279cd8cf410918.json @@ -0,0 +1,32 @@ +{ + "db_name": "SQLite", + "query": "SELECT title as \"title!\", file_path as \"path!\", id as \"id: i32\" from images", + "describe": { + "columns": [ + { + "name": "title!", + "ordinal": 0, + "type_info": "Text" + }, + { + "name": "path!", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "id: i32", + "ordinal": 2, + "type_info": "Integer" + } + ], + "parameters": { + "Right": 0 + }, + "nullable": [ + false, + false, + false + ] + }, + "hash": "8cc171f2be70148e4178fa23d34887be69527e6fda128b11a6279cd8cf410918" +} diff --git a/.sqlx/query-aa01b675a8e40d152144b3b6a11ec9c68244defd5ea85764979535e1b2267496.json b/.sqlx/query-aa01b675a8e40d152144b3b6a11ec9c68244defd5ea85764979535e1b2267496.json new file mode 100644 index 0000000..0831b5b --- /dev/null +++ b/.sqlx/query-aa01b675a8e40d152144b3b6a11ec9c68244defd5ea85764979535e1b2267496.json @@ -0,0 +1,32 @@ +{ + "db_name": "SQLite", + "query": "SELECT title as \"title!\", file_path as \"path!\", id as \"id: i32\" from images where id = ?", + "describe": { + "columns": [ + { + "name": "title!", + "ordinal": 0, + "type_info": "Text" + }, + { + "name": "path!", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "id: i32", + "ordinal": 2, + "type_info": "Integer" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + false, + false, + false + ] + }, + "hash": "aa01b675a8e40d152144b3b6a11ec9c68244defd5ea85764979535e1b2267496" +} diff --git a/.sqlx/query-d4b324ece51b3a314367f570bb7f28a36ef703387d3f9eace9f51f102b1ed6da.json b/.sqlx/query-d4b324ece51b3a314367f570bb7f28a36ef703387d3f9eace9f51f102b1ed6da.json new file mode 100644 index 0000000..7c6ead1 --- /dev/null +++ b/.sqlx/query-d4b324ece51b3a314367f570bb7f28a36ef703387d3f9eace9f51f102b1ed6da.json @@ -0,0 +1,50 @@ +{ + "db_name": "SQLite", + "query": "SELECT title as \"title!\", file_path as \"path!\", start_time as \"start_time!: f32\", end_time as \"end_time!: f32\", loop as \"looping!\", id as \"id: i32\" from videos where id = ?", + "describe": { + "columns": [ + { + "name": "title!", + "ordinal": 0, + "type_info": "Text" + }, + { + "name": "path!", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "start_time!: f32", + "ordinal": 2, + "type_info": "Null" + }, + { + "name": "end_time!: f32", + "ordinal": 3, + "type_info": "Null" + }, + { + "name": "looping!", + "ordinal": 4, + "type_info": "Bool" + }, + { + "name": "id: i32", + "ordinal": 5, + "type_info": "Integer" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + false, + false, + true, + true, + false, + false + ] + }, + "hash": "d4b324ece51b3a314367f570bb7f28a36ef703387d3f9eace9f51f102b1ed6da" +} diff --git a/.sqlx/query-f6c1c41a68b04f939301d6bb897cf79915ef389eedb009daef3be737709266f8.json b/.sqlx/query-f6c1c41a68b04f939301d6bb897cf79915ef389eedb009daef3be737709266f8.json new file mode 100644 index 0000000..7eefc00 --- /dev/null +++ b/.sqlx/query-f6c1c41a68b04f939301d6bb897cf79915ef389eedb009daef3be737709266f8.json @@ -0,0 +1,50 @@ +{ + "db_name": "SQLite", + "query": "SELECT title as \"title!\", file_path as \"path!\", start_time as \"start_time!: f32\", end_time as \"end_time!: f32\", loop as \"looping!\", id as \"id: i32\" from videos", + "describe": { + "columns": [ + { + "name": "title!", + "ordinal": 0, + "type_info": "Text" + }, + { + "name": "path!", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "start_time!: f32", + "ordinal": 2, + "type_info": "Float" + }, + { + "name": "end_time!: f32", + "ordinal": 3, + "type_info": "Float" + }, + { + "name": "looping!", + "ordinal": 4, + "type_info": "Bool" + }, + { + "name": "id: i32", + "ordinal": 5, + "type_info": "Integer" + } + ], + "parameters": { + "Right": 0 + }, + "nullable": [ + false, + false, + true, + true, + false, + false + ] + }, + "hash": "f6c1c41a68b04f939301d6bb897cf79915ef389eedb009daef3be737709266f8" +} diff --git a/Cargo.lock b/Cargo.lock index 589b7a1..833e761 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -541,6 +541,15 @@ dependencies = [ "syn 2.0.81", ] +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -653,6 +662,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bit-set" version = "0.6.0" @@ -1036,6 +1051,12 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "const-random" version = "0.1.18" @@ -1209,6 +1230,21 @@ dependencies = [ "libc", ] +[[package]] +name = "crc" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + [[package]] name = "crc32fast" version = "1.4.2" @@ -1246,6 +1282,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.20" @@ -1348,6 +1393,17 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + [[package]] name = "deranged" version = "0.3.11" @@ -1393,7 +1449,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", + "subtle", ] [[package]] @@ -1462,6 +1520,12 @@ dependencies = [ "litrs", ] +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + [[package]] name = "downcast-rs" version = "1.2.1" @@ -1517,6 +1581,9 @@ name = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +dependencies = [ + "serde", +] [[package]] name = "endi" @@ -1577,6 +1644,17 @@ dependencies = [ "svg_fmt", ] +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if", + "home", + "windows-sys 0.48.0", +] + [[package]] name = "euclid" version = "0.22.11" @@ -1710,6 +1788,8 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" dependencies = [ + "futures-core", + "futures-sink", "spin", ] @@ -1876,6 +1956,17 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot 0.12.3", +] + [[package]] name = "futures-io" version = "0.3.31" @@ -2381,6 +2472,15 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +[[package]] +name = "hashlink" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" +dependencies = [ + "hashbrown 0.14.5", +] + [[package]] name = "hassle-rs" version = "0.11.0" @@ -2432,6 +2532,33 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "html-escape" version = "0.2.13" @@ -2973,6 +3100,9 @@ name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] [[package]] name = "lebe" @@ -3076,6 +3206,17 @@ dependencies = [ "redox_syscall 0.5.7", ] +[[package]] +name = "libsqlite3-sys" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linux-raw-sys" version = "0.3.8" @@ -3127,6 +3268,7 @@ name = "lumina" version = "0.1.0" dependencies = [ "clap", + "dirs", "iced_video_player", "lexpr", "libcosmic", @@ -3135,8 +3277,10 @@ dependencies = [ "ron", "serde", "serde-lexpr", + "sqlx", "strum", "strum_macros", + "tokio", "tracing", "tracing-subscriber", ] @@ -3211,6 +3355,16 @@ dependencies = [ "regex-automata 0.1.10", ] +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + [[package]] name = "memchr" version = "2.7.4" @@ -3307,6 +3461,12 @@ dependencies = [ "smithay-clipboard", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.7.4" @@ -3447,6 +3607,16 @@ dependencies = [ "memoffset 0.9.1", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "notify" version = "6.1.1" @@ -3500,6 +3670,23 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "smallvec", + "zeroize", +] + [[package]] name = "num-complex" version = "0.4.6" @@ -4018,6 +4205,15 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -4115,6 +4311,27 @@ dependencies = [ "futures-io", ] +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "pkg-config" version = "0.3.31" @@ -4508,6 +4725,26 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" +[[package]] +name = "rsa" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "signature", + "spki", + "subtle", + "zeroize", +] + [[package]] name = "rust-ini" version = "0.20.0" @@ -4695,6 +4932,18 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "sha1" version = "0.10.6" @@ -4706,6 +4955,17 @@ dependencies = [ "digest", ] +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sharded-slab" version = "0.1.7" @@ -4730,6 +4990,16 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + [[package]] name = "simd-adler32" version = "0.3.7" @@ -4790,6 +5060,9 @@ name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +dependencies = [ + "serde", +] [[package]] name = "smawk" @@ -4913,6 +5186,217 @@ dependencies = [ "bitflags 2.6.0", ] +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "sqlformat" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790" +dependencies = [ + "nom", + "unicode_categories", +] + +[[package]] +name = "sqlx" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93334716a037193fac19df402f8571269c84a00852f6a7066b5d2616dcd64d3e" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d8060b456358185f7d50c55d9b5066ad956956fddec42ee2e8567134a8936e" +dependencies = [ + "atoi", + "byteorder", + "bytes", + "crc", + "crossbeam-queue", + "either", + "event-listener 5.3.1", + "futures-channel", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashbrown 0.14.5", + "hashlink", + "hex", + "indexmap", + "log", + "memchr", + "once_cell", + "paste", + "percent-encoding", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlformat", + "thiserror", + "tracing", + "url", +] + +[[package]] +name = "sqlx-macros" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cac0692bcc9de3b073e8d747391827297e075c7710ff6276d9f7a1f3d58c6657" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 2.0.81", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1804e8a7c7865599c9c79be146dc8a9fd8cc86935fa641d3ea58e5f0688abaa5" +dependencies = [ + "dotenvy", + "either", + "heck 0.5.0", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2", + "sqlx-core", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", + "syn 2.0.81", + "tempfile", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64bb4714269afa44aef2755150a0fc19d756fb580a67db8885608cf02f47d06a" +dependencies = [ + "atoi", + "base64 0.22.1", + "bitflags 2.6.0", + "byteorder", + "bytes", + "crc", + "digest", + "dotenvy", + "either", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "generic-array", + "hex", + "hkdf", + "hmac", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "percent-encoding", + "rand", + "rsa", + "serde", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fa91a732d854c5d7726349bb4bb879bb9478993ceb764247660aee25f67c2f8" +dependencies = [ + "atoi", + "base64 0.22.1", + "bitflags 2.6.0", + "byteorder", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "hex", + "hkdf", + "hmac", + "home", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "rand", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5b2cf34a45953bfd3daaf3db0f7a7878ab9b7a6b91b422d24a7a9e4c857b680" +dependencies = [ + "atoi", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "serde_urlencoded", + "sqlx-core", + "tracing", + "url", +] + [[package]] name = "static_assertions" version = "1.1.0" @@ -4928,6 +5412,17 @@ dependencies = [ "float-cmp", ] +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + [[package]] name = "strsim" version = "0.11.1" @@ -4953,6 +5448,12 @@ dependencies = [ "syn 2.0.81", ] +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "supports-color" version = "3.0.1" @@ -5244,9 +5745,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.40.0" +version = "1.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" +checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" dependencies = [ "backtrace", "bytes", @@ -5333,6 +5834,7 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -5500,6 +6002,12 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + [[package]] name = "url" version = "2.5.2" @@ -5576,6 +6084,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version-compare" version = "0.2.0" @@ -5610,6 +6124,12 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" + [[package]] name = "wasm-bindgen" version = "0.2.95" @@ -5949,6 +6469,16 @@ dependencies = [ "web-sys", ] +[[package]] +name = "whoami" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" +dependencies = [ + "redox_syscall 0.5.7", + "wasite", +] + [[package]] name = "widestring" version = "1.1.0" @@ -6618,6 +7148,12 @@ dependencies = [ "syn 2.0.81", ] +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + [[package]] name = "zune-inflate" version = "0.2.54" diff --git a/Cargo.toml b/Cargo.toml index bbd806d..e04efce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,3 +20,6 @@ iced_video_player = { git = "https://github.com/jackpot51/iced_video_player", br strum = "0.26.3" strum_macros = "0.26.4" ron = "0.8.1" +sqlx = { version = "0.8.2", features = ["sqlite"] } +dirs = "5.0.1" +tokio = "1.41.1" diff --git a/flake.nix b/flake.nix index 3fcf513..972c45b 100644 --- a/flake.nix +++ b/flake.nix @@ -64,6 +64,8 @@ # yt-dlp just + sqlx-cli + cargo-watch ]; in rec { diff --git a/migrations/20241112030535_initial.sql b/migrations/20241112030535_initial.sql new file mode 100644 index 0000000..23aab4c --- /dev/null +++ b/migrations/20241112030535_initial.sql @@ -0,0 +1,43 @@ +-- Add migration script here +CREATE TABLE IF NOT EXISTS 'songs' ( +'id' INTEGER NOT NULL, +'title' TEXT NOT NULL, +'lyrics' TEXT, +'author' TEXT, +'ccli' TEXT, +'audio' TEXT, +'vorder' TEXT, +'background' TEXT, +'backgroundType' TEXT, +horizontalTextAlignment TEXT, +verticalTextAlignment TEXT, +font TEXT, +fontSize INTEGER, +PRIMARY KEY(id) +); + +CREATE TABLE IF NOT EXISTS 'videos' ( +'id' INTEGER NOT NULL, +'title' TEXT NOT NULL, +'filePath' TEXT NOT NULL, +startTime REAL, +endTime REAL, +loop BOOLEAN NOT NULL DEFAULT 0, +PRIMARY KEY(id) +); + +CREATE TABLE IF NOT EXISTS 'images' ( +'id' INTEGER NOT NULL, +'title' TEXT NOT NULL, +'filePath' TEXT NOT NULL, +PRIMARY KEY(id) +); + +CREATE TABLE IF NOT EXISTS 'presentations' ( +'id' INTEGER NOT NULL, +'title' TEXT NOT NULL, +'filePath' TEXT NOT NULL, +pageCount INTEGER DEFAULT 1, +html BOOLEAN NOT NULL DEFAULT 0, +PRIMARY KEY(id) +); diff --git a/migrations/20241112120121_alter_columns.sql b/migrations/20241112120121_alter_columns.sql new file mode 100644 index 0000000..0c33087 --- /dev/null +++ b/migrations/20241112120121_alter_columns.sql @@ -0,0 +1,33 @@ +-- Add migration script here +ALTER TABLE images +RENAME COLUMN filePath TO file_path; + +ALTER TABLE videos +RENAME COLUMN filePath TO file_path; + +ALTER TABLE videos +RENAME COLUMN startTime TO start_time; + +ALTER TABLE videos +RENAME COLUMN endTime TO end_time; + +ALTER TABLE presentations +RENAME COLUMN filePath TO file_path; + +ALTER TABLE presentations +RENAME COLUMN pageCount TO pageCount; + +ALTER TABLE songs +RENAME COLUMN fontSize TO font_size; + +ALTER TABLE songs +RENAME COLUMN vorder TO verse_order; + +ALTER TABLE songs +RENAME COLUMN horizontalTextAlignment TO horizontal_text_alignment; + +ALTER TABLE songs +RENAME COLUMN verticalTextAlignment TO vertical_text_alignment; + +ALTER TABLE songs +RENAME COLUMN backgroundType TO background_type; diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..91b451d --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,3 @@ +max_width = 70 +style_edition = "2024" +# version = "Two" \ No newline at end of file diff --git a/src/core/images.rs b/src/core/images.rs index 96a74a0..254b61f 100644 --- a/src/core/images.rs +++ b/src/core/images.rs @@ -1,5 +1,5 @@ -use crate::model::Model; -use color_eyre::eyre::Result; +use super::model::Model; +use miette::{Result, miette, IntoDiagnostic}; use serde::{Deserialize, Serialize}; use sqlx::{query_as, SqliteConnection}; use std::path::PathBuf; @@ -13,25 +13,26 @@ pub struct Image { } impl Model { - pub fn load_from_db(&mut self) { - let rt = tokio::runtime::Runtime::new().unwrap(); - rt.block_on(async { - let result = query_as!(Image, r#"SELECT title as "title!", filePath as "path!", id as "id: i32" from images"#).fetch_all(&mut self.db).await; - match result { - Ok(v) => { - for image in v.into_iter() { - let _ = self.add_item(image); - } + pub async fn load_from_db(&mut self) { + let result = query_as!( + Image, + r#"SELECT title as "title!", file_path as "path!", id as "id: i32" from images"# + ) + .fetch_all(&mut self.db) + .await; + match result { + Ok(v) => { + for image in v.into_iter() { + let _ = self.add_item(image); } - Err(e) => error!("There was an error in converting images: {e}"), } - }); + Err(e) => error!("There was an error in converting images: {e}"), + }; } } - pub async fn get_image_from_db(database_id: i32, db: &mut SqliteConnection) -> Result { - Ok(query_as!(Image, r#"SELECT title as "title!", filePath as "path!", id as "id: i32" from images where id = ?"#, database_id).fetch_one(db).await?) + Ok(query_as!(Image, r#"SELECT title as "title!", file_path as "path!", id as "id: i32" from images where id = ?"#, database_id).fetch_one(db).await.into_diagnostic()?) } #[cfg(test)] @@ -47,37 +48,38 @@ mod test { } } - #[test] - pub fn test_db_and_model() { - let mut image_model: Model = Model::default(); - image_model.load_from_db(); + #[tokio::test] + pub async fn test_db_and_model() { + let mut image_model: Model = Model { + items: vec![], + db: crate::core::model::get_db().await + }; + image_model.load_from_db().await; + dbg!(&image_model.items); if let Some(image) = image_model.find(|i| i.id == 3) { let test_image = test_image("nccq5".into()); + dbg!(&test_image); assert_eq!(test_image.title, image.title); } else { assert!(false); } } - #[test] - pub fn test_add_image() { + #[tokio::test] + pub async fn test_add_image() { let image = test_image("A new image".into()); - let mut image_model: Model = Model::default(); + let mut image_model: Model = Model { + items: vec![], + db: crate::core::model::get_db().await + }; let result = image_model.add_item(image.clone()); let new_image = test_image("A newer image".into()); match result { Ok(_) => { assert_eq!(&image, image_model.find(|i| i.id == 0).unwrap()); - assert_ne!( - &new_image, - image_model.find(|i| i.id == 0).unwrap() - ); + assert_ne!(&new_image, image_model.find(|i| i.id == 0).unwrap()); } - Err(e) => assert!( - false, - "There was an error adding the image: {:?}", - e - ), + Err(e) => assert!(false, "There was an error adding the image: {:?}", e), } } } diff --git a/src/core/kinds.rs b/src/core/kinds.rs index 3660b78..e3330fe 100644 --- a/src/core/kinds.rs +++ b/src/core/kinds.rs @@ -2,7 +2,7 @@ use std::{error::Error, fmt::Display}; use serde::{Deserialize, Serialize}; -use crate::presentations::PresKind; +use super::presentations::PresKind; #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] pub enum ServiceItemKind { @@ -22,9 +22,7 @@ impl std::fmt::Display for ServiceItemKind { Self::Video => "video".to_owned(), Self::Presentation(PresKind::Html) => "html".to_owned(), Self::Presentation(PresKind::Pdf) => "pdf".to_owned(), - Self::Presentation(PresKind::Generic) => { - "presentation".to_owned() - } + Self::Presentation(PresKind::Generic) => "presentation".to_owned(), Self::Content => "content".to_owned(), }; write!(f, "{s}") @@ -38,9 +36,7 @@ impl TryFrom for ServiceItemKind { "song" => Ok(Self::Song), "image" => Ok(Self::Image), "video" => Ok(Self::Video), - "presentation" => { - Ok(Self::Presentation(PresKind::Generic)) - } + "presentation" => Ok(Self::Presentation(PresKind::Generic)), "html" => Ok(Self::Presentation(PresKind::Html)), "pdf" => Ok(Self::Presentation(PresKind::Pdf)), "content" => Ok(Self::Content), @@ -55,9 +51,7 @@ impl From for String { ServiceItemKind::Song => "song".to_owned(), ServiceItemKind::Video => "video".to_owned(), ServiceItemKind::Image => "image".to_owned(), - ServiceItemKind::Presentation(_) => { - "presentation".to_owned() - } + ServiceItemKind::Presentation(_) => "presentation".to_owned(), ServiceItemKind::Content => "content".to_owned(), } } @@ -71,10 +65,7 @@ pub enum ParseError { impl Error for ParseError {} impl Display for ParseError { - fn fmt( - &self, - f: &mut std::fmt::Formatter<'_>, - ) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let message = match self { Self::UnknownType => "The type does not exist. It needs to be one of 'song', 'video', 'image', 'presentation', or 'content'", }; diff --git a/src/core/mod.rs b/src/core/mod.rs index 3ccc703..6501999 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -1,2 +1,9 @@ +pub mod images; +pub mod kinds; pub mod lisp; +pub mod presentations; +pub mod service_items; pub mod slide; +pub mod songs; +pub mod videos; +pub mod model; diff --git a/src/core/model.rs b/src/core/model.rs index bb94d12..482deec 100644 --- a/src/core/model.rs +++ b/src/core/model.rs @@ -1,6 +1,7 @@ use std::mem::replace; -use color_eyre::eyre::{eyre, Result}; +use cosmic::{executor, iced::Executor, Task}; +use miette::{miette, IntoDiagnostic, Result}; use sqlx::{Connection, SqliteConnection}; #[derive(Debug)] @@ -24,7 +25,7 @@ impl Model { let _old_item = replace(current_item, item); Ok(()) } else { - Err(eyre!( + Err(miette!( "Item doesn't exist in model. Id was {}", index )) @@ -36,8 +37,7 @@ impl Model { Ok(()) } - pub fn get_item(&self, index: i32) -> Option<&T> - { + pub fn get_item(&self, index: i32) -> Option<&T> { self.items.get(index as usize) } @@ -54,19 +54,16 @@ impl Model { } } -impl Default for Model { - fn default() -> Self { - Self { - items: vec![], - db: { - let rt = tokio::runtime::Runtime::new().unwrap(); - rt.block_on(async { - get_db().await - }) - } - } - } -} +// impl Default for Model { +// fn default() -> Self { +// Self { +// items: vec![], +// db: { +// get_db().await +// } +// } +// } +// } pub async fn get_db() -> SqliteConnection { let mut data = dirs::data_local_dir().unwrap(); @@ -82,19 +79,25 @@ pub async fn get_db() -> SqliteConnection { pub trait Modeling { type Item; - fn setup_db() -> SqliteConnection { - let rt = tokio::runtime::Runtime::new().unwrap(); - let mut data = dirs::data_local_dir().unwrap(); - data.push("lumina"); - data.push("library-db.sqlite3"); - let mut db_url = String::from("sqlite://"); - db_url.push_str(data.to_str().unwrap()); - rt.block_on(async { - SqliteConnection::connect(&db_url) - .await - .expect("problems") - }) - } + // fn setup_db() -> SqliteConnection { + // let rt = executor::Default::new().unwrap(); + // let rt = executor::multi::Executor::new().unwrap(); + // let mut data = dirs::data_local_dir().unwrap(); + // data.push("lumina"); + // data.push("library-db.sqlite3"); + // let mut db_url = String::from("sqlite://"); + // db_url.push_str(data.to_str().unwrap()); + // rt.spawn(async { + // SqliteConnection::connect(&db_url) + // .await + // .expect("problems") + // }); + // rt.enter(async { + // SqliteConnection::connect(&db_url) + // .await + // .expect("problems") + // }); + // } } #[cfg(test)] diff --git a/src/core/presentations.rs b/src/core/presentations.rs index 8f9b33b..04022a4 100644 --- a/src/core/presentations.rs +++ b/src/core/presentations.rs @@ -1,10 +1,10 @@ -use std::path::PathBuf; -use color_eyre::eyre::Result; +use miette::{miette, Result, IntoDiagnostic}; use serde::{Deserialize, Serialize}; use sqlx::{prelude::FromRow, query, sqlite::SqliteRow, Row, SqliteConnection}; +use std::path::PathBuf; use tracing::error; -use crate::model::Model; +use super::model::Model; #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] pub enum PresKind { @@ -54,34 +54,38 @@ impl FromRow<'_, SqliteRow> for Presentation { } impl Model { - pub fn load_from_db(&mut self) { - let rt = tokio::runtime::Runtime::new().unwrap(); - rt.block_on(async { - let result = query!(r#"SELECT id as "id: i32", title, filePath as "path", html from presentations"#).fetch_all(&mut self.db).await; - match result { - Ok(v) => { - for presentation in v.into_iter() { - let _ = self.add_item(Presentation { - id: presentation.id, - title: presentation.title, - path: presentation.path.into(), - kind: if presentation.html { - PresKind::Html - } else { - PresKind::Pdf - } - }); - } + pub async fn load_from_db(&mut self) { + let result = query!( + r#"SELECT id as "id: i32", title, file_path as "path", html from presentations"# + ) + .fetch_all(&mut self.db) + .await; + match result { + Ok(v) => { + for presentation in v.into_iter() { + let _ = self.add_item(Presentation { + id: presentation.id, + title: presentation.title, + path: presentation.path.into(), + kind: if presentation.html { + PresKind::Html + } else { + PresKind::Pdf + }, + }); } - Err(e) => error!("There was an error in converting presentations: {e}"), } - }); + Err(e) => error!("There was an error in converting presentations: {e}"), + } } } -pub async fn get_presentation_from_db(database_id: i32, db: &mut SqliteConnection) -> Result { - let row = query(r#"SELECT id as "id: i32", title, filePath as "path", html from presentations where id = $1"#).bind(database_id).fetch_one(db).await?; - Ok(Presentation::from_row(&row)?) +pub async fn get_presentation_from_db( + database_id: i32, + db: &mut SqliteConnection, +) -> Result { + let row = query(r#"SELECT id as "id: i32", title, file_path as "path", html from presentations where id = $1"#).bind(database_id).fetch_one(db).await.into_diagnostic()?; + Ok(Presentation::from_row(&row).into_diagnostic()?) } #[cfg(test)] @@ -106,11 +110,13 @@ mod test { assert_eq!(pres.get_kind(), &PresKind::Pdf) } - #[test] - pub fn test_db_and_model() { - let mut presentation_model: Model = - Model::default(); - presentation_model.load_from_db(); + #[tokio::test] + async fn test_db_and_model() { + let mut presentation_model: Model = Model { + items: vec![], + db: crate::core::model::get_db().await + }; + presentation_model.load_from_db().await; if let Some(presentation) = presentation_model.find(|p| p.id == 54) { let test_presentation = test_presentation(); assert_eq!(&test_presentation, presentation); diff --git a/src/core/service_items.rs b/src/core/service_items.rs index 222f2d6..55519a6 100644 --- a/src/core/service_items.rs +++ b/src/core/service_items.rs @@ -1,9 +1,9 @@ -use color_eyre::eyre::Result; +use miette::Result; -use crate::images::Image; -use crate::presentations::Presentation; -use crate::songs::Song; -use crate::videos::Video; +use super::images::Image; +use super::presentations::Presentation; +use super::songs::Song; +use super::videos::Video; use super::kinds::ServiceItemKind; @@ -71,7 +71,7 @@ impl ServiceItemModel { mod test { use std::path::PathBuf; - use crate::presentations::PresKind; + use crate::core::presentations::PresKind; use super::*; use pretty_assertions::{assert_eq, assert_ne}; @@ -94,7 +94,6 @@ mod test { } } - #[test] pub fn test_service_item() { let song = test_song(); @@ -105,9 +104,12 @@ mod test { match service_model.add_item(&song) { Ok(_) => { assert_eq!(ServiceItemKind::Song, service_model.items[0].kind); - assert_eq!(ServiceItemKind::Presentation(PresKind::Html), pres_item.kind); + assert_eq!( + ServiceItemKind::Presentation(PresKind::Html), + pres_item.kind + ); assert_eq!(service_item, service_model.items[0]); - }, + } Err(e) => panic!("Problem adding item: {:?}", e), } } diff --git a/src/core/songs.rs b/src/core/songs.rs index d259563..b3720d6 100644 --- a/src/core/songs.rs +++ b/src/core/songs.rs @@ -1,13 +1,14 @@ use std::{collections::HashMap, path::PathBuf}; -use color_eyre::eyre::{eyre, Context, Result}; +use cosmic::{executor, iced::Executor}; +use miette::{miette, IntoDiagnostic, Result}; use serde::{Deserialize, Serialize}; use sqlx::{query, query_as, sqlite::SqliteRow, FromRow, Row, SqliteConnection}; use tracing::{debug, error}; -use crate::{ - model::{get_db, Model}, - slides::{Background, TextAlignment}, +use super::{ + model::{Model}, + slide::{Background, TextAlignment}, }; #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] @@ -26,11 +27,9 @@ pub struct Song { } const VERSE_KEYWORDS: [&str; 24] = [ - "Verse 1", "Verse 2", "Verse 3", "Verse 4", "Verse 5", "Verse 6", - "Verse 7", "Verse 8", "Chorus 1", "Chorus 2", "Chorus 3", - "Chorus 4", "Bridge 1", "Bridge 2", "Bridge 3", "Bridge 4", - "Intro 1", "Intro 2", "Ending 1", "Ending 2", "Other 1", - "Other 2", "Other 3", "Other 4", + "Verse 1", "Verse 2", "Verse 3", "Verse 4", "Verse 5", "Verse 6", "Verse 7", "Verse 8", + "Chorus 1", "Chorus 2", "Chorus 3", "Chorus 4", "Bridge 1", "Bridge 2", "Bridge 3", "Bridge 4", + "Intro 1", "Intro 2", "Ending 1", "Ending 2", "Other 1", "Other 2", "Other 3", "Other 4", ]; impl FromRow<'_, SqliteRow> for Song { @@ -49,14 +48,21 @@ impl FromRow<'_, SqliteRow> for Song { let str: &str = row.try_get(0)?; str.split(' ').map(|s| s.to_string()).collect() }), - background: Some({ + background: { let string: String = row.try_get(7)?; - Background::try_from(string)? - }), + match Background::try_from(string) { + Ok(background) => Some(background), + Err(_) => None, + } + + }, text_alignment: Some({ let horizontal_alignment: String = row.try_get(3)?; let vertical_alignment: String = row.try_get(4)?; - match (horizontal_alignment.to_lowercase().as_str(), vertical_alignment.to_lowercase().as_str()) { + match ( + horizontal_alignment.to_lowercase().as_str(), + vertical_alignment.to_lowercase().as_str(), + ) { ("left", "top") => TextAlignment::TopLeft, ("left", "center") => TextAlignment::MiddleLeft, ("left", "bottom") => TextAlignment::BottomLeft, @@ -66,7 +72,7 @@ impl FromRow<'_, SqliteRow> for Song { ("right", "top") => TextAlignment::TopRight, ("right", "center") => TextAlignment::MiddleRight, ("right", "bottom") => TextAlignment::BottomRight, - _ => TextAlignment::MiddleCenter + _ => TextAlignment::MiddleCenter, } }), font: row.try_get(6)?, @@ -75,35 +81,30 @@ impl FromRow<'_, SqliteRow> for Song { } } - -pub async fn get_song_from_db(index: i32, db: &mut SqliteConnection) -> Result { - let row = query(r#"SELECT vorder as "verse_order!", fontSize as "font_size!: i32", backgroundType as "background_type!", horizontalTextAlignment as "horizontal_text_alignment!", verticalTextAlignment as "vertical_text_alignment!", title as "title!", font as "font!", background as "background!", lyrics as "lyrics!", ccli as "ccli!", author as "author!", audio as "audio!", id as "id: i32" from songs where id = $1"#).bind(index).fetch_one(db).await?; - Ok(Song::from_row(&row)?) +pub async fn get_song_from_db(index: i32, db: &mut SqliteConnection) -> Result { + let row = query(r#"SELECT verse_order as "verse_order!", font_size as "font_size!: i32", background_type as "background_type!", horizontal_text_alignment as "horizontal_text_alignment!", vertical_text_alignment as "vertical_text_alignment!", title as "title!", font as "font!", background as "background!", lyrics as "lyrics!", ccli as "ccli!", author as "author!", audio as "audio!", id as "id: i32" from songs where id = $1"#).bind(index).fetch_one(db).await.into_diagnostic()?; + Ok(Song::from_row(&row).into_diagnostic()?) } - impl Model { - pub fn load_from_db(&mut self) { + pub async fn load_from_db(&mut self) { // static DATABASE_URL: &str = "sqlite:///home/chris/.local/share/lumina/library-db.sqlite3"; - let rt = tokio::runtime::Runtime::new().unwrap(); - rt.block_on(async { - let result = query(r#"SELECT vorder as "verse_order!", fontSize as "font_size!: i32", backgroundType as "background_type!", horizontalTextAlignment as "horizontal_text_alignment!", verticalTextAlignment as "vertical_text_alignment!", title as "title!", font as "font!", background as "background!", lyrics as "lyrics!", ccli as "ccli!", author as "author!", audio as "audio!", id as "id: i32" from songs"#).fetch_all(&mut self.db).await; - match result { - Ok(s) => { - for song in s.into_iter() { - match Song::from_row(&song) { - Ok(song) => { - let _ = self.add_item(song); - }, - Err(e) => error!("Could not convert song: {e}"), - }; + let result = query(r#"SELECT verse_order as "verse_order!", font_size as "font_size!: i32", background_type as "background_type!", horizontal_text_alignment as "horizontal_text_alignment!", vertical_text_alignment as "vertical_text_alignment!", title as "title!", font as "font!", background as "background!", lyrics as "lyrics!", ccli as "ccli!", author as "author!", audio as "audio!", id as "id: i32" from songs"#).fetch_all(&mut self.db).await; + match result { + Ok(s) => { + for song in s.into_iter() { + match Song::from_row(&song) { + Ok(song) => { + let _ = self.add_item(song); + }, + Err(e) => error!("Could not convert song: {e}"), }; - }, - Err(e) => { - error!("There was an error in converting songs: {e}"); - }, - } - }) + }; + }, + Err(e) => { + error!("There was an error in converting songs: {e}"); + }, + } } } @@ -111,15 +112,11 @@ impl Song { pub fn get_lyrics(&self) -> Result> { let mut lyric_list = Vec::new(); if self.lyrics.is_none() { - return Err(eyre!("There is no lyrics here")); + return Err(miette!("There is no lyrics here")); } else if self.verse_order.is_none() { - return Err(eyre!("There is no verse_order here")); - } else if self - .verse_order - .clone() - .is_some_and(|v| v.is_empty()) - { - return Err(eyre!("There is no verse_order here")); + return Err(miette!("There is no verse_order here")); + } else if self.verse_order.clone().is_some_and(|v| v.is_empty()) { + return Err(miette!("There is no verse_order here")); } if let Some(raw_lyrics) = self.lyrics.clone() { let raw_lyrics = raw_lyrics.as_str(); @@ -148,21 +145,16 @@ impl Song { let mut verse_name = ""; debug!(verse = verse); for word in VERSE_KEYWORDS { - let end_verse = - verse.get(1..2).unwrap_or_default(); - let beg_verse = - verse.get(0..1).unwrap_or_default(); - if word.starts_with(beg_verse) - && word.ends_with(end_verse) - { + let end_verse = verse.get(1..2).unwrap_or_default(); + let beg_verse = verse.get(0..1).unwrap_or_default(); + if word.starts_with(beg_verse) && word.ends_with(end_verse) { verse_name = word; continue; } } if let Some(lyric) = lyric_map.get(verse_name) { if lyric.contains("\n\n") { - let split_lyrics: Vec<&str> = - lyric.split("\n\n").collect(); + let split_lyrics: Vec<&str> = lyric.split("\n\n").collect(); for lyric in split_lyrics { if lyric.is_empty() { continue; @@ -181,7 +173,7 @@ impl Song { } Ok(lyric_list) } else { - Err(eyre!("There are no lyrics")) + Err(miette!("There are no lyrics")) } } } @@ -254,12 +246,11 @@ From the day You saved my soul" .to_string(), ); - song.verse_order = - "O1 V1 C1 C2 O2 V2 C3 C2 O2 B1 C2 C2 E1 O2" - .to_string() - .split(' ') - .map(|s| Some(s.to_string())) - .collect(); + song.verse_order = "O1 V1 C1 C2 O2 V2 C3 C2 O2 B1 C2 C2 E1 O2" + .to_string() + .split(' ') + .map(|s| Some(s.to_string())) + .collect(); let lyrics = song.get_lyrics(); match lyrics { Ok(lyrics) => { @@ -271,40 +262,47 @@ You saved my soul" } } - #[test] - pub fn test_db_and_model() { - let mut song_model: Model = Model::default(); - song_model.load_from_db(); + async fn model() -> Model { + let song_model: Model = Model { + items: vec![], + db: crate::core::model::get_db().await + }; + song_model + } + + #[tokio::test] + async fn test_db_and_model() { + let mut song_model = model().await; + song_model.load_from_db().await; if let Some(song) = song_model.find(|s| s.id == 7) { let test_song = test_song(); assert_eq!(&test_song, song); } else { + dbg!(song_model); assert!(false); } } #[tokio::test] - pub async fn test_song_from_db() { + async fn test_song_from_db() { let song = test_song(); - let result = get_song_from_db(7, &mut get_db().await).await; + let mut db = model().await.db; + let result = get_song_from_db(7, &mut db).await; match result { Ok(db_song) => assert_eq!(song, db_song), Err(e) => assert!(false, "{e}"), } } - #[test] - pub fn test_update() { + #[tokio::test] + async fn test_update() { let song = test_song(); let cloned_song = song.clone(); - let mut song_model: Model = Model::default(); - song_model.load_from_db(); + let mut song_model: Model = model().await; + song_model.load_from_db().await; match song_model.update_item(song, 2) { - Ok(()) => assert_eq!( - &cloned_song, - song_model.find(|s| s.id == 7).unwrap() - ), + Ok(()) => assert_eq!(&cloned_song, song_model.find(|s| s.id == 7).unwrap()), Err(e) => assert!(false, "{e}"), } } diff --git a/src/core/videos.rs b/src/core/videos.rs index c7cdb3d..991d414 100644 --- a/src/core/videos.rs +++ b/src/core/videos.rs @@ -1,5 +1,6 @@ -use crate::model::Model; -use color_eyre::eyre::Result; +use super::model::Model; +use cosmic::{executor, iced::Executor}; +use miette::{Result, miette, IntoDiagnostic}; use serde::{Deserialize, Serialize}; use sqlx::{query_as, SqliteConnection}; use std::path::PathBuf; @@ -16,28 +17,23 @@ pub struct Video { } impl Model