Skip to content

Commit 958e722

Browse files
committed
jsonb: Introduce JsonDom type and parsing/conversion
1 parent 3d6bd8e commit 958e722

File tree

8 files changed

+605
-15
lines changed

8 files changed

+605
-15
lines changed

README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@ column and protocol type correspondence:
5252
| `mysql_common::Deserialized<T : DeserializeOwned>` | MySql bytes parsed using `serde_json::from_str` |
5353
| `Option<T: FromValue>` | Must be used for nullable columns to avoid errors |
5454
| [`decimal::Decimal`] | MySql int, uint or bytes parsed using `Decimal::from_str`.<br>⚠️ Note that this type doesn't support full range of MySql `DECIMAL` type. |
55-
| [`bigdecimal::BigDecimal`] (v0.2.x) | MySql int, uint, floats or bytes parsed using `BigDecimal::parse_bytes`.<br>⚠️ Note that range of this type is greater than supported by MySql `DECIMAL` type but it'll be serialized anyway. |
56-
| [`bigdecimal::BigDecimal`] (v0.3.x) | MySql int, uint, floats or bytes parsed using `BigDecimal::parse_bytes`.<br>⚠️ Note that range of this type is greater than supported by MySql `DECIMAL` type but it'll be serialized anyway. |
57-
| [`bigdecimal::BigDecimal`] (v0.4.x) | MySql int, uint, floats or bytes parsed using `BigDecimal::parse_bytes`.<br>⚠️ Note that range of this type is greater than supported by MySql `DECIMAL` type but it'll be serialized anyway. |
55+
| [`bigdecimal::BigDecimal`] (v0.2.x) | MySql int, uint, floats or bytes parsed using `BigDecimal::parse_str_bytes`.<br>⚠️ Note that range of this type is greater than supported by MySql `DECIMAL` type but it'll be serialized anyway. |
56+
| [`bigdecimal::BigDecimal`] (v0.3.x) | MySql int, uint, floats or bytes parsed using `BigDecimal::parse_str_bytes`.<br>⚠️ Note that range of this type is greater than supported by MySql `DECIMAL` type but it'll be serialized anyway. |
57+
| [`bigdecimal::BigDecimal`] (v0.4.x) | MySql int, uint, floats or bytes parsed using `BigDecimal::parse_str_bytes`.<br>⚠️ Note that range of this type is greater than supported by MySql `DECIMAL` type but it'll be serialized anyway. |
5858
| `num_bigint::{BigInt, BigUint}` | MySql int, uint or bytes parsed using `_::parse_bytes`.<br>⚠️ Note that range of this type is greater than supported by MySql integer types but it'll be serialized anyway (as decimal bytes string). |
5959

6060
Also crate provides from-row convertion for the following list of types (see `FromRow` trait):
@@ -242,6 +242,9 @@ Supported derivations:
242242
* `#[mysql(rename = "some_name")]` – overrides column name of a field
243243
* `#[mysql(json)]` - column will be interpreted as a JSON string containing
244244
a value of a field type
245+
* `#[mysql(with = path::to::convert_fn)]``convert_fn` will be used to deserialize
246+
a field value (expects a function with a signature that mimics
247+
`TryFrom<Value, Error=FromValueError>``)
245248

246249
#### Example
247250

src/binlog/decimal/mod.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ pub const POWERS_10: [i32; DIG_PER_DEC + 1] = [
4949
///
5050
/// * serialization/deserialization to/from binary format
5151
/// (see `read_bin` and `write_bin` functions);
52-
/// * parsing from decimal string/buffer (see `Decimal::parse_bytes`, `FromStr` impl);
52+
/// * parsing from decimal string/buffer (see `Decimal::parse_str_bytes`, `FromStr` impl);
5353
/// * conversion to decimal string (using `Display`).
5454
///
5555
/// # Notes
@@ -58,7 +58,7 @@ pub const POWERS_10: [i32; DIG_PER_DEC + 1] = [
5858
/// i.e. both `rhs` and `lhs` will be serialized into temporary buffers;
5959
/// * even though MySql's `string2decimal` function allows scientific notation,
6060
/// this implementation denies it.
61-
#[derive(Default, Debug, Eq)]
61+
#[derive(Default, Debug, Eq, Clone)]
6262
pub struct Decimal {
6363
/// The number of *decimal* digits (NOT number of `Digit`s!) before the point.
6464
intg: usize,
@@ -75,13 +75,23 @@ impl Decimal {
7575
decimal_bin_size(self.intg + self.frac, self.frac)
7676
}
7777

78+
/// See [`Decimal::parse_str_bytes`].
79+
#[deprecated = "use parse_str_bytes"]
7880
pub fn parse_bytes(bytes: &[u8]) -> Result<Self, ParseDecimalError> {
7981
match std::str::from_utf8(bytes) {
8082
Ok(string) => Decimal::from_str(string),
8183
Err(_) => Err(ParseDecimalError),
8284
}
8385
}
8486

87+
/// Runs `Decimal::from_str` on the given bytes. Errors if not UTF-8 or not a decimal string.
88+
pub fn parse_str_bytes(bytes: &[u8]) -> Result<Self, ParseDecimalError> {
89+
match std::str::from_utf8(bytes) {
90+
Ok(string) => Decimal::from_str(string),
91+
Err(_) => Err(ParseDecimalError),
92+
}
93+
}
94+
8595
pub fn write_bin<T: Write>(&self, mut output: T) -> io::Result<()> {
8696
// result bits must be inverted if the sign is negative,
8797
// we'll XOR it with `mask` to achieve this.
@@ -139,6 +149,27 @@ impl Decimal {
139149
output.write_all(&out_buf)
140150
}
141151

152+
/// Reads packed representation of a [`Decimal`].
153+
///
154+
/// Packed representation is:
155+
///
156+
/// 1. precision (u8)
157+
/// 2. scale (u8)
158+
/// 3. serialized decimal value (see [`Decimal::read_bin`])
159+
pub fn read_packed<T: Read>(mut input: T, keep_precision: bool) -> io::Result<Self> {
160+
let mut precision_and_scale = [0_u8, 0_u8];
161+
input.read_exact(&mut precision_and_scale)?;
162+
Self::read_bin(
163+
input,
164+
precision_and_scale[0] as usize,
165+
precision_and_scale[1] as usize,
166+
keep_precision,
167+
)
168+
}
169+
170+
/// Reads serialized representation of a decimal value.
171+
///
172+
/// The value is usually written in the packed form (see [`Decimal::read_packed`]).
142173
pub fn read_bin<T: Read>(
143174
mut input: T,
144175
precision: usize,

src/binlog/decimal/test/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ proptest! {
135135
let num = dbg!(&num);
136136

137137
// test string2decimal
138-
let dec = dbg!(super::Decimal::parse_bytes(num.as_bytes()).unwrap());
138+
let dec = dbg!(super::Decimal::parse_str_bytes(num.as_bytes()).unwrap());
139139
let mysql_dec = dbg!(decimal_t::rust_string2decimal(num).unwrap());
140140
assert_eq!(dec.intg, mysql_dec.intg as usize);
141141
assert_eq!(dec.frac, mysql_dec.frac as usize);

0 commit comments

Comments
 (0)