1pub mod insert;
4pub mod ddl;
5
6pub use ddl::infer_table_ddl;
7pub use insert::serialize_insert;
8
9use std::fmt::{self, Display};
10
11use serde_json::Value as JsonValue;
12
13#[derive(Debug)]
14pub enum SqlSerializeError {
15 InvalidRoot,
16 Message(String),
17}
18
19impl Display for SqlSerializeError {
20 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21 match self {
22 SqlSerializeError::InvalidRoot => {
23 write!(f, "expected struct root for SQL serialization")
24 }
25 SqlSerializeError::Message(msg) => f.write_str(msg),
26 }
27 }
28}
29
30impl std::error::Error for SqlSerializeError {}
31
32impl serde::ser::Error for SqlSerializeError {
33 fn custom<T: Display>(msg: T) -> Self {
34 SqlSerializeError::Message(msg.to_string())
35 }
36}
37
38#[derive(Debug, Clone)]
39pub(crate) struct ColumnDefinition {
40 pub name: String,
41 pub column_type: ColumnType,
42 pub nullable: bool,
43}
44
45#[derive(Debug, Clone, Copy)]
46pub(crate) enum ColumnType {
47 Integer,
48 Real,
49 Text,
50 Json,
51}
52
53impl ColumnType {
54 pub fn sql_type(self) -> &'static str {
55 match self {
56 ColumnType::Integer => "INTEGER",
57 ColumnType::Real => "REAL",
58 ColumnType::Text => "TEXT",
59 ColumnType::Json => "TEXT",
60 }
61 }
62}
63
64pub(crate) fn quote_identifier(value: &str) -> String {
65 let mut quoted = String::with_capacity(value.len() + 2);
66 quoted.push('"');
67 for ch in value.chars() {
68 if ch == '"' {
69 quoted.push('"');
70 }
71 quoted.push(ch);
72 }
73 quoted.push('"');
74 quoted
75}
76
77pub(crate) fn infer_column_type(value: &JsonValue) -> (ColumnType, bool) {
78 match value {
79 JsonValue::Null => (ColumnType::Text, true),
80 JsonValue::Bool(_) => (ColumnType::Integer, false),
81 JsonValue::Number(number) => {
82 if number.is_i64() || number.is_u64() {
83 (ColumnType::Integer, false)
84 } else {
85 (ColumnType::Real, false)
86 }
87 }
88 JsonValue::String(_) => (ColumnType::Text, false),
89 JsonValue::Array(_) | JsonValue::Object(_) => (ColumnType::Json, false),
90 }
91}