use alloc::string::String;
use alloc::vec::Vec;
use core::ops::Deref;
use super::Connection;
#[derive(Debug, Clone, Copy)]
pub(crate) enum Param<'a> {
Text(&'a str),
Blob(&'a [u8]),
Integer(i64),
}
impl<'a> From<&'a str> for Param<'a> {
fn from(text: &'a str) -> Self {
Self::Text(text)
}
}
impl<'a> From<&'a String> for Param<'a> {
fn from(text: &'a String) -> Self {
Self::Text(text)
}
}
impl<'a> From<&'a [u8]> for Param<'a> {
fn from(blob: &'a [u8]) -> Self {
Self::Blob(blob)
}
}
impl<'a> From<&'a Vec<u8>> for Param<'a> {
fn from(blob: &'a Vec<u8>) -> Self {
Self::Blob(blob)
}
}
impl From<i64> for Param<'_> {
fn from(integer: i64) -> Self {
Self::Integer(integer)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) enum SqlError {
Busy(String),
#[cfg_attr(
sqlite_engine,
expect(dead_code, reason = "SQLite opens every file for any process")
)]
HeldByAnotherProcess(String),
Corrupt(String),
NotADatabase(String),
ReadOnly(String),
Full(String),
Io(String),
Other(String),
}
impl core::fmt::Display for SqlError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Busy(message)
| Self::HeldByAnotherProcess(message)
| Self::Corrupt(message)
| Self::NotADatabase(message)
| Self::ReadOnly(message)
| Self::Full(message)
| Self::Io(message)
| Self::Other(message) => f.write_str(message),
}
}
}
impl From<SqlError> for String {
fn from(error: SqlError) -> Self {
alloc::string::ToString::to_string(&error)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(
browser_cache,
expect(dead_code, reason = "the browser opens its files one way")
)]
pub(crate) enum Opening {
ReadOnly,
Shared,
ProcessLocal,
Staging,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum Behavior {
#[cfg_attr(
not(browser_cache),
expect(dead_code, reason = "only the browser's writes defer")
)]
Deferred,
#[cfg_attr(
browser_cache,
expect(dead_code, reason = "the browser's writes defer")
)]
Immediate,
}
impl Behavior {
fn begin(self) -> &'static str {
match self {
Self::Deferred => "BEGIN DEFERRED",
Self::Immediate => "BEGIN IMMEDIATE",
}
}
}
pub(crate) struct Transaction<'c> {
connection: &'c Connection,
open: bool,
}
impl<'c> Transaction<'c> {
pub(crate) fn new(connection: &'c Connection, behavior: Behavior) -> Result<Self, SqlError> {
connection.execute(behavior.begin(), &[])?;
Ok(Self {
connection,
open: true,
})
}
pub(crate) fn commit(mut self) -> Result<(), SqlError> {
self.connection.execute("COMMIT", &[])?;
self.open = false;
Ok(())
}
}
impl Deref for Transaction<'_> {
type Target = Connection;
fn deref(&self) -> &Connection {
self.connection
}
}
impl Drop for Transaction<'_> {
fn drop(&mut self) {
if self.open {
let _ = self.connection.execute("ROLLBACK", &[]);
}
}
}