Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic creation/updating of metadata in .raph for MetaGraph #1976

Merged
merged 9 commits into from
Apr 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test_rust_disk_storage_workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
matrix:
include:
- { os: macos-latest, flags: "" }
- { os: ubuntu-20.04, flags: "-C link-arg=-fuse-ld=lld" }
- { os: ubuntu-latest, flags: "-C link-arg=-fuse-ld=lld" }
- { os: windows-latest, flags: "" }
steps:
- uses: maxim-lobanov/setup-xcode@v1
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test_rust_workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
matrix:
include:
- os: macos-latest
- os: ubuntu-20.04
- os: ubuntu-latest
- os: windows-latest
steps:
- uses: maxim-lobanov/setup-xcode@v1
Expand Down
164 changes: 163 additions & 1 deletion raphtory-graphql/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -920,7 +920,7 @@ mod graphql_test {
let mut req = Request::new(query).variables(Variables::from_json(variables));
req.set_upload("variables.file", upload_val);
let res = schema.execute(req).await;
assert_eq!(res.errors.len(), 0);
assert_eq!(res.errors, vec![]);
let res_json = res.data.into_json().unwrap();
assert_eq!(res_json, json!({"uploadGraph": "test"}));

Expand Down Expand Up @@ -1202,4 +1202,166 @@ mod graphql_test {
}),
);
}

#[tokio::test]
async fn test_query_namespace() {
let graph = Graph::new();
graph.add_constant_properties([("name", "graph")]).unwrap();
graph.add_node(1, 1, NO_PROPS, Some("a")).unwrap();
graph.add_node(1, 2, NO_PROPS, Some("b")).unwrap();
graph.add_node(1, 3, NO_PROPS, Some("b")).unwrap();
graph.add_node(1, 4, NO_PROPS, Some("a")).unwrap();
graph.add_node(1, 5, NO_PROPS, Some("c")).unwrap();
graph.add_node(1, 6, NO_PROPS, Some("e")).unwrap();
graph.add_edge(2, 1, 2, NO_PROPS, Some("a")).unwrap();
graph.add_edge(2, 3, 2, NO_PROPS, Some("a")).unwrap();
graph.add_edge(2, 2, 4, NO_PROPS, Some("a")).unwrap();
graph.add_edge(2, 4, 5, NO_PROPS, Some("a")).unwrap();
graph.add_edge(2, 4, 5, NO_PROPS, Some("a")).unwrap();
graph.add_edge(2, 5, 6, NO_PROPS, Some("a")).unwrap();
graph.add_edge(2, 3, 6, NO_PROPS, Some("a")).unwrap();

let graph = graph.into();
let graphs = HashMap::from([("graph".to_string(), graph)]);
let tmp_dir = tempdir().unwrap();
save_graphs_to_work_dir(tmp_dir.path(), &graphs).unwrap();

let data = Data::new(tmp_dir.path(), &AppConfig::default());
let schema = App::create_schema().data(data).finish().unwrap();

let req = r#"
{
namespace(path: "") {
path
graphs {
path
name
metadata {
nodeCount
edgeCount
properties {
key
value
}
}
}
children {
path
}
parent {
path
}
}
}
"#;

let req = Request::new(req);
let res = schema.execute(req).await;
let data = res.data.into_json().unwrap();
assert_eq!(
data,
json!({
"namespace": {
"path": "",
"graphs": [
{
"path": "graph",
"name": "graph",
"metadata": {
"nodeCount": 6,
"edgeCount": 6,
"properties": [
{
"key": "name",
"value": "graph"
},
]
}
},
],
"children": [],
"parent": null
},
}),
);

let req = r#"
mutation CreateSubgraph {
createSubgraph(parentPath: "graph", newPath: "graph2", nodes: ["1", "2"], overwrite: false)
}
"#;
let req = Request::new(req);
let res = schema.execute(req).await;
assert_eq!(res.errors, vec![]);

let req = r#"
{
namespace(path: "") {
path
graphs {
path
name
metadata {
nodeCount
edgeCount
properties {
key
value
}
}
}
children {
path
}
parent {
path
}
}
}
"#;

let req = Request::new(req);
let res = schema.execute(req).await;
let data = res.data.into_json().unwrap();
assert_eq!(
data,
json!({
"namespace": {
"path": "",
"graphs": [
{
"path": "graph",
"name": "graph",
"metadata": {
"nodeCount": 6,
"edgeCount": 6,
"properties": [
{
"key": "name",
"value": "graph"
},
]
}
},
{
"path": "graph2",
"name": "graph2",
"metadata": {
"nodeCount": 2,
"edgeCount": 1,
"properties": [
{
"key": "name",
"value": "graph"
},
]
}
},
],
"children": [],
"parent": null
},
}),
);
}
}
32 changes: 28 additions & 4 deletions raphtory-graphql/src/model/graph/meta_graph.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use dynamic_graphql::{ResolvedObject, ResolvedObjectFields};
use raphtory::core::utils::errors::GraphError;

use crate::paths::ExistingGraphFolder;
use crate::{model::graph::property::GqlProp, paths::ExistingGraphFolder};
use dynamic_graphql::{ResolvedObject, ResolvedObjectFields, SimpleObject};
use raphtory::{core::utils::errors::GraphError, serialise::metadata::GraphMetadata};

#[derive(ResolvedObject)]
pub(crate) struct MetaGraph {
Expand Down Expand Up @@ -31,4 +30,29 @@ impl MetaGraph {
async fn last_updated(&self) -> Result<i64, GraphError> {
self.folder.last_updated()
}
async fn metadata(&self) -> Result<GqlGraphMetadata, GraphError> {
let metadata = self.folder.read_metadata()?;
Ok(GqlGraphMetadata::from(metadata))
}
}

#[derive(Clone, SimpleObject)]
pub(crate) struct GqlGraphMetadata {
pub(crate) node_count: usize,
pub(crate) edge_count: usize,
pub(crate) properties: Vec<GqlProp>,
}

impl From<GraphMetadata> for GqlGraphMetadata {
fn from(metadata: GraphMetadata) -> Self {
GqlGraphMetadata {
node_count: metadata.node_count,
edge_count: metadata.edge_count,
properties: metadata
.properties
.into_iter()
.map(|(key, prop)| GqlProp::new(key.to_string(), prop))
.collect(),
}
}
}
12 changes: 10 additions & 2 deletions raphtory-graphql/src/model/graph/namespace.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use crate::{
data::get_relative_path,
model::graph::meta_graph::MetaGraph,
paths::{valid_path, ExistingGraphFolder},
paths::{valid_path, ExistingGraphFolder, ValidGraphFolder},
};
use dynamic_graphql::{ResolvedObject, ResolvedObjectFields};
use itertools::Itertools;
use std::path::PathBuf;
use walkdir::WalkDir;

Expand Down Expand Up @@ -60,7 +61,14 @@ impl Namespace {
impl Namespace {
async fn graphs(&self) -> Vec<MetaGraph> {
self.get_all_graph_folders()
.iter()
.into_iter()
.sorted_by(|a, b| {
let a_as_valid_folder: ValidGraphFolder = a.clone().into();
let b_as_valid_folder: ValidGraphFolder = b.clone().into();
a_as_valid_folder
.get_original_path_str()
.cmp(b_as_valid_folder.get_original_path_str())
})
.map(|g| MetaGraph::new(g.clone()))
.collect()
}
Expand Down
11 changes: 4 additions & 7 deletions raphtory-graphql/src/model/graph/property.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
use async_graphql::{Error, Name, Value as GqlValue};
use dynamic_graphql::{
internal::{InputObject, Resolve},
Enum, InputObject, ResolvedObject, ResolvedObjectFields, Scalar, ScalarValue,
};
use dynamic_graphql::{InputObject, ResolvedObject, ResolvedObjectFields, Scalar, ScalarValue};
use itertools::Itertools;
use raphtory::{
core::{utils::errors::GraphError, IntoPropMap, Prop},
Expand Down Expand Up @@ -144,7 +141,7 @@ fn prop_to_gql(prop: &Prop) -> GqlValue {
}
}

#[derive(ResolvedObject)]
#[derive(Clone, ResolvedObject)]
pub(crate) struct GqlProp {
key: String,
prop: Prop,
Expand Down Expand Up @@ -354,7 +351,7 @@ impl GqlProperties {
self.props.temporal().into()
}

async fn constant(&self) -> GqlConstantProperties {
pub(crate) async fn constant(&self) -> GqlConstantProperties {
self.props.constant().into()
}
}
Expand All @@ -373,7 +370,7 @@ impl GqlConstantProperties {
self.props.keys().map(|k| k.clone().into()).collect()
}

async fn values(&self, keys: Option<Vec<String>>) -> Vec<GqlProp> {
pub(crate) async fn values(&self, keys: Option<Vec<String>>) -> Vec<GqlProp> {
match keys {
Some(keys) => self
.props
Expand Down
16 changes: 10 additions & 6 deletions raphtory-graphql/src/paths.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
use raphtory::{
core::utils::errors::{GraphError, InvalidPathReason, InvalidPathReason::*},
serialise::GraphFolder,
};
use std::{
fs,
ops::Deref,
path::{Component, Path, PathBuf},
time::{SystemTime, UNIX_EPOCH},
};

use raphtory::{
core::utils::errors::{GraphError, InvalidPathReason, InvalidPathReason::*},
serialise::GraphFolder,
};

#[derive(Clone, Debug)]
pub struct ExistingGraphFolder {
folder: ValidGraphFolder,
Expand All @@ -34,7 +33,6 @@ impl From<ExistingGraphFolder> for GraphFolder {
value.folder.folder
}
}

impl ExistingGraphFolder {
pub(crate) fn try_from(base_path: PathBuf, relative_path: &str) -> Result<Self, GraphError> {
let graph_folder = ValidGraphFolder::try_from(base_path, relative_path)?;
Expand Down Expand Up @@ -72,6 +70,12 @@ pub struct ValidGraphFolder {
folder: GraphFolder,
}

impl From<ExistingGraphFolder> for ValidGraphFolder {
fn from(value: ExistingGraphFolder) -> Self {
value.folder
}
}

impl Deref for ValidGraphFolder {
type Target = GraphFolder;

Expand Down
4 changes: 2 additions & 2 deletions raphtory/src/core/utils/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,8 +316,8 @@ pub enum GraphError {
TqdmError,
#[error("An error when parsing Jinja query templates: {0}")]
JinjaError(String),
#[error("An error when parsing the data to json")]
SerdeError,
#[error("An error when parsing the data to json: {0}")]
SerdeError(#[from] serde_json::Error),
#[error("System time error: {0}")]
SystemTimeError(#[from] SystemTimeError),
#[error("Property filtering not implemented on PersistentGraph yet")]
Expand Down
6 changes: 2 additions & 4 deletions raphtory/src/db/api/storage/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,8 @@ impl Storage {
/// Initialise the cache by pointing it at a proto file.
/// Future updates will be appended to the cache.
pub(crate) fn init_cache(&self, path: &GraphFolder) -> Result<(), GraphError> {
self.cache.get_or_try_init(|| {
let file = path.get_appendable_graph_file()?;
Ok::<_, GraphError>(GraphWriter::new(file))
})?;
self.cache
.get_or_try_init(|| Ok::<_, GraphError>(GraphWriter::new(path.clone())?))?;
Ok(())
}

Expand Down
Loading
Loading