From 0858ac66a71cc4152a84168291814e8530bf94e7 Mon Sep 17 00:00:00 2001 From: David Lutterkort Date: Wed, 13 Dec 2023 12:44:59 -0800 Subject: [PATCH 1/2] Add a graph-node-napi crate This crate exposes graph-node functionality for Node's N-API --- Cargo.lock | 101 ++++++++++++++++++++++++++++++++++++++++++++++-- Cargo.toml | 2 +- napi/Cargo.toml | 11 ++++++ napi/src/lib.rs | 22 +++++++++++ 4 files changed, 132 insertions(+), 4 deletions(-) create mode 100644 napi/Cargo.toml create mode 100644 napi/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 6ce187405e5..96767fb9549 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -631,6 +631,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "core-foundation" version = "0.9.1" @@ -899,6 +908,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "ctor" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d2b3721e861707777e3195b0158f950ae6dc4a27e4d02ff9f67e3eb3de199e" +dependencies = [ + "quote", + "syn 2.0.32", +] + [[package]] name = "data-encoding" version = "2.3.2" @@ -948,7 +967,7 @@ version = "0.99.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ - "convert_case", + "convert_case 0.4.0", "proc-macro2", "quote", "rustc_version", @@ -1811,6 +1830,15 @@ dependencies = [ "url", ] +[[package]] +name = "graph-node-napi" +version = "0.1.0" +dependencies = [ + "graph", + "napi", + "napi-derive", +] + [[package]] name = "graph-runtime-derive" version = "0.33.0" @@ -2643,6 +2671,16 @@ version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +[[package]] +name = "libloading" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" +dependencies = [ + "cfg-if 1.0.0", + "windows-sys 0.48.0", +] + [[package]] name = "linux-raw-sys" version = "0.3.1" @@ -2876,6 +2914,57 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" +[[package]] +name = "napi" +version = "2.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1133249c46e92da921bafc8aba4912bf84d6c475f7625183772ed2d0844dc3a7" +dependencies = [ + "bitflags 2.4.0", + "ctor", + "napi-derive", + "napi-sys", + "once_cell", +] + +[[package]] +name = "napi-derive" +version = "2.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b5af262f1d8e660742eb722abc7113a5b3c3de4144d0ef23ede2518672ceff1" +dependencies = [ + "cfg-if 1.0.0", + "convert_case 0.6.0", + "napi-derive-backend", + "proc-macro2", + "quote", + "syn 2.0.32", +] + +[[package]] +name = "napi-derive-backend" +version = "1.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea236321b521d6926213a2021e407b0562e28a257c037a45919e414d2cdb4f8" +dependencies = [ + "convert_case 0.6.0", + "once_cell", + "proc-macro2", + "quote", + "regex", + "semver", + "syn 2.0.32", +] + +[[package]] +name = "napi-sys" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2503fa6af34dc83fb74888df8b22afe933b58d37daf7d80424b1c60c68196b8b" +dependencies = [ + "libloading", +] + [[package]] name = "native-tls" version = "0.2.11" @@ -2973,9 +3062,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.13.1" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opaque-debug" @@ -5083,6 +5172,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + [[package]] name = "unicode-width" version = "0.1.8" diff --git a/Cargo.toml b/Cargo.toml index 1b49e8b2194..7a3f3504f78 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ members = [ "core", "chain/*", "graphql", + "napi", "node", "runtime/*", "server/*", @@ -38,4 +39,3 @@ incremental = false lto = true opt-level = 's' strip = "debuginfo" - diff --git a/napi/Cargo.toml b/napi/Cargo.toml new file mode 100644 index 00000000000..a4d25c8e86e --- /dev/null +++ b/napi/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "graph-node-napi" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +graph = { path = "../graph" } +napi = "2.14.1" +napi-derive = "2.14.4" diff --git a/napi/src/lib.rs b/napi/src/lib.rs new file mode 100644 index 00000000000..042a73e51b5 --- /dev/null +++ b/napi/src/lib.rs @@ -0,0 +1,22 @@ +use napi::bindgen_prelude as n; +use napi_derive::napi; + +use graph::{data::subgraph::DeploymentHash, schema::InputSchema}; + +#[napi] +pub fn validate_schema(schema: String, id: String) -> n::Result { + let id = match DeploymentHash::new(id) { + Ok(id) => id, + Err(e) => { + return Err(n::Error::new( + n::Status::InvalidArg, + format!("Invalid deployment hash {e}"), + )) + } + }; + let res = InputSchema::parse(&schema, id); + match res { + Ok(_) => Ok("ok".to_string()), + Err(e) => Err(n::Error::new(n::Status::GenericFailure, e.to_string())), + } +} From 01aed9c968030b5b78ad026cb3c8094b608839de Mon Sep 17 00:00:00 2001 From: David Lutterkort Date: Wed, 13 Dec 2023 14:03:27 -0800 Subject: [PATCH 2/2] graph, napi: Return each error as its own string --- graph/src/schema/input_schema.rs | 15 ++++++++++++++- graph/src/schema/mod.rs | 2 ++ napi/src/lib.rs | 12 ++++++------ 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/graph/src/schema/input_schema.rs b/graph/src/schema/input_schema.rs index c286f6ed527..13f77c5b56b 100644 --- a/graph/src/schema/input_schema.rs +++ b/graph/src/schema/input_schema.rs @@ -19,7 +19,9 @@ use crate::schema::api::api_schema; use crate::util::intern::{Atom, AtomPool}; use super::fulltext::FulltextDefinition; -use super::{ApiSchema, AsEntityTypeName, EntityType, Schema, SCHEMA_TYPE_NAME}; +use super::{ + ApiSchema, AsEntityTypeName, EntityType, Schema, SchemaValidationError, SCHEMA_TYPE_NAME, +}; /// The name of the PoI entity type pub(crate) const POI_OBJECT: &str = "Poi$"; @@ -465,6 +467,17 @@ impl InputSchema { }) } + pub fn validate(raw: &str, id: DeploymentHash) -> Vec { + let schema = match Schema::parse(raw, id.clone()) { + Ok(schema) => schema, + Err(err) => return vec![SchemaValidationError::InvalidSchema(err.to_string())], + }; + match validations::validate(&schema) { + Ok(_) => vec![], + Err(errors) => errors, + } + } + /// Convenience for tests to construct an `InputSchema` /// /// # Panics diff --git a/graph/src/schema/mod.rs b/graph/src/schema/mod.rs index 80b54ddb22b..1c1be8cd927 100644 --- a/graph/src/schema/mod.rs +++ b/graph/src/schema/mod.rs @@ -52,6 +52,8 @@ impl fmt::Display for Strings { #[derive(Debug, Error, PartialEq, Eq)] pub enum SchemaValidationError { + #[error("Invalid schema: {0}")] + InvalidSchema(String), #[error("Interface `{0}` not defined")] InterfaceUndefined(String), diff --git a/napi/src/lib.rs b/napi/src/lib.rs index 042a73e51b5..0ab1171aa0e 100644 --- a/napi/src/lib.rs +++ b/napi/src/lib.rs @@ -4,7 +4,7 @@ use napi_derive::napi; use graph::{data::subgraph::DeploymentHash, schema::InputSchema}; #[napi] -pub fn validate_schema(schema: String, id: String) -> n::Result { +pub fn validate_schema(schema: String, id: String) -> n::Result> { let id = match DeploymentHash::new(id) { Ok(id) => id, Err(e) => { @@ -14,9 +14,9 @@ pub fn validate_schema(schema: String, id: String) -> n::Result { )) } }; - let res = InputSchema::parse(&schema, id); - match res { - Ok(_) => Ok("ok".to_string()), - Err(e) => Err(n::Error::new(n::Status::GenericFailure, e.to_string())), - } + let errs = InputSchema::validate(&schema, id) + .into_iter() + .map(|e| e.to_string()) + .collect(); + Ok(errs) }