Initial commit

Change-Id: I2b916ff0acd2a88aeef709cf4f900503e823d44d
diff --git a/client/src/schema.rs b/client/src/schema.rs
new file mode 100644
index 0000000..f17e757
--- /dev/null
+++ b/client/src/schema.rs
@@ -0,0 +1,120 @@
+use serde::de::{self, SeqAccess, Visitor};
+use serde::{Deserialize, Deserializer, Serialize};
+use std::collections::HashMap;
+use std::fmt;
+use std::marker::PhantomData;
+
+#[derive(Debug, Deserialize)]
+pub struct DatabaseSchema {
+    pub name: String,
+
+    pub version: String,
+
+    #[serde(rename = "cksum")]
+    pub checksum: Option<String>,
+
+    pub tables: HashMap<String, TableSchema>,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct TableSchema {
+    pub columns: HashMap<String, ColumnSchema>,
+
+    #[serde(rename = "maxRows")]
+    pub max_rows: Option<u64>,
+
+    #[serde(rename = "isRoot")]
+    pub is_root: Option<bool>,
+
+    #[serde(rename = "indexes")]
+    pub indexes: Option<Vec<Vec<String>>>,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct ColumnSchema {
+    pub r#type: serde_json::Value,
+
+    #[serde(rename = "ephemeral")]
+    pub ephemeral: Option<bool>,
+
+    #[serde(rename = "mutable")]
+    pub mutable: Option<bool>,
+}
+
+#[derive(Debug, Default, Deserialize, Serialize)]
+pub struct MonitorRequest {
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub columns: Option<Vec<String>>,
+
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub select: Option<MonitorRequestSelect>,
+}
+
+#[derive(Debug, Deserialize, Serialize)]
+pub struct MonitorRequestSelect {
+    initial: Option<bool>,
+    insert: Option<bool>,
+    delete: Option<bool>,
+    modify: Option<bool>,
+}
+
+pub type TableUpdate<T> = HashMap<String, TableUpdateRows<T>>;
+pub type TableUpdateRows<T> = HashMap<String, T>;
+
+#[derive(Debug, Deserialize)]
+pub struct RowUpdate<T> {
+    pub old: Option<T>,
+    pub new: Option<T>,
+}
+
+#[derive(Debug)]
+pub struct UpdateNotification<T> {
+    pub id: Option<String>,
+    pub message: TableUpdate<T>,
+}
+
+impl<'de, T> Deserialize<'de> for UpdateNotification<T>
+where
+    T: Deserialize<'de>,
+{
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        // Define a visitor that carries a PhantomData for T.
+        struct UpdateNotificationVisitor<T> {
+            marker: PhantomData<T>,
+        }
+
+        impl<'de, T> Visitor<'de> for UpdateNotificationVisitor<T>
+        where
+            T: Deserialize<'de>,
+        {
+            type Value = UpdateNotification<T>;
+
+            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+                formatter
+                    .write_str("an array with two elements: Option<String> and a TableUpdate<T>")
+            }
+
+            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
+            where
+                A: SeqAccess<'de>,
+            {
+                let id: Option<String> = seq
+                    .next_element()?
+                    .ok_or_else(|| de::Error::invalid_length(0, &self))?;
+                let message: TableUpdate<T> = seq
+                    .next_element()?
+                    .ok_or_else(|| de::Error::invalid_length(1, &self))?;
+
+                Ok(UpdateNotification { id, message })
+            }
+        }
+
+        // Start deserializing using the visitor.
+        deserializer.deserialize_seq(UpdateNotificationVisitor {
+            marker: PhantomData,
+        })
+    }
+}