zed/crates/sqlez/src/bindable.rs

427 lines
12 KiB
Rust
Raw Normal View History

use std::{
2022-11-04 17:34:28 +00:00
ffi::OsStr,
os::unix::prelude::OsStrExt,
path::{Path, PathBuf},
sync::Arc,
};
use anyhow::{Context, Result};
2022-11-01 20:32:46 +00:00
use crate::statement::{SqlType, Statement};
2023-01-23 04:33:21 +00:00
pub trait StaticColumnCount {
fn column_count() -> usize {
2023-01-20 20:15:21 +00:00
1
}
}
2023-01-23 04:33:21 +00:00
pub trait Bind {
2022-11-01 20:32:46 +00:00
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32>;
}
2023-01-23 04:33:21 +00:00
pub trait Column: Sized {
2022-11-01 20:32:46 +00:00
fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)>;
}
2023-01-23 04:33:21 +00:00
impl StaticColumnCount for bool {}
impl Bind for bool {
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
statement
.bind(self.then_some(1).unwrap_or(0), start_index)
.with_context(|| format!("Failed to bind bool at index {start_index}"))
}
}
impl Column for bool {
fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
i32::column(statement, start_index)
.map(|(i, next_index)| (i != 0, next_index))
.with_context(|| format!("Failed to read bool at index {start_index}"))
}
}
2023-01-23 04:33:21 +00:00
impl StaticColumnCount for &[u8] {}
2022-11-01 20:32:46 +00:00
impl Bind for &[u8] {
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
statement
.bind_blob(start_index, self)
.with_context(|| format!("Failed to bind &[u8] at index {start_index}"))?;
2022-11-01 20:32:46 +00:00
Ok(start_index + 1)
}
}
2023-01-23 04:33:21 +00:00
impl<const C: usize> StaticColumnCount for &[u8; C] {}
impl<const C: usize> Bind for &[u8; C] {
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
statement
.bind_blob(start_index, self.as_slice())
.with_context(|| format!("Failed to bind &[u8; C] at index {start_index}"))?;
Ok(start_index + 1)
}
}
2023-01-25 19:30:03 +00:00
impl<const C: usize> Column for [u8; C] {
fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
let bytes_slice = statement.column_blob(start_index)?;
let array = bytes_slice.try_into()?;
Ok((array, start_index + 1))
}
}
2023-01-23 04:33:21 +00:00
impl StaticColumnCount for Vec<u8> {}
2022-11-01 20:32:46 +00:00
impl Bind for Vec<u8> {
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
statement
.bind_blob(start_index, self)
.with_context(|| format!("Failed to bind Vec<u8> at index {start_index}"))?;
2022-11-01 20:32:46 +00:00
Ok(start_index + 1)
}
}
impl Column for Vec<u8> {
fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
let result = statement
.column_blob(start_index)
.with_context(|| format!("Failed to read Vec<u8> at index {start_index}"))?;
2022-11-01 20:32:46 +00:00
Ok((Vec::from(result), start_index + 1))
}
}
2023-01-23 04:33:21 +00:00
impl StaticColumnCount for f64 {}
2022-11-01 20:32:46 +00:00
impl Bind for f64 {
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
statement
.bind_double(start_index, *self)
.with_context(|| format!("Failed to bind f64 at index {start_index}"))?;
2022-11-01 20:32:46 +00:00
Ok(start_index + 1)
}
}
impl Column for f64 {
fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
let result = statement
.column_double(start_index)
.with_context(|| format!("Failed to parse f64 at index {start_index}"))?;
2022-11-01 20:32:46 +00:00
Ok((result, start_index + 1))
}
}
2023-01-23 04:33:21 +00:00
impl StaticColumnCount for f32 {}
impl Bind for f32 {
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
statement
.bind_double(start_index, *self as f64)
.with_context(|| format!("Failed to bind f64 at index {start_index}"))?;
Ok(start_index + 1)
}
}
impl Column for f32 {
fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
let result = statement
.column_double(start_index)
.with_context(|| format!("Failed to parse f32 at index {start_index}"))?
as f32;
Ok((result, start_index + 1))
}
}
2023-01-23 04:33:21 +00:00
impl StaticColumnCount for i32 {}
2022-11-01 20:32:46 +00:00
impl Bind for i32 {
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
statement
.bind_int(start_index, *self)
.with_context(|| format!("Failed to bind i32 at index {start_index}"))?;
2022-11-01 20:32:46 +00:00
Ok(start_index + 1)
}
}
impl Column for i32 {
fn column<'a>(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
let result = statement.column_int(start_index)?;
Ok((result, start_index + 1))
}
}
2023-01-23 04:33:21 +00:00
impl StaticColumnCount for i64 {}
2022-11-01 20:32:46 +00:00
impl Bind for i64 {
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
statement
.bind_int64(start_index, *self)
.with_context(|| format!("Failed to bind i64 at index {start_index}"))?;
2022-11-01 20:32:46 +00:00
Ok(start_index + 1)
}
}
impl Column for i64 {
fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
let result = statement.column_int64(start_index)?;
Ok((result, start_index + 1))
}
}
2023-01-23 04:33:21 +00:00
impl StaticColumnCount for u32 {}
impl Bind for u32 {
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
(*self as i64)
.bind(statement, start_index)
.with_context(|| format!("Failed to bind usize at index {start_index}"))
}
}
impl Column for u32 {
fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
let result = statement.column_int64(start_index)?;
Ok((result as u32, start_index + 1))
}
}
2023-01-23 04:33:21 +00:00
impl StaticColumnCount for usize {}
2022-11-01 20:32:46 +00:00
impl Bind for usize {
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
(*self as i64)
.bind(statement, start_index)
.with_context(|| format!("Failed to bind usize at index {start_index}"))
2022-11-01 20:32:46 +00:00
}
}
impl Column for usize {
fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
let result = statement.column_int64(start_index)?;
Ok((result as usize, start_index + 1))
}
}
2023-01-23 04:33:21 +00:00
impl StaticColumnCount for &str {}
2022-11-01 20:32:46 +00:00
impl Bind for &str {
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
statement.bind_text(start_index, self)?;
Ok(start_index + 1)
}
}
2023-01-23 04:33:21 +00:00
impl StaticColumnCount for Arc<str> {}
impl Bind for Arc<str> {
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
statement.bind_text(start_index, self.as_ref())?;
Ok(start_index + 1)
}
}
2023-01-23 04:33:21 +00:00
impl StaticColumnCount for String {}
2022-11-01 20:32:46 +00:00
impl Bind for String {
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
statement.bind_text(start_index, self)?;
Ok(start_index + 1)
}
}
impl Column for Arc<str> {
fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
let result = statement.column_text(start_index)?;
Ok((Arc::from(result), start_index + 1))
}
}
2022-11-01 20:32:46 +00:00
impl Column for String {
fn column<'a>(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
let result = statement.column_text(start_index)?;
Ok((result.to_owned(), start_index + 1))
}
}
2023-01-23 04:33:21 +00:00
impl<T: StaticColumnCount> StaticColumnCount for Option<T> {
fn column_count() -> usize {
T::column_count()
2023-01-20 20:15:21 +00:00
}
}
2023-01-23 04:33:21 +00:00
impl<T: Bind + StaticColumnCount> Bind for Option<T> {
2023-01-20 20:15:21 +00:00
fn bind(&self, statement: &Statement, mut start_index: i32) -> Result<i32> {
2022-11-01 20:32:46 +00:00
if let Some(this) = self {
this.bind(statement, start_index)
} else {
2023-01-25 19:30:03 +00:00
for _ in 0..T::column_count() {
2023-01-20 20:15:21 +00:00
statement.bind_null(start_index)?;
start_index += 1;
}
Ok(start_index)
2022-11-01 20:32:46 +00:00
}
}
}
2023-01-23 04:33:21 +00:00
impl<T: Column + StaticColumnCount> Column for Option<T> {
2022-11-01 20:32:46 +00:00
fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
if let SqlType::Null = statement.column_type(start_index)? {
2023-01-23 04:33:21 +00:00
Ok((None, start_index + T::column_count() as i32))
2022-11-01 20:32:46 +00:00
} else {
T::column(statement, start_index).map(|(result, next_index)| (Some(result), next_index))
}
}
}
2023-01-23 04:33:21 +00:00
impl<T: StaticColumnCount, const COUNT: usize> StaticColumnCount for [T; COUNT] {
fn column_count() -> usize {
T::column_count() * COUNT
2023-01-20 20:15:21 +00:00
}
}
2023-01-23 04:33:21 +00:00
impl<T: Bind, const COUNT: usize> Bind for [T; COUNT] {
2022-11-01 20:32:46 +00:00
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
let mut current_index = start_index;
for binding in self {
current_index = binding.bind(statement, current_index)?
}
Ok(current_index)
}
}
2023-01-23 04:33:21 +00:00
impl StaticColumnCount for &Path {}
impl Bind for &Path {
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
self.as_os_str().as_bytes().bind(statement, start_index)
}
}
2023-01-23 04:33:21 +00:00
impl StaticColumnCount for Arc<Path> {}
impl Bind for Arc<Path> {
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
self.as_ref().bind(statement, start_index)
}
}
2023-01-23 04:33:21 +00:00
impl StaticColumnCount for PathBuf {}
impl Bind for PathBuf {
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
(self.as_ref() as &Path).bind(statement, start_index)
}
}
impl Column for PathBuf {
fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
let blob = statement.column_blob(start_index)?;
Ok((
PathBuf::from(OsStr::from_bytes(blob).to_owned()),
start_index + 1,
))
}
}
2023-01-25 19:30:03 +00:00
impl StaticColumnCount for uuid::Uuid {
fn column_count() -> usize {
1
}
}
impl Bind for uuid::Uuid {
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
self.as_bytes().bind(statement, start_index)
}
}
impl Column for uuid::Uuid {
fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
let (bytes, next_index) = Column::column(statement, start_index)?;
Ok((uuid::Uuid::from_bytes(bytes), next_index))
}
}
2023-01-23 04:33:21 +00:00
impl StaticColumnCount for () {
fn column_count() -> usize {
2023-01-20 20:15:21 +00:00
0
}
}
/// Unit impls do nothing. This simplifies query macros
impl Bind for () {
fn bind(&self, _statement: &Statement, start_index: i32) -> Result<i32> {
Ok(start_index)
}
}
impl Column for () {
fn column(_statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
Ok(((), start_index))
}
}
2023-01-20 20:15:21 +00:00
macro_rules! impl_tuple_row_traits {
( $($local:ident: $type:ident),+ ) => {
2023-01-23 04:33:21 +00:00
impl<$($type: StaticColumnCount),+> StaticColumnCount for ($($type,)+) {
fn column_count() -> usize {
2023-01-20 20:15:21 +00:00
let mut count = 0;
2023-01-23 04:33:21 +00:00
$(count += $type::column_count();)+
2023-01-20 20:15:21 +00:00
count
}
}
2023-01-20 20:15:21 +00:00
impl<$($type: Bind),+> Bind for ($($type,)+) {
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
let mut next_index = start_index;
let ($($local,)+) = self;
$(next_index = $local.bind(statement, next_index)?;)+
Ok(next_index)
}
}
2023-01-20 20:15:21 +00:00
impl<$($type: Column),+> Column for ($($type,)+) {
fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
let mut next_index = start_index;
Ok((
(
$({
let value;
(value, next_index) = $type::column(statement, next_index)?;
value
},)+
),
next_index,
))
}
}
}
}
2023-01-20 20:15:21 +00:00
impl_tuple_row_traits!(t1: T1, t2: T2);
impl_tuple_row_traits!(t1: T1, t2: T2, t3: T3);
impl_tuple_row_traits!(t1: T1, t2: T2, t3: T3, t4: T4);
impl_tuple_row_traits!(t1: T1, t2: T2, t3: T3, t4: T4, t5: T5);
impl_tuple_row_traits!(t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6);
impl_tuple_row_traits!(t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6, t7: T7);
impl_tuple_row_traits!(
t1: T1,
t2: T2,
t3: T3,
t4: T4,
t5: T5,
t6: T6,
t7: T7,
t8: T8
);
impl_tuple_row_traits!(
t1: T1,
t2: T2,
t3: T3,
t4: T4,
t5: T5,
t6: T6,
t7: T7,
t8: T8,
t9: T9
);
impl_tuple_row_traits!(
t1: T1,
t2: T2,
t3: T3,
t4: T4,
t5: T5,
t6: T6,
t7: T7,
t8: T8,
t9: T9,
t10: T10
);