1use crate::error::{KitError, Result};
4use mongreldb_core::memtable::Value as CoreValue;
5use mongreldb_core::schema::{
6 ColumnDef, ColumnFlags, IndexDef, IndexKind, Schema as CoreSchema, TypeId,
7};
8use mongreldb_kit_core::schema::{
9 Column, ColumnType, IndexKind as KitIndexKind, Table as KitTable,
10};
11use serde_json::{Map, Value};
12
13pub fn to_core_schema(table: &KitTable) -> CoreSchema {
15 let columns: Vec<ColumnDef> = table
16 .columns
17 .iter()
18 .map(|c| ColumnDef {
19 id: c.id as u16,
20 name: c.name.clone(),
21 ty: match c.storage_type {
22 ColumnType::Embedding => TypeId::Embedding {
23 dim: c.embedding_dim.unwrap_or(0),
24 },
25 other => to_core_type(other),
26 },
27 flags: to_core_flags(table, c),
28 })
29 .collect();
30
31 let mut indexes: Vec<IndexDef> = Vec::new();
32 for idx in &table.indexes {
33 let kind = match idx.kind {
34 KitIndexKind::Bitmap => IndexKind::Bitmap,
35 KitIndexKind::Fm => IndexKind::FmIndex,
36 KitIndexKind::Ann => IndexKind::Ann,
37 KitIndexKind::Sparse => IndexKind::Sparse,
38 KitIndexKind::MinHash => IndexKind::MinHash,
39 KitIndexKind::LearnedRange => IndexKind::LearnedRange,
40 };
41 for col_name in &idx.columns {
42 if let Some(col) = table.column(col_name) {
43 indexes.push(IndexDef {
44 name: format!("{}_{}", idx.name, col_name),
45 column_id: col.id as u16,
46 kind,
47 predicate: None,
48 });
49 }
50 }
51 }
52 for uq in &table.unique_constraints {
53 for col_name in &uq.columns {
54 if let Some(col) = table.column(col_name) {
55 indexes.push(IndexDef {
56 name: format!("uq_{}_{}", uq.name, col_name),
57 column_id: col.id as u16,
58 kind: IndexKind::Bitmap,
59 predicate: None,
60 });
61 }
62 }
63 }
64
65 CoreSchema {
66 schema_id: table.id as u64,
67 columns,
68 indexes,
69 colocation: Vec::new(),
70 constraints: Default::default(),
71 clustered: false,
72 }
73}
74
75pub(crate) fn to_core_flags(table: &KitTable, column: &Column) -> ColumnFlags {
76 let mut flags = ColumnFlags::empty();
77 if column.nullable {
78 flags = flags.with(ColumnFlags::NULLABLE);
79 }
80 if table.primary_key.contains(&column.name) || column.primary_key {
81 flags = flags.with(ColumnFlags::PRIMARY_KEY);
82 }
83 if column.encrypted {
84 flags = flags.with(ColumnFlags::ENCRYPTED);
85 }
86 if column.encrypted_indexable {
87 flags = flags.with(ColumnFlags::ENCRYPTED_INDEXABLE);
88 }
89 flags
90}
91
92pub(crate) fn to_core_type(ty: ColumnType) -> TypeId {
93 match ty {
94 ColumnType::Bool => TypeId::Bool,
95 ColumnType::Int8 | ColumnType::Int16 | ColumnType::Int32 | ColumnType::Int64 => {
96 TypeId::Int64
97 }
98 ColumnType::Float32 | ColumnType::Float64 => TypeId::Float64,
99 ColumnType::Text
100 | ColumnType::Bytes
101 | ColumnType::Json
102 | ColumnType::Date
103 | ColumnType::DateTime => TypeId::Bytes,
104 ColumnType::TimestampNanos => TypeId::Int64,
105 ColumnType::Date64 => TypeId::Date64,
106 ColumnType::Time64 => TypeId::Time64,
107 ColumnType::Interval => TypeId::Interval,
108 ColumnType::Decimal128 => TypeId::Decimal128 {
109 precision: 38,
110 scale: 2,
111 },
112 ColumnType::Embedding => TypeId::Embedding { dim: 0 },
115 ColumnType::Sparse => TypeId::Bytes,
118 }
119}
120
121pub fn json_to_core(value: &Value, ty: ColumnType) -> Result<CoreValue> {
123 Ok(match value {
124 Value::Null => CoreValue::Null,
125 Value::Bool(b) => CoreValue::Bool(*b),
126 Value::Number(n) => {
127 if let Some(i) = n.as_i64() {
128 CoreValue::Int64(i)
129 } else {
130 CoreValue::Float64(n.as_f64().unwrap_or(f64::NAN))
131 }
132 }
133 Value::String(s) => CoreValue::Bytes(s.as_bytes().to_vec()),
134 Value::Array(arr) => {
135 if ty == ColumnType::Sparse {
136 let mut terms: Vec<(u32, f32)> = Vec::with_capacity(arr.len());
137 for pair in arr {
138 let p = pair
139 .as_array()
140 .ok_or_else(|| KitError::Validation("sparse expects pairs".into()))?;
141 let token =
142 p.first().and_then(|v| v.as_u64()).ok_or_else(|| {
143 KitError::Validation("sparse token must be u32".into())
144 })? as u32;
145 let weight = p.get(1).and_then(|v| v.as_f64()).ok_or_else(|| {
146 KitError::Validation("sparse weight must be number".into())
147 })? as f32;
148 terms.push((token, weight));
149 }
150 CoreValue::Bytes(
151 bincode::serialize(&terms).map_err(|e| KitError::Validation(e.to_string()))?,
152 )
153 } else if ty == ColumnType::Embedding {
154 let mut vec = Vec::with_capacity(arr.len());
155 for v in arr {
156 match v.as_f64() {
157 Some(f) => vec.push(f as f32),
158 None => {
159 return Err(KitError::Validation("embedding expects numbers".into()))
160 }
161 }
162 }
163 CoreValue::Embedding(vec)
164 } else if ty == ColumnType::Bytes {
165 let mut bytes = Vec::with_capacity(arr.len());
166 for v in arr {
167 match v {
168 Value::Number(n) => bytes.push(n.as_i64().unwrap_or(0) as u8),
169 _ => return Err(KitError::Validation("bytes array expected".into())),
170 }
171 }
172 CoreValue::Bytes(bytes)
173 } else {
174 CoreValue::Bytes(serde_json::to_vec(value)?)
175 }
176 }
177 Value::Object(_) => CoreValue::Bytes(serde_json::to_vec(value)?),
178 })
179}
180
181pub fn core_to_json(value: &CoreValue, ty: ColumnType) -> Result<Value> {
183 Ok(match (value, ty) {
184 (CoreValue::Null, _) => Value::Null,
185 (CoreValue::Bool(b), _) => Value::Bool(*b),
186 (CoreValue::Int64(i), ColumnType::Int8) => Value::Number((*i as i8).into()),
187 (CoreValue::Int64(i), ColumnType::Int16) => Value::Number((*i as i16).into()),
188 (CoreValue::Int64(i), ColumnType::Int32) => Value::Number((*i as i32).into()),
189 (CoreValue::Int64(i), ColumnType::Int64) => Value::Number((*i).into()),
190 (CoreValue::Int64(i), ColumnType::TimestampNanos) => Value::Number((*i).into()),
191 (CoreValue::Int64(i), _) => Value::Number((*i).into()),
192 (CoreValue::Float64(f), ColumnType::Float32) => serde_json::to_value(*f as f32)?,
193 (CoreValue::Float64(f), _) => serde_json::to_value(*f)?,
194 (CoreValue::Bytes(b), ColumnType::Sparse) => {
195 let terms: Vec<(u32, f32)> =
196 bincode::deserialize(b).map_err(|e| KitError::Validation(e.to_string()))?;
197 Value::Array(
198 terms
199 .into_iter()
200 .map(|(t, w)| Value::Array(vec![Value::from(t), Value::from(w as f64)]))
201 .collect(),
202 )
203 }
204 (CoreValue::Bytes(b), ColumnType::Bytes) => {
205 Value::Array(b.iter().map(|x| Value::Number((*x).into())).collect())
206 }
207 (CoreValue::Bytes(b), _) => match std::str::from_utf8(b) {
208 Ok(s) => Value::String(s.to_string()),
209 Err(_) => Value::Array(b.iter().map(|x| Value::Number((*x).into())).collect()),
210 },
211 (CoreValue::Embedding(v), _) => serde_json::to_value(v)?,
212 (CoreValue::Decimal(d), _) => Value::String(d.to_string()),
213 (
214 CoreValue::Interval {
215 months,
216 days,
217 nanos,
218 },
219 _,
220 ) => {
221 serde_json::json!({ "months": months, "days": days, "nanos": nanos })
222 }
223 })
224}
225
226pub fn core_row_to_json(row: &mongreldb_core::memtable::Row, table: &KitTable) -> Result<Row> {
228 let mut values = Map::new();
229 for col in &table.columns {
230 let v = row
231 .columns
232 .get(&(col.id as u16))
233 .cloned()
234 .unwrap_or(CoreValue::Null);
235 values.insert(col.name.clone(), core_to_json(&v, col.storage_type)?);
236 }
237 Ok(Row {
238 row_id: row.row_id.0,
239 values,
240 })
241}
242
243#[derive(Debug, Clone, PartialEq)]
245pub struct Row {
246 pub row_id: u64,
247 pub values: Map<String, Value>,
248}
249
250impl Row {
251 pub fn pk(&self, table: &KitTable) -> Option<Value> {
256 if table.primary_key.len() == 1 {
257 self.values.get(&table.primary_key[0]).cloned()
258 } else {
259 let mut obj = Map::new();
260 for name in &table.primary_key {
261 obj.insert(
262 name.clone(),
263 self.values.get(name).cloned().unwrap_or(Value::Null),
264 );
265 }
266 Some(Value::Object(obj))
267 }
268 }
269}
270
271pub fn pk_value(values: &Map<String, Value>, table: &KitTable) -> Option<Value> {
273 if table.primary_key.len() == 1 {
274 values.get(&table.primary_key[0]).cloned()
275 } else {
276 let mut obj = Map::new();
277 for name in &table.primary_key {
278 obj.insert(
279 name.clone(),
280 values.get(name).cloned().unwrap_or(Value::Null),
281 );
282 }
283 Some(Value::Object(obj))
284 }
285}
286
287pub fn pk_to_map(pk: &Value, table: &KitTable) -> Result<Map<String, Value>> {
289 let mut map = Map::new();
290 match pk {
291 Value::Object(obj) => {
292 for name in &table.primary_key {
293 let v = obj
294 .get(name)
295 .cloned()
296 .ok_or_else(|| KitError::Validation(format!("missing pk column {name}")))?;
297 map.insert(name.clone(), v);
298 }
299 }
300 scalar if table.primary_key.len() == 1 => {
301 map.insert(table.primary_key[0].clone(), scalar.clone());
302 }
303 _ => {
304 return Err(KitError::Validation(
305 "primary key value shape mismatch".into(),
306 ))
307 }
308 }
309 Ok(map)
310}
311
312pub fn row_to_core_cells(
314 values: &Map<String, Value>,
315 table: &KitTable,
316) -> Result<Vec<(u16, CoreValue)>> {
317 let mut cells = Vec::with_capacity(table.columns.len());
318 for col in &table.columns {
319 let v = values.get(&col.name).cloned().unwrap_or(Value::Null);
320 cells.push((col.id as u16, json_to_core(&v, col.storage_type)?));
321 }
322 Ok(cells)
323}