From 52cacbb201a55b4f320fa0f552c5ad2444fe896a Mon Sep 17 00:00:00 2001 From: Shivam Kapoor <4599890+iamsmkr@users.noreply.github.com> Date: Fri, 22 Sep 2023 15:03:10 +0100 Subject: [PATCH] Archive (#1271) * init archive graphs * fix subgraph * fix fmt * upsert creation time for new graph as well as saved as graphs * cargo fmt * update lastUpdated time upon save * rename graph * fix issue with uiProps getting overwritten with last uiProps * rid expectations * fmt * fix merge issues --- raphtory-graphql/src/model/mod.rs | 164 +++++++++++++++++++++++++----- 1 file changed, 141 insertions(+), 23 deletions(-) diff --git a/raphtory-graphql/src/model/mod.rs b/raphtory-graphql/src/model/mod.rs index e57cd7e470..398440923d 100644 --- a/raphtory-graphql/src/model/mod.rs +++ b/raphtory-graphql/src/model/mod.rs @@ -4,23 +4,26 @@ use crate::{ }; use async_graphql::Context; use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine}; +use chrono::{NaiveDateTime, Utc}; use dynamic_graphql::{ App, Mutation, MutationFields, MutationRoot, ResolvedObject, ResolvedObjectFields, Result, Upload, }; use itertools::Itertools; use raphtory::{ - core::Prop, - db::api::view::internal::{CoreGraphOps, IntoDynamic, MaterializedGraph}, - prelude::{Graph, GraphViewOps, PropertyAdditionOps}, + core::{ArcStr, Prop}, + db::api::view::internal::{CoreGraphOps, DynamicGraph, IntoDynamic, MaterializedGraph}, + prelude::{Graph, GraphViewOps, PropertyAdditionOps, VertexViewOps}, search::IndexedGraph, }; use std::{ collections::HashMap, error::Error, fmt::{Display, Formatter}, + fs, io::BufReader, ops::Deref, + time::UNIX_EPOCH, }; use uuid::Uuid; @@ -143,6 +146,59 @@ impl Mut { keys } + async fn rename_graph<'a>( + ctx: &Context<'a>, + parent_graph_name: String, + graph_name: String, + new_graph_name: String, + ) -> Result { + if new_graph_name.ne(&graph_name) && parent_graph_name.ne(&graph_name) { + let mut data = ctx.data_unchecked::().graphs.write(); + + let subgraph = data.get(&graph_name).ok_or("Graph not found")?; + let path = subgraph + .constant_prop(&"path".to_string()) + .ok_or("Path is missing")? + .to_string(); + + let parent_graph = data.get(&parent_graph_name).ok_or("Graph not found")?; + let new_subgraph = parent_graph + .subgraph(subgraph.vertices().iter().map(|v| v.name()).collect_vec()) + .materialize()?; + + let static_props_without_name: Vec<(ArcStr, Prop)> = subgraph + .properties() + .into_iter() + .filter(|(a, b)| a != "name") + .collect_vec(); + + new_subgraph.add_constant_properties(static_props_without_name)?; + new_subgraph.add_constant_properties([( + "name".to_string(), + Prop::Str(new_graph_name.clone().into()), + )])?; + + let dt = Utc::now(); + let timestamp: i64 = dt.timestamp(); + new_subgraph.add_constant_properties([( + "lastUpdated".to_string(), + Prop::I64(timestamp * 1000), + )])?; + + new_subgraph.save_to_file(path)?; + + let gi: IndexedGraph = new_subgraph + .into_events() + .ok_or("Graph with deletions not supported")? + .into(); + + data.insert(new_graph_name.clone(), gi.clone()); + data.remove(&graph_name); + } + + Ok(true) + } + async fn save_graph<'a>( ctx: &Context<'a>, parent_graph_name: String, @@ -156,7 +212,7 @@ impl Mut { let subgraph = data.get(&graph_name).ok_or("Graph not found")?; let mut path = subgraph .constant_prop(&"path".to_string()) - .expect("Path is missing") + .ok_or("Path is missing")? .to_string(); if new_graph_name.ne(&graph_name) { @@ -181,27 +237,49 @@ impl Mut { } let parent_graph = data.get(&parent_graph_name).ok_or("Graph not found")?; - let new_subgraph = parent_graph - .subgraph(graph_nodes) - .materialize() - .expect("Failed to materialize graph"); - let static_props_without_name = subgraph - .properties() - .into_iter() - .filter(|(a, _)| a != "name"); - new_subgraph - .add_constant_properties(static_props_without_name) - .expect("Failed to add static properties"); - new_subgraph - .add_constant_properties([("name".to_string(), Prop::str(new_graph_name.clone()))]) - .expect("Failed to add static property"); - new_subgraph - .add_constant_properties([("uiProps".to_string(), Prop::str(props))]) - .expect("Failed to add static property"); + + let new_subgraph = parent_graph.subgraph(graph_nodes).materialize()?; + + new_subgraph.add_constant_properties([( + "name".to_string(), + Prop::Str(new_graph_name.clone().into()), + )])?; + + // parent_graph_name == graph_name, means its a graph created from UI + if parent_graph_name.ne(&graph_name) { + // graph_name == new_graph_name, means its a "save" and not "save as" action + if graph_name.ne(&new_graph_name) { + let static_props: Vec<(ArcStr, Prop)> = subgraph + .properties() + .into_iter() + .filter(|(a, b)| a != "name" && a != "creationTime" && a != "uiProps") + .collect_vec(); + new_subgraph.add_constant_properties(static_props)?; + } else { + let static_props: Vec<(ArcStr, Prop)> = subgraph + .properties() + .into_iter() + .filter(|(a, b)| a != "name" && a != "lastUpdated" && a != "uiProps") + .collect_vec(); + new_subgraph.add_constant_properties(static_props)?; + } + } + + let dt = Utc::now(); + let timestamp: i64 = dt.timestamp(); + + if parent_graph_name.eq(&graph_name) || graph_name.ne(&new_graph_name) { + new_subgraph.add_constant_properties([( + "creationTime".to_string(), + Prop::I64(timestamp * 1000), + )])?; + } new_subgraph - .save_to_file(path) - .expect("Failed to save graph"); + .add_constant_properties([("lastUpdated".to_string(), Prop::I64(timestamp * 1000))])?; + new_subgraph.add_constant_properties([("uiProps".to_string(), Prop::Str(props.into()))])?; + + new_subgraph.save_to_file(path)?; let gi: IndexedGraph = new_subgraph .into_events() @@ -259,6 +337,46 @@ impl Mut { ); Ok(name) } + + async fn archive_graph<'a>( + ctx: &Context<'a>, + graph_name: String, + parent_graph_name: String, + is_archive: u8, + ) -> Result { + let mut data = ctx.data_unchecked::().graphs.write(); + + let subgraph = data.get(&graph_name).ok_or("Graph not found")?; + + let path = subgraph + .constant_prop(&"path".to_string()) + .ok_or("Path is missing")? + .to_string(); + + let parent_graph = data.get(&parent_graph_name).ok_or("Graph not found")?; + let new_subgraph = parent_graph + .subgraph(subgraph.vertices().iter().map(|v| v.name()).collect_vec()) + .materialize()?; + + let static_props_without_isactive: Vec<(ArcStr, Prop)> = subgraph + .properties() + .into_iter() + .filter(|(a, b)| a != "isArchive") + .collect_vec(); + new_subgraph.add_constant_properties(static_props_without_isactive)?; + new_subgraph + .add_constant_properties([("isArchive".to_string(), Prop::U8(is_archive.clone()))])?; + new_subgraph.save_to_file(path)?; + + let gi: IndexedGraph = new_subgraph + .into_events() + .ok_or("Graph with deletions not supported")? + .into(); + + data.insert(graph_name, gi.clone()); + + Ok(true) + } } #[derive(App)]