use rorm_db::sql::aggregation::SelectAggregator;
use rorm_db::sql::join_table::JoinType;
use rorm_db::sql::limit_clause::LimitClause;
use rorm_db::sql::ordering::Ordering;
use rorm_db::sql::value::NullType;
use rorm_db::{DatabaseConfiguration, DatabaseDriver};
use crate::utils::FFIOption;
use crate::{Error, FFIDate, FFIDateTime, FFISlice, FFIString, FFITime};
#[repr(i32)]
pub enum DBBackend {
Invalid,
SQLite,
MySQL,
Postgres,
}
#[repr(C)]
pub struct DBConnectOptions<'a> {
backend: DBBackend,
name: FFIString<'a>,
host: FFIString<'a>,
port: u16,
user: FFIString<'a>,
password: FFIString<'a>,
min_connections: u32,
max_connections: u32,
}
impl From<DBConnectOptions<'_>> for Result<DatabaseConfiguration, Error<'_>> {
fn from(config: DBConnectOptions) -> Self {
if config.min_connections == 0 || config.max_connections == 0 {
return Err(Error::ConfigurationError(FFIString::from(
"DBConnectOptions.min_connections and DBConnectOptions.max_connections must not be 0",
)));
}
let d = match config.backend {
DBBackend::Invalid => {
return Err(Error::ConfigurationError(FFIString::from(
"Invalid database backend selected",
)))
}
DBBackend::SQLite => DatabaseDriver::SQLite {
filename: <&str>::try_from(config.name).unwrap().to_owned(),
},
DBBackend::MySQL => DatabaseDriver::MySQL {
name: <&str>::try_from(config.name).unwrap().to_owned(),
host: <&str>::try_from(config.host).unwrap().to_owned(),
port: config.port,
user: <&str>::try_from(config.user).unwrap().to_owned(),
password: <&str>::try_from(config.password).unwrap().to_owned(),
},
DBBackend::Postgres => DatabaseDriver::Postgres {
name: <&str>::try_from(config.name).unwrap().to_owned(),
host: <&str>::try_from(config.host).unwrap().to_owned(),
port: config.port,
user: <&str>::try_from(config.user).unwrap().to_owned(),
password: <&str>::try_from(config.password).unwrap().to_owned(),
},
};
#[cfg(feature = "logging")]
return Ok(DatabaseConfiguration {
driver: d,
min_connections: config.min_connections,
max_connections: config.max_connections,
disable_logging: None,
statement_log_level: None,
slow_statement_log_level: None,
});
#[cfg(not(feature = "logging"))]
Ok(DatabaseConfiguration {
driver: d,
min_connections: config.min_connections,
max_connections: config.max_connections,
disable_logging: Some(true),
statement_log_level: None,
slow_statement_log_level: None,
})
}
}
#[repr(C)]
#[derive(Copy, Clone)]
pub enum FFINullType {
String,
I64,
I32,
I16,
Bool,
F64,
F32,
Binary,
NaiveTime,
NaiveDate,
NaiveDateTime,
Choice,
}
impl From<NullType> for FFINullType {
fn from(value: NullType) -> Self {
match value {
NullType::String => Self::String,
NullType::I64 => Self::I64,
NullType::I32 => Self::I32,
NullType::I16 => Self::I16,
NullType::Bool => Self::Bool,
NullType::F64 => Self::F64,
NullType::F32 => Self::F32,
NullType::Binary => Self::Binary,
NullType::NaiveTime => Self::NaiveTime,
NullType::NaiveDate => Self::NaiveDate,
NullType::NaiveDateTime => Self::NaiveDateTime,
NullType::Choice => Self::Choice,
}
}
}
impl From<FFINullType> for NullType {
fn from(value: FFINullType) -> Self {
match value {
FFINullType::String => Self::String,
FFINullType::I64 => Self::I64,
FFINullType::I32 => Self::I32,
FFINullType::I16 => Self::I16,
FFINullType::Bool => Self::Bool,
FFINullType::F64 => Self::F64,
FFINullType::F32 => Self::F32,
FFINullType::Binary => Self::Binary,
FFINullType::NaiveTime => Self::NaiveTime,
FFINullType::NaiveDate => Self::NaiveDate,
FFINullType::NaiveDateTime => Self::NaiveDateTime,
FFINullType::Choice => Self::Choice,
}
}
}
#[repr(C)]
#[derive(Copy, Clone)]
pub enum FFIValue<'a> {
Null(FFINullType),
Ident(FFIString<'a>),
Column {
table_name: FFIOption<FFIString<'a>>,
column_name: FFIString<'a>,
},
String(FFIString<'a>),
I64(i64),
I32(i32),
I16(i16),
Bool(bool),
F64(f64),
F32(f32),
Binary(FFISlice<'a, u8>),
NaiveTime(FFITime),
NaiveDate(FFIDate),
NaiveDateTime(FFIDateTime),
Choice(FFIString<'a>),
}
impl<'a> TryFrom<&'a FFIValue<'a>> for rorm_db::sql::value::Value<'a> {
type Error = Error<'a>;
fn try_from(value: &'a FFIValue<'a>) -> Result<Self, Self::Error> {
match value {
FFIValue::Null(t) => Ok(rorm_db::sql::value::Value::Null((*t).into())),
FFIValue::Ident(x) => Ok(rorm_db::sql::value::Value::Ident(
x.try_into().map_err(|_| Error::InvalidStringError)?,
)),
FFIValue::Column {
table_name,
column_name,
} => {
let table_name = match table_name {
FFIOption::None => None,
FFIOption::Some(v) => {
Some(v.try_into().map_err(|_| Error::InvalidStringError)?)
}
};
Ok(rorm_db::sql::value::Value::Column {
table_name,
column_name: column_name
.try_into()
.map_err(|_| Error::InvalidStringError)?,
})
}
FFIValue::String(x) => Ok(rorm_db::sql::value::Value::String(
x.try_into().map_err(|_| Error::InvalidStringError)?,
)),
FFIValue::I64(x) => Ok(rorm_db::sql::value::Value::I64(*x)),
FFIValue::I32(x) => Ok(rorm_db::sql::value::Value::I32(*x)),
FFIValue::I16(x) => Ok(rorm_db::sql::value::Value::I16(*x)),
FFIValue::Bool(x) => Ok(rorm_db::sql::value::Value::Bool(*x)),
FFIValue::F64(x) => Ok(rorm_db::sql::value::Value::F64(*x)),
FFIValue::F32(x) => Ok(rorm_db::sql::value::Value::F32(*x)),
FFIValue::Binary(x) => Ok(rorm_db::sql::value::Value::Binary(x.into())),
FFIValue::NaiveTime(x) => Ok(rorm_db::sql::value::Value::NaiveTime(x.try_into()?)),
FFIValue::NaiveDate(x) => Ok(rorm_db::sql::value::Value::NaiveDate(x.try_into()?)),
FFIValue::NaiveDateTime(x) => {
Ok(rorm_db::sql::value::Value::NaiveDateTime(x.try_into()?))
}
FFIValue::Choice(x) => Ok(rorm_db::sql::value::Value::Choice(
x.try_into().map_err(|_| Error::InvalidStringError)?,
)),
}
}
}
#[repr(C)]
pub enum FFITernaryCondition<'a> {
Between([&'a FFICondition<'a>; 3]),
NotBetween([&'a FFICondition<'a>; 3]),
}
impl<'a> TryFrom<&FFITernaryCondition<'a>> for rorm_db::sql::conditional::TernaryCondition<'a> {
type Error = Error<'a>;
fn try_from(value: &FFITernaryCondition<'a>) -> Result<Self, Self::Error> {
match value {
FFITernaryCondition::Between(x) => {
let [a, b, c] = x;
let x_conv = [(*a).try_into()?, (*b).try_into()?, (*c).try_into()?];
Ok(rorm_db::sql::conditional::TernaryCondition::Between(
Box::new(x_conv),
))
}
FFITernaryCondition::NotBetween(x) => {
let [a, b, c] = x;
let x_conv = [(*a).try_into()?, (*b).try_into()?, (*c).try_into()?];
Ok(rorm_db::sql::conditional::TernaryCondition::NotBetween(
Box::new(x_conv),
))
}
}
}
}
#[repr(C)]
pub enum FFIBinaryCondition<'a> {
Equals([&'a FFICondition<'a>; 2]),
NotEquals([&'a FFICondition<'a>; 2]),
Greater([&'a FFICondition<'a>; 2]),
GreaterOrEquals([&'a FFICondition<'a>; 2]),
Less([&'a FFICondition<'a>; 2]),
LessOrEquals([&'a FFICondition<'a>; 2]),
Like([&'a FFICondition<'a>; 2]),
NotLike([&'a FFICondition<'a>; 2]),
Regexp([&'a FFICondition<'a>; 2]),
NotRegexp([&'a FFICondition<'a>; 2]),
In([&'a FFICondition<'a>; 2]),
NotIn([&'a FFICondition<'a>; 2]),
}
impl<'a> TryFrom<&FFIBinaryCondition<'a>> for rorm_db::sql::conditional::BinaryCondition<'a> {
type Error = Error<'a>;
fn try_from(value: &FFIBinaryCondition<'a>) -> Result<Self, Self::Error> {
match value {
FFIBinaryCondition::Equals(x) => {
let [a, b] = x;
let x_conv = [(*a).try_into()?, (*b).try_into()?];
Ok(rorm_db::sql::conditional::BinaryCondition::Equals(
Box::new(x_conv),
))
}
FFIBinaryCondition::NotEquals(x) => {
let [a, b] = x;
let x_conv = [(*a).try_into()?, (*b).try_into()?];
Ok(rorm_db::sql::conditional::BinaryCondition::NotEquals(
Box::new(x_conv),
))
}
FFIBinaryCondition::Greater(x) => {
let [a, b] = x;
let x_conv = [(*a).try_into()?, (*b).try_into()?];
Ok(rorm_db::sql::conditional::BinaryCondition::Greater(
Box::new(x_conv),
))
}
FFIBinaryCondition::GreaterOrEquals(x) => {
let [a, b] = x;
let x_conv = [(*a).try_into()?, (*b).try_into()?];
Ok(rorm_db::sql::conditional::BinaryCondition::GreaterOrEquals(
Box::new(x_conv),
))
}
FFIBinaryCondition::Less(x) => {
let [a, b] = x;
let x_conv = [(*a).try_into()?, (*b).try_into()?];
Ok(rorm_db::sql::conditional::BinaryCondition::Less(Box::new(
x_conv,
)))
}
FFIBinaryCondition::LessOrEquals(x) => {
let [a, b] = x;
let x_conv = [(*a).try_into()?, (*b).try_into()?];
Ok(rorm_db::sql::conditional::BinaryCondition::LessOrEquals(
Box::new(x_conv),
))
}
FFIBinaryCondition::Like(x) => {
let [a, b] = x;
let x_conv = [(*a).try_into()?, (*b).try_into()?];
Ok(rorm_db::sql::conditional::BinaryCondition::Like(Box::new(
x_conv,
)))
}
FFIBinaryCondition::NotLike(x) => {
let [a, b] = x;
let x_conv = [(*a).try_into()?, (*b).try_into()?];
Ok(rorm_db::sql::conditional::BinaryCondition::NotLike(
Box::new(x_conv),
))
}
FFIBinaryCondition::Regexp(x) => {
let [a, b] = x;
let x_conv = [(*a).try_into()?, (*b).try_into()?];
Ok(rorm_db::sql::conditional::BinaryCondition::Regexp(
Box::new(x_conv),
))
}
FFIBinaryCondition::NotRegexp(x) => {
let [a, b] = x;
let x_conv = [(*a).try_into()?, (*b).try_into()?];
Ok(rorm_db::sql::conditional::BinaryCondition::NotRegexp(
Box::new(x_conv),
))
}
FFIBinaryCondition::In(x) => {
let [a, b] = x;
let x_conv = [(*a).try_into()?, (*b).try_into()?];
Ok(rorm_db::sql::conditional::BinaryCondition::In(Box::new(
x_conv,
)))
}
FFIBinaryCondition::NotIn(x) => {
let [a, b] = x;
let x_conv = [(*a).try_into()?, (*b).try_into()?];
Ok(rorm_db::sql::conditional::BinaryCondition::NotIn(Box::new(
x_conv,
)))
}
}
}
}
#[repr(C)]
pub enum FFIUnaryCondition<'a> {
IsNull(&'a FFICondition<'a>),
IsNotNull(&'a FFICondition<'a>),
Exists(&'a FFICondition<'a>),
NotExists(&'a FFICondition<'a>),
Not(&'a FFICondition<'a>),
}
impl<'a> TryFrom<&FFIUnaryCondition<'a>> for rorm_db::sql::conditional::UnaryCondition<'a> {
type Error = Error<'a>;
fn try_from(value: &FFIUnaryCondition<'a>) -> Result<Self, Self::Error> {
match value {
FFIUnaryCondition::IsNull(x) => Ok(rorm_db::sql::conditional::UnaryCondition::IsNull(
Box::new((*x).try_into()?),
)),
FFIUnaryCondition::IsNotNull(x) => Ok(
rorm_db::sql::conditional::UnaryCondition::IsNotNull(Box::new((*x).try_into()?)),
),
FFIUnaryCondition::Exists(x) => Ok(rorm_db::sql::conditional::UnaryCondition::Exists(
Box::new((*x).try_into()?),
)),
FFIUnaryCondition::NotExists(x) => Ok(
rorm_db::sql::conditional::UnaryCondition::NotExists(Box::new((*x).try_into()?)),
),
FFIUnaryCondition::Not(x) => Ok(rorm_db::sql::conditional::UnaryCondition::Not(
Box::new((*x).try_into()?),
)),
}
}
}
#[repr(C)]
pub enum FFICondition<'a> {
Conjunction(FFISlice<'a, FFICondition<'a>>),
Disjunction(FFISlice<'a, FFICondition<'a>>),
UnaryCondition(FFIUnaryCondition<'a>),
BinaryCondition(FFIBinaryCondition<'a>),
TernaryCondition(FFITernaryCondition<'a>),
Value(FFIValue<'a>),
}
impl<'a> TryFrom<&'a FFICondition<'a>> for rorm_db::sql::conditional::Condition<'a> {
type Error = Error<'a>;
fn try_from(value: &'a FFICondition<'a>) -> Result<Self, Self::Error> {
match value {
FFICondition::Conjunction(x) => {
let x_conv: &[FFICondition] = x.into();
let mut x_vec = vec![];
for cond in x_conv {
x_vec.push(cond.try_into()?);
}
Ok(rorm_db::sql::conditional::Condition::Conjunction(x_vec))
}
FFICondition::Disjunction(x) => {
let x_conv: &[FFICondition] = x.into();
let mut x_vec = vec![];
for cond in x_conv {
x_vec.push(cond.try_into()?);
}
Ok(rorm_db::sql::conditional::Condition::Disjunction(x_vec))
}
FFICondition::UnaryCondition(x) => Ok(
rorm_db::sql::conditional::Condition::UnaryCondition(x.try_into()?),
),
FFICondition::BinaryCondition(x) => Ok(
rorm_db::sql::conditional::Condition::BinaryCondition(x.try_into()?),
),
FFICondition::TernaryCondition(x) => Ok(
rorm_db::sql::conditional::Condition::TernaryCondition(x.try_into()?),
),
FFICondition::Value(x) => {
Ok(rorm_db::sql::conditional::Condition::Value(x.try_into()?))
}
}
}
}
#[repr(C)]
pub struct FFIUpdate<'a> {
pub(crate) column: FFIString<'a>,
pub(crate) value: FFIValue<'a>,
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub enum FFIJoinType {
Join,
CrossJoin,
LeftJoin,
RightJoin,
FullJoin,
}
impl From<FFIJoinType> for JoinType {
fn from(v: FFIJoinType) -> Self {
match v {
FFIJoinType::Join => JoinType::Join,
FFIJoinType::CrossJoin => JoinType::CrossJoin,
FFIJoinType::LeftJoin => JoinType::LeftJoin,
FFIJoinType::RightJoin => JoinType::RightJoin,
FFIJoinType::FullJoin => JoinType::FullJoin,
}
}
}
#[repr(C)]
pub struct FFIJoin<'a> {
pub(crate) join_type: FFIJoinType,
pub(crate) table_name: FFIString<'a>,
pub(crate) join_alias: FFIString<'a>,
pub(crate) join_condition: &'a FFICondition<'a>,
}
#[repr(C)]
pub struct FFILimitClause {
pub(crate) limit: u64,
pub(crate) offset: FFIOption<u64>,
}
impl From<FFILimitClause> for LimitClause {
fn from(v: FFILimitClause) -> Self {
Self {
limit: v.limit,
offset: v.offset.into(),
}
}
}
#[repr(C)]
pub struct FFIColumnSelector<'a> {
pub(crate) table_name: FFIOption<FFIString<'a>>,
pub(crate) column_name: FFIString<'a>,
pub(crate) select_alias: FFIOption<FFIString<'a>>,
pub(crate) aggregation: FFIOption<FFIAggregation>,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub enum FFIOrdering {
Asc,
Desc,
}
impl From<FFIOrdering> for Ordering {
fn from(v: FFIOrdering) -> Self {
match v {
FFIOrdering::Asc => Self::Asc,
FFIOrdering::Desc => Self::Desc,
}
}
}
#[repr(C)]
#[derive(Copy, Clone)]
pub enum FFIAggregation {
Avg,
Count,
Sum,
Max,
Min,
}
impl From<FFIAggregation> for SelectAggregator {
fn from(v: FFIAggregation) -> Self {
match v {
FFIAggregation::Avg => SelectAggregator::Avg,
FFIAggregation::Count => SelectAggregator::Count,
FFIAggregation::Sum => SelectAggregator::Sum,
FFIAggregation::Max => SelectAggregator::Max,
FFIAggregation::Min => SelectAggregator::Min,
}
}
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct FFIOrderByEntry<'a> {
pub(crate) ordering: FFIOrdering,
pub(crate) table_name: FFIOption<FFIString<'a>>,
pub(crate) column_name: FFIString<'a>,
}