#![allow(clippy::type_complexity)]
use napi::bindgen_prelude::*;
use napi_derive::napi;
use parking_lot::RwLock;
use std::collections::HashMap;
use std::sync::Arc;
use crate::api::kite::{Kite as RustKite, NodeRef};
use crate::types::{NodeId, PropValue};
use super::conversion::{js_props_to_map, js_value_to_prop_value, key_suffix_from_js};
use super::helpers::{node_props, node_to_js};
use super::key_spec::KeySpec;
#[napi]
pub struct KiteInsertBuilder {
pub(crate) ray: Arc<RwLock<Option<RustKite>>>,
pub(crate) node_type: String,
pub(crate) key_prefix: String,
pub(crate) key_spec: Arc<KeySpec>,
}
impl KiteInsertBuilder {
pub(crate) fn new(
ray: Arc<RwLock<Option<RustKite>>>,
node_type: String,
key_prefix: String,
key_spec: Arc<KeySpec>,
) -> Self {
Self {
ray,
node_type,
key_prefix,
key_spec,
}
}
}
#[napi]
impl KiteInsertBuilder {
#[napi]
pub fn values(
&self,
env: Env,
key: Unknown,
props: Option<Object>,
) -> Result<KiteInsertExecutorSingle> {
let key_suffix = key_suffix_from_js(&env, self.key_spec.as_ref(), key)?;
let props_map = js_props_to_map(&env, props)?;
Ok(KiteInsertExecutorSingle {
ray: self.ray.clone(),
node_type: self.node_type.clone(),
key_suffix,
props: props_map,
})
}
#[napi]
pub fn values_many(&self, env: Env, entries: Vec<Unknown>) -> Result<KiteInsertExecutorMany> {
let mut items = Vec::with_capacity(entries.len());
for entry in entries {
let obj = entry.coerce_to_object()?;
let key: Unknown = obj.get_named_property("key")?;
let props: Option<Object> = obj.get_named_property("props")?;
let key_suffix = key_suffix_from_js(&env, self.key_spec.as_ref(), key)?;
let props_map = js_props_to_map(&env, props)?;
items.push((key_suffix, props_map));
}
Ok(KiteInsertExecutorMany {
ray: self.ray.clone(),
node_type: self.node_type.clone(),
entries: items,
})
}
}
#[napi]
pub struct KiteInsertExecutorSingle {
ray: Arc<RwLock<Option<RustKite>>>,
node_type: String,
key_suffix: String,
props: HashMap<String, PropValue>,
}
#[napi]
impl KiteInsertExecutorSingle {
#[napi]
pub fn execute(&mut self) -> Result<()> {
let props = std::mem::take(&mut self.props);
insert_single_execute(&self.ray, &self.node_type, &self.key_suffix, props)
}
#[napi]
pub fn returning(&mut self, env: Env) -> Result<Object<'_>> {
let props = std::mem::take(&mut self.props);
let (node_ref, props) =
insert_single_returning(&self.ray, &self.node_type, &self.key_suffix, props)?;
let (node_id, node_key, node_type) = node_ref.into_parts();
node_to_js(&env, node_id, node_key, &node_type, props)
}
}
#[napi]
pub struct KiteInsertExecutorMany {
ray: Arc<RwLock<Option<RustKite>>>,
node_type: String,
entries: Vec<(String, HashMap<String, PropValue>)>,
}
#[napi]
impl KiteInsertExecutorMany {
#[napi]
pub fn execute(&mut self) -> Result<()> {
let entries = std::mem::take(&mut self.entries);
let _ = insert_many(&self.ray, &self.node_type, entries, false)?;
Ok(())
}
#[napi]
pub fn returning(&mut self, env: Env) -> Result<Vec<Object<'_>>> {
let entries = std::mem::take(&mut self.entries);
let results = insert_many(&self.ray, &self.node_type, entries, true)?;
let mut out = Vec::with_capacity(results.len());
for (node_ref, props) in results.into_iter() {
let props =
props.ok_or_else(|| Error::from_reason("Insert returning=true did not yield props"))?;
let (node_id, node_key, node_type) = node_ref.into_parts();
out.push(node_to_js(&env, node_id, node_key, &node_type, props)?);
}
Ok(out)
}
}
fn insert_single_execute(
ray: &Arc<RwLock<Option<RustKite>>>,
node_type: &str,
key_suffix: &str,
props: HashMap<String, PropValue>,
) -> Result<()> {
let mut guard = ray.write();
let ray = guard
.as_mut()
.ok_or_else(|| Error::from_reason("Kite is closed"))?;
ray
.insert(node_type)
.map_err(|e| Error::from_reason(e.to_string()))?
.values(key_suffix, props)
.map_err(|e| Error::from_reason(e.to_string()))?
.execute()
.map_err(|e| Error::from_reason(e.to_string()))
}
fn insert_single_returning(
ray: &Arc<RwLock<Option<RustKite>>>,
node_type: &str,
key_suffix: &str,
props: HashMap<String, PropValue>,
) -> Result<(NodeRef, HashMap<String, PropValue>)> {
let mut guard = ray.write();
let ray = guard
.as_mut()
.ok_or_else(|| Error::from_reason("Kite is closed"))?;
let props_for_return = props.clone();
let node_ref = ray
.insert(node_type)
.map_err(|e| Error::from_reason(e.to_string()))?
.values(key_suffix, props)
.map_err(|e| Error::from_reason(e.to_string()))?
.returning()
.map_err(|e| Error::from_reason(e.to_string()))?;
Ok((node_ref, props_for_return))
}
fn insert_many(
ray: &Arc<RwLock<Option<RustKite>>>,
node_type: &str,
entries: Vec<(String, HashMap<String, PropValue>)>,
load_props: bool,
) -> Result<Vec<(NodeRef, Option<HashMap<String, PropValue>>)>> {
if entries.is_empty() {
return Ok(Vec::new());
}
let mut guard = ray.write();
let ray = guard
.as_mut()
.ok_or_else(|| Error::from_reason("Kite is closed"))?;
if !load_props {
ray
.insert(node_type)
.map_err(|e| Error::from_reason(e.to_string()))?
.values_many_owned(entries)
.map_err(|e| Error::from_reason(e.to_string()))?
.execute()
.map_err(|e| Error::from_reason(e.to_string()))?;
return Ok(Vec::new());
}
let props_for_return: Vec<HashMap<String, PropValue>> =
entries.iter().map(|(_, props)| props.clone()).collect();
let node_refs = ray
.insert(node_type)
.map_err(|e| Error::from_reason(e.to_string()))?
.values_many_owned(entries)
.map_err(|e| Error::from_reason(e.to_string()))?
.returning()
.map_err(|e| Error::from_reason(e.to_string()))?;
Ok(
node_refs
.into_iter()
.zip(props_for_return)
.map(|(node_ref, props)| (node_ref, Some(props)))
.collect(),
)
}
#[napi]
pub struct KiteUpsertBuilder {
pub(crate) ray: Arc<RwLock<Option<RustKite>>>,
pub(crate) node_type: String,
pub(crate) key_prefix: String,
pub(crate) key_spec: Arc<KeySpec>,
}
impl KiteUpsertBuilder {
pub(crate) fn new(
ray: Arc<RwLock<Option<RustKite>>>,
node_type: String,
key_prefix: String,
key_spec: Arc<KeySpec>,
) -> Self {
Self {
ray,
node_type,
key_prefix,
key_spec,
}
}
}
#[napi]
impl KiteUpsertBuilder {
#[napi]
pub fn values(
&self,
env: Env,
key: Unknown,
props: Option<Object>,
) -> Result<KiteUpsertExecutorSingle> {
let key_suffix = key_suffix_from_js(&env, self.key_spec.as_ref(), key)?;
let props_map = js_props_to_map(&env, props)?;
Ok(KiteUpsertExecutorSingle {
ray: self.ray.clone(),
node_type: self.node_type.clone(),
key_suffix,
props: props_map,
})
}
#[napi]
pub fn values_many(&self, env: Env, entries: Vec<Unknown>) -> Result<KiteUpsertExecutorMany> {
let mut items = Vec::with_capacity(entries.len());
for entry in entries {
let obj = entry.coerce_to_object()?;
let key: Unknown = obj.get_named_property("key")?;
let props: Option<Object> = obj.get_named_property("props")?;
let key_suffix = key_suffix_from_js(&env, self.key_spec.as_ref(), key)?;
let props_map = js_props_to_map(&env, props)?;
items.push((key_suffix, props_map));
}
Ok(KiteUpsertExecutorMany {
ray: self.ray.clone(),
node_type: self.node_type.clone(),
entries: items,
})
}
}
#[napi]
pub struct KiteUpsertExecutorSingle {
ray: Arc<RwLock<Option<RustKite>>>,
node_type: String,
key_suffix: String,
props: HashMap<String, PropValue>,
}
#[napi]
impl KiteUpsertExecutorSingle {
#[napi]
pub fn execute(&mut self) -> Result<()> {
let props = std::mem::take(&mut self.props);
upsert_single_execute(&self.ray, &self.node_type, &self.key_suffix, props)
}
#[napi]
pub fn returning(&mut self, env: Env) -> Result<Object<'_>> {
let props = std::mem::take(&mut self.props);
let (node_ref, props) =
upsert_single_returning(&self.ray, &self.node_type, &self.key_suffix, props)?;
let (node_id, node_key, node_type) = node_ref.into_parts();
node_to_js(&env, node_id, node_key, &node_type, props)
}
}
#[napi]
pub struct KiteUpsertExecutorMany {
ray: Arc<RwLock<Option<RustKite>>>,
node_type: String,
entries: Vec<(String, HashMap<String, PropValue>)>,
}
#[napi]
impl KiteUpsertExecutorMany {
#[napi]
pub fn execute(&mut self) -> Result<()> {
let entries = std::mem::take(&mut self.entries);
let _ = upsert_many(&self.ray, &self.node_type, entries, false)?;
Ok(())
}
#[napi]
pub fn returning(&mut self, env: Env) -> Result<Vec<Object<'_>>> {
let entries = std::mem::take(&mut self.entries);
let results = upsert_many(&self.ray, &self.node_type, entries, true)?;
let mut out = Vec::with_capacity(results.len());
for (node_ref, props) in results.into_iter() {
let props =
props.ok_or_else(|| Error::from_reason("Upsert returning=true did not yield props"))?;
let (node_id, node_key, node_type) = node_ref.into_parts();
out.push(node_to_js(&env, node_id, node_key, &node_type, props)?);
}
Ok(out)
}
}
fn upsert_single_execute(
ray: &Arc<RwLock<Option<RustKite>>>,
node_type: &str,
key_suffix: &str,
props: HashMap<String, PropValue>,
) -> Result<()> {
let mut guard = ray.write();
let ray = guard
.as_mut()
.ok_or_else(|| Error::from_reason("Kite is closed"))?;
ray
.upsert(node_type)
.map_err(|e| Error::from_reason(e.to_string()))?
.values(key_suffix, props)
.map_err(|e| Error::from_reason(e.to_string()))?
.execute()
.map_err(|e| Error::from_reason(e.to_string()))
}
fn upsert_single_returning(
ray: &Arc<RwLock<Option<RustKite>>>,
node_type: &str,
key_suffix: &str,
props: HashMap<String, PropValue>,
) -> Result<(NodeRef, HashMap<String, PropValue>)> {
let mut guard = ray.write();
let ray = guard
.as_mut()
.ok_or_else(|| Error::from_reason("Kite is closed"))?;
let node_ref = ray
.upsert(node_type)
.map_err(|e| Error::from_reason(e.to_string()))?
.values(key_suffix, props)
.map_err(|e| Error::from_reason(e.to_string()))?
.returning()
.map_err(|e| Error::from_reason(e.to_string()))?;
let props_for_return = node_props(ray, node_ref.id());
Ok((node_ref, props_for_return))
}
fn upsert_many(
ray: &Arc<RwLock<Option<RustKite>>>,
node_type: &str,
entries: Vec<(String, HashMap<String, PropValue>)>,
load_props: bool,
) -> Result<Vec<(NodeRef, Option<HashMap<String, PropValue>>)>> {
if entries.is_empty() {
return Ok(Vec::new());
}
let mut guard = ray.write();
let ray = guard
.as_mut()
.ok_or_else(|| Error::from_reason("Kite is closed"))?;
if !load_props {
ray
.upsert(node_type)
.map_err(|e| Error::from_reason(e.to_string()))?
.values_many_owned(entries)
.map_err(|e| Error::from_reason(e.to_string()))?
.execute()
.map_err(|e| Error::from_reason(e.to_string()))?;
return Ok(Vec::new());
}
let node_refs = ray
.upsert(node_type)
.map_err(|e| Error::from_reason(e.to_string()))?
.values_many_owned(entries)
.map_err(|e| Error::from_reason(e.to_string()))?
.returning()
.map_err(|e| Error::from_reason(e.to_string()))?;
Ok(
node_refs
.into_iter()
.map(|node_ref| {
let props = node_props(ray, node_ref.id());
(node_ref, Some(props))
})
.collect(),
)
}
#[napi]
pub struct KiteUpdateBuilder {
pub(crate) ray: Arc<RwLock<Option<RustKite>>>,
pub(crate) node_id: NodeId,
pub(crate) updates: HashMap<String, Option<PropValue>>,
}
impl KiteUpdateBuilder {
pub(crate) fn new(ray: Arc<RwLock<Option<RustKite>>>, node_id: NodeId) -> Self {
Self {
ray,
node_id,
updates: HashMap::new(),
}
}
}
#[napi]
impl KiteUpdateBuilder {
#[napi]
pub fn set(&mut self, env: Env, prop_name: String, value: Unknown) -> Result<()> {
let prop_value = js_value_to_prop_value(&env, value)?;
self.updates.insert(prop_name, Some(prop_value));
Ok(())
}
#[napi]
pub fn unset(&mut self, prop_name: String) -> Result<()> {
self.updates.insert(prop_name, None);
Ok(())
}
#[napi]
pub fn set_all(&mut self, env: Env, props: Object) -> Result<()> {
let props_map = js_props_to_map(&env, Some(props))?;
for (prop_name, value) in props_map {
self.updates.insert(prop_name, Some(value));
}
Ok(())
}
#[napi]
pub fn execute(&self) -> Result<()> {
if self.updates.is_empty() {
return Ok(());
}
let mut guard = self.ray.write();
let ray = guard
.as_mut()
.ok_or_else(|| Error::from_reason("Kite is closed"))?;
let mut builder = ray
.update_by_id(self.node_id)
.map_err(|e| Error::from_reason(e.to_string()))?;
for (prop_name, value_opt) in &self.updates {
builder = match value_opt {
Some(value) => builder.set(prop_name, value.clone()),
None => builder.unset(prop_name),
};
}
builder
.execute()
.map_err(|e| Error::from_reason(e.to_string()))
}
}
#[napi]
pub struct KiteUpsertByIdBuilder {
pub(crate) ray: Arc<RwLock<Option<RustKite>>>,
pub(crate) node_type: String,
pub(crate) node_id: NodeId,
pub(crate) updates: HashMap<String, Option<PropValue>>,
}
impl KiteUpsertByIdBuilder {
pub(crate) fn new(
ray: Arc<RwLock<Option<RustKite>>>,
node_type: String,
node_id: NodeId,
) -> Self {
Self {
ray,
node_type,
node_id,
updates: HashMap::new(),
}
}
}
#[napi]
impl KiteUpsertByIdBuilder {
#[napi]
pub fn set(&mut self, env: Env, prop_name: String, value: Unknown) -> Result<()> {
let prop_value = js_value_to_prop_value(&env, value)?;
self.updates.insert(prop_name, Some(prop_value));
Ok(())
}
#[napi]
pub fn unset(&mut self, prop_name: String) -> Result<()> {
self.updates.insert(prop_name, None);
Ok(())
}
#[napi]
pub fn set_all(&mut self, env: Env, props: Object) -> Result<()> {
let props_map = js_props_to_map(&env, Some(props))?;
for (prop_name, value) in props_map {
self.updates.insert(prop_name, Some(value));
}
Ok(())
}
#[napi]
pub fn execute(&self) -> Result<()> {
let mut guard = self.ray.write();
let ray = guard
.as_mut()
.ok_or_else(|| Error::from_reason("Kite is closed"))?;
let mut builder = ray
.upsert_by_id(&self.node_type, self.node_id)
.map_err(|e| Error::from_reason(e.to_string()))?;
for (prop_name, value_opt) in &self.updates {
builder = match value_opt {
Some(value) => builder.set(prop_name, value.clone()),
None => builder.unset(prop_name),
};
}
builder
.execute()
.map_err(|e| Error::from_reason(e.to_string()))
}
}
#[napi]
pub struct KiteUpdateEdgeBuilder {
pub(crate) ray: Arc<RwLock<Option<RustKite>>>,
pub(crate) src: NodeId,
pub(crate) edge_type: String,
pub(crate) dst: NodeId,
pub(crate) updates: HashMap<String, Option<PropValue>>,
}
impl KiteUpdateEdgeBuilder {
pub(crate) fn new(
ray: Arc<RwLock<Option<RustKite>>>,
src: NodeId,
edge_type: String,
dst: NodeId,
) -> Self {
Self {
ray,
src,
edge_type,
dst,
updates: HashMap::new(),
}
}
}
#[napi]
impl KiteUpdateEdgeBuilder {
#[napi]
pub fn set(&mut self, env: Env, prop_name: String, value: Unknown) -> Result<()> {
let prop_value = js_value_to_prop_value(&env, value)?;
self.updates.insert(prop_name, Some(prop_value));
Ok(())
}
#[napi]
pub fn unset(&mut self, prop_name: String) -> Result<()> {
self.updates.insert(prop_name, None);
Ok(())
}
#[napi]
pub fn set_all(&mut self, env: Env, props: Object) -> Result<()> {
let props_map = js_props_to_map(&env, Some(props))?;
for (prop_name, value) in props_map {
self.updates.insert(prop_name, Some(value));
}
Ok(())
}
#[napi]
pub fn execute(&self) -> Result<()> {
if self.updates.is_empty() {
return Ok(());
}
let mut guard = self.ray.write();
let ray = guard
.as_mut()
.ok_or_else(|| Error::from_reason("Kite is closed"))?;
let mut builder = ray
.update_edge(self.src, &self.edge_type, self.dst)
.map_err(|e| Error::from_reason(e.to_string()))?;
for (prop_name, value_opt) in &self.updates {
builder = match value_opt {
Some(value) => builder.set(prop_name, value.clone()),
None => builder.unset(prop_name),
};
}
builder
.execute()
.map_err(|e| Error::from_reason(e.to_string()))
}
}
#[napi]
pub struct KiteUpsertEdgeBuilder {
pub(crate) ray: Arc<RwLock<Option<RustKite>>>,
pub(crate) src: NodeId,
pub(crate) edge_type: String,
pub(crate) dst: NodeId,
pub(crate) updates: HashMap<String, Option<PropValue>>,
}
impl KiteUpsertEdgeBuilder {
pub(crate) fn new(
ray: Arc<RwLock<Option<RustKite>>>,
src: NodeId,
edge_type: String,
dst: NodeId,
) -> Self {
Self {
ray,
src,
edge_type,
dst,
updates: HashMap::new(),
}
}
}
#[napi]
impl KiteUpsertEdgeBuilder {
#[napi]
pub fn set(&mut self, env: Env, prop_name: String, value: Unknown) -> Result<()> {
let prop_value = js_value_to_prop_value(&env, value)?;
self.updates.insert(prop_name, Some(prop_value));
Ok(())
}
#[napi]
pub fn unset(&mut self, prop_name: String) -> Result<()> {
self.updates.insert(prop_name, None);
Ok(())
}
#[napi]
pub fn set_all(&mut self, env: Env, props: Object) -> Result<()> {
let props_map = js_props_to_map(&env, Some(props))?;
for (prop_name, value) in props_map {
self.updates.insert(prop_name, Some(value));
}
Ok(())
}
#[napi]
pub fn execute(&self) -> Result<()> {
let mut guard = self.ray.write();
let ray = guard
.as_mut()
.ok_or_else(|| Error::from_reason("Kite is closed"))?;
let mut builder = ray
.upsert_edge(self.src, &self.edge_type, self.dst)
.map_err(|e| Error::from_reason(e.to_string()))?;
for (prop_name, value_opt) in &self.updates {
builder = match value_opt {
Some(value) => builder.set(prop_name, value.clone()),
None => builder.unset(prop_name),
};
}
builder
.execute()
.map_err(|e| Error::from_reason(e.to_string()))
}
}