Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix gen code without chrono to handle nullable logical-dates #75

Merged
merged 2 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/templates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -889,6 +889,7 @@ impl Templater {
union.variants()[1],
Schema::TimestampMillis | Schema::LocalTimestampMillis
)
&& self.use_chrono_dates
{
w.insert(name_std.clone(), "chrono::serde::ts_milliseconds_option");
} else if union.is_nullable()
Expand All @@ -897,6 +898,7 @@ impl Templater {
union.variants()[1],
Schema::TimestampMicros | Schema::LocalTimestampMicros
)
&& self.use_chrono_dates
{
w.insert(name_std.clone(), "chrono::serde::ts_microseconds_option");
} else if union.is_nullable()
Expand All @@ -905,6 +907,7 @@ impl Templater {
union.variants()[1],
Schema::TimestampNanos | Schema::LocalTimestampNanos
)
&& self.use_chrono_dates
{
w.insert(name_std.clone(), "chrono::serde::ts_nanoseconds_option");
};
Expand Down
15 changes: 14 additions & 1 deletion tests/generation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,14 @@ fn gen_nullable_bytes() {
fn gen_nullable_logical_dates() {
validate_generation(
"nullable_logical_dates",
Generator::builder().nullable(true).build().unwrap(),
);
}

#[test]
fn gen_nullable_chrono_logical_dates() {
validate_generation(
"nullable_chrono_logical_dates",
Generator::builder()
.nullable(true)
.use_chrono_dates(true)
Expand All @@ -142,8 +150,13 @@ fn gen_decimals() {

#[test]
fn gen_logical_dates() {
validate_generation("logical_dates", Generator::builder().build().unwrap());
}

#[test]
fn gen_chrono_logical_dates() {
validate_generation(
"logical_dates",
"chrono_logical_dates",
Generator::builder().use_chrono_dates(true).build().unwrap(),
);
}
Expand Down
28 changes: 25 additions & 3 deletions tests/nullable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,13 @@ fn deser_nullable_bytes() {
}

#[test]
fn deser_nullable_logical_dates() {
fn deser_nullable_chrono_logical_dates() {
let serialized =
r#"{"birthday":null,"meeting_time":null,"release_datetime_micro":1681601301000000}"#;

let val = serde_json::from_str::<schemas::nullable_logical_dates::DateLogicalType>(serialized)
.unwrap();
let val =
serde_json::from_str::<schemas::nullable_chrono_logical_dates::DateLogicalType>(serialized)
.unwrap();
assert!(
val.birthday == chrono::DateTime::<chrono::Utc>::from_timestamp(1681601653, 0).unwrap(),
"Should use schema-defined default value when null"
Expand All @@ -57,3 +58,24 @@ fn deser_nullable_logical_dates() {
"Deserialized value is different from payload value"
);
}

#[test]
fn deser_nullable_logical_dates() {
let serialized =
r#"{"birthday":null,"meeting_time":null,"release_datetime_micro":1681601301000000}"#;

let val = serde_json::from_str::<schemas::nullable_logical_dates::DateLogicalType>(serialized)
.unwrap();
assert!(
val.birthday == 1681601653,
"Should use schema-defined default value when null"
);
assert!(
val.meeting_time.is_none(),
"Schema-defined optional should remain optional in Rust"
);
assert!(
val.release_datetime_micro == 1681601301000000,
"Deserialized value is different from payload value"
);
}
17 changes: 17 additions & 0 deletions tests/schemas/chrono_logical_dates.avsc
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"type": "record",
"name": "DateLogicalType",
"fields": [ {
"name": "birthday",
"type": {"type": "int", "logicalType": "date"}
}, {
"name": "meeting_time",
"type": ["null", {"type": "long", "logicalType": "timestamp-millis"}],
"default": null
}, {
"name": "release_datetime_micro",
"type": {"type": "long", "logicalType": "timestamp-micros"},
"default": 1570903062000000
} ],
"doc": "Date type"
}
19 changes: 19 additions & 0 deletions tests/schemas/chrono_logical_dates.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@

/// Date type
#[derive(Debug, PartialEq, Eq, Clone, serde::Deserialize, serde::Serialize)]
pub struct DateLogicalType {
#[serde(with = "chrono::serde::ts_seconds")]
pub birthday: chrono::DateTime<chrono::Utc>,
#[serde(with = "chrono::serde::ts_milliseconds_option")]
#[serde(default = "default_datelogicaltype_meeting_time")]
pub meeting_time: Option<chrono::DateTime<chrono::Utc>>,
#[serde(with = "chrono::serde::ts_microseconds")]
#[serde(default = "default_datelogicaltype_release_datetime_micro")]
pub release_datetime_micro: chrono::DateTime<chrono::Utc>,
}

#[inline(always)]
fn default_datelogicaltype_meeting_time() -> Option<chrono::DateTime<chrono::Utc>> { None }

#[inline(always)]
fn default_datelogicaltype_release_datetime_micro() -> chrono::DateTime<chrono::Utc> { chrono::DateTime::<chrono::Utc>::from_timestamp_micros(1570903062000000).unwrap() }
13 changes: 5 additions & 8 deletions tests/schemas/logical_dates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,15 @@
/// Date type
#[derive(Debug, PartialEq, Eq, Clone, serde::Deserialize, serde::Serialize)]
pub struct DateLogicalType {
#[serde(with = "chrono::serde::ts_seconds")]
pub birthday: chrono::DateTime<chrono::Utc>,
#[serde(with = "chrono::serde::ts_milliseconds_option")]
pub birthday: i32,
#[serde(default = "default_datelogicaltype_meeting_time")]
pub meeting_time: Option<chrono::DateTime<chrono::Utc>>,
#[serde(with = "chrono::serde::ts_microseconds")]
pub meeting_time: Option<i64>,
#[serde(default = "default_datelogicaltype_release_datetime_micro")]
pub release_datetime_micro: chrono::DateTime<chrono::Utc>,
pub release_datetime_micro: i64,
}

#[inline(always)]
fn default_datelogicaltype_meeting_time() -> Option<chrono::DateTime<chrono::Utc>> { None }
fn default_datelogicaltype_meeting_time() -> Option<i64> { None }

#[inline(always)]
fn default_datelogicaltype_release_datetime_micro() -> chrono::DateTime<chrono::Utc> { chrono::DateTime::<chrono::Utc>::from_timestamp_micros(1570903062000000).unwrap() }
fn default_datelogicaltype_release_datetime_micro() -> i64 { 1570903062000000 }
2 changes: 2 additions & 0 deletions tests/schemas/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub mod enums_sanitize;
pub mod fixed;
pub mod interop;
pub mod logical_dates;
pub mod chrono_logical_dates;
pub mod map_default;
pub mod map_multiple_def;
pub mod mono_valued_union;
Expand All @@ -22,6 +23,7 @@ pub mod nested_record_partial_default;
pub mod nullable;
pub mod nullable_bytes;
pub mod nullable_logical_dates;
pub mod nullable_chrono_logical_dates;
pub mod optional_array;
pub mod optional_arrays;
pub mod record;
Expand Down
18 changes: 18 additions & 0 deletions tests/schemas/nullable_chrono_logical_dates.avsc
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"type": "record",
"name": "DateLogicalType",
"fields": [ {
"name": "birthday",
"type": {"type": "int", "logicalType": "date"},
"default": 1681601653
}, {
"name": "meeting_time",
"type": ["null", {"type": "long", "logicalType": "timestamp-millis"}],
"default": null
}, {
"name": "release_datetime_micro",
"type": {"type": "long", "logicalType": "timestamp-micros"},
"default": 1570903062000000
} ],
"doc": "Date type"
}
56 changes: 56 additions & 0 deletions tests/schemas/nullable_chrono_logical_dates.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@

/// Date type
#[derive(Debug, PartialEq, Eq, Clone, serde::Deserialize, serde::Serialize)]
#[serde(default)]
pub struct DateLogicalType {
#[serde(deserialize_with = "nullable_datelogicaltype_birthday")]
#[serde(serialize_with = "chrono::serde::ts_seconds::serialize")]
pub birthday: chrono::DateTime<chrono::Utc>,
pub meeting_time: Option<chrono::DateTime<chrono::Utc>>,
#[serde(deserialize_with = "nullable_datelogicaltype_release_datetime_micro")]
#[serde(serialize_with = "chrono::serde::ts_microseconds::serialize")]
pub release_datetime_micro: chrono::DateTime<chrono::Utc>,
}

#[inline(always)]
fn nullable_datelogicaltype_birthday<'de, D>(deserializer: D) -> Result<chrono::DateTime<chrono::Utc>, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::Deserialize;
#[derive(serde::Deserialize)]
struct Wrapper(#[serde(with = "chrono::serde::ts_seconds")] chrono::DateTime<chrono::Utc>);
let opt = Option::<Wrapper>::deserialize(deserializer)?.map(|w| w.0);
Ok(opt.unwrap_or_else(|| default_datelogicaltype_birthday() ))
}

#[inline(always)]
fn nullable_datelogicaltype_release_datetime_micro<'de, D>(deserializer: D) -> Result<chrono::DateTime<chrono::Utc>, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::Deserialize;
#[derive(serde::Deserialize)]
struct Wrapper(#[serde(with = "chrono::serde::ts_microseconds")] chrono::DateTime<chrono::Utc>);
let opt = Option::<Wrapper>::deserialize(deserializer)?.map(|w| w.0);
Ok(opt.unwrap_or_else(|| default_datelogicaltype_release_datetime_micro() ))
}

#[inline(always)]
fn default_datelogicaltype_birthday() -> chrono::DateTime<chrono::Utc> { chrono::DateTime::<chrono::Utc>::from_timestamp(1681601653, 0).unwrap() }

#[inline(always)]
fn default_datelogicaltype_meeting_time() -> Option<chrono::DateTime<chrono::Utc>> { None }

#[inline(always)]
fn default_datelogicaltype_release_datetime_micro() -> chrono::DateTime<chrono::Utc> { chrono::DateTime::<chrono::Utc>::from_timestamp_micros(1570903062000000).unwrap() }

impl Default for DateLogicalType {
fn default() -> DateLogicalType {
DateLogicalType {
birthday: default_datelogicaltype_birthday(),
meeting_time: default_datelogicaltype_meeting_time(),
release_datetime_micro: default_datelogicaltype_release_datetime_micro(),
}
}
}
26 changes: 10 additions & 16 deletions tests/schemas/nullable_logical_dates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,46 +4,40 @@
#[serde(default)]
pub struct DateLogicalType {
#[serde(deserialize_with = "nullable_datelogicaltype_birthday")]
#[serde(serialize_with = "chrono::serde::ts_seconds::serialize")]
pub birthday: chrono::DateTime<chrono::Utc>,
pub meeting_time: Option<chrono::DateTime<chrono::Utc>>,
pub birthday: i32,
pub meeting_time: Option<i64>,
#[serde(deserialize_with = "nullable_datelogicaltype_release_datetime_micro")]
#[serde(serialize_with = "chrono::serde::ts_microseconds::serialize")]
pub release_datetime_micro: chrono::DateTime<chrono::Utc>,
pub release_datetime_micro: i64,
}

#[inline(always)]
fn nullable_datelogicaltype_birthday<'de, D>(deserializer: D) -> Result<chrono::DateTime<chrono::Utc>, D::Error>
fn nullable_datelogicaltype_birthday<'de, D>(deserializer: D) -> Result<i32, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::Deserialize;
#[derive(serde::Deserialize)]
struct Wrapper(#[serde(with = "chrono::serde::ts_seconds")] chrono::DateTime<chrono::Utc>);
let opt = Option::<Wrapper>::deserialize(deserializer)?.map(|w| w.0);
let opt = Option::deserialize(deserializer)?;
Ok(opt.unwrap_or_else(|| default_datelogicaltype_birthday() ))
}

#[inline(always)]
fn nullable_datelogicaltype_release_datetime_micro<'de, D>(deserializer: D) -> Result<chrono::DateTime<chrono::Utc>, D::Error>
fn nullable_datelogicaltype_release_datetime_micro<'de, D>(deserializer: D) -> Result<i64, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::Deserialize;
#[derive(serde::Deserialize)]
struct Wrapper(#[serde(with = "chrono::serde::ts_microseconds")] chrono::DateTime<chrono::Utc>);
let opt = Option::<Wrapper>::deserialize(deserializer)?.map(|w| w.0);
let opt = Option::deserialize(deserializer)?;
Ok(opt.unwrap_or_else(|| default_datelogicaltype_release_datetime_micro() ))
}

#[inline(always)]
fn default_datelogicaltype_birthday() -> chrono::DateTime<chrono::Utc> { chrono::DateTime::<chrono::Utc>::from_timestamp(1681601653, 0).unwrap() }
fn default_datelogicaltype_birthday() -> i32 { 1681601653 }

#[inline(always)]
fn default_datelogicaltype_meeting_time() -> Option<chrono::DateTime<chrono::Utc>> { None }
fn default_datelogicaltype_meeting_time() -> Option<i64> { None }

#[inline(always)]
fn default_datelogicaltype_release_datetime_micro() -> chrono::DateTime<chrono::Utc> { chrono::DateTime::<chrono::Utc>::from_timestamp_micros(1570903062000000).unwrap() }
fn default_datelogicaltype_release_datetime_micro() -> i64 { 1570903062000000 }

impl Default for DateLogicalType {
fn default() -> DateLogicalType {
Expand Down
Loading