Skip to content

Commit

Permalink
Add (optional) support for time 0.3 (#21)
Browse files Browse the repository at this point in the history
  • Loading branch information
msrd0 authored Jan 1, 2022
1 parent ba2a0a9 commit 95c2aa2
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 33 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ serde_json = "1.0"

# optional dependencies / features
chrono = { version = "0.4.19", default-features = false, optional = true }
uuid = { version = "0.8.2" , optional = true }
time = { version = "0.3.4", features = ["serde-human-readable"], optional = true }
uuid = { version = "0.8.2", optional = true }

[dev-dependencies]
paste = "1.0"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ This repository contains the following crates:

# openapi_type

This crate gives static type information for primitives and commonly used types from the standard library and a few other commonly used libraries like `chrono` and `uuid`. Also, it provides a derive macro for structs and enums to gain access to their static type information at runtime.
This crate gives static type information for primitives and commonly used types from the standard library and a few other commonly used libraries like `chrono`, `time` and `uuid`. Also, it provides a derive macro for structs and enums to gain access to their static type information at runtime.

The core of this crate is the [`OpenapiType`][__link0] trait. It has one static function, [`schema`][__link1], which returns an [`OpenapiSchema`][__link2]. This assembles the static type information in a way that is convenient to use for a generated OpenAPI specification, but can also be utilized in other use cases as well.

Expand Down
2 changes: 1 addition & 1 deletion crates-io.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# openapi_type [![Rust 1.49+](https://img.shields.io/badge/rustc-1.49+-orange.svg)](https://blog.rust-lang.org/2020/12/31/Rust-1.49.0.html) [![License Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0) [![GitHub](https://img.shields.io/badge/Code-On%20Github-blue?logo=GitHub)](https://github.com/msrd0/openapi_type)

This crate gives static type information for primitives and commonly used types from the standard library and a few other commonly used libraries like `chrono` and `uuid`. Also, it provides a derive macro for structs and enums to gain access to their static type information at runtime.
This crate gives static type information for primitives and commonly used types from the standard library and a few other commonly used libraries like `chrono`, `time` and `uuid`. Also, it provides a derive macro for structs and enums to gain access to their static type information at runtime.

The core of this crate is the [`OpenapiType`][__link0] trait. It has one static function, [`schema`][__link1], which returns an [`OpenapiSchema`][__link2]. This assembles the static type information in a way that is convenient to use for a generated OpenAPI specification, but can also be utilized in other use cases as well.

Expand Down
24 changes: 15 additions & 9 deletions src/impls.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
use crate::{OpenapiSchema, OpenapiType};
#[cfg(feature = "chrono")]
use chrono::{offset::TimeZone, Date, DateTime, NaiveDate, NaiveDateTime};
use indexmap::{IndexMap, IndexSet};
use openapiv3::{
AdditionalProperties, ArrayType, IntegerType, NumberFormat, NumberType, ObjectType, ReferenceOr, SchemaKind,
Expand All @@ -12,13 +10,11 @@ use std::{
hash::BuildHasher,
num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}
};
#[cfg(feature = "uuid")]
use uuid::Uuid;

macro_rules! impl_openapi_type {
($($ty:ident $(<$($generic:ident : $bound:path),+>)*),* => $schema:expr) => {
($($($ty:ident)::+ $(<$($generic:ident : $bound:path),+>)?),* => $schema:expr) => {
$(
impl $(<$($generic : $bound),+>)* OpenapiType for $ty $(<$($generic),+>)* {
impl $(<$($generic : $bound),+>)? OpenapiType for $($ty)::+ $(<$($generic),+>)? {
fn schema() -> OpenapiSchema {
$schema
}
Expand Down Expand Up @@ -101,17 +97,27 @@ fn str_schema(format: VariantOrUnknownOrEmpty<StringFormat>) -> OpenapiSchema {
impl_openapi_type!(String, str => str_schema(VariantOrUnknownOrEmpty::Empty));

#[cfg(feature = "chrono")]
impl_openapi_type!(Date<T: TimeZone>, NaiveDate => {
impl_openapi_type!(chrono::Date<T: chrono::TimeZone>, chrono::NaiveDate => {
str_schema(VariantOrUnknownOrEmpty::Item(StringFormat::Date))
});

#[cfg(feature = "time")]
impl_openapi_type!(time::Date => {
str_schema(VariantOrUnknownOrEmpty::Item(StringFormat::Date))
});

#[cfg(feature = "chrono")]
impl_openapi_type!(DateTime<T: TimeZone>, NaiveDateTime => {
impl_openapi_type!(chrono::DateTime<T: chrono::TimeZone>, chrono::NaiveDateTime => {
str_schema(VariantOrUnknownOrEmpty::Item(StringFormat::DateTime))
});

#[cfg(feature = "time")]
impl_openapi_type!(time::OffsetDateTime, time::PrimitiveDateTime => {
str_schema(VariantOrUnknownOrEmpty::Item(StringFormat::DateTime))
});

#[cfg(feature = "uuid")]
impl_openapi_type!(Uuid => {
impl_openapi_type!(uuid::Uuid => {
str_schema(VariantOrUnknownOrEmpty::Unknown("uuid".to_owned()))
});

Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
#![cfg_attr(feature = "cargo-clippy", allow(clippy::tabs_in_doc_comments))]
#![doc = r##"
This crate gives static type information for primitives and commonly used types from the standard
library and a few other commonly used libraries like `chrono` and `uuid`. Also, it provides a
derive macro for structs and enums to gain access to their static type information at runtime.
library and a few other commonly used libraries like `chrono`, `time` and `uuid`. Also, it provides
a derive macro for structs and enums to gain access to their static type information at runtime.
The core of this crate is the [`OpenapiType`] trait. It has one static function,
[`schema`](OpenapiType::schema), which returns an [`OpenapiSchema`]. This assembles the static
Expand Down
47 changes: 28 additions & 19 deletions tests/std_types.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,24 @@
#[cfg(feature = "chrono")]
use chrono::{Date, DateTime, FixedOffset, NaiveDate, NaiveDateTime, Utc};
use indexmap::{IndexMap, IndexSet};
use openapi_type::OpenapiType;
use serde_json::Value;
use std::{
collections::{BTreeMap, BTreeSet, HashMap, HashSet},
num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}
};
#[cfg(feature = "uuid")]
use uuid::Uuid;

macro_rules! test_type {
($($ty:ident $(<$($generic:ident),+>)*),* = $json:tt) => {
paste::paste! { $(
#[test]
fn [< $ty:lower $($(_ $generic:lower)+)* >]() {
let schema = <$ty $(<$($generic),+>)* as OpenapiType>::schema();
let schema = openapi_type::OpenapiSchema::into_schema(schema);
let schema_json = serde_json::to_value(&schema).unwrap();
let expected = serde_json::json!($json);
pretty_assertions::assert_eq!(schema_json, expected);
}
)* }
($($($ty:ident)::+ $(<$($($generic:ident)::+),+>)?),* = $json:tt) => {
paste::paste! {
$(
#[test]
fn [<$($ty:lower)_+ $($($(_$generic:lower)+)+)? >]() {
let schema = <$($ty)::+ $(<$($($generic)::+),+>)? as OpenapiType>::schema();
let schema = openapi_type::OpenapiSchema::into_schema(schema);
let schema_json = serde_json::to_value(&schema).unwrap();
let expected = serde_json::json!($json);
pretty_assertions::assert_eq!(schema_json, expected);
}
)*
}
};
}

Expand Down Expand Up @@ -161,21 +158,33 @@ test_type!(String = {
});

#[cfg(feature = "uuid")]
test_type!(Uuid = {
test_type!(uuid::Uuid = {
"type": "string",
"format": "uuid"
});

// ### date/time

#[cfg(feature = "chrono")]
test_type!(Date<FixedOffset>, Date<Utc>, NaiveDate = {
test_type!(chrono::Date<chrono::FixedOffset>, chrono::Date<chrono::Utc>, chrono::NaiveDate = {
"type": "string",
"format": "date"
});

#[cfg(feature = "time")]
test_type!(time::Date = {
"type": "string",
"format": "date"
});

#[cfg(feature = "chrono")]
test_type!(DateTime<FixedOffset>, DateTime<Utc>, NaiveDateTime = {
test_type!(chrono::DateTime<chrono::FixedOffset>, chrono::DateTime<chrono::Utc>, chrono::NaiveDateTime = {
"type": "string",
"format": "date-time"
});

#[cfg(feature = "time")]
test_type!(time::OffsetDateTime, time::PrimitiveDateTime = {
"type": "string",
"format": "date-time"
});
Expand Down

0 comments on commit 95c2aa2

Please sign in to comment.