Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions PARITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ lowercase `action` names — are language-neutral. Since
[#1131](https://github.com/thekevinscott/dirsql/issues/1131) they live once in
`dirsql::flatten_row_event` (`#[doc(hidden)]`, not a public Rust API); each
binding keeps only the marshaling of the borrowed rows into host values
(`value_row_to_py_dict` / `value_row_to_js`) and its own event struct. No
SDK-visible shape changed — this restores parity rather than introducing drift.
(`value_row_to_py_dict` / `value_row_to_js`) and its own event struct. The
CLI's HTTP `/events` serializer shares that same source, so the SSE payload and
the two SDK event objects cannot drift apart. No SDK-visible shape changed —
this restores parity rather than introducing drift.

The `on_file` callback receives a single argument: the absolute filesystem
path of the matched file. `dirsql` does not read file contents — a callback
Expand Down
7 changes: 7 additions & 0 deletions packages/python/e2e-attestations/claude-1139-sse-flatten.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"command": "just test-e2e",
"ran_at": 1789750671,
"exit_code": 0,
"commit": "5c33ad533545ff8791f462f42b2c3869b871ec7a",
"branch": "claude/1139-sse-flatten"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
**Changed**

The CLI's HTTP `/events` serializer now builds its JSON from
`dirsql::flatten_row_event` instead of its own per-variant `match`, leaving the
core as the single owner of the flattening decisions. The SSE payload is
unchanged byte for byte: same keys, same key order, same null-versus-absent
handling, same blob-to-hex rendering.
82 changes: 36 additions & 46 deletions packages/rust/src/cli/serialize.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
//! `Row` / `RowEvent` → JSON serialization for the HTTP API.

use serde_json::{Map, Value, json};
use serde_json::{Map, Value};

use crate::Row;
use crate::db::Value as CellValue;
use crate::differ::RowEvent;
use crate::row_event_flat::flatten_row_event;

pub(super) fn rows_to_json(rows: &[Row]) -> Vec<Value> {
rows.iter().map(row_to_json).collect()
Expand Down Expand Up @@ -35,52 +36,27 @@ pub(super) fn event_to_json(event: &RowEvent) -> String {
}

fn event_to_value(event: &RowEvent) -> Value {
match event {
RowEvent::Insert {
table,
row,
file_path,
} => json!({
"action": "insert",
"table": table,
"file_path": file_path,
"row": row_to_json(row),
"old_row": Value::Null,
}),
RowEvent::Update {
table,
old_row,
new_row,
file_path,
} => json!({
"action": "update",
"table": table,
"file_path": file_path,
"row": row_to_json(new_row),
"old_row": row_to_json(old_row),
}),
RowEvent::Delete {
table,
row,
file_path,
} => json!({
"action": "delete",
"table": table,
"file_path": file_path,
"row": row_to_json(row),
"old_row": Value::Null,
}),
RowEvent::Error {
table,
file_path,
error,
} => json!({
"action": "error",
"table": table,
"file_path": file_path.to_string_lossy(),
"error": error,
}),
let flat = flatten_row_event(event);
let mut map = Map::new();
map.insert("action".into(), Value::from(flat.action));
map.insert(
"table".into(),
flat.table.map_or(Value::Null, Value::String),
);
map.insert("file_path".into(), Value::String(flat.file_path));
match flat.error {
Some(error) => {
map.insert("error".into(), Value::String(error));
}
None => {
map.insert("row".into(), flat.row.map_or(Value::Null, row_to_json));
map.insert(
"old_row".into(),
flat.old_row.map_or(Value::Null, row_to_json),
);
}
}
Value::Object(map)
}

#[cfg(test)]
Expand Down Expand Up @@ -116,6 +92,7 @@ mod tests {
Some("posts/a.json"),
);
assert!(parsed.get("old_row").unwrap().is_null());
assert!(parsed.get("error").is_none());
assert_eq!(event_to_json(&event), parsed.to_string());
}

Expand Down Expand Up @@ -157,6 +134,19 @@ mod tests {
);
}

#[test]
fn error_event_omits_the_row_keys() {
let event = RowEvent::Error {
table: None,
file_path: PathBuf::from("bad.json"),
error: "parse failed".into(),
};
let parsed = event_to_value(&event);
assert!(parsed.get("table").unwrap().is_null());
assert!(parsed.get("row").is_none());
assert!(parsed.get("old_row").is_none());
}

#[test]
fn delete_event_emits_expected_shape() {
let mut row: Row = HashMap::new();
Expand Down
7 changes: 7 additions & 0 deletions packages/ts/e2e-attestations/claude-1139-sse-flatten.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"command": "pnpm test:e2e",
"ran_at": 1789750728,
"exit_code": 0,
"commit": "7d0bce94d84c7e51ec1e6a2bf005b4a265624456",
"branch": "claude/1139-sse-flatten"
}
Loading