Use Julids for DbId.

First phase just does a typedef of "DbId = Julid", and confirms the plugin will load into
sqlite. All tests pass. Next phase removes client-side generation of IDs.
This commit is contained in:
Joe Ardent 2023-07-26 17:10:52 -07:00
parent 8a23272cfe
commit 7aefedf993
10 changed files with 277 additions and 259 deletions

1
.gitignore vendored
View file

@ -1 +1,2 @@
/target
/libjulid.so

289
Cargo.lock generated
View file

@ -234,6 +234,17 @@ dependencies = [
"num-traits",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi 0.1.19",
"libc",
"winapi",
]
[[package]]
name = "auto-future"
version = "1.0.0"
@ -439,6 +450,29 @@ dependencies = [
"serde",
]
[[package]]
name = "bindgen"
version = "0.60.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "062dddbc1ba4aca46de6338e2bf87771414c335f7b2f2036e8f3e9befebf88e6"
dependencies = [
"bitflags 1.3.2",
"cexpr",
"clang-sys",
"clap 3.2.25",
"env_logger",
"lazy_static",
"lazycell",
"log",
"peeking_take_while",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"which",
]
[[package]]
name = "bitflags"
version = "1.3.2"
@ -520,6 +554,15 @@ version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
[[package]]
name = "cexpr"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [
"nom",
]
[[package]]
name = "cfg-if"
version = "0.1.10"
@ -545,6 +588,32 @@ dependencies = [
"winapi",
]
[[package]]
name = "clang-sys"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f"
dependencies = [
"glob",
"libc",
"libloading",
]
[[package]]
name = "clap"
version = "3.2.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123"
dependencies = [
"atty",
"bitflags 1.3.2",
"clap_lex 0.2.4",
"indexmap 1.9.3",
"strsim",
"termcolor",
"textwrap",
]
[[package]]
name = "clap"
version = "4.3.19"
@ -564,7 +633,7 @@ checksum = "01c6a3f08f1fe5662a35cfe393aec09c4df95f60ee93b7556505260f75eee9e1"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"clap_lex 0.5.0",
"strsim",
"unicase",
"unicode-width",
@ -582,6 +651,15 @@ dependencies = [
"syn 2.0.27",
]
[[package]]
name = "clap_lex"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
dependencies = [
"os_str_bytes",
]
[[package]]
name = "clap_lex"
version = "0.5.0"
@ -754,6 +832,19 @@ dependencies = [
"serde",
]
[[package]]
name = "env_logger"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7"
dependencies = [
"atty",
"humantime",
"log",
"regex",
"termcolor",
]
[[package]]
name = "equivalent"
version = "1.0.1"
@ -958,6 +1049,18 @@ version = "0.27.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e"
[[package]]
name = "glob"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
version = "0.14.0"
@ -974,7 +1077,7 @@ version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "312f66718a2d7789ffef4f4b7b213138ed9f1eb3aa1d0d82fc99f88fb3ffd26f"
dependencies = [
"hashbrown",
"hashbrown 0.14.0",
]
[[package]]
@ -1011,6 +1114,15 @@ dependencies = [
"unicode-segmentation",
]
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "hermit-abi"
version = "0.3.2"
@ -1109,6 +1221,12 @@ dependencies = [
"libm",
]
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "hyper"
version = "0.14.27"
@ -1165,6 +1283,16 @@ dependencies = [
"unicode-normalization",
]
[[package]]
name = "indexmap"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown 0.12.3",
]
[[package]]
name = "indexmap"
version = "2.0.0"
@ -1172,7 +1300,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
dependencies = [
"equivalent",
"hashbrown",
"hashbrown 0.14.0",
]
[[package]]
@ -1181,7 +1309,7 @@ version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
dependencies = [
"hermit-abi",
"hermit-abi 0.3.2",
"rustix",
"windows-sys",
]
@ -1210,6 +1338,16 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "julid-rs"
version = "0.1.6"
dependencies = [
"rand",
"serde",
"sqlite-loadable",
"sqlx",
]
[[package]]
name = "justerror"
version = "1.1.0"
@ -1230,12 +1368,28 @@ dependencies = [
"spin 0.5.2",
]
[[package]]
name = "lazycell"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "libc"
version = "0.2.147"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
[[package]]
name = "libloading"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
dependencies = [
"cfg-if 1.0.0",
"winapi",
]
[[package]]
name = "libm"
version = "0.2.7"
@ -1421,7 +1575,7 @@ version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
dependencies = [
"hermit-abi",
"hermit-abi 0.3.2",
"libc",
]
@ -1454,6 +1608,12 @@ dependencies = [
"syn 2.0.27",
]
[[package]]
name = "os_str_bytes"
version = "6.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac"
[[package]]
name = "overload"
version = "0.1.1"
@ -1500,6 +1660,12 @@ version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
[[package]]
name = "peeking_take_while"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
[[package]]
name = "pem-rfc7468"
version = "0.7.0"
@ -1743,6 +1909,12 @@ version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustix"
version = "0.38.4"
@ -1825,18 +1997,18 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.175"
version = "1.0.176"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d25439cd7397d044e2748a6fe2432b5e85db703d6d097bd014b3c0ad1ebff0b"
checksum = "76dc28c9523c5d70816e393136b86d48909cfb27cecaa902d338c19ed47164dc"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.175"
version = "1.0.176"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b23f7ade6f110613c0d63858ddb8b94c1041f550eab58a16b371bdf2c9c80ab4"
checksum = "a4e7b8c5dc823e3b90651ff1d3808419cd14e5ad76de04feaf37da114e7a306f"
dependencies = [
"proc-macro2",
"quote",
@ -1929,6 +2101,12 @@ dependencies = [
"lazy_static",
]
[[package]]
name = "shlex"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
[[package]]
name = "signal-hook-registry"
version = "1.4.1"
@ -2009,6 +2187,40 @@ dependencies = [
"unicode_categories",
]
[[package]]
name = "sqlite-loadable"
version = "0.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a916b7bb8738eef189dea88731b619b80bf3f62b3acf05138fa43fbf8621cc94"
dependencies = [
"bitflags 1.3.2",
"serde",
"serde_json",
"sqlite-loadable-macros",
"sqlite3ext-sys",
]
[[package]]
name = "sqlite-loadable-macros"
version = "0.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f98bc75a8d6fd24f6a2cfea34f28758780fa17279d3051eec926efa381971e48"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "sqlite3ext-sys"
version = "0.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3afdc2b3dc08f16d6eecf8aa07d19975a268603ab1cca67d3f9b4172c507cf16"
dependencies = [
"bindgen",
"cc",
]
[[package]]
name = "sqlx"
version = "0.7.1"
@ -2032,7 +2244,6 @@ dependencies = [
"atoi",
"byteorder",
"bytes",
"chrono",
"crc",
"crossbeam-queue",
"dotenvy",
@ -2045,7 +2256,7 @@ dependencies = [
"futures-util",
"hashlink",
"hex",
"indexmap",
"indexmap 2.0.0",
"log",
"memchr",
"once_cell",
@ -2059,7 +2270,6 @@ dependencies = [
"smallvec",
"sqlformat",
"thiserror",
"time",
"tokio",
"tokio-stream",
"tracing",
@ -2098,7 +2308,6 @@ dependencies = [
"sha2 0.10.7",
"sqlx-core",
"sqlx-mysql",
"sqlx-postgres",
"sqlx-sqlite",
"syn 1.0.109",
"tempfile",
@ -2117,7 +2326,6 @@ dependencies = [
"bitflags 2.3.3",
"byteorder",
"bytes",
"chrono",
"crc",
"digest 0.10.7",
"dotenvy",
@ -2145,7 +2353,6 @@ dependencies = [
"sqlx-core",
"stringprep",
"thiserror",
"time",
"tracing",
"whoami",
]
@ -2160,7 +2367,6 @@ dependencies = [
"base64 0.21.2",
"bitflags 2.3.3",
"byteorder",
"chrono",
"crc",
"dotenvy",
"etcetera",
@ -2186,7 +2392,6 @@ dependencies = [
"sqlx-core",
"stringprep",
"thiserror",
"time",
"tracing",
"whoami",
]
@ -2198,7 +2403,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4c21bf34c7cae5b283efb3ac1bcc7670df7561124dc2f8bdc0b59be40f79a2"
dependencies = [
"atoi",
"chrono",
"flume",
"futures-channel",
"futures-core",
@ -2210,7 +2414,6 @@ dependencies = [
"percent-encoding",
"serde",
"sqlx-core",
"time",
"tracing",
"url",
]
@ -2278,6 +2481,21 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "termcolor"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
dependencies = [
"winapi-util",
]
[[package]]
name = "textwrap"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
[[package]]
name = "thiserror"
version = "1.0.44"
@ -2528,15 +2746,6 @@ version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]]
name = "ulid"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13a3aaa69b04e5b66cc27309710a569ea23593612387d67daaf102e73aa974fd"
dependencies = [
"rand",
]
[[package]]
name = "unicase"
version = "2.6.0"
@ -2727,7 +2936,8 @@ dependencies = [
"axum-macros",
"axum-test",
"chrono",
"clap",
"clap 4.3.19",
"julid-rs",
"justerror",
"optional_optional_user",
"password-hash",
@ -2744,10 +2954,20 @@ dependencies = [
"tower-http",
"tracing",
"tracing-subscriber",
"ulid",
"unicode-segmentation",
]
[[package]]
name = "which"
version = "4.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269"
dependencies = [
"either",
"libc",
"once_cell",
]
[[package]]
name = "whoami"
version = "1.4.1"
@ -2770,6 +2990,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"

View file

@ -18,11 +18,13 @@ axum-login = { git = "https://github.com/nebkor/axum-login", branch = "sqlx-0.7"
axum-macros = "0.3"
chrono = { version = "0.4", default-features = false, features = ["std", "clock"] }
clap = { version = "4", features = ["derive", "env", "unicode", "suggestions", "usage"] }
julid-rs = { path = "../julid" }
justerror = "1"
password-hash = { version = "0.5", features = ["std", "getrandom"] }
rand = "0.8"
rand_distr = "0.4"
serde = { version = "1", features = ["derive"] }
sqlx = { version = "0.7", default-features = false, features = ["runtime-tokio-rustls", "sqlite", "chrono", "time"] }
sqlx = { version = "0.7", default-features = false, features = ["runtime-tokio-rustls", "sqlite"] }
thiserror = "1"
tokio = { version = "1", features = ["full", "tracing"], default-features = false }
tokio-retry = "0.3"
@ -31,9 +33,7 @@ tower = { version = "0.4", features = ["util", "timeout"], default-features = fa
tower-http = { version = "0.4", features = ["add-extension", "trace"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
ulid = { version = "1", features = ["rand"] }
unicode-segmentation = "1"
rand_distr = "0.4"
[dev-dependencies]
axum-test = "9"

View file

@ -5,7 +5,7 @@
-- users
create table if not exists users (
id blob not null primary key,
id blob not null primary key default (julid_new()),
username text not null unique,
displayname text,
email text,
@ -16,7 +16,7 @@ create table if not exists users (
-- table of things to watch
create table if not exists watches (
id blob not null primary key,
id blob not null primary key default (julid_new()),
kind int not null, -- enum for movie or tv show or whatev
title text not null,
metadata_url text, -- possible url for imdb or other metadata-esque site to show the user
@ -52,7 +52,7 @@ create table if not exists follows (
);
create table if not exists watch_notes (
id blob not null primary key, -- a user can have multiple notes about the same thing
id blob not null primary key default (julid_new()), -- a user can have multiple notes about the same thing
user blob not null,
watch blob not null,
note blob,

View file

@ -12,7 +12,7 @@ use sqlx::{
SqlitePool,
};
use crate::{db_id::DbId, User};
use crate::{DbId, User};
const MAX_CONNS: u32 = 200;
const MIN_CONNS: u32 = 5;
@ -49,6 +49,9 @@ pub fn get_db_pool() -> SqlitePool {
.journal_mode(SqliteJournalMode::Wal)
.synchronous(sqlx::sqlite::SqliteSynchronous::Normal)
.filename(&db_filename)
// need to build this out of band and put it in the project root; see instructions at
// https://gitlab.com/nebkor/julid
.extension("./libjulid")
.busy_timeout(Duration::from_secs(TIMEOUT))
.create_if_missing(true);

View file

@ -1,214 +0,0 @@
use std::{
borrow::Cow,
fmt::{Debug, Display},
};
use chrono::Utc;
use serde::{de::Visitor, Deserialize, Serialize};
use sqlx::{
encode::IsNull,
sqlite::{SqliteArgumentValue, SqliteValueRef},
Decode, Encode, Sqlite,
};
use ulid::Ulid;
#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DbId(pub Ulid);
impl DbId {
pub fn bytes(&self) -> [u8; 16] {
self.to_be_bytes()
}
pub fn to_be_bytes(self) -> [u8; 16] {
self.0 .0.to_be_bytes()
}
pub fn is_nil(&self) -> bool {
self.0.is_nil()
}
pub fn new() -> Self {
Self(Ulid::new())
}
pub fn from_string(s: &str) -> Result<Self, ulid::DecodeError> {
let id = Ulid::from_string(s)?;
Ok(id.into())
}
pub fn as_string(&self) -> String {
self.0.to_string()
}
pub fn created_at(&self) -> chrono::DateTime<Utc> {
self.0.datetime().into()
}
}
//-************************************************************************
// standard trait impls
//-************************************************************************
impl Display for DbId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0.to_string())
}
}
impl Debug for DbId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("DbId").field(&self.as_string()).finish()
}
}
impl From<Ulid> for DbId {
fn from(value: Ulid) -> Self {
DbId(value)
}
}
impl From<u128> for DbId {
fn from(value: u128) -> Self {
DbId(value.into())
}
}
//-************************************************************************
// sqlx traits for going in and out of the db
//-************************************************************************
impl sqlx::Type<sqlx::Sqlite> for DbId {
fn type_info() -> <sqlx::Sqlite as sqlx::Database>::TypeInfo {
<&[u8] as sqlx::Type<sqlx::Sqlite>>::type_info()
}
}
impl<'q> Encode<'q, Sqlite> for DbId {
fn encode_by_ref(&self, args: &mut Vec<SqliteArgumentValue<'q>>) -> IsNull {
args.push(SqliteArgumentValue::Blob(Cow::Owned(self.bytes().to_vec())));
IsNull::No
}
}
impl Decode<'_, Sqlite> for DbId {
fn decode(value: SqliteValueRef<'_>) -> Result<Self, sqlx::error::BoxDynError> {
let bytes = <&[u8] as Decode<Sqlite>>::decode(value)?;
let bytes: [u8; 16] = bytes.try_into().unwrap_or_default();
Ok(u128::from_be_bytes(bytes).into())
}
}
//-************************************************************************
// serde traits
//-************************************************************************
impl Serialize for DbId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_bytes(&self.bytes())
}
}
struct DbIdVisitor;
impl<'de> Visitor<'de> for DbIdVisitor {
type Value = DbId;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("16 bytes")
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
match std::convert::TryInto::<[u8; 16]>::try_into(v) {
Ok(v) => Ok(u128::from_be_bytes(v).into()),
Err(_) => Err(serde::de::Error::invalid_length(v.len(), &self)),
}
}
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
DbId::from_string(&v)
.map_err(|_| serde::de::Error::invalid_value(serde::de::Unexpected::Str(&v), &self))
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
DbId::from_string(v)
.map_err(|_| serde::de::Error::invalid_value(serde::de::Unexpected::Str(v), &self))
}
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
let len = v.len();
match std::convert::TryInto::<[u8; 16]>::try_into(v) {
Ok(v) => Ok(u128::from_be_bytes(v).into()),
Err(_) => Err(serde::de::Error::invalid_length(len, &self)),
}
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: serde::de::SeqAccess<'de>,
{
let mut raw_bytes_from_db = [0u8; 16];
let size = seq.size_hint().unwrap_or(0);
let mut count = 0;
while let Some(val) = seq.next_element()? {
if count > 15 {
break;
}
raw_bytes_from_db[count] = val;
count += 1;
}
if count != 16 || size > 16 {
let sz = if count < 16 { count } else { size };
Err(serde::de::Error::invalid_length(sz, &self))
} else {
Ok(u128::from_be_bytes(raw_bytes_from_db).into())
}
}
}
impl<'de> Deserialize<'de> for DbId {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_bytes(DbIdVisitor)
}
}
//-************************************************************************
// serialization tests
//-************************************************************************
#[cfg(test)]
mod test {
use serde_test::{assert_tokens, Token};
use super::*;
#[test]
fn test_ser_de() {
let bytes: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
let id: DbId = u128::from_be_bytes(bytes).into();
assert_tokens(
&id,
&[Token::Bytes(&[
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
])],
);
}
}

View file

@ -1,6 +1,6 @@
use sqlx::{query_scalar, SqlitePool};
use crate::{db_id::DbId, util::year_to_epoch, ShowKind, User, Watch, WatchQuest};
use crate::{util::year_to_epoch, DbId, ShowKind, User, Watch, WatchQuest};
const USER_EXISTS_QUERY: &str = "select count(*) from users where id = $1";

View file

@ -9,7 +9,6 @@ pub mod test_utils;
/// Some public interfaces for interacting with the database outside of the web
/// app
pub use db::get_db_pool;
pub use db_id::DbId;
pub mod import_utils;
pub use users::User;
pub use watches::{ShowKind, Watch, WatchQuest};
@ -18,7 +17,6 @@ pub type WWRouter = axum::Router<SqlitePool>;
// everything else is private to the crate
mod db;
mod db_id;
mod generic_handlers;
mod login;
mod signup;
@ -32,6 +30,7 @@ use optional_optional_user::OptionalOptionalUser;
use templates::*;
use watches::templates::*;
pub type DbId = julid::Julid;
type AuthContext = axum_login::extractors::AuthContext<DbId, User, axum_login::SqliteStore<User>>;
/// Returns the router to be used as a service or test object, you do you.

View file

@ -110,7 +110,7 @@ pub async fn post_create_user(
let id = DbId::new();
let user = create_user(username, &displayname, &email, password, &pool, id).await?;
let now = user.id.created_at();
let now = user.id.timestamp();
tracing::debug!("created {user:?} at {now:?}");
let id = user.id.as_string();
let location = format!("/signup_success/{id}");
@ -137,7 +137,7 @@ pub async fn get_signup_success(
let mut resp = SignupSuccessPage(user.clone()).into_response();
if user.username.is_empty() || id.is_nil() {
if user.username.is_empty() || id.is_alpha() {
// redirect to front page if we got here without a valid user ID
*resp.status_mut() = StatusCode::SEE_OTHER;
resp.headers_mut().insert("Location", "/".parse().unwrap());
@ -267,7 +267,8 @@ mod test {
let server = server_with_pool(&pool).await;
let user = get_test_user();
let id = user.id.0.to_string();
let id = user.id.to_string();
dbg!(&id);
let path = format!("/signup_success/{id}");

View file

@ -8,9 +8,8 @@ use sqlx::{query, query_as, SqlitePool};
use super::templates::{AddNewWatchPage, GetWatchPage, SearchWatchesPage};
use crate::{
db_id::DbId,
util::{empty_string_as_none, year_to_epoch},
AuthContext, MyWatchesPage, ShowKind, Watch, WatchQuest,
AuthContext, DbId, MyWatchesPage, ShowKind, Watch, WatchQuest,
};
//-************************************************************************