use diesel::prelude::*;
use crate::error::InvalidStateError;
use crate::registry::{
diesel::{
models::{NodeEndpointsModel, NodeKeysModel, NodeMetadataModel, NodesModel},
schema::{
splinter_nodes, splinter_nodes_endpoints, splinter_nodes_keys, splinter_nodes_metadata,
},
},
MetadataPredicate, Node, NodeBuilder, RegistryError,
};
use super::{apply_predicate_filters, RegistryOperations};
pub(in crate::registry::diesel) trait RegistryListNodesOperation {
fn list_nodes(&self, predicates: &[MetadataPredicate]) -> Result<Vec<Node>, RegistryError>;
}
impl<'a, C> RegistryListNodesOperation for RegistryOperations<'a, C>
where
C: diesel::Connection,
String: diesel::deserialize::FromSql<diesel::sql_types::Text, C::Backend>,
{
fn list_nodes(&self, predicates: &[MetadataPredicate]) -> Result<Vec<Node>, RegistryError> {
self.conn.transaction::<_, _, _>(|| {
let nodes: Vec<NodesModel> = if predicates.is_empty() {
splinter_nodes::table.load(self.conn)?
} else {
let mut query = splinter_nodes::table
.into_boxed()
.select(splinter_nodes::all_columns);
query = apply_predicate_filters(query, predicates);
query.load(self.conn)?
};
if nodes.is_empty() {
Ok(vec![])
} else {
let identities = nodes.iter().map(|node| &node.identity).collect::<Vec<_>>();
let endpoints = splinter_nodes_endpoints::table
.filter(splinter_nodes_endpoints::identity.eq_any(&identities))
.load::<NodeEndpointsModel>(self.conn)?
.grouped_by(&nodes);
let keys = splinter_nodes_keys::table
.filter(splinter_nodes_keys::identity.eq_any(&identities))
.load::<NodeKeysModel>(self.conn)?
.grouped_by(&nodes);
let metadata = splinter_nodes_metadata::table
.filter(splinter_nodes_metadata::identity.eq_any(identities))
.load::<NodeMetadataModel>(self.conn)?
.grouped_by(&nodes);
nodes
.into_iter()
.zip(endpoints.into_iter())
.zip(keys.into_iter())
.zip(metadata.into_iter())
.map(|(((node, endpoints), keys), metadata)| {
let endpoints = endpoints
.into_iter()
.map(|endpoint| endpoint.endpoint)
.collect::<Vec<_>>();
let keys = keys.into_iter().map(|key| key.key).collect::<Vec<_>>();
let mut builder = NodeBuilder::new(node.identity)
.with_display_name(node.display_name)
.with_endpoints(endpoints)
.with_keys(keys);
for entry in metadata {
builder = builder.with_metadata(entry.key, entry.value);
}
builder.build().map_err(|err| {
RegistryError::InvalidStateError(InvalidStateError::with_message(
err.to_string(),
))
})
})
.collect::<Result<Vec<_>, _>>()
}
})
}
}