type hardening
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -1288,6 +1288,7 @@ dependencies = [
|
|||||||
"prost-build",
|
"prost-build",
|
||||||
"prost-types",
|
"prost-types",
|
||||||
"rust_decimal",
|
"rust_decimal",
|
||||||
|
"rusty-money",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tantivy",
|
"tantivy",
|
||||||
|
|||||||
@@ -43,6 +43,9 @@ tantivy = "0.26.1"
|
|||||||
# Steel_decimal crate
|
# Steel_decimal crate
|
||||||
rust_decimal = { version = "1.42.0", features = ["maths", "serde"] }
|
rust_decimal = { version = "1.42.0", features = ["maths", "serde"] }
|
||||||
rust_decimal_macros = "1.40.0"
|
rust_decimal_macros = "1.40.0"
|
||||||
|
# One version across the workspace: `&'static iso::Currency` only crosses crate
|
||||||
|
# boundaries if every crate resolves rusty-money to the same instance.
|
||||||
|
rusty-money = "0.5.0"
|
||||||
thiserror = "2.0.18"
|
thiserror = "2.0.18"
|
||||||
regex = "1.12.4"
|
regex = "1.12.4"
|
||||||
|
|
||||||
|
|||||||
2
client
2
client
Submodule client updated: e3b5d57c90...520fb563f4
@@ -7,6 +7,7 @@ license.workspace = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
prost-types = { workspace = true }
|
prost-types = { workspace = true }
|
||||||
rust_decimal = { workspace = true }
|
rust_decimal = { workspace = true }
|
||||||
|
rusty-money = { workspace = true }
|
||||||
|
|
||||||
tonic = "0.14.6"
|
tonic = "0.14.6"
|
||||||
prost = "0.14.4"
|
prost = "0.14.4"
|
||||||
|
|||||||
@@ -131,7 +131,8 @@ message PostTableDataRequest {
|
|||||||
// - BOOLEAN: bool value
|
// - BOOLEAN: bool value
|
||||||
// - TIMESTAMPTZ: ISO 8601/RFC 3339 string (parsed to TIMESTAMPTZ)
|
// - TIMESTAMPTZ: ISO 8601/RFC 3339 string (parsed to TIMESTAMPTZ)
|
||||||
// - INTEGER: number with no fractional part and within i32 range
|
// - INTEGER: number with no fractional part and within i32 range
|
||||||
// - BIGINT: number with no fractional part and within i64 range
|
// - BIGINT: canonical integer string for the full i64 range; a number is
|
||||||
|
// accepted only within protobuf NumberValue's exact integer range
|
||||||
// - NUMERIC(p,s): string representation only; empty string becomes NULL
|
// - NUMERIC(p,s): string representation only; empty string becomes NULL
|
||||||
// (numbers for NUMERIC are rejected to avoid precision loss)
|
// (numbers for NUMERIC are rejected to avoid precision loss)
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
pub mod search;
|
pub mod search;
|
||||||
pub mod decimal;
|
pub mod decimal;
|
||||||
pub mod grpc_error;
|
pub mod grpc_error;
|
||||||
|
pub mod money;
|
||||||
pub mod relationship;
|
pub mod relationship;
|
||||||
pub mod system_column;
|
pub mod system_column;
|
||||||
|
|
||||||
|
|||||||
53
common/src/money.rs
Normal file
53
common/src/money.rs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
// common/src/money.rs
|
||||||
|
//!
|
||||||
|
//! The one canonical currency spelling shared by the client and the server.
|
||||||
|
//!
|
||||||
|
//! A currency code is stored, sent and compared as its canonical uppercase
|
||||||
|
//! ISO-4217 alphabetic code. Both ends resolve it with
|
||||||
|
//! [`require_iso_currency_code`], so the client rejects exactly what the server
|
||||||
|
//! would reject, and each side renders the shared error as its own error type.
|
||||||
|
|
||||||
|
pub use rusty_money::iso;
|
||||||
|
|
||||||
|
/// Resolves a canonical uppercase ISO-4217 alphabetic code to its currency.
|
||||||
|
///
|
||||||
|
/// Rejects anything not already canonical: lowercase (`eur`), surrounding
|
||||||
|
/// whitespace, and any length but three. Normalising here instead would let a
|
||||||
|
/// value be written in one spelling and compared in another.
|
||||||
|
pub fn require_iso_currency_code(currency_code: &str) -> Result<&'static iso::Currency, String> {
|
||||||
|
if currency_code.len() != 3
|
||||||
|
|| !currency_code
|
||||||
|
.chars()
|
||||||
|
.all(|character| character.is_ascii_uppercase())
|
||||||
|
{
|
||||||
|
return Err("Currency must be a canonical uppercase ISO-4217 code".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
iso::find(currency_code).ok_or_else(|| format!("Unknown ISO-4217 currency: {currency_code}"))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn canonical_codes_resolve_to_their_currency() {
|
||||||
|
assert_eq!(require_iso_currency_code("EUR").unwrap(), iso::EUR);
|
||||||
|
assert_eq!(
|
||||||
|
require_iso_currency_code("USD").unwrap().iso_alpha_code,
|
||||||
|
"USD"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn non_canonical_or_unknown_codes_are_rejected() {
|
||||||
|
for currency_code in [
|
||||||
|
"", "E", "EU", "EURO", "eur", "Eur", " EUR", "EUR ", "E R", "E\u{20AC}R", "AAA", "123",
|
||||||
|
] {
|
||||||
|
assert!(
|
||||||
|
require_iso_currency_code(currency_code).is_err(),
|
||||||
|
"unexpectedly accepted {currency_code:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
@@ -27,7 +27,8 @@ pub struct PostTableDataRequest {
|
|||||||
/// * BOOLEAN: bool value
|
/// * BOOLEAN: bool value
|
||||||
/// * TIMESTAMPTZ: ISO 8601/RFC 3339 string (parsed to TIMESTAMPTZ)
|
/// * TIMESTAMPTZ: ISO 8601/RFC 3339 string (parsed to TIMESTAMPTZ)
|
||||||
/// * INTEGER: number with no fractional part and within i32 range
|
/// * INTEGER: number with no fractional part and within i32 range
|
||||||
/// * BIGINT: number with no fractional part and within i64 range
|
/// * BIGINT: canonical integer string for the full i64 range; a number is
|
||||||
|
/// accepted only within protobuf NumberValue's exact integer range
|
||||||
/// * NUMERIC(p,s): string representation only; empty string becomes NULL
|
/// * NUMERIC(p,s): string representation only; empty string becomes NULL
|
||||||
/// (numbers for NUMERIC are rejected to avoid precision loss)
|
/// (numbers for NUMERIC are rejected to avoid precision loss)
|
||||||
///
|
///
|
||||||
|
|||||||
2
server
2
server
Submodule server updated: 412af6ea3f...62be9cbbaf
Submodule tui-canvas updated: 1251d22406...b1761279ff
Submodule tui-pages updated: 29e1e6a42e...46afc191db
Reference in New Issue
Block a user