ocs_doc_api: Phase 3 attributes + nested block traversal

- SetAttribute op + GetAttributes/GetBlockEntities queries (append-only).
- backend set_attribute (add/update Insert attribute), attributes (tag,value pairs),
  block_entities (read-only traversal via BlockRecord.entity_handles -> id+kind+bounds).
- facade Entity::set_attribute/attributes, Document::block_entities.
- spec Insert methods; api_reference + binding_schema regenerated; mocks + baseline.
- Query enum: drop Copy (GetBlockEntities carries String).
- Test phase3_attributes_and_block_traversal -> 608 host lib + 3 consistency green.
This commit is contained in:
Sebastian committed 2026-09-06 10:02:23 +02:00
1 parent 2dba0158ca
commit 67655add72
15 files changed
+267 -14

No files matched your search

+21
View File
@@ -27,6 +27,8 @@ pub struct MockBackend {
hatch_boundaries: HashMap<ObjectId, Vec<Vec<[f64; 2]>>>,
/// Stored dimension measurements.
dimension_measurements: HashMap<ObjectId, f64>,
/// Stored insert attributes.
attributes_store: HashMap<ObjectId, Vec<(String, String)>>,
}
impl MockBackend {
@@ -180,6 +182,25 @@ impl DocApiBackend for MockBackend {
fn dimension_measurement(&self, id: ObjectId) -> ApiResult<f64> {
self.dimension_measurements.get(&id).copied().ok_or(ApiError::UnknownId(id))
}
fn set_attribute(&mut self, id: ObjectId, tag: &str, value: &str) -> ApiResult<()> {
if !self.entity_exists(id) {
return Err(ApiError::UnknownId(id));
}
let attrs = self.attributes_store.entry(id).or_default();
if let Some(a) = attrs.iter_mut().find(|(t, _)| t == tag) {
a.1 = value.to_string();
} else {
attrs.push((tag.to_string(), value.to_string()));
}
Ok(())
}
fn attributes(&self, id: ObjectId) -> ApiResult<Vec<(String, String)>> {
self.attributes_store.get(&id).cloned().ok_or(ApiError::UnknownId(id))
}
fn block_entities(&self, _block_name: &str) -> ApiResult<Vec<EntityView>> {
Ok(Vec::new())
}
}
fn add_vertex(&mut self, id: ObjectId, _at: usize, _point: [f64; 3]) -> ApiResult<()> {
if self.entity_exists(id) {
Ok(())