test(sandbox): add repository testing

This commit is contained in:
Matthieu Bessat 2025-10-12 14:02:20 +02:00
parent 3d93beb5bd
commit bbec0fc3bf
15 changed files with 545 additions and 124 deletions

275
Cargo.lock generated
View file

@ -3,17 +3,20 @@
version = 4
[[package]]
name = "ahash"
version = "0.8.11"
name = "addr2line"
version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b"
dependencies = [
"cfg-if",
"once_cell",
"version_check",
"zerocopy",
"gimli",
]
[[package]]
name = "adler2"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
[[package]]
name = "allocator-api2"
version = "0.2.21"
@ -118,6 +121,21 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "backtrace"
version = "0.3.76"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6"
dependencies = [
"addr2line",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
"windows-link",
]
[[package]]
name = "base64"
version = "0.22.1"
@ -346,16 +364,6 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "errno"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
dependencies = [
"libc",
"windows-sys 0.59.0",
]
[[package]]
name = "etcetera"
version = "0.8.0"
@ -378,12 +386,6 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "fastrand"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
[[package]]
name = "flume"
version = "0.11.1"
@ -395,6 +397,12 @@ dependencies = [
"spin",
]
[[package]]
name = "foldhash"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]]
name = "form_urlencoded"
version = "1.2.1"
@ -508,28 +516,29 @@ dependencies = [
]
[[package]]
name = "hashbrown"
version = "0.14.5"
name = "gimli"
version = "0.32.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
dependencies = [
"ahash",
"allocator-api2",
]
checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7"
[[package]]
name = "hashbrown"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
dependencies = [
"allocator-api2",
"equivalent",
"foldhash",
]
[[package]]
name = "hashlink"
version = "0.9.1"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af"
checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1"
dependencies = [
"hashbrown 0.14.5",
"hashbrown",
]
[[package]]
@ -740,7 +749,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
dependencies = [
"equivalent",
"hashbrown 0.15.2",
"hashbrown",
]
[[package]]
@ -749,6 +758,17 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71dd52191aae121e8611f1e8dc3e324dd0dd1dee1e6dd91d10ee07a3cfb4d9d8"
[[package]]
name = "io-uring"
version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b"
dependencies = [
"bitflags",
"cfg-if",
"libc",
]
[[package]]
name = "itoa"
version = "1.0.14"
@ -797,12 +817,6 @@ dependencies = [
"vcpkg",
]
[[package]]
name = "linux-raw-sys"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
[[package]]
name = "litemap"
version = "0.7.4"
@ -865,19 +879,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
name = "miniz_oxide"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
dependencies = [
"adler2",
]
[[package]]
name = "nom"
version = "7.1.3"
name = "mio"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
dependencies = [
"memchr",
"minimal-lexical",
"libc",
"wasi",
"windows-sys 0.59.0",
]
[[package]]
@ -927,6 +945,15 @@ dependencies = [
"libm",
]
[[package]]
name = "object"
version = "0.37.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe"
dependencies = [
"memchr",
]
[[package]]
name = "once_cell"
version = "1.20.2"
@ -962,12 +989,6 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "paste"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]]
name = "pem-rfc7468"
version = "0.7.0"
@ -1158,17 +1179,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a157657054ffe556d8858504af8a672a054a6e0bd9e8ee531059100c0fa11bb2"
[[package]]
name = "rustix"
version = "0.38.42"
name = "rustc-demangle"
version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.59.0",
]
checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
[[package]]
name = "ryu"
@ -1293,6 +1307,16 @@ dependencies = [
"serde",
]
[[package]]
name = "socket2"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8"
dependencies = [
"libc",
"windows-sys 0.52.0",
]
[[package]]
name = "spin"
version = "0.9.8"
@ -1312,21 +1336,11 @@ dependencies = [
"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"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93334716a037193fac19df402f8571269c84a00852f6a7066b5d2616dcd64d3e"
checksum = "1fefb893899429669dcdd979aff487bd78f4064e5e7907e4269081e0ef7d97dc"
dependencies = [
"sqlx-core",
"sqlx-macros",
@ -1337,38 +1351,35 @@ dependencies = [
[[package]]
name = "sqlx-core"
version = "0.8.2"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4d8060b456358185f7d50c55d9b5066ad956956fddec42ee2e8567134a8936e"
checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6"
dependencies = [
"atoi",
"byteorder",
"base64",
"bytes",
"chrono",
"crc",
"crossbeam-queue",
"either",
"event-listener",
"futures-channel",
"futures-core",
"futures-intrusive",
"futures-io",
"futures-util",
"hashbrown 0.14.5",
"hashbrown",
"hashlink",
"hex",
"indexmap",
"log",
"memchr",
"once_cell",
"paste",
"percent-encoding",
"serde",
"serde_json",
"sha2",
"smallvec",
"sqlformat",
"thiserror",
"tokio",
"tokio-stream",
"tracing",
"url",
"uuid",
@ -1376,9 +1387,9 @@ dependencies = [
[[package]]
name = "sqlx-macros"
version = "0.8.2"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cac0692bcc9de3b073e8d747391827297e075c7710ff6276d9f7a1f3d58c6657"
checksum = "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d"
dependencies = [
"proc-macro2",
"quote",
@ -1389,9 +1400,9 @@ dependencies = [
[[package]]
name = "sqlx-macros-core"
version = "0.8.2"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1804e8a7c7865599c9c79be146dc8a9fd8cc86935fa641d3ea58e5f0688abaa5"
checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b"
dependencies = [
"dotenvy",
"either",
@ -1408,15 +1419,15 @@ dependencies = [
"sqlx-postgres",
"sqlx-sqlite",
"syn",
"tempfile",
"tokio",
"url",
]
[[package]]
name = "sqlx-mysql"
version = "0.8.2"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64bb4714269afa44aef2755150a0fc19d756fb580a67db8885608cf02f47d06a"
checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526"
dependencies = [
"atoi",
"base64",
@ -1458,9 +1469,9 @@ dependencies = [
[[package]]
name = "sqlx-postgres"
version = "0.8.2"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fa91a732d854c5d7726349bb4bb879bb9478993ceb764247660aee25f67c2f8"
checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46"
dependencies = [
"atoi",
"base64",
@ -1472,7 +1483,6 @@ dependencies = [
"etcetera",
"futures-channel",
"futures-core",
"futures-io",
"futures-util",
"hex",
"hkdf",
@ -1498,9 +1508,9 @@ dependencies = [
[[package]]
name = "sqlx-sqlite"
version = "0.8.2"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5b2cf34a45953bfd3daaf3db0f7a7878ab9b7a6b91b422d24a7a9e4c857b680"
checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea"
dependencies = [
"atoi",
"chrono",
@ -1516,6 +1526,7 @@ dependencies = [
"serde",
"serde_urlencoded",
"sqlx-core",
"thiserror",
"tracing",
"url",
"uuid",
@ -1616,33 +1627,20 @@ dependencies = [
"syn",
]
[[package]]
name = "tempfile"
version = "3.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c"
dependencies = [
"cfg-if",
"fastrand",
"once_cell",
"rustix",
"windows-sys 0.59.0",
]
[[package]]
name = "thiserror"
version = "1.0.69"
version = "2.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.69"
version = "2.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
dependencies = [
"proc-macro2",
"quote",
@ -1674,6 +1672,34 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
version = "1.46.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17"
dependencies = [
"backtrace",
"bytes",
"io-uring",
"libc",
"mio",
"pin-project-lite",
"slab",
"socket2",
"windows-sys 0.52.0",
]
[[package]]
name = "tokio-stream"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047"
dependencies = [
"futures-core",
"pin-project-lite",
"tokio",
]
[[package]]
name = "tracing"
version = "0.1.41"
@ -1745,12 +1771,6 @@ version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
[[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.4"
@ -1877,6 +1897,12 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-sys"
version = "0.48.0"
@ -1886,6 +1912,15 @@ dependencies = [
"windows-targets 0.48.5",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-sys"
version = "0.59.0"

View file

@ -38,6 +38,16 @@ Will be used in [minauthator](https://forge.lefuturiste.fr/mbess/minauthator).
cargo run --bin sqlx-generator -- ./path/to/project generate-create-migrations > migrations/all.sql
sqlx-generator \
-m path/to/models \
gen-repositories \
-o path/to/repositories
sqlx-generator \
-m path/to/models \
gen-migrations \
-o path/to/migrations/all.sql
### Generate repositories code
not implemented yet

View file

@ -10,5 +10,5 @@ path = "src/main.rs"
chrono = "0.4.39"
fully_pub = "0.1.4"
serde = "1.0.216"
sqlx = { version = "0.8.2", features = ["chrono", "uuid", "sqlite"] }
sqlx = { version = "0.8.6", features = ["sqlite", "runtime-tokio", "chrono", "uuid", "migrate"] }
sqlxgentools_attrs = { path = "../sqlxgentools_attrs" }

26
lib/sandbox/justfile Normal file
View file

@ -0,0 +1,26 @@
# Children justfile
reset-db *args:
rm sandbox.db
sqlite3 {{args}} sandbox.db < src/migrations/all.sql
gen-sqlx:
../../target/release/sqlx-generator \
-m src/models \
gen-repositories \
-o src/repositories
../../target/release/sqlx-generator \
-m src/models \
gen-migrations \
-o src/migrations/all.sql
gen-sqlx-debug:
../../target/debug/sqlx-generator \
-m src/models \
gen-repositories \
-o src/repositories
../../target/debug/sqlx-generator \
-m src/models \
gen-migrations \
-o src/migrations/all.sql

10
lib/sandbox/src/db.rs Normal file
View file

@ -0,0 +1,10 @@
use fully_pub::fully_pub;
use sqlx::{
Pool, Sqlite,
};
/// database storage interface
#[fully_pub]
#[derive(Clone, Debug)]
struct Database(Pool<Sqlite>);

3
lib/sandbox/src/lib.rs Normal file
View file

@ -0,0 +1,3 @@
pub mod repositories;
pub mod db;
pub mod models;

View file

@ -1,4 +1,6 @@
pub mod models;
pub mod repositories;
pub mod db;
fn main() {
println!("Sandbox")

View file

@ -0,0 +1,18 @@
CREATE TABLE usersss (
id TEXT NOT NULL PRIMARY KEY,
handle TEXT NOT NULL UNIQUE,
full_name TEXT,
prefered_color INTEGER,
last_login_at DATETIME,
status TEXT NOT NULL,
groups TEXT NOT NULL,
avatar_bytes BLOB NOT NULL
);
CREATE TABLE user_tokens (
id TEXT NOT NULL PRIMARY KEY,
user_id TEXT NOT NULL,
secret TEXT NOT NULL,
last_use_time DATETIME,
creation_time DATETIME NOT NULL,
expiration_time DATETIME NOT NULL
);

View file

@ -0,0 +1 @@
pub mod user;

View file

@ -5,6 +5,7 @@ use fully_pub::fully_pub;
use sqlxgentools_attrs::{sql_generator_model, SqlGeneratorDerive};
#[derive(sqlx::Type, Clone, Debug, PartialEq)]
#[fully_pub]
enum UserStatus {
Disabled,
Invited,
@ -34,7 +35,7 @@ struct User {
struct UserToken {
#[sql_generator_field(is_primary=true)]
id: String,
#[sql_generator_field(foreign_key=Relation::BelongsTo(User))]
// #[sql_generator_field(foreign_key=Relation::BelongsTo(User))]
user_id: String,
secret: String,
last_use_time: Option<DateTime<Utc>>,
@ -42,4 +43,3 @@ struct UserToken {
expiration_time: DateTime<Utc>
}

View file

@ -0,0 +1,2 @@
pub mod user_repository;
pub mod user_token_repository;

View file

@ -0,0 +1,115 @@
use crate::models::user::User;
use crate::db::Database;
pub struct UserRepository {
db: Database,
}
impl UserRepository {
pub fn new(db: Database) -> Self {
UserRepository { db }
}
pub async fn get_all(&self) -> Result<Vec<User>, sqlx::Error> {
sqlx::query_as::<_, User>("SELECT * FROM usersss").fetch_all(&self.db.0).await
}
pub async fn get_by_id(&self, item_id: &str) -> Result<User, sqlx::Error> {
sqlx::query_as::<_, User>("SELECT * FROM usersss WHERE id = $1")
.bind(item_id)
.fetch_one(&self.db.0)
.await
}
pub async fn get_many_by_id(
&self,
items_ids: &[&str],
) -> Result<Vec<User>, sqlx::Error> {
if items_ids.is_empty() {
return Ok(vec![]);
}
let placeholder_params: String = (1..=(items_ids.len()))
.map(|i| format!("${}", i))
.collect::<Vec<String>>()
.join(",");
let query_sql = format!(
"SELECT * FROM usersss WHERE id IN ({})", placeholder_params
);
let mut query = sqlx::query_as::<_, User>(&query_sql);
for id in items_ids {
query = query.bind(id);
}
query.fetch_all(&self.db.0).await
}
pub async fn insert(&self, entity: &User) -> Result<(), sqlx::Error> {
sqlx::query(
"INSERT INTO usersss (id, handle, full_name, prefered_color, last_login_at, status, groups, avatar_bytes) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)",
)
.bind(&entity.id)
.bind(&entity.handle)
.bind(&entity.full_name)
.bind(&entity.prefered_color)
.bind(&entity.last_login_at)
.bind(&entity.status)
.bind(&entity.groups)
.bind(&entity.avatar_bytes)
.execute(&self.db.0)
.await?;
Ok(())
}
pub async fn insert_many(&self, entities: &Vec<User>) -> Result<(), sqlx::Error> {
let values_templates: String = (1..(8usize * entities.len() + 1))
.collect::<Vec<usize>>()
.chunks(8usize)
.map(|c| c.to_vec())
.map(|x| {
format!(
"({})", x.iter().map(| i | format!("${}", i)).collect:: < Vec <
String >> ().join(", ")
)
})
.collect::<Vec<String>>()
.join(", ");
let query_sql = format!(
"INSERT INTO usersss (id, handle, full_name, prefered_color, last_login_at, status, groups, avatar_bytes) VALUES {} ON CONFLICT DO NOTHING",
values_templates
);
let mut query = sqlx::query(&query_sql);
for entity in entities {
query = query
.bind(&entity.id)
.bind(&entity.handle)
.bind(&entity.full_name)
.bind(&entity.prefered_color)
.bind(&entity.last_login_at)
.bind(&entity.status)
.bind(&entity.groups)
.bind(&entity.avatar_bytes);
}
query.execute(&self.db.0).await?;
Ok(())
}
pub async fn update_by_id(
&self,
item_id: &str,
entity: &User,
) -> Result<(), sqlx::Error> {
sqlx::query(
"UPDATE usersss SET id = $2, handle = $3, full_name = $4, prefered_color = $5, last_login_at = $6, status = $7, groups = $8, avatar_bytes = $9 WHERE id = $1",
)
.bind(item_id)
.bind(&entity.id)
.bind(&entity.handle)
.bind(&entity.full_name)
.bind(&entity.prefered_color)
.bind(&entity.last_login_at)
.bind(&entity.status)
.bind(&entity.groups)
.bind(&entity.avatar_bytes)
.execute(&self.db.0)
.await?;
Ok(())
}
pub async fn delete_by_id(&self, item_id: &str) -> Result<(), sqlx::Error> {
sqlx::query("DELETE FROM usersss WHERE id = $1")
.bind(item_id)
.execute(&self.db.0)
.await?;
Ok(())
}
}

View file

@ -0,0 +1,114 @@
use crate::models::user::UserToken;
use crate::db::Database;
pub struct UserTokenRepository {
db: Database,
}
impl UserTokenRepository {
pub fn new(db: Database) -> Self {
UserTokenRepository { db }
}
pub async fn get_all(&self) -> Result<Vec<UserToken>, sqlx::Error> {
sqlx::query_as::<_, UserToken>("SELECT * FROM user_tokens")
.fetch_all(&self.db.0)
.await
}
pub async fn get_by_id(&self, item_id: &str) -> Result<UserToken, sqlx::Error> {
sqlx::query_as::<_, UserToken>("SELECT * FROM user_tokens WHERE id = $1")
.bind(item_id)
.fetch_one(&self.db.0)
.await
}
pub async fn get_many_by_id(
&self,
items_ids: &[&str],
) -> Result<Vec<UserToken>, sqlx::Error> {
if items_ids.is_empty() {
return Ok(vec![]);
}
let placeholder_params: String = (1..=(items_ids.len()))
.map(|i| format!("${}", i))
.collect::<Vec<String>>()
.join(",");
let query_sql = format!(
"SELECT * FROM user_tokens WHERE id IN ({})", placeholder_params
);
let mut query = sqlx::query_as::<_, UserToken>(&query_sql);
for id in items_ids {
query = query.bind(id);
}
query.fetch_all(&self.db.0).await
}
pub async fn insert(&self, entity: &UserToken) -> Result<(), sqlx::Error> {
sqlx::query(
"INSERT INTO user_tokens (id, user_id, secret, last_use_time, creation_time, expiration_time) VALUES ($1, $2, $3, $4, $5, $6)",
)
.bind(&entity.id)
.bind(&entity.user_id)
.bind(&entity.secret)
.bind(&entity.last_use_time)
.bind(&entity.creation_time)
.bind(&entity.expiration_time)
.execute(&self.db.0)
.await?;
Ok(())
}
pub async fn insert_many(
&self,
entities: &Vec<UserToken>,
) -> Result<(), sqlx::Error> {
let values_templates: String = (1..(6usize * entities.len() + 1))
.collect::<Vec<usize>>()
.chunks(6usize)
.map(|c| c.to_vec())
.map(|x| {
format!(
"({})", x.iter().map(| i | format!("${}", i)).collect:: < Vec <
String >> ().join(", ")
)
})
.collect::<Vec<String>>()
.join(", ");
let query_sql = format!(
"INSERT INTO user_tokens (id, user_id, secret, last_use_time, creation_time, expiration_time) VALUES {} ON CONFLICT DO NOTHING",
values_templates
);
let mut query = sqlx::query(&query_sql);
for entity in entities {
query = query
.bind(&entity.id)
.bind(&entity.user_id)
.bind(&entity.secret)
.bind(&entity.last_use_time)
.bind(&entity.creation_time)
.bind(&entity.expiration_time);
}
query.execute(&self.db.0).await?;
Ok(())
}
pub async fn update_by_id(
&self,
item_id: &str,
entity: &UserToken,
) -> Result<(), sqlx::Error> {
sqlx::query(
"UPDATE user_tokens SET id = $2, user_id = $3, secret = $4, last_use_time = $5, creation_time = $6, expiration_time = $7 WHERE id = $1",
)
.bind(item_id)
.bind(&entity.id)
.bind(&entity.user_id)
.bind(&entity.secret)
.bind(&entity.last_use_time)
.bind(&entity.creation_time)
.bind(&entity.expiration_time)
.execute(&self.db.0)
.await?;
Ok(())
}
pub async fn delete_by_id(&self, item_id: &str) -> Result<(), sqlx::Error> {
sqlx::query("DELETE FROM user_tokens WHERE id = $1")
.bind(item_id)
.execute(&self.db.0)
.await?;
Ok(())
}
}

View file

@ -0,0 +1,86 @@
#![feature(assert_matches)]
// integration tests
use std::assert_matches::assert_matches;
use chrono::Utc;
use sandbox::{models::user::{User, UserStatus}, repositories::user_repository::UserRepository};
use sqlx::{types::Json, Pool, Sqlite};
#[sqlx::test(fixtures("../src/migrations/all.sql"))]
async fn test_user_repository_create_read_update_delete(pool: Pool<Sqlite>) -> sqlx::Result<()> {
pool.acquire().await?;
// Create
let user_repo = UserRepository::new(sandbox::db::Database(pool));
let new_user = User {
id: "ffffffff-0000-4000-0000-0000000000c9".into(),
handle: "caravage".into(),
full_name: Some("Michelangelo Merisi da Caravaggio".into()),
prefered_color: Some(0xff00ff.into()),
last_login_at: Some(Utc::now()),
status: UserStatus::Invited,
groups: Json(vec!["artists".into()]),
avatar_bytes: vec![0x00]
};
assert_matches!(
user_repo.insert(&new_user).await,
Ok(())
);
assert_matches!(
user_repo.get_by_id("ffffffff-0000-4000-0000-0000000000c9".into()).await,
Ok(User { .. })
);
assert_matches!(
user_repo.get_by_id("ffffffff-0000-4040-0000-000000000000".into()).await,
Err(sqlx::Error::RowNotFound)
);
// Insert Many
let bunch_of_users: Vec<User> = (0..10).map(|pid| User {
id: format!("ffffffff-0000-4000-0010-{:0>8}", pid),
handle: format!("user num {}", pid),
full_name: None,
prefered_color: None,
last_login_at: None,
status: UserStatus::Invited,
groups: Json(vec![]),
avatar_bytes: vec![]
}).collect();
assert_matches!(
user_repo.insert_many(&bunch_of_users).await,
Ok(())
);
// Read many all
let read_all_res = user_repo.get_all().await;
assert_matches!(
read_all_res,
Ok(..)
);
let all_users = read_all_res.unwrap();
assert_eq!(all_users.len(), 11);
// Update
let mut updated_user = new_user.clone();
updated_user.status = UserStatus::Disabled;
assert_matches!(
user_repo.update_by_id(&new_user.id, &updated_user).await,
Ok(())
);
let user_from_db = user_repo.get_by_id("ffffffff-0000-4000-0000-0000000000c9".into()).await.unwrap();
assert_eq!(user_from_db.status, UserStatus::Disabled);
// Delete
assert_matches!(
user_repo.delete_by_id(&new_user.id).await,
Ok(())
);
assert_matches!(
user_repo.get_by_id("ffffffff-0000-4000-0000-0000000000c9".into()).await,
Err(sqlx::Error::RowNotFound)
);
Ok(())
}

View file

@ -235,7 +235,6 @@ fn generate_repository_file(model: &Model) -> Result<SourceNodeContainer> {
let base_repository_code: TokenStream = quote! {
use crate::models::#resource_module_ident::#resource_ident;
use crate::db::Database;
use anyhow::{Result, Context};
pub struct #repository_ident {
db: Database