fix in mysql query

This commit is contained in:
Mateusz Gruszczyński
2026-07-27 15:26:29 +02:00
parent 87eee7a23d
commit 4bad891e39
3 changed files with 43 additions and 4 deletions
Generated
+1 -1
View File
@@ -2581,7 +2581,7 @@ dependencies = [
[[package]] [[package]]
name = "rustpad" name = "rustpad"
version = "0.1.1" version = "0.1.3"
dependencies = [ dependencies = [
"argon2", "argon2",
"aws-config", "aws-config",
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "rustpad" name = "rustpad"
version = "0.1.2" version = "0.1.3"
edition = "2024" edition = "2024"
rust-version = "1.94" rust-version = "1.94"
description = "Collaborative Markdown notepad built with Axum, WebSockets and SQLite, PostgreSQL and MySQL" description = "Collaborative Markdown notepad built with Axum, WebSockets and SQLite, PostgreSQL and MySQL"
+41 -2
View File
@@ -111,7 +111,10 @@ pub const SHARE_LINK_REVOKE: &str = "UPDATE resource_share_links SET revoked_at
pub const RESOURCE_PERMISSION_BY_USER: &str = "SELECT permission FROM resource_permissions WHERE resource_kind = ? AND resource_slug = ? AND user_id = ?"; pub const RESOURCE_PERMISSION_BY_USER: &str = "SELECT permission FROM resource_permissions WHERE resource_kind = ? AND resource_slug = ? AND user_id = ?";
pub const SHARE_LINK_PERMISSION: &str = "SELECT permission FROM resource_share_links WHERE token_hash = ? AND resource_kind = ? AND resource_slug = ? AND revoked_at IS NULL AND (expires_at IS NULL OR expires_at > ?)"; pub const SHARE_LINK_PERMISSION: &str = "SELECT permission FROM resource_share_links WHERE token_hash = ? AND resource_kind = ? AND resource_slug = ? AND revoked_at IS NULL AND (expires_at IS NULL OR expires_at > ?)";
pub const Q001: &str = "SELECT id, slug, title, password_hash, created_at, updated_at, CAST(CASE WHEN is_private THEN 1 ELSE 0 END AS BIGINT) AS is_private FROM workspaces WHERE slug = ?"; // SQLite uses INTEGER as the portable 64-bit integer cast target.
pub const Q001: &str = "SELECT id, slug, title, password_hash, created_at, updated_at, CAST(CASE WHEN is_private THEN 1 ELSE 0 END AS INTEGER) AS is_private FROM workspaces WHERE slug = ?";
pub const Q001_MYSQL: &str = "SELECT id, slug, title, password_hash, created_at, updated_at, CAST(CASE WHEN is_private THEN 1 ELSE 0 END AS SIGNED) AS is_private FROM workspaces WHERE slug = ?";
pub const Q001_POSTGRES: &str = "SELECT id, slug, title, password_hash, created_at, updated_at, CAST(CASE WHEN is_private THEN 1 ELSE 0 END AS BIGINT) AS is_private FROM workspaces WHERE slug = ?";
pub const Q002: &str = "INSERT INTO workspaces (slug, title, password_hash) VALUES (?, ?, ?)"; pub const Q002: &str = "INSERT INTO workspaces (slug, title, password_hash) VALUES (?, ?, ?)";
pub const Q003: &str = "SELECT id, workspace_id, slug, title, content, created_at, updated_at, owner_map, protected, created_by FROM notes WHERE workspace_id = ? ORDER BY updated_at DESC, id DESC"; pub const Q003: &str = "SELECT id, workspace_id, slug, title, content, created_at, updated_at, owner_map, protected, created_by FROM notes WHERE workspace_id = ? ORDER BY updated_at DESC, id DESC";
pub const Q004: &str = "SELECT id, workspace_id, slug, title, content, created_at, updated_at, owner_map, protected, created_by FROM notes WHERE workspace_id = ? AND slug = ?"; pub const Q004: &str = "SELECT id, workspace_id, slug, title, content, created_at, updated_at, owner_map, protected, created_by FROM notes WHERE workspace_id = ? AND slug = ?";
@@ -124,7 +127,10 @@ pub const Q008: &str =
"INSERT INTO note_revisions (note_id, content, author, owner_map) VALUES (?, ?, ?, ?)"; "INSERT INTO note_revisions (note_id, content, author, owner_map) VALUES (?, ?, ?, ?)";
pub const Q009: &str = "SELECT updated_at FROM notes WHERE id = ?"; pub const Q009: &str = "SELECT updated_at FROM notes WHERE id = ?";
pub const Q010: &str = "SELECT id, content, created_at, author, owner_map FROM note_revisions WHERE note_id = ? ORDER BY id DESC LIMIT 100"; pub const Q010: &str = "SELECT id, content, created_at, author, owner_map FROM note_revisions WHERE note_id = ? ORDER BY id DESC LIMIT 100";
pub const Q011: &str = "SELECT id, slug, title, content, password_hash, created_at, updated_at, owner_map, CAST(CASE WHEN is_private THEN 1 ELSE 0 END AS BIGINT) AS is_private FROM pads WHERE slug = ?"; // Keep privacy flags normalized to i64 across all SQLx Any drivers.
pub const Q011: &str = "SELECT id, slug, title, content, password_hash, created_at, updated_at, owner_map, CAST(CASE WHEN is_private THEN 1 ELSE 0 END AS INTEGER) AS is_private FROM pads WHERE slug = ?";
pub const Q011_MYSQL: &str = "SELECT id, slug, title, content, password_hash, created_at, updated_at, owner_map, CAST(CASE WHEN is_private THEN 1 ELSE 0 END AS SIGNED) AS is_private FROM pads WHERE slug = ?";
pub const Q011_POSTGRES: &str = "SELECT id, slug, title, content, password_hash, created_at, updated_at, owner_map, CAST(CASE WHEN is_private THEN 1 ELSE 0 END AS BIGINT) AS is_private FROM pads WHERE slug = ?";
pub const Q012: &str = "INSERT INTO pads (slug, title, password_hash) VALUES (?, ?, ?)"; pub const Q012: &str = "INSERT INTO pads (slug, title, password_hash) VALUES (?, ?, ?)";
pub const Q013: &str = pub const Q013: &str =
"UPDATE pads SET content = ?, owner_map = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?"; "UPDATE pads SET content = ?, owner_map = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?";
@@ -163,6 +169,14 @@ pub const Q047: &str = "DELETE FROM pad_files WHERE id = ? AND pad_id = ?";
static POSTGRES_QUERIES: OnceLock<Mutex<HashMap<&'static str, &'static str>>> = OnceLock::new(); static POSTGRES_QUERIES: OnceLock<Mutex<HashMap<&'static str, &'static str>>> = OnceLock::new();
pub fn get(kind: DatabaseKind, query: &'static str) -> &'static str { pub fn get(kind: DatabaseKind, query: &'static str) -> &'static str {
let query = match (kind, query) {
(DatabaseKind::MySql, Q001) => Q001_MYSQL,
(DatabaseKind::Postgres, Q001) => Q001_POSTGRES,
(DatabaseKind::MySql, Q011) => Q011_MYSQL,
(DatabaseKind::Postgres, Q011) => Q011_POSTGRES,
_ => query,
};
if kind != DatabaseKind::Postgres { if kind != DatabaseKind::Postgres {
return query; return query;
} }
@@ -202,3 +216,28 @@ pub const Q045: &str =
pub const Q021_POSTGRES: &str = "SELECT pp.token, pp.pad_id, pp.note_id, pp.allow_task_updates, COALESCE(p.title, n.title) AS title, COALESCE(p.content, n.content) AS content, COALESCE(p.updated_at, n.updated_at) AS updated_at FROM published_pages pp LEFT JOIN pads p ON p.id = pp.pad_id LEFT JOIN notes n ON n.id = pp.note_id WHERE pp.token = $1"; pub const Q021_POSTGRES: &str = "SELECT pp.token, pp.pad_id, pp.note_id, pp.allow_task_updates, COALESCE(p.title, n.title) AS title, COALESCE(p.content, n.content) AS content, COALESCE(p.updated_at, n.updated_at) AS updated_at FROM published_pages pp LEFT JOIN pads p ON p.id = pp.pad_id LEFT JOIN notes n ON n.id = pp.note_id WHERE pp.token = $1";
pub const Q044_POSTGRES: &str = "SELECT allow_task_updates FROM published_pages WHERE pad_id = $1"; pub const Q044_POSTGRES: &str = "SELECT allow_task_updates FROM published_pages WHERE pad_id = $1";
pub const Q045_POSTGRES: &str = "SELECT allow_task_updates FROM published_pages WHERE note_id = $1"; pub const Q045_POSTGRES: &str = "SELECT allow_task_updates FROM published_pages WHERE note_id = $1";
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn privacy_cast_matches_database_dialect() {
assert!(get(DatabaseKind::Sqlite, Q001).contains(" AS INTEGER)"));
assert!(get(DatabaseKind::MySql, Q001).contains(" AS SIGNED)"));
let postgres = get(DatabaseKind::Postgres, Q001);
assert!(postgres.contains(" AS BIGINT)"));
assert!(postgres.ends_with("slug = $1"));
}
#[test]
fn pad_privacy_cast_matches_database_dialect() {
assert!(get(DatabaseKind::Sqlite, Q011).contains(" AS INTEGER)"));
assert!(get(DatabaseKind::MySql, Q011).contains(" AS SIGNED)"));
let postgres = get(DatabaseKind::Postgres, Q011);
assert!(postgres.contains(" AS BIGINT)"));
assert!(postgres.ends_with("slug = $1"));
}
}