mirror of
https://github.com/launchbadge/sqlx.git
synced 2026-04-26 09:52:28 +00:00
feat: add ipnet support (#3710)
* feat: add ipnet support * fix: ipnet not decoding IP address strings * fix: prefer ipnetwork to ipnet for compatibility * fix: unnecessary cfg
This commit is contained in:
8
Cargo.lock
generated
8
Cargo.lock
generated
@@ -1939,6 +1939,12 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ipnet"
|
||||
version = "2.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708"
|
||||
|
||||
[[package]]
|
||||
name = "ipnetwork"
|
||||
version = "0.20.0"
|
||||
@@ -3443,6 +3449,7 @@ dependencies = [
|
||||
"hashbrown 0.15.2",
|
||||
"hashlink",
|
||||
"indexmap 2.7.0",
|
||||
"ipnet",
|
||||
"ipnetwork",
|
||||
"log",
|
||||
"mac_address",
|
||||
@@ -3698,6 +3705,7 @@ dependencies = [
|
||||
"hkdf",
|
||||
"hmac",
|
||||
"home",
|
||||
"ipnet",
|
||||
"ipnetwork",
|
||||
"itoa",
|
||||
"log",
|
||||
|
||||
@@ -68,6 +68,7 @@ _unstable-all-types = [
|
||||
"json",
|
||||
"time",
|
||||
"chrono",
|
||||
"ipnet",
|
||||
"ipnetwork",
|
||||
"mac_address",
|
||||
"uuid",
|
||||
@@ -117,6 +118,7 @@ json = ["sqlx-macros?/json", "sqlx-mysql?/json", "sqlx-postgres?/json", "sqlx-sq
|
||||
bigdecimal = ["sqlx-core/bigdecimal", "sqlx-macros?/bigdecimal", "sqlx-mysql?/bigdecimal", "sqlx-postgres?/bigdecimal"]
|
||||
bit-vec = ["sqlx-core/bit-vec", "sqlx-macros?/bit-vec", "sqlx-postgres?/bit-vec"]
|
||||
chrono = ["sqlx-core/chrono", "sqlx-macros?/chrono", "sqlx-mysql?/chrono", "sqlx-postgres?/chrono", "sqlx-sqlite?/chrono"]
|
||||
ipnet = ["sqlx-core/ipnet", "sqlx-macros?/ipnet", "sqlx-postgres?/ipnet"]
|
||||
ipnetwork = ["sqlx-core/ipnetwork", "sqlx-macros?/ipnetwork", "sqlx-postgres?/ipnetwork"]
|
||||
mac_address = ["sqlx-core/mac_address", "sqlx-macros?/mac_address", "sqlx-postgres?/mac_address"]
|
||||
rust_decimal = ["sqlx-core/rust_decimal", "sqlx-macros?/rust_decimal", "sqlx-mysql?/rust_decimal", "sqlx-postgres?/rust_decimal"]
|
||||
@@ -144,6 +146,7 @@ sqlx = { version = "=0.8.3", path = ".", default-features = false }
|
||||
bigdecimal = "0.4.0"
|
||||
bit-vec = "0.6.3"
|
||||
chrono = { version = "0.4.34", default-features = false, features = ["std", "clock"] }
|
||||
ipnet = "2.3.0"
|
||||
ipnetwork = "0.20.0"
|
||||
mac_address = "1.1.5"
|
||||
rust_decimal = { version = "1.26.1", default-features = false, features = ["std"] }
|
||||
|
||||
@@ -220,6 +220,8 @@ be removed in the future.
|
||||
|
||||
- `rust_decimal`: Add support for `NUMERIC` using the `rust_decimal` crate.
|
||||
|
||||
- `ipnet`: Add support for `INET` and `CIDR` (in postgres) using the `ipnet` crate.
|
||||
|
||||
- `ipnetwork`: Add support for `INET` and `CIDR` (in postgres) using the `ipnetwork` crate.
|
||||
|
||||
- `json`: Add support for `JSON` and `JSONB` (in postgres) using the `serde_json` crate.
|
||||
|
||||
@@ -48,6 +48,7 @@ bit-vec = { workspace = true, optional = true }
|
||||
bigdecimal = { workspace = true, optional = true }
|
||||
rust_decimal = { workspace = true, optional = true }
|
||||
time = { workspace = true, optional = true }
|
||||
ipnet = { workspace = true, optional = true }
|
||||
ipnetwork = { workspace = true, optional = true }
|
||||
mac_address = { workspace = true, optional = true }
|
||||
uuid = { workspace = true, optional = true }
|
||||
|
||||
@@ -67,6 +67,13 @@ pub use bigdecimal::BigDecimal;
|
||||
#[doc(no_inline)]
|
||||
pub use rust_decimal::Decimal;
|
||||
|
||||
#[cfg(feature = "ipnet")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "ipnet")))]
|
||||
pub mod ipnet {
|
||||
#[doc(no_inline)]
|
||||
pub use ipnet::{IpNet, Ipv4Net, Ipv6Net};
|
||||
}
|
||||
|
||||
#[cfg(feature = "ipnetwork")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "ipnetwork")))]
|
||||
pub mod ipnetwork {
|
||||
|
||||
@@ -38,6 +38,7 @@ json = ["sqlx-core/json", "sqlx-mysql?/json", "sqlx-postgres?/json", "sqlx-sqlit
|
||||
bigdecimal = ["sqlx-core/bigdecimal", "sqlx-mysql?/bigdecimal", "sqlx-postgres?/bigdecimal"]
|
||||
bit-vec = ["sqlx-core/bit-vec", "sqlx-postgres?/bit-vec"]
|
||||
chrono = ["sqlx-core/chrono", "sqlx-mysql?/chrono", "sqlx-postgres?/chrono", "sqlx-sqlite?/chrono"]
|
||||
ipnet = ["sqlx-core/ipnet", "sqlx-postgres?/ipnet"]
|
||||
ipnetwork = ["sqlx-core/ipnetwork", "sqlx-postgres?/ipnetwork"]
|
||||
mac_address = ["sqlx-core/mac_address", "sqlx-postgres?/mac_address"]
|
||||
rust_decimal = ["sqlx-core/rust_decimal", "sqlx-mysql?/rust_decimal", "sqlx-postgres?/rust_decimal"]
|
||||
|
||||
@@ -37,6 +37,7 @@ sqlite-unbundled = ["sqlx-macros-core/sqlite-unbundled"]
|
||||
bigdecimal = ["sqlx-macros-core/bigdecimal"]
|
||||
bit-vec = ["sqlx-macros-core/bit-vec"]
|
||||
chrono = ["sqlx-macros-core/chrono"]
|
||||
ipnet = ["sqlx-macros-core/ipnet"]
|
||||
ipnetwork = ["sqlx-macros-core/ipnetwork"]
|
||||
mac_address = ["sqlx-macros-core/mac_address"]
|
||||
rust_decimal = ["sqlx-macros-core/rust_decimal"]
|
||||
|
||||
@@ -19,6 +19,7 @@ offline = ["sqlx-core/offline"]
|
||||
bigdecimal = ["dep:bigdecimal", "dep:num-bigint", "sqlx-core/bigdecimal"]
|
||||
bit-vec = ["dep:bit-vec", "sqlx-core/bit-vec"]
|
||||
chrono = ["dep:chrono", "sqlx-core/chrono"]
|
||||
ipnet = ["dep:ipnet", "sqlx-core/ipnet"]
|
||||
ipnetwork = ["dep:ipnetwork", "sqlx-core/ipnetwork"]
|
||||
mac_address = ["dep:mac_address", "sqlx-core/mac_address"]
|
||||
rust_decimal = ["dep:rust_decimal", "rust_decimal/maths", "sqlx-core/rust_decimal"]
|
||||
@@ -43,6 +44,7 @@ sha2 = { version = "0.10.0", default-features = false }
|
||||
bigdecimal = { workspace = true, optional = true }
|
||||
bit-vec = { workspace = true, optional = true }
|
||||
chrono = { workspace = true, optional = true }
|
||||
ipnet = { workspace = true, optional = true }
|
||||
ipnetwork = { workspace = true, optional = true }
|
||||
mac_address = { workspace = true, optional = true }
|
||||
rust_decimal = { workspace = true, optional = true }
|
||||
|
||||
@@ -88,6 +88,9 @@ impl_type_checking!(
|
||||
#[cfg(feature = "ipnetwork")]
|
||||
sqlx::types::ipnetwork::IpNetwork,
|
||||
|
||||
#[cfg(feature = "ipnet")]
|
||||
sqlx::types::ipnet::IpNet,
|
||||
|
||||
#[cfg(feature = "mac_address")]
|
||||
sqlx::types::mac_address::MacAddress,
|
||||
|
||||
@@ -149,6 +152,9 @@ impl_type_checking!(
|
||||
#[cfg(feature = "ipnetwork")]
|
||||
Vec<sqlx::types::ipnetwork::IpNetwork> | &[sqlx::types::ipnetwork::IpNetwork],
|
||||
|
||||
#[cfg(feature = "ipnet")]
|
||||
Vec<sqlx::types::ipnet::IpNet> | &[sqlx::types::ipnet::IpNet],
|
||||
|
||||
#[cfg(feature = "mac_address")]
|
||||
Vec<sqlx::types::mac_address::MacAddress> | &[sqlx::types::mac_address::MacAddress],
|
||||
|
||||
|
||||
62
sqlx-postgres/src/types/ipnet/ipaddr.rs
Normal file
62
sqlx-postgres/src/types/ipnet/ipaddr.rs
Normal file
@@ -0,0 +1,62 @@
|
||||
use std::net::IpAddr;
|
||||
|
||||
use ipnet::IpNet;
|
||||
|
||||
use crate::decode::Decode;
|
||||
use crate::encode::{Encode, IsNull};
|
||||
use crate::error::BoxDynError;
|
||||
use crate::types::Type;
|
||||
use crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueRef, Postgres};
|
||||
|
||||
impl Type<Postgres> for IpAddr
|
||||
where
|
||||
IpNet: Type<Postgres>,
|
||||
{
|
||||
fn type_info() -> PgTypeInfo {
|
||||
IpNet::type_info()
|
||||
}
|
||||
|
||||
fn compatible(ty: &PgTypeInfo) -> bool {
|
||||
IpNet::compatible(ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl PgHasArrayType for IpAddr {
|
||||
fn array_type_info() -> PgTypeInfo {
|
||||
<IpNet as PgHasArrayType>::array_type_info()
|
||||
}
|
||||
|
||||
fn array_compatible(ty: &PgTypeInfo) -> bool {
|
||||
<IpNet as PgHasArrayType>::array_compatible(ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> Encode<'db, Postgres> for IpAddr
|
||||
where
|
||||
IpNet: Encode<'db, Postgres>,
|
||||
{
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
IpNet::from(*self).encode_by_ref(buf)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> usize {
|
||||
IpNet::from(*self).size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> Decode<'db, Postgres> for IpAddr
|
||||
where
|
||||
IpNet: Decode<'db, Postgres>,
|
||||
{
|
||||
fn decode(value: PgValueRef<'db>) -> Result<Self, BoxDynError> {
|
||||
let ipnet = IpNet::decode(value)?;
|
||||
|
||||
if matches!(ipnet, IpNet::V4(net) if net.prefix_len() != 32)
|
||||
|| matches!(ipnet, IpNet::V6(net) if net.prefix_len() != 128)
|
||||
{
|
||||
Err("lossy decode from inet/cidr")?
|
||||
}
|
||||
|
||||
Ok(ipnet.addr())
|
||||
}
|
||||
}
|
||||
130
sqlx-postgres/src/types/ipnet/ipnet.rs
Normal file
130
sqlx-postgres/src/types/ipnet/ipnet.rs
Normal file
@@ -0,0 +1,130 @@
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
||||
|
||||
#[cfg(feature = "ipnet")]
|
||||
use ipnet::{IpNet, Ipv4Net, Ipv6Net};
|
||||
|
||||
use crate::decode::Decode;
|
||||
use crate::encode::{Encode, IsNull};
|
||||
use crate::error::BoxDynError;
|
||||
use crate::types::Type;
|
||||
use crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
|
||||
|
||||
// https://github.com/postgres/postgres/blob/574925bfd0a8175f6e161936ea11d9695677ba09/src/include/utils/inet.h#L39
|
||||
|
||||
// Technically this is a magic number here but it doesn't make sense to drag in the whole of `libc`
|
||||
// just for one constant.
|
||||
const PGSQL_AF_INET: u8 = 2; // AF_INET
|
||||
const PGSQL_AF_INET6: u8 = PGSQL_AF_INET + 1;
|
||||
|
||||
impl Type<Postgres> for IpNet {
|
||||
fn type_info() -> PgTypeInfo {
|
||||
PgTypeInfo::INET
|
||||
}
|
||||
|
||||
fn compatible(ty: &PgTypeInfo) -> bool {
|
||||
*ty == PgTypeInfo::CIDR || *ty == PgTypeInfo::INET
|
||||
}
|
||||
}
|
||||
|
||||
impl PgHasArrayType for IpNet {
|
||||
fn array_type_info() -> PgTypeInfo {
|
||||
PgTypeInfo::INET_ARRAY
|
||||
}
|
||||
|
||||
fn array_compatible(ty: &PgTypeInfo) -> bool {
|
||||
*ty == PgTypeInfo::CIDR_ARRAY || *ty == PgTypeInfo::INET_ARRAY
|
||||
}
|
||||
}
|
||||
|
||||
impl Encode<'_, Postgres> for IpNet {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
// https://github.com/postgres/postgres/blob/574925bfd0a8175f6e161936ea11d9695677ba09/src/backend/utils/adt/network.c#L293
|
||||
// https://github.com/postgres/postgres/blob/574925bfd0a8175f6e161936ea11d9695677ba09/src/backend/utils/adt/network.c#L271
|
||||
|
||||
match self {
|
||||
IpNet::V4(net) => {
|
||||
buf.push(PGSQL_AF_INET); // ip_family
|
||||
buf.push(net.prefix_len()); // ip_bits
|
||||
buf.push(0); // is_cidr
|
||||
buf.push(4); // nb (number of bytes)
|
||||
buf.extend_from_slice(&net.addr().octets()) // address
|
||||
}
|
||||
|
||||
IpNet::V6(net) => {
|
||||
buf.push(PGSQL_AF_INET6); // ip_family
|
||||
buf.push(net.prefix_len()); // ip_bits
|
||||
buf.push(0); // is_cidr
|
||||
buf.push(16); // nb (number of bytes)
|
||||
buf.extend_from_slice(&net.addr().octets()); // address
|
||||
}
|
||||
}
|
||||
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> usize {
|
||||
match self {
|
||||
IpNet::V4(_) => 8,
|
||||
IpNet::V6(_) => 20,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Decode<'_, Postgres> for IpNet {
|
||||
fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {
|
||||
let bytes = match value.format() {
|
||||
PgValueFormat::Binary => value.as_bytes()?,
|
||||
PgValueFormat::Text => {
|
||||
let s = value.as_str()?;
|
||||
println!("{s}");
|
||||
if s.contains('/') {
|
||||
return Ok(s.parse()?);
|
||||
}
|
||||
// IpNet::from_str doesn't handle conversion from IpAddr to IpNet
|
||||
let addr: IpAddr = s.parse()?;
|
||||
return Ok(addr.into());
|
||||
}
|
||||
};
|
||||
|
||||
if bytes.len() >= 8 {
|
||||
let family = bytes[0];
|
||||
let prefix = bytes[1];
|
||||
let _is_cidr = bytes[2] != 0;
|
||||
let len = bytes[3];
|
||||
|
||||
match family {
|
||||
PGSQL_AF_INET => {
|
||||
if bytes.len() == 8 && len == 4 {
|
||||
let inet = Ipv4Net::new(
|
||||
Ipv4Addr::new(bytes[4], bytes[5], bytes[6], bytes[7]),
|
||||
prefix,
|
||||
)?;
|
||||
|
||||
return Ok(IpNet::V4(inet));
|
||||
}
|
||||
}
|
||||
|
||||
PGSQL_AF_INET6 => {
|
||||
if bytes.len() == 20 && len == 16 {
|
||||
let inet = Ipv6Net::new(
|
||||
Ipv6Addr::from([
|
||||
bytes[4], bytes[5], bytes[6], bytes[7], bytes[8], bytes[9],
|
||||
bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15],
|
||||
bytes[16], bytes[17], bytes[18], bytes[19],
|
||||
]),
|
||||
prefix,
|
||||
)?;
|
||||
|
||||
return Ok(IpNet::V6(inet));
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
return Err(format!("unknown ip family {family}").into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err("invalid data received when expecting an INET".into())
|
||||
}
|
||||
}
|
||||
7
sqlx-postgres/src/types/ipnet/mod.rs
Normal file
7
sqlx-postgres/src/types/ipnet/mod.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
// Prefer `ipnetwork` over `ipnet` because it was implemented first (want to avoid breaking change).
|
||||
#[cfg(not(feature = "ipnetwork"))]
|
||||
mod ipaddr;
|
||||
|
||||
// Parent module is named after the `ipnet` crate, this is named after the `IpNet` type.
|
||||
#[allow(clippy::module_inception)]
|
||||
mod ipnet;
|
||||
5
sqlx-postgres/src/types/ipnetwork/mod.rs
Normal file
5
sqlx-postgres/src/types/ipnetwork/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
mod ipaddr;
|
||||
|
||||
// Parent module is named after the `ipnetwork` crate, this is named after the `IpNetwork` type.
|
||||
#[allow(clippy::module_inception)]
|
||||
mod ipnetwork;
|
||||
@@ -87,7 +87,7 @@
|
||||
//!
|
||||
//! ### [`ipnetwork`](https://crates.io/crates/ipnetwork)
|
||||
//!
|
||||
//! Requires the `ipnetwork` Cargo feature flag.
|
||||
//! Requires the `ipnetwork` Cargo feature flag (takes precedence over `ipnet` if both are used).
|
||||
//!
|
||||
//! | Rust type | Postgres type(s) |
|
||||
//! |---------------------------------------|------------------------------------------------------|
|
||||
@@ -100,6 +100,17 @@
|
||||
//!
|
||||
//! `IpNetwork` does not have this limitation.
|
||||
//!
|
||||
//! ### [`ipnet`](https://crates.io/crates/ipnet)
|
||||
//!
|
||||
//! Requires the `ipnet` Cargo feature flag.
|
||||
//!
|
||||
//! | Rust type | Postgres type(s) |
|
||||
//! |---------------------------------------|------------------------------------------------------|
|
||||
//! | `ipnet::IpNet` | INET, CIDR |
|
||||
//! | `std::net::IpAddr` | INET, CIDR |
|
||||
//!
|
||||
//! The same `IpAddr` limitation for smaller network prefixes applies as with `ipnet`.
|
||||
//!
|
||||
//! ### [`mac_address`](https://crates.io/crates/mac_address)
|
||||
//!
|
||||
//! Requires the `mac_address` Cargo feature flag.
|
||||
@@ -248,11 +259,11 @@ mod time;
|
||||
#[cfg(feature = "uuid")]
|
||||
mod uuid;
|
||||
|
||||
#[cfg(feature = "ipnetwork")]
|
||||
mod ipnetwork;
|
||||
#[cfg(feature = "ipnet")]
|
||||
mod ipnet;
|
||||
|
||||
#[cfg(feature = "ipnetwork")]
|
||||
mod ipaddr;
|
||||
mod ipnetwork;
|
||||
|
||||
#[cfg(feature = "mac_address")]
|
||||
mod mac_address;
|
||||
|
||||
@@ -2,6 +2,7 @@ extern crate time_ as time;
|
||||
|
||||
use std::net::SocketAddr;
|
||||
use std::ops::Bound;
|
||||
use std::str::FromStr;
|
||||
|
||||
use sqlx::postgres::types::{Oid, PgCiText, PgInterval, PgMoney, PgRange};
|
||||
use sqlx::postgres::Postgres;
|
||||
@@ -9,7 +10,6 @@ use sqlx_test::{new, test_decode_type, test_prepared_type, test_type};
|
||||
|
||||
use sqlx_core::executor::Executor;
|
||||
use sqlx_core::types::Text;
|
||||
use std::str::FromStr;
|
||||
|
||||
test_type!(null<Option<i16>>(Postgres,
|
||||
"NULL::int2" == None::<i16>
|
||||
@@ -171,6 +171,38 @@ test_type!(uuid_vec<Vec<sqlx::types::Uuid>>(Postgres,
|
||||
]
|
||||
));
|
||||
|
||||
#[cfg(feature = "ipnet")]
|
||||
test_type!(ipnet<sqlx::types::ipnet::IpNet>(Postgres,
|
||||
"'127.0.0.1'::inet"
|
||||
== "127.0.0.1/32"
|
||||
.parse::<sqlx::types::ipnet::IpNet>()
|
||||
.unwrap(),
|
||||
"'8.8.8.8/24'::inet"
|
||||
== "8.8.8.8/24"
|
||||
.parse::<sqlx::types::ipnet::IpNet>()
|
||||
.unwrap(),
|
||||
"'10.1.1/24'::inet"
|
||||
== "10.1.1.0/24"
|
||||
.parse::<sqlx::types::ipnet::IpNet>()
|
||||
.unwrap(),
|
||||
"'::ffff:1.2.3.0'::inet"
|
||||
== "::ffff:1.2.3.0/128"
|
||||
.parse::<sqlx::types::ipnet::IpNet>()
|
||||
.unwrap(),
|
||||
"'2001:4f8:3:ba::/64'::inet"
|
||||
== "2001:4f8:3:ba::/64"
|
||||
.parse::<sqlx::types::ipnet::IpNet>()
|
||||
.unwrap(),
|
||||
"'192.168'::cidr"
|
||||
== "192.168.0.0/24"
|
||||
.parse::<sqlx::types::ipnet::IpNet>()
|
||||
.unwrap(),
|
||||
"'::ffff:1.2.3.0/120'::cidr"
|
||||
== "::ffff:1.2.3.0/120"
|
||||
.parse::<sqlx::types::ipnet::IpNet>()
|
||||
.unwrap(),
|
||||
));
|
||||
|
||||
#[cfg(feature = "ipnetwork")]
|
||||
test_type!(ipnetwork<sqlx::types::ipnetwork::IpNetwork>(Postgres,
|
||||
"'127.0.0.1'::inet"
|
||||
@@ -232,6 +264,15 @@ test_type!(bitvec<sqlx::types::BitVec>(
|
||||
},
|
||||
));
|
||||
|
||||
#[cfg(feature = "ipnet")]
|
||||
test_type!(ipnet_vec<Vec<sqlx::types::ipnet::IpNet>>(Postgres,
|
||||
"'{127.0.0.1,8.8.8.8/24}'::inet[]"
|
||||
== vec![
|
||||
"127.0.0.1/32".parse::<sqlx::types::ipnet::IpNet>().unwrap(),
|
||||
"8.8.8.8/24".parse::<sqlx::types::ipnet::IpNet>().unwrap()
|
||||
]
|
||||
));
|
||||
|
||||
#[cfg(feature = "ipnetwork")]
|
||||
test_type!(ipnetwork_vec<Vec<sqlx::types::ipnetwork::IpNetwork>>(Postgres,
|
||||
"'{127.0.0.1,8.8.8.8/24}'::inet[]"
|
||||
|
||||
@@ -17,7 +17,7 @@ fn ui_tests() {
|
||||
t.compile_fail("tests/ui/postgres/gated/uuid.rs");
|
||||
}
|
||||
|
||||
if cfg!(not(feature = "ipnetwork")) {
|
||||
if cfg!(not(feature = "ipnet")) && cfg!(not(feature = "ipnetwork")) {
|
||||
t.compile_fail("tests/ui/postgres/gated/ipnetwork.rs");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user