pub(crate) mod order_direction;
pub(crate) mod query_builder;
pub use order_direction::Direction;
pub use query_builder::*;
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) struct SqlKeywords;
#[allow(non_upper_case_globals)]
impl SqlKeywords {
pub const Null: &'static str = " IS NULL ";
#[allow(dead_code)]
pub const NotNull: &'static str = " IS NOT NULL ";
pub const Eq: &'static str = " = ";
pub const Not: &'static str = " != ";
pub const Gt: &'static str = " > ";
pub const Gte: &'static str = " >= ";
pub const Lt: &'static str = " < ";
pub const Lte: &'static str = " <= ";
pub const In: &'static str = " IN ( ";
pub const NotIn: &'static str = " NOT IN ( ";
pub const Contains: &'static str = " LIKE ";
pub const ContainsNoCase: &'static str = " ILIKE ";
pub const NotContains: &'static str = " NOT LIKE ";
pub const NotContainsNoCase: &'static str = " NOT ILIKE ";
pub const StartsWith: &'static str = " LIKE ";
pub const StartsWithNoCase: &'static str = " ILIKE ";
pub const NotStartsWith: &'static str = " NOT LIKE ";
pub const NotStartsWithNoCase: &'static str = " NOT ILIKE ";
pub const EndsWith: &'static str = " LIKE ";
pub const EndsWithNoCase: &'static str = " ILIKE ";
pub const NotEndsWith: &'static str = " NOT LIKE ";
pub const NotEndsWithNoCase: &'static str = " NOT ILIKE ";
}
pub struct PgBindIter<I>(pub I);
impl<'q, T, I> From<I> for PgBindIter<I>
where
T: sqlx::Type<sqlx::Postgres> + sqlx::Encode<'q, sqlx::Postgres> + Send + 'q,
I: Iterator<Item = T> + Clone + Send,
{
fn from(inner: I) -> Self {
Self(inner)
}
}
impl<'q, T, I> PgBindIter<I>
where
I: Iterator<Item = T>,
T: sqlx::Type<sqlx::Postgres> + sqlx::Encode<'q, sqlx::Postgres> + 'q,
{
fn encode_owned(
iter: I,
buf: &mut sqlx::postgres::PgArgumentBuffer,
) -> Result<sqlx::encode::IsNull, Box<dyn std::error::Error + Send + Sync + 'static>> {
const I32_SIZE: usize = core::mem::size_of::<i32>();
let mut iter = iter.peekable();
let first = iter.peek();
let type_info = first
.and_then(sqlx::Encode::produces)
.unwrap_or_else(T::type_info);
buf.extend(&1_i32.to_be_bytes()); buf.extend(&0_i32.to_be_bytes());
match type_info.oid() {
Some(oid) => buf.extend(oid.0.to_be_bytes()),
None => return Err("Unable to implement encode for custom type".into()), }
let len_start = buf.len();
buf.extend(0_i32.to_be_bytes()); buf.extend(1_i32.to_be_bytes());
let mut encode = |value: T| -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
let offset = buf.len();
buf.extend([0; I32_SIZE]);
let len = if let sqlx::encode::IsNull::No = value.encode(buf)? {
(buf.len() - offset - I32_SIZE) as i32
} else {
debug_assert_eq!(buf.len(), offset + I32_SIZE);
-1_i32
};
buf[offset..(offset + I32_SIZE)].copy_from_slice(&len.to_be_bytes());
Ok(())
};
let mut count = 0_i32;
for value in iter {
encode(value)?;
match count.checked_add(1) {
Some(i) => count = i,
None => {
return Err(
format!(
"Overflowed max array size while encoding {type_info} ({})",
std::any::type_name::<T>()
)
.into(),
);
}
}
}
buf[len_start..(len_start + I32_SIZE)].copy_from_slice(&count.to_be_bytes());
Ok(sqlx::encode::IsNull::No)
}
}
impl<'q, T, I> sqlx::Encode<'q, sqlx::Postgres> for PgBindIter<I>
where
T: sqlx::Type<sqlx::Postgres> + sqlx::Encode<'q, sqlx::Postgres> + Send + 'q,
I: Iterator<Item = T> + Clone + Send,
{
fn encode_by_ref(
&self,
buf: &mut sqlx::postgres::PgArgumentBuffer,
) -> Result<sqlx::encode::IsNull, Box<dyn std::error::Error + Send + Sync + 'static>> {
Self::encode_owned(self.0.clone(), buf)
}
fn encode(
self,
buf: &mut <sqlx::Postgres as sqlx::database::Database>::ArgumentBuffer<'q>,
) -> Result<sqlx::encode::IsNull, Box<dyn std::error::Error + Send + Sync + 'static>>
where
Self: Sized,
{
Self::encode_owned(self.0, buf)
}
}
impl<T, I> sqlx::Type<sqlx::Postgres> for PgBindIter<I>
where
T: sqlx::Type<sqlx::Postgres> + sqlx::postgres::PgHasArrayType,
I: Iterator<Item = T>,
{
fn type_info() -> <sqlx::Postgres as sqlx::Database>::TypeInfo {
<&[T] as sqlx::Type<sqlx::Postgres>>::type_info()
}
fn compatible(ty: &sqlx::postgres::PgTypeInfo) -> bool {
<&[T] as sqlx::Type<sqlx::Postgres>>::compatible(ty)
}
}