aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-11-01 22:32:24 +0100
committertv <tv@krebsco.de>2026-11-01 22:32:24 +0100
commit0a870df1ca78ce732134853a512d958eecf84032 (patch)
treeced395c3aae885b0c97a13ab9dceb340bd68db71
parent422056962f0c53e36d00501d54f710365bc21f65 (diff)
document: create new compound values at once
This speeds up large writes as new maps and lists are created in one batch operation instead of one operation per value.
-rw-r--r--src/document/store.rs40
1 files changed, 29 insertions, 11 deletions
diff --git a/src/document/store.rs b/src/document/store.rs
index 4d9bc74..cc67f77 100644
--- a/src/document/store.rs
+++ b/src/document/store.rs
@@ -1102,17 +1102,15 @@ fn write_value(
value: &JsonValue,
) -> Result<(), StoreError> {
match value {
- JsonValue::Object(object) => {
- let id = put_object(doc, parent, slot, ObjType::Map)?;
- for (child_key, child_value) in object {
- write_value(doc, &id, Slot::Key(child_key), child_value)?;
- }
- }
- JsonValue::Array(items) => {
- let id = put_object(doc, parent, slot, ObjType::List)?;
- for (index, item) in items.iter().enumerate() {
- write_value(doc, &id, Slot::Index(index), item)?;
- }
+ JsonValue::Object(_) | JsonValue::Array(_) => {
+ // A new tree in one go, not an operation at a time.
+ let tree = hydrated(value)?;
+ let (prop, insert): (Prop, bool) = match slot {
+ Slot::Key(key) => (key.into(), false),
+ Slot::Index(index) => (index.into(), true),
+ Slot::At(index) => (index.into(), false),
+ };
+ doc.batch_create_object(parent, prop, &tree, insert)?;
}
scalar => {
let scalar = json_scalar(scalar)?.expect("neither an object nor an array");
@@ -1123,6 +1121,26 @@ fn write_value(
Ok(())
}
+/// `value` as Automerge holds it: maps, lists and scalars as `write_value` stores them.
+fn hydrated(value: &JsonValue) -> Result<automerge::hydrate::Value, StoreError> {
+ use automerge::hydrate;
+ Ok(match value {
+ JsonValue::Object(object) => {
+ let mut map = std::collections::HashMap::new();
+ for (key, value) in object {
+ map.insert(key.clone(), hydrated(value)?);
+ }
+ hydrate::Value::Map(hydrate::Map::from(map))
+ }
+ JsonValue::Array(items) => {
+ hydrate::Value::from(items.iter().map(hydrated).collect::<Result<Vec<_>, _>>()?)
+ }
+ scalar => {
+ hydrate::Value::from(json_scalar(scalar)?.expect("neither an object nor an array"))
+ }
+ })
+}
+
fn json_to_automerge(
doc: &mut impl Transactable,
parent: &ObjId,