use crate::{
add_value, compact_collection_with, compact_iri, compact_iri_with, compact_key, value_value,
CompactFragment, CompactIndexedFragment, Error, MetaError, Options,
};
use json_ld_context_processing::ProcessMeta;
use json_ld_core::{
context::Nest,
object::{self, List},
Container, ContainerKind, Context, ContextLoader, Id, Indexed, Loader, Node, Object, Term,
};
use json_ld_syntax::Keyword;
use locspan::Meta;
use rdf_types::VocabularyMut;
use std::hash::Hash;
async fn compact_property_list<I, B, M, C, N, L>(
vocabulary: &mut N,
Meta(list, meta): Meta<&List<I, B, M>, &M>,
expanded_index: Option<&json_ld_syntax::Entry<String, M>>,
nest_result: &mut json_syntax::Object<M>,
container: Container,
as_array: bool,
item_active_property: Meta<&str, &M>,
active_context: &Context<I, B, C, M>,
loader: &mut L,
options: Options,
) -> Result<(), MetaError<M, L::ContextError>>
where
N: Send + Sync + VocabularyMut<Iri = I, BlankId = B>,
I: Clone + Hash + Eq + Send + Sync,
B: Clone + Hash + Eq + Send + Sync,
M: Clone + Send + Sync,
C: ProcessMeta<I, B, M>,
L: Loader<I, M> + ContextLoader<I, M> + Send + Sync,
L::Context: Into<C>,
{
let mut compacted_item = compact_collection_with(
vocabulary,
Meta(list.iter(), meta),
active_context,
active_context,
Some(item_active_property),
loader,
options,
)
.await?;
if !compacted_item.is_array() {
let array = vec![compacted_item];
compacted_item = Meta(json_syntax::Value::Array(array), meta.clone())
}
if !container.contains(ContainerKind::List) {
let key = compact_key(
vocabulary,
active_context,
Meta(&Term::Keyword(Keyword::List), meta),
true,
false,
options,
)
.map_err(Meta::cast)?;
let mut compacted_item_list_object = json_syntax::Object::default();
compacted_item_list_object.insert(key.unwrap(), compacted_item);
if let Some(index) = expanded_index {
let key = compact_key(
vocabulary,
active_context,
Meta(&Term::Keyword(Keyword::Index), &index.key_metadata),
true,
false,
options,
)
.map_err(Meta::cast)?;
let Meta(index_value, meta) = &index.value;
compacted_item_list_object.insert(
key.unwrap(),
Meta(
json_syntax::Value::String(index_value.as_str().into()),
meta.clone(),
),
);
}
compacted_item = Meta(
json_syntax::Value::Object(compacted_item_list_object),
meta.clone(),
);
add_value(nest_result, item_active_property, compacted_item, as_array)
} else {
nest_result.insert(
Meta(
item_active_property.0.into(),
item_active_property.1.clone(),
),
compacted_item,
);
}
Ok(())
}
async fn compact_property_graph<I, B, M, C, N, L>(
vocabulary: &mut N,
Meta(node, meta): Meta<&Node<I, B, M>, &M>,
expanded_index: Option<&json_ld_syntax::Entry<String, M>>,
nest_result: &mut json_syntax::Object<M>,
container: Container,
as_array: bool,
item_active_property: Meta<&str, &M>,
active_context: &Context<I, B, C, M>,
loader: &mut L,
options: Options,
) -> Result<(), MetaError<M, L::ContextError>>
where
N: Send + Sync + VocabularyMut<Iri = I, BlankId = B>,
I: Clone + Hash + Eq + Send + Sync,
B: Clone + Hash + Eq + Send + Sync,
M: Clone + Send + Sync,
C: ProcessMeta<I, B, M>,
L: Loader<I, M> + ContextLoader<I, M> + Send + Sync,
L::Context: Into<C>,
{
let mut compacted_item = node
.graph()
.unwrap()
.compact_fragment_full(
vocabulary,
active_context,
active_context,
Some(item_active_property),
loader,
options,
)
.await?;
if container.contains(ContainerKind::Graph) && container.contains(ContainerKind::Id) {
if nest_result
.get_unique(*item_active_property)
.ok()
.unwrap()
.is_none()
{
nest_result.insert(
Meta(
item_active_property.0.into(),
item_active_property.1.clone(),
),
Meta(json_ld_syntax::Object::default().into(), meta.clone()),
);
}
let map_object = nest_result
.get_unique_mut(*item_active_property)
.ok()
.unwrap()
.unwrap();
let map_object = map_object.as_object_mut().unwrap();
let (id_value, vocab): (Meta<Term<I, B>, M>, bool) = match node.id_entry() {
Some(entry) => (entry.value.clone().cast(), false),
None => (Meta(Term::Keyword(Keyword::None), meta.clone()), true),
};
let map_key = compact_iri(
vocabulary,
active_context,
id_value.borrow(),
vocab,
false,
options,
)
.map_err(Meta::cast)?
.unwrap();
add_value(
map_object,
map_key.borrow().map(String::as_str),
compacted_item,
as_array,
)
} else if container.contains(ContainerKind::Graph)
&& container.contains(ContainerKind::Index)
&& node.is_simple_graph()
{
if nest_result
.get_unique(*item_active_property)
.ok()
.unwrap()
.is_none()
{
nest_result.insert(
Meta(
item_active_property.0.into(),
item_active_property.1.clone(),
),
Meta(json_ld_syntax::Object::default().into(), meta.clone()),
);
}
let map_object = nest_result
.get_unique_mut(*item_active_property)
.ok()
.unwrap()
.unwrap();
let map_object = map_object.as_object_mut().unwrap();
let map_key = expanded_index
.map(|e| e.value.borrow().map(String::as_str))
.unwrap_or_else(|| Meta("@none", meta));
add_value(map_object, map_key, compacted_item, as_array)
} else if container.contains(ContainerKind::Graph) && node.is_simple_graph() {
compacted_item = match compacted_item {
Meta(json_syntax::Value::Array(items), items_meta) if items.len() > 1 => {
let key = compact_iri(
vocabulary,
active_context,
Meta(&Term::Keyword(Keyword::Included), &items_meta),
true,
false,
options,
)
.map_err(Meta::cast)?
.unwrap();
let mut map = json_syntax::Object::default();
map.insert(
key.cast(),
Meta(json_syntax::Value::Array(items), items_meta.clone()),
);
Meta(json_syntax::Value::Object(map), items_meta)
}
item => item,
};
add_value(nest_result, item_active_property, compacted_item, as_array)
} else {
let key = compact_iri(
vocabulary,
active_context,
Meta(&Term::Keyword(Keyword::Graph), meta),
true,
false,
options,
)
.map_err(Meta::cast)?
.unwrap();
let mut map = json_syntax::Object::default();
map.insert(key.cast(), compacted_item);
if let Some(id_entry) = node.id_entry() {
let key = compact_iri(
vocabulary,
active_context,
Meta(&Term::Keyword(Keyword::Id), &id_entry.key_metadata),
false,
false,
options,
)
.map_err(Meta::cast)?
.unwrap();
let id: Meta<Term<I, B>, M> = id_entry.value.clone().cast();
let value = compact_iri(
vocabulary,
active_context,
id.borrow(),
false,
false,
options,
)
.map_err(Meta::cast)?;
map.insert(
key.cast(),
match value {
Some(s) => s.cast(),
None => Meta(json_syntax::Value::Null, meta.clone()),
},
);
}
if let Some(index_entry) = expanded_index {
let key = compact_iri(
vocabulary,
active_context,
Meta(&Term::Keyword(Keyword::Index), &index_entry.key_metadata),
true,
false,
options,
)
.map_err(Meta::cast)?
.unwrap();
map.insert(key.cast(), index_entry.value.clone().cast());
}
let compacted_item = Meta(json_syntax::Value::Object(map), meta.clone());
add_value(nest_result, item_active_property, compacted_item, as_array)
}
Ok(())
}
fn select_nest_result<'a, I, B, M, C, E>(
result: &'a mut json_syntax::Object<M>,
active_context: &Context<I, B, C, M>,
item_active_property: Meta<&str, &M>,
compact_arrays: bool,
) -> Result<(&'a mut json_syntax::Object<M>, Container, bool), MetaError<M, E>>
where
I: Clone + Hash + Eq + Send + Sync,
B: Clone + Hash + Eq + Send + Sync,
M: Clone + Send + Sync,
{
let (nest_result, container) = match active_context.get(*item_active_property) {
Some(term_definition) => {
let nest_result = match term_definition.nest() {
Some(nest_term) => {
if *nest_term.value != Nest::Nest {
match active_context.get(nest_term.as_str()) {
Some(term_def)
if term_def.value() == Some(&Term::Keyword(Keyword::Nest)) => {}
_ => {
return Err(Meta(
Error::InvalidNestValue,
nest_term.key_metadata.clone(),
))
}
}
}
let meta = nest_term.key_metadata.clone();
if result
.get_unique(nest_term.as_str())
.ok()
.unwrap()
.is_none()
{
result.insert(
nest_term.value.clone().map(|k| k.as_str().into()),
Meta(json_syntax::Object::default().into(), meta),
);
}
let value = result
.get_unique_mut(nest_term.as_str())
.ok()
.unwrap()
.unwrap();
let sub_object = value.as_object_mut().unwrap();
sub_object
}
None => {
result
}
};
(nest_result, term_definition.container())
}
None => (result, Container::None),
};
let as_array = if container.contains(ContainerKind::Set)
|| *item_active_property == "@graph"
|| *item_active_property == "@list"
{
true
} else {
!compact_arrays
};
Ok((nest_result, container, as_array))
}
pub async fn compact_property<'a, T, O, I, B, M, C, N, L>(
vocabulary: &mut N,
result: &mut json_syntax::Object<M>,
expanded_property: Meta<Term<I, B>, M>,
expanded_value: O,
active_context: &Context<I, B, C, M>,
loader: &mut L,
inside_reverse: bool,
options: Options,
) -> Result<(), MetaError<M, L::ContextError>>
where
T: 'a + object::Any<I, B, M> + Sync + Send,
O: IntoIterator<Item = &'a Meta<Indexed<T, M>, M>>,
N: Send + Sync + VocabularyMut<Iri = I, BlankId = B>,
I: Clone + Hash + Eq + Send + Sync,
B: Clone + Hash + Eq + Send + Sync,
M: 'a + Clone + Send + Sync,
C: ProcessMeta<I, B, M>,
L: Loader<I, M> + ContextLoader<I, M> + Send + Sync,
L::Context: Into<C>,
{
let mut is_empty = true;
for expanded_item in expanded_value {
is_empty = false;
let item_active_property = compact_iri_with(
vocabulary,
active_context,
Meta(&expanded_property.0, &expanded_property.1),
expanded_item,
true,
inside_reverse,
options,
)
.map_err(Meta::cast)?;
if let Some(item_active_property) = item_active_property {
let (nest_result, container, as_array) = select_nest_result(
result,
active_context,
item_active_property.borrow().map(String::as_str),
options.compact_arrays,
)?;
match expanded_item.inner().as_ref() {
object::Ref::List(list) => {
compact_property_list(
vocabulary,
Meta(list, expanded_item.metadata()),
expanded_item.index_entry(),
nest_result,
container,
as_array,
item_active_property.borrow().map(String::as_str),
active_context,
loader,
options,
)
.await?
}
object::Ref::Node(node) if node.is_graph() => {
compact_property_graph(
vocabulary,
Meta(node, expanded_item.metadata()),
expanded_item.index_entry(),
nest_result,
container,
as_array,
item_active_property.borrow().map(String::as_str),
active_context,
loader,
options,
)
.await?
}
_ => {
let mut compacted_item = expanded_item
.compact_fragment_full(
vocabulary,
active_context,
active_context,
Some(item_active_property.borrow().map(String::as_str)),
loader,
options,
)
.await?;
if !container.contains(ContainerKind::Graph)
&& (container.contains(ContainerKind::Language)
|| container.contains(ContainerKind::Index)
|| container.contains(ContainerKind::Id)
|| container.contains(ContainerKind::Type))
{
if nest_result
.get_unique(item_active_property.as_str())
.ok()
.unwrap()
.is_none()
{
let meta = item_active_property.metadata().clone();
nest_result.insert(
item_active_property.clone().cast(),
Meta(json_syntax::Object::default().into(), meta),
);
}
let map_object = nest_result
.get_unique_mut(item_active_property.as_str())
.ok()
.unwrap()
.unwrap();
let map_object = map_object.as_object_mut().unwrap();
let container_type = if container.contains(ContainerKind::Language) {
ContainerKind::Language
} else if container.contains(ContainerKind::Index) {
ContainerKind::Index
} else if container.contains(ContainerKind::Id) {
ContainerKind::Id
} else {
ContainerKind::Type
};
let mut container_key = compact_iri(
vocabulary,
active_context,
Meta(
&Term::Keyword(container_type.into()),
compacted_item.metadata(),
),
true,
false,
options,
)
.map_err(Meta::cast)?;
let index_key = match active_context.get(item_active_property.as_str()) {
Some(def) if def.index().is_some() => def.index(),
_ => None,
};
let map_key = if container_type == ContainerKind::Language
&& expanded_item.is_value()
{
if let object::Ref::Value(value) = expanded_item.inner().as_ref() {
compacted_item = value_value(value, expanded_item.metadata())
}
expanded_item.language().map(|lang| {
Meta(lang.to_string(), expanded_item.metadata().clone())
})
} else if container_type == ContainerKind::Index {
match index_key {
Some(index_key) => {
container_key = compact_iri(
vocabulary,
active_context,
Meta(
&Term::Id(Id::Invalid(index_key.to_string())),
index_key.metadata(),
),
true,
false,
options,
)
.map_err(Meta::cast)?;
let (map_key, remaining_values) = match compacted_item
.value_mut()
{
json_syntax::Value::Object(map) => {
match map
.remove_unique(
container_key.as_ref().unwrap().as_str(),
)
.ok()
.unwrap()
{
Some(entry) => match entry.value {
Meta(json_syntax::Value::String(s), meta) => (
Some(Meta(s.to_string(), meta.clone())),
Vec::new(),
),
Meta(json_syntax::Value::Array(values), _) => {
let mut values = values.into_iter();
match values.next() {
Some(first_value) => (
first_value.as_str().map(|v| {
Meta(
v.to_string(),
first_value
.metadata()
.clone(),
)
}),
values.collect(),
),
None => (None, values.collect()),
}
}
other => (None, vec![other]),
},
None => (None, Vec::new()),
}
}
_ => (None, Vec::new()),
};
if !remaining_values.is_empty() {
if let Some(map) = compacted_item.as_object_mut() {
for value in remaining_values {
add_value(
map,
container_key
.as_ref()
.unwrap()
.borrow()
.map(String::as_str),
value,
false,
)
}
}
}
map_key
}
None => {
expanded_item.index_entry().map(|entry| {
Meta(entry.value.to_string(), entry.metadata().clone())
})
}
}
} else if container_type == ContainerKind::Id {
compacted_item
.as_object_mut()
.and_then(|map| {
map.remove_unique(container_key.unwrap().as_str())
.ok()
.unwrap()
.map(|entry| {
entry.value.as_str().map(|s| {
Meta(s.to_string(), entry.value.metadata().clone())
})
})
})
.flatten()
} else {
let (map_key, remaining_values) = match compacted_item.as_object_mut() {
Some(map) => {
match map
.remove_unique(container_key.as_ref().unwrap().as_str())
.ok()
.unwrap()
{
Some(entry) => match entry.value {
Meta(json_syntax::Value::String(s), meta) => (
Some(Meta((*s).to_string(), meta.clone())),
Vec::new(),
),
Meta(json_syntax::Value::Array(values), _) => {
let mut values = values.into_iter();
match values.next() {
Some(first_value) => (
first_value.as_str().map(|v| {
Meta(
v.to_string(),
first_value.metadata().clone(),
)
}),
values.collect(),
),
None => (None, values.collect()),
}
}
other => (None, vec![other]),
},
None => (None, Vec::new()),
}
}
_ => (None, Vec::new()),
};
if !remaining_values.is_empty() {
if let Some(map) = compacted_item.as_object_mut() {
for value in remaining_values {
add_value(
map,
container_key
.as_ref()
.unwrap()
.borrow()
.map(String::as_str),
value,
false,
)
}
}
}
if let Some(map) = compacted_item.as_object() {
if map.len() == 1 && map.get_unique("@id").ok().unwrap().is_some() {
let obj = Object::node(Node::with_id(
expanded_item.id_entry().unwrap().clone(),
));
compacted_item = obj
.compact_indexed_fragment(
vocabulary,
compacted_item.metadata(),
None,
active_context,
active_context,
Some(item_active_property.borrow().map(String::as_str)),
loader,
options,
)
.await?
}
}
map_key
};
let map_key = match map_key {
Some(key) => key,
None => {
let key = compact_iri(
vocabulary,
active_context,
Meta(&Term::Keyword(Keyword::None), compacted_item.metadata()),
true,
false,
options,
)
.map_err(Meta::cast)?;
key.unwrap()
}
};
add_value(
map_object,
map_key.borrow().map(String::as_str),
compacted_item,
as_array,
)
} else {
add_value(
nest_result,
item_active_property.borrow().map(String::as_str),
compacted_item,
as_array,
)
}
}
};
}
}
if is_empty {
let item_active_property = compact_iri_with(
vocabulary,
active_context,
expanded_property.borrow(),
&Indexed::new(Object::node(Node::new()), None),
true,
inside_reverse,
options,
)
.map_err(Meta::cast)?;
if let Some(item_active_property) = item_active_property {
let (nest_result, _, _) = select_nest_result(
result,
active_context,
item_active_property.borrow().map(String::as_str),
options.compact_arrays,
)?;
add_value(
nest_result,
item_active_property.borrow().map(String::as_str),
Meta(Vec::new().into(), item_active_property.metadata().clone()),
true,
)
}
}
Ok(())
}