From d3658fd6f097db8160927dd0e236781a5c0cd14e Mon Sep 17 00:00:00 2001 From: Sandipsinh Rathod Date: Sun, 22 Dec 2024 15:28:50 -0500 Subject: [PATCH] fix add_fields population --- Cargo.lock | 1 + Cargo.toml | 1 + src/config/config.rs | 3 +- src/config/fixargs.rs | 111 ++++++++++++++++++++++++---------- src/config/handle_files.rs | 6 +- src/config/mod.rs | 4 +- src/config/schema_document.rs | 101 +++++++++++++++++++++++++++++++ src/config/to_config.rs | 9 +++ src/config/to_wit.rs | 44 +++++++------- src/config/wit_types.rs | 1 - src/merge_right.rs | 2 +- src/proto.rs | 11 ++-- 12 files changed, 227 insertions(+), 67 deletions(-) create mode 100644 src/config/schema_document.rs create mode 100644 src/config/to_config.rs diff --git a/Cargo.lock b/Cargo.lock index 55f62d5..035ed5e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ "anyhow", "base64", "convert_case", + "derive_setters", "lazy_static", "macros", "oapi", diff --git a/Cargo.toml b/Cargo.toml index 4c150e6..96cc657 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ lazy_static = "1.5.0" base64 = "0.22.1" strum_macros = "0.26.4" macros = {path = "macros"} +derive_setters = "0.1.6" [workspace] members = [".", "macros"] diff --git a/src/config/config.rs b/src/config/config.rs index ff1ec42..215fa92 100644 --- a/src/config/config.rs +++ b/src/config/config.rs @@ -42,7 +42,6 @@ impl Ord for Interface { pub struct Record { pub name: String, pub fields: BTreeSet, - pub added_fields: BTreeSet, } impl PartialOrd for Record { @@ -85,7 +84,7 @@ pub struct Parameter { #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, MergeRight)] pub struct Field { pub name: String, - pub field_type: WitType, + pub field_type: String, } impl PartialOrd for Field { diff --git a/src/config/fixargs.rs b/src/config/fixargs.rs index 85d270b..8a51934 100644 --- a/src/config/fixargs.rs +++ b/src/config/fixargs.rs @@ -1,45 +1,101 @@ use std::collections::BTreeSet; use base64::Engine; use tailcall_valid::{Valid, Validator}; -use crate::config::config::{Config, Field, Interface, Record}; +use crate::config::schema_document::{SchemaDocument, Field, Interface, Record}; use crate::config::wit_types::WitType; use crate::merge_right::MergeRight; use crate::tryfold::TryFold; -pub fn fix_args(config: Config) -> Valid { +pub fn fix_args(config: SchemaDocument) -> Valid { Valid::succeed(config) .and_then(|mut config| { - Valid::from_iter(config.interfaces.iter(), |interface| { - Valid::from_iter(interface.records.iter(), |record| { - Valid::from_iter(record.fields.iter(), |field| { + Valid::from_iter(config.interfaces.iter().cloned().collect::>(), |mut interface| { + Valid::from_iter(interface.records.iter().cloned(), |mut record| { + Valid::from_iter(record.fields.iter().cloned(), |field| { if !field.field_type.is_kind_of_primitive() { fix_field() - .try_fold(&(&config, interface, record, &field, &field.field_type), interface.clone()) - .and_then(|new_interface| { - Valid::succeed(Some(new_interface)) + .try_fold(&(&config, &interface, &record, &field, &field.field_type), Field::default()) + .and_then(|field| { + Valid::succeed(Some(field)) }) - } else { + }else { Valid::succeed(None) } - }) - }) - }).and_then(|x| { - let x = x.into_iter().flatten().into_iter().flatten().filter_map(|x| x).collect::>(); + }).and_then(|v| { + let fields = v.into_iter().filter_map(|x| x).collect(); + record.added_fields = fields; - let mut map = BTreeSet::new(); - for interface in x { - map.insert(interface); + Valid::succeed(record) + }) + }).and_then(|records| { + interface.records = records.into_iter().collect(); + Valid::succeed(interface) + }) + }).and_then(|interfaces| { + config.interfaces = interfaces.into_iter().collect(); + /*for interface in interfaces { + if let Some(interface) = config.interfaces.iter().find(|i| i.name == interface.name) { + for record in interface.records { + if let Some(mut record) = interface.records.iter().find(|r| r.name == record.name).cloned() { + for field in record.fields { + if let Some(field) = record.fields.iter().find(|f| f.name == field.name) { + let mut new_field = field.clone(); + new_field.field_type = field.field_type.clone().merge_right(new_field.field_type.clone()); + record.fields.remove(&field); + record.fields.insert(new_field); + } + } + } + } + }else { + config.interfaces.insert(interface); + } + }*/ +/* let mut new_interfaces = BTreeSet::new(); + for mut interface in config.interfaces { + let mut new_records = BTreeSet::new(); + for mut record in interface.records { + let mut new_fields = BTreeSet::new(); + for mut field in record.fields { + let mut new_field = interfaces + .iter() + .find(|i| i.name == interface.name).and_then(|interface| interface.records.iter().find(|r| r.name == record.name).and_then(|record|record.fields.iter().find(|f| f.name == field.name))) + .unwrap_or(&field) + .clone(); + + new_field = new_field.merge_right(field); + new_fields.insert(new_field); + } + record.fields = new_fields; + new_records.insert(record); + } + interface.records = new_records; + new_interfaces.insert(interface); } - config.interfaces = config.interfaces.merge_right(map); + config.interfaces = new_interfaces;*/ + // config.interfaces = config.interfaces.merge_right(map); Valid::succeed(config) }) }) } -fn fix_field<'a>() -> TryFold<'a, (&'a Config, &'a Interface, &'a Record, &'a Field, &'a WitType), Interface, anyhow::Error> { - TryFold::<(&Config, &Interface, &Record, &Field, &WitType), Interface, anyhow::Error>::new(move |(config, interface, rec, field, wit), mut o| { +/* +interface types { + + record error { error: { message: string, details: list<{ field: string, message: string }>, code: string } } + record todo { completed: bool, created-at: string, description: string, due-date: string, id: string, title: string, updated-at: string, user-id: string } + record todo-create { description: string, due-date: string, title: string, user-id: string } + record todo-list { data: list<{ id: string, user-id: string, title: string, due-date: string, created-at: string, updated-at: string, completed: bool, description: string }>, metadata: { total: s32, offset: s32, limit: s32 } } + record todo-response { data: { id: string, user-id: string, title: string, due-date: string, created-at: string, updated-at: string, completed: bool, description: string } } + record todo-update { completed: bool, description: string, due-date: string, title: string } + +} +*/ + +fn fix_field<'a>() -> TryFold<'a, (&'a SchemaDocument, &'a Interface, &'a Record, &'a Field, &'a WitType), Field, anyhow::Error> { + TryFold::<(&SchemaDocument, &Interface, &Record, &Field, &WitType), Field, anyhow::Error>::new(move |(config, interface, rec, field, wit), mut o| { match &wit { WitType::Option(x) => { return fix_field().try_fold(&(*config, *interface, *rec, *field, x), o); @@ -63,30 +119,23 @@ fn fix_field<'a>() -> TryFold<'a, (&'a Config, &'a Interface, &'a Record, &'a Fi WitType::Tuple(x) => { // TODO: Fix the possible conflicts here return Valid::from_iter(x.iter(), |x| fix_field().try_fold(&(*config, *interface, *rec, *field, x), o.clone())) - .and_then(|v| Valid::succeed(v.into_iter().fold((*interface).clone(), |mut a, b| { - a.records.extend(b.records); - a + .and_then(|v| Valid::succeed(v.into_iter().fold((*field).clone(), |mut a, b| { + a.merge_right(b) }))); } WitType::Record(records) => { let field_name = if field.name.is_empty() { base64::prelude::BASE64_STANDARD.encode(field.name.as_bytes()) - }else { + } else { field.name.clone() }; let name = format!("{}-{}", rec.name, field_name); - + let new_field = Field { name, field_type: WitType::Record(records.clone()), }; - let mut rec = (*rec).clone(); - rec.added_fields.insert(new_field); - // let mut filtered_records = o.records.into_iter().filter(|r| r.name == rec.name).collect::>(); - // filtered_records.push(rec); - o.records.remove(&rec); - o.records.insert(rec); - Valid::succeed(o) + Valid::succeed(new_field) } // Ideally this case should never happen, // but we should always throw an error to avoid infinite recursion diff --git a/src/config/handle_files.rs b/src/config/handle_files.rs index b3f0e0d..b68b8ee 100644 --- a/src/config/handle_files.rs +++ b/src/config/handle_files.rs @@ -1,12 +1,12 @@ use std::collections::BTreeSet; use anyhow::{anyhow, Error}; use tailcall_valid::{Valid, Validator}; -use crate::config::config::{Config, Field, Interface, Record}; +use crate::config::schema_document::{SchemaDocument, Field, Interface, Record}; use crate::config::wit_types::WitType; use crate::ser::OpenApiSpec; -pub fn handle_types(config: Config, spec: &OpenApiSpec) -> Valid { - Valid::succeed(config).and_then(|mut config: Config| { +pub fn handle_types(config: SchemaDocument, spec: &OpenApiSpec) -> Valid { + Valid::succeed(config).and_then(|mut config: SchemaDocument| { Valid::from_option(spec.components.as_ref(), anyhow!("Components are required")) .and_then(|v| Valid::from_option(v.schemas.as_ref(), anyhow!("Schemas are required"))) .and_then(|schemas| { diff --git a/src/config/mod.rs b/src/config/mod.rs index 193fee1..8a18149 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,5 +1,7 @@ -pub mod config; +pub mod schema_document; pub mod wit_types; pub mod to_wit; pub mod fixargs; pub mod handle_files; +pub mod config; +pub mod to_config; diff --git a/src/config/schema_document.rs b/src/config/schema_document.rs new file mode 100644 index 0000000..1d9299f --- /dev/null +++ b/src/config/schema_document.rs @@ -0,0 +1,101 @@ +use std::collections::BTreeSet; +use serde::{Deserialize, Serialize}; +use macros::MergeRight; +use crate::config::wit_types::WitType; + +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, MergeRight)] +pub struct SchemaDocument { + pub package: String, + pub interfaces: BTreeSet, + pub world: World, +} + +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, MergeRight)] +pub struct World { + pub name: String, + pub uses: Vec, + pub imports: Vec, + pub exports: Vec, +} + +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, MergeRight, derive_setters::Setters)] +pub struct Interface { + pub name: String, + pub records: BTreeSet, + pub uses: Vec, + pub functions: Vec, +} + +impl PartialOrd for Interface { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.name.cmp(&other.name)) + } +} + +impl Ord for Interface { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.name.cmp(&other.name) + } +} + +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, MergeRight)] +pub struct Record { + pub name: String, + pub fields: BTreeSet, + pub added_fields: BTreeSet, +} + +impl PartialOrd for Record { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.name.cmp(&other.name)) + } +} + +impl Ord for Record { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.name.cmp(&other.name) + } +} + +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, MergeRight)] +pub struct UseStatement { + pub name: String, + pub items: Vec, +} + +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, MergeRight)] +pub struct Function { + pub name: String, + pub parameters: Vec, + pub return_type: ReturnTy, +} + +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, MergeRight)] +pub struct ReturnTy { + pub return_type: String, + pub error_type: String, +} + +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, MergeRight)] +pub struct Parameter { + pub name: String, + pub parameter_type: String, +} + +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, MergeRight)] +pub struct Field { + pub name: String, + pub field_type: WitType, +} + +impl PartialOrd for Field { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.name.cmp(&other.name)) + } +} + +impl Ord for Field { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.name.cmp(&other.name) + } +} diff --git a/src/config/to_config.rs b/src/config/to_config.rs new file mode 100644 index 0000000..47143bb --- /dev/null +++ b/src/config/to_config.rs @@ -0,0 +1,9 @@ +use tailcall_valid::Valid; +use crate::config::config::Config; +use crate::config::schema_document::SchemaDocument; + +impl SchemaDocument { + pub fn to_config(&self) -> Valid { + todo!() + } +} \ No newline at end of file diff --git a/src/config/to_wit.rs b/src/config/to_wit.rs index ab658f1..ea9aaaa 100644 --- a/src/config/to_wit.rs +++ b/src/config/to_wit.rs @@ -1,4 +1,4 @@ -use crate::config::config::{Config, Field, Function, Interface, Parameter, Record, ReturnTy, UseStatement, World}; +use crate::config::schema_document::{SchemaDocument, Field, Function, Interface, Parameter, Record, ReturnTy, UseStatement, World}; use crate::config::wit_types::WitType; use convert_case::{Case, Casing}; use std::collections::HashSet; @@ -41,8 +41,8 @@ fn generate_wit_name(name: &str) -> String { final_name } -impl ToWit for Config { - fn to_wit(&self) -> String { +impl SchemaDocument { + pub fn to_wit(&self) -> String { let package = format!("package {};\n", generate_wit_name(&self.package)); let world = self.world.to_wit(); let interfaces = self @@ -56,8 +56,8 @@ impl ToWit for Config { } } -impl ToWit for World { - fn to_wit(&self) -> String { +impl World { + pub fn to_wit(&self) -> String { if self == &World::default() { return String::new(); } @@ -93,8 +93,8 @@ impl ToWit for World { } } -impl ToWit for Interface { - fn to_wit(&self) -> String { +impl Interface { + pub fn to_wit(&self) -> String { let uses = self .uses .iter() @@ -126,8 +126,8 @@ impl ToWit for Interface { } } -impl ToWit for Record { - fn to_wit(&self) -> String { +impl Record { + pub fn to_wit(&self) -> String { let fields = self .fields .iter() @@ -139,8 +139,8 @@ impl ToWit for Record { } } -impl ToWit for Field { - fn to_wit(&self) -> String { +impl Field { + pub fn to_wit(&self) -> String { format!( "{}: {}", generate_wit_name(&self.name), @@ -150,8 +150,8 @@ impl ToWit for Field { } -impl ToWit for Function { - fn to_wit(&self) -> String { +impl Function { + pub fn to_wit(&self) -> String { let params = self .parameters .iter() @@ -174,8 +174,8 @@ impl ToWit for Function { } } -impl ToWit for ReturnTy { - fn to_wit(&self) -> String { +impl ReturnTy { + pub fn to_wit(&self) -> String { if self.error_type.is_empty() { self.return_type.clone() } else { @@ -188,8 +188,8 @@ impl ToWit for ReturnTy { } } -impl ToWit for Parameter { - fn to_wit(&self) -> String { +impl Parameter { + pub fn to_wit(&self) -> String { format!( "{}: {}", generate_wit_name(&self.name), @@ -198,8 +198,8 @@ impl ToWit for Parameter { } } -impl ToWit for UseStatement { - fn to_wit(&self) -> String { +impl UseStatement { + pub fn to_wit(&self) -> String { format!( "use {}.{{{}}};", generate_wit_name(&self.name), @@ -212,8 +212,8 @@ impl ToWit for UseStatement { } } -impl ToWit for WitType { - fn to_wit(&self) -> String { +impl WitType { + pub fn to_wit(&self) -> String { match self { WitType::Bool => "bool".to_string(), WitType::U8 => "u8".to_string(), @@ -274,7 +274,7 @@ impl ToWit for WitType { .join(", ") ), WitType::Handle(name) => format!("handle<{}>", generate_wit_name(name)), - WitType::TypeAlias(name, inner) => format!("type {} = {}", generate_wit_name(name), inner.to_wit()), + WitType::TypeAlias(name, inner) => format!("type {} = {}", generate_wit_name(name), inner.to_wit()), } } } diff --git a/src/config/wit_types.rs b/src/config/wit_types.rs index 9841711..26705af 100644 --- a/src/config/wit_types.rs +++ b/src/config/wit_types.rs @@ -1,6 +1,5 @@ use serde::{Deserialize, Serialize}; use tailcall_valid::{Valid, Validator}; -use crate::config::to_wit::ToWit; use crate::ser::{OpenApiSpec, Schema}; diff --git a/src/merge_right.rs b/src/merge_right.rs index 025ce41..150cf8d 100644 --- a/src/merge_right.rs +++ b/src/merge_right.rs @@ -25,7 +25,7 @@ impl MergeRight for Vec { impl MergeRight for BTreeSet where - V: Ord, + V: Ord + MergeRight, { fn merge_right(self, mut other: Self) -> Self { other.extend(self); diff --git a/src/proto.rs b/src/proto.rs index 03ed445..acf8a2e 100644 --- a/src/proto.rs +++ b/src/proto.rs @@ -1,13 +1,13 @@ use anyhow::Error; use tailcall_valid::{Valid, Validator}; -use crate::config::config::Config; +use crate::config::schema_document::SchemaDocument; use crate::config::fixargs::fix_args; use crate::config::handle_files::handle_types; use crate::ser::OpenApiSpec; -fn to_config(spec: OpenApiSpec) -> Valid { - Valid::succeed(Config::default()) +fn to_config(spec: OpenApiSpec) -> Valid { + Valid::succeed(SchemaDocument::default()) .and_then(|config| handle_types(config, &spec)) .and_then(|config| fix_args(config)) } @@ -16,7 +16,6 @@ fn to_config(spec: OpenApiSpec) -> Valid { mod t { use tailcall_valid::Validator; - use crate::config::to_wit::ToWit; use crate::proto::to_config; use crate::ser::OpenApiSpec; @@ -30,8 +29,8 @@ mod t { match res.as_mut() { Ok(v) => { println!("{}", serde_json::to_string_pretty(v).unwrap()); - // v.package = "api:todos@1.0.0".to_string(); - // println!("{}", v.to_wit()); + v.package = "api:todos@1.0.0".to_string(); + println!("{}", v.to_wit()); // let mut resolve = Resolve::new(); // resolve.push_str("foox.wit", &v.to_wit()).expect("TODO: panic message`"); // println!("{:#?}", resolve);