Skip to content

Commit

Permalink
feat: add AttributeFraming overlay and related structures to enhance …
Browse files Browse the repository at this point in the history
…attribute management
olichwiruk committed Jan 16, 2025
1 parent cab0634 commit 0321796
Showing 4 changed files with 188 additions and 1 deletion.
20 changes: 20 additions & 0 deletions semantics/oca-ast/src/ast/mod.rs
Original file line number Diff line number Diff line change
@@ -156,6 +156,7 @@ pub enum OverlayType {
Layout,
Sensitivity,
Link,
AttributeFraming
}

impl Serialize for OverlayType {
@@ -188,6 +189,7 @@ impl Serialize for OverlayType {
OverlayType::Layout => serializer.serialize_str("spec/overlays/layout/1.0"),
OverlayType::Sensitivity => serializer.serialize_str("spec/overlays/sensitivity/1.0"),
OverlayType::Link => serializer.serialize_str("spec/overlays/link/1.0"),
OverlayType::AttributeFraming => serializer.serialize_str("spec/overlays/attribute_framing/1.0"),
}
}
}
@@ -243,6 +245,7 @@ impl FromStr for OverlayType {
"Layout" => Ok(OverlayType::Layout),
"Sensitivity" => Ok(OverlayType::Sensitivity),
"Link" => Ok(OverlayType::Link),
"AttributeFraming" => Ok(OverlayType::AttributeFraming),
_ => Err(()),
}
}
@@ -271,6 +274,7 @@ impl fmt::Display for OverlayType {
OverlayType::Layout => write!(f, "Layout"),
OverlayType::Sensitivity => write!(f, "Sensitivity"),
OverlayType::Link => write!(f, "Link"),
OverlayType::AttributeFraming => write!(f, "AttributeFraming"),
}
}
}
@@ -302,6 +306,7 @@ impl<'de> Deserialize<'de> for OverlayType {
"spec/overlays/layout/1.0" => Ok(OverlayType::Layout),
"spec/overlays/sensitivity/1.0" => Ok(OverlayType::Sensitivity),
"spec/overlays/link/1.0" => Ok(OverlayType::Link),
"spec/overlays/attribute_framing/1.0" => Ok(OverlayType::AttributeFraming),
_ => Err(serde::de::Error::custom(format!(
"unknown overlay type: {}",
s
@@ -771,6 +776,13 @@ impl From<u8> for ObjectKind {
properties: None,
},
),
22 => ObjectKind::Overlay(
OverlayType::AttributeFraming,
Content {
attributes: None,
properties: None,
},
),
_ => panic!("Unknown object type"),
}
}
@@ -801,6 +813,7 @@ impl From<ObjectKind> for u8 {
ObjectKind::Overlay(OverlayType::Layout, _) => 19,
ObjectKind::Overlay(OverlayType::Sensitivity, _) => 20,
ObjectKind::Overlay(OverlayType::Link, _) => 21,
ObjectKind::Overlay(OverlayType::AttributeFraming, _) => 22,
}
}
}
@@ -960,6 +973,13 @@ impl<'de> Deserialize<'de> for ObjectKind {
properties: None,
},
)),
"AttributeFraming" => Ok(ObjectKind::Overlay(
OverlayType::AttributeFraming,
Content {
attributes: None,
properties: None,
},
)),
_ => Err(serde::de::Error::custom(format!(
"unknown object kind: {}",
s
8 changes: 7 additions & 1 deletion semantics/oca-bundle/src/state/attribute.rs
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ use oca_ast_semantics::ast::NestedAttrType;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

use crate::state::{encoding::Encoding, entries::EntriesElement, entry_codes::EntryCodes};
use crate::state::{encoding::Encoding, entries::EntriesElement, entry_codes::EntryCodes, oca::overlay::attribute_framing::Framing};
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Attribute {
pub name: String,
@@ -29,6 +29,7 @@ pub struct Attribute {
pub conformance: Option<String>,
pub standards: Option<Vec<Standard>>,
pub links: Option<HashMap<String, String>>,
pub framings: Option<HashMap<String, Framing>>,
}

impl Default for Attribute {
@@ -60,6 +61,7 @@ impl Attribute {
conformance: None,
standards: None,
links: None,
framings: None,
}
}

@@ -134,6 +136,10 @@ impl Attribute {
if other.links.is_some() {
self.links.clone_from(&other.links);
}

if other.framings.is_some() {
self.framings.clone_from(&other.framings);
}
}
}

2 changes: 2 additions & 0 deletions semantics/oca-bundle/src/state/oca/overlay.rs
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@ pub mod standard;
pub mod subset;
pub mod unit;
pub mod link;
pub mod attribute_framing;

pub use self::attribute_mapping::AttributeMappingOverlay as AttributeMapping;
pub use self::cardinality::CardinalityOverlay as Cardinality;
@@ -32,6 +33,7 @@ pub use self::meta::MetaOverlay as Meta;
pub use self::standard::StandardOverlay as Standard;
pub use self::subset::SubsetOverlay as Subset;
pub use self::link::LinkOverlay as Link;
pub use self::attribute_framing::AttributeFramingOverlay as AttributeFraming;
pub use oca_ast_semantics::ast::OverlayType;
use said::derivation::HashFunctionCode;

159 changes: 159 additions & 0 deletions semantics/oca-bundle/src/state/oca/overlay/attribute_framing.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
use crate::state::{attribute::Attribute, oca::Overlay};
use isolang::Language;
use oca_ast_semantics::ast::OverlayType;
use said::derivation::HashFunctionCode;
use said::{sad::SerializationFormats, sad::SAD};
use serde::{ser::SerializeMap, Deserialize, Serialize, Serializer};
use std::any::Any;
use std::collections::HashMap;

pub type Framing = HashMap<String, FramingScope>;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct FramingScope {
pub predicate_id: String,
pub framing_justification: String,
}

pub trait Framings {
fn set_framing(&mut self, id: String, framing: Framing);
}

impl Framings for Attribute {
fn set_framing(&mut self, id: String, framing: Framing) {
match self.framings {
Some(ref mut framings) => {
if let Some(f) = framings.get_mut(&id) {
f.extend(framing);
} else {
framings.insert(id, framing);
}
}
None => {
let mut framings = HashMap::new();
framings.insert(id, framing);
self.framings = Some(framings);
}
}
}
}

pub fn serialize_framing<S>(
attributes: &HashMap<String, Framing>,
s: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
use std::collections::BTreeMap;

let mut ser = s.serialize_map(Some(attributes.len()))?;
let sorted_attributes: BTreeMap<_, _> = attributes.iter().collect();
for (k, v) in sorted_attributes {
let sorted_framings: BTreeMap<_, _> = v.iter().collect();
ser.serialize_entry(k, &sorted_framings)?;
}
ser.end()
}

#[derive(SAD, Serialize, Deserialize, Debug, Clone)]
pub struct AttributeFramingOverlay {
#[said]
#[serde(rename = "d")]
said: Option<said::SelfAddressingIdentifier>,
capture_base: Option<said::SelfAddressingIdentifier>,
#[serde(rename = "type")]
overlay_type: OverlayType,
#[serde(rename = "framing_metadata")]
pub metadata: HashMap<String, String>,
#[serde(serialize_with = "serialize_framing")]
pub attribute_framing: HashMap<String, Framing>,
}

impl Overlay for AttributeFramingOverlay {
fn as_any(&self) -> &dyn Any {
self
}
fn capture_base(&self) -> &Option<said::SelfAddressingIdentifier> {
&self.capture_base
}
fn set_capture_base(&mut self, said: &said::SelfAddressingIdentifier) {
self.capture_base = Some(said.clone());
}
fn overlay_type(&self) -> &OverlayType {
&self.overlay_type
}
fn said(&self) -> &Option<said::SelfAddressingIdentifier> {
&self.said
}
fn language(&self) -> Option<&Language> {
None
}
fn attributes(&self) -> Vec<&String> {
self.attribute_framing.keys().collect::<Vec<&String>>()
}
/// Add an attribute to the Label Overlay
/// TODO add assignment of attribute to category
fn add(&mut self, attribute: &Attribute) {
if let Some(id) = self.metadata.get("frame_id") {
if let Some(framing) = &attribute.framings {
if let Some(value) = framing.get(id) {
self.attribute_framing
.insert(attribute.name.clone(), value.clone());
}
}
}
}
}

impl AttributeFramingOverlay {
pub fn new(id: String) -> Self {
let mut metadata = HashMap::new();
metadata.insert("frame_id".to_string(), id);
Self {
capture_base: None,
said: None,
overlay_type: OverlayType::AttributeFraming,
metadata,
attribute_framing: HashMap::new(),
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn create_attribute_framing_overlay() {
let mut overlay = AttributeFramingOverlay::new("frame_id".to_string());
let mut loc1 = HashMap::new();
loc1.insert(
"http://loc.1".to_string(),
FramingScope {
predicate_id: "skos:exactMatch".to_string(),
framing_justification: "semapv:ManualMappingCuration"
.to_string(),
},
);
let mut loc2 = HashMap::new();
loc2.insert(
"http://loc.2".to_string(),
FramingScope {
predicate_id: "skos:exactMatch".to_string(),
framing_justification: "semapv:ManualMappingCuration"
.to_string(),
},
);
let attr = cascade! {
Attribute::new("attr1".to_string());
..set_framing("frame_id".to_string(), loc1);
..set_framing("frame_id".to_string(), loc2);
};
// even that attribute has 2 lagnuage only one attribute should be added to the overlay according to it's language
overlay.add(&attr);

assert_eq!(overlay.overlay_type, OverlayType::AttributeFraming);
assert_eq!(overlay.attribute_framing.len(), 1);
}
}

0 comments on commit 0321796

Please sign in to comment.