mirror of
https://git.alemi.dev/guestbook.rs.git
synced 2024-12-19 02:54:52 +01:00
fix: sqlx AnyDb is kinda broken...
This commit is contained in:
parent
460ebef1bf
commit
41f86634e5
2 changed files with 39 additions and 27 deletions
27
src/model.rs
27
src/model.rs
|
@ -20,23 +20,16 @@ pub struct Page {
|
||||||
pub public: bool,
|
pub public: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO this is only necessary until sqlx fixes parsing BOOL and NULL, check model.rs for more
|
||||||
// deserializing Option<T> values on AnyDriver is broken, pr to fix is in progress
|
|
||||||
// https://github.com/launchbadge/sqlx/issues/2416
|
|
||||||
// https://github.com/launchbadge/sqlx/pull/2716
|
|
||||||
// until this is merged, must implement by hand
|
|
||||||
// once this is merged, just do #[derive(sqlx::FromRow)]
|
|
||||||
// also what the fuck is going on with bools???
|
|
||||||
// https://github.com/launchbadge/sqlx/issues/2778
|
|
||||||
impl<'r> sqlx::FromRow<'r, sqlx::any::AnyRow> for Page {
|
impl<'r> sqlx::FromRow<'r, sqlx::any::AnyRow> for Page {
|
||||||
fn from_row(row: &'r sqlx::any::AnyRow) -> Result<Self, sqlx::Error> {
|
fn from_row(row: &'r sqlx::any::AnyRow) -> Result<Self, sqlx::Error> {
|
||||||
Ok(
|
Ok(
|
||||||
Page {
|
Page {
|
||||||
id: row.get(0),
|
id: row.get::<i64, usize>(0),
|
||||||
author: row.get(1),
|
author: row.get::<String, usize>(1),
|
||||||
contact: row.try_get(2).ok(),
|
contact: _non_empty_string(row.get::<String, usize>(2)),
|
||||||
body: row.get(3),
|
body: row.get::<String, usize>(3),
|
||||||
timestamp: row.get(4),
|
timestamp: row.get::<i64, usize>(4),
|
||||||
public: row.get::<i32, usize>(5) > 0,
|
public: row.get::<i32, usize>(5) > 0,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -45,7 +38,6 @@ impl<'r> sqlx::FromRow<'r, sqlx::any::AnyRow> for Page {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, Serialize)]
|
#[derive(Debug, Clone, Default, Serialize)]
|
||||||
pub struct PageView {
|
pub struct PageView {
|
||||||
pub id: i64,
|
pub id: i64,
|
||||||
|
@ -128,3 +120,10 @@ pub struct PageOptions {
|
||||||
pub offset: Option<i32>,
|
pub offset: Option<i32>,
|
||||||
pub limit: Option<i32>,
|
pub limit: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn _non_empty_string(input: String) -> Option<String> {
|
||||||
|
match input.is_empty() {
|
||||||
|
true => None,
|
||||||
|
false => Some(input),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
|
use sqlx::Database;
|
||||||
|
|
||||||
use crate::{model::{PageView, PageInsertion, Page}, config::ConfigOverrides};
|
use crate::{model::{PageView, PageInsertion, Page}, config::ConfigOverrides};
|
||||||
|
|
||||||
|
@ -8,17 +9,29 @@ pub struct StorageProvider {
|
||||||
overrides: ConfigOverrides,
|
overrides: ConfigOverrides,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO bool type is not supported in Any driver?????
|
// TODO what the fuck is wrong with AnyPool driver?????
|
||||||
// so the `public` field is an integer which is ridicolous
|
// * deserializing Option<T> values on AnyDriver is broken, pr to fix is in progress
|
||||||
// but literally cannot get it to work ffs
|
// https://github.com/launchbadge/sqlx/issues/2416
|
||||||
|
// https://github.com/launchbadge/sqlx/pull/2716
|
||||||
|
// until this is merged, must implement by hand sqlx::FromRow<sqlx::any::AnyRow>
|
||||||
|
// once this is merged, just do #[derive(sqlx::FromRow)]
|
||||||
//
|
//
|
||||||
|
// * serializing Option<T> values on Postgres is unreliable, not even sure why?
|
||||||
|
// `incorrect binary data format in bind parameter`
|
||||||
|
// it seems related to expression caching and types that change (sometimes T, sometimes NULL)
|
||||||
|
// https://github.com/launchbadge/sqlx/issues/2885
|
||||||
|
// the suggested solution (`.persistent(false)`) doesn't work!
|
||||||
|
// we are forced to serialize NULLs as empty strings and lose the distinction
|
||||||
|
//
|
||||||
|
// * deserializing BOOL just doesn't work for some reason
|
||||||
// https://github.com/launchbadge/sqlx/issues/2778
|
// https://github.com/launchbadge/sqlx/issues/2778
|
||||||
|
// so the `public` field is an integer which is ridicolous
|
||||||
|
|
||||||
const SQLITE_SCHEMA : &str = "
|
const SQLITE_SCHEMA : &str = "
|
||||||
CREATE TABLE IF NOT EXISTS pages (
|
CREATE TABLE IF NOT EXISTS pages (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
author VARCHAR NOT NULL,
|
author VARCHAR NOT NULL,
|
||||||
contact VARCHAR,
|
contact VARCHAR NOT NULL,
|
||||||
body VARCHAR NOT NULL,
|
body VARCHAR NOT NULL,
|
||||||
timestamp INTEGER NOT NULL,
|
timestamp INTEGER NOT NULL,
|
||||||
public INTEGER NOT NULL
|
public INTEGER NOT NULL
|
||||||
|
@ -29,7 +42,7 @@ const POSTGRES_SCHEMA : &str = "
|
||||||
CREATE TABLE IF NOT EXISTS pages (
|
CREATE TABLE IF NOT EXISTS pages (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
author TEXT NOT NULL,
|
author TEXT NOT NULL,
|
||||||
contact TEXT,
|
contact TEXT NOT NULL,
|
||||||
body TEXT NOT NULL,
|
body TEXT NOT NULL,
|
||||||
timestamp INTEGER NOT NULL,
|
timestamp INTEGER NOT NULL,
|
||||||
public INTEGER NOT NULL
|
public INTEGER NOT NULL
|
||||||
|
@ -41,9 +54,9 @@ impl StorageProvider {
|
||||||
let db = sqlx::AnyPool::connect(dest).await?;
|
let db = sqlx::AnyPool::connect(dest).await?;
|
||||||
|
|
||||||
match db.acquire().await?.backend_name() {
|
match db.acquire().await?.backend_name() {
|
||||||
"PostgreSQL" => { sqlx::query(POSTGRES_SCHEMA).execute(&db).await?; },
|
sqlx::Postgres::NAME => { sqlx::query(POSTGRES_SCHEMA).execute(&db).await?; },
|
||||||
"SQLite" => { sqlx::query(SQLITE_SCHEMA).execute(&db).await?; },
|
sqlx::Sqlite::NAME => { sqlx::query(SQLITE_SCHEMA).execute(&db).await?; },
|
||||||
"MySQL" => { sqlx::query(SQLITE_SCHEMA).execute(&db).await?; }, // TODO will this work?
|
sqlx::MySql::NAME => { sqlx::query(SQLITE_SCHEMA).execute(&db).await?; }, // TODO will this work?
|
||||||
_ => tracing::warn!("could not ensure schema: unsupported database type"),
|
_ => tracing::warn!("could not ensure schema: unsupported database type"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,9 +67,9 @@ impl StorageProvider {
|
||||||
page.sanitize();
|
page.sanitize();
|
||||||
page.overrides(&self.overrides);
|
page.overrides(&self.overrides);
|
||||||
let result = sqlx::query("INSERT INTO pages (author, contact, body, timestamp, public) VALUES ($1, $2, $3, $4, $5)")
|
let result = sqlx::query("INSERT INTO pages (author, contact, body, timestamp, public) VALUES ($1, $2, $3, $4, $5)")
|
||||||
.bind(page.author.as_deref().unwrap_or("anonymous").to_string())
|
.bind(page.author.as_deref().unwrap_or("anonymous"))
|
||||||
.bind(page.contact.clone())
|
.bind(page.contact.as_deref().unwrap_or(""))
|
||||||
.bind(page.body.clone())
|
.bind(page.body.as_str())
|
||||||
.bind(page.date.unwrap_or(Utc::now()).timestamp())
|
.bind(page.date.unwrap_or(Utc::now()).timestamp())
|
||||||
.bind(if page.public.unwrap_or(true) { 1 } else { 0 })
|
.bind(if page.public.unwrap_or(true) { 1 } else { 0 })
|
||||||
.execute(&self.db)
|
.execute(&self.db)
|
||||||
|
@ -74,7 +87,7 @@ impl StorageProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn extract(&self, offset: i32, window: i32, public: bool) -> sqlx::Result<Vec<PageView>> {
|
pub async fn extract(&self, offset: i32, window: i32, public: bool) -> sqlx::Result<Vec<PageView>> {
|
||||||
let out = sqlx::query_as("SELECT * FROM pages WHERE public = $1 LIMIT $2 OFFSET $3")
|
let out = sqlx::query_as::<_, Page>("SELECT * FROM pages WHERE public = $1 LIMIT $2 OFFSET $3")
|
||||||
.bind(if public { 1 } else { 0 }) // TODO since AnyPool won't handle booleans we compare with an integer
|
.bind(if public { 1 } else { 0 }) // TODO since AnyPool won't handle booleans we compare with an integer
|
||||||
.bind(window)
|
.bind(window)
|
||||||
.bind(offset)
|
.bind(offset)
|
||||||
|
|
Loading…
Reference in a new issue