Skip to main content

klukai_types/
api.rs

1use std::{
2    borrow::Borrow,
3    collections::HashMap,
4    fmt::{self, Write},
5    hash::Hash,
6    ops::{AddAssign, Deref},
7};
8
9use compact_str::CompactString;
10use rusqlite::{
11    ToSql,
12    types::{FromSql, FromSqlError, ToSqlOutput, Value, ValueRef},
13};
14use serde::{Deserialize, Serialize};
15use serde_json::value::RawValue;
16use smallvec::{SmallVec, ToSmallVec};
17use speedy::{Context, Readable, Reader, Writable, Writer};
18
19pub mod sqlite {
20    use rusqlite::{
21        ToSql,
22        types::{FromSql, FromSqlError},
23    };
24    use serde::{Deserialize, Serialize};
25    use speedy::{Readable, Writable};
26
27    #[derive(
28        Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Readable, Writable, strum::FromRepr,
29    )]
30    #[serde(rename_all = "snake_case")]
31    #[repr(u8)]
32    pub enum ChangeType {
33        Insert = 0,
34        Update = 1,
35        Delete = 2,
36    }
37
38    impl FromSql for ChangeType {
39        fn column_result(
40            value: rusqlite::types::ValueRef<'_>,
41        ) -> rusqlite::types::FromSqlResult<Self> {
42            match value {
43                rusqlite::types::ValueRef::Integer(i) => Ok(ChangeType::from_repr(
44                    i.try_into().map_err(|e| FromSqlError::Other(Box::new(e)))?,
45                )
46                .ok_or_else(|| FromSqlError::OutOfRange(i))?),
47                _ => Err(FromSqlError::InvalidType),
48            }
49        }
50    }
51
52    impl ToSql for ChangeType {
53        fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> {
54            Ok(rusqlite::types::ToSqlOutput::Owned(
55                rusqlite::types::Value::Integer((*self as u8) as i64),
56            ))
57        }
58    }
59}
60
61use sqlite::ChangeType;
62
63pub type QueryEvent = TypedQueryEvent<Vec<SqliteValue>>;
64
65#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
66#[serde(rename_all = "snake_case")]
67pub enum TypedQueryEvent<T> {
68    Columns(Vec<ColumnName>),
69    Row(RowId, T),
70    #[serde(rename = "eoq")]
71    EndOfQuery {
72        time: f64,
73        #[serde(skip_serializing_if = "Option::is_none")]
74        change_id: Option<ChangeId>,
75    },
76    Change(ChangeType, RowId, T, ChangeId),
77    Error(CompactString),
78}
79
80impl<T> TypedQueryEvent<T> {
81    pub fn meta(&self) -> QueryEventMeta {
82        match self {
83            TypedQueryEvent::Columns(_) => QueryEventMeta::Columns,
84            TypedQueryEvent::Row(rowid, _) => QueryEventMeta::Row(*rowid),
85            TypedQueryEvent::EndOfQuery { change_id, .. } => QueryEventMeta::EndOfQuery(*change_id),
86            TypedQueryEvent::Change(_, _, _, id) => QueryEventMeta::Change(*id),
87            TypedQueryEvent::Error(_) => QueryEventMeta::Error,
88        }
89    }
90}
91
92#[derive(Debug, Clone, Copy, PartialEq)]
93pub enum QueryEventMeta {
94    Columns,
95    Row(RowId),
96    EndOfQuery(Option<ChangeId>),
97    Change(ChangeId),
98    Error,
99    Notify,
100}
101
102pub type NotifyEvent = TypedNotifyEvent<Vec<SqliteValue>>;
103
104#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
105#[serde(rename_all = "snake_case")]
106pub enum TypedNotifyEvent<T> {
107    Notify(ChangeType, T),
108    Error(CompactString),
109}
110
111/// RowId newtype to differentiate from ChangeId
112#[derive(
113    Debug,
114    Clone,
115    Copy,
116    Serialize,
117    Deserialize,
118    Readable,
119    Writable,
120    PartialEq,
121    Eq,
122    Ord,
123    PartialOrd,
124    Hash,
125)]
126#[serde(transparent)]
127pub struct RowId(pub u64);
128
129impl fmt::Display for RowId {
130    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131        self.0.fmt(f)
132    }
133}
134
135impl From<u64> for RowId {
136    fn from(value: u64) -> Self {
137        Self(value)
138    }
139}
140
141impl FromSql for RowId {
142    fn column_result(value: ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
143        u64::column_result(value).map(Self)
144    }
145}
146
147impl ToSql for RowId {
148    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
149        self.0.to_sql()
150    }
151}
152
153/// ChangeId newtype to differentiate from RowId
154#[derive(
155    Debug,
156    Default,
157    Clone,
158    Copy,
159    Serialize,
160    Deserialize,
161    Readable,
162    Writable,
163    PartialEq,
164    Eq,
165    Ord,
166    PartialOrd,
167)]
168#[serde(transparent)]
169pub struct ChangeId(pub u64);
170
171impl ChangeId {
172    pub fn is_zero(&self) -> bool {
173        self.0 == 0
174    }
175}
176
177impl fmt::Display for ChangeId {
178    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
179        self.0.fmt(f)
180    }
181}
182
183impl From<u64> for ChangeId {
184    fn from(value: u64) -> Self {
185        Self(value)
186    }
187}
188
189impl FromSql for ChangeId {
190    fn column_result(value: ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
191        u64::column_result(value).map(Self)
192    }
193}
194
195impl ToSql for ChangeId {
196    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
197        self.0.to_sql()
198    }
199}
200
201impl AddAssign<u64> for ChangeId {
202    fn add_assign(&mut self, rhs: u64) {
203        self.0 += rhs
204    }
205}
206
207impl AddAssign<Self> for ChangeId {
208    fn add_assign(&mut self, rhs: Self) {
209        self.0 += rhs.0
210    }
211}
212
213impl std::ops::Add<u64> for ChangeId {
214    type Output = ChangeId;
215
216    fn add(self, rhs: u64) -> Self::Output {
217        ChangeId(self.0 + rhs)
218    }
219}
220
221impl std::ops::Add<Self> for ChangeId {
222    type Output = ChangeId;
223
224    fn add(self, rhs: Self) -> Self::Output {
225        ChangeId(self.0 + rhs.0)
226    }
227}
228
229#[derive(Debug, Clone, Serialize, Deserialize)]
230#[serde(untagged)]
231pub enum Statement {
232    Verbose {
233        query: String,
234        params: Option<Vec<SqliteParam>>,
235        named_params: Option<HashMap<String, SqliteParam>>,
236    },
237    Simple(String),
238    WithParams(String, Vec<SqliteParam>),
239    WithNamedParams(String, HashMap<String, SqliteParam>),
240}
241
242impl Statement {
243    pub fn query(&self) -> &str {
244        match self {
245            Statement::Verbose { query, .. }
246            | Statement::Simple(query)
247            | Statement::WithParams(query, _)
248            | Statement::WithNamedParams(query, _) => query,
249        }
250    }
251}
252
253impl From<&str> for Statement {
254    fn from(value: &str) -> Self {
255        Statement::Simple(value.into())
256    }
257}
258
259#[derive(Debug, Serialize, Deserialize)]
260pub struct ExecResponse {
261    pub results: Vec<ExecResult>,
262    pub time: f64,
263    pub version: Option<u64>,
264    pub actor_id: Option<String>,
265}
266
267#[derive(Debug, Serialize, Deserialize)]
268#[serde(untagged)]
269pub enum ExecResult {
270    Execute { rows_affected: usize, time: f64 },
271    Error { error: String },
272}
273#[derive(Debug, Serialize, Deserialize)]
274pub struct TableStatRequest {
275    pub tables: Vec<String>,
276}
277
278/// Contain node and sync status information
279#[derive(Debug, Serialize, Deserialize)]
280pub struct TableStatResponse {
281    pub total_row_count: i64,
282    pub invalid_tables: Vec<String>,
283}
284
285#[derive(Debug, Copy, Clone, PartialEq)]
286pub struct SqliteValueRef<'a>(pub ValueRef<'a>);
287
288impl<'a> SqliteValueRef<'a> {
289    pub fn is_null(&self) -> bool {
290        matches!(self.0, ValueRef::Null)
291    }
292
293    pub fn as_integer(&self) -> Option<i64> {
294        self.0.as_i64().ok()
295    }
296
297    pub fn as_real(&self) -> Option<f64> {
298        self.0.as_f64().ok()
299    }
300
301    pub fn as_text(&self) -> Option<&str> {
302        self.0.as_str().ok()
303    }
304
305    pub fn as_blob(&self) -> Option<&[u8]> {
306        self.0.as_blob().ok()
307    }
308
309    pub fn to_owned(&self) -> SqliteValue {
310        match self.0 {
311            ValueRef::Null => SqliteValue::Null,
312            ValueRef::Integer(v) => SqliteValue::Integer(v),
313            ValueRef::Real(v) => SqliteValue::Real(Real(v)),
314            ValueRef::Text(v) => SqliteValue::Text(CompactString::from_utf8_lossy(v)),
315            ValueRef::Blob(v) => SqliteValue::Blob(v.to_smallvec()),
316        }
317    }
318}
319
320impl<'a> Hash for SqliteValueRef<'a> {
321    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
322        core::mem::discriminant(&self.0).hash(state);
323        match self.0 {
324            ValueRef::Null => {}
325            ValueRef::Integer(v) => {
326                v.hash(state);
327            }
328            ValueRef::Real(v) => {
329                integer_decode(v).hash(state);
330            }
331            ValueRef::Text(v) => {
332                v.hash(state);
333            }
334            ValueRef::Blob(v) => {
335                v.hash(state);
336            }
337        }
338    }
339}
340
341#[derive(PartialEq, Debug)]
342pub enum ColumnType {
343    Integer = 1,
344    Float = 2,
345    Text = 3,
346    Blob = 4,
347    Null = 5,
348}
349
350impl ColumnType {
351    pub fn from_u8(u: u8) -> Option<Self> {
352        Some(match u {
353            1 => Self::Integer,
354            2 => Self::Float,
355            3 => Self::Text,
356            4 => Self::Blob,
357            5 => Self::Null,
358            _ => return None,
359        })
360    }
361
362    pub fn from_sqlite_name(s: &str) -> Option<Self> {
363        Some(match s {
364            "INTEGER" => Self::Integer,
365            "REAL" => Self::Float,
366            "TEXT" => Self::Text,
367            "BLOB" => Self::Blob,
368            _ => return None,
369        })
370    }
371}
372
373impl FromSql for ColumnType {
374    fn column_result(value: ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
375        match value {
376            ValueRef::Text(s) => Ok(match String::from_utf8_lossy(s).as_ref() {
377                "INTEGER" => Self::Integer,
378                "REAL" => Self::Float,
379                "TEXT" => Self::Text,
380                "BLOB" => Self::Blob,
381                _ => {
382                    return Err(FromSqlError::InvalidType);
383                }
384            }),
385            _ => Err(FromSqlError::InvalidType),
386        }
387    }
388}
389
390#[allow(clippy::large_enum_variant)]
391#[derive(Debug, Default, Clone, Serialize, Deserialize)]
392#[serde(untagged)]
393pub enum SqliteParam {
394    #[default]
395    Null,
396    Bool(bool),
397    Integer(i64),
398    Real(f64),
399    Text(CompactString),
400    Blob(SmallVec<[u8; 512]>),
401    Json(Box<RawValue>),
402}
403
404impl From<&str> for SqliteParam {
405    fn from(value: &str) -> Self {
406        Self::Text(value.into())
407    }
408}
409
410impl From<Vec<u8>> for SqliteParam {
411    fn from(value: Vec<u8>) -> Self {
412        Self::Blob(value.into())
413    }
414}
415
416impl From<String> for SqliteParam {
417    fn from(value: String) -> Self {
418        Self::Text(value.into())
419    }
420}
421
422impl From<u16> for SqliteParam {
423    fn from(value: u16) -> Self {
424        Self::Integer(value as i64)
425    }
426}
427
428impl From<i64> for SqliteParam {
429    fn from(value: i64) -> Self {
430        Self::Integer(value)
431    }
432}
433
434impl ToSql for SqliteParam {
435    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
436        Ok(match self {
437            SqliteParam::Null => ToSqlOutput::Owned(Value::Null),
438            SqliteParam::Bool(v) => ToSqlOutput::Owned(Value::Integer(*v as i64)),
439            SqliteParam::Integer(i) => ToSqlOutput::Owned(Value::Integer(*i)),
440            SqliteParam::Real(f) => ToSqlOutput::Owned(Value::Real(*f)),
441            SqliteParam::Text(t) => ToSqlOutput::Borrowed(ValueRef::Text(t.as_bytes())),
442            SqliteParam::Blob(b) => ToSqlOutput::Borrowed(ValueRef::Blob(b)),
443            SqliteParam::Json(map) => ToSqlOutput::Borrowed(ValueRef::Text(map.get().as_bytes())),
444        })
445    }
446}
447
448impl<'a> ToSql for SqliteValueRef<'a> {
449    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'a>> {
450        Ok(ToSqlOutput::Borrowed(self.0))
451    }
452}
453
454impl<'a> From<ValueRef<'a>> for SqliteValueRef<'a> {
455    fn from(value: ValueRef<'a>) -> Self {
456        Self(value)
457    }
458}
459
460#[allow(clippy::large_enum_variant)]
461#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Hash)]
462#[serde(untagged)]
463pub enum SqliteValue {
464    #[default]
465    Null,
466    Integer(i64),
467    Real(Real),
468    Text(CompactString),
469    Blob(SmallVec<[u8; 512]>),
470}
471
472#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize, PartialEq)]
473#[serde(transparent)]
474pub struct Real(pub f64);
475
476impl Deref for Real {
477    type Target = f64;
478
479    fn deref(&self) -> &Self::Target {
480        &self.0
481    }
482}
483
484impl Hash for Real {
485    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
486        integer_decode(self.0).hash(state)
487    }
488}
489
490fn integer_decode(val: f64) -> (u64, i16, i8) {
491    let bits: u64 = val.to_bits();
492    let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
493    let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
494    let mantissa = if exponent == 0 {
495        (bits & 0xfffffffffffff) << 1
496    } else {
497        (bits & 0xfffffffffffff) | 0x10000000000000
498    };
499
500    exponent -= 1023 + 52;
501    (mantissa, exponent, sign)
502}
503
504impl SqliteValue {
505    pub fn column_type(&self) -> ColumnType {
506        match self {
507            SqliteValue::Null => ColumnType::Null,
508            SqliteValue::Integer(_) => ColumnType::Integer,
509            SqliteValue::Real(_) => ColumnType::Float,
510            SqliteValue::Text(_) => ColumnType::Text,
511            SqliteValue::Blob(_) => ColumnType::Blob,
512        }
513    }
514
515    pub fn as_str(&self) -> Option<&str> {
516        if let Self::Text(s) = self {
517            Some(s)
518        } else {
519            None
520        }
521    }
522
523    pub fn is_null(&self) -> bool {
524        matches!(self, SqliteValue::Null)
525    }
526
527    pub fn as_integer(&self) -> Option<&i64> {
528        match self {
529            SqliteValue::Integer(i) => Some(i),
530            _ => None,
531        }
532    }
533
534    pub fn as_real(&self) -> Option<&f64> {
535        match self {
536            SqliteValue::Real(f) => Some(f),
537            _ => None,
538        }
539    }
540
541    pub fn as_text(&self) -> Option<&str> {
542        match self {
543            SqliteValue::Text(s) => Some(s),
544            _ => None,
545        }
546    }
547
548    pub fn as_blob(&self) -> Option<&[u8]> {
549        match self {
550            SqliteValue::Blob(b) => Some(b),
551            _ => None,
552        }
553    }
554
555    pub fn as_ref(&self) -> SqliteValueRef<'_> {
556        match self {
557            SqliteValue::Null => SqliteValueRef(ValueRef::Null),
558            SqliteValue::Integer(i) => SqliteValueRef(ValueRef::Integer(*i)),
559            SqliteValue::Real(r) => SqliteValueRef(ValueRef::Real(r.0)),
560            SqliteValue::Text(s) => SqliteValueRef(ValueRef::Text(s.as_bytes())),
561            SqliteValue::Blob(v) => SqliteValueRef(ValueRef::Blob(v.as_slice())),
562        }
563    }
564
565    pub fn estimated_byte_size(&self) -> usize {
566        1 + match self {
567            SqliteValue::Null => 1,
568            SqliteValue::Integer(_) => 8,
569            SqliteValue::Real(_) => 8,
570            SqliteValue::Text(t) => 4 + t.len(),
571            SqliteValue::Blob(v) => 4 + v.len(),
572        }
573    }
574}
575
576impl From<&str> for SqliteValue {
577    fn from(value: &str) -> Self {
578        Self::Text(value.into())
579    }
580}
581
582impl From<Vec<u8>> for SqliteValue {
583    fn from(value: Vec<u8>) -> Self {
584        Self::Blob(value.into())
585    }
586}
587
588impl From<String> for SqliteValue {
589    fn from(value: String) -> Self {
590        Self::Text(value.into())
591    }
592}
593
594impl From<u16> for SqliteValue {
595    fn from(value: u16) -> Self {
596        Self::Integer(value as i64)
597    }
598}
599
600impl From<i64> for SqliteValue {
601    fn from(value: i64) -> Self {
602        Self::Integer(value)
603    }
604}
605
606impl From<f64> for SqliteValue {
607    fn from(value: f64) -> Self {
608        Self::Real(Real(value))
609    }
610}
611
612impl FromSql for SqliteValue {
613    fn column_result(value: ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
614        Ok(match value {
615            ValueRef::Null => SqliteValue::Null,
616            ValueRef::Integer(i) => SqliteValue::Integer(i),
617            ValueRef::Real(f) => SqliteValue::Real(Real(f)),
618            ValueRef::Text(t) => SqliteValue::Text(
619                std::str::from_utf8(t)
620                    .map_err(|e| FromSqlError::Other(Box::new(e)))?
621                    .into(),
622            ),
623            ValueRef::Blob(b) => SqliteValue::Blob(b.into()),
624        })
625    }
626}
627
628impl ToSql for SqliteValue {
629    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
630        Ok(match self {
631            SqliteValue::Null => ToSqlOutput::Owned(Value::Null),
632            SqliteValue::Integer(i) => ToSqlOutput::Owned(Value::Integer(*i)),
633            SqliteValue::Real(f) => ToSqlOutput::Owned(Value::Real(f.0)),
634            SqliteValue::Text(t) => ToSqlOutput::Borrowed(ValueRef::Text(t.as_bytes())),
635            SqliteValue::Blob(b) => ToSqlOutput::Borrowed(ValueRef::Blob(b.as_slice())),
636        })
637    }
638}
639
640impl fmt::Display for SqliteValue {
641    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
642        match self {
643            SqliteValue::Null => f.write_str(""),
644            SqliteValue::Integer(v) => v.fmt(f),
645            SqliteValue::Real(v) => v.fmt(f),
646            SqliteValue::Text(v) => v.fmt(f),
647            SqliteValue::Blob(v) => {
648                f.write_str("x'")?;
649                f.write_str(&hex::encode(v))?;
650                f.write_char('\'')
651            }
652        }
653    }
654}
655
656impl<'a, C> Readable<'a, C> for SqliteValue
657where
658    C: Context,
659{
660    #[inline]
661    fn read_from<R: Reader<'a, C>>(reader: &mut R) -> Result<Self, C::Error> {
662        Ok(match u8::read_from(reader)? {
663            0 => SqliteValue::Null,
664            1 => SqliteValue::Integer(i64::read_from(reader)?),
665            2 => SqliteValue::Real(Real(f64::read_from(reader)?)),
666            3 => {
667                let len = reader.read_u32()? as usize;
668
669                SqliteValue::Text(unsafe {
670                    CompactString::from_utf8_unchecked(reader.read_vec(len)?)
671                })
672            }
673            4 => SqliteValue::Blob(Readable::read_from(reader)?),
674            _ => return Err(speedy::Error::custom("unknown SqliteValue variant").into()),
675        })
676    }
677
678    #[inline]
679    fn minimum_bytes_needed() -> usize {
680        1
681    }
682}
683
684impl<C> Writable<C> for SqliteValue
685where
686    C: Context,
687{
688    #[inline]
689    fn write_to<T: ?Sized + Writer<C>>(&self, writer: &mut T) -> Result<(), C::Error> {
690        match self {
691            SqliteValue::Null => writer.write_u8(0),
692            SqliteValue::Integer(i) => {
693                1u8.write_to(writer)?;
694                i.write_to(writer)
695            }
696            SqliteValue::Real(f) => {
697                2u8.write_to(writer)?;
698                f.write_to(writer)
699            }
700            SqliteValue::Text(s) => {
701                3u8.write_to(writer)?;
702                s.as_bytes().write_to(writer)
703            }
704            SqliteValue::Blob(b) => {
705                4u8.write_to(writer)?;
706                b.write_to(writer)
707            }
708        }
709    }
710
711    #[inline]
712    fn bytes_needed(&self) -> Result<usize, C::Error> {
713        Ok(1 + match self {
714            SqliteValue::Null => 0,
715            SqliteValue::Integer(i) => <i64 as Writable<C>>::bytes_needed(i)?,
716            SqliteValue::Real(f) => <f64 as Writable<C>>::bytes_needed(f)?,
717            SqliteValue::Text(s) => <[u8] as Writable<C>>::bytes_needed(s.as_bytes())?,
718            SqliteValue::Blob(b) => <[u8] as Writable<C>>::bytes_needed(b.as_slice())?,
719        })
720    }
721}
722
723impl<'a, C> Writable<C> for SqliteValueRef<'a>
724where
725    C: Context,
726{
727    #[inline]
728    fn write_to<T: ?Sized + Writer<C>>(&self, writer: &mut T) -> Result<(), C::Error> {
729        match self {
730            SqliteValueRef(ValueRef::Null) => writer.write_u8(0),
731            SqliteValueRef(ValueRef::Integer(i)) => {
732                1u8.write_to(writer)?;
733                i.write_to(writer)
734            }
735            SqliteValueRef(ValueRef::Real(f)) => {
736                2u8.write_to(writer)?;
737                f.write_to(writer)
738            }
739            SqliteValueRef(ValueRef::Text(s)) => {
740                3u8.write_to(writer)?;
741                (*s).write_to(writer)
742            }
743            SqliteValueRef(ValueRef::Blob(b)) => {
744                4u8.write_to(writer)?;
745                (*b).write_to(writer)
746            }
747        }
748    }
749
750    #[inline]
751    fn bytes_needed(&self) -> Result<usize, C::Error> {
752        Ok(1 + match self {
753            SqliteValueRef(ValueRef::Null) => 0,
754            SqliteValueRef(ValueRef::Integer(i)) => <i64 as Writable<C>>::bytes_needed(i)?,
755            SqliteValueRef(ValueRef::Real(f)) => <f64 as Writable<C>>::bytes_needed(f)?,
756            SqliteValueRef(ValueRef::Text(s)) => <[u8] as Writable<C>>::bytes_needed(s)?,
757            SqliteValueRef(ValueRef::Blob(b)) => <[u8] as Writable<C>>::bytes_needed(b)?,
758        })
759    }
760}
761
762#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
763#[serde(transparent)]
764pub struct TableName(pub CompactString);
765
766impl fmt::Display for TableName {
767    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
768        self.0.fmt(f)
769    }
770}
771
772impl Borrow<str> for TableName {
773    #[inline]
774    fn borrow(&self) -> &str {
775        self.as_str()
776    }
777}
778
779impl From<&str> for TableName {
780    fn from(value: &str) -> Self {
781        TableName(value.into())
782    }
783}
784
785#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
786#[serde(transparent)]
787pub struct ColumnName(pub CompactString);
788
789impl ColumnName {
790    pub fn is_crsql_sentinel(&self) -> bool {
791        self.0 == "-1"
792    }
793}
794
795impl Borrow<str> for ColumnName {
796    #[inline]
797    fn borrow(&self) -> &str {
798        self.as_str()
799    }
800}
801
802impl AsRef<[u8]> for ColumnName {
803    fn as_ref(&self) -> &[u8] {
804        self.as_bytes()
805    }
806}
807
808impl From<&str> for ColumnName {
809    fn from(value: &str) -> Self {
810        ColumnName(value.into())
811    }
812}
813
814impl Deref for TableName {
815    type Target = CompactString;
816
817    fn deref(&self) -> &Self::Target {
818        &self.0
819    }
820}
821
822impl<C> Writable<C> for TableName
823where
824    C: Context,
825{
826    #[inline]
827    fn write_to<T: ?Sized + Writer<C>>(&self, writer: &mut T) -> Result<(), <C as Context>::Error> {
828        self.0.as_str().write_to(writer)
829    }
830
831    #[inline]
832    fn bytes_needed(&self) -> Result<usize, <C as Context>::Error> {
833        Writable::<C>::bytes_needed(self.0.as_str())
834    }
835}
836
837impl<'a, C> Readable<'a, C> for TableName
838where
839    C: Context,
840{
841    #[inline]
842    fn read_from<R: Reader<'a, C>>(reader: &mut R) -> Result<Self, <C as Context>::Error> {
843        let s: &'a str = Readable::<'a, C>::read_from(reader)?;
844        Ok(Self(CompactString::new(s)))
845    }
846}
847
848impl FromSql for TableName {
849    fn column_result(value: ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
850        Ok(Self(CompactString::new(value.as_str()?)))
851    }
852}
853
854impl ToSql for TableName {
855    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
856        self.0.as_str().to_sql()
857    }
858}
859
860impl Deref for ColumnName {
861    type Target = CompactString;
862
863    fn deref(&self) -> &Self::Target {
864        &self.0
865    }
866}
867
868impl<C> Writable<C> for ColumnName
869where
870    C: Context,
871{
872    #[inline]
873    fn write_to<T: ?Sized + Writer<C>>(&self, writer: &mut T) -> Result<(), <C as Context>::Error> {
874        self.0.as_str().write_to(writer)
875    }
876
877    #[inline]
878    fn bytes_needed(&self) -> Result<usize, <C as Context>::Error> {
879        Writable::<C>::bytes_needed(self.0.as_str())
880    }
881}
882
883impl<'a, C> Readable<'a, C> for ColumnName
884where
885    C: Context,
886{
887    #[inline]
888    fn read_from<R: Reader<'a, C>>(reader: &mut R) -> Result<Self, <C as Context>::Error> {
889        let s: &'a str = Readable::<'a, C>::read_from(reader)?;
890        Ok(Self(CompactString::new(s)))
891    }
892}
893
894impl FromSql for ColumnName {
895    fn column_result(value: ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
896        Ok(Self(CompactString::new(value.as_str()?)))
897    }
898}
899
900impl ToSql for ColumnName {
901    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
902        self.0.as_str().to_sql()
903    }
904}
905
906#[cfg(test)]
907mod tests {
908    use super::*;
909
910    #[test]
911    fn test_statement_serialization() {
912        let s = serde_json::to_string(&vec![Statement::WithParams(
913            "select 1
914                from table
915                where column = ?"
916                .into(),
917            vec!["my-value".into()],
918        )])
919        .unwrap();
920        println!("{s}");
921
922        let stmts: Vec<Statement> = serde_json::from_str(&s).unwrap();
923        println!("stmts: {stmts:?}");
924
925        let json = r#"[["some statement",[1,"encodedID","nodeName",1,"Name","State",true,true,"",1234,1698084893487,1698084893487]]]"#;
926
927        let value: serde_json::Value = serde_json::from_str(json).unwrap();
928        println!("value: {value:#?}");
929
930        let stmts: Vec<Statement> = serde_json::from_str(json).unwrap();
931        println!("stmts: {stmts:?}");
932
933        let json = r#"[{"query": "some statement", "params": [1,"encodedID","nodeName",1,"Name","State",true,true,"",1234,1698084893487,1698084893487]}]"#;
934        let value: serde_json::Value = serde_json::from_str(json).unwrap();
935        println!("value: {value:#?}");
936
937        let stmts: Vec<Statement> = serde_json::from_str(json).unwrap();
938        println!("stmts: {stmts:?}");
939    }
940}