mirror of
https://github.com/aljazceru/turso.git
synced 2025-12-24 19:44:21 +01:00
- add `--watch` flag - start saving seeds in persistent storage - make a separate version of execution functions that use `vector of interaction` instead of `InteractionPlan`
114 lines
3.0 KiB
Rust
114 lines
3.0 KiB
Rust
use std::{fmt::Display, ops::Deref};
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
pub(crate) struct Name(pub(crate) String);
|
|
|
|
impl Deref for Name {
|
|
type Target = str;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub(crate) struct Table {
|
|
pub(crate) rows: Vec<Vec<Value>>,
|
|
pub(crate) name: String,
|
|
pub(crate) columns: Vec<Column>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub(crate) struct Column {
|
|
pub(crate) name: String,
|
|
pub(crate) column_type: ColumnType,
|
|
pub(crate) primary: bool,
|
|
pub(crate) unique: bool,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub(crate) enum ColumnType {
|
|
Integer,
|
|
Float,
|
|
Text,
|
|
Blob,
|
|
}
|
|
|
|
impl Display for ColumnType {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
Self::Integer => write!(f, "INTEGER"),
|
|
Self::Float => write!(f, "REAL"),
|
|
Self::Text => write!(f, "TEXT"),
|
|
Self::Blob => write!(f, "BLOB"),
|
|
}
|
|
}
|
|
}
|
|
|
|
fn float_to_string<S>(float: &f64, serializer: S) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: serde::Serializer,
|
|
{
|
|
serializer.serialize_str(&format!("{}", float))
|
|
}
|
|
|
|
fn string_to_float<'de, D>(deserializer: D) -> Result<f64, D::Error>
|
|
where
|
|
D: serde::Deserializer<'de>,
|
|
{
|
|
let s = String::deserialize(deserializer)?;
|
|
s.parse().map_err(serde::de::Error::custom)
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
|
pub(crate) enum Value {
|
|
Null,
|
|
Integer(i64),
|
|
// we use custom serialization to preserve float precision
|
|
#[serde(
|
|
serialize_with = "float_to_string",
|
|
deserialize_with = "string_to_float"
|
|
)]
|
|
Float(f64),
|
|
Text(String),
|
|
Blob(Vec<u8>),
|
|
}
|
|
|
|
impl PartialOrd for Value {
|
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
match (self, other) {
|
|
(Self::Null, Self::Null) => Some(std::cmp::Ordering::Equal),
|
|
(Self::Null, _) => Some(std::cmp::Ordering::Less),
|
|
(_, Self::Null) => Some(std::cmp::Ordering::Greater),
|
|
(Self::Integer(i1), Self::Integer(i2)) => i1.partial_cmp(i2),
|
|
(Self::Float(f1), Self::Float(f2)) => f1.partial_cmp(f2),
|
|
(Self::Text(t1), Self::Text(t2)) => t1.partial_cmp(t2),
|
|
(Self::Blob(b1), Self::Blob(b2)) => b1.partial_cmp(b2),
|
|
// todo: add type coercions here
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
fn to_sqlite_blob(bytes: &[u8]) -> String {
|
|
format!(
|
|
"X'{}'",
|
|
bytes
|
|
.iter()
|
|
.fold(String::new(), |acc, b| acc + &format!("{:02X}", b))
|
|
)
|
|
}
|
|
|
|
impl Display for Value {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
Self::Null => write!(f, "NULL"),
|
|
Self::Integer(i) => write!(f, "{}", i),
|
|
Self::Float(fl) => write!(f, "{}", fl),
|
|
Self::Text(t) => write!(f, "'{}'", t),
|
|
Self::Blob(b) => write!(f, "{}", to_sqlite_blob(b)),
|
|
}
|
|
}
|
|
}
|