adding all of our core sql systems

This commit is contained in:
Chris Cochrun 2024-11-12 06:29:24 -06:00
parent 2408404ff4
commit c9225680c3
20 changed files with 1055 additions and 227 deletions

1
.envrc
View file

@ -1,4 +1,3 @@
export DATABASE_URL=sqlite://~/.local/share/lumina/library-db.sqlite3
use flake . --impure use flake . --impure
# eval $(guix shell -D --search-paths) # eval $(guix shell -D --search-paths)

View file

@ -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"
}

View file

@ -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"
}

View file

@ -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"
}

View file

@ -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"
}

View file

@ -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"
}

540
Cargo.lock generated
View file

@ -541,6 +541,15 @@ dependencies = [
"syn 2.0.81", "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]] [[package]]
name = "atomic-waker" name = "atomic-waker"
version = "1.1.2" version = "1.1.2"
@ -653,6 +662,12 @@ version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "base64ct"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]] [[package]]
name = "bit-set" name = "bit-set"
version = "0.6.0" version = "0.6.0"
@ -1036,6 +1051,12 @@ dependencies = [
"crossbeam-utils", "crossbeam-utils",
] ]
[[package]]
name = "const-oid"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
[[package]] [[package]]
name = "const-random" name = "const-random"
version = "0.1.18" version = "0.1.18"
@ -1209,6 +1230,21 @@ dependencies = [
"libc", "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]] [[package]]
name = "crc32fast" name = "crc32fast"
version = "1.4.2" version = "1.4.2"
@ -1246,6 +1282,15 @@ dependencies = [
"crossbeam-utils", "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]] [[package]]
name = "crossbeam-utils" name = "crossbeam-utils"
version = "0.8.20" version = "0.8.20"
@ -1348,6 +1393,17 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" 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]] [[package]]
name = "deranged" name = "deranged"
version = "0.3.11" version = "0.3.11"
@ -1393,7 +1449,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [ dependencies = [
"block-buffer", "block-buffer",
"const-oid",
"crypto-common", "crypto-common",
"subtle",
] ]
[[package]] [[package]]
@ -1462,6 +1520,12 @@ dependencies = [
"litrs", "litrs",
] ]
[[package]]
name = "dotenvy"
version = "0.15.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
[[package]] [[package]]
name = "downcast-rs" name = "downcast-rs"
version = "1.2.1" version = "1.2.1"
@ -1517,6 +1581,9 @@ name = "either"
version = "1.13.0" version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "endi" name = "endi"
@ -1577,6 +1644,17 @@ dependencies = [
"svg_fmt", "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]] [[package]]
name = "euclid" name = "euclid"
version = "0.22.11" version = "0.22.11"
@ -1710,6 +1788,8 @@ version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095"
dependencies = [ dependencies = [
"futures-core",
"futures-sink",
"spin", "spin",
] ]
@ -1876,6 +1956,17 @@ dependencies = [
"num_cpus", "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]] [[package]]
name = "futures-io" name = "futures-io"
version = "0.3.31" version = "0.3.31"
@ -2381,6 +2472,15 @@ version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" 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]] [[package]]
name = "hassle-rs" name = "hassle-rs"
version = "0.11.0" version = "0.11.0"
@ -2432,6 +2532,33 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" 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]] [[package]]
name = "html-escape" name = "html-escape"
version = "0.2.13" version = "0.2.13"
@ -2973,6 +3100,9 @@ name = "lazy_static"
version = "1.5.0" version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
dependencies = [
"spin",
]
[[package]] [[package]]
name = "lebe" name = "lebe"
@ -3076,6 +3206,17 @@ dependencies = [
"redox_syscall 0.5.7", "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]] [[package]]
name = "linux-raw-sys" name = "linux-raw-sys"
version = "0.3.8" version = "0.3.8"
@ -3127,6 +3268,7 @@ name = "lumina"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"clap", "clap",
"dirs",
"iced_video_player", "iced_video_player",
"lexpr", "lexpr",
"libcosmic", "libcosmic",
@ -3135,8 +3277,10 @@ dependencies = [
"ron", "ron",
"serde", "serde",
"serde-lexpr", "serde-lexpr",
"sqlx",
"strum", "strum",
"strum_macros", "strum_macros",
"tokio",
"tracing", "tracing",
"tracing-subscriber", "tracing-subscriber",
] ]
@ -3211,6 +3355,16 @@ dependencies = [
"regex-automata 0.1.10", "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]] [[package]]
name = "memchr" name = "memchr"
version = "2.7.4" version = "2.7.4"
@ -3307,6 +3461,12 @@ dependencies = [
"smithay-clipboard", "smithay-clipboard",
] ]
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.7.4" version = "0.7.4"
@ -3447,6 +3607,16 @@ dependencies = [
"memoffset 0.9.1", "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]] [[package]]
name = "notify" name = "notify"
version = "6.1.1" version = "6.1.1"
@ -3500,6 +3670,23 @@ dependencies = [
"num-traits", "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]] [[package]]
name = "num-complex" name = "num-complex"
version = "0.4.6" version = "0.4.6"
@ -4018,6 +4205,15 @@ version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" 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]] [[package]]
name = "percent-encoding" name = "percent-encoding"
version = "2.3.1" version = "2.3.1"
@ -4115,6 +4311,27 @@ dependencies = [
"futures-io", "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]] [[package]]
name = "pkg-config" name = "pkg-config"
version = "0.3.31" version = "0.3.31"
@ -4508,6 +4725,26 @@ version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" 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]] [[package]]
name = "rust-ini" name = "rust-ini"
version = "0.20.0" version = "0.20.0"
@ -4695,6 +4932,18 @@ dependencies = [
"serde", "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]] [[package]]
name = "sha1" name = "sha1"
version = "0.10.6" version = "0.10.6"
@ -4706,6 +4955,17 @@ dependencies = [
"digest", "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]] [[package]]
name = "sharded-slab" name = "sharded-slab"
version = "0.1.7" version = "0.1.7"
@ -4730,6 +4990,16 @@ dependencies = [
"libc", "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]] [[package]]
name = "simd-adler32" name = "simd-adler32"
version = "0.3.7" version = "0.3.7"
@ -4790,6 +5060,9 @@ name = "smallvec"
version = "1.13.2" version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "smawk" name = "smawk"
@ -4913,6 +5186,217 @@ dependencies = [
"bitflags 2.6.0", "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]] [[package]]
name = "static_assertions" name = "static_assertions"
version = "1.1.0" version = "1.1.0"
@ -4928,6 +5412,17 @@ dependencies = [
"float-cmp", "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]] [[package]]
name = "strsim" name = "strsim"
version = "0.11.1" version = "0.11.1"
@ -4953,6 +5448,12 @@ dependencies = [
"syn 2.0.81", "syn 2.0.81",
] ]
[[package]]
name = "subtle"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]] [[package]]
name = "supports-color" name = "supports-color"
version = "3.0.1" version = "3.0.1"
@ -5244,9 +5745,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.40.0" version = "1.41.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"bytes", "bytes",
@ -5333,6 +5834,7 @@ version = "0.1.40"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
dependencies = [ dependencies = [
"log",
"pin-project-lite", "pin-project-lite",
"tracing-attributes", "tracing-attributes",
"tracing-core", "tracing-core",
@ -5500,6 +6002,12 @@ version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
[[package]]
name = "unicode_categories"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
[[package]] [[package]]
name = "url" name = "url"
version = "2.5.2" version = "2.5.2"
@ -5576,6 +6084,12 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]] [[package]]
name = "version-compare" name = "version-compare"
version = "0.2.0" 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" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasite"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b"
[[package]] [[package]]
name = "wasm-bindgen" name = "wasm-bindgen"
version = "0.2.95" version = "0.2.95"
@ -5949,6 +6469,16 @@ dependencies = [
"web-sys", "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]] [[package]]
name = "widestring" name = "widestring"
version = "1.1.0" version = "1.1.0"
@ -6618,6 +7148,12 @@ dependencies = [
"syn 2.0.81", "syn 2.0.81",
] ]
[[package]]
name = "zeroize"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
[[package]] [[package]]
name = "zune-inflate" name = "zune-inflate"
version = "0.2.54" version = "0.2.54"

View file

@ -20,3 +20,6 @@ iced_video_player = { git = "https://github.com/jackpot51/iced_video_player", br
strum = "0.26.3" strum = "0.26.3"
strum_macros = "0.26.4" strum_macros = "0.26.4"
ron = "0.8.1" ron = "0.8.1"
sqlx = { version = "0.8.2", features = ["sqlite"] }
dirs = "5.0.1"
tokio = "1.41.1"

View file

@ -64,6 +64,8 @@
# yt-dlp # yt-dlp
just just
sqlx-cli
cargo-watch
]; ];
in rec in rec
{ {

View file

@ -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)
);

View file

@ -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;

3
rustfmt.toml Normal file
View file

@ -0,0 +1,3 @@
max_width = 70
style_edition = "2024"
# version = "Two"

View file

@ -1,5 +1,5 @@
use crate::model::Model; use super::model::Model;
use color_eyre::eyre::Result; use miette::{Result, miette, IntoDiagnostic};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sqlx::{query_as, SqliteConnection}; use sqlx::{query_as, SqliteConnection};
use std::path::PathBuf; use std::path::PathBuf;
@ -13,25 +13,26 @@ pub struct Image {
} }
impl Model<Image> { impl Model<Image> {
pub fn load_from_db(&mut self) { pub async fn load_from_db(&mut self) {
let rt = tokio::runtime::Runtime::new().unwrap(); let result = query_as!(
rt.block_on(async { Image,
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; r#"SELECT title as "title!", file_path as "path!", id as "id: i32" from images"#
match result { )
Ok(v) => { .fetch_all(&mut self.db)
for image in v.into_iter() { .await;
let _ = self.add_item(image); 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<Image> { pub async fn get_image_from_db(database_id: i32, db: &mut SqliteConnection) -> Result<Image> {
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)] #[cfg(test)]
@ -47,37 +48,38 @@ mod test {
} }
} }
#[test] #[tokio::test]
pub fn test_db_and_model() { pub async fn test_db_and_model() {
let mut image_model: Model<Image> = Model::default(); let mut image_model: Model<Image> = Model {
image_model.load_from_db(); 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) { if let Some(image) = image_model.find(|i| i.id == 3) {
let test_image = test_image("nccq5".into()); let test_image = test_image("nccq5".into());
dbg!(&test_image);
assert_eq!(test_image.title, image.title); assert_eq!(test_image.title, image.title);
} else { } else {
assert!(false); assert!(false);
} }
} }
#[test] #[tokio::test]
pub fn test_add_image() { pub async fn test_add_image() {
let image = test_image("A new image".into()); let image = test_image("A new image".into());
let mut image_model: Model<Image> = Model::default(); let mut image_model: Model<Image> = Model {
items: vec![],
db: crate::core::model::get_db().await
};
let result = image_model.add_item(image.clone()); let result = image_model.add_item(image.clone());
let new_image = test_image("A newer image".into()); let new_image = test_image("A newer image".into());
match result { match result {
Ok(_) => { Ok(_) => {
assert_eq!(&image, image_model.find(|i| i.id == 0).unwrap()); assert_eq!(&image, image_model.find(|i| i.id == 0).unwrap());
assert_ne!( assert_ne!(&new_image, image_model.find(|i| i.id == 0).unwrap());
&new_image,
image_model.find(|i| i.id == 0).unwrap()
);
} }
Err(e) => assert!( Err(e) => assert!(false, "There was an error adding the image: {:?}", e),
false,
"There was an error adding the image: {:?}",
e
),
} }
} }
} }

View file

@ -2,7 +2,7 @@ use std::{error::Error, fmt::Display};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::presentations::PresKind; use super::presentations::PresKind;
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub enum ServiceItemKind { pub enum ServiceItemKind {
@ -22,9 +22,7 @@ impl std::fmt::Display for ServiceItemKind {
Self::Video => "video".to_owned(), Self::Video => "video".to_owned(),
Self::Presentation(PresKind::Html) => "html".to_owned(), Self::Presentation(PresKind::Html) => "html".to_owned(),
Self::Presentation(PresKind::Pdf) => "pdf".to_owned(), Self::Presentation(PresKind::Pdf) => "pdf".to_owned(),
Self::Presentation(PresKind::Generic) => { Self::Presentation(PresKind::Generic) => "presentation".to_owned(),
"presentation".to_owned()
}
Self::Content => "content".to_owned(), Self::Content => "content".to_owned(),
}; };
write!(f, "{s}") write!(f, "{s}")
@ -38,9 +36,7 @@ impl TryFrom<String> for ServiceItemKind {
"song" => Ok(Self::Song), "song" => Ok(Self::Song),
"image" => Ok(Self::Image), "image" => Ok(Self::Image),
"video" => Ok(Self::Video), "video" => Ok(Self::Video),
"presentation" => { "presentation" => Ok(Self::Presentation(PresKind::Generic)),
Ok(Self::Presentation(PresKind::Generic))
}
"html" => Ok(Self::Presentation(PresKind::Html)), "html" => Ok(Self::Presentation(PresKind::Html)),
"pdf" => Ok(Self::Presentation(PresKind::Pdf)), "pdf" => Ok(Self::Presentation(PresKind::Pdf)),
"content" => Ok(Self::Content), "content" => Ok(Self::Content),
@ -55,9 +51,7 @@ impl From<ServiceItemKind> for String {
ServiceItemKind::Song => "song".to_owned(), ServiceItemKind::Song => "song".to_owned(),
ServiceItemKind::Video => "video".to_owned(), ServiceItemKind::Video => "video".to_owned(),
ServiceItemKind::Image => "image".to_owned(), ServiceItemKind::Image => "image".to_owned(),
ServiceItemKind::Presentation(_) => { ServiceItemKind::Presentation(_) => "presentation".to_owned(),
"presentation".to_owned()
}
ServiceItemKind::Content => "content".to_owned(), ServiceItemKind::Content => "content".to_owned(),
} }
} }
@ -71,10 +65,7 @@ pub enum ParseError {
impl Error for ParseError {} impl Error for ParseError {}
impl Display for ParseError { impl Display for ParseError {
fn fmt( fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
&self,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
let message = match self { let message = match self {
Self::UnknownType => "The type does not exist. It needs to be one of 'song', 'video', 'image', 'presentation', or 'content'", Self::UnknownType => "The type does not exist. It needs to be one of 'song', 'video', 'image', 'presentation', or 'content'",
}; };

View file

@ -1,2 +1,9 @@
pub mod images;
pub mod kinds;
pub mod lisp; pub mod lisp;
pub mod presentations;
pub mod service_items;
pub mod slide; pub mod slide;
pub mod songs;
pub mod videos;
pub mod model;

View file

@ -1,6 +1,7 @@
use std::mem::replace; 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}; use sqlx::{Connection, SqliteConnection};
#[derive(Debug)] #[derive(Debug)]
@ -24,7 +25,7 @@ impl<T> Model<T> {
let _old_item = replace(current_item, item); let _old_item = replace(current_item, item);
Ok(()) Ok(())
} else { } else {
Err(eyre!( Err(miette!(
"Item doesn't exist in model. Id was {}", "Item doesn't exist in model. Id was {}",
index index
)) ))
@ -36,8 +37,7 @@ impl<T> Model<T> {
Ok(()) 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) self.items.get(index as usize)
} }
@ -54,19 +54,16 @@ impl<T> Model<T> {
} }
} }
impl<T> Default for Model<T> { // impl<T> Default for Model<T> {
fn default() -> Self { // fn default() -> Self {
Self { // Self {
items: vec![], // items: vec![],
db: { // db: {
let rt = tokio::runtime::Runtime::new().unwrap(); // get_db().await
rt.block_on(async { // }
get_db().await // }
}) // }
} // }
}
}
}
pub async fn get_db() -> SqliteConnection { pub async fn get_db() -> SqliteConnection {
let mut data = dirs::data_local_dir().unwrap(); let mut data = dirs::data_local_dir().unwrap();
@ -82,19 +79,25 @@ pub async fn get_db() -> SqliteConnection {
pub trait Modeling { pub trait Modeling {
type Item; type Item;
fn setup_db() -> SqliteConnection { // fn setup_db() -> SqliteConnection {
let rt = tokio::runtime::Runtime::new().unwrap(); // let rt = executor::Default::new().unwrap();
let mut data = dirs::data_local_dir().unwrap(); // let rt = executor::multi::Executor::new().unwrap();
data.push("lumina"); // let mut data = dirs::data_local_dir().unwrap();
data.push("library-db.sqlite3"); // data.push("lumina");
let mut db_url = String::from("sqlite://"); // data.push("library-db.sqlite3");
db_url.push_str(data.to_str().unwrap()); // let mut db_url = String::from("sqlite://");
rt.block_on(async { // db_url.push_str(data.to_str().unwrap());
SqliteConnection::connect(&db_url) // rt.spawn(async {
.await // SqliteConnection::connect(&db_url)
.expect("problems") // .await
}) // .expect("problems")
} // });
// rt.enter(async {
// SqliteConnection::connect(&db_url)
// .await
// .expect("problems")
// });
// }
} }
#[cfg(test)] #[cfg(test)]

View file

@ -1,10 +1,10 @@
use std::path::PathBuf; use miette::{miette, Result, IntoDiagnostic};
use color_eyre::eyre::Result;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sqlx::{prelude::FromRow, query, sqlite::SqliteRow, Row, SqliteConnection}; use sqlx::{prelude::FromRow, query, sqlite::SqliteRow, Row, SqliteConnection};
use std::path::PathBuf;
use tracing::error; use tracing::error;
use crate::model::Model; use super::model::Model;
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub enum PresKind { pub enum PresKind {
@ -54,34 +54,38 @@ impl FromRow<'_, SqliteRow> for Presentation {
} }
impl Model<Presentation> { impl Model<Presentation> {
pub fn load_from_db(&mut self) { pub async fn load_from_db(&mut self) {
let rt = tokio::runtime::Runtime::new().unwrap(); let result = query!(
rt.block_on(async { r#"SELECT id as "id: i32", title, file_path as "path", html from presentations"#
let result = query!(r#"SELECT id as "id: i32", title, filePath as "path", html from presentations"#).fetch_all(&mut self.db).await; )
match result { .fetch_all(&mut self.db)
Ok(v) => { .await;
for presentation in v.into_iter() { match result {
let _ = self.add_item(Presentation { Ok(v) => {
id: presentation.id, for presentation in v.into_iter() {
title: presentation.title, let _ = self.add_item(Presentation {
path: presentation.path.into(), id: presentation.id,
kind: if presentation.html { title: presentation.title,
PresKind::Html path: presentation.path.into(),
} else { kind: if presentation.html {
PresKind::Pdf 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<Presentation> { pub async fn get_presentation_from_db(
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?; database_id: i32,
Ok(Presentation::from_row(&row)?) db: &mut SqliteConnection,
) -> Result<Presentation> {
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)] #[cfg(test)]
@ -106,11 +110,13 @@ mod test {
assert_eq!(pres.get_kind(), &PresKind::Pdf) assert_eq!(pres.get_kind(), &PresKind::Pdf)
} }
#[test] #[tokio::test]
pub fn test_db_and_model() { async fn test_db_and_model() {
let mut presentation_model: Model<Presentation> = let mut presentation_model: Model<Presentation> = Model {
Model::default(); items: vec![],
presentation_model.load_from_db(); db: crate::core::model::get_db().await
};
presentation_model.load_from_db().await;
if let Some(presentation) = presentation_model.find(|p| p.id == 54) { if let Some(presentation) = presentation_model.find(|p| p.id == 54) {
let test_presentation = test_presentation(); let test_presentation = test_presentation();
assert_eq!(&test_presentation, presentation); assert_eq!(&test_presentation, presentation);

View file

@ -1,9 +1,9 @@
use color_eyre::eyre::Result; use miette::Result;
use crate::images::Image; use super::images::Image;
use crate::presentations::Presentation; use super::presentations::Presentation;
use crate::songs::Song; use super::songs::Song;
use crate::videos::Video; use super::videos::Video;
use super::kinds::ServiceItemKind; use super::kinds::ServiceItemKind;
@ -71,7 +71,7 @@ impl ServiceItemModel {
mod test { mod test {
use std::path::PathBuf; use std::path::PathBuf;
use crate::presentations::PresKind; use crate::core::presentations::PresKind;
use super::*; use super::*;
use pretty_assertions::{assert_eq, assert_ne}; use pretty_assertions::{assert_eq, assert_ne};
@ -94,7 +94,6 @@ mod test {
} }
} }
#[test] #[test]
pub fn test_service_item() { pub fn test_service_item() {
let song = test_song(); let song = test_song();
@ -105,9 +104,12 @@ mod test {
match service_model.add_item(&song) { match service_model.add_item(&song) {
Ok(_) => { Ok(_) => {
assert_eq!(ServiceItemKind::Song, service_model.items[0].kind); 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]); assert_eq!(service_item, service_model.items[0]);
}, }
Err(e) => panic!("Problem adding item: {:?}", e), Err(e) => panic!("Problem adding item: {:?}", e),
} }
} }

View file

@ -1,13 +1,14 @@
use std::{collections::HashMap, path::PathBuf}; 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 serde::{Deserialize, Serialize};
use sqlx::{query, query_as, sqlite::SqliteRow, FromRow, Row, SqliteConnection}; use sqlx::{query, query_as, sqlite::SqliteRow, FromRow, Row, SqliteConnection};
use tracing::{debug, error}; use tracing::{debug, error};
use crate::{ use super::{
model::{get_db, Model}, model::{Model},
slides::{Background, TextAlignment}, slide::{Background, TextAlignment},
}; };
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
@ -26,11 +27,9 @@ pub struct Song {
} }
const VERSE_KEYWORDS: [&str; 24] = [ const VERSE_KEYWORDS: [&str; 24] = [
"Verse 1", "Verse 2", "Verse 3", "Verse 4", "Verse 5", "Verse 6", "Verse 1", "Verse 2", "Verse 3", "Verse 4", "Verse 5", "Verse 6", "Verse 7", "Verse 8",
"Verse 7", "Verse 8", "Chorus 1", "Chorus 2", "Chorus 3", "Chorus 1", "Chorus 2", "Chorus 3", "Chorus 4", "Bridge 1", "Bridge 2", "Bridge 3", "Bridge 4",
"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",
"Intro 1", "Intro 2", "Ending 1", "Ending 2", "Other 1",
"Other 2", "Other 3", "Other 4",
]; ];
impl FromRow<'_, SqliteRow> for Song { impl FromRow<'_, SqliteRow> for Song {
@ -49,14 +48,21 @@ impl FromRow<'_, SqliteRow> for Song {
let str: &str = row.try_get(0)?; let str: &str = row.try_get(0)?;
str.split(' ').map(|s| s.to_string()).collect() str.split(' ').map(|s| s.to_string()).collect()
}), }),
background: Some({ background: {
let string: String = row.try_get(7)?; 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({ text_alignment: Some({
let horizontal_alignment: String = row.try_get(3)?; let horizontal_alignment: String = row.try_get(3)?;
let vertical_alignment: String = row.try_get(4)?; 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", "top") => TextAlignment::TopLeft,
("left", "center") => TextAlignment::MiddleLeft, ("left", "center") => TextAlignment::MiddleLeft,
("left", "bottom") => TextAlignment::BottomLeft, ("left", "bottom") => TextAlignment::BottomLeft,
@ -66,7 +72,7 @@ impl FromRow<'_, SqliteRow> for Song {
("right", "top") => TextAlignment::TopRight, ("right", "top") => TextAlignment::TopRight,
("right", "center") => TextAlignment::MiddleRight, ("right", "center") => TextAlignment::MiddleRight,
("right", "bottom") => TextAlignment::BottomRight, ("right", "bottom") => TextAlignment::BottomRight,
_ => TextAlignment::MiddleCenter _ => TextAlignment::MiddleCenter,
} }
}), }),
font: row.try_get(6)?, 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<Song> {
pub async fn get_song_from_db(index: i32, db: &mut SqliteConnection) -> Result<Song> { 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()?;
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).into_diagnostic()?)
Ok(Song::from_row(&row)?)
} }
impl Model<Song> { impl Model<Song> {
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"; // static DATABASE_URL: &str = "sqlite:///home/chris/.local/share/lumina/library-db.sqlite3";
let rt = tokio::runtime::Runtime::new().unwrap(); 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;
rt.block_on(async { match result {
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; Ok(s) => {
match result { for song in s.into_iter() {
Ok(s) => { match Song::from_row(&song) {
for song in s.into_iter() { Ok(song) => {
match Song::from_row(&song) { let _ = self.add_item(song);
Ok(song) => { },
let _ = self.add_item(song); Err(e) => error!("Could not convert song: {e}"),
},
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<Vec<String>> { pub fn get_lyrics(&self) -> Result<Vec<String>> {
let mut lyric_list = Vec::new(); let mut lyric_list = Vec::new();
if self.lyrics.is_none() { 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() { } else if self.verse_order.is_none() {
return Err(eyre!("There is no verse_order here")); return Err(miette!("There is no verse_order here"));
} else if self } else if self.verse_order.clone().is_some_and(|v| v.is_empty()) {
.verse_order return Err(miette!("There is no verse_order here"));
.clone()
.is_some_and(|v| v.is_empty())
{
return Err(eyre!("There is no verse_order here"));
} }
if let Some(raw_lyrics) = self.lyrics.clone() { if let Some(raw_lyrics) = self.lyrics.clone() {
let raw_lyrics = raw_lyrics.as_str(); let raw_lyrics = raw_lyrics.as_str();
@ -148,21 +145,16 @@ impl Song {
let mut verse_name = ""; let mut verse_name = "";
debug!(verse = verse); debug!(verse = verse);
for word in VERSE_KEYWORDS { for word in VERSE_KEYWORDS {
let end_verse = let end_verse = verse.get(1..2).unwrap_or_default();
verse.get(1..2).unwrap_or_default(); let beg_verse = verse.get(0..1).unwrap_or_default();
let beg_verse = if word.starts_with(beg_verse) && word.ends_with(end_verse) {
verse.get(0..1).unwrap_or_default();
if word.starts_with(beg_verse)
&& word.ends_with(end_verse)
{
verse_name = word; verse_name = word;
continue; continue;
} }
} }
if let Some(lyric) = lyric_map.get(verse_name) { if let Some(lyric) = lyric_map.get(verse_name) {
if lyric.contains("\n\n") { if lyric.contains("\n\n") {
let split_lyrics: Vec<&str> = let split_lyrics: Vec<&str> = lyric.split("\n\n").collect();
lyric.split("\n\n").collect();
for lyric in split_lyrics { for lyric in split_lyrics {
if lyric.is_empty() { if lyric.is_empty() {
continue; continue;
@ -181,7 +173,7 @@ impl Song {
} }
Ok(lyric_list) Ok(lyric_list)
} else { } else {
Err(eyre!("There are no lyrics")) Err(miette!("There are no lyrics"))
} }
} }
} }
@ -254,12 +246,11 @@ From the day
You saved my soul" You saved my soul"
.to_string(), .to_string(),
); );
song.verse_order = song.verse_order = "O1 V1 C1 C2 O2 V2 C3 C2 O2 B1 C2 C2 E1 O2"
"O1 V1 C1 C2 O2 V2 C3 C2 O2 B1 C2 C2 E1 O2" .to_string()
.to_string() .split(' ')
.split(' ') .map(|s| Some(s.to_string()))
.map(|s| Some(s.to_string())) .collect();
.collect();
let lyrics = song.get_lyrics(); let lyrics = song.get_lyrics();
match lyrics { match lyrics {
Ok(lyrics) => { Ok(lyrics) => {
@ -271,40 +262,47 @@ You saved my soul"
} }
} }
#[test] async fn model() -> Model<Song> {
pub fn test_db_and_model() { let song_model: Model<Song> = Model {
let mut song_model: Model<Song> = Model::default(); items: vec![],
song_model.load_from_db(); 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) { if let Some(song) = song_model.find(|s| s.id == 7) {
let test_song = test_song(); let test_song = test_song();
assert_eq!(&test_song, song); assert_eq!(&test_song, song);
} else { } else {
dbg!(song_model);
assert!(false); assert!(false);
} }
} }
#[tokio::test] #[tokio::test]
pub async fn test_song_from_db() { async fn test_song_from_db() {
let song = test_song(); 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 { match result {
Ok(db_song) => assert_eq!(song, db_song), Ok(db_song) => assert_eq!(song, db_song),
Err(e) => assert!(false, "{e}"), Err(e) => assert!(false, "{e}"),
} }
} }
#[test] #[tokio::test]
pub fn test_update() { async fn test_update() {
let song = test_song(); let song = test_song();
let cloned_song = song.clone(); let cloned_song = song.clone();
let mut song_model: Model<Song> = Model::default(); let mut song_model: Model<Song> = model().await;
song_model.load_from_db(); song_model.load_from_db().await;
match song_model.update_item(song, 2) { match song_model.update_item(song, 2) {
Ok(()) => assert_eq!( Ok(()) => assert_eq!(&cloned_song, song_model.find(|s| s.id == 7).unwrap()),
&cloned_song,
song_model.find(|s| s.id == 7).unwrap()
),
Err(e) => assert!(false, "{e}"), Err(e) => assert!(false, "{e}"),
} }
} }

View file

@ -1,5 +1,6 @@
use crate::model::Model; use super::model::Model;
use color_eyre::eyre::Result; use cosmic::{executor, iced::Executor};
use miette::{Result, miette, IntoDiagnostic};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sqlx::{query_as, SqliteConnection}; use sqlx::{query_as, SqliteConnection};
use std::path::PathBuf; use std::path::PathBuf;
@ -16,28 +17,23 @@ pub struct Video {
} }
impl Model<Video> { impl Model<Video> {
pub fn load_from_db(&mut self) { pub async fn load_from_db(&mut self) {
let rt = tokio::runtime::Runtime::new().unwrap(); let result = query_as!(Video, r#"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"#).fetch_all(&mut self.db).await;
rt.block_on(async { match result {
let result = query_as!(Video, r#"SELECT title as "title!", filePath as "path!", startTime as "start_time!: f32", endTime as "end_time!: f32", loop as "looping!", id as "id: i32" from videos"#).fetch_all(&mut self.db).await; Ok(v) => {
match result { for video in v.into_iter() {
Ok(v) => { let _ = self.add_item(video);
for video in v.into_iter() {
let _ = self.add_item(video);
}
} }
Err(e) => error!("There was an error in converting videos: {e}"),
} }
}); Err(e) => error!("There was an error in converting videos: {e}"),
};
} }
} }
pub async fn get_video_from_db(database_id: i32, db: &mut SqliteConnection) -> Result<Video> { pub async fn get_video_from_db(database_id: i32, db: &mut SqliteConnection) -> Result<Video> {
Ok(query_as!(Video, r#"SELECT title as "title!", filePath as "path!", startTime as "start_time!: f32", endTime as "end_time!: f32", loop as "looping!", id as "id: i32" from videos where id = ?"#, database_id).fetch_one(db).await?) Ok(query_as!(Video, r#"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 = ?"#, database_id).fetch_one(db).await.into_diagnostic()?)
} }
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
@ -51,37 +47,39 @@ mod test {
} }
} }
#[test] #[tokio::test]
pub fn test_db_and_model() { async fn test_db_and_model() {
let mut video_model: Model<Video> = Model::default(); let mut video_model: Model<Video> = Model {
video_model.load_from_db(); items: vec![],
db: crate::core::model::get_db().await
};
video_model.load_from_db().await;
if let Some(video) = video_model.find(|v| v.id == 73) { if let Some(video) = video_model.find(|v| v.id == 73) {
let test_video = test_video("Getting started with Tokio. The ultimate starter guide to writing async Rust.".into()); let test_video = test_video(
"Getting started with Tokio. The ultimate starter guide to writing async Rust."
.into(),
);
assert_eq!(test_video.title, video.title); assert_eq!(test_video.title, video.title);
} else { } else {
assert!(false); assert!(false);
} }
} }
#[test] #[tokio::test]
pub fn test_add_video() { async fn test_add_video() {
let video = test_video("A new video".into()); let video = test_video("A new video".into());
let mut video_model: Model<Video> = Model::default(); let mut video_model: Model<Video> = Model {
items: vec![],
db: crate::core::model::get_db().await
};
let result = video_model.add_item(video.clone()); let result = video_model.add_item(video.clone());
let new_video = test_video("A newer video".into()); let new_video = test_video("A newer video".into());
match result { match result {
Ok(_) => { Ok(_) => {
assert_eq!(&video, video_model.find(|v| v.id == 0).unwrap()); assert_eq!(&video, video_model.find(|v| v.id == 0).unwrap());
assert_ne!( assert_ne!(&new_video, video_model.find(|v| v.id == 0).unwrap());
&new_video,
video_model.find(|v| v.id == 0).unwrap()
);
} }
Err(e) => assert!( Err(e) => assert!(false, "There was an error adding the video: {:?}", e),
false,
"There was an error adding the video: {:?}",
e
),
} }
} }
} }