From 82504e2825c79bfeff03e5c60a3e313a87a91543 Mon Sep 17 00:00:00 2001 From: Natoandro Date: Thu, 6 Feb 2025 15:06:04 +0300 Subject: [PATCH 1/6] wip --- Cargo.lock | 38 +- Cargo.toml | 6 + src/common/src/lib.rs | 9 - src/metagen/Cargo.toml | 4 +- src/metagen/src/client_py/mod.rs | 2 +- src/metagen/src/client_py/node_metas.rs | 2 +- src/metagen/src/client_py/selections.rs | 2 +- src/metagen/src/client_py/types.rs | 2 +- src/metagen/src/client_rs/mod.rs | 2 +- src/metagen/src/client_rs/node_metas.rs | 2 +- src/metagen/src/client_rs/selections.rs | 2 +- src/metagen/src/client_ts/mod.rs | 2 +- src/metagen/src/client_ts/node_metas.rs | 2 +- src/metagen/src/client_ts/selections.rs | 2 +- src/metagen/src/fdk_rs/types.rs | 2 +- src/metagen/src/fdk_ts/types.rs | 2 +- src/metagen/src/lib.rs | 4 +- src/metagen/src/shared/client.rs | 6 +- src/metagen/src/shared/files.rs | 2 +- src/metagen/src/shared/mod.rs | 2 +- src/metagen/src/shared/types.rs | 4 +- src/typegraph/core/Cargo.toml | 5 +- .../src/conversion/parameter_transform.rs | 2 +- src/typegraph/core/src/conversion/params.rs | 2 +- src/typegraph/core/src/conversion/policies.rs | 2 +- src/typegraph/core/src/conversion/runtimes.rs | 40 +- src/typegraph/core/src/conversion/types.rs | 2 +- src/typegraph/core/src/global_store.rs | 8 +- src/typegraph/core/src/lib.rs | 4 +- src/typegraph/core/src/runtimes/aws/mod.rs | 4 +- src/typegraph/core/src/runtimes/deno.rs | 2 +- src/typegraph/core/src/runtimes/graphql.rs | 2 +- src/typegraph/core/src/runtimes/grpc/mod.rs | 2 +- .../core/src/runtimes/grpc/type_generation.rs | 2 +- .../core/src/runtimes/prisma/context.rs | 2 +- .../core/src/runtimes/prisma/migration.rs | 2 +- src/typegraph/core/src/runtimes/prisma/mod.rs | 4 +- .../core/src/runtimes/prisma/model.rs | 10 +- .../prisma/type_generation/input_type.rs | 2 +- .../runtimes/prisma/type_generation/where_.rs | 2 +- .../core/src/runtimes/substantial/mod.rs | 2 +- src/typegraph/core/src/runtimes/typegate.rs | 2 +- src/typegraph/core/src/runtimes/typegraph.rs | 2 +- src/typegraph/core/src/typedef/boolean.rs | 2 +- src/typegraph/core/src/typedef/either.rs | 2 +- src/typegraph/core/src/typedef/file.rs | 2 +- src/typegraph/core/src/typedef/float.rs | 2 +- src/typegraph/core/src/typedef/func.rs | 6 +- src/typegraph/core/src/typedef/integer.rs | 2 +- src/typegraph/core/src/typedef/list.rs | 2 +- src/typegraph/core/src/typedef/optional.rs | 2 +- src/typegraph/core/src/typedef/string.rs | 2 +- src/typegraph/core/src/typedef/struct_.rs | 2 +- src/typegraph/core/src/typedef/union.rs | 2 +- src/typegraph/core/src/typegraph.rs | 14 +- src/typegraph/core/src/types/type_def.rs | 2 +- src/typegraph/core/src/types/type_ref.rs | 2 +- .../core/src/types/type_ref/injection.rs | 2 +- src/typegraph/core/src/utils/archive.rs | 2 +- src/typegraph/core/src/utils/artifacts.rs | 2 +- src/typegraph/core/src/utils/metagen_utils.rs | 2 +- src/typegraph/core/src/utils/mod.rs | 2 +- .../core/src/utils/postprocess/deno_rt.rs | 6 +- .../core/src/utils/postprocess/mod.rs | 2 +- .../core/src/utils/postprocess/naming.rs | 11 +- .../core/src/utils/postprocess/prisma_rt.rs | 6 +- .../core/src/utils/postprocess/python_rt.rs | 4 +- .../src/utils/postprocess/substantial_rt.rs | 4 +- .../core/src/utils/postprocess/validation.rs | 2 +- .../core/src/utils/postprocess/wasm_rt.rs | 2 +- .../core/src/validation/materializers.rs | 2 +- src/typegraph/schema/Cargo.toml | 26 + src/typegraph/schema/src/lib.rs | 215 ++++++ .../schema/src/parameter_transform.rs | 53 ++ .../schema/src}/runtimes/deno.rs | 0 .../schema/src}/runtimes/graphql.rs | 0 .../schema/src}/runtimes/grpc.rs | 0 .../schema/src}/runtimes/http.rs | 0 .../schema/src}/runtimes/kv.rs | 0 .../schema/src}/runtimes/mod.rs | 0 .../schema/src}/runtimes/prisma.rs | 0 .../schema/src}/runtimes/python.rs | 0 .../schema/src}/runtimes/random.rs | 0 .../schema/src}/runtimes/s3.rs | 0 .../schema/src}/runtimes/substantial.rs | 0 .../schema/src}/runtimes/temporal.rs | 0 .../schema/src}/runtimes/wasm.rs | 0 src/typegraph/schema/src/types.rs | 380 ++++++++++ src/typegraph/schema/src/utils.rs | 42 ++ src/typegraph/schema/src/validator/common.rs | 53 ++ .../schema/src/validator/injection.rs | 269 +++++++ src/typegraph/schema/src/validator/input.rs | 41 ++ src/typegraph/schema/src/validator/mod.rs | 277 ++++++++ src/typegraph/schema/src/validator/types.rs | 662 ++++++++++++++++++ src/typegraph/schema/src/validator/value.rs | 268 +++++++ src/typegraph/schema/src/visitor.rs | 447 ++++++++++++ src/typegraph/schema/src/visitor2.rs | 253 +++++++ src/utils/archive/Cargo.toml | 12 + .../archive.rs => utils/archive/src/lib.rs} | 0 src/utils/grpc/Cargo.toml | 9 + .../src/grpc.rs => utils/grpc/src/lib.rs} | 0 101 files changed, 3169 insertions(+), 135 deletions(-) create mode 100644 src/typegraph/schema/Cargo.toml create mode 100644 src/typegraph/schema/src/lib.rs create mode 100644 src/typegraph/schema/src/parameter_transform.rs rename src/{common/src/typegraph => typegraph/schema/src}/runtimes/deno.rs (100%) rename src/{common/src/typegraph => typegraph/schema/src}/runtimes/graphql.rs (100%) rename src/{common/src/typegraph => typegraph/schema/src}/runtimes/grpc.rs (100%) rename src/{common/src/typegraph => typegraph/schema/src}/runtimes/http.rs (100%) rename src/{common/src/typegraph => typegraph/schema/src}/runtimes/kv.rs (100%) rename src/{common/src/typegraph => typegraph/schema/src}/runtimes/mod.rs (100%) rename src/{common/src/typegraph => typegraph/schema/src}/runtimes/prisma.rs (100%) rename src/{common/src/typegraph => typegraph/schema/src}/runtimes/python.rs (100%) rename src/{common/src/typegraph => typegraph/schema/src}/runtimes/random.rs (100%) rename src/{common/src/typegraph => typegraph/schema/src}/runtimes/s3.rs (100%) rename src/{common/src/typegraph => typegraph/schema/src}/runtimes/substantial.rs (100%) rename src/{common/src/typegraph => typegraph/schema/src}/runtimes/temporal.rs (100%) rename src/{common/src/typegraph => typegraph/schema/src}/runtimes/wasm.rs (100%) create mode 100644 src/typegraph/schema/src/types.rs create mode 100644 src/typegraph/schema/src/utils.rs create mode 100644 src/typegraph/schema/src/validator/common.rs create mode 100644 src/typegraph/schema/src/validator/injection.rs create mode 100644 src/typegraph/schema/src/validator/input.rs create mode 100644 src/typegraph/schema/src/validator/mod.rs create mode 100644 src/typegraph/schema/src/validator/types.rs create mode 100644 src/typegraph/schema/src/validator/value.rs create mode 100644 src/typegraph/schema/src/visitor.rs create mode 100644 src/typegraph/schema/src/visitor2.rs create mode 100644 src/utils/archive/Cargo.toml rename src/{common/src/archive.rs => utils/archive/src/lib.rs} (100%) create mode 100644 src/utils/grpc/Cargo.toml rename src/{common/src/grpc.rs => utils/grpc/src/lib.rs} (100%) diff --git a/Cargo.lock b/Cargo.lock index 7c0aa4aaca..d3ca3d2060 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -341,6 +341,18 @@ dependencies = [ "derive_arbitrary", ] +[[package]] +name = "archive_utils" +version = "0.5.1-rc.0" +dependencies = [ + "anyhow", + "base64 0.22.1", + "flate2", + "ignore", + "indexmap 2.6.0", + "tar", +] + [[package]] name = "arrayvec" version = "0.7.4" @@ -5300,6 +5312,15 @@ dependencies = [ "subtle", ] +[[package]] +name = "grpc_utils" +version = "0.5.1-rc.0" +dependencies = [ + "anyhow", + "proto-parser", + "protobuf", +] + [[package]] name = "gzip-header" version = "1.0.0" @@ -7035,7 +7056,6 @@ name = "metagen" version = "0.5.1-rc.0" dependencies = [ "color-eyre", - "common", "dashmap 6.1.0", "futures-concurrency", "futures-lite 2.3.0", @@ -7051,6 +7071,7 @@ dependencies = [ "serde_json", "tempfile", "tera", + "tg_schema", "tokio", ] @@ -12241,6 +12262,17 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "tg_schema" +version = "0.5.1-rc.0" +dependencies = [ + "anyhow", + "indexmap 2.6.0", + "serde", + "serde_json", + "serde_with", +] + [[package]] name = "thiserror" version = "1.0.64" @@ -13013,11 +13045,12 @@ name = "typegraph_core" version = "0.5.1-rc.0" dependencies = [ "anyhow", + "archive_utils", "color-eyre", - "common", "enum_dispatch", "glob", "graphql-parser 0.4.0", + "grpc_utils", "indexmap 2.6.0", "indoc", "insta", @@ -13031,6 +13064,7 @@ dependencies = [ "serde", "serde_json", "sha2 0.10.8", + "tg_schema", "unindent", "wit-bindgen", ] diff --git a/Cargo.toml b/Cargo.toml index a2f8396ca9..03ad9eff1e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,10 @@ members = [ "src/typegate/engine", "src/typegate/standalone", "src/typegraph/core", + "src/typegraph/schema", "src/xtask", + "src/utils/grpc", + "src/utils/archive", "src/substantial", "src/metagen-client-rs", "tests/metagen/typegraphs/sample/rs", @@ -32,10 +35,13 @@ edition = "2021" # internal crates mt_deno = { path = "src/mt_deno/" } common = { path = "src/common/" } +tg_schema = { path = "src/typegraph/schema" } substantial = { path = "src/substantial/" } metagen = { path = "src/metagen/" } metagen-client = { path = "src/metagen-client-rs" } typegate_engine = { path = "src/typegate/engine" } +grpc_utils = { path = "src/utils/grpc" } +archive_utils = { path = "src/utils/archive" } # cli clap = "=4.5.13" diff --git a/src/common/src/lib.rs b/src/common/src/lib.rs index 013467534d..1d568bd4f9 100644 --- a/src/common/src/lib.rs +++ b/src/common/src/lib.rs @@ -1,14 +1,5 @@ // Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. // SPDX-License-Identifier: MPL-2.0 -pub mod archive; -pub mod grpc; -pub mod typegraph; - -// Note: -// try refactoring the typegraph deploy feature on both sdks -// once WebAssembly async and networking have matured enough -#[cfg(not(target_arch = "wasm32"))] pub mod graphql; -#[cfg(not(target_arch = "wasm32"))] pub mod node; diff --git a/src/metagen/Cargo.toml b/src/metagen/Cargo.toml index 87279d2620..88bcfa79fb 100644 --- a/src/metagen/Cargo.toml +++ b/src/metagen/Cargo.toml @@ -10,9 +10,7 @@ version.workspace = true path = "src/lib.rs" [dependencies] -# this library is used by typegraph_core -# so keep the codesize lite -common.workspace = true +tg_schema.workspace = true # logging log.workspace = true diff --git a/src/metagen/src/client_py/mod.rs b/src/metagen/src/client_py/mod.rs index 9f29a93a4a..e56ec2f1bb 100644 --- a/src/metagen/src/client_py/mod.rs +++ b/src/metagen/src/client_py/mod.rs @@ -9,8 +9,8 @@ mod utils; use core::fmt::Write; -use common::typegraph::EffectType; use shared::get_gql_type; +use tg_schema::EffectType; use crate::interlude::*; use crate::*; diff --git a/src/metagen/src/client_py/node_metas.rs b/src/metagen/src/client_py/node_metas.rs index ef788764f7..9bf90cbf06 100644 --- a/src/metagen/src/client_py/node_metas.rs +++ b/src/metagen/src/client_py/node_metas.rs @@ -3,7 +3,7 @@ use std::{collections::HashMap, fmt::Write}; -use common::typegraph::*; +use tg_schema::*; use super::utils::normalize_type_title; use crate::{ diff --git a/src/metagen/src/client_py/selections.rs b/src/metagen/src/client_py/selections.rs index 4b66385539..9085fc6329 100644 --- a/src/metagen/src/client_py/selections.rs +++ b/src/metagen/src/client_py/selections.rs @@ -3,7 +3,7 @@ use std::fmt::Write; -use common::typegraph::*; +use tg_schema::*; use super::utils::*; use crate::{interlude::*, shared::client::*, shared::types::*}; diff --git a/src/metagen/src/client_py/types.rs b/src/metagen/src/client_py/types.rs index 490ba7f4e5..6c65b4ad86 100644 --- a/src/metagen/src/client_py/types.rs +++ b/src/metagen/src/client_py/types.rs @@ -3,7 +3,7 @@ use std::fmt::Write; -use common::typegraph::*; +use tg_schema::*; use super::utils::{normalize_struct_prop_name, normalize_type_title}; use crate::{interlude::*, shared::types::*}; diff --git a/src/metagen/src/client_rs/mod.rs b/src/metagen/src/client_rs/mod.rs index ff25087f03..04722c158f 100644 --- a/src/metagen/src/client_rs/mod.rs +++ b/src/metagen/src/client_rs/mod.rs @@ -6,7 +6,7 @@ mod selections; use core::fmt::Write; -use common::typegraph::EffectType; +use tg_schema::EffectType; use shared::get_gql_type; use crate::interlude::*; diff --git a/src/metagen/src/client_rs/node_metas.rs b/src/metagen/src/client_rs/node_metas.rs index c9a5fc34c2..c350d829a3 100644 --- a/src/metagen/src/client_rs/node_metas.rs +++ b/src/metagen/src/client_rs/node_metas.rs @@ -3,7 +3,7 @@ use std::{collections::HashMap, fmt::Write}; -use common::typegraph::*; +use tg_schema::*; use super::utils::normalize_type_title; use crate::{ diff --git a/src/metagen/src/client_rs/selections.rs b/src/metagen/src/client_rs/selections.rs index fcaf10112e..df144bd61e 100644 --- a/src/metagen/src/client_rs/selections.rs +++ b/src/metagen/src/client_rs/selections.rs @@ -3,7 +3,7 @@ use std::fmt::Write; -use common::typegraph::*; +use tg_schema::*; use super::utils::*; use crate::{interlude::*, shared::client::*, shared::types::*}; diff --git a/src/metagen/src/client_ts/mod.rs b/src/metagen/src/client_ts/mod.rs index c8e343b715..63c6237ca1 100644 --- a/src/metagen/src/client_ts/mod.rs +++ b/src/metagen/src/client_ts/mod.rs @@ -6,8 +6,8 @@ mod selections; use core::fmt::Write; -use common::typegraph::EffectType; use shared::get_gql_type; +use tg_schema::EffectType; use crate::interlude::*; use crate::*; diff --git a/src/metagen/src/client_ts/node_metas.rs b/src/metagen/src/client_ts/node_metas.rs index 8605a5e98b..d0af47b78f 100644 --- a/src/metagen/src/client_ts/node_metas.rs +++ b/src/metagen/src/client_ts/node_metas.rs @@ -3,7 +3,7 @@ use std::{collections::HashMap, fmt::Write}; -use common::typegraph::*; +use tg_schema::*; use super::utils::normalize_type_title; use crate::{ diff --git a/src/metagen/src/client_ts/selections.rs b/src/metagen/src/client_ts/selections.rs index c1ac6e68e0..48857cfb39 100644 --- a/src/metagen/src/client_ts/selections.rs +++ b/src/metagen/src/client_ts/selections.rs @@ -3,7 +3,7 @@ use std::fmt::Write; -use common::typegraph::*; +use tg_schema::*; use super::utils::*; use crate::{interlude::*, shared::client::*, shared::types::*}; diff --git a/src/metagen/src/fdk_rs/types.rs b/src/metagen/src/fdk_rs/types.rs index 417b6aeddf..14e7d68cef 100644 --- a/src/metagen/src/fdk_rs/types.rs +++ b/src/metagen/src/fdk_rs/types.rs @@ -4,9 +4,9 @@ use super::utils::*; use crate::interlude::*; use crate::shared::types::*; -use common::typegraph::*; use heck::ToPascalCase; use std::fmt::Write; +use tg_schema::*; pub struct RustTypeRenderer { pub derive_debug: bool, diff --git a/src/metagen/src/fdk_ts/types.rs b/src/metagen/src/fdk_ts/types.rs index 6fc6476c70..adb8b85a3a 100644 --- a/src/metagen/src/fdk_ts/types.rs +++ b/src/metagen/src/fdk_ts/types.rs @@ -3,7 +3,7 @@ use std::fmt::Write; -use common::typegraph::*; +use tg_schema::*; use super::utils::{normalize_struct_prop_name, normalize_type_title}; use crate::{interlude::*, shared::types::*}; diff --git a/src/metagen/src/lib.rs b/src/metagen/src/lib.rs index 8b14add6d0..0925c61fb9 100644 --- a/src/metagen/src/lib.rs +++ b/src/metagen/src/lib.rs @@ -3,8 +3,8 @@ #[allow(unused)] mod interlude { - pub use common::typegraph::TypeNode; - pub use common::typegraph::Typegraph; + pub use tg_schema::TypeNode; + pub use tg_schema::Typegraph; pub use std::collections::{BTreeMap, BTreeSet}; pub use std::ops::Deref; diff --git a/src/metagen/src/shared/client.rs b/src/metagen/src/shared/client.rs index 39a592b9e8..cc228ab0cd 100644 --- a/src/metagen/src/shared/client.rs +++ b/src/metagen/src/shared/client.rs @@ -9,8 +9,8 @@ use super::{ files::{get_path_to_files, TypePath}, types::*, }; -use common::typegraph::{EffectType, ListTypeData, OptionalTypeData}; use indexmap::IndexSet; +use tg_schema::{EffectType, ListTypeData, OptionalTypeData}; pub struct RenderManifest { pub return_types: IndexSet, @@ -155,11 +155,11 @@ pub fn selection_for_field( select_ty: renderer.render_subgraph(ty, cursor)?.0.unwrap(), }, TypeNode::Either { - data: common::typegraph::EitherTypeData { one_of: variants }, + data: tg_schema::EitherTypeData { one_of: variants }, .. } | TypeNode::Union { - data: common::typegraph::UnionTypeData { any_of: variants }, + data: tg_schema::UnionTypeData { any_of: variants }, .. } => { let select_ty = renderer.render_subgraph(ty, cursor)?.0.unwrap(); diff --git a/src/metagen/src/shared/files.rs b/src/metagen/src/shared/files.rs index f2e5230bf9..2b89023bb9 100644 --- a/src/metagen/src/shared/files.rs +++ b/src/metagen/src/shared/files.rs @@ -4,7 +4,7 @@ use std::collections::HashMap; use crate::interlude::*; -use common::typegraph::{ +use tg_schema::{ visitor::{Edge, PathSegment}, visitor2::{self, NearestFn, VisitNext}, Typegraph, diff --git a/src/metagen/src/shared/mod.rs b/src/metagen/src/shared/mod.rs index 4d3445e32e..3e5103ad18 100644 --- a/src/metagen/src/shared/mod.rs +++ b/src/metagen/src/shared/mod.rs @@ -8,7 +8,7 @@ pub mod client; pub mod files; pub mod types; -use common::typegraph::{runtimes::TGRuntime, Materializer}; +use tg_schema::{runtimes::TGRuntime, Materializer}; use crate::interlude::*; diff --git a/src/metagen/src/shared/types.rs b/src/metagen/src/shared/types.rs index caa8f58dbd..34cce31ffe 100644 --- a/src/metagen/src/shared/types.rs +++ b/src/metagen/src/shared/types.rs @@ -3,7 +3,7 @@ use std::fmt::Write; -use common::typegraph::*; +use tg_schema::*; use crate::{interlude::*, utils::GenDestBuf}; @@ -273,7 +273,7 @@ pub fn type_body_required(node: Rc) -> bool { TypeNode::Integer { base, data: - common::typegraph::IntegerTypeData { + tg_schema::IntegerTypeData { minimum: None, maximum: None, multiple_of: None, diff --git a/src/typegraph/core/Cargo.toml b/src/typegraph/core/Cargo.toml index 1f3fb79a19..c548e04189 100644 --- a/src/typegraph/core/Cargo.toml +++ b/src/typegraph/core/Cargo.toml @@ -7,8 +7,11 @@ edition = "2021" crate-type = ["cdylib", "rlib"] [dependencies] -common.workspace = true +# common.workspace = true +tg_schema.workspace = true metagen.workspace = true +grpc_utils.workspace = true +archive_utils.workspace = true enum_dispatch.workspace = true color-eyre.workspace = true diff --git a/src/typegraph/core/src/conversion/parameter_transform.rs b/src/typegraph/core/src/conversion/parameter_transform.rs index 9b47a9d8c9..320d0791e3 100644 --- a/src/typegraph/core/src/conversion/parameter_transform.rs +++ b/src/typegraph/core/src/conversion/parameter_transform.rs @@ -9,7 +9,7 @@ use crate::t; use crate::t::TypeBuilder; use crate::types::TypeId; use crate::{params::apply::*, typegraph::TypegraphContext}; -use common::typegraph::parameter_transform as cm; +use tg_schema::parameter_transform as cm; pub fn convert_tree( ctx: &mut TypegraphContext, diff --git a/src/typegraph/core/src/conversion/params.rs b/src/typegraph/core/src/conversion/params.rs index f11b391357..38238cfd7a 100644 --- a/src/typegraph/core/src/conversion/params.rs +++ b/src/typegraph/core/src/conversion/params.rs @@ -2,8 +2,8 @@ // SPDX-License-Identifier: MPL-2.0 use crate::errors::Result; -use common::typegraph::{Auth, AuthProtocol, Cors, Rate}; use indexmap::IndexMap; +use tg_schema::{Auth, AuthProtocol, Cors, Rate}; impl From for Cors { fn from(value: crate::wit::core::Cors) -> Self { diff --git a/src/typegraph/core/src/conversion/policies.rs b/src/typegraph/core/src/conversion/policies.rs index 1c2747fc91..e0b794fa91 100644 --- a/src/typegraph/core/src/conversion/policies.rs +++ b/src/typegraph/core/src/conversion/policies.rs @@ -1,7 +1,7 @@ // Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. // SPDX-License-Identifier: MPL-2.0 -use common::typegraph::Policy; +use tg_schema::Policy; use crate::errors::Result; use crate::typegraph::TypegraphContext; diff --git a/src/typegraph/core/src/conversion/runtimes.rs b/src/typegraph/core/src/conversion/runtimes.rs index 537bd4e7d2..bf3ff3d1c6 100644 --- a/src/typegraph/core/src/conversion/runtimes.rs +++ b/src/typegraph/core/src/conversion/runtimes.rs @@ -12,23 +12,6 @@ use crate::wit::runtimes::{ HttpMethod, KvMaterializer, MaterializerHttpRequest, SubstantialBackend, }; use crate::{typegraph::TypegraphContext, wit::runtimes::Effect as WitEffect}; -use common::typegraph::runtimes::deno::DenoRuntimeData; -use common::typegraph::runtimes::graphql::GraphQLRuntimeData; -use common::typegraph::runtimes::grpc::GrpcRuntimeData; -use common::typegraph::runtimes::http::HTTPRuntimeData; -use common::typegraph::runtimes::kv::KvRuntimeData; -use common::typegraph::runtimes::python::PythonRuntimeData; -use common::typegraph::runtimes::random::RandomRuntimeData; -use common::typegraph::runtimes::s3::S3RuntimeData; -use common::typegraph::runtimes::substantial::{ - self, RedisConfig, SubstantialRuntimeData, WorkflowFileDescription, -}; -use common::typegraph::runtimes::temporal::TemporalRuntimeData; -use common::typegraph::runtimes::wasm::WasmRuntimeData; -use common::typegraph::runtimes::{ - Artifact, KnownRuntime, PrismaMigrationRuntimeData, TypegateRuntimeData, TypegraphRuntimeData, -}; -use common::typegraph::{runtimes::TGRuntime, Effect, EffectType, Materializer}; use enum_dispatch::enum_dispatch; use indexmap::IndexMap; use serde_json::json; @@ -36,6 +19,23 @@ use sha2::{Digest, Sha256}; use std::collections::HashMap; use std::path::PathBuf; use std::rc::Rc; +use tg_schema::runtimes::deno::DenoRuntimeData; +use tg_schema::runtimes::graphql::GraphQLRuntimeData; +use tg_schema::runtimes::grpc::GrpcRuntimeData; +use tg_schema::runtimes::http::HTTPRuntimeData; +use tg_schema::runtimes::kv::KvRuntimeData; +use tg_schema::runtimes::python::PythonRuntimeData; +use tg_schema::runtimes::random::RandomRuntimeData; +use tg_schema::runtimes::s3::S3RuntimeData; +use tg_schema::runtimes::substantial::{ + self, RedisConfig, SubstantialRuntimeData, WorkflowFileDescription, +}; +use tg_schema::runtimes::temporal::TemporalRuntimeData; +use tg_schema::runtimes::wasm::WasmRuntimeData; +use tg_schema::runtimes::{ + Artifact, KnownRuntime, PrismaMigrationRuntimeData, TypegateRuntimeData, TypegraphRuntimeData, +}; +use tg_schema::{runtimes::TGRuntime, Effect, EffectType, Materializer}; use unindent::Unindent; fn effect(typ: EffectType, idempotent: bool) -> Effect { @@ -63,7 +63,7 @@ pub trait MaterializerConverter { c: &mut TypegraphContext, runtime_id: RuntimeId, effect: WitEffect, - ) -> Result; + ) -> Result; } impl MaterializerConverter for Rc { @@ -72,7 +72,7 @@ impl MaterializerConverter for Rc { c: &mut TypegraphContext, runtime_id: RuntimeId, effect: WitEffect, - ) -> Result { + ) -> Result { (**self).convert(c, runtime_id, effect) } } @@ -157,7 +157,7 @@ impl MaterializerConverter for MaterializerHttpRequest { c: &mut TypegraphContext, runtime_id: RuntimeId, effect: WitEffect, - ) -> Result { + ) -> Result { let runtime = c.register_runtime(runtime_id)?; let mut data: IndexMap = serde_json::from_value(json!({ diff --git a/src/typegraph/core/src/conversion/types.rs b/src/typegraph/core/src/conversion/types.rs index e7bed25d7a..c0088ae272 100644 --- a/src/typegraph/core/src/conversion/types.rs +++ b/src/typegraph/core/src/conversion/types.rs @@ -4,9 +4,9 @@ use crate::errors::Result; use crate::typegraph::TypegraphContext; use crate::types::{ExtendedTypeDef, TypeId}; -use common::typegraph::{TypeNode, TypeNodeBase}; use enum_dispatch::enum_dispatch; use std::rc::Rc; +use tg_schema::{TypeNode, TypeNodeBase}; #[enum_dispatch] pub trait TypeConversion { diff --git a/src/typegraph/core/src/global_store.rs b/src/typegraph/core/src/global_store.rs index a0c6f7dd47..f3849057d8 100644 --- a/src/typegraph/core/src/global_store.rs +++ b/src/typegraph/core/src/global_store.rs @@ -14,11 +14,11 @@ use crate::wit::utils::Auth as WitAuth; #[allow(unused)] use crate::wit::runtimes::{Effect, MaterializerDenoPredefined, MaterializerId}; -use common::typegraph::runtimes::deno::PredefinedFunctionMatData; use graphql_parser::parse_query; use indexmap::IndexMap; use std::rc::Rc; use std::{cell::RefCell, collections::HashMap}; +use tg_schema::runtimes::deno::PredefinedFunctionMatData; const PLACEHOLDER_TYPE_SUFFIX: &str = "_____PLACEHOLDER_____"; @@ -65,7 +65,7 @@ pub struct Store { typegate_runtime: RuntimeId, typegraph_runtime: RuntimeId, graphql_endpoints: Vec, - auths: Vec, + auths: Vec, random_seed: Option, } @@ -418,14 +418,14 @@ impl Store { }) } - pub fn add_raw_auth(auth: common::typegraph::Auth) -> Result { + pub fn add_raw_auth(auth: tg_schema::Auth) -> Result { with_store_mut(|s| { s.auths.push(auth); Ok(s.auths.len() as u32) }) } - pub fn get_auths() -> Vec { + pub fn get_auths() -> Vec { with_store(|s| s.auths.clone()) } } diff --git a/src/typegraph/core/src/lib.rs b/src/typegraph/core/src/lib.rs index a3816d3132..92be684b30 100644 --- a/src/typegraph/core/src/lib.rs +++ b/src/typegraph/core/src/lib.rs @@ -19,13 +19,13 @@ mod test_utils; use std::collections::HashSet; -use common::typegraph::runtimes::deno::{ContextCheckX, PredefinedFunctionMatData}; -use common::typegraph::Injection; use errors::{Result, TgError}; use global_store::Store; use params::apply; use regex::Regex; use runtimes::{DenoMaterializer, Materializer}; +use tg_schema::runtimes::deno::{ContextCheckX, PredefinedFunctionMatData}; +use tg_schema::Injection; use types::type_ref::AsId; use types::{ AsTypeDefEx as _, Boolean, Either, File, Float, Func, Integer, List, Named, Optional, StringT, diff --git a/src/typegraph/core/src/runtimes/aws/mod.rs b/src/typegraph/core/src/runtimes/aws/mod.rs index 6d9474b310..30c2f0a9eb 100644 --- a/src/typegraph/core/src/runtimes/aws/mod.rs +++ b/src/typegraph/core/src/runtimes/aws/mod.rs @@ -83,7 +83,7 @@ impl MaterializerConverter for S3Materializer { c: &mut TypegraphContext, runtime_id: u32, effect: Effect, - ) -> Result { + ) -> Result { use S3Materializer as M; let runtime = c.register_runtime(runtime_id)?; @@ -111,7 +111,7 @@ impl MaterializerConverter for S3Materializer { ), }; - Ok(common::typegraph::Materializer { + Ok(tg_schema::Materializer { name: name.to_string(), runtime, effect: effect.into(), diff --git a/src/typegraph/core/src/runtimes/deno.rs b/src/typegraph/core/src/runtimes/deno.rs index eb89f6a0fa..3929f7c09b 100644 --- a/src/typegraph/core/src/runtimes/deno.rs +++ b/src/typegraph/core/src/runtimes/deno.rs @@ -1,7 +1,7 @@ // Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. // SPDX-License-Identifier: MPL-2.0 -use common::typegraph::runtimes::deno::PredefinedFunctionMatData; +use tg_schema::runtimes::deno::PredefinedFunctionMatData; use crate::wit::runtimes as wit; diff --git a/src/typegraph/core/src/runtimes/graphql.rs b/src/typegraph/core/src/runtimes/graphql.rs index 57d3e33933..5851de90a0 100644 --- a/src/typegraph/core/src/runtimes/graphql.rs +++ b/src/typegraph/core/src/runtimes/graphql.rs @@ -1,8 +1,8 @@ // Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. // SPDX-License-Identifier: MPL-2.0 -use common::typegraph::Materializer; use indexmap::IndexMap; +use tg_schema::Materializer; use crate::conversion::runtimes::MaterializerConverter; use crate::errors::Result; diff --git a/src/typegraph/core/src/runtimes/grpc/mod.rs b/src/typegraph/core/src/runtimes/grpc/mod.rs index 2a821c03da..3a6c3699fb 100644 --- a/src/typegraph/core/src/runtimes/grpc/mod.rs +++ b/src/typegraph/core/src/runtimes/grpc/mod.rs @@ -13,7 +13,7 @@ use crate::{ conversion::runtimes::MaterializerConverter, errors::Result, typegraph::TypegraphContext, }; -use common::typegraph::Materializer; +use tg_schema::Materializer; use serde_json::{from_value, json}; diff --git a/src/typegraph/core/src/runtimes/grpc/type_generation.rs b/src/typegraph/core/src/runtimes/grpc/type_generation.rs index 1a6e2d8f74..31c9fdf79e 100644 --- a/src/typegraph/core/src/runtimes/grpc/type_generation.rs +++ b/src/typegraph/core/src/runtimes/grpc/type_generation.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: MPL-2.0 use anyhow::{bail, Result}; -use common::grpc::{ +use grpc_utils::{ get_file_descriptor, get_message_field_descriptor, get_method_descriptor_proto, Fields, FileDescriptor, Type, }; diff --git a/src/typegraph/core/src/runtimes/prisma/context.rs b/src/typegraph/core/src/runtimes/prisma/context.rs index c1067e7272..9cb0cef455 100644 --- a/src/typegraph/core/src/runtimes/prisma/context.rs +++ b/src/typegraph/core/src/runtimes/prisma/context.rs @@ -11,13 +11,13 @@ use super::{ use crate::errors::Result; use crate::types::TypeId; use crate::{typegraph::TypegraphContext, wit::runtimes as wit}; -use common::typegraph::runtimes::prisma as cm; use indexmap::{map::Entry, IndexMap, IndexSet}; use std::{ cell::{OnceCell, Ref, RefCell, RefMut}, collections::HashMap, rc::{Rc, Weak}, }; +use tg_schema::runtimes::prisma as cm; use super::{errors, model::Model, relationship::Relationship}; diff --git a/src/typegraph/core/src/runtimes/prisma/migration.rs b/src/typegraph/core/src/runtimes/prisma/migration.rs index 5268b99373..938c8706e5 100644 --- a/src/typegraph/core/src/runtimes/prisma/migration.rs +++ b/src/typegraph/core/src/runtimes/prisma/migration.rs @@ -1,8 +1,8 @@ // Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. // SPDX-License-Identifier: MPL-2.0 -use common::typegraph::Materializer; use indexmap::IndexMap; +use tg_schema::Materializer; use crate::conversion::runtimes::MaterializerConverter; use crate::errors::Result; diff --git a/src/typegraph/core/src/runtimes/prisma/mod.rs b/src/typegraph/core/src/runtimes/prisma/mod.rs index 91c3d0870f..908f8502ee 100644 --- a/src/typegraph/core/src/runtimes/prisma/mod.rs +++ b/src/typegraph/core/src/runtimes/prisma/mod.rs @@ -14,9 +14,9 @@ use std::cell::RefCell; use std::fmt::Debug; use std::rc::Rc; -use common::typegraph::runtimes::prisma as cm; -use common::typegraph::Materializer; use indexmap::IndexMap; +use tg_schema::runtimes::prisma as cm; +use tg_schema::Materializer; use crate::conversion::runtimes::MaterializerConverter; use crate::errors::Result; diff --git a/src/typegraph/core/src/runtimes/prisma/model.rs b/src/typegraph/core/src/runtimes/prisma/model.rs index 84b2bdf6e6..1a74a1c38a 100644 --- a/src/typegraph/core/src/runtimes/prisma/model.rs +++ b/src/typegraph/core/src/runtimes/prisma/model.rs @@ -13,10 +13,10 @@ use crate::types::{ }; use crate::validation::types::validate_value; use crate::{runtimes::prisma::relationship::Cardinality, types::TypeId}; -pub use common::typegraph::runtimes::prisma::{ScalarType, StringType}; -use common::typegraph::{EffectType, InjectionData}; use indexmap::IndexMap; use std::rc::Rc; +pub use tg_schema::runtimes::prisma::{ScalarType, StringType}; +use tg_schema::{EffectType, InjectionData}; #[derive(Debug, Clone)] pub struct ModelType { @@ -403,12 +403,12 @@ impl Injection { } } -impl TryFrom<&common::typegraph::Injection> for Injection { +impl TryFrom<&tg_schema::Injection> for Injection { // unmanaged property type Error = (); - fn try_from(injection: &common::typegraph::Injection) -> Result { - use common::typegraph::Injection as I; + fn try_from(injection: &tg_schema::Injection) -> Result { + use tg_schema::Injection as I; match injection { I::Static(inj) | I::Secret(inj) | I::Context(inj) | I::Random(inj) => { diff --git a/src/typegraph/core/src/runtimes/prisma/type_generation/input_type.rs b/src/typegraph/core/src/runtimes/prisma/type_generation/input_type.rs index 62d9c5a79e..efe0269a15 100644 --- a/src/typegraph/core/src/runtimes/prisma/type_generation/input_type.rs +++ b/src/typegraph/core/src/runtimes/prisma/type_generation/input_type.rs @@ -1,7 +1,7 @@ // Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. // SPDX-License-Identifier: MPL-2.0 -use common::typegraph::runtimes::prisma::ScalarType; +use tg_schema::runtimes::prisma::ScalarType; use crate::errors::Result; use crate::runtimes::prisma::context::PrismaContext; diff --git a/src/typegraph/core/src/runtimes/prisma/type_generation/where_.rs b/src/typegraph/core/src/runtimes/prisma/type_generation/where_.rs index 1b8c6bb4d0..85d5e1e20d 100644 --- a/src/typegraph/core/src/runtimes/prisma/type_generation/where_.rs +++ b/src/typegraph/core/src/runtimes/prisma/type_generation/where_.rs @@ -1,7 +1,7 @@ // Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. // SPDX-License-Identifier: MPL-2.0 -use common::typegraph::runtimes::prisma::ScalarType; +use tg_schema::runtimes::prisma::ScalarType; use crate::errors::Result; use crate::runtimes::prisma::context::PrismaContext; diff --git a/src/typegraph/core/src/runtimes/substantial/mod.rs b/src/typegraph/core/src/runtimes/substantial/mod.rs index 72b650feb3..a151951fbc 100644 --- a/src/typegraph/core/src/runtimes/substantial/mod.rs +++ b/src/typegraph/core/src/runtimes/substantial/mod.rs @@ -10,8 +10,8 @@ use crate::wit::core::FuncParams; use crate::wit::{ core::RuntimeId, runtimes::Effect as WitEffect, runtimes::SubstantialOperationData, }; -use common::typegraph::Materializer; use serde_json::json; +use tg_schema::Materializer; mod type_utils; diff --git a/src/typegraph/core/src/runtimes/typegate.rs b/src/typegraph/core/src/runtimes/typegate.rs index 37c8110834..1a6599c197 100644 --- a/src/typegraph/core/src/runtimes/typegate.rs +++ b/src/typegraph/core/src/runtimes/typegate.rs @@ -1,8 +1,8 @@ // Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. // SPDX-License-Identifier: MPL-2.0 -use common::typegraph::Materializer; use indexmap::IndexMap; +use tg_schema::Materializer; use crate::{ conversion::runtimes::MaterializerConverter, errors::Result, typegraph::TypegraphContext, diff --git a/src/typegraph/core/src/runtimes/typegraph.rs b/src/typegraph/core/src/runtimes/typegraph.rs index a8cd63d53f..a3ba1dd926 100644 --- a/src/typegraph/core/src/runtimes/typegraph.rs +++ b/src/typegraph/core/src/runtimes/typegraph.rs @@ -1,8 +1,8 @@ // Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. // SPDX-License-Identifier: MPL-2.0 -use common::typegraph::Materializer; use indexmap::IndexMap; +use tg_schema::Materializer; use crate::{ conversion::runtimes::MaterializerConverter, errors::Result, typegraph::TypegraphContext, diff --git a/src/typegraph/core/src/typedef/boolean.rs b/src/typegraph/core/src/typedef/boolean.rs index 786e9e097c..d6bb1421d8 100644 --- a/src/typegraph/core/src/typedef/boolean.rs +++ b/src/typegraph/core/src/typedef/boolean.rs @@ -1,8 +1,8 @@ // Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. // SPDX-License-Identifier: MPL-2.0 -use common::typegraph::TypeNode; use errors::Result; +use tg_schema::TypeNode; use crate::{ conversion::{ diff --git a/src/typegraph/core/src/typedef/either.rs b/src/typegraph/core/src/typedef/either.rs index a90b9c2a45..65d8e81522 100644 --- a/src/typegraph/core/src/typedef/either.rs +++ b/src/typegraph/core/src/typedef/either.rs @@ -3,8 +3,8 @@ use std::hash::Hash as _; -use common::typegraph::{EitherTypeData, TypeNode}; use errors::Result; +use tg_schema::{EitherTypeData, TypeNode}; use crate::{ conversion::{ diff --git a/src/typegraph/core/src/typedef/file.rs b/src/typegraph/core/src/typedef/file.rs index 0cb4660831..b3c554b553 100644 --- a/src/typegraph/core/src/typedef/file.rs +++ b/src/typegraph/core/src/typedef/file.rs @@ -3,7 +3,7 @@ use std::hash::Hash as _; -use common::typegraph::{FileTypeData, TypeNode}; +use tg_schema::{FileTypeData, TypeNode}; use crate::conversion::hash::Hashable; use crate::conversion::types::{BaseBuilderInit, TypeConversion}; diff --git a/src/typegraph/core/src/typedef/float.rs b/src/typegraph/core/src/typedef/float.rs index 6b08a41e9b..a906075760 100644 --- a/src/typegraph/core/src/typedef/float.rs +++ b/src/typegraph/core/src/typedef/float.rs @@ -3,9 +3,9 @@ use std::hash::Hash as _; -use common::typegraph::types::{FloatTypeData, TypeNode}; use errors::Result; use ordered_float::OrderedFloat; +use tg_schema::types::{FloatTypeData, TypeNode}; use crate::{ conversion::{ diff --git a/src/typegraph/core/src/typedef/func.rs b/src/typegraph/core/src/typedef/func.rs index c6a23630d1..99742012b5 100644 --- a/src/typegraph/core/src/typedef/func.rs +++ b/src/typegraph/core/src/typedef/func.rs @@ -15,14 +15,12 @@ use crate::types::{ TypeDef, TypeDefData, TypeId, }; use crate::wit::core::TypeFunc; -use common::typegraph::{ - parameter_transform::FunctionParameterTransform, FunctionTypeData, TypeNode, -}; -use common::typegraph::{Injection, InjectionData, InjectionNode}; use indexmap::IndexMap; use std::collections::HashSet; use std::hash::Hash as _; use std::rc::Rc; +use tg_schema::{parameter_transform::FunctionParameterTransform, FunctionTypeData, TypeNode}; +use tg_schema::{Injection, InjectionData, InjectionNode}; impl TypeConversion for Func { fn convert(&self, ctx: &mut TypegraphContext, xdef: ExtendedTypeDef) -> Result { diff --git a/src/typegraph/core/src/typedef/integer.rs b/src/typegraph/core/src/typedef/integer.rs index 37e1b2666a..2909eb8398 100644 --- a/src/typegraph/core/src/typedef/integer.rs +++ b/src/typegraph/core/src/typedef/integer.rs @@ -3,8 +3,8 @@ use std::hash::Hash as _; -use common::typegraph::{IntegerTypeData, TypeNode}; use errors::Result; +use tg_schema::{IntegerTypeData, TypeNode}; use crate::{ conversion::{ diff --git a/src/typegraph/core/src/typedef/list.rs b/src/typegraph/core/src/typedef/list.rs index 3ea9e405a2..cfa74531f9 100644 --- a/src/typegraph/core/src/typedef/list.rs +++ b/src/typegraph/core/src/typedef/list.rs @@ -3,7 +3,7 @@ use std::hash::Hash as _; -use common::typegraph::{ListTypeData, TypeNode}; +use tg_schema::{ListTypeData, TypeNode}; use crate::{ conversion::{ diff --git a/src/typegraph/core/src/typedef/optional.rs b/src/typegraph/core/src/typedef/optional.rs index cb89e3b68e..bc2ee80edd 100644 --- a/src/typegraph/core/src/typedef/optional.rs +++ b/src/typegraph/core/src/typedef/optional.rs @@ -3,8 +3,8 @@ use std::hash::Hash as _; -use common::typegraph::{OptionalTypeData, TypeNode}; use errors::Result; +use tg_schema::{OptionalTypeData, TypeNode}; use crate::{ conversion::{ diff --git a/src/typegraph/core/src/typedef/string.rs b/src/typegraph/core/src/typedef/string.rs index 57d3e0c9d3..5482eb5a07 100644 --- a/src/typegraph/core/src/typedef/string.rs +++ b/src/typegraph/core/src/typedef/string.rs @@ -3,8 +3,8 @@ use std::hash::Hash; -use common::typegraph::{StringFormat, StringTypeData, TypeNode}; use errors::Result; +use tg_schema::{StringFormat, StringTypeData, TypeNode}; use crate::{ conversion::{ diff --git a/src/typegraph/core/src/typedef/struct_.rs b/src/typegraph/core/src/typedef/struct_.rs index 3f7338e1f4..81d1aec757 100644 --- a/src/typegraph/core/src/typedef/struct_.rs +++ b/src/typegraph/core/src/typedef/struct_.rs @@ -8,10 +8,10 @@ use crate::types::{ TypeDefData, TypeId, }; use crate::{errors, typegraph::TypegraphContext, wit::core::TypeStruct}; -use common::typegraph::{ObjectTypeData, PolicyIndices, TypeNode}; use errors::Result; use indexmap::IndexMap; use std::hash::Hash as _; +use tg_schema::{ObjectTypeData, PolicyIndices, TypeNode}; impl TypeStruct { pub fn get_prop(&self, key: &str) -> Option { diff --git a/src/typegraph/core/src/typedef/union.rs b/src/typegraph/core/src/typedef/union.rs index 1eeb0b9240..acc3828b6d 100644 --- a/src/typegraph/core/src/typedef/union.rs +++ b/src/typegraph/core/src/typedef/union.rs @@ -3,8 +3,8 @@ use std::hash::Hash as _; -use common::typegraph::{TypeNode, UnionTypeData}; use errors::Result; +use tg_schema::{TypeNode, UnionTypeData}; use crate::{ conversion::{ diff --git a/src/typegraph/core/src/typegraph.rs b/src/typegraph/core/src/typegraph.rs index fa41dc8d27..f51f93fab6 100644 --- a/src/typegraph/core/src/typegraph.rs +++ b/src/typegraph/core/src/typegraph.rs @@ -16,11 +16,6 @@ use crate::{ errors::{self, Result}, global_store::Store, }; -use common::typegraph::runtimes::TGRuntime; -use common::typegraph::{ - Materializer, ObjectTypeData, Policy, PolicyIndices, PolicyIndicesByEffect, Queries, TypeMeta, - TypeNode, TypeNodeBase, Typegraph, -}; use indexmap::IndexMap; use std::cell::RefCell; use std::collections::hash_map::Entry; @@ -28,6 +23,11 @@ use std::collections::{HashMap, HashSet}; use std::hash::Hasher as _; use std::path::{Path, PathBuf}; use std::rc::Rc; +use tg_schema::runtimes::TGRuntime; +use tg_schema::{ + Materializer, ObjectTypeData, Policy, PolicyIndices, PolicyIndicesByEffect, Queries, TypeMeta, + TypeNode, TypeNodeBase, Typegraph, +}; use crate::wit::core::{ Artifact as WitArtifact, Error as TgError, MaterializerId, PolicyId, RuntimeId, @@ -147,11 +147,11 @@ pub fn init(params: TypegraphInitParams) -> Result<()> { Ok(()) } -pub fn finalize_auths(ctx: &mut TypegraphContext) -> Result> { +pub fn finalize_auths(ctx: &mut TypegraphContext) -> Result> { Store::get_auths() .iter() .map(|auth| match auth.protocol { - common::typegraph::AuthProtocol::OAuth2 => { + tg_schema::AuthProtocol::OAuth2 => { let profiler_key = "profiler"; match auth.auth_data.get(profiler_key) { Some(value) => match value { diff --git a/src/typegraph/core/src/types/type_def.rs b/src/typegraph/core/src/types/type_def.rs index a145bcd9d9..39ae694a1e 100644 --- a/src/typegraph/core/src/types/type_def.rs +++ b/src/typegraph/core/src/types/type_def.rs @@ -14,9 +14,9 @@ use crate::wit::core::{ TypeEither, TypeFile, TypeFloat, TypeFunc, TypeInteger, TypeList, TypeOptional, TypeString, TypeStruct, TypeUnion, }; -use common::typegraph::TypeNode; use enum_dispatch::enum_dispatch; use std::hash::Hash as _; +use tg_schema::TypeNode; pub trait TypeDefData: Hashable { fn get_display_params_into(&self, params: &mut Vec); diff --git a/src/typegraph/core/src/types/type_ref.rs b/src/typegraph/core/src/types/type_ref.rs index 57cd33b591..8514220590 100644 --- a/src/typegraph/core/src/types/type_ref.rs +++ b/src/typegraph/core/src/types/type_ref.rs @@ -8,8 +8,8 @@ use super::Type; use crate::errors::Result; use crate::global_store::Store; use crate::types::{TypeDef, TypeDefExt as _, TypeId}; -use common::typegraph::Injection; use serde::{Deserialize, Serialize}; +use tg_schema::Injection; pub use as_id::{AsId, IdKind}; pub use injection::{InjectionTree, OverrideInjections, WithInjection}; diff --git a/src/typegraph/core/src/types/type_ref/injection.rs b/src/typegraph/core/src/types/type_ref/injection.rs index 948e976e98..7cffdb8846 100644 --- a/src/typegraph/core/src/types/type_ref/injection.rs +++ b/src/typegraph/core/src/types/type_ref/injection.rs @@ -5,10 +5,10 @@ use super::{RefAttr, TypeRef}; use crate::types::Type; use crate::wit::utils::ReduceEntry; use crate::{errors::Result, wit::core::Error}; -use common::typegraph::{Injection, InjectionNode}; use indexmap::{map::Entry, IndexMap}; use serde::{Deserialize, Serialize}; use std::hash::{Hash, Hasher}; +use tg_schema::{Injection, InjectionNode}; #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct InjectionTree(pub IndexMap); diff --git a/src/typegraph/core/src/utils/archive.rs b/src/typegraph/core/src/utils/archive.rs index e33a8cb4e0..0539cb88bd 100644 --- a/src/typegraph/core/src/utils/archive.rs +++ b/src/typegraph/core/src/utils/archive.rs @@ -3,7 +3,7 @@ use super::fs::FsContext; use crate::errors::Result; -use common::archive::{archive_entries_from_bytes, encode_bytes_to_base_64}; +use archive_utils::{archive_entries_from_bytes, encode_bytes_to_base_64}; use std::{collections::BTreeMap, path::Path}; pub trait ArchiveExt { diff --git a/src/typegraph/core/src/utils/artifacts.rs b/src/typegraph/core/src/utils/artifacts.rs index 70b01f6504..984ecae3dd 100644 --- a/src/typegraph/core/src/utils/artifacts.rs +++ b/src/typegraph/core/src/utils/artifacts.rs @@ -5,7 +5,7 @@ use std::path::PathBuf; use super::fs::FsContext; use crate::errors::Result; -use common::typegraph::{runtimes::Artifact, Typegraph}; +use tg_schema::{runtimes::Artifact, Typegraph}; pub trait ArtifactsExt { /// update the artifact meta, and register the artifact in the typegraph diff --git a/src/typegraph/core/src/utils/metagen_utils.rs b/src/typegraph/core/src/utils/metagen_utils.rs index 4d1bda21e1..d6b4be9d31 100644 --- a/src/typegraph/core/src/utils/metagen_utils.rs +++ b/src/typegraph/core/src/utils/metagen_utils.rs @@ -5,8 +5,8 @@ use std::borrow::Cow; use super::fs::FsContext; use color_eyre::Result; -use common::typegraph::Typegraph; use metagen::{GeneratorInputOrder, GeneratorInputResolved, InputResolverSync}; +use tg_schema::Typegraph; #[derive(Clone)] pub struct RawTgResolver { diff --git a/src/typegraph/core/src/utils/mod.rs b/src/typegraph/core/src/utils/mod.rs index fe424aaeb9..2c87c27781 100644 --- a/src/typegraph/core/src/utils/mod.rs +++ b/src/typegraph/core/src/utils/mod.rs @@ -4,10 +4,10 @@ use std::path::PathBuf; use crate::utils::metagen_utils::RawTgResolver; -use common::typegraph::{Auth, AuthProtocol}; use fs::FsContext; use indexmap::IndexMap; use serde_json::json; +use tg_schema::{Auth, AuthProtocol}; use self::oauth2::std::{named_provider, Oauth2Builder}; use crate::errors::Result; diff --git a/src/typegraph/core/src/utils/postprocess/deno_rt.rs b/src/typegraph/core/src/utils/postprocess/deno_rt.rs index 5cf88b5ee3..bd0ab90d53 100644 --- a/src/typegraph/core/src/utils/postprocess/deno_rt.rs +++ b/src/typegraph/core/src/utils/postprocess/deno_rt.rs @@ -1,10 +1,10 @@ // Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. // SPDX-License-Identifier: MPL-2.0 -use common::typegraph::runtimes::deno::ModuleMatData; -use common::typegraph::utils::map_from_object; -use common::typegraph::{utils::object_from_map, Typegraph}; use std::path::PathBuf; +use tg_schema::runtimes::deno::ModuleMatData; +use tg_schema::utils::map_from_object; +use tg_schema::{utils::object_from_map, Typegraph}; use crate::utils::{artifacts::ArtifactsExt, fs::FsContext, postprocess::PostProcessor}; diff --git a/src/typegraph/core/src/utils/postprocess/mod.rs b/src/typegraph/core/src/utils/postprocess/mod.rs index 3839a007b7..bded841c4a 100644 --- a/src/typegraph/core/src/utils/postprocess/mod.rs +++ b/src/typegraph/core/src/utils/postprocess/mod.rs @@ -2,9 +2,9 @@ // SPDX-License-Identifier: MPL-2.0 use crate::wit::core::SerializeParams; -use common::typegraph::Typegraph; use std::path::PathBuf; use substantial_rt::SubstantialProcessor; +use tg_schema::Typegraph; pub mod deno_rt; pub mod naming; diff --git a/src/typegraph/core/src/utils/postprocess/naming.rs b/src/typegraph/core/src/utils/postprocess/naming.rs index d3d575282b..49272b211b 100644 --- a/src/typegraph/core/src/utils/postprocess/naming.rs +++ b/src/typegraph/core/src/utils/postprocess/naming.rs @@ -6,12 +6,12 @@ use std::{ rc::Rc, }; -use common::typegraph::{ +use indexmap::IndexSet; +use sha2::{Digest, Sha256}; +use tg_schema::{ visitor::{Edge, PathSegment}, StringFormat, TypeNode, Typegraph, }; -use indexmap::IndexSet; -use sha2::{Digest, Sha256}; use crate::errors::TgError; @@ -19,10 +19,7 @@ pub struct NamingProcessor { pub user_named: HashSet, } impl super::PostProcessor for NamingProcessor { - fn postprocess( - self, - tg: &mut common::typegraph::Typegraph, - ) -> Result<(), crate::errors::TgError> { + fn postprocess(self, tg: &mut tg_schema::Typegraph) -> Result<(), crate::errors::TgError> { let cx = VisitContext { tg, user_named: self.user_named, diff --git a/src/typegraph/core/src/utils/postprocess/prisma_rt.rs b/src/typegraph/core/src/utils/postprocess/prisma_rt.rs index 039027f732..9a23de880e 100644 --- a/src/typegraph/core/src/utils/postprocess/prisma_rt.rs +++ b/src/typegraph/core/src/utils/postprocess/prisma_rt.rs @@ -2,9 +2,9 @@ // SPDX-License-Identifier: MPL-2.0 use std::path::PathBuf; -use common::typegraph::runtimes::prisma::MigrationOptions; -use common::typegraph::runtimes::{KnownRuntime::Prisma, TGRuntime}; -use common::typegraph::Typegraph; +use tg_schema::runtimes::prisma::MigrationOptions; +use tg_schema::runtimes::{KnownRuntime::Prisma, TGRuntime}; +use tg_schema::Typegraph; use crate::errors::Result; use crate::utils::archive::ArchiveExt; diff --git a/src/typegraph/core/src/utils/postprocess/python_rt.rs b/src/typegraph/core/src/utils/postprocess/python_rt.rs index 475bd28feb..5b66086c5f 100644 --- a/src/typegraph/core/src/utils/postprocess/python_rt.rs +++ b/src/typegraph/core/src/utils/postprocess/python_rt.rs @@ -2,12 +2,12 @@ // SPDX-License-Identifier: MPL-2.0 use crate::utils::{artifacts::ArtifactsExt, fs::FsContext, postprocess::PostProcessor}; -use common::typegraph::{ +use std::path::PathBuf; +use tg_schema::{ runtimes::python::ModuleMatData, utils::{map_from_object, object_from_map}, Typegraph, }; -use std::path::PathBuf; pub struct PythonProcessor { typegraph_dir: PathBuf, diff --git a/src/typegraph/core/src/utils/postprocess/substantial_rt.rs b/src/typegraph/core/src/utils/postprocess/substantial_rt.rs index 4eb405c8df..c13020ad6e 100644 --- a/src/typegraph/core/src/utils/postprocess/substantial_rt.rs +++ b/src/typegraph/core/src/utils/postprocess/substantial_rt.rs @@ -2,11 +2,11 @@ // SPDX-License-Identifier: MPL-2.0 use crate::utils::{artifacts::ArtifactsExt, fs::FsContext, postprocess::PostProcessor}; -use common::typegraph::{ +use std::path::PathBuf; +use tg_schema::{ runtimes::{self, TGRuntime}, Typegraph, }; -use std::path::PathBuf; pub struct SubstantialProcessor { typegraph_dir: PathBuf, diff --git a/src/typegraph/core/src/utils/postprocess/validation.rs b/src/typegraph/core/src/utils/postprocess/validation.rs index 021869772c..e86735f136 100644 --- a/src/typegraph/core/src/utils/postprocess/validation.rs +++ b/src/typegraph/core/src/utils/postprocess/validation.rs @@ -3,7 +3,7 @@ use crate::errors::TgError; use crate::utils::postprocess::PostProcessor; -use common::typegraph::{validator::validate_typegraph, Typegraph}; +use tg_schema::{validator::validate_typegraph, Typegraph}; pub struct ValidationProcessor; diff --git a/src/typegraph/core/src/utils/postprocess/wasm_rt.rs b/src/typegraph/core/src/utils/postprocess/wasm_rt.rs index 207f4365e5..113849f6d5 100644 --- a/src/typegraph/core/src/utils/postprocess/wasm_rt.rs +++ b/src/typegraph/core/src/utils/postprocess/wasm_rt.rs @@ -4,7 +4,7 @@ use std::path::PathBuf; use crate::utils::{artifacts::ArtifactsExt, fs::FsContext}; -use common::typegraph::{ +use tg_schema::{ runtimes::{KnownRuntime, TGRuntime}, Typegraph, }; diff --git a/src/typegraph/core/src/validation/materializers.rs b/src/typegraph/core/src/validation/materializers.rs index 1901efcf02..ec920c1453 100644 --- a/src/typegraph/core/src/validation/materializers.rs +++ b/src/typegraph/core/src/validation/materializers.rs @@ -1,7 +1,7 @@ // Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. // SPDX-License-Identifier: MPL-2.0 -use common::typegraph::runtimes::deno::PredefinedFunctionMatData; +use tg_schema::runtimes::deno::PredefinedFunctionMatData; use crate::runtimes::{DenoMaterializer, MaterializerData, Runtime}; use crate::types::{AsTypeDefEx as _, TypeDef, TypeId}; diff --git a/src/typegraph/schema/Cargo.toml b/src/typegraph/schema/Cargo.toml new file mode 100644 index 0000000000..765cca78a7 --- /dev/null +++ b/src/typegraph/schema/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "tg_schema" +version.workspace = true +edition.workspace = true + +[dependencies] +# patterns +anyhow.workspace = true +# itertools.workspace = true +# indoc.workspace = true +# thiserror.workspace = true + + +# encoding +# base64.workspace = true +# flate2.workspace = true +# tar.workspace = true + +serde.workspace = true +serde_json = { workspace = true, features = ["preserve_order"] } +serde_with.workspace = true + + +# ds +indexmap.workspace = true + diff --git a/src/typegraph/schema/src/lib.rs b/src/typegraph/schema/src/lib.rs new file mode 100644 index 0000000000..f43cc59f13 --- /dev/null +++ b/src/typegraph/schema/src/lib.rs @@ -0,0 +1,215 @@ +// Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. +// SPDX-License-Identifier: MPL-2.0 + +pub mod parameter_transform; +pub mod runtimes; +pub mod types; +pub mod utils; +pub mod validator; +pub mod visitor; +pub mod visitor2; + +pub use types::*; + +use std::collections::BTreeMap; +use std::hash::Hash; +use std::path::{Path, PathBuf}; +use std::sync::Arc; + +use anyhow::{bail, Result}; +use indexmap::IndexMap; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use serde_with::skip_serializing_none; + +use self::runtimes::Artifact; +use self::runtimes::TGRuntime; + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Typegraph { + pub types: Vec, + pub materializers: Vec, + pub runtimes: Vec, + pub policies: Vec, + pub meta: TypeMeta, + + // TODO: factor out non-essential fields into a separate struct + #[serde(skip)] + pub path: Option>, + #[serde(skip)] + pub deps: Vec, +} + +#[derive(Serialize, Deserialize, Clone, Debug, Default)] +pub struct Cors { + pub allow_origin: Vec, + pub allow_headers: Vec, + pub expose_headers: Vec, + #[serde(default)] + pub allow_methods: Vec, + pub allow_credentials: bool, + pub max_age_sec: Option, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(rename_all = "lowercase")] +pub enum AuthProtocol { + OAuth2, + Jwt, + Basic, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Auth { + pub name: String, + pub protocol: AuthProtocol, + pub auth_data: IndexMap, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Rate { + pub window_limit: u32, + pub window_sec: u32, + pub query_limit: u32, + pub context_identifier: Option, + pub local_excess: u32, +} + +// TODO: remove default, as they should all be explicity set in the core SDK +#[derive(Serialize, Deserialize, Clone, Debug, Default)] +pub struct Queries { + pub dynamic: bool, + pub endpoints: Vec, +} + +#[derive(Serialize, Deserialize, Clone, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct TypeMeta { + pub prefix: Option, + pub secrets: Vec, + #[serde(skip_serializing_if = "Vec::is_empty")] + #[serde(default)] + pub outjection_secrets: Vec, + pub queries: Queries, + pub cors: Cors, + pub auths: Vec, + pub rate: Option, + pub version: String, + pub random_seed: Option, + pub artifacts: BTreeMap, + #[serde(skip_serializing_if = "Vec::is_empty")] + #[serde(default)] + pub namespaces: Vec, +} + +#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[serde(rename_all = "lowercase")] +pub enum EffectType { + Create, + Update, + Delete, + Read, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Effect { + pub effect: Option, + pub idempotent: bool, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Materializer { + pub name: String, + pub runtime: u32, + pub effect: Effect, + pub data: IndexMap, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Policy { + pub name: String, + pub materializer: u32, +} + +#[skip_serializing_none] +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct PolicyIndicesByEffect { + pub read: Option, + pub create: Option, + pub delete: Option, + pub update: Option, +} + +#[skip_serializing_none] +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(untagged)] +pub enum PolicyIndices { + Policy(u32), + EffectPolicies(PolicyIndicesByEffect), +} + +impl Typegraph { + pub fn name(&self) -> Result { + match &self.types[0] { + TypeNode::Object { base, .. } => Ok(base.title.clone()), + _ => bail!("invalid variant for root type"), + } + } + + pub fn full_name(&self) -> Result { + Ok(format!( + "{}{}", + self.meta.prefix.as_deref().unwrap_or(""), + self.name()? + )) + } + + pub fn with_prefix(&self, prefix: String) -> Result { + let mut tg = self.clone(); + tg.meta.prefix = Some(prefix); + Ok(tg) + } + + pub fn get_key(&self) -> Result { + let path = self.get_path()?; + Ok(format!("{}#{}", path, self.name()?)) + } + + pub fn get_path(&self) -> Result { + let path = self + .path + .as_ref() + .ok_or_else(|| anyhow::anyhow!("typegraph path not set, cannot get id"))? + .to_str() + .ok_or_else(|| anyhow::anyhow!("typegraph path is not valid unicode"))? + .to_owned(); + Ok(path) + } + + pub fn root(&self) -> Result<(&TypeNodeBase, &ObjectTypeData)> { + if self.types.is_empty() { + bail!("typegraph is empty: no nodes found"); + } + let root = &self.types[0]; + match root { + TypeNode::Object { base, data } => Ok((base, data)), + _ => bail!("typegraph is invalid: root node is not object"), + } + } + + pub fn resolve_quant(&self, type_idx: TypeId) -> TypeId { + let mut type_idx = type_idx; + loop { + match &self.types[type_idx as usize] { + TypeNode::Optional { data, .. } => { + type_idx = data.item; + } + TypeNode::List { data, .. } => { + type_idx = data.items; + } + _ => break, + } + } + type_idx + } +} diff --git a/src/typegraph/schema/src/parameter_transform.rs b/src/typegraph/schema/src/parameter_transform.rs new file mode 100644 index 0000000000..045836319c --- /dev/null +++ b/src/typegraph/schema/src/parameter_transform.rs @@ -0,0 +1,53 @@ +// Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. +// SPDX-License-Identifier: MPL-2.0 + +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(tag = "source", rename_all = "lowercase")] +pub enum ParameterTransformLeafNode { + #[serde(rename_all = "camelCase")] + Arg { name: String }, + #[serde(rename_all = "camelCase")] + Static { value_json: String }, + #[serde(rename_all = "camelCase")] + Secret { key: String }, + #[serde(rename_all = "camelCase")] + Context { key: String }, + #[serde(rename_all = "camelCase")] + Parent { parent_idx: u32 }, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(tag = "type", rename_all = "lowercase")] +pub enum ParameterTransformParentNode { + #[serde(rename_all = "camelCase")] + Object { + fields: HashMap, + }, + #[serde(rename_all = "camelCase")] + Array { items: Vec }, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(untagged)] +pub enum ParameterTransformNodeData { + Leaf(ParameterTransformLeafNode), + Parent(ParameterTransformParentNode), +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] +pub struct ParameterTransformNode { + pub type_idx: u32, + // #[serde(flatten)] + pub data: ParameterTransformNodeData, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct FunctionParameterTransform { + pub resolver_input: u32, + pub transform_root: ParameterTransformNode, +} diff --git a/src/common/src/typegraph/runtimes/deno.rs b/src/typegraph/schema/src/runtimes/deno.rs similarity index 100% rename from src/common/src/typegraph/runtimes/deno.rs rename to src/typegraph/schema/src/runtimes/deno.rs diff --git a/src/common/src/typegraph/runtimes/graphql.rs b/src/typegraph/schema/src/runtimes/graphql.rs similarity index 100% rename from src/common/src/typegraph/runtimes/graphql.rs rename to src/typegraph/schema/src/runtimes/graphql.rs diff --git a/src/common/src/typegraph/runtimes/grpc.rs b/src/typegraph/schema/src/runtimes/grpc.rs similarity index 100% rename from src/common/src/typegraph/runtimes/grpc.rs rename to src/typegraph/schema/src/runtimes/grpc.rs diff --git a/src/common/src/typegraph/runtimes/http.rs b/src/typegraph/schema/src/runtimes/http.rs similarity index 100% rename from src/common/src/typegraph/runtimes/http.rs rename to src/typegraph/schema/src/runtimes/http.rs diff --git a/src/common/src/typegraph/runtimes/kv.rs b/src/typegraph/schema/src/runtimes/kv.rs similarity index 100% rename from src/common/src/typegraph/runtimes/kv.rs rename to src/typegraph/schema/src/runtimes/kv.rs diff --git a/src/common/src/typegraph/runtimes/mod.rs b/src/typegraph/schema/src/runtimes/mod.rs similarity index 100% rename from src/common/src/typegraph/runtimes/mod.rs rename to src/typegraph/schema/src/runtimes/mod.rs diff --git a/src/common/src/typegraph/runtimes/prisma.rs b/src/typegraph/schema/src/runtimes/prisma.rs similarity index 100% rename from src/common/src/typegraph/runtimes/prisma.rs rename to src/typegraph/schema/src/runtimes/prisma.rs diff --git a/src/common/src/typegraph/runtimes/python.rs b/src/typegraph/schema/src/runtimes/python.rs similarity index 100% rename from src/common/src/typegraph/runtimes/python.rs rename to src/typegraph/schema/src/runtimes/python.rs diff --git a/src/common/src/typegraph/runtimes/random.rs b/src/typegraph/schema/src/runtimes/random.rs similarity index 100% rename from src/common/src/typegraph/runtimes/random.rs rename to src/typegraph/schema/src/runtimes/random.rs diff --git a/src/common/src/typegraph/runtimes/s3.rs b/src/typegraph/schema/src/runtimes/s3.rs similarity index 100% rename from src/common/src/typegraph/runtimes/s3.rs rename to src/typegraph/schema/src/runtimes/s3.rs diff --git a/src/common/src/typegraph/runtimes/substantial.rs b/src/typegraph/schema/src/runtimes/substantial.rs similarity index 100% rename from src/common/src/typegraph/runtimes/substantial.rs rename to src/typegraph/schema/src/runtimes/substantial.rs diff --git a/src/common/src/typegraph/runtimes/temporal.rs b/src/typegraph/schema/src/runtimes/temporal.rs similarity index 100% rename from src/common/src/typegraph/runtimes/temporal.rs rename to src/typegraph/schema/src/runtimes/temporal.rs diff --git a/src/common/src/typegraph/runtimes/wasm.rs b/src/typegraph/schema/src/runtimes/wasm.rs similarity index 100% rename from src/common/src/typegraph/runtimes/wasm.rs rename to src/typegraph/schema/src/runtimes/wasm.rs diff --git a/src/typegraph/schema/src/types.rs b/src/typegraph/schema/src/types.rs new file mode 100644 index 0000000000..1cd144886d --- /dev/null +++ b/src/typegraph/schema/src/types.rs @@ -0,0 +1,380 @@ +// Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. +// SPDX-License-Identifier: MPL-2.0 + +use std::collections::BTreeMap; + +use anyhow::Result; +use indexmap::IndexMap; +use serde::{Deserialize, Serialize}; +use serde_with::skip_serializing_none; +use std::hash::Hash; + +use super::{parameter_transform::FunctionParameterTransform, EffectType, PolicyIndices}; + +// TODO: consider exploring interning +pub type TypeName = String; +pub type TypeId = u32; + +type JsonValue = serde_json::Value; + +#[derive(Serialize, Deserialize, Clone, Debug, Hash)] +pub struct SingleValue { + pub value: JsonValue, +} + +#[derive(Serialize, Deserialize, Clone, Debug, Hash)] +#[serde(untagged)] +pub enum InjectionData { + SingleValue(SingleValue), + ValueByEffect(BTreeMap), +} + +impl InjectionData { + pub fn values(&self) -> Result> { + match self { + InjectionData::SingleValue(v) => Ok(vec![serde_json::from_value(v.value.clone())?]), + InjectionData::ValueByEffect(m) => m + .values() + .map(|v| serde_json::from_value(v.clone()).map_err(Into::into)) + .collect(), + } + } + + pub fn values_mut(&mut self) -> Vec<&mut JsonValue> { + match self { + InjectionData::SingleValue(v) => vec![&mut v.value], + InjectionData::ValueByEffect(m) => m.values_mut().collect(), + } + } +} + +#[derive(Serialize, Deserialize, Clone, Debug, Hash)] +#[serde(tag = "source", content = "data", rename_all = "lowercase")] +pub enum Injection { + Static(InjectionData), + Context(InjectionData), + Secret(InjectionData), + Parent(InjectionData), + Dynamic(InjectionData), + Random(InjectionData), +} + +#[skip_serializing_none] +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct TypeNodeBase { + pub title: String, + #[serde(default)] + pub description: Option, + #[serde(default, rename = "enum")] + pub enumeration: Option>, // JSON-serialized values +} + +#[skip_serializing_none] +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct OptionalTypeData { + pub item: Id, + #[serialize_always] + pub default_value: Option, +} + +#[skip_serializing_none] +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] +pub struct FloatTypeData { + pub minimum: Option, + pub maximum: Option, + pub exclusive_minimum: Option, + pub exclusive_maximum: Option, + pub multiple_of: Option, +} + +#[skip_serializing_none] +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] +pub struct IntegerTypeData { + // we use i32 as GraphQL spec only support 32-bit integers (Int) + pub minimum: Option, + pub maximum: Option, + pub exclusive_minimum: Option, + pub exclusive_maximum: Option, + pub multiple_of: Option, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[serde(rename_all = "kebab-case")] +pub enum StringFormat { + Uuid, + Email, + Uri, + Json, + Hostname, + Ean, + Date, + DateTime, + Phone, +} + +impl core::fmt::Display for StringFormat { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + use StringFormat::*; + match self { + Uuid => write!(f, "uuid"), + Email => write!(f, "email"), + Uri => write!(f, "uri"), + Json => write!(f, "json"), + Hostname => write!(f, "hostname"), + Ean => write!(f, "ean"), + Date => write!(f, "date"), + DateTime => write!(f, "date_time"), + Phone => write!(f, "phone"), + } + } +} + +#[skip_serializing_none] +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] +pub struct StringTypeData { + pub min_length: Option, + pub max_length: Option, + pub pattern: Option, + pub format: Option, +} + +#[skip_serializing_none] +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] +pub struct FileTypeData { + pub min_size: Option, + pub max_size: Option, + pub mime_types: Option>, +} + +#[skip_serializing_none] +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct ObjectTypeData { + pub properties: IndexMap, + pub id: Vec, + #[serde(default)] + pub required: Vec, + #[serde(skip_serializing_if = "IndexMap::is_empty")] + #[serde(default)] + pub policies: IndexMap>, +} + +#[skip_serializing_none] +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] +pub struct ListTypeData { + pub items: Id, + pub max_items: Option, + pub min_items: Option, + pub unique_items: Option, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(untagged)] +pub enum InjectionNode { + Parent { + children: IndexMap, + }, + Leaf { + injection: Injection, + }, +} + +impl InjectionNode { + pub fn collect_secrets_into(&self, collector: &mut Vec) -> Result<()> { + match self { + InjectionNode::Leaf { injection } => { + if let Injection::Secret(d) = injection { + collector.extend(d.values::()?); + } + } + InjectionNode::Parent { children } => { + for child in children.values() { + child.collect_secrets_into(collector)?; + } + } + } + Ok(()) + } +} + +#[skip_serializing_none] +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct FunctionTypeData { + pub input: Id, + #[serde(rename = "parameterTransform")] + pub parameter_transform: Option, + pub output: Id, + #[serde(skip_serializing_if = "IndexMap::is_empty")] + #[serde(default)] + pub injections: IndexMap, + #[serde(skip_serializing_if = "IndexMap::is_empty")] + #[serde(default)] + pub outjections: IndexMap, + #[serde(rename = "runtimeConfig")] + pub runtime_config: serde_json::Value, + pub materializer: u32, + #[serialize_always] + pub rate_weight: Option, + pub rate_calls: bool, +} + +#[skip_serializing_none] +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] +pub struct UnionTypeData { + /// Array of indexes of the nodes that are used as subschemes in the + /// anyOf field of JSON Schema. + pub any_of: Vec, +} + +#[skip_serializing_none] +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] +pub struct EitherTypeData { + /// Array of indexes of the nodes that are used as subschemes in the + /// oneOf field of JSON Schema. + pub one_of: Vec, +} + +#[skip_serializing_none] +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(tag = "type", rename_all = "lowercase")] +pub enum TypeNode { + Optional { + #[serde(flatten)] + base: TypeNodeBase, + #[serde(flatten)] + data: OptionalTypeData, + }, + Boolean { + #[serde(flatten)] + base: TypeNodeBase, + }, + Float { + #[serde(flatten)] + base: TypeNodeBase, + #[serde(flatten)] + data: FloatTypeData, + }, + Integer { + #[serde(flatten)] + base: TypeNodeBase, + #[serde(flatten)] + data: IntegerTypeData, + }, + String { + #[serde(flatten)] + base: TypeNodeBase, + #[serde(flatten)] + data: StringTypeData, + }, + File { + #[serde(flatten)] + base: TypeNodeBase, + #[serde(flatten)] + data: FileTypeData, + }, + Object { + #[serde(flatten)] + base: TypeNodeBase, + #[serde(flatten)] + data: ObjectTypeData, + }, + List { + #[serde(flatten)] + base: TypeNodeBase, + #[serde(flatten)] + data: ListTypeData, + }, + Function { + #[serde(flatten)] + base: TypeNodeBase, + #[serde(flatten)] + data: FunctionTypeData, + }, + Union { + #[serde(flatten)] + base: TypeNodeBase, + #[serde(flatten)] + data: UnionTypeData, + }, + #[serde(rename_all = "camelCase")] + Either { + #[serde(flatten)] + base: TypeNodeBase, + #[serde(flatten)] + data: EitherTypeData, + }, + Any { + #[serde(flatten)] + base: TypeNodeBase, + }, +} + +impl TypeNode { + pub fn base(&self) -> &TypeNodeBase { + use TypeNode::*; + match self { + Optional { base, .. } + | Boolean { base, .. } + | Float { base, .. } + | Integer { base, .. } + | String { base, .. } + | File { base, .. } + | Object { base, .. } + | List { base, .. } + | Function { base, .. } + | Union { base, .. } + | Either { base, .. } + | Any { base, .. } => base, + } + } + + pub fn base_mut(&mut self) -> &mut TypeNodeBase { + use TypeNode::*; + match self { + Optional { base, .. } + | Boolean { base, .. } + | Float { base, .. } + | Integer { base, .. } + | String { base, .. } + | File { base, .. } + | Object { base, .. } + | List { base, .. } + | Function { base, .. } + | Union { base, .. } + | Either { base, .. } + | Any { base, .. } => base, + } + } + + pub fn type_name(&self) -> &'static str { + use TypeNode::*; + match self { + Optional { .. } => "optional", + Boolean { .. } => "boolean", + Float { .. } => "float", + Integer { .. } => "integer", + String { .. } => "string", + File { .. } => "file", + Object { .. } => "object", + List { .. } => "list", + Function { .. } => "function", + Union { .. } => "union", + Either { .. } => "either", + Any { .. } => "any", + } + } + + pub fn is_scalar(&self) -> bool { + use TypeNode::*; + matches!( + self, + Boolean { .. } | Float { .. } | Integer { .. } | String { .. } + ) + } +} diff --git a/src/typegraph/schema/src/utils.rs b/src/typegraph/schema/src/utils.rs new file mode 100644 index 0000000000..aa8888c675 --- /dev/null +++ b/src/typegraph/schema/src/utils.rs @@ -0,0 +1,42 @@ +// Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. +// SPDX-License-Identifier: MPL-2.0 + +use crate::{runtimes::TGRuntime, Typegraph}; +use anyhow::{bail, Result}; +use indexmap::IndexMap; +use serde::{de::DeserializeOwned, ser::Serialize}; +use serde_json::{from_value, to_value, Value}; + +pub fn object_from_map(map: IndexMap) -> Result { + let map = Value::Object(map.into_iter().collect()); + Ok(from_value(map)?) +} + +pub fn map_from_object(obj: T) -> Result> { + let val = to_value(obj)?; + if let Value::Object(map) = val { + Ok(map.into_iter().collect()) + } else { + bail!("value is not an object"); + } +} + +pub fn find_runtimes(typegraph: &Typegraph, predicate: impl Fn(&TGRuntime) -> bool) -> Vec { + typegraph + .runtimes + .iter() + .enumerate() + .filter(|(_, rt)| predicate(rt)) + .map(|(idx, _)| idx) + .collect() +} + +pub fn get_materializers(typegraph: &Typegraph, rt_idx: u32) -> Vec { + typegraph + .materializers + .iter() + .enumerate() + .filter(|(_, mat)| mat.runtime == rt_idx) + .map(|(idx, _)| idx) + .collect() +} diff --git a/src/typegraph/schema/src/validator/common.rs b/src/typegraph/schema/src/validator/common.rs new file mode 100644 index 0000000000..2606f3f8ba --- /dev/null +++ b/src/typegraph/schema/src/validator/common.rs @@ -0,0 +1,53 @@ +// Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. +// SPDX-License-Identifier: MPL-2.0 + +use crate::{EitherTypeData, TypeNode, Typegraph, UnionTypeData}; + +impl Typegraph { + pub fn check_enum_values( + &self, + type_idx: u32, + enum_values: &[String], + ) -> Result<(), Vec> { + let type_node = self.types.get(type_idx as usize).unwrap(); + let mut errors = Vec::new(); + if matches!(type_node, TypeNode::Optional { .. }) { + errors.push("optional not cannot have enumerated values".to_owned()); + } else { + for value in enum_values { + match serde_json::from_str::(value) { + Ok(val) => match self.validate_value(type_idx, &val) { + Ok(_) => {} + Err(err) => errors.push(err.to_string()), + }, + Err(e) => errors.push(format!( + "Error while deserializing enum value {value:?}: {e:?}" + )), + } + } + } + + if errors.is_empty() { + Ok(()) + } else { + Err(errors) + } + } + + pub fn collect_nested_variants_into(&self, out: &mut Vec, variants: &[u32]) { + for idx in variants { + let node = self.types.get(*idx as usize).unwrap(); + match node { + TypeNode::Union { + data: UnionTypeData { any_of: variants }, + .. + } + | TypeNode::Either { + data: EitherTypeData { one_of: variants }, + .. + } => self.collect_nested_variants_into(out, variants), + _ => out.push(*idx), + } + } + } +} diff --git a/src/typegraph/schema/src/validator/injection.rs b/src/typegraph/schema/src/validator/injection.rs new file mode 100644 index 0000000000..791299a398 --- /dev/null +++ b/src/typegraph/schema/src/validator/injection.rs @@ -0,0 +1,269 @@ +// Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. +// SPDX-License-Identifier: MPL-2.0 + +use indexmap::IndexMap; +use serde_json::Value; + +use super::types::{EnsureSubtypeOf as _, ErrorCollector, ExtendedTypeNode}; +use super::{Validator, ValidatorContext}; +use crate::visitor::{Edge, PathSegment, TypeVisitorContext as _}; +use crate::{Injection, InjectionNode, ObjectTypeData, TypeId, TypeNode}; + +pub struct InjectionValidationContext<'a> { + pub fn_path: Vec, + pub fn_idx: TypeId, + pub input_idx: TypeId, + pub parent_object: &'a ObjectTypeData, + pub validator: &'a ValidatorContext<'a>, +} + +impl<'a> InjectionValidationContext<'a> { + fn get_path(&self, path: &[String]) -> Vec { + let mut res = self.fn_path.clone(); + res.push(PathSegment { + from: self.fn_idx, + edge: Edge::FunctionInput, + }); + res.push(PathSegment { + from: self.input_idx, + edge: Edge::ObjectProp(path.join(".")), + }); + res + } +} + +enum UnionKind { + Union, + Either, +} + +impl Validator { + pub fn validate_injection( + &mut self, + path: &mut Vec, + type_idx: TypeId, + injection_node: &InjectionNode, + cx: &InjectionValidationContext<'_>, + ) { + let tg = cx.validator.get_typegraph(); + match injection_node { + InjectionNode::Leaf { injection } => match injection { + Injection::Static(data) => { + for value in data.values::().unwrap().iter() { + match serde_json::from_str::(value) { + Ok(val) => match tg.validate_value(type_idx, &val) { + Ok(_) => {} + Err(err) => self.push_error(&cx.get_path(path), err.to_string()), + }, + Err(e) => { + self.push_error( + &cx.get_path(path), + format!( + "Error while parsing static injection value {value:?}: {e:?}", + value = value + ), + ); + } + } + } + } + Injection::Parent(data) => { + let sources = data.values::().unwrap(); + for source_key in sources.iter() { + self.validate_parent_injection(source_key, type_idx, path, cx); + } + } + _ => (), + }, + InjectionNode::Parent { children } => { + let type_idx = tg.resolve_quant(type_idx); + let type_node = &cx.validator.get_typegraph().types[type_idx as usize]; + match type_node { + TypeNode::Object { data, .. } => { + for (key, node) in children.iter() { + path.push(key.clone()); + match data.properties.get(key) { + Some(type_idx) => { + self.validate_injection(path, *type_idx, node, cx); + } + None => { + self.push_error( + &cx.get_path(path), + format!( + "unexpected injection path prefix: {:?}, available properties are: {:?}", + path.join("."), data.properties.keys().collect::>() + ), + ); + } + } + path.pop(); + } + } + TypeNode::Union { data, .. } => { + self.validate_union( + type_node, + &data.any_of, + children, + path, + cx, + UnionKind::Union, + ); + } + TypeNode::Either { data, .. } => { + self.validate_union( + type_node, + &data.one_of, + children, + path, + cx, + UnionKind::Either, + ); + } + _ => { + self.push_error( + &cx.get_path(path), + format!("expected object type, found: {:?}", type_node), + ); + self.push_error( + &cx.get_path(path), + format!("unexpected injection path prefix: {:?}", path.join(".")), + ); + } + } + } + } + } + + fn validate_parent_injection( + &mut self, + source_key: &str, + in_type_idx: TypeId, + in_path: &[String], + cx: &InjectionValidationContext<'_>, + ) { + let tg = cx.validator.get_typegraph(); + let source_idx = { + let source_idx = cx.parent_object.properties.get(source_key); + match source_idx { + Some(idx) => *idx, + None => { + let keys = cx.parent_object.properties.keys().collect::>(); + self.push_error( + &cx.get_path(in_path), + format!( + "from_parent injection: source key {source_key} not found in parent; available keys: {keys:?}", + source_key = source_key + ), + ); + return; + } + } + }; + + let source = ExtendedTypeNode::new(tg, source_idx); + let target = ExtendedTypeNode::new(tg, in_type_idx); + let mut errors = ErrorCollector::default(); + source.ensure_subtype_of(&target, tg, &mut errors); + for error in errors.errors.into_iter() { + self.push_error( + &cx.get_path(in_path), + format!("from_parent injection: {error}", error = error), + ); + } + } + + fn validate_union( + &mut self, + type_node: &TypeNode, + variants: &[TypeId], + children: &IndexMap, + path: &mut Vec, + cx: &InjectionValidationContext<'_>, + union_kind: UnionKind, + ) { + let eligible_variants = variants + .iter() + .cloned() + .filter_map(|type_idx| { + let type_node = &cx.validator.get_typegraph().types[type_idx as usize]; + match type_node { + TypeNode::Object { data, .. } => children + .keys() + .all(|key| data.properties.contains_key(key)) + .then_some(data), + _ => None, + } + }) + .collect::>(); + if eligible_variants.is_empty() { + self.push_error( + &cx.get_path(path), + format!("expected object type, found: {:?}", type_node), + ); + self.push_error( + &cx.get_path(path), + format!("unexpected injection path prefix: {:?}", path.join(".")), + ); + } + + let mut match_count = 0; + + for type_data in eligible_variants { + let mut validator = Validator::default(); + for (key, node) in children.iter() { + path.push(key.clone()); + match type_data.properties.get(key) { + Some(type_idx) => { + validator.validate_injection(path, *type_idx, node, cx); + } + None => { + unreachable!(); + } + } + path.pop(); + } + if validator.errors.is_empty() { + match union_kind { + UnionKind::Union => { + return; + } + UnionKind::Either => { + match_count += 1; + } + } + } + } + match union_kind { + UnionKind::Union => { + self.push_error( + &cx.get_path(path), + format!( + "no variant of the union type matches the injection path prefix: {:?}", + path.join(".") + ), + ); + } + UnionKind::Either => match match_count { + 0 => { + self.push_error( + &cx.get_path(path), + format!( + "no variant of the union type matches the injection path prefix: {:?}", + path.join(".") + ), + ); + } + 1 => {} + _ => { + self.push_error( + &cx.get_path(path), + format!( + "multiple variants of the union type match the injection path prefix: {:?}", + path.join(".") + ), + ); + } + }, + } + } +} diff --git a/src/typegraph/schema/src/validator/input.rs b/src/typegraph/schema/src/validator/input.rs new file mode 100644 index 0000000000..bbdfa8fbb9 --- /dev/null +++ b/src/typegraph/schema/src/validator/input.rs @@ -0,0 +1,41 @@ +// Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. +// SPDX-License-Identifier: MPL-2.0 + +use crate::{ + visitor::{CurrentNode, TypeVisitor, VisitResult}, + TypeNode, +}; + +use super::{TypeVisitorContext, Validator}; + +impl Validator { + pub fn visit_input_type_impl( + &mut self, + current_node: CurrentNode<'_>, + context: &::Context, + ) -> VisitResult<::Return> { + let type_node = current_node.type_node; + + if let TypeNode::Function { .. } = type_node { + // TODO suggest to use composition-- when available + self.push_error(current_node.path, "Function is not allowed in input types."); + return VisitResult::Continue(false); + } + + if let Some(enumeration) = &type_node.base().enumeration { + match context + .get_typegraph() + .check_enum_values(current_node.type_idx, enumeration) + { + Ok(_) => {} + Err(err) => { + for e in err { + self.push_error(current_node.path, e); + } + } + } + } + + VisitResult::Continue(true) + } +} diff --git a/src/typegraph/schema/src/validator/mod.rs b/src/typegraph/schema/src/validator/mod.rs new file mode 100644 index 0000000000..a6deec3bc8 --- /dev/null +++ b/src/typegraph/schema/src/validator/mod.rs @@ -0,0 +1,277 @@ +// Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. +// SPDX-License-Identifier: MPL-2.0 + +mod common; +mod injection; +mod input; +mod types; +mod value; + +use self::injection::InjectionValidationContext; + +use super::visitor::{ + visit_child, ChildNode, CurrentNode, ParentFn, Path, PathSegment, TypeVisitor, + TypeVisitorContext, VisitLayer, VisitResult, VisitorResult, +}; +use crate::{TypeNode, Typegraph}; +use std::collections::{hash_map, HashMap}; + +use self::types::{EnsureSubtypeOf, ErrorCollector, ExtendedTypeNode}; + +#[allow(dead_code)] +fn assert_unique_titles(types: &[TypeNode]) -> Vec { + let mut duplicates = vec![]; + let mut map: HashMap = HashMap::new(); + for (i, t) in types.iter().enumerate() { + let entry = map.entry(t.base().title.clone()); + match entry { + hash_map::Entry::Occupied(o) => { + duplicates.push((t.base().title.clone(), *o.get(), i)); + } + hash_map::Entry::Vacant(v) => { + v.insert(i); + } + } + } + duplicates + .into_iter() + .map(|(title, i, j)| ValidatorError { + path: "".to_owned(), + message: format!("Duplicate title '{}' in types #{} and #{}", title, i, j), + }) + .collect() +} + +pub fn validate_typegraph(tg: &Typegraph) -> Vec { + let mut errors = vec![]; + // FIXME temporarily disabled, will be re-enabled after all changes on the + // typegraph are merged + // errors.extend(assert_unique_titles(&tg.types)); + let context = ValidatorContext { typegraph: tg }; + let validator = Validator::default(); + + errors.extend(tg.traverse_types(validator, &context, Layer, 0).unwrap()); + errors +} + +#[derive(Debug)] +pub struct ValidatorError { + pub path: String, + pub message: String, +} + +#[derive(Debug, Clone)] +pub struct ValidatorContext<'a> { + typegraph: &'a Typegraph, +} + +#[derive(Debug, Default)] +struct Validator { + errors: Vec, +} + +#[derive(Clone)] +struct Layer; + +impl<'a> VisitLayer<'a, Validator> for Layer { + fn visit( + &self, + traversal: &mut super::visitor::TypegraphTraversal<'a, Validator, Self>, + source: impl Iterator, + context: &'a ValidatorContext<'a>, + ) -> Option<::Return> { + let mut errors = vec![]; + for ChildNode(path_seg, idx) in source { + if let Some(err) = visit_child(traversal, path_seg, idx, context) { + errors.extend(err); + } + } + if errors.is_empty() { + None + } else { + Some(errors) + } + } +} + +impl Validator { + fn push_error(&mut self, path: &[PathSegment], message: impl Into) { + self.errors.push(ValidatorError { + path: Path(path).to_string(), + message: message.into(), + }); + } +} + +impl VisitorResult for Vec { + fn from_error(path: String, message: String) -> Self { + vec![ValidatorError { path, message }] + } +} + +impl<'a> TypeVisitorContext for ValidatorContext<'a> { + fn get_typegraph(&self) -> &Typegraph { + self.typegraph + } +} + +impl<'a> TypeVisitor<'a> for Validator { + type Return = Vec; + type Context = ValidatorContext<'a>; + + fn visit( + &mut self, + current_node: CurrentNode<'_>, + context: &Self::Context, + ) -> VisitResult { + let type_node = current_node.type_node; + + let tg = context.get_typegraph(); + + let get_type_name = |idx: u32| tg.types.get(idx as usize).unwrap().type_name(); + + if let TypeNode::Function { data, .. } = type_node { + let parent_idx = current_node.path.last().unwrap().from; + let parent_object = match &context.get_typegraph().types[parent_idx as usize] { + TypeNode::Object { data, .. } => data, + _ => { + self.push_error( + current_node.path, + "function parent is not an object".to_owned(), + ); + return VisitResult::Continue(false); + } + }; + let mut path = vec![]; + let inj_cx = InjectionValidationContext { + fn_path: current_node.path.to_vec(), + fn_idx: current_node.type_idx, + input_idx: data.input, + parent_object, + validator: context, + }; + let input_object = match &context.get_typegraph().types[data.input as usize] { + TypeNode::Object { data, .. } => data, + _ => { + self.push_error( + current_node.path, + "function input is not an object".to_owned(), + ); + return VisitResult::Continue(false); + } + }; + for (k, inj) in data.injections.iter() { + path.push(k.clone()); + self.validate_injection( + &mut path, + *input_object.properties.get(k).unwrap(), + inj, + &inj_cx, + ); + path.pop(); + } + // TODO validate outjection + // if !data.outjections.is_empty() { + // let outj_cx = InjectionValidationContext { + // fn_path: current_node.path.to_vec(), + // fn_idx: current_node.type_idx, + // input_idx: data.output, + // parent_object, + // validator: context, + // }; + // for (k, outj) in data.outjections.iter() { + // path.push(k.clone()); + // self.validate_injection( + // &mut path, + // *parent_object.properties.get(k).unwrap(), + // outj, + // &outj_cx, + // ); + // path.pop(); + // } + // } + } else if let TypeNode::Either { data, .. } = type_node { + let variants = data.one_of.clone(); + for i in 0..variants.len() { + for j in (i + 1)..variants.len() { + let type1 = ExtendedTypeNode::new(tg, variants[i]); + let type2 = ExtendedTypeNode::new(tg, variants[j]); + + let mut subtype_errors = ErrorCollector::default(); + type1.ensure_subtype_of(&type2, tg, &mut subtype_errors); + + if subtype_errors.errors.is_empty() { + self.push_error( + current_node.path, + format!( + "Invalid either type: variant #{i} ('{}') is a subtype of variant #{j} ('{}')", + get_type_name(variants[i]), + get_type_name(variants[j]), + ), + ); + } + + let mut subtype_errors = ErrorCollector::default(); + type2.ensure_subtype_of(&type1, tg, &mut subtype_errors); + + if subtype_errors.errors.is_empty() { + self.push_error( + current_node.path, + format!( + "Invalid either type: variant #{j} ('{}') is a subtype of variant #{i} ('{}')", + get_type_name(variants[j]), + get_type_name(variants[i]), + ), + ); + } + } + } + } else if let TypeNode::Union { data, .. } = type_node { + let variants = data.any_of.clone(); + + for i in 0..variants.len() { + for j in (i + 1)..variants.len() { + if variants[i] == variants[j] { + self.push_error( + current_node.path, + format!( + "Invalid union type: variant #{i} ('{}') is the same type as variant #{j} ('{}')", + get_type_name(variants[i]), + get_type_name(variants[j]), + ), + ); + } + } + } + } + + if let Some(enumeration) = &type_node.base().enumeration { + match context + .get_typegraph() + .check_enum_values(current_node.type_idx, enumeration) + { + Ok(_) => {} + Err(err) => { + for e in err { + self.push_error(current_node.path, e); + } + } + } + } + + VisitResult::Continue(true) + } + + fn visit_input_type( + &mut self, + current_node: CurrentNode<'_>, + context: &Self::Context, + _parent_fn: ParentFn, + ) -> VisitResult { + self.visit_input_type_impl(current_node, context) + } + + fn take_result(&mut self) -> Option { + Some(std::mem::take(&mut self.errors)) + } +} diff --git a/src/typegraph/schema/src/validator/types.rs b/src/typegraph/schema/src/validator/types.rs new file mode 100644 index 0000000000..ac631f2eed --- /dev/null +++ b/src/typegraph/schema/src/validator/types.rs @@ -0,0 +1,662 @@ +// Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. +// SPDX-License-Identifier: MPL-2.0 + +use crate::{ + EitherTypeData, FileTypeData, FloatTypeData, IntegerTypeData, ListTypeData, ObjectTypeData, + StringTypeData, TypeNode, Typegraph, UnionTypeData, +}; +use std::{collections::HashSet, fmt::Display}; + +pub struct ExtendedTypeNode<'a>(u32, &'a TypeNode); + +impl<'a> ExtendedTypeNode<'a> { + pub fn new(typegraph: &'a Typegraph, idx: u32) -> Self { + ExtendedTypeNode(idx, typegraph.types.get(idx as usize).unwrap()) + } +} + +#[derive(Debug, Default)] +pub struct ErrorCollector { + pub errors: Vec, +} + +impl ErrorCollector { + fn push(&mut self, message: impl Into) { + self.errors.push(message.into()); + } + + fn push_nested(&mut self, title: impl Display, nested: Self) { + self.errors.push(format!(" - {title}")); + for error in nested.errors { + self.errors.push(format!(" - - {error}")); + } + } +} + +pub trait EnsureSubtypeOf { + fn ensure_subtype_of(&self, sup: &T, typegraph: &Typegraph, errors: &mut ErrorCollector); +} + +fn ensure_subtype_of_for_min( + left: Option, + right: Option, + key: &str, + errors: &mut ErrorCollector, +) where + T: Display + PartialOrd, +{ + match (left, right) { + (Some(left), Some(right)) => { + if left < right { + errors.push(format!( + "'{key}' cannot be lower on the subtype: {} < {}", + left, right + )); + } + } + (None, Some(_)) => { + errors.push(format!( + "'{key}' is required on the subtype if it is defined on the supertype" + )); + } + _ => {} + } +} + +fn ensure_subtype_of_for_max( + left: Option, + right: Option, + key: &str, + errors: &mut ErrorCollector, +) where + T: Display + PartialOrd, +{ + match (left, right) { + (Some(left), Some(right)) => { + if left > right { + errors.push(format!( + "'{key}' cannot be higher on the subtype: {} > {}", + left, right + )); + } + } + (None, Some(_)) => { + errors.push(format!( + "'{key}' is required on the subtype if it is defined on the supertype" + )); + } + _ => {} + } +} + +fn ensure_subtype_of_for_multiple_of( + left: Option, + right: Option, + key: &str, + errors: &mut ErrorCollector, +) where + T: Display + std::ops::Rem + Copy + Default + PartialEq, +{ + match (left, right) { + (Some(left), Some(right)) => { + if left % right != Default::default() { + errors.push(format!( + "'{key}' is not a multiple of the '{key}' of the supertype ({} % {} != 0)", + left, right + )); + } + } + (None, Some(_)) => { + errors.push(format!( + "'{key}' is required on the subtype if it is defined on the supertype" + )); + } + _ => {} + } +} + +impl EnsureSubtypeOf for IntegerTypeData { + fn ensure_subtype_of(&self, other: &Self, _tg: &Typegraph, errors: &mut ErrorCollector) { + ensure_subtype_of_for_min(self.minimum, other.minimum, "minimum", errors); + ensure_subtype_of_for_max(self.maximum, other.maximum, "maximum", errors); + ensure_subtype_of_for_min( + self.exclusive_minimum, + other.exclusive_minimum, + "exclusive_minimum", + errors, + ); + ensure_subtype_of_for_max( + self.exclusive_maximum, + other.exclusive_maximum, + "exclusive_maximum", + errors, + ); + ensure_subtype_of_for_multiple_of( + self.multiple_of, + other.multiple_of, + "multiple_of", + errors, + ); + } +} + +impl EnsureSubtypeOf for FloatTypeData { + fn ensure_subtype_of(&self, other: &Self, _tg: &Typegraph, errors: &mut ErrorCollector) { + ensure_subtype_of_for_min(self.minimum, other.minimum, "minimum", errors); + ensure_subtype_of_for_max(self.maximum, other.maximum, "maximum", errors); + ensure_subtype_of_for_min( + self.exclusive_minimum, + other.exclusive_minimum, + "exclusive_minimum", + errors, + ); + ensure_subtype_of_for_max( + self.exclusive_maximum, + other.exclusive_maximum, + "exclusive_maximum", + errors, + ); + ensure_subtype_of_for_multiple_of( + self.multiple_of, + other.multiple_of, + "multiple_of", + errors, + ); + } +} + +impl EnsureSubtypeOf for IntegerTypeData { + fn ensure_subtype_of( + &self, + other: &FloatTypeData, + _tg: &Typegraph, + errors: &mut ErrorCollector, + ) { + ensure_subtype_of_for_min( + self.minimum.map(|m| m as f64), + other.minimum, + "minimum", + errors, + ); + ensure_subtype_of_for_max( + self.maximum.map(|m| m as f64), + other.maximum, + "maximum", + errors, + ); + ensure_subtype_of_for_min( + self.exclusive_minimum.map(|m| m as f64), + other.exclusive_minimum, + "exclusive_minimum", + errors, + ); + ensure_subtype_of_for_max( + self.exclusive_maximum.map(|m| m as f64), + other.exclusive_maximum, + "exclusive_maximum", + errors, + ); + ensure_subtype_of_for_multiple_of( + self.multiple_of.map(|m| m as f64), + other.multiple_of, + "multiple_of", + errors, + ); + } +} + +impl EnsureSubtypeOf for StringTypeData { + fn ensure_subtype_of(&self, other: &Self, _tg: &Typegraph, errors: &mut ErrorCollector) { + ensure_subtype_of_for_min(self.min_length, other.min_length, "minimum_length", errors); + ensure_subtype_of_for_max(self.max_length, other.max_length, "maximum_length", errors); + + match (&self.pattern, &other.pattern) { + (Some(left), Some(right)) => { + if left != right { + errors.push(format!( + "'pattern' is required to be exactly the same as the supertype's: {} != {}", + left, right + )); + } + } + (None, Some(_)) => { + errors + .push("'pattern' is required on the subtype if it is defined on the supertype"); + } + _ => {} + } + + match (&self.format, &other.format) { + (Some(left), Some(right)) => { + if left != right { + errors.push(format!( + "'format' is required to be the same as the supertype's: {} != {}", + left, right + )); + } + } + (None, Some(_)) => { + errors + .push("'format' is required on the subtype if it is defined on the supertype"); + } + _ => {} + } + } +} + +impl EnsureSubtypeOf for FileTypeData { + fn ensure_subtype_of(&self, other: &Self, _tg: &Typegraph, errors: &mut ErrorCollector) { + ensure_subtype_of_for_min(self.min_size, other.min_size, "minimum_size", errors); + ensure_subtype_of_for_max(self.max_size, other.max_size, "maximum_size", errors); + + // FIXME consistency: the name on the SDK is 'allow' + match (&self.mime_types, &other.mime_types) { + (Some(left), Some(right)) => { + // O(n * m) but n and m are _usually_ small + if left.iter().any(|m| !right.contains(m)) { + errors.push("'mime_types' is required to be a subset of the supertype's"); + } + } + (None, Some(_)) => { + errors.push( + "'mime_types' is required on the subtype if it is defined on the supertype", + ); + } + _ => {} + } + } +} + +impl EnsureSubtypeOf for ObjectTypeData { + fn ensure_subtype_of(&self, other: &Self, tg: &Typegraph, errors: &mut ErrorCollector) { + let mut right_keys = other.properties.keys().collect::>(); + + for (key, left_idx) in &self.properties { + if let Some(right_idx) = other.properties.get(key) { + // TODO add some context on the error messages + ExtendedTypeNode::new(tg, *left_idx).ensure_subtype_of( + &ExtendedTypeNode::new(tg, *right_idx), + tg, + errors, + ); + } else { + errors.push(format!( + "property {} is not allowed: it is not defined in the supertype", + key + )); + } + right_keys.remove(key); + } + + for key in right_keys { + let type_idx = other.properties.get(key).unwrap(); + let type_node = tg.types.get(*type_idx as usize).unwrap(); + if !matches!(type_node, TypeNode::Optional { .. }) { + errors.push(format!( + "property {} is required: it is not optional in the supertype", + key + )); + } + } + + // FIXME https://linear.app/metatypedev/issue/MET-664/graph-check-the-semantics-of-type-refinements-on-tstruct + for key in &self.required { + if !other.required.contains(key) { + errors.push(format!("property {} is not required in the supertype", key)); + } + } + } +} + +impl EnsureSubtypeOf for ListTypeData { + fn ensure_subtype_of(&self, sup: &Self, typegraph: &Typegraph, errors: &mut ErrorCollector) { + ensure_subtype_of_for_min(self.min_items, sup.min_items, "minimum_items", errors); + ensure_subtype_of_for_max(self.max_items, sup.max_items, "maximum_items", errors); + if self.unique_items.unwrap_or(false) && !sup.unique_items.unwrap_or(false) { + errors.push("unique_items is not defined in the subtype"); + } + ExtendedTypeNode::new(typegraph, self.items).ensure_subtype_of( + &ExtendedTypeNode::new(typegraph, sup.items), + typegraph, + errors, + ); + } +} + +struct AnyOf<'a>(&'a [u32]); +struct OneOf<'a>(&'a [u32]); +struct AllOf<'a>(&'a [u32]); + +impl<'a, 'b> EnsureSubtypeOf> for ExtendedTypeNode<'b> { + fn ensure_subtype_of( + &self, + sup: &AnyOf<'a>, + typegraph: &Typegraph, + errors: &mut ErrorCollector, + ) { + let collectors: Vec = vec![]; + for idx in sup.0 { + let sup_type = ExtendedTypeNode::new(typegraph, *idx); + let mut errors = ErrorCollector::default(); + self.ensure_subtype_of(&sup_type, typegraph, &mut errors); + if errors.errors.is_empty() { + return; + } + } + errors.push("Expected at least one variant to be a supertype, got none"); + for (idx, nested) in collectors.into_iter().enumerate() { + errors.push_nested(format!("Variant {}", idx), nested); + } + } +} + +impl<'a, 'b> EnsureSubtypeOf> for ExtendedTypeNode<'b> { + fn ensure_subtype_of( + &self, + sup: &OneOf<'a>, + typegraph: &Typegraph, + errors: &mut ErrorCollector, + ) { + let collectors = sup + .0 + .iter() + .map(|idx| { + let sup_type = ExtendedTypeNode::new(typegraph, *idx); + let mut errors = ErrorCollector::default(); + self.ensure_subtype_of(&sup_type, typegraph, &mut errors); + errors + }) + .collect::>(); + + let match_count = collectors.iter().filter(|c| c.errors.is_empty()).count(); + match match_count { + 0 => { + errors.push("Expected a single variant to be a supertype, got none"); + for (idx, nested) in collectors.into_iter().enumerate() { + errors.push_nested(format!("Variant {}", idx), nested); + } + } + 1 => { + // nothing to do + } + _ => { + errors.push(format!( + "Expected a single variant to be a supertype, got more: variants {}", + collectors + .iter() + .enumerate() + .filter(|(_, c)| c.errors.is_empty()) + .map(|(i, _)| i.to_string()) + .collect::>() + .join(", "), + )); + } + } + } +} + +impl<'b, S> EnsureSubtypeOf for AllOf<'b> +where + for<'a> ExtendedTypeNode<'a>: EnsureSubtypeOf, +{ + fn ensure_subtype_of(&self, sup: &S, typegraph: &Typegraph, errors: &mut ErrorCollector) { + let mut count = 0; + let collectors = self + .0 + .iter() + .enumerate() + .filter_map(|(i, type_idx)| { + let mut errors = ErrorCollector::default(); + let sub_type = ExtendedTypeNode::new(typegraph, *type_idx); + sub_type.ensure_subtype_of(sup, typegraph, &mut errors); + if errors.errors.is_empty() { + None + } else { + count += 1; + Some((i, errors)) + } + }) + .collect::>(); + + if count > 0 { + errors.push("Expected all variants to be a subtype"); + for (idx, nested) in collectors { + errors.push_nested(format!("Variant {} is not a subtype", idx), nested); + } + } + } +} + +impl EnsureSubtypeOf for UnionTypeData { + fn ensure_subtype_of(&self, sup: &Self, typegraph: &Typegraph, errors: &mut ErrorCollector) { + AllOf(&self.any_of).ensure_subtype_of(&AnyOf(&sup.any_of), typegraph, errors); + } +} + +impl EnsureSubtypeOf for EitherTypeData { + fn ensure_subtype_of(&self, sup: &Self, typegraph: &Typegraph, errors: &mut ErrorCollector) { + AllOf(&self.one_of).ensure_subtype_of(&OneOf(&sup.one_of), typegraph, errors); + } +} + +impl EnsureSubtypeOf for EitherTypeData { + fn ensure_subtype_of( + &self, + sup: &UnionTypeData, + typegraph: &Typegraph, + errors: &mut ErrorCollector, + ) { + AllOf(&self.one_of).ensure_subtype_of(&AnyOf(&sup.any_of), typegraph, errors); + } +} + +impl EnsureSubtypeOf for UnionTypeData { + fn ensure_subtype_of( + &self, + sup: &EitherTypeData, + typegraph: &Typegraph, + errors: &mut ErrorCollector, + ) { + AllOf(&self.any_of).ensure_subtype_of(&OneOf(&sup.one_of), typegraph, errors); + } +} + +struct Enum<'a>(Option<&'a [String]>); + +impl<'a, 'b> EnsureSubtypeOf> for Enum<'b> { + fn ensure_subtype_of(&self, sup: &Enum<'a>, _tg: &Typegraph, errors: &mut ErrorCollector) { + let sub = self.0.unwrap_or(&[]); + let sup = sup.0.unwrap_or(&[]); + if sub.is_empty() && !sup.is_empty() { + errors.push("Expected the subtype to be an enum"); + return; + } + let sup = sup + .iter() + .map(|s| serde_json::to_value(s).unwrap()) + .collect::>(); + let not_found = sub + .iter() + .map(|s| serde_json::to_value(s).unwrap()) + .enumerate() + .filter(|(_, sup_v)| sup.iter().all(|v| !value_equals(v, sup_v))) + .collect::>(); + if !not_found.is_empty() { + errors.push_nested("Expected all enum values to be defined on the supertype", { + let mut nested = ErrorCollector::default(); + for (idx, sup_v) in not_found { + nested.push(format!( + "Value {} (#{}) is not defined on the supertype", + sup_v, idx + )); + } + nested + }); + } + } +} + +// TODO move to different module +fn value_equals(left: &serde_json::Value, right: &serde_json::Value) -> bool { + match (left, right) { + (serde_json::Value::String(left), serde_json::Value::String(right)) => left == right, + (serde_json::Value::Number(left), serde_json::Value::Number(right)) => left == right, + (serde_json::Value::Bool(left), serde_json::Value::Bool(right)) => left == right, + (serde_json::Value::Array(left), serde_json::Value::Array(right)) => left + .iter() + .zip(right.iter()) + .all(|(l, r)| value_equals(l, r)), + (serde_json::Value::Object(left), serde_json::Value::Object(right)) => { + left.len() == right.len() + && left + .iter() + .all(|(k, v)| right.get(k).map_or(false, |r| value_equals(v, r))) + } + _ => false, + } +} + +impl<'a, 'b> EnsureSubtypeOf> for ExtendedTypeNode<'a> { + fn ensure_subtype_of( + &self, + sup: &ExtendedTypeNode<'b>, + tg: &Typegraph, + errors: &mut ErrorCollector, + ) { + let sub_idx = self.0; + let sup_idx = sup.0; + if sub_idx != sup_idx { + // self.1.ensure_subtype_of(sup.1, typegraph, errors); + match (self.1, sup.1) { + (TypeNode::Optional { data: sub, .. }, TypeNode::Optional { data: sup, .. }) => { + ExtendedTypeNode::new(tg, sub.item).ensure_subtype_of( + &ExtendedTypeNode::new(tg, sup.item), + tg, + errors, + ); + } + (_, TypeNode::Optional { data: sup, .. }) => { + self.ensure_subtype_of(&ExtendedTypeNode::new(tg, sup.item), tg, errors); + } + (TypeNode::Optional { .. }, _) => { + errors.push("Optional type cannot be a subtype of a non-optional type"); + } + (TypeNode::Boolean { .. }, TypeNode::Boolean { .. }) => { /* nothing to check */ } + ( + TypeNode::Integer { + data: sub, + base: sub_base, + }, + TypeNode::Integer { + data: sup, + base: sup_base, + }, + ) => { + sub.ensure_subtype_of(sup, tg, errors); + Enum(sub_base.enumeration.as_deref()).ensure_subtype_of( + &Enum(sup_base.enumeration.as_deref()), + tg, + errors, + ); + } + ( + TypeNode::Float { + data: sub, + base: sub_base, + }, + TypeNode::Float { + data: sup, + base: sup_base, + }, + ) => { + sub.ensure_subtype_of(sup, tg, errors); + Enum(sub_base.enumeration.as_deref()).ensure_subtype_of( + &Enum(sup_base.enumeration.as_deref()), + tg, + errors, + ); + } + ( + TypeNode::Integer { + data: sub, + base: sub_base, + }, + TypeNode::Float { + data: sup, + base: sup_base, + }, + ) => { + sub.ensure_subtype_of(sup, tg, errors); + Enum(sub_base.enumeration.as_deref()).ensure_subtype_of( + &Enum(sup_base.enumeration.as_deref()), + tg, + errors, + ); + } + ( + TypeNode::String { + data: sub, + base: sub_base, + }, + TypeNode::String { + data: sup, + base: sup_base, + }, + ) => { + sub.ensure_subtype_of(sup, tg, errors); + Enum(sub_base.enumeration.as_deref()).ensure_subtype_of( + &Enum(sup_base.enumeration.as_deref()), + tg, + errors, + ); + } + (TypeNode::File { data: sub, .. }, TypeNode::File { data: sup, .. }) => { + sub.ensure_subtype_of(sup, tg, errors) + } + ( + TypeNode::Object { + data: sub, + base: sub_base, + }, + TypeNode::Object { + data: sup, + base: sup_base, + }, + ) => { + sub.ensure_subtype_of(sup, tg, errors); + Enum(sub_base.enumeration.as_deref()).ensure_subtype_of( + &Enum(sup_base.enumeration.as_deref()), + tg, + errors, + ); + } + (TypeNode::List { data: sub, .. }, TypeNode::List { data: sup, .. }) => { + sub.ensure_subtype_of(sup, tg, errors) + } + (TypeNode::Union { data: sub, .. }, _) => { + AllOf(&sub.any_of).ensure_subtype_of(sup, tg, errors); + } + (TypeNode::Either { data: sub, .. }, _) => { + AllOf(&sub.one_of).ensure_subtype_of(sup, tg, errors); + } + (_, TypeNode::Union { data: sup, .. }) => { + self.ensure_subtype_of(&AnyOf(&sup.any_of), tg, errors); + } + (_, TypeNode::Either { data: sup, .. }) => { + self.ensure_subtype_of(&OneOf(&sup.one_of), tg, errors); + } + (_, TypeNode::Function { .. }) => { + errors.push("Function types are not supported for supertype"); + } + (TypeNode::Function { data, .. }, _) => { + ExtendedTypeNode::new(tg, data.output).ensure_subtype_of(sup, tg, errors); + } + (x, y) => errors.push(format!( + "Type mismatch: {} to {}", + x.type_name(), + y.type_name() + )), + } + } + } +} diff --git a/src/typegraph/schema/src/validator/value.rs b/src/typegraph/schema/src/validator/value.rs new file mode 100644 index 0000000000..58d5a57fe4 --- /dev/null +++ b/src/typegraph/schema/src/validator/value.rs @@ -0,0 +1,268 @@ +// Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. +// SPDX-License-Identifier: MPL-2.0 + +use std::collections::HashSet; + +use anyhow::{anyhow, bail, Result}; +use serde_json::Value; + +use crate::{ + EitherTypeData, FloatTypeData, IntegerTypeData, ListTypeData, ObjectTypeData, StringTypeData, + TypeNode, Typegraph, UnionTypeData, +}; + +fn to_string(value: &Value) -> String { + serde_json::to_string(value).unwrap() +} + +// TODO validation path +impl Typegraph { + pub fn validate_value(&self, type_idx: u32, value: &Value) -> Result<()> { + let type_node = &self.types[type_idx as usize]; + + match type_node { + TypeNode::Any { .. } => Ok(()), + TypeNode::Integer { data, .. } => self.validate_integer(data, value), + TypeNode::Float { data, .. } => self.validate_float(data, value), + TypeNode::Boolean { .. } => value.as_bool().map(|_| ()).ok_or_else(|| { + anyhow!("Expected a boolean got '{value}'", value = to_string(value)) + }), + TypeNode::String { data, .. } => self.validate_string(data, value), + TypeNode::File { .. } => bail!("Literal file not supported"), + TypeNode::Optional { data, .. } => { + if value.is_null() { + Ok(()) + } else { + self.validate_value(data.item, value) + } + } + TypeNode::List { data, .. } => self.validate_array(data, value), + TypeNode::Object { data, .. } => self.validate_object(data, value), + TypeNode::Function { .. } => Err(anyhow!("Unexpected function type")), + TypeNode::Union { data, .. } => self.validate_union(data, value), + TypeNode::Either { data, .. } => self.validate_either(data, value), + } + } + + fn validate_integer(&self, data: &IntegerTypeData, value: &Value) -> Result<()> { + let Value::Number(n) = value else { + bail!("Expected number got '{}'", to_string(value)); + }; + let Some(value) = n.as_i64().map(|value| value.try_into()).transpose()? else { + bail!("Number value {value:?} cannot be stored in f64"); + }; + if let Some(min) = data.minimum { + number_validator::expect_min(min, value)?; + } + if let Some(max) = data.maximum { + number_validator::expect_max(max, value)?; + } + if let Some(xmin) = data.exclusive_minimum { + number_validator::expect_xmin(xmin, value)?; + } + if let Some(xmax) = data.exclusive_maximum { + number_validator::expect_xmax(xmax, value)?; + } + if let Some(divisor) = data.multiple_of.as_ref() { + if value % divisor == 0 { + bail!("Expected a multiple of {divisor}, got {value}"); + } + } + Ok(()) + } + + fn validate_float(&self, data: &FloatTypeData, value: &Value) -> Result<()> { + let Value::Number(n) = value else { + bail!("Expected float got '{}'", to_string(value)); + }; + let Some(value) = n.as_f64() else { + bail!("Float value {value:?} cannot be stored in f64"); + }; + if let Some(min) = data.minimum { + number_validator::expect_min(min, value)?; + } + if let Some(max) = data.maximum { + number_validator::expect_max(max, value)?; + } + if let Some(xmin) = data.exclusive_minimum { + number_validator::expect_xmin(xmin, value)?; + } + if let Some(xmax) = data.exclusive_maximum { + number_validator::expect_xmax(xmax, value)?; + } + if let Some(divisor) = data.multiple_of.as_ref() { + let quot = value / divisor; + if quot.round() != quot { + bail!("Expected a multiple of {divisor}, got {value}"); + } + } + Ok(()) + } + + fn validate_string(&self, data: &StringTypeData, value: &Value) -> Result<()> { + let s = value + .as_str() + .ok_or_else(|| anyhow!("Expected a string, got '{}'", to_string(value)))?; + if let Some(min_length) = data.min_length { + if s.len() < min_length as usize { + bail!( + "Expected a minimum length of {min_length}, got {s:?} (len={})", + s.len() + ); + } + } + if let Some(max_length) = data.max_length { + if s.len() > max_length as usize { + bail!( + "Expected a maximun length of {max_length}, got {s:?} (len={})", + s.len() + ); + } + } + // TODO pattern, format + Ok(()) + } + + fn validate_array(&self, data: &ListTypeData, value: &Value) -> Result<()> { + let array = value + .as_array() + .ok_or_else(|| anyhow!("Expected an array got '{}'", to_string(value)))?; + + if let Some(max_items) = data.max_items { + if array.len() > max_items as usize { + bail!( + "Expected a maximum item count of {max_items} in array '{arr}' (len={})", + array.len(), + arr = to_string(value), + ); + } + } + + if let Some(min_items) = data.min_items { + if array.len() < min_items as usize { + bail!( + "Expected a minimum item count of {min_items} in array '{arr}' (len={})", + array.len(), + arr = to_string(value), + ); + } + } + + for item in array { + self.validate_value(data.items, item)?; + } + Ok(()) + } + + fn validate_object(&self, data: &ObjectTypeData, value: &Value) -> Result<()> { + let object = value.as_object().ok_or_else(|| { + anyhow!( + "Expected an object, got '{value}'", + value = to_string(value) + ) + })?; + + let mut remaining_keys = object.keys().collect::>(); + for (key, typ) in data.properties.iter() { + match object.get(key) { + None => { + if !matches!(self.types[*typ as usize], TypeNode::Optional { .. }) { + bail!( + "Required field {key:?} not found in object '{value}'", + value = to_string(value) + ); + } + } + Some(val) => { + self.validate_value(*typ, val)?; + remaining_keys.remove(key); + } + } + } + + // additional properties? + if !remaining_keys.is_empty() { + bail!( + "Unexpected fields {} in object {:?}", + remaining_keys + .iter() + .map(|k| format!("{k:?}")) + .collect::>() + .join(", "), + to_string(value), + ); + } + + Ok(()) + } + + fn validate_union(&self, data: &UnionTypeData, value: &Value) -> Result<()> { + for &variant in data.any_of.iter() { + if self.validate_value(variant, value).is_ok() { + return Ok(()); + } + } + bail!( + "Value '{value}' did not match any of the variants of the union", + value = to_string(value) + ); + } + + fn validate_either(&self, data: &EitherTypeData, value: &Value) -> Result<()> { + let mut valid_variants = vec![]; + for &variant in data.one_of.iter() { + if self.validate_value(variant, value).is_ok() { + valid_variants.push(variant); + } + } + match valid_variants.len() { + 0 => bail!( + "Value '{value}' did not match any of the variants of the either", + value = to_string(value) + ), + 1 => Ok(()), + _ => bail!( + "Value '{value}' matched to more than one variant onf the either: {}", + valid_variants + .iter() + .map(|v| format!("#{v}")) + .collect::>() + .join(", "), + value = to_string(value) + ), + } + } +} + +mod number_validator { + use anyhow::{bail, Result}; + use std::fmt::Display; + + pub fn expect_min(min: T, value: T) -> Result<()> { + if value < min { + bail!("Expected a minimum value of {min}, got {value}"); + } + Ok(()) + } + + pub fn expect_max(max: T, value: T) -> Result<()> { + if value > max { + bail!("Expected a maximum value of {max}, got {value}"); + } + Ok(()) + } + + pub fn expect_xmin(xmin: T, value: T) -> Result<()> { + if value <= xmin { + bail!("Expected an exclusive minimum value of {xmin}, got {value}"); + } + Ok(()) + } + + pub fn expect_xmax(xmax: T, value: T) -> Result<()> { + if value >= xmax { + bail!("Expected an exclusive maximum value of {xmax}, got {value}"); + } + Ok(()) + } +} diff --git a/src/typegraph/schema/src/visitor.rs b/src/typegraph/schema/src/visitor.rs new file mode 100644 index 0000000000..d264afd202 --- /dev/null +++ b/src/typegraph/schema/src/visitor.rs @@ -0,0 +1,447 @@ +// Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. +// SPDX-License-Identifier: MPL-2.0 + +use indexmap::IndexMap; +use std::{ + collections::{HashMap, HashSet}, + fmt::Display, +}; + +use super::{TypeNode, Typegraph}; + +#[derive(Clone)] +pub struct DefaultLayer; + +pub struct ChildNode(pub PathSegment, pub u32); + +pub trait VisitLayer<'a, V: TypeVisitor<'a>>: Clone + Sized + 'a { + fn visit( + &self, + traversal: &mut TypegraphTraversal<'a, V, Self>, + source: impl Iterator, + context: &'a V::Context, + ) -> Option; +} + +impl<'a, V: TypeVisitor<'a>> VisitLayer<'a, V> for DefaultLayer { + fn visit( + &self, + traversal: &mut TypegraphTraversal<'a, V, Self>, + source: impl Iterator, + context: &'a V::Context, + ) -> Option { + for ChildNode(path_seg, idx) in source { + if let Some(res) = visit_child(traversal, path_seg, idx, context) { + return Some(res); + } + } + None + } +} + +pub fn visit_child<'a, V: TypeVisitor<'a>, L: VisitLayer<'a, V>>( + traversal: &mut TypegraphTraversal<'a, V, L>, + path_seg: PathSegment, + idx: u32, + context: &'a V::Context, +) -> Option { + traversal.visit_child(path_seg, idx, context) +} + +impl Typegraph { + /// Depth-first traversal over all the types + pub fn traverse_types<'a, V, L>( + &'a self, + visitor: V, + context: &'a V::Context, + layer: L, + root_type_idx: u32, + ) -> Option + where + V: TypeVisitor<'a> + Sized + 'a, + L: VisitLayer<'a, V>, + { + let mut traversal = TypegraphTraversal { + tg: self, + path: vec![], + visited_types: HashMap::new(), + visited_input_types: HashMap::new(), + as_input: false, + visitor, + parent_fn: None, + layer, + }; + traversal + .visit_type(root_type_idx, context) + .or_else(|| traversal.visitor.take_result()) + } +} + +pub struct FunctionMetadata { + pub idx: u32, + // TODO Vec<> + pub path: String, + pub parent_struct_idx: u32, +} + +#[derive(Hash, PartialEq, Eq, Debug, Clone)] +pub struct ParentFn { + pub struct_idx: u32, + pub fn_key: String, +} + +pub struct TypegraphTraversal<'a, V, L = DefaultLayer> +where + V: TypeVisitor<'a> + Sized + 'a, + L: VisitLayer<'a, V>, +{ + tg: &'a Typegraph, + path: Vec, + parent_fn: Option, + as_input: bool, + visited_types: HashMap>, // non input types; per parent function + visited_input_types: HashMap>, // input types; per parent function + visitor: V, + layer: L, +} + +impl<'a, V, L> TypegraphTraversal<'a, V, L> +where + V: TypeVisitor<'a> + Sized, + L: VisitLayer<'a, V>, +{ + fn visit_type(&mut self, type_idx: u32, context: &'a V::Context) -> Option { + let res = if self.as_input { + let parent_fn = self.parent_fn.clone().unwrap(); + let visited = self + .visited_input_types + .entry(parent_fn.clone()) + .or_default(); + if visited.contains(&type_idx) { + return None; + } + visited.insert(type_idx); + let type_node = &context.get_typegraph().types[type_idx as usize]; + let node = CurrentNode { + type_idx, + type_node, + path: &self.path, + }; + + self.visitor.visit_input_type(node, context, parent_fn) + } else { + if let Some(parent_fn) = &self.parent_fn { + let visited = self.visited_types.entry(parent_fn.clone()).or_default(); + if visited.contains(&type_idx) { + return None; + } + visited.insert(type_idx); + } + + let type_node = &context.get_typegraph().types[type_idx as usize]; + let node = CurrentNode { + type_idx, + type_node, + path: &self.path, + }; + + self.visitor.visit(node, context) + }; + + let type_node = &self.tg.types[type_idx as usize]; + + match res { + VisitResult::Continue(deeper) if deeper => match type_node { + TypeNode::Optional { data, .. } => { + self.visit_optional(type_idx, data.item, context) + } + TypeNode::Object { data, .. } => { + self.visit_object(type_idx, &data.properties, context) + } + TypeNode::List { data, .. } => self.visit_array(type_idx, data.items, context), + TypeNode::Union { data, .. } => self.visit_union(type_idx, &data.any_of, context), + TypeNode::Either { data, .. } => self.visit_either(type_idx, &data.one_of, context), + TypeNode::Function { data, .. } => { + self.visit_function(type_idx, data.input, data.output, context) + } + TypeNode::Boolean { .. } + | TypeNode::Float { .. } + | TypeNode::Integer { .. } + | TypeNode::String { .. } + | TypeNode::File { .. } + | TypeNode::Any { .. } => { + // scalar types -- no children + None + } + }, + VisitResult::Continue(_) => None, + VisitResult::Return(ret) => Some(ret), + } + } + + fn visit_optional( + &mut self, + type_idx: u32, + item_type_idx: u32, + context: &'a V::Context, + ) -> Option { + self.visit_child( + PathSegment { + from: type_idx, + edge: Edge::OptionalItem, + }, + item_type_idx, + context, + ) + } + + fn visit_array( + &mut self, + type_idx: u32, + item_type_idx: u32, + context: &'a V::Context, + ) -> Option { + self.visit_child( + PathSegment { + from: type_idx, + edge: Edge::ArrayItem, + }, + item_type_idx, + context, + ) + } + + fn visit_object( + &mut self, + type_idx: u32, + props: &'a IndexMap, + context: &'a V::Context, + ) -> Option { + self.visit_children( + props.iter().map(|(name, idx)| { + ( + PathSegment { + from: type_idx, + edge: Edge::ObjectProp(name.clone()), + }, + *idx, + ) + }), + context, + ) + } + + fn visit_union( + &mut self, + type_idx: u32, + variants: &'a [u32], + context: &'a V::Context, + ) -> Option { + for (i, variant_type) in variants.iter().enumerate() { + let res = self.visit_child( + PathSegment { + from: type_idx, + edge: Edge::UnionVariant(i), + }, + *variant_type, + context, + ); + if let Some(ret) = res { + return Some(ret); + } + } + None + } + + fn visit_either( + &mut self, + type_idx: u32, + variants: &'a [u32], + context: &'a V::Context, + ) -> Option { + variants.iter().enumerate().find_map(|(i, t)| { + self.visit_child( + PathSegment { + from: type_idx, + edge: Edge::EitherVariant(i), + }, + *t, + context, + ) + }) + } + + fn visit_function( + &mut self, + type_idx: u32, + input: u32, + output: u32, + context: &'a V::Context, + ) -> Option { + if self.as_input { + // TODO warning + return None; + } + + let last_path_seg = self.path.last().unwrap(); + match last_path_seg.edge { + Edge::ObjectProp(_) => {} + _ => { + return Some(V::Return::from_error( + Path(&self.path).to_string(), + "Function is only allowed as struct field (direct child)".to_string(), + )); + } + } + + let last_seg = self.path.last().unwrap(); + let fn_key = match &last_seg.edge { + Edge::ObjectProp(k) => k.to_string(), + _ => unreachable!(), // or error? + }; + let struct_idx = last_seg.from; + let old_parent_fn = + std::mem::replace(&mut self.parent_fn, Some(ParentFn { struct_idx, fn_key })); + self.as_input = true; + let res = self.visit_child( + PathSegment { + from: type_idx, + edge: Edge::FunctionInput, + }, + input, + context, + ); + self.as_input = false; + + if let Some(ret) = res { + self.parent_fn = old_parent_fn; + return Some(ret); + } + + let res = self.visit_child( + PathSegment { + from: type_idx, + edge: Edge::FunctionOutput, + }, + output, + context, + ); + self.parent_fn = old_parent_fn; + + res + } + + fn visit_children( + &mut self, + children: impl Iterator, + context: &'a V::Context, + ) -> Option { + self.layer.clone().visit( + self, + children.map(|(seg, idx)| ChildNode(seg, idx)), + context, + ) + } + + fn visit_child( + &mut self, + segment: PathSegment, + type_idx: u32, + context: &'a V::Context, + ) -> Option { + self.path.push(segment); + let res = self.visit_type(type_idx, context); + self.path.pop().unwrap(); + res + } +} + +#[derive(Debug, Clone)] +pub struct PathSegment { + pub from: u32, // typeIdx + pub edge: Edge, +} + +impl Display for PathSegment { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self.edge { + Edge::ObjectProp(name) => write!(f, "{}", name)?, + Edge::ArrayItem => write!(f, "[]")?, + Edge::OptionalItem => write!(f, "*")?, + Edge::FunctionInput => write!(f, "[in]")?, + Edge::FunctionOutput => write!(f, "[out]")?, + Edge::EitherVariant(v) | Edge::UnionVariant(v) => write!(f, "{}", v)?, + } + Ok(()) + } +} + +pub struct Path<'a>(pub &'a [PathSegment]); + +impl<'a> Display for Path<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for segment in self.0.iter() { + write!(f, "/{segment}")?; + } + Ok(()) + } +} + +#[derive(Debug, Clone)] +pub enum Edge { + ObjectProp(String), + ArrayItem, + OptionalItem, + FunctionInput, + FunctionOutput, + EitherVariant(usize), + UnionVariant(usize), +} + +pub enum VisitResult { + Continue(bool), + Return(T), +} + +#[derive(Clone, Copy)] +pub struct CurrentNode<'a> { + pub type_idx: u32, + pub type_node: &'a TypeNode, + pub path: &'a [PathSegment], +} + +pub trait TypeVisitorContext { + fn get_typegraph(&self) -> &Typegraph; +} + +pub trait TypeVisitor<'a> { + type Return: Sized + VisitorResult; + type Context: TypeVisitorContext + Clone; + + /// return true to continue the traversal on the subgraph + fn visit( + &mut self, + current_node: CurrentNode<'_>, + context: &Self::Context, + ) -> VisitResult; + + fn visit_input_type( + &mut self, + current_node: CurrentNode<'_>, + context: &Self::Context, + _parent_fn: ParentFn, + ) -> VisitResult { + self.visit(current_node, context) + } + + fn take_result(&mut self) -> Option + where + Self: Sized, + { + None + } +} + +pub trait VisitorResult { + fn from_error(path: String, message: String) -> Self; +} diff --git a/src/typegraph/schema/src/visitor2.rs b/src/typegraph/schema/src/visitor2.rs new file mode 100644 index 0000000000..33c8e4fc48 --- /dev/null +++ b/src/typegraph/schema/src/visitor2.rs @@ -0,0 +1,253 @@ +// Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. +// SPDX-License-Identifier: MPL-2.0 + +use std::{cell::RefCell, rc::Rc}; + +use crate::{ + visitor::{Edge, PathSegment}, + TypeNode, Typegraph, +}; + +pub struct VisitorContext<'tg> { + pub tg: &'tg Typegraph, + pub current_node: CurrentNode<'tg>, +} + +pub struct NearestFn { + pub path_index: usize, + pub type_idx: u32, + pub is_input: bool, +} + +impl<'a> CurrentNode<'a> { + pub fn nearest_function(&self) -> Option { + for (i, segment) in self.path.borrow().iter().enumerate().rev() { + match segment.edge { + Edge::FunctionInput => { + return Some(NearestFn { + path_index: i, + type_idx: segment.from, + is_input: true, + }) + } + Edge::FunctionOutput => { + return Some(NearestFn { + path_index: i, + type_idx: segment.from, + is_input: false, + }) + } + _ => continue, + } + } + None + } +} + +pub enum VisitNext { + /// continue traversal, with the eventual child nodes + Children, + /// continue traversal, but do not visit the children + Siblings, + Stop, +} + +pub fn traverse_types<'tg, 'path, A, V, E>( + tg: &'tg Typegraph, + root_type_idx: u32, + accumulator: A, + visit_fn: V, +) -> Result +where + V: Fn(VisitorContext<'tg>, &mut A) -> Result, +{ + let path = Rc::new(RefCell::new(Vec::new())); + let output = traverse_types_with_path(tg, root_type_idx, &path, accumulator, &visit_fn)?; + Ok(output.accumulator) +} + +struct TraverseOutput { + accumulator: A, + stop: bool, +} + +type SharedPath = Rc>>; + +#[derive(Debug)] +pub struct CurrentNode<'tg> { + pub type_node: &'tg TypeNode, + pub type_idx: u32, + pub path: SharedPath, + pub in_cycle: bool, +} + +fn traverse_types_with_path<'tg, A, V, E>( + tg: &'tg Typegraph, + type_idx: u32, + path: &Rc>>, + mut accumulator: A, + visit_fn: &V, +) -> Result, E> +where + V: Fn(VisitorContext<'tg>, &mut A) -> Result, +{ + let type_node = &tg.types[type_idx as usize]; + + // visit current + { + let current_node = CurrentNode { + type_node, + type_idx, + path: path.clone(), + in_cycle: path.borrow().iter().any(|seg| seg.from == type_idx), + }; + let cx = VisitorContext { tg, current_node }; + match visit_fn(cx, &mut accumulator)? { + VisitNext::Stop => { + return Ok(TraverseOutput { + accumulator, + stop: true, + }) + } + VisitNext::Siblings => { + return Ok(TraverseOutput { + accumulator, + stop: false, + }) + } + VisitNext::Children => (), + } + } + + let push = { + let path = path.clone(); + move |edge: Edge| { + path.borrow_mut().push(PathSegment { + from: type_idx, + edge, + }); + } + }; + + let pop = { + let path = path.clone(); + move || { + path.borrow_mut().pop(); + } + }; + + // visit children + match type_node { + TypeNode::Boolean { .. } + | TypeNode::Integer { .. } + | TypeNode::Float { .. } + | TypeNode::String { .. } + | TypeNode::File { .. } + | TypeNode::Any { .. } => Ok(TraverseOutput { + accumulator, + stop: false, + }), + + TypeNode::Optional { data, .. } => { + let item_type_idx = data.item; + push(Edge::OptionalItem); + let output = traverse_types_with_path(tg, item_type_idx, path, accumulator, visit_fn)?; + pop(); + Ok(output) + } + + TypeNode::List { data, .. } => { + let item_type_idx = data.items; + push(Edge::ArrayItem); + let output = traverse_types_with_path(tg, item_type_idx, path, accumulator, visit_fn)?; + pop(); + Ok(output) + } + + TypeNode::Object { data, .. } => { + let mut accumulator = Some(accumulator); + for (key, prop_idx) in data.properties.iter() { + push(Edge::ObjectProp(key.clone())); + let output = traverse_types_with_path( + tg, + *prop_idx, + path, + accumulator.take().unwrap(), + visit_fn, + )?; + pop(); + if output.stop { + return Ok(output); + } + accumulator = Some(output.accumulator); + } + Ok(TraverseOutput { + accumulator: accumulator.unwrap(), + stop: false, + }) + } + + TypeNode::Union { data, .. } => { + let mut accumulator = Some(accumulator); + for (v, &item_type_idx) in data.any_of.iter().enumerate() { + push(Edge::UnionVariant(v)); + let output = traverse_types_with_path( + tg, + item_type_idx, + path, + accumulator.take().unwrap(), + visit_fn, + )?; + pop(); + if output.stop { + return Ok(output); + } + accumulator = Some(output.accumulator); + } + Ok(TraverseOutput { + accumulator: accumulator.unwrap(), + stop: false, + }) + } + + TypeNode::Either { data, .. } => { + let mut accumulator = Some(accumulator); + for (v, &item_type_idx) in data.one_of.iter().enumerate() { + push(Edge::EitherVariant(v)); + let output = traverse_types_with_path( + tg, + item_type_idx, + path, + accumulator.take().unwrap(), + visit_fn, + )?; + pop(); + if output.stop { + return Ok(output); + } + accumulator = Some(output.accumulator); + } + Ok(TraverseOutput { + accumulator: accumulator.unwrap(), + stop: false, + }) + } + + TypeNode::Function { data, .. } => { + let input_type_idx = data.input; + push(Edge::FunctionInput); + let output = traverse_types_with_path(tg, input_type_idx, path, accumulator, visit_fn)?; + pop(); + if output.stop { + return Ok(output); + } + + let output_type_idx = data.output; + push(Edge::FunctionOutput); + let output = + traverse_types_with_path(tg, output_type_idx, path, output.accumulator, visit_fn)?; + pop(); + Ok(output) + } + } +} diff --git a/src/utils/archive/Cargo.toml b/src/utils/archive/Cargo.toml new file mode 100644 index 0000000000..4314266791 --- /dev/null +++ b/src/utils/archive/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "archive_utils" +version.workspace = true +edition.workspace = true + +[dependencies] +anyhow.workspace = true +base64.workspace = true +flate2.workspace = true +tar.workspace = true +indexmap.workspace = true +ignore.workspace = true diff --git a/src/common/src/archive.rs b/src/utils/archive/src/lib.rs similarity index 100% rename from src/common/src/archive.rs rename to src/utils/archive/src/lib.rs diff --git a/src/utils/grpc/Cargo.toml b/src/utils/grpc/Cargo.toml new file mode 100644 index 0000000000..b87f6c8ecc --- /dev/null +++ b/src/utils/grpc/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "grpc_utils" +version.workspace = true +edition.workspace = true + +[dependencies] +anyhow.workspace = true +protobuf.workspace = true +proto-parser.workspace = true diff --git a/src/common/src/grpc.rs b/src/utils/grpc/src/lib.rs similarity index 100% rename from src/common/src/grpc.rs rename to src/utils/grpc/src/lib.rs From b21f8ce608d757d460bf9eb066d868c13c085296 Mon Sep 17 00:00:00 2001 From: Natoandro Date: Thu, 6 Feb 2025 15:22:49 +0300 Subject: [PATCH 2/6] wip --- src/common/src/typegraph/mod.rs | 215 ------ .../src/typegraph/parameter_transform.rs | 53 -- src/common/src/typegraph/types.rs | 380 ---------- src/common/src/typegraph/utils.rs | 42 -- src/common/src/typegraph/validator/common.rs | 53 -- .../src/typegraph/validator/injection.rs | 269 ------- src/common/src/typegraph/validator/input.rs | 41 -- src/common/src/typegraph/validator/mod.rs | 277 -------- src/common/src/typegraph/validator/types.rs | 662 ------------------ src/common/src/typegraph/validator/value.rs | 268 ------- src/common/src/typegraph/visitor.rs | 447 ------------ src/common/src/typegraph/visitor2.rs | 253 ------- 12 files changed, 2960 deletions(-) delete mode 100644 src/common/src/typegraph/mod.rs delete mode 100644 src/common/src/typegraph/parameter_transform.rs delete mode 100644 src/common/src/typegraph/types.rs delete mode 100644 src/common/src/typegraph/utils.rs delete mode 100644 src/common/src/typegraph/validator/common.rs delete mode 100644 src/common/src/typegraph/validator/injection.rs delete mode 100644 src/common/src/typegraph/validator/input.rs delete mode 100644 src/common/src/typegraph/validator/mod.rs delete mode 100644 src/common/src/typegraph/validator/types.rs delete mode 100644 src/common/src/typegraph/validator/value.rs delete mode 100644 src/common/src/typegraph/visitor.rs delete mode 100644 src/common/src/typegraph/visitor2.rs diff --git a/src/common/src/typegraph/mod.rs b/src/common/src/typegraph/mod.rs deleted file mode 100644 index f43cc59f13..0000000000 --- a/src/common/src/typegraph/mod.rs +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. -// SPDX-License-Identifier: MPL-2.0 - -pub mod parameter_transform; -pub mod runtimes; -pub mod types; -pub mod utils; -pub mod validator; -pub mod visitor; -pub mod visitor2; - -pub use types::*; - -use std::collections::BTreeMap; -use std::hash::Hash; -use std::path::{Path, PathBuf}; -use std::sync::Arc; - -use anyhow::{bail, Result}; -use indexmap::IndexMap; -use serde::{Deserialize, Serialize}; -use serde_json::Value; -use serde_with::skip_serializing_none; - -use self::runtimes::Artifact; -use self::runtimes::TGRuntime; - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct Typegraph { - pub types: Vec, - pub materializers: Vec, - pub runtimes: Vec, - pub policies: Vec, - pub meta: TypeMeta, - - // TODO: factor out non-essential fields into a separate struct - #[serde(skip)] - pub path: Option>, - #[serde(skip)] - pub deps: Vec, -} - -#[derive(Serialize, Deserialize, Clone, Debug, Default)] -pub struct Cors { - pub allow_origin: Vec, - pub allow_headers: Vec, - pub expose_headers: Vec, - #[serde(default)] - pub allow_methods: Vec, - pub allow_credentials: bool, - pub max_age_sec: Option, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(rename_all = "lowercase")] -pub enum AuthProtocol { - OAuth2, - Jwt, - Basic, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct Auth { - pub name: String, - pub protocol: AuthProtocol, - pub auth_data: IndexMap, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct Rate { - pub window_limit: u32, - pub window_sec: u32, - pub query_limit: u32, - pub context_identifier: Option, - pub local_excess: u32, -} - -// TODO: remove default, as they should all be explicity set in the core SDK -#[derive(Serialize, Deserialize, Clone, Debug, Default)] -pub struct Queries { - pub dynamic: bool, - pub endpoints: Vec, -} - -#[derive(Serialize, Deserialize, Clone, Debug, Default)] -#[serde(rename_all = "camelCase")] -pub struct TypeMeta { - pub prefix: Option, - pub secrets: Vec, - #[serde(skip_serializing_if = "Vec::is_empty")] - #[serde(default)] - pub outjection_secrets: Vec, - pub queries: Queries, - pub cors: Cors, - pub auths: Vec, - pub rate: Option, - pub version: String, - pub random_seed: Option, - pub artifacts: BTreeMap, - #[serde(skip_serializing_if = "Vec::is_empty")] - #[serde(default)] - pub namespaces: Vec, -} - -#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[serde(rename_all = "lowercase")] -pub enum EffectType { - Create, - Update, - Delete, - Read, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct Effect { - pub effect: Option, - pub idempotent: bool, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct Materializer { - pub name: String, - pub runtime: u32, - pub effect: Effect, - pub data: IndexMap, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct Policy { - pub name: String, - pub materializer: u32, -} - -#[skip_serializing_none] -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct PolicyIndicesByEffect { - pub read: Option, - pub create: Option, - pub delete: Option, - pub update: Option, -} - -#[skip_serializing_none] -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(untagged)] -pub enum PolicyIndices { - Policy(u32), - EffectPolicies(PolicyIndicesByEffect), -} - -impl Typegraph { - pub fn name(&self) -> Result { - match &self.types[0] { - TypeNode::Object { base, .. } => Ok(base.title.clone()), - _ => bail!("invalid variant for root type"), - } - } - - pub fn full_name(&self) -> Result { - Ok(format!( - "{}{}", - self.meta.prefix.as_deref().unwrap_or(""), - self.name()? - )) - } - - pub fn with_prefix(&self, prefix: String) -> Result { - let mut tg = self.clone(); - tg.meta.prefix = Some(prefix); - Ok(tg) - } - - pub fn get_key(&self) -> Result { - let path = self.get_path()?; - Ok(format!("{}#{}", path, self.name()?)) - } - - pub fn get_path(&self) -> Result { - let path = self - .path - .as_ref() - .ok_or_else(|| anyhow::anyhow!("typegraph path not set, cannot get id"))? - .to_str() - .ok_or_else(|| anyhow::anyhow!("typegraph path is not valid unicode"))? - .to_owned(); - Ok(path) - } - - pub fn root(&self) -> Result<(&TypeNodeBase, &ObjectTypeData)> { - if self.types.is_empty() { - bail!("typegraph is empty: no nodes found"); - } - let root = &self.types[0]; - match root { - TypeNode::Object { base, data } => Ok((base, data)), - _ => bail!("typegraph is invalid: root node is not object"), - } - } - - pub fn resolve_quant(&self, type_idx: TypeId) -> TypeId { - let mut type_idx = type_idx; - loop { - match &self.types[type_idx as usize] { - TypeNode::Optional { data, .. } => { - type_idx = data.item; - } - TypeNode::List { data, .. } => { - type_idx = data.items; - } - _ => break, - } - } - type_idx - } -} diff --git a/src/common/src/typegraph/parameter_transform.rs b/src/common/src/typegraph/parameter_transform.rs deleted file mode 100644 index 045836319c..0000000000 --- a/src/common/src/typegraph/parameter_transform.rs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. -// SPDX-License-Identifier: MPL-2.0 - -use std::collections::HashMap; - -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(tag = "source", rename_all = "lowercase")] -pub enum ParameterTransformLeafNode { - #[serde(rename_all = "camelCase")] - Arg { name: String }, - #[serde(rename_all = "camelCase")] - Static { value_json: String }, - #[serde(rename_all = "camelCase")] - Secret { key: String }, - #[serde(rename_all = "camelCase")] - Context { key: String }, - #[serde(rename_all = "camelCase")] - Parent { parent_idx: u32 }, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(tag = "type", rename_all = "lowercase")] -pub enum ParameterTransformParentNode { - #[serde(rename_all = "camelCase")] - Object { - fields: HashMap, - }, - #[serde(rename_all = "camelCase")] - Array { items: Vec }, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(untagged)] -pub enum ParameterTransformNodeData { - Leaf(ParameterTransformLeafNode), - Parent(ParameterTransformParentNode), -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(rename_all = "camelCase")] -pub struct ParameterTransformNode { - pub type_idx: u32, - // #[serde(flatten)] - pub data: ParameterTransformNodeData, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct FunctionParameterTransform { - pub resolver_input: u32, - pub transform_root: ParameterTransformNode, -} diff --git a/src/common/src/typegraph/types.rs b/src/common/src/typegraph/types.rs deleted file mode 100644 index 1cd144886d..0000000000 --- a/src/common/src/typegraph/types.rs +++ /dev/null @@ -1,380 +0,0 @@ -// Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. -// SPDX-License-Identifier: MPL-2.0 - -use std::collections::BTreeMap; - -use anyhow::Result; -use indexmap::IndexMap; -use serde::{Deserialize, Serialize}; -use serde_with::skip_serializing_none; -use std::hash::Hash; - -use super::{parameter_transform::FunctionParameterTransform, EffectType, PolicyIndices}; - -// TODO: consider exploring interning -pub type TypeName = String; -pub type TypeId = u32; - -type JsonValue = serde_json::Value; - -#[derive(Serialize, Deserialize, Clone, Debug, Hash)] -pub struct SingleValue { - pub value: JsonValue, -} - -#[derive(Serialize, Deserialize, Clone, Debug, Hash)] -#[serde(untagged)] -pub enum InjectionData { - SingleValue(SingleValue), - ValueByEffect(BTreeMap), -} - -impl InjectionData { - pub fn values(&self) -> Result> { - match self { - InjectionData::SingleValue(v) => Ok(vec![serde_json::from_value(v.value.clone())?]), - InjectionData::ValueByEffect(m) => m - .values() - .map(|v| serde_json::from_value(v.clone()).map_err(Into::into)) - .collect(), - } - } - - pub fn values_mut(&mut self) -> Vec<&mut JsonValue> { - match self { - InjectionData::SingleValue(v) => vec![&mut v.value], - InjectionData::ValueByEffect(m) => m.values_mut().collect(), - } - } -} - -#[derive(Serialize, Deserialize, Clone, Debug, Hash)] -#[serde(tag = "source", content = "data", rename_all = "lowercase")] -pub enum Injection { - Static(InjectionData), - Context(InjectionData), - Secret(InjectionData), - Parent(InjectionData), - Dynamic(InjectionData), - Random(InjectionData), -} - -#[skip_serializing_none] -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct TypeNodeBase { - pub title: String, - #[serde(default)] - pub description: Option, - #[serde(default, rename = "enum")] - pub enumeration: Option>, // JSON-serialized values -} - -#[skip_serializing_none] -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct OptionalTypeData { - pub item: Id, - #[serialize_always] - pub default_value: Option, -} - -#[skip_serializing_none] -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(rename_all = "camelCase")] -pub struct FloatTypeData { - pub minimum: Option, - pub maximum: Option, - pub exclusive_minimum: Option, - pub exclusive_maximum: Option, - pub multiple_of: Option, -} - -#[skip_serializing_none] -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(rename_all = "camelCase")] -pub struct IntegerTypeData { - // we use i32 as GraphQL spec only support 32-bit integers (Int) - pub minimum: Option, - pub maximum: Option, - pub exclusive_minimum: Option, - pub exclusive_maximum: Option, - pub multiple_of: Option, -} - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] -#[serde(rename_all = "kebab-case")] -pub enum StringFormat { - Uuid, - Email, - Uri, - Json, - Hostname, - Ean, - Date, - DateTime, - Phone, -} - -impl core::fmt::Display for StringFormat { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - use StringFormat::*; - match self { - Uuid => write!(f, "uuid"), - Email => write!(f, "email"), - Uri => write!(f, "uri"), - Json => write!(f, "json"), - Hostname => write!(f, "hostname"), - Ean => write!(f, "ean"), - Date => write!(f, "date"), - DateTime => write!(f, "date_time"), - Phone => write!(f, "phone"), - } - } -} - -#[skip_serializing_none] -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(rename_all = "camelCase")] -pub struct StringTypeData { - pub min_length: Option, - pub max_length: Option, - pub pattern: Option, - pub format: Option, -} - -#[skip_serializing_none] -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(rename_all = "camelCase")] -pub struct FileTypeData { - pub min_size: Option, - pub max_size: Option, - pub mime_types: Option>, -} - -#[skip_serializing_none] -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct ObjectTypeData { - pub properties: IndexMap, - pub id: Vec, - #[serde(default)] - pub required: Vec, - #[serde(skip_serializing_if = "IndexMap::is_empty")] - #[serde(default)] - pub policies: IndexMap>, -} - -#[skip_serializing_none] -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(rename_all = "camelCase")] -pub struct ListTypeData { - pub items: Id, - pub max_items: Option, - pub min_items: Option, - pub unique_items: Option, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(untagged)] -pub enum InjectionNode { - Parent { - children: IndexMap, - }, - Leaf { - injection: Injection, - }, -} - -impl InjectionNode { - pub fn collect_secrets_into(&self, collector: &mut Vec) -> Result<()> { - match self { - InjectionNode::Leaf { injection } => { - if let Injection::Secret(d) = injection { - collector.extend(d.values::()?); - } - } - InjectionNode::Parent { children } => { - for child in children.values() { - child.collect_secrets_into(collector)?; - } - } - } - Ok(()) - } -} - -#[skip_serializing_none] -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct FunctionTypeData { - pub input: Id, - #[serde(rename = "parameterTransform")] - pub parameter_transform: Option, - pub output: Id, - #[serde(skip_serializing_if = "IndexMap::is_empty")] - #[serde(default)] - pub injections: IndexMap, - #[serde(skip_serializing_if = "IndexMap::is_empty")] - #[serde(default)] - pub outjections: IndexMap, - #[serde(rename = "runtimeConfig")] - pub runtime_config: serde_json::Value, - pub materializer: u32, - #[serialize_always] - pub rate_weight: Option, - pub rate_calls: bool, -} - -#[skip_serializing_none] -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(rename_all = "camelCase")] -pub struct UnionTypeData { - /// Array of indexes of the nodes that are used as subschemes in the - /// anyOf field of JSON Schema. - pub any_of: Vec, -} - -#[skip_serializing_none] -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(rename_all = "camelCase")] -pub struct EitherTypeData { - /// Array of indexes of the nodes that are used as subschemes in the - /// oneOf field of JSON Schema. - pub one_of: Vec, -} - -#[skip_serializing_none] -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(tag = "type", rename_all = "lowercase")] -pub enum TypeNode { - Optional { - #[serde(flatten)] - base: TypeNodeBase, - #[serde(flatten)] - data: OptionalTypeData, - }, - Boolean { - #[serde(flatten)] - base: TypeNodeBase, - }, - Float { - #[serde(flatten)] - base: TypeNodeBase, - #[serde(flatten)] - data: FloatTypeData, - }, - Integer { - #[serde(flatten)] - base: TypeNodeBase, - #[serde(flatten)] - data: IntegerTypeData, - }, - String { - #[serde(flatten)] - base: TypeNodeBase, - #[serde(flatten)] - data: StringTypeData, - }, - File { - #[serde(flatten)] - base: TypeNodeBase, - #[serde(flatten)] - data: FileTypeData, - }, - Object { - #[serde(flatten)] - base: TypeNodeBase, - #[serde(flatten)] - data: ObjectTypeData, - }, - List { - #[serde(flatten)] - base: TypeNodeBase, - #[serde(flatten)] - data: ListTypeData, - }, - Function { - #[serde(flatten)] - base: TypeNodeBase, - #[serde(flatten)] - data: FunctionTypeData, - }, - Union { - #[serde(flatten)] - base: TypeNodeBase, - #[serde(flatten)] - data: UnionTypeData, - }, - #[serde(rename_all = "camelCase")] - Either { - #[serde(flatten)] - base: TypeNodeBase, - #[serde(flatten)] - data: EitherTypeData, - }, - Any { - #[serde(flatten)] - base: TypeNodeBase, - }, -} - -impl TypeNode { - pub fn base(&self) -> &TypeNodeBase { - use TypeNode::*; - match self { - Optional { base, .. } - | Boolean { base, .. } - | Float { base, .. } - | Integer { base, .. } - | String { base, .. } - | File { base, .. } - | Object { base, .. } - | List { base, .. } - | Function { base, .. } - | Union { base, .. } - | Either { base, .. } - | Any { base, .. } => base, - } - } - - pub fn base_mut(&mut self) -> &mut TypeNodeBase { - use TypeNode::*; - match self { - Optional { base, .. } - | Boolean { base, .. } - | Float { base, .. } - | Integer { base, .. } - | String { base, .. } - | File { base, .. } - | Object { base, .. } - | List { base, .. } - | Function { base, .. } - | Union { base, .. } - | Either { base, .. } - | Any { base, .. } => base, - } - } - - pub fn type_name(&self) -> &'static str { - use TypeNode::*; - match self { - Optional { .. } => "optional", - Boolean { .. } => "boolean", - Float { .. } => "float", - Integer { .. } => "integer", - String { .. } => "string", - File { .. } => "file", - Object { .. } => "object", - List { .. } => "list", - Function { .. } => "function", - Union { .. } => "union", - Either { .. } => "either", - Any { .. } => "any", - } - } - - pub fn is_scalar(&self) -> bool { - use TypeNode::*; - matches!( - self, - Boolean { .. } | Float { .. } | Integer { .. } | String { .. } - ) - } -} diff --git a/src/common/src/typegraph/utils.rs b/src/common/src/typegraph/utils.rs deleted file mode 100644 index 73d5a6c2a3..0000000000 --- a/src/common/src/typegraph/utils.rs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. -// SPDX-License-Identifier: MPL-2.0 - -use crate::typegraph::{runtimes::TGRuntime, Typegraph}; -use anyhow::{bail, Result}; -use indexmap::IndexMap; -use serde::{de::DeserializeOwned, ser::Serialize}; -use serde_json::{from_value, to_value, Value}; - -pub fn object_from_map(map: IndexMap) -> Result { - let map = Value::Object(map.into_iter().collect()); - Ok(from_value(map)?) -} - -pub fn map_from_object(obj: T) -> Result> { - let val = to_value(obj)?; - if let Value::Object(map) = val { - Ok(map.into_iter().collect()) - } else { - bail!("value is not an object"); - } -} - -pub fn find_runtimes(typegraph: &Typegraph, predicate: impl Fn(&TGRuntime) -> bool) -> Vec { - typegraph - .runtimes - .iter() - .enumerate() - .filter(|(_, rt)| predicate(rt)) - .map(|(idx, _)| idx) - .collect() -} - -pub fn get_materializers(typegraph: &Typegraph, rt_idx: u32) -> Vec { - typegraph - .materializers - .iter() - .enumerate() - .filter(|(_, mat)| mat.runtime == rt_idx) - .map(|(idx, _)| idx) - .collect() -} diff --git a/src/common/src/typegraph/validator/common.rs b/src/common/src/typegraph/validator/common.rs deleted file mode 100644 index e499478878..0000000000 --- a/src/common/src/typegraph/validator/common.rs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. -// SPDX-License-Identifier: MPL-2.0 - -use crate::typegraph::{EitherTypeData, TypeNode, Typegraph, UnionTypeData}; - -impl Typegraph { - pub fn check_enum_values( - &self, - type_idx: u32, - enum_values: &[String], - ) -> Result<(), Vec> { - let type_node = self.types.get(type_idx as usize).unwrap(); - let mut errors = Vec::new(); - if matches!(type_node, TypeNode::Optional { .. }) { - errors.push("optional not cannot have enumerated values".to_owned()); - } else { - for value in enum_values { - match serde_json::from_str::(value) { - Ok(val) => match self.validate_value(type_idx, &val) { - Ok(_) => {} - Err(err) => errors.push(err.to_string()), - }, - Err(e) => errors.push(format!( - "Error while deserializing enum value {value:?}: {e:?}" - )), - } - } - } - - if errors.is_empty() { - Ok(()) - } else { - Err(errors) - } - } - - pub fn collect_nested_variants_into(&self, out: &mut Vec, variants: &[u32]) { - for idx in variants { - let node = self.types.get(*idx as usize).unwrap(); - match node { - TypeNode::Union { - data: UnionTypeData { any_of: variants }, - .. - } - | TypeNode::Either { - data: EitherTypeData { one_of: variants }, - .. - } => self.collect_nested_variants_into(out, variants), - _ => out.push(*idx), - } - } - } -} diff --git a/src/common/src/typegraph/validator/injection.rs b/src/common/src/typegraph/validator/injection.rs deleted file mode 100644 index 09bd9cf381..0000000000 --- a/src/common/src/typegraph/validator/injection.rs +++ /dev/null @@ -1,269 +0,0 @@ -// Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. -// SPDX-License-Identifier: MPL-2.0 - -use indexmap::IndexMap; -use serde_json::Value; - -use super::types::{EnsureSubtypeOf as _, ErrorCollector, ExtendedTypeNode}; -use super::{Validator, ValidatorContext}; -use crate::typegraph::visitor::{Edge, PathSegment, TypeVisitorContext as _}; -use crate::typegraph::{Injection, InjectionNode, ObjectTypeData, TypeId, TypeNode}; - -pub struct InjectionValidationContext<'a> { - pub fn_path: Vec, - pub fn_idx: TypeId, - pub input_idx: TypeId, - pub parent_object: &'a ObjectTypeData, - pub validator: &'a ValidatorContext<'a>, -} - -impl<'a> InjectionValidationContext<'a> { - fn get_path(&self, path: &[String]) -> Vec { - let mut res = self.fn_path.clone(); - res.push(PathSegment { - from: self.fn_idx, - edge: Edge::FunctionInput, - }); - res.push(PathSegment { - from: self.input_idx, - edge: Edge::ObjectProp(path.join(".")), - }); - res - } -} - -enum UnionKind { - Union, - Either, -} - -impl Validator { - pub fn validate_injection( - &mut self, - path: &mut Vec, - type_idx: TypeId, - injection_node: &InjectionNode, - cx: &InjectionValidationContext<'_>, - ) { - let tg = cx.validator.get_typegraph(); - match injection_node { - InjectionNode::Leaf { injection } => match injection { - Injection::Static(data) => { - for value in data.values::().unwrap().iter() { - match serde_json::from_str::(value) { - Ok(val) => match tg.validate_value(type_idx, &val) { - Ok(_) => {} - Err(err) => self.push_error(&cx.get_path(path), err.to_string()), - }, - Err(e) => { - self.push_error( - &cx.get_path(path), - format!( - "Error while parsing static injection value {value:?}: {e:?}", - value = value - ), - ); - } - } - } - } - Injection::Parent(data) => { - let sources = data.values::().unwrap(); - for source_key in sources.iter() { - self.validate_parent_injection(source_key, type_idx, path, cx); - } - } - _ => (), - }, - InjectionNode::Parent { children } => { - let type_idx = tg.resolve_quant(type_idx); - let type_node = &cx.validator.get_typegraph().types[type_idx as usize]; - match type_node { - TypeNode::Object { data, .. } => { - for (key, node) in children.iter() { - path.push(key.clone()); - match data.properties.get(key) { - Some(type_idx) => { - self.validate_injection(path, *type_idx, node, cx); - } - None => { - self.push_error( - &cx.get_path(path), - format!( - "unexpected injection path prefix: {:?}, available properties are: {:?}", - path.join("."), data.properties.keys().collect::>() - ), - ); - } - } - path.pop(); - } - } - TypeNode::Union { data, .. } => { - self.validate_union( - type_node, - &data.any_of, - children, - path, - cx, - UnionKind::Union, - ); - } - TypeNode::Either { data, .. } => { - self.validate_union( - type_node, - &data.one_of, - children, - path, - cx, - UnionKind::Either, - ); - } - _ => { - self.push_error( - &cx.get_path(path), - format!("expected object type, found: {:?}", type_node), - ); - self.push_error( - &cx.get_path(path), - format!("unexpected injection path prefix: {:?}", path.join(".")), - ); - } - } - } - } - } - - fn validate_parent_injection( - &mut self, - source_key: &str, - in_type_idx: TypeId, - in_path: &[String], - cx: &InjectionValidationContext<'_>, - ) { - let tg = cx.validator.get_typegraph(); - let source_idx = { - let source_idx = cx.parent_object.properties.get(source_key); - match source_idx { - Some(idx) => *idx, - None => { - let keys = cx.parent_object.properties.keys().collect::>(); - self.push_error( - &cx.get_path(in_path), - format!( - "from_parent injection: source key {source_key} not found in parent; available keys: {keys:?}", - source_key = source_key - ), - ); - return; - } - } - }; - - let source = ExtendedTypeNode::new(tg, source_idx); - let target = ExtendedTypeNode::new(tg, in_type_idx); - let mut errors = ErrorCollector::default(); - source.ensure_subtype_of(&target, tg, &mut errors); - for error in errors.errors.into_iter() { - self.push_error( - &cx.get_path(in_path), - format!("from_parent injection: {error}", error = error), - ); - } - } - - fn validate_union( - &mut self, - type_node: &TypeNode, - variants: &[TypeId], - children: &IndexMap, - path: &mut Vec, - cx: &InjectionValidationContext<'_>, - union_kind: UnionKind, - ) { - let eligible_variants = variants - .iter() - .cloned() - .filter_map(|type_idx| { - let type_node = &cx.validator.get_typegraph().types[type_idx as usize]; - match type_node { - TypeNode::Object { data, .. } => children - .keys() - .all(|key| data.properties.contains_key(key)) - .then_some(data), - _ => None, - } - }) - .collect::>(); - if eligible_variants.is_empty() { - self.push_error( - &cx.get_path(path), - format!("expected object type, found: {:?}", type_node), - ); - self.push_error( - &cx.get_path(path), - format!("unexpected injection path prefix: {:?}", path.join(".")), - ); - } - - let mut match_count = 0; - - for type_data in eligible_variants { - let mut validator = Validator::default(); - for (key, node) in children.iter() { - path.push(key.clone()); - match type_data.properties.get(key) { - Some(type_idx) => { - validator.validate_injection(path, *type_idx, node, cx); - } - None => { - unreachable!(); - } - } - path.pop(); - } - if validator.errors.is_empty() { - match union_kind { - UnionKind::Union => { - return; - } - UnionKind::Either => { - match_count += 1; - } - } - } - } - match union_kind { - UnionKind::Union => { - self.push_error( - &cx.get_path(path), - format!( - "no variant of the union type matches the injection path prefix: {:?}", - path.join(".") - ), - ); - } - UnionKind::Either => match match_count { - 0 => { - self.push_error( - &cx.get_path(path), - format!( - "no variant of the union type matches the injection path prefix: {:?}", - path.join(".") - ), - ); - } - 1 => {} - _ => { - self.push_error( - &cx.get_path(path), - format!( - "multiple variants of the union type match the injection path prefix: {:?}", - path.join(".") - ), - ); - } - }, - } - } -} diff --git a/src/common/src/typegraph/validator/input.rs b/src/common/src/typegraph/validator/input.rs deleted file mode 100644 index eac871462b..0000000000 --- a/src/common/src/typegraph/validator/input.rs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. -// SPDX-License-Identifier: MPL-2.0 - -use crate::typegraph::{ - visitor::{CurrentNode, TypeVisitor, VisitResult}, - TypeNode, -}; - -use super::{TypeVisitorContext, Validator}; - -impl Validator { - pub fn visit_input_type_impl( - &mut self, - current_node: CurrentNode<'_>, - context: &::Context, - ) -> VisitResult<::Return> { - let type_node = current_node.type_node; - - if let TypeNode::Function { .. } = type_node { - // TODO suggest to use composition-- when available - self.push_error(current_node.path, "Function is not allowed in input types."); - return VisitResult::Continue(false); - } - - if let Some(enumeration) = &type_node.base().enumeration { - match context - .get_typegraph() - .check_enum_values(current_node.type_idx, enumeration) - { - Ok(_) => {} - Err(err) => { - for e in err { - self.push_error(current_node.path, e); - } - } - } - } - - VisitResult::Continue(true) - } -} diff --git a/src/common/src/typegraph/validator/mod.rs b/src/common/src/typegraph/validator/mod.rs deleted file mode 100644 index 217ad6a925..0000000000 --- a/src/common/src/typegraph/validator/mod.rs +++ /dev/null @@ -1,277 +0,0 @@ -// Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. -// SPDX-License-Identifier: MPL-2.0 - -mod common; -mod injection; -mod input; -mod types; -mod value; - -use self::injection::InjectionValidationContext; - -use super::visitor::{ - visit_child, ChildNode, CurrentNode, ParentFn, Path, PathSegment, TypeVisitor, - TypeVisitorContext, VisitLayer, VisitResult, VisitorResult, -}; -use crate::typegraph::{TypeNode, Typegraph}; -use std::collections::{hash_map, HashMap}; - -use self::types::{EnsureSubtypeOf, ErrorCollector, ExtendedTypeNode}; - -#[allow(dead_code)] -fn assert_unique_titles(types: &[TypeNode]) -> Vec { - let mut duplicates = vec![]; - let mut map: HashMap = HashMap::new(); - for (i, t) in types.iter().enumerate() { - let entry = map.entry(t.base().title.clone()); - match entry { - hash_map::Entry::Occupied(o) => { - duplicates.push((t.base().title.clone(), *o.get(), i)); - } - hash_map::Entry::Vacant(v) => { - v.insert(i); - } - } - } - duplicates - .into_iter() - .map(|(title, i, j)| ValidatorError { - path: "".to_owned(), - message: format!("Duplicate title '{}' in types #{} and #{}", title, i, j), - }) - .collect() -} - -pub fn validate_typegraph(tg: &Typegraph) -> Vec { - let mut errors = vec![]; - // FIXME temporarily disabled, will be re-enabled after all changes on the - // typegraph are merged - // errors.extend(assert_unique_titles(&tg.types)); - let context = ValidatorContext { typegraph: tg }; - let validator = Validator::default(); - - errors.extend(tg.traverse_types(validator, &context, Layer, 0).unwrap()); - errors -} - -#[derive(Debug)] -pub struct ValidatorError { - pub path: String, - pub message: String, -} - -#[derive(Debug, Clone)] -pub struct ValidatorContext<'a> { - typegraph: &'a Typegraph, -} - -#[derive(Debug, Default)] -struct Validator { - errors: Vec, -} - -#[derive(Clone)] -struct Layer; - -impl<'a> VisitLayer<'a, Validator> for Layer { - fn visit( - &self, - traversal: &mut super::visitor::TypegraphTraversal<'a, Validator, Self>, - source: impl Iterator, - context: &'a ValidatorContext<'a>, - ) -> Option<::Return> { - let mut errors = vec![]; - for ChildNode(path_seg, idx) in source { - if let Some(err) = visit_child(traversal, path_seg, idx, context) { - errors.extend(err); - } - } - if errors.is_empty() { - None - } else { - Some(errors) - } - } -} - -impl Validator { - fn push_error(&mut self, path: &[PathSegment], message: impl Into) { - self.errors.push(ValidatorError { - path: Path(path).to_string(), - message: message.into(), - }); - } -} - -impl VisitorResult for Vec { - fn from_error(path: String, message: String) -> Self { - vec![ValidatorError { path, message }] - } -} - -impl<'a> TypeVisitorContext for ValidatorContext<'a> { - fn get_typegraph(&self) -> &Typegraph { - self.typegraph - } -} - -impl<'a> TypeVisitor<'a> for Validator { - type Return = Vec; - type Context = ValidatorContext<'a>; - - fn visit( - &mut self, - current_node: CurrentNode<'_>, - context: &Self::Context, - ) -> VisitResult { - let type_node = current_node.type_node; - - let tg = context.get_typegraph(); - - let get_type_name = |idx: u32| tg.types.get(idx as usize).unwrap().type_name(); - - if let TypeNode::Function { data, .. } = type_node { - let parent_idx = current_node.path.last().unwrap().from; - let parent_object = match &context.get_typegraph().types[parent_idx as usize] { - TypeNode::Object { data, .. } => data, - _ => { - self.push_error( - current_node.path, - "function parent is not an object".to_owned(), - ); - return VisitResult::Continue(false); - } - }; - let mut path = vec![]; - let inj_cx = InjectionValidationContext { - fn_path: current_node.path.to_vec(), - fn_idx: current_node.type_idx, - input_idx: data.input, - parent_object, - validator: context, - }; - let input_object = match &context.get_typegraph().types[data.input as usize] { - TypeNode::Object { data, .. } => data, - _ => { - self.push_error( - current_node.path, - "function input is not an object".to_owned(), - ); - return VisitResult::Continue(false); - } - }; - for (k, inj) in data.injections.iter() { - path.push(k.clone()); - self.validate_injection( - &mut path, - *input_object.properties.get(k).unwrap(), - inj, - &inj_cx, - ); - path.pop(); - } - // TODO validate outjection - // if !data.outjections.is_empty() { - // let outj_cx = InjectionValidationContext { - // fn_path: current_node.path.to_vec(), - // fn_idx: current_node.type_idx, - // input_idx: data.output, - // parent_object, - // validator: context, - // }; - // for (k, outj) in data.outjections.iter() { - // path.push(k.clone()); - // self.validate_injection( - // &mut path, - // *parent_object.properties.get(k).unwrap(), - // outj, - // &outj_cx, - // ); - // path.pop(); - // } - // } - } else if let TypeNode::Either { data, .. } = type_node { - let variants = data.one_of.clone(); - for i in 0..variants.len() { - for j in (i + 1)..variants.len() { - let type1 = ExtendedTypeNode::new(tg, variants[i]); - let type2 = ExtendedTypeNode::new(tg, variants[j]); - - let mut subtype_errors = ErrorCollector::default(); - type1.ensure_subtype_of(&type2, tg, &mut subtype_errors); - - if subtype_errors.errors.is_empty() { - self.push_error( - current_node.path, - format!( - "Invalid either type: variant #{i} ('{}') is a subtype of variant #{j} ('{}')", - get_type_name(variants[i]), - get_type_name(variants[j]), - ), - ); - } - - let mut subtype_errors = ErrorCollector::default(); - type2.ensure_subtype_of(&type1, tg, &mut subtype_errors); - - if subtype_errors.errors.is_empty() { - self.push_error( - current_node.path, - format!( - "Invalid either type: variant #{j} ('{}') is a subtype of variant #{i} ('{}')", - get_type_name(variants[j]), - get_type_name(variants[i]), - ), - ); - } - } - } - } else if let TypeNode::Union { data, .. } = type_node { - let variants = data.any_of.clone(); - - for i in 0..variants.len() { - for j in (i + 1)..variants.len() { - if variants[i] == variants[j] { - self.push_error( - current_node.path, - format!( - "Invalid union type: variant #{i} ('{}') is the same type as variant #{j} ('{}')", - get_type_name(variants[i]), - get_type_name(variants[j]), - ), - ); - } - } - } - } - - if let Some(enumeration) = &type_node.base().enumeration { - match context - .get_typegraph() - .check_enum_values(current_node.type_idx, enumeration) - { - Ok(_) => {} - Err(err) => { - for e in err { - self.push_error(current_node.path, e); - } - } - } - } - - VisitResult::Continue(true) - } - - fn visit_input_type( - &mut self, - current_node: CurrentNode<'_>, - context: &Self::Context, - _parent_fn: ParentFn, - ) -> VisitResult { - self.visit_input_type_impl(current_node, context) - } - - fn take_result(&mut self) -> Option { - Some(std::mem::take(&mut self.errors)) - } -} diff --git a/src/common/src/typegraph/validator/types.rs b/src/common/src/typegraph/validator/types.rs deleted file mode 100644 index 9d1a62b909..0000000000 --- a/src/common/src/typegraph/validator/types.rs +++ /dev/null @@ -1,662 +0,0 @@ -// Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. -// SPDX-License-Identifier: MPL-2.0 - -use crate::typegraph::{ - EitherTypeData, FileTypeData, FloatTypeData, IntegerTypeData, ListTypeData, ObjectTypeData, - StringTypeData, TypeNode, Typegraph, UnionTypeData, -}; -use std::{collections::HashSet, fmt::Display}; - -pub struct ExtendedTypeNode<'a>(u32, &'a TypeNode); - -impl<'a> ExtendedTypeNode<'a> { - pub fn new(typegraph: &'a Typegraph, idx: u32) -> Self { - ExtendedTypeNode(idx, typegraph.types.get(idx as usize).unwrap()) - } -} - -#[derive(Debug, Default)] -pub struct ErrorCollector { - pub errors: Vec, -} - -impl ErrorCollector { - fn push(&mut self, message: impl Into) { - self.errors.push(message.into()); - } - - fn push_nested(&mut self, title: impl Display, nested: Self) { - self.errors.push(format!(" - {title}")); - for error in nested.errors { - self.errors.push(format!(" - - {error}")); - } - } -} - -pub trait EnsureSubtypeOf { - fn ensure_subtype_of(&self, sup: &T, typegraph: &Typegraph, errors: &mut ErrorCollector); -} - -fn ensure_subtype_of_for_min( - left: Option, - right: Option, - key: &str, - errors: &mut ErrorCollector, -) where - T: Display + PartialOrd, -{ - match (left, right) { - (Some(left), Some(right)) => { - if left < right { - errors.push(format!( - "'{key}' cannot be lower on the subtype: {} < {}", - left, right - )); - } - } - (None, Some(_)) => { - errors.push(format!( - "'{key}' is required on the subtype if it is defined on the supertype" - )); - } - _ => {} - } -} - -fn ensure_subtype_of_for_max( - left: Option, - right: Option, - key: &str, - errors: &mut ErrorCollector, -) where - T: Display + PartialOrd, -{ - match (left, right) { - (Some(left), Some(right)) => { - if left > right { - errors.push(format!( - "'{key}' cannot be higher on the subtype: {} > {}", - left, right - )); - } - } - (None, Some(_)) => { - errors.push(format!( - "'{key}' is required on the subtype if it is defined on the supertype" - )); - } - _ => {} - } -} - -fn ensure_subtype_of_for_multiple_of( - left: Option, - right: Option, - key: &str, - errors: &mut ErrorCollector, -) where - T: Display + std::ops::Rem + Copy + Default + PartialEq, -{ - match (left, right) { - (Some(left), Some(right)) => { - if left % right != Default::default() { - errors.push(format!( - "'{key}' is not a multiple of the '{key}' of the supertype ({} % {} != 0)", - left, right - )); - } - } - (None, Some(_)) => { - errors.push(format!( - "'{key}' is required on the subtype if it is defined on the supertype" - )); - } - _ => {} - } -} - -impl EnsureSubtypeOf for IntegerTypeData { - fn ensure_subtype_of(&self, other: &Self, _tg: &Typegraph, errors: &mut ErrorCollector) { - ensure_subtype_of_for_min(self.minimum, other.minimum, "minimum", errors); - ensure_subtype_of_for_max(self.maximum, other.maximum, "maximum", errors); - ensure_subtype_of_for_min( - self.exclusive_minimum, - other.exclusive_minimum, - "exclusive_minimum", - errors, - ); - ensure_subtype_of_for_max( - self.exclusive_maximum, - other.exclusive_maximum, - "exclusive_maximum", - errors, - ); - ensure_subtype_of_for_multiple_of( - self.multiple_of, - other.multiple_of, - "multiple_of", - errors, - ); - } -} - -impl EnsureSubtypeOf for FloatTypeData { - fn ensure_subtype_of(&self, other: &Self, _tg: &Typegraph, errors: &mut ErrorCollector) { - ensure_subtype_of_for_min(self.minimum, other.minimum, "minimum", errors); - ensure_subtype_of_for_max(self.maximum, other.maximum, "maximum", errors); - ensure_subtype_of_for_min( - self.exclusive_minimum, - other.exclusive_minimum, - "exclusive_minimum", - errors, - ); - ensure_subtype_of_for_max( - self.exclusive_maximum, - other.exclusive_maximum, - "exclusive_maximum", - errors, - ); - ensure_subtype_of_for_multiple_of( - self.multiple_of, - other.multiple_of, - "multiple_of", - errors, - ); - } -} - -impl EnsureSubtypeOf for IntegerTypeData { - fn ensure_subtype_of( - &self, - other: &FloatTypeData, - _tg: &Typegraph, - errors: &mut ErrorCollector, - ) { - ensure_subtype_of_for_min( - self.minimum.map(|m| m as f64), - other.minimum, - "minimum", - errors, - ); - ensure_subtype_of_for_max( - self.maximum.map(|m| m as f64), - other.maximum, - "maximum", - errors, - ); - ensure_subtype_of_for_min( - self.exclusive_minimum.map(|m| m as f64), - other.exclusive_minimum, - "exclusive_minimum", - errors, - ); - ensure_subtype_of_for_max( - self.exclusive_maximum.map(|m| m as f64), - other.exclusive_maximum, - "exclusive_maximum", - errors, - ); - ensure_subtype_of_for_multiple_of( - self.multiple_of.map(|m| m as f64), - other.multiple_of, - "multiple_of", - errors, - ); - } -} - -impl EnsureSubtypeOf for StringTypeData { - fn ensure_subtype_of(&self, other: &Self, _tg: &Typegraph, errors: &mut ErrorCollector) { - ensure_subtype_of_for_min(self.min_length, other.min_length, "minimum_length", errors); - ensure_subtype_of_for_max(self.max_length, other.max_length, "maximum_length", errors); - - match (&self.pattern, &other.pattern) { - (Some(left), Some(right)) => { - if left != right { - errors.push(format!( - "'pattern' is required to be exactly the same as the supertype's: {} != {}", - left, right - )); - } - } - (None, Some(_)) => { - errors - .push("'pattern' is required on the subtype if it is defined on the supertype"); - } - _ => {} - } - - match (&self.format, &other.format) { - (Some(left), Some(right)) => { - if left != right { - errors.push(format!( - "'format' is required to be the same as the supertype's: {} != {}", - left, right - )); - } - } - (None, Some(_)) => { - errors - .push("'format' is required on the subtype if it is defined on the supertype"); - } - _ => {} - } - } -} - -impl EnsureSubtypeOf for FileTypeData { - fn ensure_subtype_of(&self, other: &Self, _tg: &Typegraph, errors: &mut ErrorCollector) { - ensure_subtype_of_for_min(self.min_size, other.min_size, "minimum_size", errors); - ensure_subtype_of_for_max(self.max_size, other.max_size, "maximum_size", errors); - - // FIXME consistency: the name on the SDK is 'allow' - match (&self.mime_types, &other.mime_types) { - (Some(left), Some(right)) => { - // O(n * m) but n and m are _usually_ small - if left.iter().any(|m| !right.contains(m)) { - errors.push("'mime_types' is required to be a subset of the supertype's"); - } - } - (None, Some(_)) => { - errors.push( - "'mime_types' is required on the subtype if it is defined on the supertype", - ); - } - _ => {} - } - } -} - -impl EnsureSubtypeOf for ObjectTypeData { - fn ensure_subtype_of(&self, other: &Self, tg: &Typegraph, errors: &mut ErrorCollector) { - let mut right_keys = other.properties.keys().collect::>(); - - for (key, left_idx) in &self.properties { - if let Some(right_idx) = other.properties.get(key) { - // TODO add some context on the error messages - ExtendedTypeNode::new(tg, *left_idx).ensure_subtype_of( - &ExtendedTypeNode::new(tg, *right_idx), - tg, - errors, - ); - } else { - errors.push(format!( - "property {} is not allowed: it is not defined in the supertype", - key - )); - } - right_keys.remove(key); - } - - for key in right_keys { - let type_idx = other.properties.get(key).unwrap(); - let type_node = tg.types.get(*type_idx as usize).unwrap(); - if !matches!(type_node, TypeNode::Optional { .. }) { - errors.push(format!( - "property {} is required: it is not optional in the supertype", - key - )); - } - } - - // FIXME https://linear.app/metatypedev/issue/MET-664/graph-check-the-semantics-of-type-refinements-on-tstruct - for key in &self.required { - if !other.required.contains(key) { - errors.push(format!("property {} is not required in the supertype", key)); - } - } - } -} - -impl EnsureSubtypeOf for ListTypeData { - fn ensure_subtype_of(&self, sup: &Self, typegraph: &Typegraph, errors: &mut ErrorCollector) { - ensure_subtype_of_for_min(self.min_items, sup.min_items, "minimum_items", errors); - ensure_subtype_of_for_max(self.max_items, sup.max_items, "maximum_items", errors); - if self.unique_items.unwrap_or(false) && !sup.unique_items.unwrap_or(false) { - errors.push("unique_items is not defined in the subtype"); - } - ExtendedTypeNode::new(typegraph, self.items).ensure_subtype_of( - &ExtendedTypeNode::new(typegraph, sup.items), - typegraph, - errors, - ); - } -} - -struct AnyOf<'a>(&'a [u32]); -struct OneOf<'a>(&'a [u32]); -struct AllOf<'a>(&'a [u32]); - -impl<'a, 'b> EnsureSubtypeOf> for ExtendedTypeNode<'b> { - fn ensure_subtype_of( - &self, - sup: &AnyOf<'a>, - typegraph: &Typegraph, - errors: &mut ErrorCollector, - ) { - let collectors: Vec = vec![]; - for idx in sup.0 { - let sup_type = ExtendedTypeNode::new(typegraph, *idx); - let mut errors = ErrorCollector::default(); - self.ensure_subtype_of(&sup_type, typegraph, &mut errors); - if errors.errors.is_empty() { - return; - } - } - errors.push("Expected at least one variant to be a supertype, got none"); - for (idx, nested) in collectors.into_iter().enumerate() { - errors.push_nested(format!("Variant {}", idx), nested); - } - } -} - -impl<'a, 'b> EnsureSubtypeOf> for ExtendedTypeNode<'b> { - fn ensure_subtype_of( - &self, - sup: &OneOf<'a>, - typegraph: &Typegraph, - errors: &mut ErrorCollector, - ) { - let collectors = sup - .0 - .iter() - .map(|idx| { - let sup_type = ExtendedTypeNode::new(typegraph, *idx); - let mut errors = ErrorCollector::default(); - self.ensure_subtype_of(&sup_type, typegraph, &mut errors); - errors - }) - .collect::>(); - - let match_count = collectors.iter().filter(|c| c.errors.is_empty()).count(); - match match_count { - 0 => { - errors.push("Expected a single variant to be a supertype, got none"); - for (idx, nested) in collectors.into_iter().enumerate() { - errors.push_nested(format!("Variant {}", idx), nested); - } - } - 1 => { - // nothing to do - } - _ => { - errors.push(format!( - "Expected a single variant to be a supertype, got more: variants {}", - collectors - .iter() - .enumerate() - .filter(|(_, c)| c.errors.is_empty()) - .map(|(i, _)| i.to_string()) - .collect::>() - .join(", "), - )); - } - } - } -} - -impl<'b, S> EnsureSubtypeOf for AllOf<'b> -where - for<'a> ExtendedTypeNode<'a>: EnsureSubtypeOf, -{ - fn ensure_subtype_of(&self, sup: &S, typegraph: &Typegraph, errors: &mut ErrorCollector) { - let mut count = 0; - let collectors = self - .0 - .iter() - .enumerate() - .filter_map(|(i, type_idx)| { - let mut errors = ErrorCollector::default(); - let sub_type = ExtendedTypeNode::new(typegraph, *type_idx); - sub_type.ensure_subtype_of(sup, typegraph, &mut errors); - if errors.errors.is_empty() { - None - } else { - count += 1; - Some((i, errors)) - } - }) - .collect::>(); - - if count > 0 { - errors.push("Expected all variants to be a subtype"); - for (idx, nested) in collectors { - errors.push_nested(format!("Variant {} is not a subtype", idx), nested); - } - } - } -} - -impl EnsureSubtypeOf for UnionTypeData { - fn ensure_subtype_of(&self, sup: &Self, typegraph: &Typegraph, errors: &mut ErrorCollector) { - AllOf(&self.any_of).ensure_subtype_of(&AnyOf(&sup.any_of), typegraph, errors); - } -} - -impl EnsureSubtypeOf for EitherTypeData { - fn ensure_subtype_of(&self, sup: &Self, typegraph: &Typegraph, errors: &mut ErrorCollector) { - AllOf(&self.one_of).ensure_subtype_of(&OneOf(&sup.one_of), typegraph, errors); - } -} - -impl EnsureSubtypeOf for EitherTypeData { - fn ensure_subtype_of( - &self, - sup: &UnionTypeData, - typegraph: &Typegraph, - errors: &mut ErrorCollector, - ) { - AllOf(&self.one_of).ensure_subtype_of(&AnyOf(&sup.any_of), typegraph, errors); - } -} - -impl EnsureSubtypeOf for UnionTypeData { - fn ensure_subtype_of( - &self, - sup: &EitherTypeData, - typegraph: &Typegraph, - errors: &mut ErrorCollector, - ) { - AllOf(&self.any_of).ensure_subtype_of(&OneOf(&sup.one_of), typegraph, errors); - } -} - -struct Enum<'a>(Option<&'a [String]>); - -impl<'a, 'b> EnsureSubtypeOf> for Enum<'b> { - fn ensure_subtype_of(&self, sup: &Enum<'a>, _tg: &Typegraph, errors: &mut ErrorCollector) { - let sub = self.0.unwrap_or(&[]); - let sup = sup.0.unwrap_or(&[]); - if sub.is_empty() && !sup.is_empty() { - errors.push("Expected the subtype to be an enum"); - return; - } - let sup = sup - .iter() - .map(|s| serde_json::to_value(s).unwrap()) - .collect::>(); - let not_found = sub - .iter() - .map(|s| serde_json::to_value(s).unwrap()) - .enumerate() - .filter(|(_, sup_v)| sup.iter().all(|v| !value_equals(v, sup_v))) - .collect::>(); - if !not_found.is_empty() { - errors.push_nested("Expected all enum values to be defined on the supertype", { - let mut nested = ErrorCollector::default(); - for (idx, sup_v) in not_found { - nested.push(format!( - "Value {} (#{}) is not defined on the supertype", - sup_v, idx - )); - } - nested - }); - } - } -} - -// TODO move to different module -fn value_equals(left: &serde_json::Value, right: &serde_json::Value) -> bool { - match (left, right) { - (serde_json::Value::String(left), serde_json::Value::String(right)) => left == right, - (serde_json::Value::Number(left), serde_json::Value::Number(right)) => left == right, - (serde_json::Value::Bool(left), serde_json::Value::Bool(right)) => left == right, - (serde_json::Value::Array(left), serde_json::Value::Array(right)) => left - .iter() - .zip(right.iter()) - .all(|(l, r)| value_equals(l, r)), - (serde_json::Value::Object(left), serde_json::Value::Object(right)) => { - left.len() == right.len() - && left - .iter() - .all(|(k, v)| right.get(k).map_or(false, |r| value_equals(v, r))) - } - _ => false, - } -} - -impl<'a, 'b> EnsureSubtypeOf> for ExtendedTypeNode<'a> { - fn ensure_subtype_of( - &self, - sup: &ExtendedTypeNode<'b>, - tg: &Typegraph, - errors: &mut ErrorCollector, - ) { - let sub_idx = self.0; - let sup_idx = sup.0; - if sub_idx != sup_idx { - // self.1.ensure_subtype_of(sup.1, typegraph, errors); - match (self.1, sup.1) { - (TypeNode::Optional { data: sub, .. }, TypeNode::Optional { data: sup, .. }) => { - ExtendedTypeNode::new(tg, sub.item).ensure_subtype_of( - &ExtendedTypeNode::new(tg, sup.item), - tg, - errors, - ); - } - (_, TypeNode::Optional { data: sup, .. }) => { - self.ensure_subtype_of(&ExtendedTypeNode::new(tg, sup.item), tg, errors); - } - (TypeNode::Optional { .. }, _) => { - errors.push("Optional type cannot be a subtype of a non-optional type"); - } - (TypeNode::Boolean { .. }, TypeNode::Boolean { .. }) => { /* nothing to check */ } - ( - TypeNode::Integer { - data: sub, - base: sub_base, - }, - TypeNode::Integer { - data: sup, - base: sup_base, - }, - ) => { - sub.ensure_subtype_of(sup, tg, errors); - Enum(sub_base.enumeration.as_deref()).ensure_subtype_of( - &Enum(sup_base.enumeration.as_deref()), - tg, - errors, - ); - } - ( - TypeNode::Float { - data: sub, - base: sub_base, - }, - TypeNode::Float { - data: sup, - base: sup_base, - }, - ) => { - sub.ensure_subtype_of(sup, tg, errors); - Enum(sub_base.enumeration.as_deref()).ensure_subtype_of( - &Enum(sup_base.enumeration.as_deref()), - tg, - errors, - ); - } - ( - TypeNode::Integer { - data: sub, - base: sub_base, - }, - TypeNode::Float { - data: sup, - base: sup_base, - }, - ) => { - sub.ensure_subtype_of(sup, tg, errors); - Enum(sub_base.enumeration.as_deref()).ensure_subtype_of( - &Enum(sup_base.enumeration.as_deref()), - tg, - errors, - ); - } - ( - TypeNode::String { - data: sub, - base: sub_base, - }, - TypeNode::String { - data: sup, - base: sup_base, - }, - ) => { - sub.ensure_subtype_of(sup, tg, errors); - Enum(sub_base.enumeration.as_deref()).ensure_subtype_of( - &Enum(sup_base.enumeration.as_deref()), - tg, - errors, - ); - } - (TypeNode::File { data: sub, .. }, TypeNode::File { data: sup, .. }) => { - sub.ensure_subtype_of(sup, tg, errors) - } - ( - TypeNode::Object { - data: sub, - base: sub_base, - }, - TypeNode::Object { - data: sup, - base: sup_base, - }, - ) => { - sub.ensure_subtype_of(sup, tg, errors); - Enum(sub_base.enumeration.as_deref()).ensure_subtype_of( - &Enum(sup_base.enumeration.as_deref()), - tg, - errors, - ); - } - (TypeNode::List { data: sub, .. }, TypeNode::List { data: sup, .. }) => { - sub.ensure_subtype_of(sup, tg, errors) - } - (TypeNode::Union { data: sub, .. }, _) => { - AllOf(&sub.any_of).ensure_subtype_of(sup, tg, errors); - } - (TypeNode::Either { data: sub, .. }, _) => { - AllOf(&sub.one_of).ensure_subtype_of(sup, tg, errors); - } - (_, TypeNode::Union { data: sup, .. }) => { - self.ensure_subtype_of(&AnyOf(&sup.any_of), tg, errors); - } - (_, TypeNode::Either { data: sup, .. }) => { - self.ensure_subtype_of(&OneOf(&sup.one_of), tg, errors); - } - (_, TypeNode::Function { .. }) => { - errors.push("Function types are not supported for supertype"); - } - (TypeNode::Function { data, .. }, _) => { - ExtendedTypeNode::new(tg, data.output).ensure_subtype_of(sup, tg, errors); - } - (x, y) => errors.push(format!( - "Type mismatch: {} to {}", - x.type_name(), - y.type_name() - )), - } - } - } -} diff --git a/src/common/src/typegraph/validator/value.rs b/src/common/src/typegraph/validator/value.rs deleted file mode 100644 index bab4c599cd..0000000000 --- a/src/common/src/typegraph/validator/value.rs +++ /dev/null @@ -1,268 +0,0 @@ -// Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. -// SPDX-License-Identifier: MPL-2.0 - -use std::collections::HashSet; - -use anyhow::{anyhow, bail, Result}; -use serde_json::Value; - -use crate::typegraph::{ - EitherTypeData, FloatTypeData, IntegerTypeData, ListTypeData, ObjectTypeData, StringTypeData, - TypeNode, Typegraph, UnionTypeData, -}; - -fn to_string(value: &Value) -> String { - serde_json::to_string(value).unwrap() -} - -// TODO validation path -impl Typegraph { - pub fn validate_value(&self, type_idx: u32, value: &Value) -> Result<()> { - let type_node = &self.types[type_idx as usize]; - - match type_node { - TypeNode::Any { .. } => Ok(()), - TypeNode::Integer { data, .. } => self.validate_integer(data, value), - TypeNode::Float { data, .. } => self.validate_float(data, value), - TypeNode::Boolean { .. } => value.as_bool().map(|_| ()).ok_or_else(|| { - anyhow!("Expected a boolean got '{value}'", value = to_string(value)) - }), - TypeNode::String { data, .. } => self.validate_string(data, value), - TypeNode::File { .. } => bail!("Literal file not supported"), - TypeNode::Optional { data, .. } => { - if value.is_null() { - Ok(()) - } else { - self.validate_value(data.item, value) - } - } - TypeNode::List { data, .. } => self.validate_array(data, value), - TypeNode::Object { data, .. } => self.validate_object(data, value), - TypeNode::Function { .. } => Err(anyhow!("Unexpected function type")), - TypeNode::Union { data, .. } => self.validate_union(data, value), - TypeNode::Either { data, .. } => self.validate_either(data, value), - } - } - - fn validate_integer(&self, data: &IntegerTypeData, value: &Value) -> Result<()> { - let Value::Number(n) = value else { - bail!("Expected number got '{}'", to_string(value)); - }; - let Some(value) = n.as_i64().map(|value| value.try_into()).transpose()? else { - bail!("Number value {value:?} cannot be stored in f64"); - }; - if let Some(min) = data.minimum { - number_validator::expect_min(min, value)?; - } - if let Some(max) = data.maximum { - number_validator::expect_max(max, value)?; - } - if let Some(xmin) = data.exclusive_minimum { - number_validator::expect_xmin(xmin, value)?; - } - if let Some(xmax) = data.exclusive_maximum { - number_validator::expect_xmax(xmax, value)?; - } - if let Some(divisor) = data.multiple_of.as_ref() { - if value % divisor == 0 { - bail!("Expected a multiple of {divisor}, got {value}"); - } - } - Ok(()) - } - - fn validate_float(&self, data: &FloatTypeData, value: &Value) -> Result<()> { - let Value::Number(n) = value else { - bail!("Expected float got '{}'", to_string(value)); - }; - let Some(value) = n.as_f64() else { - bail!("Float value {value:?} cannot be stored in f64"); - }; - if let Some(min) = data.minimum { - number_validator::expect_min(min, value)?; - } - if let Some(max) = data.maximum { - number_validator::expect_max(max, value)?; - } - if let Some(xmin) = data.exclusive_minimum { - number_validator::expect_xmin(xmin, value)?; - } - if let Some(xmax) = data.exclusive_maximum { - number_validator::expect_xmax(xmax, value)?; - } - if let Some(divisor) = data.multiple_of.as_ref() { - let quot = value / divisor; - if quot.round() != quot { - bail!("Expected a multiple of {divisor}, got {value}"); - } - } - Ok(()) - } - - fn validate_string(&self, data: &StringTypeData, value: &Value) -> Result<()> { - let s = value - .as_str() - .ok_or_else(|| anyhow!("Expected a string, got '{}'", to_string(value)))?; - if let Some(min_length) = data.min_length { - if s.len() < min_length as usize { - bail!( - "Expected a minimum length of {min_length}, got {s:?} (len={})", - s.len() - ); - } - } - if let Some(max_length) = data.max_length { - if s.len() > max_length as usize { - bail!( - "Expected a maximun length of {max_length}, got {s:?} (len={})", - s.len() - ); - } - } - // TODO pattern, format - Ok(()) - } - - fn validate_array(&self, data: &ListTypeData, value: &Value) -> Result<()> { - let array = value - .as_array() - .ok_or_else(|| anyhow!("Expected an array got '{}'", to_string(value)))?; - - if let Some(max_items) = data.max_items { - if array.len() > max_items as usize { - bail!( - "Expected a maximum item count of {max_items} in array '{arr}' (len={})", - array.len(), - arr = to_string(value), - ); - } - } - - if let Some(min_items) = data.min_items { - if array.len() < min_items as usize { - bail!( - "Expected a minimum item count of {min_items} in array '{arr}' (len={})", - array.len(), - arr = to_string(value), - ); - } - } - - for item in array { - self.validate_value(data.items, item)?; - } - Ok(()) - } - - fn validate_object(&self, data: &ObjectTypeData, value: &Value) -> Result<()> { - let object = value.as_object().ok_or_else(|| { - anyhow!( - "Expected an object, got '{value}'", - value = to_string(value) - ) - })?; - - let mut remaining_keys = object.keys().collect::>(); - for (key, typ) in data.properties.iter() { - match object.get(key) { - None => { - if !matches!(self.types[*typ as usize], TypeNode::Optional { .. }) { - bail!( - "Required field {key:?} not found in object '{value}'", - value = to_string(value) - ); - } - } - Some(val) => { - self.validate_value(*typ, val)?; - remaining_keys.remove(key); - } - } - } - - // additional properties? - if !remaining_keys.is_empty() { - bail!( - "Unexpected fields {} in object {:?}", - remaining_keys - .iter() - .map(|k| format!("{k:?}")) - .collect::>() - .join(", "), - to_string(value), - ); - } - - Ok(()) - } - - fn validate_union(&self, data: &UnionTypeData, value: &Value) -> Result<()> { - for &variant in data.any_of.iter() { - if self.validate_value(variant, value).is_ok() { - return Ok(()); - } - } - bail!( - "Value '{value}' did not match any of the variants of the union", - value = to_string(value) - ); - } - - fn validate_either(&self, data: &EitherTypeData, value: &Value) -> Result<()> { - let mut valid_variants = vec![]; - for &variant in data.one_of.iter() { - if self.validate_value(variant, value).is_ok() { - valid_variants.push(variant); - } - } - match valid_variants.len() { - 0 => bail!( - "Value '{value}' did not match any of the variants of the either", - value = to_string(value) - ), - 1 => Ok(()), - _ => bail!( - "Value '{value}' matched to more than one variant onf the either: {}", - valid_variants - .iter() - .map(|v| format!("#{v}")) - .collect::>() - .join(", "), - value = to_string(value) - ), - } - } -} - -mod number_validator { - use anyhow::{bail, Result}; - use std::fmt::Display; - - pub fn expect_min(min: T, value: T) -> Result<()> { - if value < min { - bail!("Expected a minimum value of {min}, got {value}"); - } - Ok(()) - } - - pub fn expect_max(max: T, value: T) -> Result<()> { - if value > max { - bail!("Expected a maximum value of {max}, got {value}"); - } - Ok(()) - } - - pub fn expect_xmin(xmin: T, value: T) -> Result<()> { - if value <= xmin { - bail!("Expected an exclusive minimum value of {xmin}, got {value}"); - } - Ok(()) - } - - pub fn expect_xmax(xmax: T, value: T) -> Result<()> { - if value >= xmax { - bail!("Expected an exclusive maximum value of {xmax}, got {value}"); - } - Ok(()) - } -} diff --git a/src/common/src/typegraph/visitor.rs b/src/common/src/typegraph/visitor.rs deleted file mode 100644 index d264afd202..0000000000 --- a/src/common/src/typegraph/visitor.rs +++ /dev/null @@ -1,447 +0,0 @@ -// Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. -// SPDX-License-Identifier: MPL-2.0 - -use indexmap::IndexMap; -use std::{ - collections::{HashMap, HashSet}, - fmt::Display, -}; - -use super::{TypeNode, Typegraph}; - -#[derive(Clone)] -pub struct DefaultLayer; - -pub struct ChildNode(pub PathSegment, pub u32); - -pub trait VisitLayer<'a, V: TypeVisitor<'a>>: Clone + Sized + 'a { - fn visit( - &self, - traversal: &mut TypegraphTraversal<'a, V, Self>, - source: impl Iterator, - context: &'a V::Context, - ) -> Option; -} - -impl<'a, V: TypeVisitor<'a>> VisitLayer<'a, V> for DefaultLayer { - fn visit( - &self, - traversal: &mut TypegraphTraversal<'a, V, Self>, - source: impl Iterator, - context: &'a V::Context, - ) -> Option { - for ChildNode(path_seg, idx) in source { - if let Some(res) = visit_child(traversal, path_seg, idx, context) { - return Some(res); - } - } - None - } -} - -pub fn visit_child<'a, V: TypeVisitor<'a>, L: VisitLayer<'a, V>>( - traversal: &mut TypegraphTraversal<'a, V, L>, - path_seg: PathSegment, - idx: u32, - context: &'a V::Context, -) -> Option { - traversal.visit_child(path_seg, idx, context) -} - -impl Typegraph { - /// Depth-first traversal over all the types - pub fn traverse_types<'a, V, L>( - &'a self, - visitor: V, - context: &'a V::Context, - layer: L, - root_type_idx: u32, - ) -> Option - where - V: TypeVisitor<'a> + Sized + 'a, - L: VisitLayer<'a, V>, - { - let mut traversal = TypegraphTraversal { - tg: self, - path: vec![], - visited_types: HashMap::new(), - visited_input_types: HashMap::new(), - as_input: false, - visitor, - parent_fn: None, - layer, - }; - traversal - .visit_type(root_type_idx, context) - .or_else(|| traversal.visitor.take_result()) - } -} - -pub struct FunctionMetadata { - pub idx: u32, - // TODO Vec<> - pub path: String, - pub parent_struct_idx: u32, -} - -#[derive(Hash, PartialEq, Eq, Debug, Clone)] -pub struct ParentFn { - pub struct_idx: u32, - pub fn_key: String, -} - -pub struct TypegraphTraversal<'a, V, L = DefaultLayer> -where - V: TypeVisitor<'a> + Sized + 'a, - L: VisitLayer<'a, V>, -{ - tg: &'a Typegraph, - path: Vec, - parent_fn: Option, - as_input: bool, - visited_types: HashMap>, // non input types; per parent function - visited_input_types: HashMap>, // input types; per parent function - visitor: V, - layer: L, -} - -impl<'a, V, L> TypegraphTraversal<'a, V, L> -where - V: TypeVisitor<'a> + Sized, - L: VisitLayer<'a, V>, -{ - fn visit_type(&mut self, type_idx: u32, context: &'a V::Context) -> Option { - let res = if self.as_input { - let parent_fn = self.parent_fn.clone().unwrap(); - let visited = self - .visited_input_types - .entry(parent_fn.clone()) - .or_default(); - if visited.contains(&type_idx) { - return None; - } - visited.insert(type_idx); - let type_node = &context.get_typegraph().types[type_idx as usize]; - let node = CurrentNode { - type_idx, - type_node, - path: &self.path, - }; - - self.visitor.visit_input_type(node, context, parent_fn) - } else { - if let Some(parent_fn) = &self.parent_fn { - let visited = self.visited_types.entry(parent_fn.clone()).or_default(); - if visited.contains(&type_idx) { - return None; - } - visited.insert(type_idx); - } - - let type_node = &context.get_typegraph().types[type_idx as usize]; - let node = CurrentNode { - type_idx, - type_node, - path: &self.path, - }; - - self.visitor.visit(node, context) - }; - - let type_node = &self.tg.types[type_idx as usize]; - - match res { - VisitResult::Continue(deeper) if deeper => match type_node { - TypeNode::Optional { data, .. } => { - self.visit_optional(type_idx, data.item, context) - } - TypeNode::Object { data, .. } => { - self.visit_object(type_idx, &data.properties, context) - } - TypeNode::List { data, .. } => self.visit_array(type_idx, data.items, context), - TypeNode::Union { data, .. } => self.visit_union(type_idx, &data.any_of, context), - TypeNode::Either { data, .. } => self.visit_either(type_idx, &data.one_of, context), - TypeNode::Function { data, .. } => { - self.visit_function(type_idx, data.input, data.output, context) - } - TypeNode::Boolean { .. } - | TypeNode::Float { .. } - | TypeNode::Integer { .. } - | TypeNode::String { .. } - | TypeNode::File { .. } - | TypeNode::Any { .. } => { - // scalar types -- no children - None - } - }, - VisitResult::Continue(_) => None, - VisitResult::Return(ret) => Some(ret), - } - } - - fn visit_optional( - &mut self, - type_idx: u32, - item_type_idx: u32, - context: &'a V::Context, - ) -> Option { - self.visit_child( - PathSegment { - from: type_idx, - edge: Edge::OptionalItem, - }, - item_type_idx, - context, - ) - } - - fn visit_array( - &mut self, - type_idx: u32, - item_type_idx: u32, - context: &'a V::Context, - ) -> Option { - self.visit_child( - PathSegment { - from: type_idx, - edge: Edge::ArrayItem, - }, - item_type_idx, - context, - ) - } - - fn visit_object( - &mut self, - type_idx: u32, - props: &'a IndexMap, - context: &'a V::Context, - ) -> Option { - self.visit_children( - props.iter().map(|(name, idx)| { - ( - PathSegment { - from: type_idx, - edge: Edge::ObjectProp(name.clone()), - }, - *idx, - ) - }), - context, - ) - } - - fn visit_union( - &mut self, - type_idx: u32, - variants: &'a [u32], - context: &'a V::Context, - ) -> Option { - for (i, variant_type) in variants.iter().enumerate() { - let res = self.visit_child( - PathSegment { - from: type_idx, - edge: Edge::UnionVariant(i), - }, - *variant_type, - context, - ); - if let Some(ret) = res { - return Some(ret); - } - } - None - } - - fn visit_either( - &mut self, - type_idx: u32, - variants: &'a [u32], - context: &'a V::Context, - ) -> Option { - variants.iter().enumerate().find_map(|(i, t)| { - self.visit_child( - PathSegment { - from: type_idx, - edge: Edge::EitherVariant(i), - }, - *t, - context, - ) - }) - } - - fn visit_function( - &mut self, - type_idx: u32, - input: u32, - output: u32, - context: &'a V::Context, - ) -> Option { - if self.as_input { - // TODO warning - return None; - } - - let last_path_seg = self.path.last().unwrap(); - match last_path_seg.edge { - Edge::ObjectProp(_) => {} - _ => { - return Some(V::Return::from_error( - Path(&self.path).to_string(), - "Function is only allowed as struct field (direct child)".to_string(), - )); - } - } - - let last_seg = self.path.last().unwrap(); - let fn_key = match &last_seg.edge { - Edge::ObjectProp(k) => k.to_string(), - _ => unreachable!(), // or error? - }; - let struct_idx = last_seg.from; - let old_parent_fn = - std::mem::replace(&mut self.parent_fn, Some(ParentFn { struct_idx, fn_key })); - self.as_input = true; - let res = self.visit_child( - PathSegment { - from: type_idx, - edge: Edge::FunctionInput, - }, - input, - context, - ); - self.as_input = false; - - if let Some(ret) = res { - self.parent_fn = old_parent_fn; - return Some(ret); - } - - let res = self.visit_child( - PathSegment { - from: type_idx, - edge: Edge::FunctionOutput, - }, - output, - context, - ); - self.parent_fn = old_parent_fn; - - res - } - - fn visit_children( - &mut self, - children: impl Iterator, - context: &'a V::Context, - ) -> Option { - self.layer.clone().visit( - self, - children.map(|(seg, idx)| ChildNode(seg, idx)), - context, - ) - } - - fn visit_child( - &mut self, - segment: PathSegment, - type_idx: u32, - context: &'a V::Context, - ) -> Option { - self.path.push(segment); - let res = self.visit_type(type_idx, context); - self.path.pop().unwrap(); - res - } -} - -#[derive(Debug, Clone)] -pub struct PathSegment { - pub from: u32, // typeIdx - pub edge: Edge, -} - -impl Display for PathSegment { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match &self.edge { - Edge::ObjectProp(name) => write!(f, "{}", name)?, - Edge::ArrayItem => write!(f, "[]")?, - Edge::OptionalItem => write!(f, "*")?, - Edge::FunctionInput => write!(f, "[in]")?, - Edge::FunctionOutput => write!(f, "[out]")?, - Edge::EitherVariant(v) | Edge::UnionVariant(v) => write!(f, "{}", v)?, - } - Ok(()) - } -} - -pub struct Path<'a>(pub &'a [PathSegment]); - -impl<'a> Display for Path<'a> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - for segment in self.0.iter() { - write!(f, "/{segment}")?; - } - Ok(()) - } -} - -#[derive(Debug, Clone)] -pub enum Edge { - ObjectProp(String), - ArrayItem, - OptionalItem, - FunctionInput, - FunctionOutput, - EitherVariant(usize), - UnionVariant(usize), -} - -pub enum VisitResult { - Continue(bool), - Return(T), -} - -#[derive(Clone, Copy)] -pub struct CurrentNode<'a> { - pub type_idx: u32, - pub type_node: &'a TypeNode, - pub path: &'a [PathSegment], -} - -pub trait TypeVisitorContext { - fn get_typegraph(&self) -> &Typegraph; -} - -pub trait TypeVisitor<'a> { - type Return: Sized + VisitorResult; - type Context: TypeVisitorContext + Clone; - - /// return true to continue the traversal on the subgraph - fn visit( - &mut self, - current_node: CurrentNode<'_>, - context: &Self::Context, - ) -> VisitResult; - - fn visit_input_type( - &mut self, - current_node: CurrentNode<'_>, - context: &Self::Context, - _parent_fn: ParentFn, - ) -> VisitResult { - self.visit(current_node, context) - } - - fn take_result(&mut self) -> Option - where - Self: Sized, - { - None - } -} - -pub trait VisitorResult { - fn from_error(path: String, message: String) -> Self; -} diff --git a/src/common/src/typegraph/visitor2.rs b/src/common/src/typegraph/visitor2.rs deleted file mode 100644 index f1dc96723d..0000000000 --- a/src/common/src/typegraph/visitor2.rs +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. -// SPDX-License-Identifier: MPL-2.0 - -use std::{cell::RefCell, rc::Rc}; - -use crate::typegraph::{ - visitor::{Edge, PathSegment}, - TypeNode, Typegraph, -}; - -pub struct VisitorContext<'tg> { - pub tg: &'tg Typegraph, - pub current_node: CurrentNode<'tg>, -} - -pub struct NearestFn { - pub path_index: usize, - pub type_idx: u32, - pub is_input: bool, -} - -impl<'a> CurrentNode<'a> { - pub fn nearest_function(&self) -> Option { - for (i, segment) in self.path.borrow().iter().enumerate().rev() { - match segment.edge { - Edge::FunctionInput => { - return Some(NearestFn { - path_index: i, - type_idx: segment.from, - is_input: true, - }) - } - Edge::FunctionOutput => { - return Some(NearestFn { - path_index: i, - type_idx: segment.from, - is_input: false, - }) - } - _ => continue, - } - } - None - } -} - -pub enum VisitNext { - /// continue traversal, with the eventual child nodes - Children, - /// continue traversal, but do not visit the children - Siblings, - Stop, -} - -pub fn traverse_types<'tg, 'path, A, V, E>( - tg: &'tg Typegraph, - root_type_idx: u32, - accumulator: A, - visit_fn: V, -) -> Result -where - V: Fn(VisitorContext<'tg>, &mut A) -> Result, -{ - let path = Rc::new(RefCell::new(Vec::new())); - let output = traverse_types_with_path(tg, root_type_idx, &path, accumulator, &visit_fn)?; - Ok(output.accumulator) -} - -struct TraverseOutput { - accumulator: A, - stop: bool, -} - -type SharedPath = Rc>>; - -#[derive(Debug)] -pub struct CurrentNode<'tg> { - pub type_node: &'tg TypeNode, - pub type_idx: u32, - pub path: SharedPath, - pub in_cycle: bool, -} - -fn traverse_types_with_path<'tg, A, V, E>( - tg: &'tg Typegraph, - type_idx: u32, - path: &Rc>>, - mut accumulator: A, - visit_fn: &V, -) -> Result, E> -where - V: Fn(VisitorContext<'tg>, &mut A) -> Result, -{ - let type_node = &tg.types[type_idx as usize]; - - // visit current - { - let current_node = CurrentNode { - type_node, - type_idx, - path: path.clone(), - in_cycle: path.borrow().iter().any(|seg| seg.from == type_idx), - }; - let cx = VisitorContext { tg, current_node }; - match visit_fn(cx, &mut accumulator)? { - VisitNext::Stop => { - return Ok(TraverseOutput { - accumulator, - stop: true, - }) - } - VisitNext::Siblings => { - return Ok(TraverseOutput { - accumulator, - stop: false, - }) - } - VisitNext::Children => (), - } - } - - let push = { - let path = path.clone(); - move |edge: Edge| { - path.borrow_mut().push(PathSegment { - from: type_idx, - edge, - }); - } - }; - - let pop = { - let path = path.clone(); - move || { - path.borrow_mut().pop(); - } - }; - - // visit children - match type_node { - TypeNode::Boolean { .. } - | TypeNode::Integer { .. } - | TypeNode::Float { .. } - | TypeNode::String { .. } - | TypeNode::File { .. } - | TypeNode::Any { .. } => Ok(TraverseOutput { - accumulator, - stop: false, - }), - - TypeNode::Optional { data, .. } => { - let item_type_idx = data.item; - push(Edge::OptionalItem); - let output = traverse_types_with_path(tg, item_type_idx, path, accumulator, visit_fn)?; - pop(); - Ok(output) - } - - TypeNode::List { data, .. } => { - let item_type_idx = data.items; - push(Edge::ArrayItem); - let output = traverse_types_with_path(tg, item_type_idx, path, accumulator, visit_fn)?; - pop(); - Ok(output) - } - - TypeNode::Object { data, .. } => { - let mut accumulator = Some(accumulator); - for (key, prop_idx) in data.properties.iter() { - push(Edge::ObjectProp(key.clone())); - let output = traverse_types_with_path( - tg, - *prop_idx, - path, - accumulator.take().unwrap(), - visit_fn, - )?; - pop(); - if output.stop { - return Ok(output); - } - accumulator = Some(output.accumulator); - } - Ok(TraverseOutput { - accumulator: accumulator.unwrap(), - stop: false, - }) - } - - TypeNode::Union { data, .. } => { - let mut accumulator = Some(accumulator); - for (v, &item_type_idx) in data.any_of.iter().enumerate() { - push(Edge::UnionVariant(v)); - let output = traverse_types_with_path( - tg, - item_type_idx, - path, - accumulator.take().unwrap(), - visit_fn, - )?; - pop(); - if output.stop { - return Ok(output); - } - accumulator = Some(output.accumulator); - } - Ok(TraverseOutput { - accumulator: accumulator.unwrap(), - stop: false, - }) - } - - TypeNode::Either { data, .. } => { - let mut accumulator = Some(accumulator); - for (v, &item_type_idx) in data.one_of.iter().enumerate() { - push(Edge::EitherVariant(v)); - let output = traverse_types_with_path( - tg, - item_type_idx, - path, - accumulator.take().unwrap(), - visit_fn, - )?; - pop(); - if output.stop { - return Ok(output); - } - accumulator = Some(output.accumulator); - } - Ok(TraverseOutput { - accumulator: accumulator.unwrap(), - stop: false, - }) - } - - TypeNode::Function { data, .. } => { - let input_type_idx = data.input; - push(Edge::FunctionInput); - let output = traverse_types_with_path(tg, input_type_idx, path, accumulator, visit_fn)?; - pop(); - if output.stop { - return Ok(output); - } - - let output_type_idx = data.output; - push(Edge::FunctionOutput); - let output = - traverse_types_with_path(tg, output_type_idx, path, output.accumulator, visit_fn)?; - pop(); - Ok(output) - } - } -} From ed71bef14d1fd6334543ca2d923fda344cb19e4b Mon Sep 17 00:00:00 2001 From: Natoandro Date: Thu, 6 Feb 2025 15:27:18 +0300 Subject: [PATCH 3/6] remove old migrations (merge confusion) --- .../prisma/20241204070020_init/migration.sql | 52 ------------------- .../prisma/20241128060951_init/migration.sql | 10 ---- .../prisma/20241128061308_init/migration.sql | 10 ---- .../prisma/20241128061429_init/migration.sql | 10 ---- .../prisma/20241128061813_init/migration.sql | 10 ---- .../prisma/20241128061933_init/migration.sql | 10 ---- .../prisma/20241128062049_init/migration.sql | 10 ---- .../prisma/20241128062310_init/migration.sql | 10 ---- .../prisma/20241128063810_init/migration.sql | 10 ---- .../prisma/20241128064200_init/migration.sql | 10 ---- .../prisma/20241128064410_init/migration.sql | 10 ---- .../prisma/20241128064911_init/migration.sql | 10 ---- .../prisma/20241128065237_init/migration.sql | 10 ---- .../prisma/20241128065923_init/migration.sql | 10 ---- .../prisma/20241128070637_init/migration.sql | 10 ---- .../prisma/20241128070942_init/migration.sql | 10 ---- .../prisma/20241128071228_init/migration.sql | 10 ---- .../prisma/20241203073924_init/migration.sql | 10 ---- .../prisma/20241203073954_init/migration.sql | 10 ---- .../prisma/20241203080702_init/migration.sql | 10 ---- .../prisma/20241203081051_init/migration.sql | 10 ---- .../prisma/20241203081420_init/migration.sql | 10 ---- .../prisma/20241203082135_init/migration.sql | 10 ---- .../prisma/20241203082320_init/migration.sql | 10 ---- .../prisma/20241203085925_init/migration.sql | 10 ---- .../prisma/20241203090525_init/migration.sql | 10 ---- .../prisma/20241203090653_init/migration.sql | 10 ---- .../20250114072258_generated/migration.sql | 6 --- .../db/20241108195939_init/migration.sql | 12 ----- .../db/20241108200030_init/migration.sql | 12 ----- .../db/20241108200115_init/migration.sql | 12 ----- .../db/20241108200151_init/migration.sql | 12 ----- .../db/20241108200319_init/migration.sql | 12 ----- .../db/20241108200506_init/migration.sql | 12 ----- .../db/20241108200547_init/migration.sql | 12 ----- .../db/20241108200925_init/migration.sql | 12 ----- .../db/20241108201004_init/migration.sql | 12 ----- .../db/20241108201707_init/migration.sql | 12 ----- .../db/20241108202304_init/migration.sql | 12 ----- .../db/20250129070250_init/migration.sql | 12 ----- .../db/20250130051054_init/migration.sql | 12 ----- .../db/20250130064430_init/migration.sql | 12 ----- .../db/20250130064812_init/migration.sql | 12 ----- .../db/20250130064857_init/migration.sql | 12 ----- .../db/20250130064944_init/migration.sql | 12 ----- .../db/20250130065004_init/migration.sql | 12 ----- .../db/20250130065034_init/migration.sql | 12 ----- .../db/20250130065309_init/migration.sql | 12 ----- .../db/20250130065707_init/migration.sql | 12 ----- .../prisma/20241204093547_init/migration.sql | 6 --- 50 files changed, 576 deletions(-) delete mode 100644 tests/prisma-migrations/full-prisma-mapping/prisma/20241204070020_init/migration.sql delete mode 100644 tests/prisma-migrations/injection/prisma/20241128060951_init/migration.sql delete mode 100644 tests/prisma-migrations/injection/prisma/20241128061308_init/migration.sql delete mode 100644 tests/prisma-migrations/injection/prisma/20241128061429_init/migration.sql delete mode 100644 tests/prisma-migrations/injection/prisma/20241128061813_init/migration.sql delete mode 100644 tests/prisma-migrations/injection/prisma/20241128061933_init/migration.sql delete mode 100644 tests/prisma-migrations/injection/prisma/20241128062049_init/migration.sql delete mode 100644 tests/prisma-migrations/injection/prisma/20241128062310_init/migration.sql delete mode 100644 tests/prisma-migrations/injection/prisma/20241128063810_init/migration.sql delete mode 100644 tests/prisma-migrations/injection/prisma/20241128064200_init/migration.sql delete mode 100644 tests/prisma-migrations/injection/prisma/20241128064410_init/migration.sql delete mode 100644 tests/prisma-migrations/injection/prisma/20241128064911_init/migration.sql delete mode 100644 tests/prisma-migrations/injection/prisma/20241128065237_init/migration.sql delete mode 100644 tests/prisma-migrations/injection/prisma/20241128065923_init/migration.sql delete mode 100644 tests/prisma-migrations/injection/prisma/20241128070637_init/migration.sql delete mode 100644 tests/prisma-migrations/injection/prisma/20241128070942_init/migration.sql delete mode 100644 tests/prisma-migrations/injection/prisma/20241128071228_init/migration.sql delete mode 100644 tests/prisma-migrations/injection/prisma/20241203073924_init/migration.sql delete mode 100644 tests/prisma-migrations/injection/prisma/20241203073954_init/migration.sql delete mode 100644 tests/prisma-migrations/injection/prisma/20241203080702_init/migration.sql delete mode 100644 tests/prisma-migrations/injection/prisma/20241203081051_init/migration.sql delete mode 100644 tests/prisma-migrations/injection/prisma/20241203081420_init/migration.sql delete mode 100644 tests/prisma-migrations/injection/prisma/20241203082135_init/migration.sql delete mode 100644 tests/prisma-migrations/injection/prisma/20241203082320_init/migration.sql delete mode 100644 tests/prisma-migrations/injection/prisma/20241203085925_init/migration.sql delete mode 100644 tests/prisma-migrations/injection/prisma/20241203090525_init/migration.sql delete mode 100644 tests/prisma-migrations/injection/prisma/20241203090653_init/migration.sql delete mode 100644 tests/prisma-migrations/migration-failure-test-1/main/20250114072258_generated/migration.sql delete mode 100644 tests/prisma-migrations/prisma-apply/db/20241108195939_init/migration.sql delete mode 100644 tests/prisma-migrations/prisma-apply/db/20241108200030_init/migration.sql delete mode 100644 tests/prisma-migrations/prisma-apply/db/20241108200115_init/migration.sql delete mode 100644 tests/prisma-migrations/prisma-apply/db/20241108200151_init/migration.sql delete mode 100644 tests/prisma-migrations/prisma-apply/db/20241108200319_init/migration.sql delete mode 100644 tests/prisma-migrations/prisma-apply/db/20241108200506_init/migration.sql delete mode 100644 tests/prisma-migrations/prisma-apply/db/20241108200547_init/migration.sql delete mode 100644 tests/prisma-migrations/prisma-apply/db/20241108200925_init/migration.sql delete mode 100644 tests/prisma-migrations/prisma-apply/db/20241108201004_init/migration.sql delete mode 100644 tests/prisma-migrations/prisma-apply/db/20241108201707_init/migration.sql delete mode 100644 tests/prisma-migrations/prisma-apply/db/20241108202304_init/migration.sql delete mode 100644 tests/prisma-migrations/prisma-apply/db/20250129070250_init/migration.sql delete mode 100644 tests/prisma-migrations/prisma-apply/db/20250130051054_init/migration.sql delete mode 100644 tests/prisma-migrations/prisma-apply/db/20250130064430_init/migration.sql delete mode 100644 tests/prisma-migrations/prisma-apply/db/20250130064812_init/migration.sql delete mode 100644 tests/prisma-migrations/prisma-apply/db/20250130064857_init/migration.sql delete mode 100644 tests/prisma-migrations/prisma-apply/db/20250130064944_init/migration.sql delete mode 100644 tests/prisma-migrations/prisma-apply/db/20250130065004_init/migration.sql delete mode 100644 tests/prisma-migrations/prisma-apply/db/20250130065034_init/migration.sql delete mode 100644 tests/prisma-migrations/prisma-apply/db/20250130065309_init/migration.sql delete mode 100644 tests/prisma-migrations/prisma-apply/db/20250130065707_init/migration.sql delete mode 100644 tests/prisma-migrations/typename/prisma/20241204093547_init/migration.sql diff --git a/tests/prisma-migrations/full-prisma-mapping/prisma/20241204070020_init/migration.sql b/tests/prisma-migrations/full-prisma-mapping/prisma/20241204070020_init/migration.sql deleted file mode 100644 index a70c01a4c2..0000000000 --- a/tests/prisma-migrations/full-prisma-mapping/prisma/20241204070020_init/migration.sql +++ /dev/null @@ -1,52 +0,0 @@ --- CreateTable -CREATE TABLE "User" ( - "id" INTEGER NOT NULL, - "name" TEXT NOT NULL, - "age" INTEGER, - "coinflips" BOOLEAN[], - "city" TEXT NOT NULL, - - CONSTRAINT "User_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Post" ( - "id" INTEGER NOT NULL, - "title" TEXT NOT NULL, - "views" INTEGER NOT NULL, - "likes" INTEGER NOT NULL, - "published" BOOLEAN NOT NULL, - "authorId" INTEGER NOT NULL, - - CONSTRAINT "Post_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Comment" ( - "id" INTEGER NOT NULL, - "content" TEXT NOT NULL, - "related_postId" INTEGER NOT NULL, - "authorId" INTEGER NOT NULL, - - CONSTRAINT "Comment_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "ExtendedProfile" ( - "bio" TEXT NOT NULL, - "userId" INTEGER NOT NULL, - - CONSTRAINT "ExtendedProfile_pkey" PRIMARY KEY ("userId") -); - --- AddForeignKey -ALTER TABLE "Post" ADD CONSTRAINT "Post_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Comment" ADD CONSTRAINT "Comment_related_postId_fkey" FOREIGN KEY ("related_postId") REFERENCES "Post"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Comment" ADD CONSTRAINT "Comment_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "ExtendedProfile" ADD CONSTRAINT "ExtendedProfile_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/tests/prisma-migrations/injection/prisma/20241128060951_init/migration.sql b/tests/prisma-migrations/injection/prisma/20241128060951_init/migration.sql deleted file mode 100644 index d4647cea5d..0000000000 --- a/tests/prisma-migrations/injection/prisma/20241128060951_init/migration.sql +++ /dev/null @@ -1,10 +0,0 @@ --- CreateTable -CREATE TABLE "Messages" ( - "id" UUID NOT NULL, - "time" TIMESTAMP(3) NOT NULL, - "text" TEXT NOT NULL, - "senderId" INTEGER NOT NULL, - "recipientId" INTEGER NOT NULL, - - CONSTRAINT "Messages_pkey" PRIMARY KEY ("id") -); diff --git a/tests/prisma-migrations/injection/prisma/20241128061308_init/migration.sql b/tests/prisma-migrations/injection/prisma/20241128061308_init/migration.sql deleted file mode 100644 index d4647cea5d..0000000000 --- a/tests/prisma-migrations/injection/prisma/20241128061308_init/migration.sql +++ /dev/null @@ -1,10 +0,0 @@ --- CreateTable -CREATE TABLE "Messages" ( - "id" UUID NOT NULL, - "time" TIMESTAMP(3) NOT NULL, - "text" TEXT NOT NULL, - "senderId" INTEGER NOT NULL, - "recipientId" INTEGER NOT NULL, - - CONSTRAINT "Messages_pkey" PRIMARY KEY ("id") -); diff --git a/tests/prisma-migrations/injection/prisma/20241128061429_init/migration.sql b/tests/prisma-migrations/injection/prisma/20241128061429_init/migration.sql deleted file mode 100644 index d4647cea5d..0000000000 --- a/tests/prisma-migrations/injection/prisma/20241128061429_init/migration.sql +++ /dev/null @@ -1,10 +0,0 @@ --- CreateTable -CREATE TABLE "Messages" ( - "id" UUID NOT NULL, - "time" TIMESTAMP(3) NOT NULL, - "text" TEXT NOT NULL, - "senderId" INTEGER NOT NULL, - "recipientId" INTEGER NOT NULL, - - CONSTRAINT "Messages_pkey" PRIMARY KEY ("id") -); diff --git a/tests/prisma-migrations/injection/prisma/20241128061813_init/migration.sql b/tests/prisma-migrations/injection/prisma/20241128061813_init/migration.sql deleted file mode 100644 index d4647cea5d..0000000000 --- a/tests/prisma-migrations/injection/prisma/20241128061813_init/migration.sql +++ /dev/null @@ -1,10 +0,0 @@ --- CreateTable -CREATE TABLE "Messages" ( - "id" UUID NOT NULL, - "time" TIMESTAMP(3) NOT NULL, - "text" TEXT NOT NULL, - "senderId" INTEGER NOT NULL, - "recipientId" INTEGER NOT NULL, - - CONSTRAINT "Messages_pkey" PRIMARY KEY ("id") -); diff --git a/tests/prisma-migrations/injection/prisma/20241128061933_init/migration.sql b/tests/prisma-migrations/injection/prisma/20241128061933_init/migration.sql deleted file mode 100644 index d4647cea5d..0000000000 --- a/tests/prisma-migrations/injection/prisma/20241128061933_init/migration.sql +++ /dev/null @@ -1,10 +0,0 @@ --- CreateTable -CREATE TABLE "Messages" ( - "id" UUID NOT NULL, - "time" TIMESTAMP(3) NOT NULL, - "text" TEXT NOT NULL, - "senderId" INTEGER NOT NULL, - "recipientId" INTEGER NOT NULL, - - CONSTRAINT "Messages_pkey" PRIMARY KEY ("id") -); diff --git a/tests/prisma-migrations/injection/prisma/20241128062049_init/migration.sql b/tests/prisma-migrations/injection/prisma/20241128062049_init/migration.sql deleted file mode 100644 index d4647cea5d..0000000000 --- a/tests/prisma-migrations/injection/prisma/20241128062049_init/migration.sql +++ /dev/null @@ -1,10 +0,0 @@ --- CreateTable -CREATE TABLE "Messages" ( - "id" UUID NOT NULL, - "time" TIMESTAMP(3) NOT NULL, - "text" TEXT NOT NULL, - "senderId" INTEGER NOT NULL, - "recipientId" INTEGER NOT NULL, - - CONSTRAINT "Messages_pkey" PRIMARY KEY ("id") -); diff --git a/tests/prisma-migrations/injection/prisma/20241128062310_init/migration.sql b/tests/prisma-migrations/injection/prisma/20241128062310_init/migration.sql deleted file mode 100644 index d4647cea5d..0000000000 --- a/tests/prisma-migrations/injection/prisma/20241128062310_init/migration.sql +++ /dev/null @@ -1,10 +0,0 @@ --- CreateTable -CREATE TABLE "Messages" ( - "id" UUID NOT NULL, - "time" TIMESTAMP(3) NOT NULL, - "text" TEXT NOT NULL, - "senderId" INTEGER NOT NULL, - "recipientId" INTEGER NOT NULL, - - CONSTRAINT "Messages_pkey" PRIMARY KEY ("id") -); diff --git a/tests/prisma-migrations/injection/prisma/20241128063810_init/migration.sql b/tests/prisma-migrations/injection/prisma/20241128063810_init/migration.sql deleted file mode 100644 index d4647cea5d..0000000000 --- a/tests/prisma-migrations/injection/prisma/20241128063810_init/migration.sql +++ /dev/null @@ -1,10 +0,0 @@ --- CreateTable -CREATE TABLE "Messages" ( - "id" UUID NOT NULL, - "time" TIMESTAMP(3) NOT NULL, - "text" TEXT NOT NULL, - "senderId" INTEGER NOT NULL, - "recipientId" INTEGER NOT NULL, - - CONSTRAINT "Messages_pkey" PRIMARY KEY ("id") -); diff --git a/tests/prisma-migrations/injection/prisma/20241128064200_init/migration.sql b/tests/prisma-migrations/injection/prisma/20241128064200_init/migration.sql deleted file mode 100644 index d4647cea5d..0000000000 --- a/tests/prisma-migrations/injection/prisma/20241128064200_init/migration.sql +++ /dev/null @@ -1,10 +0,0 @@ --- CreateTable -CREATE TABLE "Messages" ( - "id" UUID NOT NULL, - "time" TIMESTAMP(3) NOT NULL, - "text" TEXT NOT NULL, - "senderId" INTEGER NOT NULL, - "recipientId" INTEGER NOT NULL, - - CONSTRAINT "Messages_pkey" PRIMARY KEY ("id") -); diff --git a/tests/prisma-migrations/injection/prisma/20241128064410_init/migration.sql b/tests/prisma-migrations/injection/prisma/20241128064410_init/migration.sql deleted file mode 100644 index d4647cea5d..0000000000 --- a/tests/prisma-migrations/injection/prisma/20241128064410_init/migration.sql +++ /dev/null @@ -1,10 +0,0 @@ --- CreateTable -CREATE TABLE "Messages" ( - "id" UUID NOT NULL, - "time" TIMESTAMP(3) NOT NULL, - "text" TEXT NOT NULL, - "senderId" INTEGER NOT NULL, - "recipientId" INTEGER NOT NULL, - - CONSTRAINT "Messages_pkey" PRIMARY KEY ("id") -); diff --git a/tests/prisma-migrations/injection/prisma/20241128064911_init/migration.sql b/tests/prisma-migrations/injection/prisma/20241128064911_init/migration.sql deleted file mode 100644 index d4647cea5d..0000000000 --- a/tests/prisma-migrations/injection/prisma/20241128064911_init/migration.sql +++ /dev/null @@ -1,10 +0,0 @@ --- CreateTable -CREATE TABLE "Messages" ( - "id" UUID NOT NULL, - "time" TIMESTAMP(3) NOT NULL, - "text" TEXT NOT NULL, - "senderId" INTEGER NOT NULL, - "recipientId" INTEGER NOT NULL, - - CONSTRAINT "Messages_pkey" PRIMARY KEY ("id") -); diff --git a/tests/prisma-migrations/injection/prisma/20241128065237_init/migration.sql b/tests/prisma-migrations/injection/prisma/20241128065237_init/migration.sql deleted file mode 100644 index d4647cea5d..0000000000 --- a/tests/prisma-migrations/injection/prisma/20241128065237_init/migration.sql +++ /dev/null @@ -1,10 +0,0 @@ --- CreateTable -CREATE TABLE "Messages" ( - "id" UUID NOT NULL, - "time" TIMESTAMP(3) NOT NULL, - "text" TEXT NOT NULL, - "senderId" INTEGER NOT NULL, - "recipientId" INTEGER NOT NULL, - - CONSTRAINT "Messages_pkey" PRIMARY KEY ("id") -); diff --git a/tests/prisma-migrations/injection/prisma/20241128065923_init/migration.sql b/tests/prisma-migrations/injection/prisma/20241128065923_init/migration.sql deleted file mode 100644 index d4647cea5d..0000000000 --- a/tests/prisma-migrations/injection/prisma/20241128065923_init/migration.sql +++ /dev/null @@ -1,10 +0,0 @@ --- CreateTable -CREATE TABLE "Messages" ( - "id" UUID NOT NULL, - "time" TIMESTAMP(3) NOT NULL, - "text" TEXT NOT NULL, - "senderId" INTEGER NOT NULL, - "recipientId" INTEGER NOT NULL, - - CONSTRAINT "Messages_pkey" PRIMARY KEY ("id") -); diff --git a/tests/prisma-migrations/injection/prisma/20241128070637_init/migration.sql b/tests/prisma-migrations/injection/prisma/20241128070637_init/migration.sql deleted file mode 100644 index d4647cea5d..0000000000 --- a/tests/prisma-migrations/injection/prisma/20241128070637_init/migration.sql +++ /dev/null @@ -1,10 +0,0 @@ --- CreateTable -CREATE TABLE "Messages" ( - "id" UUID NOT NULL, - "time" TIMESTAMP(3) NOT NULL, - "text" TEXT NOT NULL, - "senderId" INTEGER NOT NULL, - "recipientId" INTEGER NOT NULL, - - CONSTRAINT "Messages_pkey" PRIMARY KEY ("id") -); diff --git a/tests/prisma-migrations/injection/prisma/20241128070942_init/migration.sql b/tests/prisma-migrations/injection/prisma/20241128070942_init/migration.sql deleted file mode 100644 index d4647cea5d..0000000000 --- a/tests/prisma-migrations/injection/prisma/20241128070942_init/migration.sql +++ /dev/null @@ -1,10 +0,0 @@ --- CreateTable -CREATE TABLE "Messages" ( - "id" UUID NOT NULL, - "time" TIMESTAMP(3) NOT NULL, - "text" TEXT NOT NULL, - "senderId" INTEGER NOT NULL, - "recipientId" INTEGER NOT NULL, - - CONSTRAINT "Messages_pkey" PRIMARY KEY ("id") -); diff --git a/tests/prisma-migrations/injection/prisma/20241128071228_init/migration.sql b/tests/prisma-migrations/injection/prisma/20241128071228_init/migration.sql deleted file mode 100644 index d4647cea5d..0000000000 --- a/tests/prisma-migrations/injection/prisma/20241128071228_init/migration.sql +++ /dev/null @@ -1,10 +0,0 @@ --- CreateTable -CREATE TABLE "Messages" ( - "id" UUID NOT NULL, - "time" TIMESTAMP(3) NOT NULL, - "text" TEXT NOT NULL, - "senderId" INTEGER NOT NULL, - "recipientId" INTEGER NOT NULL, - - CONSTRAINT "Messages_pkey" PRIMARY KEY ("id") -); diff --git a/tests/prisma-migrations/injection/prisma/20241203073924_init/migration.sql b/tests/prisma-migrations/injection/prisma/20241203073924_init/migration.sql deleted file mode 100644 index d4647cea5d..0000000000 --- a/tests/prisma-migrations/injection/prisma/20241203073924_init/migration.sql +++ /dev/null @@ -1,10 +0,0 @@ --- CreateTable -CREATE TABLE "Messages" ( - "id" UUID NOT NULL, - "time" TIMESTAMP(3) NOT NULL, - "text" TEXT NOT NULL, - "senderId" INTEGER NOT NULL, - "recipientId" INTEGER NOT NULL, - - CONSTRAINT "Messages_pkey" PRIMARY KEY ("id") -); diff --git a/tests/prisma-migrations/injection/prisma/20241203073954_init/migration.sql b/tests/prisma-migrations/injection/prisma/20241203073954_init/migration.sql deleted file mode 100644 index d4647cea5d..0000000000 --- a/tests/prisma-migrations/injection/prisma/20241203073954_init/migration.sql +++ /dev/null @@ -1,10 +0,0 @@ --- CreateTable -CREATE TABLE "Messages" ( - "id" UUID NOT NULL, - "time" TIMESTAMP(3) NOT NULL, - "text" TEXT NOT NULL, - "senderId" INTEGER NOT NULL, - "recipientId" INTEGER NOT NULL, - - CONSTRAINT "Messages_pkey" PRIMARY KEY ("id") -); diff --git a/tests/prisma-migrations/injection/prisma/20241203080702_init/migration.sql b/tests/prisma-migrations/injection/prisma/20241203080702_init/migration.sql deleted file mode 100644 index d4647cea5d..0000000000 --- a/tests/prisma-migrations/injection/prisma/20241203080702_init/migration.sql +++ /dev/null @@ -1,10 +0,0 @@ --- CreateTable -CREATE TABLE "Messages" ( - "id" UUID NOT NULL, - "time" TIMESTAMP(3) NOT NULL, - "text" TEXT NOT NULL, - "senderId" INTEGER NOT NULL, - "recipientId" INTEGER NOT NULL, - - CONSTRAINT "Messages_pkey" PRIMARY KEY ("id") -); diff --git a/tests/prisma-migrations/injection/prisma/20241203081051_init/migration.sql b/tests/prisma-migrations/injection/prisma/20241203081051_init/migration.sql deleted file mode 100644 index d4647cea5d..0000000000 --- a/tests/prisma-migrations/injection/prisma/20241203081051_init/migration.sql +++ /dev/null @@ -1,10 +0,0 @@ --- CreateTable -CREATE TABLE "Messages" ( - "id" UUID NOT NULL, - "time" TIMESTAMP(3) NOT NULL, - "text" TEXT NOT NULL, - "senderId" INTEGER NOT NULL, - "recipientId" INTEGER NOT NULL, - - CONSTRAINT "Messages_pkey" PRIMARY KEY ("id") -); diff --git a/tests/prisma-migrations/injection/prisma/20241203081420_init/migration.sql b/tests/prisma-migrations/injection/prisma/20241203081420_init/migration.sql deleted file mode 100644 index d4647cea5d..0000000000 --- a/tests/prisma-migrations/injection/prisma/20241203081420_init/migration.sql +++ /dev/null @@ -1,10 +0,0 @@ --- CreateTable -CREATE TABLE "Messages" ( - "id" UUID NOT NULL, - "time" TIMESTAMP(3) NOT NULL, - "text" TEXT NOT NULL, - "senderId" INTEGER NOT NULL, - "recipientId" INTEGER NOT NULL, - - CONSTRAINT "Messages_pkey" PRIMARY KEY ("id") -); diff --git a/tests/prisma-migrations/injection/prisma/20241203082135_init/migration.sql b/tests/prisma-migrations/injection/prisma/20241203082135_init/migration.sql deleted file mode 100644 index d4647cea5d..0000000000 --- a/tests/prisma-migrations/injection/prisma/20241203082135_init/migration.sql +++ /dev/null @@ -1,10 +0,0 @@ --- CreateTable -CREATE TABLE "Messages" ( - "id" UUID NOT NULL, - "time" TIMESTAMP(3) NOT NULL, - "text" TEXT NOT NULL, - "senderId" INTEGER NOT NULL, - "recipientId" INTEGER NOT NULL, - - CONSTRAINT "Messages_pkey" PRIMARY KEY ("id") -); diff --git a/tests/prisma-migrations/injection/prisma/20241203082320_init/migration.sql b/tests/prisma-migrations/injection/prisma/20241203082320_init/migration.sql deleted file mode 100644 index d4647cea5d..0000000000 --- a/tests/prisma-migrations/injection/prisma/20241203082320_init/migration.sql +++ /dev/null @@ -1,10 +0,0 @@ --- CreateTable -CREATE TABLE "Messages" ( - "id" UUID NOT NULL, - "time" TIMESTAMP(3) NOT NULL, - "text" TEXT NOT NULL, - "senderId" INTEGER NOT NULL, - "recipientId" INTEGER NOT NULL, - - CONSTRAINT "Messages_pkey" PRIMARY KEY ("id") -); diff --git a/tests/prisma-migrations/injection/prisma/20241203085925_init/migration.sql b/tests/prisma-migrations/injection/prisma/20241203085925_init/migration.sql deleted file mode 100644 index d4647cea5d..0000000000 --- a/tests/prisma-migrations/injection/prisma/20241203085925_init/migration.sql +++ /dev/null @@ -1,10 +0,0 @@ --- CreateTable -CREATE TABLE "Messages" ( - "id" UUID NOT NULL, - "time" TIMESTAMP(3) NOT NULL, - "text" TEXT NOT NULL, - "senderId" INTEGER NOT NULL, - "recipientId" INTEGER NOT NULL, - - CONSTRAINT "Messages_pkey" PRIMARY KEY ("id") -); diff --git a/tests/prisma-migrations/injection/prisma/20241203090525_init/migration.sql b/tests/prisma-migrations/injection/prisma/20241203090525_init/migration.sql deleted file mode 100644 index d4647cea5d..0000000000 --- a/tests/prisma-migrations/injection/prisma/20241203090525_init/migration.sql +++ /dev/null @@ -1,10 +0,0 @@ --- CreateTable -CREATE TABLE "Messages" ( - "id" UUID NOT NULL, - "time" TIMESTAMP(3) NOT NULL, - "text" TEXT NOT NULL, - "senderId" INTEGER NOT NULL, - "recipientId" INTEGER NOT NULL, - - CONSTRAINT "Messages_pkey" PRIMARY KEY ("id") -); diff --git a/tests/prisma-migrations/injection/prisma/20241203090653_init/migration.sql b/tests/prisma-migrations/injection/prisma/20241203090653_init/migration.sql deleted file mode 100644 index d4647cea5d..0000000000 --- a/tests/prisma-migrations/injection/prisma/20241203090653_init/migration.sql +++ /dev/null @@ -1,10 +0,0 @@ --- CreateTable -CREATE TABLE "Messages" ( - "id" UUID NOT NULL, - "time" TIMESTAMP(3) NOT NULL, - "text" TEXT NOT NULL, - "senderId" INTEGER NOT NULL, - "recipientId" INTEGER NOT NULL, - - CONSTRAINT "Messages_pkey" PRIMARY KEY ("id") -); diff --git a/tests/prisma-migrations/migration-failure-test-1/main/20250114072258_generated/migration.sql b/tests/prisma-migrations/migration-failure-test-1/main/20250114072258_generated/migration.sql deleted file mode 100644 index cd3bdae7b7..0000000000 --- a/tests/prisma-migrations/migration-failure-test-1/main/20250114072258_generated/migration.sql +++ /dev/null @@ -1,6 +0,0 @@ --- CreateTable -CREATE TABLE "Record" ( - "id" SERIAL NOT NULL, - - CONSTRAINT "Record_pkey" PRIMARY KEY ("id") -); diff --git a/tests/prisma-migrations/prisma-apply/db/20241108195939_init/migration.sql b/tests/prisma-migrations/prisma-apply/db/20241108195939_init/migration.sql deleted file mode 100644 index 9fcd6eb908..0000000000 --- a/tests/prisma-migrations/prisma-apply/db/20241108195939_init/migration.sql +++ /dev/null @@ -1,12 +0,0 @@ --- CreateTable -CREATE TABLE "user" ( - "id" UUID NOT NULL, - "name" TEXT NOT NULL, - "email" TEXT NOT NULL, - "age" INTEGER NOT NULL, - - CONSTRAINT "user_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "user_email_key" ON "user"("email"); diff --git a/tests/prisma-migrations/prisma-apply/db/20241108200030_init/migration.sql b/tests/prisma-migrations/prisma-apply/db/20241108200030_init/migration.sql deleted file mode 100644 index 9fcd6eb908..0000000000 --- a/tests/prisma-migrations/prisma-apply/db/20241108200030_init/migration.sql +++ /dev/null @@ -1,12 +0,0 @@ --- CreateTable -CREATE TABLE "user" ( - "id" UUID NOT NULL, - "name" TEXT NOT NULL, - "email" TEXT NOT NULL, - "age" INTEGER NOT NULL, - - CONSTRAINT "user_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "user_email_key" ON "user"("email"); diff --git a/tests/prisma-migrations/prisma-apply/db/20241108200115_init/migration.sql b/tests/prisma-migrations/prisma-apply/db/20241108200115_init/migration.sql deleted file mode 100644 index 9fcd6eb908..0000000000 --- a/tests/prisma-migrations/prisma-apply/db/20241108200115_init/migration.sql +++ /dev/null @@ -1,12 +0,0 @@ --- CreateTable -CREATE TABLE "user" ( - "id" UUID NOT NULL, - "name" TEXT NOT NULL, - "email" TEXT NOT NULL, - "age" INTEGER NOT NULL, - - CONSTRAINT "user_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "user_email_key" ON "user"("email"); diff --git a/tests/prisma-migrations/prisma-apply/db/20241108200151_init/migration.sql b/tests/prisma-migrations/prisma-apply/db/20241108200151_init/migration.sql deleted file mode 100644 index 9fcd6eb908..0000000000 --- a/tests/prisma-migrations/prisma-apply/db/20241108200151_init/migration.sql +++ /dev/null @@ -1,12 +0,0 @@ --- CreateTable -CREATE TABLE "user" ( - "id" UUID NOT NULL, - "name" TEXT NOT NULL, - "email" TEXT NOT NULL, - "age" INTEGER NOT NULL, - - CONSTRAINT "user_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "user_email_key" ON "user"("email"); diff --git a/tests/prisma-migrations/prisma-apply/db/20241108200319_init/migration.sql b/tests/prisma-migrations/prisma-apply/db/20241108200319_init/migration.sql deleted file mode 100644 index 9fcd6eb908..0000000000 --- a/tests/prisma-migrations/prisma-apply/db/20241108200319_init/migration.sql +++ /dev/null @@ -1,12 +0,0 @@ --- CreateTable -CREATE TABLE "user" ( - "id" UUID NOT NULL, - "name" TEXT NOT NULL, - "email" TEXT NOT NULL, - "age" INTEGER NOT NULL, - - CONSTRAINT "user_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "user_email_key" ON "user"("email"); diff --git a/tests/prisma-migrations/prisma-apply/db/20241108200506_init/migration.sql b/tests/prisma-migrations/prisma-apply/db/20241108200506_init/migration.sql deleted file mode 100644 index 9fcd6eb908..0000000000 --- a/tests/prisma-migrations/prisma-apply/db/20241108200506_init/migration.sql +++ /dev/null @@ -1,12 +0,0 @@ --- CreateTable -CREATE TABLE "user" ( - "id" UUID NOT NULL, - "name" TEXT NOT NULL, - "email" TEXT NOT NULL, - "age" INTEGER NOT NULL, - - CONSTRAINT "user_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "user_email_key" ON "user"("email"); diff --git a/tests/prisma-migrations/prisma-apply/db/20241108200547_init/migration.sql b/tests/prisma-migrations/prisma-apply/db/20241108200547_init/migration.sql deleted file mode 100644 index 9fcd6eb908..0000000000 --- a/tests/prisma-migrations/prisma-apply/db/20241108200547_init/migration.sql +++ /dev/null @@ -1,12 +0,0 @@ --- CreateTable -CREATE TABLE "user" ( - "id" UUID NOT NULL, - "name" TEXT NOT NULL, - "email" TEXT NOT NULL, - "age" INTEGER NOT NULL, - - CONSTRAINT "user_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "user_email_key" ON "user"("email"); diff --git a/tests/prisma-migrations/prisma-apply/db/20241108200925_init/migration.sql b/tests/prisma-migrations/prisma-apply/db/20241108200925_init/migration.sql deleted file mode 100644 index 9fcd6eb908..0000000000 --- a/tests/prisma-migrations/prisma-apply/db/20241108200925_init/migration.sql +++ /dev/null @@ -1,12 +0,0 @@ --- CreateTable -CREATE TABLE "user" ( - "id" UUID NOT NULL, - "name" TEXT NOT NULL, - "email" TEXT NOT NULL, - "age" INTEGER NOT NULL, - - CONSTRAINT "user_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "user_email_key" ON "user"("email"); diff --git a/tests/prisma-migrations/prisma-apply/db/20241108201004_init/migration.sql b/tests/prisma-migrations/prisma-apply/db/20241108201004_init/migration.sql deleted file mode 100644 index 9fcd6eb908..0000000000 --- a/tests/prisma-migrations/prisma-apply/db/20241108201004_init/migration.sql +++ /dev/null @@ -1,12 +0,0 @@ --- CreateTable -CREATE TABLE "user" ( - "id" UUID NOT NULL, - "name" TEXT NOT NULL, - "email" TEXT NOT NULL, - "age" INTEGER NOT NULL, - - CONSTRAINT "user_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "user_email_key" ON "user"("email"); diff --git a/tests/prisma-migrations/prisma-apply/db/20241108201707_init/migration.sql b/tests/prisma-migrations/prisma-apply/db/20241108201707_init/migration.sql deleted file mode 100644 index 9fcd6eb908..0000000000 --- a/tests/prisma-migrations/prisma-apply/db/20241108201707_init/migration.sql +++ /dev/null @@ -1,12 +0,0 @@ --- CreateTable -CREATE TABLE "user" ( - "id" UUID NOT NULL, - "name" TEXT NOT NULL, - "email" TEXT NOT NULL, - "age" INTEGER NOT NULL, - - CONSTRAINT "user_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "user_email_key" ON "user"("email"); diff --git a/tests/prisma-migrations/prisma-apply/db/20241108202304_init/migration.sql b/tests/prisma-migrations/prisma-apply/db/20241108202304_init/migration.sql deleted file mode 100644 index 9fcd6eb908..0000000000 --- a/tests/prisma-migrations/prisma-apply/db/20241108202304_init/migration.sql +++ /dev/null @@ -1,12 +0,0 @@ --- CreateTable -CREATE TABLE "user" ( - "id" UUID NOT NULL, - "name" TEXT NOT NULL, - "email" TEXT NOT NULL, - "age" INTEGER NOT NULL, - - CONSTRAINT "user_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "user_email_key" ON "user"("email"); diff --git a/tests/prisma-migrations/prisma-apply/db/20250129070250_init/migration.sql b/tests/prisma-migrations/prisma-apply/db/20250129070250_init/migration.sql deleted file mode 100644 index 9fcd6eb908..0000000000 --- a/tests/prisma-migrations/prisma-apply/db/20250129070250_init/migration.sql +++ /dev/null @@ -1,12 +0,0 @@ --- CreateTable -CREATE TABLE "user" ( - "id" UUID NOT NULL, - "name" TEXT NOT NULL, - "email" TEXT NOT NULL, - "age" INTEGER NOT NULL, - - CONSTRAINT "user_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "user_email_key" ON "user"("email"); diff --git a/tests/prisma-migrations/prisma-apply/db/20250130051054_init/migration.sql b/tests/prisma-migrations/prisma-apply/db/20250130051054_init/migration.sql deleted file mode 100644 index 9fcd6eb908..0000000000 --- a/tests/prisma-migrations/prisma-apply/db/20250130051054_init/migration.sql +++ /dev/null @@ -1,12 +0,0 @@ --- CreateTable -CREATE TABLE "user" ( - "id" UUID NOT NULL, - "name" TEXT NOT NULL, - "email" TEXT NOT NULL, - "age" INTEGER NOT NULL, - - CONSTRAINT "user_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "user_email_key" ON "user"("email"); diff --git a/tests/prisma-migrations/prisma-apply/db/20250130064430_init/migration.sql b/tests/prisma-migrations/prisma-apply/db/20250130064430_init/migration.sql deleted file mode 100644 index 9fcd6eb908..0000000000 --- a/tests/prisma-migrations/prisma-apply/db/20250130064430_init/migration.sql +++ /dev/null @@ -1,12 +0,0 @@ --- CreateTable -CREATE TABLE "user" ( - "id" UUID NOT NULL, - "name" TEXT NOT NULL, - "email" TEXT NOT NULL, - "age" INTEGER NOT NULL, - - CONSTRAINT "user_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "user_email_key" ON "user"("email"); diff --git a/tests/prisma-migrations/prisma-apply/db/20250130064812_init/migration.sql b/tests/prisma-migrations/prisma-apply/db/20250130064812_init/migration.sql deleted file mode 100644 index 9fcd6eb908..0000000000 --- a/tests/prisma-migrations/prisma-apply/db/20250130064812_init/migration.sql +++ /dev/null @@ -1,12 +0,0 @@ --- CreateTable -CREATE TABLE "user" ( - "id" UUID NOT NULL, - "name" TEXT NOT NULL, - "email" TEXT NOT NULL, - "age" INTEGER NOT NULL, - - CONSTRAINT "user_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "user_email_key" ON "user"("email"); diff --git a/tests/prisma-migrations/prisma-apply/db/20250130064857_init/migration.sql b/tests/prisma-migrations/prisma-apply/db/20250130064857_init/migration.sql deleted file mode 100644 index 9fcd6eb908..0000000000 --- a/tests/prisma-migrations/prisma-apply/db/20250130064857_init/migration.sql +++ /dev/null @@ -1,12 +0,0 @@ --- CreateTable -CREATE TABLE "user" ( - "id" UUID NOT NULL, - "name" TEXT NOT NULL, - "email" TEXT NOT NULL, - "age" INTEGER NOT NULL, - - CONSTRAINT "user_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "user_email_key" ON "user"("email"); diff --git a/tests/prisma-migrations/prisma-apply/db/20250130064944_init/migration.sql b/tests/prisma-migrations/prisma-apply/db/20250130064944_init/migration.sql deleted file mode 100644 index 9fcd6eb908..0000000000 --- a/tests/prisma-migrations/prisma-apply/db/20250130064944_init/migration.sql +++ /dev/null @@ -1,12 +0,0 @@ --- CreateTable -CREATE TABLE "user" ( - "id" UUID NOT NULL, - "name" TEXT NOT NULL, - "email" TEXT NOT NULL, - "age" INTEGER NOT NULL, - - CONSTRAINT "user_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "user_email_key" ON "user"("email"); diff --git a/tests/prisma-migrations/prisma-apply/db/20250130065004_init/migration.sql b/tests/prisma-migrations/prisma-apply/db/20250130065004_init/migration.sql deleted file mode 100644 index 9fcd6eb908..0000000000 --- a/tests/prisma-migrations/prisma-apply/db/20250130065004_init/migration.sql +++ /dev/null @@ -1,12 +0,0 @@ --- CreateTable -CREATE TABLE "user" ( - "id" UUID NOT NULL, - "name" TEXT NOT NULL, - "email" TEXT NOT NULL, - "age" INTEGER NOT NULL, - - CONSTRAINT "user_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "user_email_key" ON "user"("email"); diff --git a/tests/prisma-migrations/prisma-apply/db/20250130065034_init/migration.sql b/tests/prisma-migrations/prisma-apply/db/20250130065034_init/migration.sql deleted file mode 100644 index 9fcd6eb908..0000000000 --- a/tests/prisma-migrations/prisma-apply/db/20250130065034_init/migration.sql +++ /dev/null @@ -1,12 +0,0 @@ --- CreateTable -CREATE TABLE "user" ( - "id" UUID NOT NULL, - "name" TEXT NOT NULL, - "email" TEXT NOT NULL, - "age" INTEGER NOT NULL, - - CONSTRAINT "user_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "user_email_key" ON "user"("email"); diff --git a/tests/prisma-migrations/prisma-apply/db/20250130065309_init/migration.sql b/tests/prisma-migrations/prisma-apply/db/20250130065309_init/migration.sql deleted file mode 100644 index 9fcd6eb908..0000000000 --- a/tests/prisma-migrations/prisma-apply/db/20250130065309_init/migration.sql +++ /dev/null @@ -1,12 +0,0 @@ --- CreateTable -CREATE TABLE "user" ( - "id" UUID NOT NULL, - "name" TEXT NOT NULL, - "email" TEXT NOT NULL, - "age" INTEGER NOT NULL, - - CONSTRAINT "user_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "user_email_key" ON "user"("email"); diff --git a/tests/prisma-migrations/prisma-apply/db/20250130065707_init/migration.sql b/tests/prisma-migrations/prisma-apply/db/20250130065707_init/migration.sql deleted file mode 100644 index 9fcd6eb908..0000000000 --- a/tests/prisma-migrations/prisma-apply/db/20250130065707_init/migration.sql +++ /dev/null @@ -1,12 +0,0 @@ --- CreateTable -CREATE TABLE "user" ( - "id" UUID NOT NULL, - "name" TEXT NOT NULL, - "email" TEXT NOT NULL, - "age" INTEGER NOT NULL, - - CONSTRAINT "user_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "user_email_key" ON "user"("email"); diff --git a/tests/prisma-migrations/typename/prisma/20241204093547_init/migration.sql b/tests/prisma-migrations/typename/prisma/20241204093547_init/migration.sql deleted file mode 100644 index 8195a541ec..0000000000 --- a/tests/prisma-migrations/typename/prisma/20241204093547_init/migration.sql +++ /dev/null @@ -1,6 +0,0 @@ --- CreateTable -CREATE TABLE "userprisma" ( - "id" INTEGER NOT NULL, - - CONSTRAINT "userprisma_pkey" PRIMARY KEY ("id") -); From a8dc23cb744788c44a72b2bbde8aee19c6334eba Mon Sep 17 00:00:00 2001 From: Natoandro Date: Thu, 6 Feb 2025 16:02:53 +0300 Subject: [PATCH 4/6] cli --- Cargo.lock | 46 ++++++++----------- Cargo.toml | 4 +- src/meta-cli/Cargo.toml | 4 +- src/meta-cli/src/cli/deploy.rs | 2 +- src/meta-cli/src/cli/gen.rs | 4 +- src/meta-cli/src/cli/list.rs | 3 +- src/meta-cli/src/cli/serialize.rs | 2 +- src/meta-cli/src/config.rs | 2 +- src/meta-cli/src/deploy/actors/task.rs | 2 +- src/meta-cli/src/deploy/actors/task/deploy.rs | 2 +- .../deploy/actors/task/deploy/migrations.rs | 2 +- .../src/deploy/actors/task/serialize.rs | 2 +- src/meta-cli/src/utils/mod.rs | 2 +- src/typegate/engine/Cargo.toml | 1 - src/{common => typegate_api}/Cargo.toml | 25 +--------- src/{common => typegate_api}/src/graphql.rs | 0 src/{common => typegate_api}/src/lib.rs | 2 + src/{common => typegate_api}/src/node.rs | 6 +-- 18 files changed, 42 insertions(+), 69 deletions(-) rename src/{common => typegate_api}/Cargo.toml (60%) rename src/{common => typegate_api}/src/graphql.rs (100%) rename src/{common => typegate_api}/src/lib.rs (81%) rename src/{common => typegate_api}/src/node.rs (98%) diff --git a/Cargo.lock b/Cargo.lock index 5a5927a440..f0998be102 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1601,30 +1601,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "common" -version = "0.5.1-rc.0" -dependencies = [ - "anyhow", - "async-trait", - "base64 0.22.1", - "colored", - "flate2", - "ignore", - "indexmap 2.6.0", - "indoc", - "itertools 0.13.0", - "proto-parser", - "protobuf", - "reqwest", - "serde", - "serde_json", - "serde_with", - "tar", - "thiserror", - "url", -] - [[package]] name = "compact_str" version = "0.7.1" @@ -6989,6 +6965,7 @@ name = "meta-cli" version = "0.5.1-rc.0" dependencies = [ "actix", + "archive_utils", "assert_cmd", "async-trait", "base64 0.22.1", @@ -6998,7 +6975,6 @@ dependencies = [ "clap-verbosity-flag", "clap_complete", "color-eyre", - "common", "crossbeam-channel", "ctrlc", "dashmap 6.1.0", @@ -7043,11 +7019,13 @@ dependencies = [ "tar", "tempfile", "textwrap", + "tg_schema", "tokio", "tracing", "tracing-error", "tracing-subscriber", "tracing-unwrap", + "typegate_api", "typegate_engine", "typegraph_core", ] @@ -12995,6 +12973,23 @@ dependencies = [ "typegate_engine", ] +[[package]] +name = "typegate_api" +version = "0.5.1-rc.0" +dependencies = [ + "anyhow", + "async-trait", + "colored", + "indoc", + "itertools 0.13.0", + "reqwest", + "serde", + "serde_json", + "tg_schema", + "thiserror", + "url", +] + [[package]] name = "typegate_engine" version = "0.5.1-rc.0" @@ -13003,7 +12998,6 @@ dependencies = [ "base64 0.22.1", "bytes", "chrono", - "common", "connection-string", "convert_case 0.6.0", "dashmap 6.1.0", diff --git a/Cargo.toml b/Cargo.toml index 85eb229316..be3ebeaf78 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,13 @@ [workspace] resolver = "2" members = [ - "src/common", "src/meta-cli", "src/metagen", "src/metagen/src/fdk_rs/static", "src/mt_deno", "src/typegate/engine", "src/typegate/standalone", + "src/typegate_api", "src/typegraph/core", "src/typegraph/schema", "src/xtask", @@ -34,13 +34,13 @@ edition = "2021" # internal crates mt_deno = { path = "src/mt_deno/" } -common = { path = "src/common/" } tg_schema = { path = "src/typegraph/schema" } typegraph_core = { path = "src/typegraph/core" } substantial = { path = "src/substantial/" } metagen = { path = "src/metagen/" } metagen-client = { path = "src/metagen-client-rs" } typegate_engine = { path = "src/typegate/engine" } +typegate_api = { path = "src/typegate_api" } grpc_utils = { path = "src/utils/grpc" } archive_utils = { path = "src/utils/archive" } diff --git a/src/meta-cli/Cargo.toml b/src/meta-cli/Cargo.toml index 70076cd287..daff07aaa9 100644 --- a/src/meta-cli/Cargo.toml +++ b/src/meta-cli/Cargo.toml @@ -32,9 +32,11 @@ typegate = ["dep:typegate_engine"] # internal typegraph_core.workspace = true +tg_schema.workspace = true typegate_engine = { workspace = true, optional = true } -common.workspace = true +typegate_api.workspace = true metagen.workspace = true +archive_utils.workspace = true # data structures chrono = { workspace = true, features = ["serde"] } diff --git a/src/meta-cli/src/cli/deploy.rs b/src/meta-cli/src/cli/deploy.rs index 2b18098f05..30b0aee606 100644 --- a/src/meta-cli/src/cli/deploy.rs +++ b/src/meta-cli/src/cli/deploy.rs @@ -10,7 +10,7 @@ use crate::deploy::actors::console::ConsoleActor; use crate::interlude::*; use crate::secrets::{RawSecrets, Secrets}; use clap::Parser; -use common::node::Node; +use typegate_api::Node; #[derive(Parser, Debug)] pub struct DeploySubcommand { diff --git a/src/meta-cli/src/cli/gen.rs b/src/meta-cli/src/cli/gen.rs index 336bafca03..ca1c4c6add 100644 --- a/src/meta-cli/src/cli/gen.rs +++ b/src/meta-cli/src/cli/gen.rs @@ -12,10 +12,10 @@ use crate::interlude::*; use crate::{config::Config, deploy::actors::console::ConsoleActor}; use actix::Actor; use clap::Parser; -use common::typegraph::Typegraph; use dashmap::DashMap; use futures_concurrency::future::FutureGroup; use metagen::*; +use tg_schema::Typegraph; #[derive(Parser, Debug, Clone)] pub struct Gen { @@ -105,7 +105,7 @@ impl Action for Gen { #[derive(Debug)] struct MetagenCtx { config: Arc, - typegate: Arc, + typegate: Arc, dir: PathBuf, typegraph_cache: DashMap>, } diff --git a/src/meta-cli/src/cli/list.rs b/src/meta-cli/src/cli/list.rs index cc6c4a1fa8..f7643aaa57 100644 --- a/src/meta-cli/src/cli/list.rs +++ b/src/meta-cli/src/cli/list.rs @@ -11,10 +11,9 @@ use crate::interlude::*; use anyhow::Result; use async_trait::async_trait; use clap::Parser; -use common::graphql::Query; -use common::node::Node; use serde::Deserialize; use tabled::{settings::Style, Table, Tabled}; +use typegate_api::{graphql::Query, Node}; #[derive(Parser, Debug)] pub struct List { diff --git a/src/meta-cli/src/cli/serialize.rs b/src/meta-cli/src/cli/serialize.rs index 9571b8e05d..4f4b3d98b8 100644 --- a/src/meta-cli/src/cli/serialize.rs +++ b/src/meta-cli/src/cli/serialize.rs @@ -9,9 +9,9 @@ use crate::deploy::actors::task::TaskFinishStatus; use crate::deploy::actors::task_manager::{Report, StopReason, TaskManagerInit, TaskSource}; use crate::interlude::*; use clap::Parser; -use common::typegraph::Typegraph; use core::fmt::Debug; use std::io::{self, Write}; +use tg_schema::Typegraph; use tokio::io::AsyncWriteExt; #[derive(Parser, Debug)] diff --git a/src/meta-cli/src/config.rs b/src/meta-cli/src/config.rs index 18d1ac5885..2e17edcfa0 100644 --- a/src/meta-cli/src/config.rs +++ b/src/meta-cli/src/config.rs @@ -6,13 +6,13 @@ use crate::interlude::*; use crate::cli::NodeArgs; use crate::fs::find_in_parents; use crate::utils::BasicAuth; -use common::node::Node; use globset::{Glob, GlobSet, GlobSetBuilder}; use reqwest::Url; use std::fs::{self, File}; use std::io; use std::slice; use std::str::FromStr; +use typegate_api::Node; pub const METATYPE_FILES: &[&str] = &["metatype.yml", "metatype.yaml"]; pub const VENV_FOLDERS: &[&str] = &[".venv"]; diff --git a/src/meta-cli/src/deploy/actors/task.rs b/src/meta-cli/src/deploy/actors/task.rs index 313e1f2a10..2ecff45c78 100644 --- a/src/meta-cli/src/deploy/actors/task.rs +++ b/src/meta-cli/src/deploy/actors/task.rs @@ -27,11 +27,11 @@ use crate::deploy::actors::task_io::TaskIoActor; use crate::interlude::*; use action::{get_typegraph_name, TaskActionGenerator}; use colored::OwoColorize; -use common::typegraph::Typegraph; use indexmap::IndexMap; use process_wrap::tokio::TokioChildWrapper; use serde::Deserialize; use std::time::Duration; +use tg_schema::Typegraph; use tokio::process::Command; pub mod message { diff --git a/src/meta-cli/src/deploy/actors/task/deploy.rs b/src/meta-cli/src/deploy/actors/task/deploy.rs index 8237bd5d74..58edf1fe1a 100644 --- a/src/meta-cli/src/deploy/actors/task/deploy.rs +++ b/src/meta-cli/src/deploy/actors/task/deploy.rs @@ -17,12 +17,12 @@ use crate::typegraph::rpc::{RpcCall as TypegraphRpcCall, RpcDispatch}; use artifacts::ArtifactUploader; use base64::prelude::*; use color_eyre::owo_colors::OwoColorize; -use common::node::Node; use reqwest::header::{self, HeaderMap, HeaderValue}; use reqwest::Client; use serde::Deserialize; use std::{path::Path, sync::Arc}; use tokio::process::Command; +use typegate_api::Node; use typegraph_core::sdk::core::{Artifact, Handler as _, PrismaMigrationConfig, SerializeParams}; use typegraph_core::sdk::utils::{Handler as _, QueryDeployParams}; use typegraph_core::Lib; diff --git a/src/meta-cli/src/deploy/actors/task/deploy/migrations.rs b/src/meta-cli/src/deploy/actors/task/deploy/migrations.rs index 0935c391b2..7ce80c9d09 100644 --- a/src/meta-cli/src/deploy/actors/task/deploy/migrations.rs +++ b/src/meta-cli/src/deploy/actors/task/deploy/migrations.rs @@ -64,7 +64,7 @@ impl DeployActionInner { for migration in migrations.iter() { let dest = migdir.join(&migration.runtime); - if let Err(err) = common::archive::unpack(&dest, Some(&migration.archive)) { + if let Err(err) = archive_utils::unpack(&dest, Some(&migration.archive)) { ctx.console.error(format!( "{scope} error while unpacking migrations into {:?}", migdir diff --git a/src/meta-cli/src/deploy/actors/task/serialize.rs b/src/meta-cli/src/deploy/actors/task/serialize.rs index 776be32146..ae448b8fe3 100644 --- a/src/meta-cli/src/deploy/actors/task/serialize.rs +++ b/src/meta-cli/src/deploy/actors/task/serialize.rs @@ -12,9 +12,9 @@ use crate::deploy::actors::task_manager::TaskRef; use crate::interlude::*; use crate::typegraph::rpc::{RpcCall as TypegraphRpcCall, RpcDispatch}; use color_eyre::owo_colors::OwoColorize; -use common::typegraph::Typegraph; use serde::Deserialize; use std::sync::Arc; +use tg_schema::Typegraph; use tokio::process::Command; use typegraph_core::sdk::core::{Handler, SerializeParams}; use typegraph_core::Lib; diff --git a/src/meta-cli/src/utils/mod.rs b/src/meta-cli/src/utils/mod.rs index 0b18dd89a5..d28c91c3b4 100644 --- a/src/meta-cli/src/utils/mod.rs +++ b/src/meta-cli/src/utils/mod.rs @@ -11,7 +11,7 @@ use std::env::{set_var, var}; use crate::config::VENV_FOLDERS; use crate::fs::find_in_parents; -use common::node::BasicAuth as BasicAuthCommon; +use typegate_api::BasicAuth as BasicAuthCommon; pub fn ensure_venv>(dir: P) -> Result<()> { if let Ok(active_venv) = var("VIRTUAL_ENV") { diff --git a/src/typegate/engine/Cargo.toml b/src/typegate/engine/Cargo.toml index 86d29bfd9d..5d3a6f784e 100644 --- a/src/typegate/engine/Cargo.toml +++ b/src/typegate/engine/Cargo.toml @@ -48,7 +48,6 @@ tempfile.workspace = true # internal mt_deno.workspace = true -common.workspace = true substantial.workspace = true # runtimes diff --git a/src/common/Cargo.toml b/src/typegate_api/Cargo.toml similarity index 60% rename from src/common/Cargo.toml rename to src/typegate_api/Cargo.toml index 712ae7deaf..d81bbce93c 100644 --- a/src/common/Cargo.toml +++ b/src/typegate_api/Cargo.toml @@ -1,38 +1,17 @@ [package] -name = "common" +name = "typegate_api" version.workspace = true edition.workspace = true [dependencies] -# patterns +tg_schema.workspace = true anyhow.workspace = true itertools.workspace = true indoc.workspace = true thiserror.workspace = true - -# encoding -base64.workspace = true -flate2.workspace = true -tar.workspace = true - serde.workspace = true serde_json = { workspace = true, features = ["preserve_order"] } -serde_with.workspace = true - -# ds -indexmap.workspace = true - -# fs -ignore.workspace = true - -# http reqwest = { workspace = true, features = ["json"] } url = { workspace = true, features = ["serde"] } - -# grpc -protobuf.workspace = true -proto-parser.workspace = true - -# cli colored.workspace = true async-trait.workspace = true diff --git a/src/common/src/graphql.rs b/src/typegate_api/src/graphql.rs similarity index 100% rename from src/common/src/graphql.rs rename to src/typegate_api/src/graphql.rs diff --git a/src/common/src/lib.rs b/src/typegate_api/src/lib.rs similarity index 81% rename from src/common/src/lib.rs rename to src/typegate_api/src/lib.rs index 1d568bd4f9..a2cb5a4ff9 100644 --- a/src/common/src/lib.rs +++ b/src/typegate_api/src/lib.rs @@ -3,3 +3,5 @@ pub mod graphql; pub mod node; + +pub use node::{BasicAuth, Node}; diff --git a/src/common/src/node.rs b/src/typegate_api/src/node.rs similarity index 98% rename from src/common/src/node.rs rename to src/typegate_api/src/node.rs index 158aa61fd6..cd28b47dc8 100644 --- a/src/common/src/node.rs +++ b/src/typegate_api/src/node.rs @@ -7,10 +7,8 @@ use reqwest::{Client, IntoUrl, RequestBuilder, Url}; use serde::Serialize; use std::{collections::HashMap, sync::Arc, time::Duration}; -use crate::{ - graphql::{self, Query}, - typegraph::Typegraph, -}; +use crate::graphql::{self, Query}; +use tg_schema::Typegraph; #[derive(Debug, Serialize, Clone)] pub struct BasicAuth { From c5e60373d6a2d4a2b23b40d3173b93c5d43704ec Mon Sep 17 00:00:00 2001 From: Natoandro Date: Thu, 6 Feb 2025 18:01:23 +0300 Subject: [PATCH 5/6] typegate engine --- Cargo.lock | 3 +++ src/typegate/engine/Cargo.toml | 3 +++ src/typegate/engine/src/runtimes/grpc.rs | 2 +- src/typegate/engine/src/runtimes/prisma.rs | 4 ++-- src/typegate/engine/src/runtimes/prisma/migration.rs | 4 ++-- src/typegate/engine/src/runtimes/substantial.rs | 2 +- src/typegate/engine/src/typegraph.rs | 2 +- 7 files changed, 13 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f0998be102..f85dd41bfc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12995,6 +12995,7 @@ name = "typegate_engine" version = "0.5.1-rc.0" dependencies = [ "anyhow", + "archive_utils", "base64 0.22.1", "bytes", "chrono", @@ -13005,6 +13006,7 @@ dependencies = [ "deno_core", "env_logger 0.11.0", "futures", + "grpc_utils", "mt_deno", "once_cell", "protobuf", @@ -13025,6 +13027,7 @@ dependencies = [ "tempfile", "temporal-client", "temporal-sdk-core-protos", + "tg_schema", "thiserror", "tokio", "tonic 0.12.3", diff --git a/src/typegate/engine/Cargo.toml b/src/typegate/engine/Cargo.toml index 5d3a6f784e..32f8aa9a77 100644 --- a/src/typegate/engine/Cargo.toml +++ b/src/typegate/engine/Cargo.toml @@ -48,7 +48,10 @@ tempfile.workspace = true # internal mt_deno.workspace = true +tg_schema.workspace = true substantial.workspace = true +grpc_utils.workspace = true +archive_utils.workspace = true # runtimes deno_core.workspace = true diff --git a/src/typegate/engine/src/runtimes/grpc.rs b/src/typegate/engine/src/runtimes/grpc.rs index 276188ba0c..36ef105078 100644 --- a/src/typegate/engine/src/runtimes/grpc.rs +++ b/src/typegate/engine/src/runtimes/grpc.rs @@ -3,7 +3,7 @@ use std::{cell::RefCell, ops::Deref, rc::Rc, str::FromStr, sync::Arc}; -use common::grpc::{get_file_descriptor, get_method_descriptor_proto}; +use grpc_utils::{get_file_descriptor, get_method_descriptor_proto}; use anyhow::{Context, Result}; use bytes::{Buf, BufMut}; diff --git a/src/typegate/engine/src/runtimes/prisma.rs b/src/typegate/engine/src/runtimes/prisma.rs index cb77a73c22..e3cab0fd01 100644 --- a/src/typegate/engine/src/runtimes/prisma.rs +++ b/src/typegate/engine/src/runtimes/prisma.rs @@ -233,11 +233,11 @@ pub struct UnpackInp { #[deno_core::op2] pub fn op_unpack(#[serde] input: UnpackInp) -> Result<()> { - common::archive::unpack(&input.dest, Some(input.migrations)) + archive_utils::unpack(&input.dest, Some(input.migrations)) } #[deno_core::op2] #[string] pub fn op_archive(#[string] path: &str) -> Result> { - common::archive::archive(path) + archive_utils::archive(path) } diff --git a/src/typegate/engine/src/runtimes/prisma/migration.rs b/src/typegate/engine/src/runtimes/prisma/migration.rs index 6e9d8bc73d..2b399ad7f2 100644 --- a/src/typegate/engine/src/runtimes/prisma/migration.rs +++ b/src/typegate/engine/src/runtimes/prisma/migration.rs @@ -441,12 +441,12 @@ struct MigrationsFolder { impl MigrationsFolder { pub fn from(tmp_dir_path: &Path, serialized: Option>) -> Result { let tempdir = tempdir_in(tmp_dir_path)?; - common::archive::unpack(&tempdir, serialized)?; + archive_utils::unpack(&tempdir, serialized)?; Ok(Self { dir: tempdir }) } fn serialize(&self) -> Result> { - common::archive::archive(self) + archive_utils::archive(self) } } diff --git a/src/typegate/engine/src/runtimes/substantial.rs b/src/typegate/engine/src/runtimes/substantial.rs index 416609319d..4406383f9f 100644 --- a/src/typegate/engine/src/runtimes/substantial.rs +++ b/src/typegate/engine/src/runtimes/substantial.rs @@ -6,13 +6,13 @@ use crate::interlude::*; use chrono::{DateTime, Utc}; -use common::typegraph::runtimes::substantial::SubstantialBackend; use dashmap::DashMap; use deno_core::OpState; use substantial::{ backends::{fs::FsBackend, memory::MemoryBackend, redis::RedisBackend, Backend, NextRun}, converters::{MetadataEvent, Operation, Run}, }; +use tg_schema::runtimes::substantial::SubstantialBackend; #[rustfmt::skip] use deno_core as deno_core; // necessary for re-exported macros to work diff --git a/src/typegate/engine/src/typegraph.rs b/src/typegate/engine/src/typegraph.rs index 0451052bee..c98459e11b 100644 --- a/src/typegate/engine/src/typegraph.rs +++ b/src/typegate/engine/src/typegraph.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: MPL-2.0 use crate::interlude::*; -use common::typegraph::{runtimes::prisma::PrismaRuntimeData, Typegraph}; +use tg_schema::{runtimes::prisma::PrismaRuntimeData, Typegraph}; #[rustfmt::skip] use deno_core as deno_core; // necessary for re-exported macros to work From 7d9ac3fc64975151203d46b5089d2792b0de131f Mon Sep 17 00:00:00 2001 From: Natoandro Date: Thu, 6 Feb 2025 19:34:09 +0300 Subject: [PATCH 6/6] pre-commit, cargo tests --- Cargo.lock | 1 + src/metagen/Cargo.toml | 1 + src/metagen/src/client_rs/mod.rs | 2 +- src/metagen/src/fdk_rs/stubs.rs | 6 +- src/metagen/src/tests/fixtures.rs | 6 +- src/metagen/src/tests/mod.rs | 6 +- src/typegraph/core/src/t.rs | 2 +- src/typegraph/core/src/test_utils.rs | 2 +- src/typegraph/core/src/types/sdk/aws.rs | 12 +- src/typegraph/core/src/types/sdk/core.rs | 21 +++- src/typegraph/core/src/types/sdk/mod.rs | 4 +- src/typegraph/core/src/types/sdk/runtimes.rs | 112 +++++++++++++++---- src/typegraph/core/src/types/sdk/utils.rs | 24 +++- src/typegraph/schema/Cargo.toml | 1 - 14 files changed, 149 insertions(+), 51 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f85dd41bfc..be8e173ac7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7052,6 +7052,7 @@ dependencies = [ "tera", "tg_schema", "tokio", + "typegate_api", ] [[package]] diff --git a/src/metagen/Cargo.toml b/src/metagen/Cargo.toml index 88bcfa79fb..c38436a1d2 100644 --- a/src/metagen/Cargo.toml +++ b/src/metagen/Cargo.toml @@ -42,3 +42,4 @@ futures-lite.workspace = true [dev-dependencies] tokio = { workspace = true, features = ["full"] } tempfile.workspace = true +typegate_api.workspace = true diff --git a/src/metagen/src/client_rs/mod.rs b/src/metagen/src/client_rs/mod.rs index 04722c158f..d140df0729 100644 --- a/src/metagen/src/client_rs/mod.rs +++ b/src/metagen/src/client_rs/mod.rs @@ -6,8 +6,8 @@ mod selections; use core::fmt::Write; -use tg_schema::EffectType; use shared::get_gql_type; +use tg_schema::EffectType; use crate::interlude::*; use crate::*; diff --git a/src/metagen/src/fdk_rs/stubs.rs b/src/metagen/src/fdk_rs/stubs.rs index 82c2a4e2b8..48e2792763 100644 --- a/src/metagen/src/fdk_rs/stubs.rs +++ b/src/metagen/src/fdk_rs/stubs.rs @@ -82,7 +82,7 @@ pub fn gen_op_to_mat_map( mod test { use super::*; use crate::{fdk_rs::*, tests::default_type_node_base}; - use common::typegraph::*; + use tg_schema::*; #[test] fn stub_test() -> anyhow::Result<()> { @@ -94,8 +94,8 @@ mod test { meta: TypeMeta { ..Default::default() }, - runtimes: vec![common::typegraph::runtimes::TGRuntime::Unknown( - common::typegraph::runtimes::UnknownRuntime { + runtimes: vec![tg_schema::runtimes::TGRuntime::Unknown( + tg_schema::runtimes::UnknownRuntime { name: "wasm".into(), data: Default::default(), }, diff --git a/src/metagen/src/tests/fixtures.rs b/src/metagen/src/tests/fixtures.rs index 6203997af7..4b69d29bcc 100644 --- a/src/metagen/src/tests/fixtures.rs +++ b/src/metagen/src/tests/fixtures.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: MPL-2.0 use crate::interlude::*; -use common::typegraph::*; +use tg_schema::*; pub async fn test_typegraph_1() -> anyhow::Result> { let out = tokio::process::Command::new("cargo") @@ -36,8 +36,8 @@ pub fn test_typegraph_2() -> Typegraph { meta: TypeMeta { ..Default::default() }, - runtimes: vec![common::typegraph::runtimes::TGRuntime::Unknown( - common::typegraph::runtimes::UnknownRuntime { + runtimes: vec![tg_schema::runtimes::TGRuntime::Unknown( + tg_schema::runtimes::UnknownRuntime { name: "wasm".into(), data: Default::default(), }, diff --git a/src/metagen/src/tests/mod.rs b/src/metagen/src/tests/mod.rs index 475ac0a544..cc0a9e49ac 100644 --- a/src/metagen/src/tests/mod.rs +++ b/src/metagen/src/tests/mod.rs @@ -140,7 +140,7 @@ pub async fn e2e_test(cases: Vec) -> anyhow::Result<()> { } #[allow(unused)] -async fn spin_up_typegate() -> anyhow::Result<(tokio::process::Child, common::node::Node)> { +async fn spin_up_typegate() -> anyhow::Result<(tokio::process::Child, typegate_api::Node)> { let tg_port = 7899; let tg_secret = @@ -160,10 +160,10 @@ async fn spin_up_typegate() -> anyhow::Result<(tokio::process::Child, common::no ]) .kill_on_drop(true) .spawn()?; - let node = common::node::Node::new( + let node = typegate_api::Node::new( format!("localhost:{tg_port}"), None, - Some(common::node::BasicAuth { + Some(typegate_api::BasicAuth { username: "admin".into(), password: tg_admin_password.into(), }), diff --git a/src/typegraph/core/src/t.rs b/src/typegraph/core/src/t.rs index 596dc6863b..97c971a319 100644 --- a/src/typegraph/core/src/t.rs +++ b/src/typegraph/core/src/t.rs @@ -12,7 +12,7 @@ use crate::types::TypeRefBuilder; use crate::types::{Named as _, TypeId, TypeRef}; #[cfg(test)] -use common::typegraph::{Injection, InjectionData, SingleValue}; +use tg_schema::{Injection, InjectionData, SingleValue}; pub trait TypeBuilder { fn build(&self) -> Result; diff --git a/src/typegraph/core/src/test_utils.rs b/src/typegraph/core/src/test_utils.rs index 5d8e144a40..8335f83b3e 100644 --- a/src/typegraph/core/src/test_utils.rs +++ b/src/typegraph/core/src/test_utils.rs @@ -21,7 +21,7 @@ impl Default for Effect { pub mod models { use std::collections::BTreeMap; - use common::typegraph::{EffectType, Injection, InjectionData}; + use tg_schema::{EffectType, Injection, InjectionData}; use crate::errors::Result; use crate::t::{self, TypeBuilder}; diff --git a/src/typegraph/core/src/types/sdk/aws.rs b/src/typegraph/core/src/types/sdk/aws.rs index 5412c184ff..03c6ac11dc 100644 --- a/src/typegraph/core/src/types/sdk/aws.rs +++ b/src/typegraph/core/src/types/sdk/aws.rs @@ -28,9 +28,15 @@ pub struct S3PresignPutParams { pub trait Handler { fn register_s3_runtime(data: S3RuntimeData) -> Result; - fn s3_presign_get(runtime: RuntimeId, data: S3PresignGetParams) -> Result; - fn s3_presign_put(runtime: RuntimeId, data: S3PresignPutParams) -> Result; + fn s3_presign_get( + runtime: RuntimeId, + data: S3PresignGetParams, + ) -> Result; + fn s3_presign_put( + runtime: RuntimeId, + data: S3PresignPutParams, + ) -> Result; fn s3_list(runtime: RuntimeId, bucket: String) -> Result; fn s3_upload(runtime: RuntimeId, bucket: String) -> Result; fn s3_upload_all(runtime: RuntimeId, bucket: String) -> Result; -} \ No newline at end of file +} diff --git a/src/typegraph/core/src/types/sdk/core.rs b/src/typegraph/core/src/types/sdk/core.rs index 2b7b68a019..ded5fbccbe 100644 --- a/src/typegraph/core/src/types/sdk/core.rs +++ b/src/typegraph/core/src/types/sdk/core.rs @@ -222,7 +222,9 @@ pub struct FuncParams { pub trait Handler { fn init_typegraph(params: TypegraphInitParams) -> Result<(), super::Error>; - fn serialize_typegraph(params: SerializeParams) -> Result<(String, Vec), super::Error>; + fn serialize_typegraph( + params: SerializeParams, + ) -> Result<(String, Vec), super::Error>; fn with_injection(type_id: TypeId, injection: String) -> Result; fn with_config(type_id: TypeId, config: String) -> Result; fn refb(name: String, attributes: Option) -> Result; @@ -240,13 +242,22 @@ pub trait Handler { fn extend_struct(tpe: TypeId, props: Vec<(String, TypeId)>) -> Result; fn get_type_repr(id: TypeId) -> Result; fn funcb(data: TypeFunc) -> Result; - fn get_transform_data(resolver_input: TypeId, transform_tree: String) -> Result; + fn get_transform_data( + resolver_input: TypeId, + transform_tree: String, + ) -> Result; fn register_policy(pol: Policy) -> Result; fn with_policy(type_id: TypeId, policy_chain: Vec) -> Result; fn get_public_policy() -> Result<(PolicyId, String), super::Error>; fn get_internal_policy() -> Result<(PolicyId, String), super::Error>; - fn register_context_policy(key: String, check: ContextCheck) -> Result<(PolicyId, String), super::Error>; + fn register_context_policy( + key: String, + check: ContextCheck, + ) -> Result<(PolicyId, String), super::Error>; fn rename_type(tpe: TypeId, new_name: String) -> Result; - fn expose(fns: Vec<(String, TypeId)>, default_policy: Option>) -> Result<(), super::Error>; + fn expose( + fns: Vec<(String, TypeId)>, + default_policy: Option>, + ) -> Result<(), super::Error>; fn set_seed(seed: Option) -> Result<(), super::Error>; -} \ No newline at end of file +} diff --git a/src/typegraph/core/src/types/sdk/mod.rs b/src/typegraph/core/src/types/sdk/mod.rs index e238fa894a..c5c41c26c7 100644 --- a/src/typegraph/core/src/types/sdk/mod.rs +++ b/src/typegraph/core/src/types/sdk/mod.rs @@ -1,8 +1,8 @@ // Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. // SPDX-License-Identifier: MPL-2.0 -pub mod utils; -pub mod core; pub mod aws; +pub mod core; pub mod runtimes; +pub mod utils; pub use self::core::Error; diff --git a/src/typegraph/core/src/types/sdk/runtimes.rs b/src/typegraph/core/src/types/sdk/runtimes.rs index 9d58f1a417..ad9f1ff8e5 100644 --- a/src/typegraph/core/src/types/sdk/runtimes.rs +++ b/src/typegraph/core/src/types/sdk/runtimes.rs @@ -297,26 +297,67 @@ pub struct GrpcData { pub trait Handler { fn get_deno_runtime() -> Result; - fn register_deno_func(data: MaterializerDenoFunc, effect: Effect) -> Result; - fn register_deno_static(data: MaterializerDenoStatic, type_id: TypeId) -> Result; - fn get_predefined_deno_func(data: MaterializerDenoPredefined) -> Result; - fn import_deno_function(data: MaterializerDenoImport, effect: Effect) -> Result; + fn register_deno_func( + data: MaterializerDenoFunc, + effect: Effect, + ) -> Result; + fn register_deno_static( + data: MaterializerDenoStatic, + type_id: TypeId, + ) -> Result; + fn get_predefined_deno_func( + data: MaterializerDenoPredefined, + ) -> Result; + fn import_deno_function( + data: MaterializerDenoImport, + effect: Effect, + ) -> Result; fn register_graphql_runtime(data: GraphqlRuntimeData) -> Result; - fn graphql_query(base: BaseMaterializer, data: MaterializerGraphqlQuery) -> Result; - fn graphql_mutation(base: BaseMaterializer, data: MaterializerGraphqlQuery) -> Result; + fn graphql_query( + base: BaseMaterializer, + data: MaterializerGraphqlQuery, + ) -> Result; + fn graphql_mutation( + base: BaseMaterializer, + data: MaterializerGraphqlQuery, + ) -> Result; fn register_http_runtime(data: HttpRuntimeData) -> Result; - fn http_request(base: BaseMaterializer, data: MaterializerHttpRequest) -> Result; + fn http_request( + base: BaseMaterializer, + data: MaterializerHttpRequest, + ) -> Result; fn register_python_runtime() -> Result; - fn from_python_lambda(base: BaseMaterializer, data: MaterializerPythonLambda) -> Result; - fn from_python_def(base: BaseMaterializer, data: MaterializerPythonDef) -> Result; - fn from_python_module(base: BaseMaterializer, data: MaterializerPythonModule) -> Result; - fn from_python_import(base: BaseMaterializer, data: MaterializerPythonImport) -> Result; + fn from_python_lambda( + base: BaseMaterializer, + data: MaterializerPythonLambda, + ) -> Result; + fn from_python_def( + base: BaseMaterializer, + data: MaterializerPythonDef, + ) -> Result; + fn from_python_module( + base: BaseMaterializer, + data: MaterializerPythonModule, + ) -> Result; + fn from_python_import( + base: BaseMaterializer, + data: MaterializerPythonImport, + ) -> Result; fn register_random_runtime(data: RandomRuntimeData) -> Result; - fn create_random_mat(base: BaseMaterializer, data: MaterializerRandom) -> Result; + fn create_random_mat( + base: BaseMaterializer, + data: MaterializerRandom, + ) -> Result; fn register_wasm_reflected_runtime(data: WasmRuntimeData) -> Result; - fn from_wasm_reflected_func(base: BaseMaterializer, data: MaterializerWasmReflectedFunc) -> Result; + fn from_wasm_reflected_func( + base: BaseMaterializer, + data: MaterializerWasmReflectedFunc, + ) -> Result; fn register_wasm_wire_runtime(data: WasmRuntimeData) -> Result; - fn from_wasm_wire_handler(base: BaseMaterializer, data: MaterializerWasmWireHandler) -> Result; + fn from_wasm_wire_handler( + base: BaseMaterializer, + data: MaterializerWasmWireHandler, + ) -> Result; fn register_prisma_runtime(data: PrismaRuntimeData) -> Result; fn prisma_find_unique(runtime: RuntimeId, model: TypeId) -> Result; fn prisma_find_many(runtime: RuntimeId, model: TypeId) -> Result; @@ -330,18 +371,43 @@ pub trait Handler { fn prisma_upsert_one(runtime: RuntimeId, model: TypeId) -> Result; fn prisma_delete_one(runtime: RuntimeId, model: TypeId) -> Result; fn prisma_delete_many(runtime: RuntimeId, model: TypeId) -> Result; - fn prisma_execute(runtime: RuntimeId, query: String, param: TypeId, effect: Effect) -> Result; - fn prisma_query_raw(runtime: RuntimeId, query: String, out: TypeId, param: Option) -> Result; + fn prisma_execute( + runtime: RuntimeId, + query: String, + param: TypeId, + effect: Effect, + ) -> Result; + fn prisma_query_raw( + runtime: RuntimeId, + query: String, + out: TypeId, + param: Option, + ) -> Result; fn prisma_link(data: PrismaLinkData) -> Result; fn prisma_migration(operation: PrismaMigrationOperation) -> Result; fn register_temporal_runtime(data: TemporalRuntimeData) -> Result; - fn generate_temporal_operation(runtime: RuntimeId, data: TemporalOperationData) -> Result; - fn register_typegate_materializer(operation: TypegateOperation) -> Result; - fn register_typegraph_materializer(operation: TypegraphOperation) -> Result; - fn register_substantial_runtime(data: SubstantialRuntimeData) -> Result; - fn generate_substantial_operation(runtime: RuntimeId, data: SubstantialOperationData) -> Result; + fn generate_temporal_operation( + runtime: RuntimeId, + data: TemporalOperationData, + ) -> Result; + fn register_typegate_materializer( + operation: TypegateOperation, + ) -> Result; + fn register_typegraph_materializer( + operation: TypegraphOperation, + ) -> Result; + fn register_substantial_runtime( + data: SubstantialRuntimeData, + ) -> Result; + fn generate_substantial_operation( + runtime: RuntimeId, + data: SubstantialOperationData, + ) -> Result; fn register_kv_runtime(data: KvRuntimeData) -> Result; - fn kv_operation(base: BaseMaterializer, data: KvMaterializer) -> Result; + fn kv_operation( + base: BaseMaterializer, + data: KvMaterializer, + ) -> Result; fn register_grpc_runtime(data: GrpcRuntimeData) -> Result; fn call_grpc_method(runtime: RuntimeId, data: GrpcData) -> Result; -} \ No newline at end of file +} diff --git a/src/typegraph/core/src/types/sdk/utils.rs b/src/typegraph/core/src/types/sdk/utils.rs index 76c275c3aa..c4633a6a22 100644 --- a/src/typegraph/core/src/types/sdk/utils.rs +++ b/src/typegraph/core/src/types/sdk/utils.rs @@ -52,12 +52,26 @@ pub trait Handler { fn add_auth(data: Auth) -> Result; fn add_raw_auth(data: String) -> Result; fn oauth2(service_name: String, scopes: String) -> Result; - fn oauth2_without_profiler(service_name: String, scopes: String) -> Result; - fn oauth2_with_extended_profiler(service_name: String, scopes: String, extension: String) -> Result; - fn oauth2_with_custom_profiler(service_name: String, scopes: String, profiler: TypeId) -> Result; + fn oauth2_without_profiler( + service_name: String, + scopes: String, + ) -> Result; + fn oauth2_with_extended_profiler( + service_name: String, + scopes: String, + extension: String, + ) -> Result; + fn oauth2_with_custom_profiler( + service_name: String, + scopes: String, + profiler: TypeId, + ) -> Result; fn gql_deploy_query(params: QueryDeployParams) -> Result; fn gql_remove_query(tg_name: Vec) -> Result; fn gql_ping_query() -> Result; fn metagen_exec(config: FdkConfig) -> Result, super::Error>; - fn metagen_write_files(items: Vec, typegraph_dir: String) -> Result<(), super::Error>; -} \ No newline at end of file + fn metagen_write_files( + items: Vec, + typegraph_dir: String, + ) -> Result<(), super::Error>; +} diff --git a/src/typegraph/schema/Cargo.toml b/src/typegraph/schema/Cargo.toml index 765cca78a7..7ad1b411d5 100644 --- a/src/typegraph/schema/Cargo.toml +++ b/src/typegraph/schema/Cargo.toml @@ -23,4 +23,3 @@ serde_with.workspace = true # ds indexmap.workspace = true -