Improve tests

This commit is contained in:
eraden 2022-04-17 23:11:58 +02:00
parent 4097e92268
commit 05584144d6
6 changed files with 140 additions and 9 deletions

1
Cargo.lock generated
View File

@ -974,6 +974,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"sqlx", "sqlx",
"sqlx-core",
"tera", "tera",
"thiserror", "thiserror",
"tokio 1.17.0", "tokio 1.17.0",

View File

@ -30,7 +30,8 @@ serde = { version = "1.0.136", features = ["derive"] }
serde_json = { version = "1.0.79" } serde_json = { version = "1.0.79" }
toml = { version = "0.5.8" } toml = { version = "0.5.8" }
sqlx = { version = "0.5.11", features = ["migrate", "runtime-actix-rustls", "all-types", "postgres"] } sqlx = { version = "0.5.13", features = ["migrate", "runtime-actix-rustls", "all-types", "postgres"] }
sqlx-core = { version = "0.5.13" }
thiserror = { version = "1.0.30" } thiserror = { version = "1.0.30" }

View File

@ -99,12 +99,18 @@
opEL.addEventListener('change', () => { opEL.addEventListener('change', () => {
switch (opEL.value) { switch (opEL.value) {
case 'auto-login': case 'auto-login': {
paramsEl.value = `login=Eraden\npassword=text` paramsEl.value = `login=Eraden\npassword=text`
return send(mthEl.value = 'POST', urlEl.value = '/admin/sign-in', { login: 'Eraden', password: 'test' }) mthEl.value = 'POST';
case 'get-products': urlEl.value = '/admin/sign-in';
return send(mthEl.value = 'GET', urlEl.value = '/admin/api/v1/products', {}) break;
case 'create-product': }
case 'get-products': {
mthEl.value = 'GET';
urlEl.value = '/admin/api/v1/products';
break;
}
case 'create-product': {
const p = { const p = {
name: 'Foo', name: 'Foo',
short_description: 'asd', short_description: 'asd',
@ -112,8 +118,11 @@
price_major: 12, price_major: 12,
price_minor: 0, price_minor: 0,
}; };
paramsEl.value = Object.entries(p).map((k, v) => `${ k }=${ v }}`).join('\n'); paramsEl.value = Object.entries(p).map(([k, v]) => `${ k }=${ v }`).join('\n');
return send(mthEl.value = 'POST', urlEl.value = '/admin/api/v1/product', p) mthEl.value = 'POST';
urlEl.value = '/admin/api/v1/product';
break;
}
} }
}) })

View File

@ -36,7 +36,8 @@ SELECT id,
long_description, long_description,
category, category,
price_major, price_major,
price_minor price_minor,
deliver_days_flag
FROM products FROM products
"#, "#,
) )

View File

@ -8,6 +8,8 @@ use serde::{Deserialize, Deserializer, Serialize};
pub enum TransformError { pub enum TransformError {
#[error("Given value is below minimal value")] #[error("Given value is below minimal value")]
BelowMinimal, BelowMinimal,
#[error("Given value is not valid day flag")]
NotDay,
} }
pub type RecordId = i32; pub type RecordId = i32;
@ -169,6 +171,108 @@ impl<'de> serde::Deserialize<'de> for NonNegative {
} }
} }
#[derive(Serialize, Deserialize, Debug, Copy, Clone, Display, From)]
#[serde(rename_all = "lowercase")]
pub enum Day {
Monday = 1 << 0,
Tuesday = 1 << 1,
Wednesday = 1 << 2,
Thursday = 1 << 3,
Friday = 1 << 4,
Saturday = 1 << 5,
Sunday = 1 << 6,
}
impl TryFrom<i32> for Day {
type Error = TransformError;
fn try_from(value: i32) -> Result<Self, Self::Error> {
if value == (Day::Monday as i32) {
Ok(Day::Monday)
} else if value == (Day::Tuesday as i32) {
Ok(Day::Tuesday)
} else if value == (Day::Wednesday as i32) {
Ok(Day::Wednesday)
} else if value == (Day::Thursday as i32) {
Ok(Day::Thursday)
} else if value == (Day::Friday as i32) {
Ok(Day::Friday)
} else if value == (Day::Saturday as i32) {
Ok(Day::Saturday)
} else if value == (Day::Sunday as i32) {
Ok(Day::Sunday)
} else {
Err(TransformError::NotDay)
}
}
}
#[derive(Serialize, Deserialize, Deref, Debug)]
#[serde(transparent)]
pub struct Days(Vec<Day>);
impl<'q> ::sqlx::encode::Encode<'q, sqlx::Postgres> for Days
where
i32: ::sqlx::encode::Encode<'q, sqlx::Postgres>,
{
fn encode_by_ref(
&self,
buf: &mut <sqlx::Postgres as ::sqlx::database::HasArguments<'q>>::ArgumentBuffer,
) -> ::sqlx::encode::IsNull {
let value = self.0.iter().fold(1, |memo, v| memo | *v as i32);
<i32 as ::sqlx::encode::Encode<sqlx::Postgres>>::encode_by_ref(&value, buf)
}
fn size_hint(&self) -> usize {
<i32 as ::sqlx::encode::Encode<sqlx::Postgres>>::size_hint(&Default::default())
}
}
impl<'r> ::sqlx::decode::Decode<'r, sqlx::Postgres> for Days
where
i32: ::sqlx::decode::Decode<'r, sqlx::Postgres>,
{
fn decode(
value: <sqlx::Postgres as ::sqlx::database::HasValueRef<'r>>::ValueRef,
) -> ::std::result::Result<
Self,
::std::boxed::Box<
dyn ::std::error::Error + 'static + ::std::marker::Send + ::std::marker::Sync,
>,
> {
let value = <i32 as ::sqlx::decode::Decode<'r, sqlx::Postgres>>::decode(value)?;
Ok(Days(
(0..9)
.into_iter()
.filter_map(|n| {
eprintln!(
"d {} {} {} {:?}",
n,
1 << n,
value & 1 << n,
Day::try_from(value & 1 << n).ok()
);
Day::try_from(value & 1 << n).ok()
})
.collect(),
))
}
}
impl sqlx::Type<sqlx::Postgres> for Days
where
i32: ::sqlx::Type<sqlx::Postgres>,
{
fn type_info() -> <sqlx::Postgres as ::sqlx::Database>::TypeInfo {
<i32 as ::sqlx::Type<sqlx::Postgres>>::type_info()
}
fn compatible(ty: &<sqlx::Postgres as ::sqlx::Database>::TypeInfo) -> bool {
<i32 as ::sqlx::Type<sqlx::Postgres>>::compatible(ty)
}
}
#[derive(sqlx::Type, Serialize, Deserialize, Deref, Debug)] #[derive(sqlx::Type, Serialize, Deserialize, Deref, Debug)]
#[sqlx(transparent)] #[sqlx(transparent)]
#[serde(transparent)] #[serde(transparent)]
@ -252,6 +356,7 @@ pub struct Product {
pub category: Option<ProductCategory>, pub category: Option<ProductCategory>,
pub price_major: PriceMajor, pub price_major: PriceMajor,
pub price_minor: PriceMinor, pub price_minor: PriceMinor,
pub deliver_days_flag: Days,
} }
#[derive(sqlx::Type, Serialize, Deserialize)] #[derive(sqlx::Type, Serialize, Deserialize)]

View File

@ -0,0 +1,14 @@
BEGIN;
CREATE TYPE "Price" AS (
"value" integer,
"currency" varchar
);
ALTER TABLE products
ADD COLUMN "deliver_days_flag" int
NOT NULL
-- 0x1111111
DEFAULT 127;
COMMIT;