use zer_core::{
record::{FieldValue, Record},
schema::Schema,
};
pub fn serialize_pair(a: &Record, b: &Record, schema: &Schema) -> String {
let mut out = String::with_capacity(256);
out.push_str("[CLS]");
append_record(&mut out, a, schema);
out.push_str(" [SEP]");
append_record(&mut out, b, schema);
out.push_str(" [SEP]");
out
}
fn append_record(buf: &mut String, record: &Record, schema: &Schema) {
for field in schema.fields.iter() {
let value = record.get(&field.name);
let display = display_value(value);
buf.push(' ');
buf.push_str("COL:");
buf.push_str(&field.name);
buf.push_str(" VAL:");
buf.push_str(&display);
}
}
fn display_value(value: Option<&FieldValue>) -> String {
match value {
None => String::new(),
Some(v) => match v {
FieldValue::Text(s) => s.clone(),
FieldValue::Int(n) => n.to_string(),
FieldValue::UInt(n) => n.to_string(),
FieldValue::Float(f) => format!("{f:.6}"),
FieldValue::Bool(b) => {
if *b {
"true".into()
} else {
"false".into()
}
}
FieldValue::Bytes(_) => String::new(), FieldValue::Null => String::new(),
},
}
}
#[cfg(test)]
mod tests {
use super::*;
use zer_core::{
record::{FieldValue, Record},
schema::{FieldKind, SchemaBuilder},
};
fn schema() -> Schema {
SchemaBuilder::new()
.field("naam", FieldKind::Name)
.field("geboortedatum", FieldKind::Date)
.build()
.unwrap()
}
#[test]
fn serialize_produces_expected_format() {
let schema = schema();
let a = Record::new(1)
.insert("naam", FieldValue::Text("jan smits".into()))
.insert("geboortedatum", FieldValue::Text("1981-04-02".into()));
let b = Record::new(2)
.insert("naam", FieldValue::Text("jan smyts".into()))
.insert("geboortedatum", FieldValue::Text("1981-04-03".into()));
let s = serialize_pair(&a, &b, &schema);
assert!(
s.contains("COL:naam VAL:jan smits"),
"left record not serialized: {s}"
);
assert!(
s.contains("COL:naam VAL:jan smyts"),
"right record not serialized: {s}"
);
assert!(s.starts_with("[CLS]"), "must start with [CLS]: {s}");
assert!(s.ends_with("[SEP]"), "must end with [SEP]: {s}");
assert_eq!(
s.matches("[SEP]").count(),
2,
"must have exactly two [SEP]: {s}"
);
}
#[test]
fn serialize_null_field_is_empty_val() {
let schema = schema();
let a = Record::new(1).insert("naam", FieldValue::Text("jan".into()));
let b = Record::new(2).insert("naam", FieldValue::Text("jan".into()));
let s = serialize_pair(&a, &b, &schema);
assert!(s.contains("COL:geboortedatum VAL:"), "{s}");
}
#[test]
fn serialize_fields_in_schema_order() {
let schema = schema();
let r = Record::new(1)
.insert("geboortedatum", FieldValue::Text("1981-04-02".into()))
.insert("naam", FieldValue::Text("jan".into()));
let s = serialize_pair(&r, &r, &schema);
let naam_pos = s.find("COL:naam").unwrap();
let dob_pos = s.find("COL:geboortedatum").unwrap();
assert!(
naam_pos < dob_pos,
"naam should come before geboortedatum (schema order): {s}"
);
}
}