From 7f7f30583e8646aa3ece423f47f4cb9a9d6cdf07 Mon Sep 17 00:00:00 2001 From: Kurt Wolf Date: Sat, 14 Sep 2024 23:20:53 -0700 Subject: [PATCH] add support for additional props / HashMap --- core/src/extractor/record.rs | 20 +++++++++++++++++--- libninja/src/rust/client.rs | 7 ++++--- libninja/src/rust/codegen/example.rs | 5 +++-- libninja/src/rust/codegen/ty.rs | 10 ++++++++++ mir/src/ty.rs | 3 +++ 5 files changed, 37 insertions(+), 8 deletions(-) diff --git a/core/src/extractor/record.rs b/core/src/extractor/record.rs index 1e47cae..c07acd9 100644 --- a/core/src/extractor/record.rs +++ b/core/src/extractor/record.rs @@ -3,8 +3,8 @@ use std::collections::{BTreeMap, HashSet}; use convert_case::{Case, Casing}; /// Records are the "model"s of the MIR world. model is a crazy overloaded word though. use openapiv3::{ - ObjectType, OpenAPI, ReferenceOr, RefOr, RefOrMap, Schema, SchemaData, SchemaKind, - SchemaReference, StringType, Type, + AdditionalProperties, ObjectType, OpenAPI, RefOr, RefOrMap, ReferenceOr, Schema, SchemaData, + SchemaKind, SchemaReference, StringType, Type, }; use hir::{HirField, HirSpec, NewType, Record, StrEnum, Struct}; @@ -88,7 +88,21 @@ pub fn extract_schema( let name = name.to_string(); let k = &schema.kind; - if let SchemaKind::Type(Type::Object(ObjectType { properties, .. })) = k { + if let SchemaKind::Type(Type::Object(ObjectType { + properties, + additional_properties, + .. + })) = k + { + if properties.is_empty() && additional_properties.is_some() { + let p = additional_properties.as_ref().unwrap(); + return match p { + AdditionalProperties::Any(_) => Some(Ty::HashMap(Box::new(Ty::Any(None)))), + AdditionalProperties::Schema(s) => { + Some(Ty::HashMap(Box::new(schema_ref_to_ty(s, spec)))) + } + }; + } let fields = extract_fields(properties, schema, spec, hir); let s = Struct { name: name.clone(), diff --git a/libninja/src/rust/client.rs b/libninja/src/rust/client.rs index 5eddcab..953c676 100644 --- a/libninja/src/rust/client.rs +++ b/libninja/src/rust/client.rs @@ -3,8 +3,7 @@ use proc_macro2::TokenStream; use quote::{quote, ToTokens}; use hir::{ - AuthLocation, AuthStrategy, HirSpec, Language, Operation, qualified_env_var - , ServerStrategy, + qualified_env_var, AuthLocation, AuthStrategy, HirSpec, Language, Operation, ServerStrategy, }; use ln_core::PackageConfig; use mir::{Class, Field, Visibility}; @@ -139,7 +138,9 @@ pub fn struct_Client(spec: &HirSpec, opt: &PackageConfig) -> Class ..Function::default() }); } - class_methods.push(build_Client_new_with(spec, opt)); + if spec.has_security() { + class_methods.push(build_Client_new_with(spec, opt)); + } Class { name: opt.client_name().to_rust_struct(), instance_fields, diff --git a/libninja/src/rust/codegen/example.rs b/libninja/src/rust/codegen/example.rs index 1f61332..8802ae3 100644 --- a/libninja/src/rust/codegen/example.rs +++ b/libninja/src/rust/codegen/example.rs @@ -7,9 +7,9 @@ use ln_macro::rfunction; use mir::{File, Import, Ty}; use mir_rust::format_code; -use crate::PackageConfig; -use crate::rust::codegen::{ToRustCode, ToRustType}; use crate::rust::codegen::ToRustIdent; +use crate::rust::codegen::{ToRustCode, ToRustType}; +use crate::PackageConfig; pub trait ToRustExample { fn to_rust_example(&self, spec: &HirSpec) -> anyhow::Result; @@ -184,6 +184,7 @@ pub fn to_rust_example_value( Ty::Date { .. } => quote!(chrono::Utc::now().date_naive()), Ty::DateTime { .. } => quote!(chrono::Utc::now()), Ty::Currency { .. } => quote!(rust_decimal_macros::dec!(100.01)), + Ty::HashMap(_) => quote!(std::collections::HashMap::new()), }; Ok(s) } diff --git a/libninja/src/rust/codegen/ty.rs b/libninja/src/rust/codegen/ty.rs index 1f4e44e..56d8606 100644 --- a/libninja/src/rust/codegen/ty.rs +++ b/libninja/src/rust/codegen/ty.rs @@ -33,6 +33,10 @@ impl ToRustType for Ty { Ty::Date { .. } => quote!(chrono::NaiveDate), Ty::DateTime { .. } => quote!(chrono::DateTime), Ty::Currency { .. } => quote!(rust_decimal::Decimal), + Ty::HashMap(inner) => { + let inner = inner.to_rust_type(); + quote!(std::collections::HashMap) + } } } @@ -56,6 +60,10 @@ impl ToRustType for Ty { Ty::Date { .. } => quote!(chrono::NaiveDate), Ty::DateTime { .. } => quote!(chrono::DateTime), Ty::Currency { .. } => quote!(rust_decimal::Decimal), + Ty::HashMap(inner) => { + let inner = inner.to_rust_type(); + quote!(std::collections::HashMap) + } } } @@ -84,6 +92,7 @@ impl ToRustType for Ty { Ty::Date { .. } => true, Ty::DateTime => true, Ty::Currency { .. } => true, + Ty::HashMap(_) => true, } } @@ -103,6 +112,7 @@ impl ToRustType for Ty { Ty::Date { .. } => true, Ty::DateTime => true, Ty::Currency { .. } => true, + Ty::HashMap(inner) => inner.implements_dummy(spec), } } } diff --git a/mir/src/ty.rs b/mir/src/ty.rs index 2529f0b..ab12bee 100644 --- a/mir/src/ty.rs +++ b/mir/src/ty.rs @@ -25,6 +25,7 @@ pub enum Ty { Float, Boolean, Array(Box), + HashMap(Box), // OpenAPI name for the model. Hasn't been converted to a language type (e.g. cased, sanitized) Model(String), Unit, @@ -51,6 +52,7 @@ impl Ty { match self { Ty::Model(name) => Some(name), Ty::Array(ty) => ty.inner_model(), + Ty::HashMap(ty) => ty.inner_model(), _ => None, } } @@ -73,6 +75,7 @@ impl Ty { Ty::Float => true, Ty::Boolean => true, Ty::Array(_) => false, + Ty::HashMap(_) => false, Ty::Model(_) => false, Ty::Any(_) => false, Ty::Unit => true,