Skip to content

Commit

Permalink
Revise date/time newtypes
Browse files Browse the repository at this point in the history
  • Loading branch information
uklotzde committed Jul 26, 2023
1 parent 9bf2361 commit a4c0947
Show file tree
Hide file tree
Showing 55 changed files with 476 additions and 408 deletions.
4 changes: 2 additions & 2 deletions crates/backend-embedded/src/batch/reindex_tracks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use std::num::NonZeroU64;

use aoide_core::util::clock::DateTime;
use aoide_core::util::clock::OffsetDateTimeMs;
use aoide_core_api::{
sorting::SortDirection,
track::search::{SortField, SortOrder},
Expand Down Expand Up @@ -76,7 +76,7 @@ pub async fn reindex_tracks(
#[allow(clippy::cast_possible_truncation)]
let mut collector = EntityCollector::new(Vec::with_capacity(batch_size.get() as usize));
// Last timestamp to consider for updates
let mut last_updated_at: Option<DateTime> = None;
let mut last_updated_at: Option<OffsetDateTimeMs> = None;
connection.transaction::<_, anyhow::Error, _>(|connection| {
'batch_loop: loop {
let pagination = Pagination {
Expand Down
4 changes: 2 additions & 2 deletions crates/core-api/src/filtering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use std::borrow::Cow;

use aoide_core::util::clock::DateTime;
use aoide_core::util::clock::OffsetDateTimeMs;

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum FilterModifier {
Expand Down Expand Up @@ -136,4 +136,4 @@ pub type NumericValue = f64;

pub type NumericPredicate = ScalarPredicate<NumericValue>;

pub type DateTimePredicate = ScalarPredicate<DateTime>;
pub type DateTimePredicate = ScalarPredicate<OffsetDateTimeMs>;
10 changes: 5 additions & 5 deletions crates/core-api/src/track/search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use aoide_core::{
actor::{Kind as ActorKind, Role as ActorRole},
title::Kind as TitleKind,
},
util::clock::{DateOrDateTime, DateTime},
util::clock::{DateOrDateTime, OffsetDateTimeMs},
PlaylistUid, TrackUid,
};
use strum::FromRepr;
Expand Down Expand Up @@ -58,7 +58,7 @@ pub enum ConditionFilter {

pub type NumericFieldFilter = ScalarFieldFilter<NumericField, NumericValue>;

pub type DateTimeFieldFilter = ScalarFieldFilter<DateTimeField, DateTime>;
pub type DateTimeFieldFilter = ScalarFieldFilter<DateTimeField, OffsetDateTimeMs>;

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PhraseFieldFilter {
Expand Down Expand Up @@ -176,7 +176,7 @@ impl Filter {
}),
DateOrDateTime::Date(date) => Self::Numeric(NumericFieldFilter {
field: NumericField::RecordedAtDate,
predicate: NumericPredicate::Equal(Some(date.to_inner().into())),
predicate: NumericPredicate::Equal(Some(date.value().into())),
}),
}
}
Expand All @@ -190,7 +190,7 @@ impl Filter {
}),
DateOrDateTime::Date(date) => Self::Numeric(NumericFieldFilter {
field: NumericField::ReleasedAtDate,
predicate: NumericPredicate::Equal(Some(date.to_inner().into())),
predicate: NumericPredicate::Equal(Some(date.value().into())),
}),
}
}
Expand All @@ -204,7 +204,7 @@ impl Filter {
}),
DateOrDateTime::Date(date) => Self::Numeric(NumericFieldFilter {
field: NumericField::ReleasedOrigAtDate,
predicate: NumericPredicate::Equal(Some(date.to_inner().into())),
predicate: NumericPredicate::Equal(Some(date.value().into())),
}),
}
}
Expand Down
4 changes: 2 additions & 2 deletions crates/core-json/src/media/tests.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: Copyright (C) 2018-2023 Uwe Klotz <uwedotklotzatgmaildotcom> et al.
// SPDX-License-Identifier: AGPL-3.0-or-later

use aoide_core::{media::content::ContentRevision, util::clock::DateTime};
use aoide_core::{media::content::ContentRevision, util::clock::OffsetDateTimeMs};

use super::*;

Expand All @@ -25,7 +25,7 @@ fn serde_digest() {

#[test]
fn deserialize_audio_source() {
let now = DateTime::now_local_or_utc();
let now = OffsetDateTimeMs::now_local_or_utc();
let content_rev = ContentRevision::new(345);
let json = serde_json::json!({
"collectedAt": now.to_string(),
Expand Down
6 changes: 4 additions & 2 deletions crates/core-json/src/playlist/tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// SPDX-FileCopyrightText: Copyright (C) 2018-2023 Uwe Klotz <uwedotklotzatgmaildotcom> et al.
// SPDX-License-Identifier: AGPL-3.0-or-later

use aoide_core::util::clock::OffsetDateTimeMs;

use super::*;

#[test]
Expand All @@ -14,8 +16,8 @@ fn serialize_item_default_separator() {
#[test]
fn deserialize_playlist() {
let uid: EntityUid = "01AN4Z07BY79KA1307SR9X4MV3".parse().unwrap();
let added_at1: aoide_core::util::clock::DateTime = "2020-12-18T21:27:15Z".parse().unwrap();
let added_at2 = aoide_core::util::clock::DateTime::now_utc();
let added_at1 = "2020-12-18T21:27:15Z".parse::<OffsetDateTimeMs>().unwrap();
let added_at2 = OffsetDateTimeMs::now_utc();
let playlist = PlaylistWithEntries {
playlist: Playlist {
title: "Title".to_string(),
Expand Down
68 changes: 35 additions & 33 deletions crates/core-json/src/util/clock/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::fmt;

use aoide_core::{
prelude::*,
util::clock::{YearType, YYYYMMDD},
util::clock::{YearType, YyyyMmDdDateValue},
};
use serde::{
de::{self, Visitor as SerdeDeserializeVisitor},
Expand All @@ -15,7 +15,7 @@ use serde::{
use crate::prelude::*;

mod _core {
pub(super) use aoide_core::util::clock::{DateOrDateTime, DateTime, DateYYYYMMDD};
pub(super) use aoide_core::util::clock::{DateOrDateTime, OffsetDateTimeMs, YyyyMmDdDate};
}

///////////////////////////////////////////////////////////////////////
Expand All @@ -31,16 +31,16 @@ pub struct DateTime {
feature = "json-schema",
schemars(with = "chrono::DateTime<chrono::FixedOffset>")
)]
inner: _core::DateTime,
inner: _core::OffsetDateTimeMs,
}

impl From<_core::DateTime> for DateTime {
fn from(inner: _core::DateTime) -> Self {
impl From<_core::OffsetDateTimeMs> for DateTime {
fn from(inner: _core::OffsetDateTimeMs) -> Self {
Self { inner }
}
}

impl From<DateTime> for _core::DateTime {
impl From<DateTime> for _core::OffsetDateTimeMs {
fn from(from: DateTime) -> Self {
let DateTime { inner } = from;
inner
Expand All @@ -63,96 +63,98 @@ impl<'de> Deserialize<'de> for DateTime {
D: Deserializer<'de>,
{
time::serde::rfc3339::deserialize(deserializer)
.map(_core::DateTime::new)
.map(_core::OffsetDateTimeMs::clamp_from)
.map(Into::into)
}
}

///////////////////////////////////////////////////////////////////////
// DateYYYYMMDD
// YyyyMmDdDate
///////////////////////////////////////////////////////////////////////

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[repr(transparent)]
#[allow(clippy::upper_case_acronyms)]
pub struct DateYYYYMMDD(_core::DateYYYYMMDD);
pub struct YyyyMmDdDate(_core::YyyyMmDdDate);

impl From<_core::DateYYYYMMDD> for DateYYYYMMDD {
fn from(from: _core::DateYYYYMMDD) -> Self {
impl From<_core::YyyyMmDdDate> for YyyyMmDdDate {
fn from(from: _core::YyyyMmDdDate) -> Self {
Self(from)
}
}

impl From<DateYYYYMMDD> for _core::DateYYYYMMDD {
fn from(from: DateYYYYMMDD) -> Self {
impl From<YyyyMmDdDate> for _core::YyyyMmDdDate {
fn from(from: YyyyMmDdDate) -> Self {
from.0
}
}

#[cfg(feature = "json-schema")]
impl schemars::JsonSchema for DateYYYYMMDD {
impl schemars::JsonSchema for YyyyMmDdDate {
fn schema_name() -> String {
"DateYYYYMMDD".to_string()
"YyyyMmDdDate".to_string()
}

fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
gen.subschema_for::<YYYYMMDD>()
gen.subschema_for::<YyyyMmDdDateValue>()
}
}

// Serialize (and deserialize) as string for maximum compatibility and portability
impl Serialize for DateYYYYMMDD {
impl Serialize for YyyyMmDdDate {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let value = if self.0.is_year() {
i32::from(self.0.year())
} else {
self.0.into()
self.0.value()
};
serializer.serialize_i32(value)
}
}

#[allow(clippy::upper_case_acronyms)]
struct DateYYYYMMDDDeserializeVisitor;
struct YyyyMmDdDateDeserializeVisitor;

impl<'de> SerdeDeserializeVisitor<'de> for DateYYYYMMDDDeserializeVisitor {
type Value = DateYYYYMMDD;
impl<'de> SerdeDeserializeVisitor<'de> for YyyyMmDdDateDeserializeVisitor {
type Value = YyyyMmDdDate;

fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_fmt(format_args!("4-digit YYYY or 8-digit YYYYMMDD integer"))
formatter.write_fmt(format_args!(
"4-digit YYYY or 8-digit YyyyMmDdDateValue integer"
))
}

#[allow(clippy::cast_possible_truncation)]
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
where
E: de::Error,
{
let value = value as YYYYMMDD;
let value = if value < _core::DateYYYYMMDD::MIN.into()
&& value >= YYYYMMDD::from(_core::DateYYYYMMDD::MIN.year())
&& value <= YYYYMMDD::from(_core::DateYYYYMMDD::MAX.year())
let value = value as YyyyMmDdDateValue;
let value = if value < _core::YyyyMmDdDate::MIN.value()
&& value >= YyyyMmDdDateValue::from(_core::YyyyMmDdDate::MIN.year())
&& value <= YyyyMmDdDateValue::from(_core::YyyyMmDdDate::MAX.year())
{
// Special case handling: YYYY
_core::DateYYYYMMDD::from_year(value as YearType)
_core::YyyyMmDdDate::from_year(value as YearType)
} else {
_core::DateYYYYMMDD::new(value)
_core::YyyyMmDdDate::new_unchecked(value)
};
value
.validate()
.map_err(|err| E::custom(format!("{err:?}")))
.map(|()| DateYYYYMMDD(value))
.map(|()| YyyyMmDdDate(value))
}
}

impl<'de> Deserialize<'de> for DateYYYYMMDD {
fn deserialize<D>(deserializer: D) -> Result<DateYYYYMMDD, D::Error>
impl<'de> Deserialize<'de> for YyyyMmDdDate {
fn deserialize<D>(deserializer: D) -> Result<YyyyMmDdDate, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_u64(DateYYYYMMDDDeserializeVisitor)
deserializer.deserialize_u64(YyyyMmDdDateDeserializeVisitor)
}
}

Expand All @@ -165,7 +167,7 @@ impl<'de> Deserialize<'de> for DateYYYYMMDD {
#[cfg_attr(test, derive(PartialEq, Eq))]
#[serde(untagged)]
pub enum DateOrDateTime {
Date(DateYYYYMMDD),
Date(YyyyMmDdDate),
DateTime(DateTime),
}

Expand Down
Loading

0 comments on commit a4c0947

Please sign in to comment.