#[cfg(not(target_family = "wasm"))]
use anyhow::*;
#[cfg(not(target_family = "wasm"))]
use clap::Parser;
#[cfg(not(target_family = "wasm"))]
use pgschema::cli::{Cli, Command};
#[cfg(not(target_family = "wasm"))]
use pgschema::parser::{map_builder::MapBuilder, pg_builder::PgBuilder, pgs_builder::PgsBuilder};
#[cfg(not(target_family = "wasm"))]
use std::result::Result::Ok;
// src/main.rs
#[cfg(target_family = "wasm")]
fn main() {}
#[cfg(not(target_family = "wasm"))]
fn main() -> Result<()> {
// Load environment variables from `.env`:
clientele::dotenv().ok();
// Expand wildcards and @argfiles:
let args = clientele::args_os()?;
// Parse command-line options:
let cli = Cli::parse_from(args);
match &cli.command {
Some(Command::Pgs { schema }) => run_pgs(schema),
Some(Command::Pg { graph }) => run_pg(graph),
Some(Command::TypeMap { map }) => run_map(map),
Some(Command::Validate { graph, schema, map }) => run_validate(graph, schema, map),
None => {
bail!("Command not specified, type `--help` to see list of commands")
},
}
}
#[cfg(not(target_family = "wasm"))]
fn run_pgs(schema: &str) -> Result<()> {
let schema = get_schema(schema)?;
println!("PGSchema:\n{}", schema);
Ok(())
}
#[cfg(not(target_family = "wasm"))]
fn run_pg(graph: &str) -> Result<()> {
let pg = get_graph(graph)?;
println!("Property graph:\n{}", pg);
Ok(())
}
#[cfg(not(target_family = "wasm"))]
fn run_map(map: &str) -> Result<()> {
let map = get_map(map)?;
println!("Type map associations:\n{}", map);
Ok(())
}
#[cfg(not(target_family = "wasm"))]
fn run_validate(graph_path: &str, schema_path: &str, map_path: &str) -> Result<()> {
let schema = get_schema(schema_path)?;
let graph = get_graph(graph_path)?;
let map = get_map(map_path)?;
let result = map.validate(&schema, &graph)?;
println!("Validation result:\n{}", result);
Ok(())
}
#[cfg(not(target_family = "wasm"))]
fn get_schema(path: &str) -> Result<pgschema::pgs::PropertyGraphSchema> {
let schema_content =
std::fs::read_to_string(path).with_context(|| format!("Failed to read schema file: {}", path))?;
let schema: pgschema::pgs::PropertyGraphSchema = match PgsBuilder::new().parse_pgs(schema_content.as_str()) {
Ok(schema) => schema,
Err(e) => {
bail!("Failed to parse schema: {}", e);
},
};
Ok(schema)
}
#[cfg(not(target_family = "wasm"))]
fn get_graph(path: &str) -> Result<pgschema::pg::PropertyGraph> {
let graph_content =
std::fs::read_to_string(path).with_context(|| format!("Failed to read graph file: {}", path))?;
let graph = match PgBuilder::new().parse_pg(graph_content.as_str()) {
Ok(graph) => graph,
Err(e) => {
bail!("Failed to parse graph: {}", e);
},
};
Ok(graph)
}
#[cfg(not(target_family = "wasm"))]
fn get_map(path: &str) -> Result<pgschema::type_map::TypeMap> {
let map_content =
std::fs::read_to_string(path).with_context(|| format!("Failed to read type map file: {}", path))?;
let map: pgschema::type_map::TypeMap = match MapBuilder::new().parse_map(map_content.as_str()) {
Ok(map) => map,
Err(e) => {
bail!("Failed to parse type map: {}", e);
},
};
Ok(map)
}
#[cfg(all(test, not(target_family = "wasm")))]
mod tests {
use super::*;
#[test]
fn adult() {
test_case(
"tests/adult.pg",
"tests/adult.pgs",
"tests/adult.map",
"tests/adult.result_map",
);
}
#[test]
fn a_or_b_and_a_or_c_content() {
test_case(
"tests/a_or_b_and_a_or_c_content.pg",
"tests/a_or_b_and_a_or_c_content.pgs",
"tests/a_or_b_and_a_or_c_content.map",
"tests/a_or_b_and_a_or_c_content.result_map",
);
}
#[test]
fn a_or_b_and_a_or_c_labels_content() {
test_case(
"tests/a_or_b_and_a_or_c_labels_content.pg",
"tests/a_or_b_and_a_or_c_labels_content.pgs",
"tests/a_or_b_and_a_or_c_labels_content.map",
"tests/a_or_b_and_a_or_c_labels_content.result_map",
);
}
#[test]
fn a_or_b_and_a_or_c_labels() {
test_case(
"tests/a_or_b_and_a_or_c.pg",
"tests/a_or_b_and_a_or_c.pgs",
"tests/a_or_b_and_a_or_c.map",
"tests/a_or_b_and_a_or_c.result_map",
);
}
#[test]
fn user() {
test_case(
"tests/user.pg",
"tests/user.pgs",
"tests/user.map",
"tests/user.result_map",
);
}
#[test]
fn course() {
test_case(
"tests/course.pg",
"tests/course.pgs",
"tests/course.map",
"tests/course.result_map",
);
}
#[test]
fn person() {
test_case(
"tests/person.pg",
"tests/person.pgs",
"tests/person.map",
"tests/person.result_map",
);
}
#[test]
fn product() {
test_case(
"tests/product.pg",
"tests/product.pgs",
"tests/product.map",
"tests/product.result_map",
);
}
#[test]
fn any() {
test_case("tests/any.pg", "tests/any.pgs", "tests/any.map", "tests/any.result_map");
}
#[test]
fn simple() {
test_case(
"tests/simple.pg",
"tests/simple.pgs",
"tests/simple.map",
"tests/simple.result_map",
);
}
#[test]
fn email() {
// It checks regexes
test_case(
"tests/email.pg",
"tests/email.pgs",
"tests/email.map",
"tests/email.result_map",
);
}
#[test]
fn edge() {
// It checks regexes
test_case(
"tests/edge.pg",
"tests/edge.pgs",
"tests/edge.map",
"tests/edge.result_map",
);
}
#[test]
fn basic() {
// It checks regexes
test_case(
"tests/basic.pg",
"tests/basic.pgs",
"tests/basic.map",
"tests/basic.result_map",
);
}
#[test]
fn datatypes() {
// It checks datatypes
test_case(
"tests/datatypes.pg",
"tests/datatypes.pgs",
"tests/datatypes.map",
"tests/datatypes.result_map",
);
}
#[test]
fn employee() {
// It checks simple inheritance
test_case(
"tests/employee.pg",
"tests/employee.pgs",
"tests/employee.map",
"tests/employee.result_map",
);
}
fn test_case(pg_file: &str, pgs_file: &str, map_file: &str, expected_map_file: &str) {
let pg = get_graph(pg_file).unwrap_or_else(|_| panic!("Failed to parse: {pg_file})"));
let pgs = get_schema(pgs_file).unwrap_or_else(|_| panic!("Failed to parse: {pgs_file})"));
let type_map = get_map(map_file).unwrap_or_else(|_| panic!("Failed to parse: {map_file})"));
let expected_result =
get_map(expected_map_file).unwrap_or_else(|_| panic!("Failed to parse: {expected_map_file})"));
let result = type_map.validate(&pgs, &pg).unwrap();
let comparison = expected_result.compare_with_result(&result).unwrap();
if comparison.is_empty() {
// Test passed
} else {
panic!(
"Validation failed: {}",
comparison.iter().map(|f| f.to_string()).collect::<Vec<_>>().join("\n")
);
}
}
}