use capnp::Error as CapnpError;
use chrono::{DateTime, TimeZone, Utc};
use std::fmt::Display;
use std::vec::IntoIter;
use uuid::Uuid;
const NANOS_PER_SEC: u64 = 1_000_000_000;
pub fn map_capnp_err<T, E: Display>(result: Result<T, E>) -> Result<T, capnp::Error> {
result.map_err(|err| capnp::Error::failed(format!("{}", err)))
}
pub fn from_vertex<'a>(vertex: &indradb::Vertex, mut builder: crate::vertex::Builder<'a>) {
builder.set_id(vertex.id.as_bytes());
builder.set_t(&vertex.t.0);
}
pub fn to_vertex<'a>(reader: &crate::vertex::Reader<'a>) -> Result<indradb::Vertex, CapnpError> {
let id = map_capnp_err(Uuid::from_slice(reader.get_id()?))?;
let t = map_capnp_err(indradb::Type::new(reader.get_t()?))?;
Ok(indradb::Vertex::with_id(id, t))
}
pub fn from_edge<'a>(edge: &indradb::Edge, mut builder: crate::edge::Builder<'a>) -> Result<(), CapnpError> {
builder.set_created_datetime(edge.created_datetime.timestamp() as u64);
from_edge_key(&edge.key, builder.init_key());
Ok(())
}
pub fn to_edge<'a>(reader: &crate::edge::Reader<'a>) -> Result<indradb::Edge, CapnpError> {
let key = to_edge_key(&reader.get_key()?)?;
let created_datetime = Utc.timestamp(reader.get_created_datetime() as i64, 0);
Ok(indradb::Edge::new(key, created_datetime))
}
pub fn from_edge_key<'a>(key: &indradb::EdgeKey, mut builder: crate::edge_key::Builder<'a>) {
builder.set_outbound_id(key.outbound_id.as_bytes());
builder.set_t(&key.t.0);
builder.set_inbound_id(key.inbound_id.as_bytes());
}
pub fn to_edge_key<'a>(reader: &crate::edge_key::Reader<'a>) -> Result<indradb::EdgeKey, CapnpError> {
let outbound_id = map_capnp_err(Uuid::from_slice(reader.get_outbound_id()?))?;
let t = map_capnp_err(indradb::Type::new(reader.get_t()?))?;
let inbound_id = map_capnp_err(Uuid::from_slice(reader.get_inbound_id()?))?;
Ok(indradb::EdgeKey::new(outbound_id, t, inbound_id))
}
pub fn from_vertex_property<'a>(property: &indradb::VertexProperty, mut builder: crate::vertex_property::Builder<'a>) {
builder.set_id(property.id.as_bytes());
builder.set_value(&property.value.to_string());
}
pub fn to_vertex_property<'a>(
reader: &crate::vertex_property::Reader<'a>,
) -> Result<indradb::VertexProperty, CapnpError> {
let id = map_capnp_err(Uuid::from_slice(reader.get_id()?))?;
let value = map_capnp_err(serde_json::from_str(reader.get_value()?))?;
Ok(indradb::VertexProperty::new(id, value))
}
pub fn from_vertex_properties<'a>(
properties: &indradb::VertexProperties,
builder: &mut crate::vertex_properties::Builder<'a>,
) {
from_vertex(&properties.vertex, builder.reborrow().init_vertex());
let mut props_builder = builder.reborrow().init_props(properties.props.len() as u32);
for (i, prop) in properties.props.iter().enumerate() {
from_named_property(prop, props_builder.reborrow().get(i as u32));
}
}
pub fn to_vertex_properties<'a>(
reader: &crate::vertex_properties::Reader<'a>,
) -> Result<indradb::VertexProperties, CapnpError> {
let vertex = map_capnp_err(to_vertex(&reader.get_vertex()?))?;
let named_props: Result<Vec<indradb::NamedProperty>, CapnpError> =
reader.get_props()?.into_iter().map(to_named_property).collect();
Ok(indradb::VertexProperties::new(vertex, named_props?))
}
pub fn from_named_property<'a>(property: &indradb::NamedProperty, mut builder: crate::property::Builder<'a>) {
builder.set_name(&property.name);
builder.set_value(&property.value.to_string());
}
pub fn to_named_property(reader: crate::property::Reader) -> Result<indradb::NamedProperty, CapnpError> {
let name = map_capnp_err(reader.get_name())?.to_string();
let value = map_capnp_err(serde_json::from_str(reader.get_value()?))?;
Ok(indradb::NamedProperty::new(name, value))
}
pub fn from_edge_properties<'a>(
properties: &indradb::EdgeProperties,
builder: &mut crate::edge_properties::Builder<'a>,
) {
from_edge(&properties.edge, builder.reborrow().init_edge()).unwrap();
let mut props_builder = builder.reborrow().init_props(properties.props.len() as u32);
for (i, prop) in properties.props.iter().enumerate() {
from_named_property(prop, props_builder.reborrow().get(i as u32));
}
}
pub fn to_edge_properties<'a>(
reader: &crate::edge_properties::Reader<'a>,
) -> Result<indradb::EdgeProperties, CapnpError> {
let edge = map_capnp_err(to_edge(&reader.get_edge()?))?;
let named_props: Result<Vec<indradb::NamedProperty>, CapnpError> =
reader.get_props()?.into_iter().map(to_named_property).collect();
Ok(indradb::EdgeProperties::new(edge, named_props?))
}
pub fn from_edge_property<'a>(property: &indradb::EdgeProperty, mut builder: crate::edge_property::Builder<'a>) {
builder.set_value(&property.value.to_string());
from_edge_key(&property.key, builder.init_key());
}
pub fn to_edge_property<'a>(reader: &crate::edge_property::Reader<'a>) -> Result<indradb::EdgeProperty, CapnpError> {
let key = to_edge_key(&reader.get_key()?)?;
let value = map_capnp_err(serde_json::from_str(reader.get_value()?))?;
Ok(indradb::EdgeProperty::new(key, value))
}
pub fn from_vertex_query<'a>(q: &indradb::VertexQuery, builder: crate::vertex_query::Builder<'a>) {
match q {
indradb::VertexQuery::Range(q) => {
let mut builder = builder.init_range();
if let Some(start_id) = q.start_id {
builder.set_start_id(start_id.as_bytes());
}
if let Some(ref t) = q.t {
builder.set_t(&t.0);
}
builder.set_limit(q.limit);
}
indradb::VertexQuery::Specific(q) => {
let mut builder = builder.init_specific().init_ids(q.ids.len() as u32);
for (i, id) in q.ids.iter().enumerate() {
builder.set(i as u32, id.as_bytes());
}
}
indradb::VertexQuery::Pipe(q) => {
let mut builder = builder.init_pipe();
builder.set_direction(from_edge_direction(q.direction));
builder.set_limit(q.limit);
if let Some(ref t) = q.t {
builder.set_t(&t.0);
}
from_edge_query(&q.inner, builder.init_inner());
}
}
}
pub fn to_vertex_query<'a>(reader: &crate::vertex_query::Reader<'a>) -> Result<indradb::VertexQuery, CapnpError> {
match reader.which()? {
crate::vertex_query::Range(params) => {
let start_id_bytes = params.get_start_id()?;
let t_str = params.get_t()?;
let mut range = indradb::RangeVertexQuery::new(params.get_limit());
if !start_id_bytes.is_empty() {
range = range.start_id(map_capnp_err(Uuid::from_slice(start_id_bytes))?);
}
if t_str != "" {
range = range.t(map_capnp_err(indradb::Type::new(t_str))?);
}
Ok(range.into())
}
crate::vertex_query::Specific(params) => {
let ids: Result<Vec<Uuid>, CapnpError> = params
.get_ids()?
.into_iter()
.map(|bytes| map_capnp_err(Uuid::from_slice(bytes?)))
.collect();
Ok(indradb::SpecificVertexQuery::new(ids?).into())
}
crate::vertex_query::Pipe(params) => {
let inner = Box::new(to_edge_query(¶ms.get_inner()?)?);
let direction = to_edge_direction(params.get_direction()?);
let limit = params.get_limit();
let t_str = params.get_t()?;
let mut pipe = indradb::PipeVertexQuery::new(inner, direction, limit);
if t_str != "" {
pipe = pipe.t(map_capnp_err(indradb::Type::new(t_str))?);
}
Ok(pipe.into())
}
}
}
pub fn from_vertex_property_query<'a>(
q: &indradb::VertexPropertyQuery,
mut builder: crate::vertex_property_query::Builder<'a>,
) {
builder.set_name(&q.name);
from_vertex_query(&q.inner, builder.init_inner());
}
pub fn to_vertex_property_query<'a>(
reader: &crate::vertex_property_query::Reader<'a>,
) -> Result<indradb::VertexPropertyQuery, CapnpError> {
let inner = to_vertex_query(&reader.get_inner()?)?;
let name = reader.get_name()?;
Ok(indradb::VertexPropertyQuery::new(inner, name))
}
pub fn from_edge_query<'a>(q: &indradb::EdgeQuery, builder: crate::edge_query::Builder<'a>) {
match q {
indradb::EdgeQuery::Specific(specific) => {
let mut builder = builder.init_specific().init_keys(specific.keys.len() as u32);
for (i, key) in specific.keys.iter().enumerate() {
from_edge_key(key, builder.reborrow().get(i as u32));
}
}
indradb::EdgeQuery::Pipe(pipe) => {
let mut builder = builder.init_pipe();
builder.set_direction(from_edge_direction(pipe.direction));
if let Some(t) = &pipe.t {
builder.set_t(&t.0);
}
if let Some(high) = pipe.high {
builder.set_high(high.timestamp_nanos() as u64);
}
if let Some(low) = pipe.low {
builder.set_low(low.timestamp_nanos() as u64);
}
builder.set_limit(pipe.limit);
from_vertex_query(&pipe.inner, builder.init_inner());
}
}
}
pub fn to_edge_query<'a>(reader: &crate::edge_query::Reader<'a>) -> Result<indradb::EdgeQuery, CapnpError> {
match reader.which()? {
crate::edge_query::Specific(params) => {
let keys: Result<Vec<indradb::EdgeKey>, CapnpError> = params
.get_keys()?
.into_iter()
.map(|reader| to_edge_key(&reader))
.collect();
Ok(indradb::EdgeQuery::Specific(indradb::SpecificEdgeQuery::new(keys?)))
}
crate::edge_query::Pipe(params) => {
let inner = Box::new(to_vertex_query(¶ms.get_inner()?)?);
let direction = to_edge_direction(params.get_direction()?);
let limit = params.get_limit();
let mut pipe = indradb::PipeEdgeQuery::new(inner, direction, limit);
let t = params.get_t()?;
if t != "" {
pipe = pipe.t(map_capnp_err(indradb::Type::new(t))?);
}
if let Some(high) = to_optional_datetime(params.get_high()) {
pipe = pipe.high(high);
}
if let Some(low) = to_optional_datetime(params.get_low()) {
pipe = pipe.low(low);
}
Ok(indradb::EdgeQuery::Pipe(pipe))
}
}
}
pub fn from_edge_property_query<'a>(
q: &indradb::EdgePropertyQuery,
mut builder: crate::edge_property_query::Builder<'a>,
) {
builder.set_name(&q.name);
from_edge_query(&q.inner, builder.init_inner());
}
pub fn to_edge_property_query<'a>(
reader: &crate::edge_property_query::Reader<'a>,
) -> Result<indradb::EdgePropertyQuery, CapnpError> {
let inner = to_edge_query(&reader.get_inner()?)?;
let name = reader.get_name()?;
Ok(indradb::EdgePropertyQuery::new(inner, name))
}
pub fn from_bulk_insert_items<'a>(
items: &[indradb::BulkInsertItem],
mut builder: capnp::struct_list::Builder<'a, crate::bulk_insert_item::Owned>,
) -> Result<(), CapnpError> {
for (i, item) in items.iter().enumerate() {
let builder = builder.reborrow().get(i as u32);
match item {
indradb::BulkInsertItem::Vertex(vertex) => {
let builder = builder.init_vertex();
from_vertex(vertex, builder.get_vertex()?);
}
indradb::BulkInsertItem::Edge(edge) => {
let builder = builder.init_edge();
from_edge_key(edge, builder.get_key()?);
}
indradb::BulkInsertItem::VertexProperty(id, name, value) => {
let mut builder = builder.init_vertex_property();
builder.set_id(id.as_bytes());
builder.set_name(name);
builder.set_value(&value.to_string());
}
indradb::BulkInsertItem::EdgeProperty(key, name, value) => {
let mut builder = builder.init_edge_property();
builder.set_name(name);
builder.set_value(&value.to_string());
from_edge_key(key, builder.get_key()?);
}
}
}
Ok(())
}
pub fn to_bulk_insert_items<'a>(
reader: &capnp::struct_list::Reader<'a, crate::bulk_insert_item::Owned>,
) -> Result<IntoIter<indradb::BulkInsertItem>, CapnpError> {
let items: Result<Vec<indradb::BulkInsertItem>, CapnpError> = reader
.into_iter()
.map(|item| match item.which()? {
crate::bulk_insert_item::Vertex(params) => {
let vertex = to_vertex(¶ms.get_vertex()?)?;
Ok(indradb::BulkInsertItem::Vertex(vertex))
}
crate::bulk_insert_item::Edge(params) => {
let edge_key = to_edge_key(¶ms.get_key()?)?;
Ok(indradb::BulkInsertItem::Edge(edge_key))
}
crate::bulk_insert_item::VertexProperty(params) => {
let id = map_capnp_err(Uuid::from_slice(params.get_id()?))?;
let name = params.get_name()?.to_string();
let value = map_capnp_err(serde_json::from_str(params.get_value()?))?;
Ok(indradb::BulkInsertItem::VertexProperty(id, name, value))
}
crate::bulk_insert_item::EdgeProperty(params) => {
let key = to_edge_key(¶ms.get_key()?)?;
let name = params.get_name()?.to_string();
let value = map_capnp_err(serde_json::from_str(params.get_value()?))?;
Ok(indradb::BulkInsertItem::EdgeProperty(key, name, value))
}
})
.collect();
Ok(items?.into_iter())
}
pub fn from_edge_direction(direction: indradb::EdgeDirection) -> crate::EdgeDirection {
match direction {
indradb::EdgeDirection::Outbound => crate::EdgeDirection::Outbound,
indradb::EdgeDirection::Inbound => crate::EdgeDirection::Inbound,
}
}
pub fn to_edge_direction(direction: crate::EdgeDirection) -> indradb::EdgeDirection {
match direction {
crate::EdgeDirection::Outbound => indradb::EdgeDirection::Outbound,
crate::EdgeDirection::Inbound => indradb::EdgeDirection::Inbound,
}
}
pub fn to_optional_datetime(timestamp: u64) -> Option<DateTime<Utc>> {
if timestamp == 0 {
None
} else {
let secs = timestamp / NANOS_PER_SEC;
let nanos = timestamp % NANOS_PER_SEC;
Some(Utc.timestamp(secs as i64, nanos as u32))
}
}