use std::any::Any;
use std::error::Error;
use std::fmt::Display;
use super::return_variant::ReturnsError;
use super::{FunctionMetadataTypeEntity, Returns};
#[derive(Clone, Copy, Debug, Hash, Ord, PartialOrd, PartialEq, Eq)]
pub enum ArgumentError {
SetOf,
Table,
BareU8,
SkipInArray,
Datum,
NotValidAsArgument(&'static str),
}
impl std::fmt::Display for ArgumentError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ArgumentError::SetOf => {
write!(f, "Cannot use SetOfIterator as an argument")
}
ArgumentError::Table => {
write!(f, "Cannot use TableIterator as an argument")
}
ArgumentError::BareU8 => {
write!(f, "Cannot use bare u8")
}
ArgumentError::SkipInArray => {
write!(f, "SqlMapping::Skip inside Array is not valid")
}
ArgumentError::Datum => {
write!(f, "A Datum as an argument means that `sql = \"...\"` must be set in the declaration")
}
ArgumentError::NotValidAsArgument(type_name) => {
write!(f, "`{}` is not able to be used as a function argument", type_name)
}
}
}
}
#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub enum SqlMapping {
As(String),
Composite {
array_brackets: bool,
},
Source {
array_brackets: bool,
},
Skip,
}
impl SqlMapping {
pub fn literal(s: &'static str) -> SqlMapping {
SqlMapping::As(String::from(s))
}
}
impl Error for ArgumentError {}
pub unsafe trait SqlTranslatable {
fn type_name() -> &'static str {
core::any::type_name::<Self>()
}
fn argument_sql() -> Result<SqlMapping, ArgumentError>;
fn return_sql() -> Result<Returns, ReturnsError>;
fn variadic() -> bool {
false
}
fn optional() -> bool {
false
}
fn entity() -> FunctionMetadataTypeEntity {
FunctionMetadataTypeEntity {
type_name: Self::type_name(),
argument_sql: Self::argument_sql(),
return_sql: Self::return_sql(),
variadic: Self::variadic(),
optional: Self::optional(),
}
}
}
unsafe impl<E> SqlTranslatable for Result<(), E>
where
E: Any + Display,
{
fn argument_sql() -> Result<SqlMapping, ArgumentError> {
Err(ArgumentError::NotValidAsArgument("()"))
}
fn return_sql() -> Result<Returns, ReturnsError> {
Ok(Returns::One(SqlMapping::literal("VOID")))
}
}
unsafe impl<T> SqlTranslatable for Option<T>
where
T: SqlTranslatable,
{
fn argument_sql() -> Result<SqlMapping, ArgumentError> {
T::argument_sql()
}
fn return_sql() -> Result<Returns, ReturnsError> {
T::return_sql()
}
fn optional() -> bool {
true
}
}
unsafe impl<T> SqlTranslatable for *mut T
where
T: SqlTranslatable,
{
fn argument_sql() -> Result<SqlMapping, ArgumentError> {
T::argument_sql()
}
fn return_sql() -> Result<Returns, ReturnsError> {
T::return_sql()
}
fn optional() -> bool {
T::optional()
}
}
unsafe impl<T, E> SqlTranslatable for Result<T, E>
where
T: SqlTranslatable,
E: Any + Display,
{
fn argument_sql() -> Result<SqlMapping, ArgumentError> {
T::argument_sql()
}
fn return_sql() -> Result<Returns, ReturnsError> {
T::return_sql()
}
fn optional() -> bool {
true
}
}
unsafe impl<T> SqlTranslatable for Vec<T>
where
T: SqlTranslatable,
{
fn argument_sql() -> Result<SqlMapping, ArgumentError> {
match T::type_name() {
id if id == u8::type_name() => Ok(SqlMapping::As(format!("bytea"))),
_ => match T::argument_sql() {
Ok(SqlMapping::As(val)) => Ok(SqlMapping::As(format!("{val}[]"))),
Ok(SqlMapping::Composite { array_brackets: _ }) => {
Ok(SqlMapping::Composite { array_brackets: true })
}
Ok(SqlMapping::Source { array_brackets: _ }) => {
Ok(SqlMapping::Source { array_brackets: true })
}
Ok(SqlMapping::Skip) => Ok(SqlMapping::Skip),
err @ Err(_) => err,
},
}
}
fn return_sql() -> Result<Returns, ReturnsError> {
match T::type_name() {
id if id == u8::type_name() => Ok(Returns::One(SqlMapping::As(format!("bytea")))),
_ => match T::return_sql() {
Ok(Returns::One(SqlMapping::As(val))) => {
Ok(Returns::One(SqlMapping::As(format!("{val}[]"))))
}
Ok(Returns::One(SqlMapping::Composite { array_brackets: _ })) => {
Ok(Returns::One(SqlMapping::Composite { array_brackets: true }))
}
Ok(Returns::One(SqlMapping::Source { array_brackets: _ })) => {
Ok(Returns::One(SqlMapping::Source { array_brackets: true }))
}
Ok(Returns::One(SqlMapping::Skip)) => Ok(Returns::One(SqlMapping::Skip)),
Ok(Returns::SetOf(_)) => Err(ReturnsError::SetOfInArray),
Ok(Returns::Table(_)) => Err(ReturnsError::TableInArray),
err @ Err(_) => err,
},
}
}
fn optional() -> bool {
T::optional()
}
}
unsafe impl SqlTranslatable for u8 {
fn argument_sql() -> Result<SqlMapping, ArgumentError> {
Err(ArgumentError::BareU8)
}
fn return_sql() -> Result<Returns, ReturnsError> {
Err(ReturnsError::BareU8)
}
}
unsafe impl SqlTranslatable for i32 {
fn argument_sql() -> Result<SqlMapping, ArgumentError> {
Ok(SqlMapping::literal("INT"))
}
fn return_sql() -> Result<Returns, ReturnsError> {
Ok(Returns::One(SqlMapping::literal("INT")))
}
}
unsafe impl SqlTranslatable for u32 {
fn argument_sql() -> Result<SqlMapping, ArgumentError> {
Ok(SqlMapping::Source { array_brackets: false })
}
fn return_sql() -> Result<Returns, ReturnsError> {
Ok(Returns::One(SqlMapping::Source { array_brackets: false }))
}
}
unsafe impl SqlTranslatable for String {
fn argument_sql() -> Result<SqlMapping, ArgumentError> {
Ok(SqlMapping::literal("TEXT"))
}
fn return_sql() -> Result<Returns, ReturnsError> {
Ok(Returns::One(SqlMapping::literal("TEXT")))
}
}
unsafe impl<T> SqlTranslatable for &T
where
T: SqlTranslatable,
{
fn argument_sql() -> Result<SqlMapping, ArgumentError> {
T::argument_sql()
}
fn return_sql() -> Result<Returns, ReturnsError> {
T::return_sql()
}
}
unsafe impl<'a> SqlTranslatable for &'a str {
fn argument_sql() -> Result<SqlMapping, ArgumentError> {
Ok(SqlMapping::literal("TEXT"))
}
fn return_sql() -> Result<Returns, ReturnsError> {
Ok(Returns::One(SqlMapping::literal("TEXT")))
}
}
unsafe impl<'a> SqlTranslatable for &'a [u8] {
fn argument_sql() -> Result<SqlMapping, ArgumentError> {
Ok(SqlMapping::literal("bytea"))
}
fn return_sql() -> Result<Returns, ReturnsError> {
Ok(Returns::One(SqlMapping::literal("bytea")))
}
}
unsafe impl SqlTranslatable for i8 {
fn argument_sql() -> Result<SqlMapping, ArgumentError> {
Ok(SqlMapping::As(String::from("\"char\"")))
}
fn return_sql() -> Result<Returns, ReturnsError> {
Ok(Returns::One(SqlMapping::As(String::from("\"char\""))))
}
}
unsafe impl SqlTranslatable for i16 {
fn argument_sql() -> Result<SqlMapping, ArgumentError> {
Ok(SqlMapping::literal("smallint"))
}
fn return_sql() -> Result<Returns, ReturnsError> {
Ok(Returns::One(SqlMapping::literal("smallint")))
}
}
unsafe impl SqlTranslatable for i64 {
fn argument_sql() -> Result<SqlMapping, ArgumentError> {
Ok(SqlMapping::literal("bigint"))
}
fn return_sql() -> Result<Returns, ReturnsError> {
Ok(Returns::One(SqlMapping::literal("bigint")))
}
}
unsafe impl SqlTranslatable for bool {
fn argument_sql() -> Result<SqlMapping, ArgumentError> {
Ok(SqlMapping::literal("bool"))
}
fn return_sql() -> Result<Returns, ReturnsError> {
Ok(Returns::One(SqlMapping::literal("bool")))
}
}
unsafe impl SqlTranslatable for char {
fn argument_sql() -> Result<SqlMapping, ArgumentError> {
Ok(SqlMapping::literal("varchar"))
}
fn return_sql() -> Result<Returns, ReturnsError> {
Ok(Returns::One(SqlMapping::literal("varchar")))
}
}
unsafe impl SqlTranslatable for f32 {
fn argument_sql() -> Result<SqlMapping, ArgumentError> {
Ok(SqlMapping::literal("real"))
}
fn return_sql() -> Result<Returns, ReturnsError> {
Ok(Returns::One(SqlMapping::literal("real")))
}
}
unsafe impl SqlTranslatable for f64 {
fn argument_sql() -> Result<SqlMapping, ArgumentError> {
Ok(SqlMapping::literal("double precision"))
}
fn return_sql() -> Result<Returns, ReturnsError> {
Ok(Returns::One(SqlMapping::literal("double precision")))
}
}
extern crate alloc;
unsafe impl SqlTranslatable for alloc::ffi::CString {
fn argument_sql() -> Result<SqlMapping, ArgumentError> {
Ok(SqlMapping::literal("cstring"))
}
fn return_sql() -> Result<Returns, ReturnsError> {
Ok(Returns::One(SqlMapping::literal("cstring")))
}
}
unsafe impl SqlTranslatable for core::ffi::CStr {
fn argument_sql() -> Result<SqlMapping, ArgumentError> {
Ok(SqlMapping::literal("cstring"))
}
fn return_sql() -> Result<Returns, ReturnsError> {
Ok(Returns::One(SqlMapping::literal("cstring")))
}
}
unsafe impl SqlTranslatable for &'_ core::ffi::CStr {
fn argument_sql() -> Result<SqlMapping, ArgumentError> {
Ok(SqlMapping::literal("cstring"))
}
fn return_sql() -> Result<Returns, ReturnsError> {
Ok(Returns::One(SqlMapping::literal("cstring")))
}
}