sqlx-oldapi 0.6.53

🧰 The Rust SQL Toolkit. An async, pure Rust SQL crate featuring compile-time checked queries without a DSL. Supports PostgreSQL, MySQL, SQLite, MSSQL, and ODBC.
Documentation
#![allow(clippy::approx_constant)]
use sqlx_oldapi::odbc::Odbc;
use sqlx_test::{test_decode_type, test_type};

// Basic null test
test_type!(null<Option<i32>>(Odbc,
    "CAST(NULL AS INTEGER)" == None::<i32>
));

// Boolean type
test_type!(bool(Odbc, "1" == true, "0" == false));

// Signed integer types
test_type!(i8(
    Odbc,
    "5" == 5_i8,
    "0" == 0_i8,
    "-1" == -1_i8,
    "127" == 127_i8,
    "-128" == -128_i8
));

test_type!(i16(
    Odbc,
    "21415" == 21415_i16,
    "-2144" == -2144_i16,
    "0" == 0_i16,
    "32767" == 32767_i16,
    "-32768" == -32768_i16
));

test_type!(i32(
    Odbc,
    "94101" == 94101_i32,
    "-5101" == -5101_i32,
    "0" == 0_i32,
    "2147483647" == 2147483647_i32,
    "-2147483648" == -2147483648_i32
));

test_type!(i64(
    Odbc,
    "9358295312" == 9358295312_i64,
    "-9223372036854775808" == -9223372036854775808_i64,
    "0" == 0_i64,
    "9223372036854775807" == 9223372036854775807_i64
));

// Unsigned integer types
test_type!(u8(Odbc, "255" == 255_u8, "0" == 0_u8, "127" == 127_u8));

test_type!(u16(
    Odbc,
    "65535" == 65535_u16,
    "0" == 0_u16,
    "32767" == 32767_u16
));

test_type!(u32(
    Odbc,
    "4294967295" == 4294967295_u32,
    "0" == 0_u32,
    "2147483647" == 2147483647_u32
));

test_type!(u64(
    Odbc,
    "9223372036854775807" == 9223372036854775807_u64,
    "0" == 0_u64,
    "4294967295" == 4294967295_u64
));

// Floating point types
test_type!(f32(
    Odbc,
    "3.125" == 3.125_f32, // Use power-of-2 fractions for exact representation
    "0.0" == 0.0_f32,
    "-2.5" == -2.5_f32
));

test_type!(f64(
    Odbc,
    "123456.75" == 123456.75_f64,
    "16777217.0" == 16777217.0_f64,
    "0.0" == 0.0_f64,
    "-1.25" == -1.25_f64
));

// String types
test_type!(string<String>(Odbc,
    "'hello world'" == "hello world",
    "''" == "",
    "'test'" == "test",
    "'Unicode: 🦀 Rust'" == "Unicode: 🦀 Rust"
));

// Binary data types - decode-only tests due to ODBC driver encoding quirks
// Note: The actual binary type implementations are correct, but ODBC drivers handle binary data differently
// The round-trip encoding converts binary to hex strings, so we test decoding capability instead
test_decode_type!(bytes<Vec<u8>>(Odbc,
    "'hello'" == "hello".as_bytes().to_vec(),
    "''" == b"".to_vec(),
    "'test'" == b"test".to_vec()
));

// Test [u8] slice decoding (can only decode, not encode slices directly)
#[cfg(test)]
mod slice_tests {
    use super::*;
    use sqlx_test::test_decode_type;

    // These tests validate that the [u8] slice type implementation works
    test_decode_type!(byte_slice<&[u8]>(Odbc,
        "'hello'" == b"hello" as &[u8],
        "'test'" == b"test" as &[u8],
        "''" == b"" as &[u8]
    ));

    test_decode_type!(str_slice<&str>(Odbc,
        "'Unicode: 🦀 Rust ❯❯'" == "Unicode: 🦀 Rust ❯❯" as &str,
        "'test'" == "test" as &str,
        "''" == "" as &str
    ));
}

// Feature-gated types
#[cfg(feature = "uuid")]
mod uuid_tests {
    use super::*;

    test_type!(uuid<sqlx_oldapi::types::Uuid>(Odbc,
    "'550e8400-e29b-41d4-a716-446655440000'" == sqlx_oldapi::types::Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap(),
        "'00000000-0000-0000-0000-000000000000'" == sqlx_oldapi::types::Uuid::nil()
    ));
}

#[cfg(feature = "json")]
mod json_tests {
    use super::*;
    use serde_json::{json, Value as JsonValue};

    test_type!(json<JsonValue>(Odbc,
        "'{\"name\":\"test\",\"value\":42}'" == json!({"name": "test", "value": 42}),
        "'\"hello\"'" == json!("hello"),
        "'[1,2,3]'" == json!([1, 2, 3]),
        "'null'" == json!(null)
    ));
}

#[cfg(feature = "bigdecimal")]
test_type!(bigdecimal<sqlx_oldapi::types::BigDecimal>(Odbc,
    "'123.456789'" == "123.456789".parse::<sqlx_oldapi::types::BigDecimal>().unwrap(),
    "'0'" == "0".parse::<sqlx_oldapi::types::BigDecimal>().unwrap(),
    "'999999.999999'" == "999999.999999".parse::<sqlx_oldapi::types::BigDecimal>().unwrap(),
    "'-123.456'" == "-123.456".parse::<sqlx_oldapi::types::BigDecimal>().unwrap()
));

#[cfg(feature = "decimal")]
test_type!(decimal<sqlx_oldapi::types::Decimal>(Odbc,
    "'123.456789'" == "123.456789".parse::<sqlx_oldapi::types::Decimal>().unwrap(),
    "'0'" == "0".parse::<sqlx_oldapi::types::Decimal>().unwrap(),
    "'999.123'" == "999.123".parse::<sqlx_oldapi::types::Decimal>().unwrap(),
    "'-456.789'" == "-456.789".parse::<sqlx_oldapi::types::Decimal>().unwrap()
));

#[cfg(feature = "chrono")]
mod chrono_tests {
    use super::*;
    use sqlx_oldapi::types::chrono::{
        DateTime, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime, Utc,
    };

    test_type!(chrono_date<NaiveDate>(Odbc,
        "'2023-12-25'" == NaiveDate::from_ymd_opt(2023, 12, 25).unwrap(),
        "'2001-01-05'" == NaiveDate::from_ymd_opt(2001, 1, 5).unwrap(),
        "'2050-11-23'" == NaiveDate::from_ymd_opt(2050, 11, 23).unwrap()
    ));

    test_type!(chrono_time<NaiveTime>(Odbc,
        "'14:30:00'" == NaiveTime::from_hms_opt(14, 30, 0).unwrap(),
        "'23:59:59'" == NaiveTime::from_hms_opt(23, 59, 59).unwrap(),
        "'00:00:00'" == NaiveTime::from_hms_opt(0, 0, 0).unwrap()
    ));

    test_decode_type!(chrono_datetime<NaiveDateTime>(Odbc,
        "'2023-12-25T14:30:00'" == NaiveDate::from_ymd_opt(2023, 12, 25).unwrap().and_hms_opt(14, 30, 0).unwrap(),
        "'2019-01-02T05:10:20'" == NaiveDate::from_ymd_opt(2019, 1, 2).unwrap().and_hms_opt(5, 10, 20).unwrap()
    ));

    // Extra chrono decoding edge case (padded timestamp string)
    test_decode_type!(chrono_datetime_padded<NaiveDateTime>(Odbc,
        "'2023-12-25T14:30:00   '" == NaiveDate::from_ymd_opt(2023, 12, 25).unwrap().and_hms_opt(14, 30, 0).unwrap()
    ));

    test_type!(chrono_datetime_utc<DateTime<Utc>>(Odbc,
        "'2023-12-25T14:30:00+00:00'" == DateTime::parse_from_rfc3339("2023-12-25T14:30:00Z").unwrap().with_timezone(&Utc),
        "'2019-01-02T05:10:20+00:00'" == DateTime::parse_from_rfc3339("2019-01-02T05:10:20Z").unwrap().with_timezone(&Utc),
    ));

    test_type!(chrono_datetime_fixed<DateTime<FixedOffset>>(Odbc,
        "'2023-12-25T14:30:00+01:00'" == DateTime::<FixedOffset>::parse_from_rfc3339("2023-12-25T14:30:00+01:00").unwrap()
    ));
}

// TODO: Enable time tests when time crate dependency is properly configured in tests
// #[cfg(feature = "time")]
// mod time_tests {
//     use super::*;
//     use sqlx_test::test_decode_type;
//     use sqlx_oldapi::types::time::{Date, OffsetDateTime, PrimitiveDateTime, Time};
//
//     // Time crate tests would go here - implementation is complete in the main code
//     // but there are test dependency issues to resolve
// }

// Cross-type compatibility tests
test_type!(cross_type_integer_compatibility<i64>(Odbc,
    "127" == 127_i64,
    "32767" == 32767_i64,
    "2147483647" == 2147483647_i64
));

test_type!(cross_type_unsigned_compatibility<u32>(Odbc,
    "255" == 255_u32,
    "65535" == 65535_u32
));

test_type!(cross_type_float_compatibility<f64>(Odbc,
    "3.125" == 3.125_f64,
    "123.75" == 123.75_f64
));