Skip to content
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
70 changes: 70 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: CI

on:
push:
branches:
- master
- 'ft*'
pull_request:
branches:
- master

env:
CARGO_TERM_COLOR: always

jobs:
test:
name: Build, Lint, and Test
runs-on: ubuntu-latest
container:
image: rust:alpine
steps:
- name: Install Alpine dependencies
run: apk add --no-cache git musl-dev

- name: Checkout repository
uses: actions/checkout@v4

- name: Install Rust components
run: rustup component add clippy rustfmt

- name: Cache Cargo dependencies
uses: actions/cache@v3
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-alpine-cargo-${{ hashFiles('**/Cargo.lock') }}

- name: Check formatting
run: cargo fmt -- --check

- name: Lint with Clippy
run: cargo clippy -- -D warnings

- name: Run Tests
run: cargo test --verbose

publish:
name: Publish to Crates.io
runs-on: ubuntu-latest
needs: test
environment: master
if: github.ref == 'refs/heads/master'
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable

- name: Build Release
run: cargo build --release

- name: Publish to Crates.io
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
run: cargo publish --token $CARGO_REGISTRY_TOKEN
32 changes: 0 additions & 32 deletions .travis.yml

This file was deleted.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pg_interval"
version = "0.4.2"
version = "0.4.3"
edition = "2018"
authors = ["Ryan Piper <piper.ryan235@gmail.com>"]
license = "MIT"
Expand Down
37 changes: 18 additions & 19 deletions src/integrations/duration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,22 @@ const NANOS_PER_SEC: i64 = 1_000_000_000;
const NANOS_PER_MICRO: i64 = 1000;

impl Interval {
/// Tries to convert from the `Duration` type to a `Interval`. Will
/// return `None` on a overflow. This is a lossy conversion in that
/// Tries to convert from the `Duration` type to a `Interval`. Will
/// return `None` on a overflow. This is a lossy conversion in that
/// any units smaller than a microsecond will be lost.
pub fn from_duration(duration: Duration) -> Option<Interval> {
let mut days = duration.num_days();
let mut new_dur = duration - Duration::days(days);
let mut hours = duration.num_hours();
new_dur = new_dur - Duration::hours(hours);
let minutes = new_dur.num_minutes();
new_dur = new_dur - Duration::minutes(minutes);
let mut days = duration.num_days();
let mut new_dur = duration - Duration::days(days);
let mut hours = duration.num_hours();
new_dur -= Duration::hours(hours);
let minutes = new_dur.num_minutes();
new_dur -= Duration::minutes(minutes);
let nano_secs = new_dur.num_nanoseconds()?;
if days > (i32::max_value() as i64) {
let overflow_days = days - (i32::max_value() as i64);
if days > (i32::MAX as i64) {
let overflow_days = days - (i32::MAX as i64);
let added_hours = overflow_days.checked_mul(24)?;
hours = hours.checked_add(added_hours)?;
days -= overflow_days;
hours = hours.checked_add(added_hours)?;
days -= overflow_days;
}
let (seconds, remaining_nano) = reduce_by_units(nano_secs, NANOS_PER_SEC);
// We have to discard any remaining nanoseconds
Expand All @@ -39,22 +39,21 @@ impl Interval {
}

fn reduce_by_units(nano_secs: i64, unit: i64) -> (i64, i64) {
let new_time_unit = (nano_secs - (nano_secs % unit)) / unit;
let new_time_unit = (nano_secs - (nano_secs % unit)) / unit;
let remaining_nano = nano_secs - (new_time_unit * unit);
(new_time_unit, remaining_nano)
(new_time_unit, remaining_nano)
}

#[cfg(test)]
mod tests {
use super::*;
use chrono::Duration;


#[test]
fn can_convert_small_amount_of_days() {
let dur = Duration::days(5);
let interval = Interval::from_duration(dur);
assert_eq!(interval, Some(Interval::new(0,5,0)))
assert_eq!(interval, Some(Interval::new(0, 5, 0)))
}

#[test]
Expand All @@ -68,13 +67,13 @@ mod tests {
fn can_convert_small_amount_of_secs() {
let dur = Duration::seconds(1);
let interval = Interval::from_duration(dur);
assert_eq!(interval, Some(Interval::new(0,0,1_000_000)))
assert_eq!(interval, Some(Interval::new(0, 0, 1_000_000)))
}

#[test]
fn can_convert_one_micro() {
let dur = Duration::nanoseconds(1000);
let interval = Interval::from_duration(dur);
assert_eq!(interval, Some(Interval::new(0,0,1)))
assert_eq!(interval, Some(Interval::new(0, 0, 1)))
}
}
}
2 changes: 1 addition & 1 deletion src/integrations/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
mod duration;
mod rust_postgres;
mod duration;
2 changes: 1 addition & 1 deletion src/integrations/rust_postgres.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::Interval;
use bytes::{Buf, BufMut, BytesMut};
use std::error::Error;
use postgres_types::{to_sql_checked, FromSql, IsNull, ToSql, Type};
use std::error::Error;

impl<'a> FromSql<'a> for Interval {
fn from_sql(_: &Type, mut raw: &'a [u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
Expand Down
4 changes: 2 additions & 2 deletions src/interval_fmt/iso_8601.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ impl IntervalNorm {
if self.days != 0 {
day_interval.push_str(&format!("{}D", self.days));
}
year_interval.push_str(&*day_interval);
year_interval.push_str(&*time_interval);
year_interval.push_str(&day_interval);
year_interval.push_str(&time_interval);
year_interval
}
}
14 changes: 7 additions & 7 deletions src/interval_fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,30 @@ use std::ops::Neg;
/// Safely maps a i64 value to a unsigned number
/// without any overflow issues.
fn safe_abs_u64(mut num: i64) -> u64 {
let max = i64::max_value();
let max = i64::MAX;
let max_min = max.neg();
if num <= max_min {
let result = max as u64;
num += max;
num *= -1;
result + num as u64
} else {
num.abs() as u64
num.unsigned_abs()
}
}

/// Safely maps a i32 value to a unsigned number
/// without any overflow issues.
fn safe_abs_u32(mut num: i32) -> u32 {
let max = i32::max_value();
let max = i32::MAX;
let max_min = max.neg();
if num <= max_min {
let result = max as u32;
num += max;
num *= -1;
result + num as u32
} else {
num.abs() as u32
num.unsigned_abs()
}
}

Expand All @@ -41,7 +41,7 @@ fn pad_i64(val: i64) -> String {
} else {
val as u64
};
return format!("{:02}", num);
format!("{:02}", num)
}

#[cfg(test)]
Expand All @@ -50,15 +50,15 @@ mod tests {

#[test]
fn abs_safe_u32() {
let min = i32::min_value();
let min = i32::MIN;
let actual = safe_abs_u32(min);
let expected = 2147483648;
assert_eq!(actual, expected);
}

#[test]
fn abs_safe_u64() {
let min = i64::min_value();
let min = i64::MIN;
let actual = safe_abs_u64(min);
let expected = 9_223_372_036_854_775_808;
assert_eq!(actual, expected);
Expand Down
12 changes: 6 additions & 6 deletions src/interval_fmt/postgres.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ impl IntervalNorm {
}
if self.is_year_month_present() {
if self.years != 0 {
year_interval.push_str(&*format!("{:#?} year ", self.years))
year_interval.push_str(&format!("{:#?} year ", self.years))
}
if self.months != 0 {
year_interval.push_str(&*format!("{:#?} mons ", self.months));
year_interval.push_str(&format!("{:#?} mons ", self.months));
}
}
year_interval.push_str(&*day_interval);
year_interval.push_str(&*time_interval);
year_interval.push_str(&day_interval);
year_interval.push_str(&time_interval);
year_interval.trim().to_owned()
}

Expand All @@ -35,15 +35,15 @@ impl IntervalNorm {
};
let hours = super::pad_i64(self.hours);
time_interval.push_str(
&*(sign
&(sign
+ &hours
+ ":"
+ &super::pad_i64(self.minutes)
+ ":"
+ &super::pad_i64(self.seconds)),
);
if self.microseconds != 0 {
time_interval.push_str(&*format!(".{:06}", super::safe_abs_u64(self.microseconds)))
time_interval.push_str(&format!(".{:06}", super::safe_abs_u64(self.microseconds)))
}
}
time_interval
Expand Down
4 changes: 2 additions & 2 deletions src/interval_norm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub struct IntervalNorm {
pub microseconds: i64,
}

impl<'a> From<&'a Interval> for IntervalNorm {
impl From<&Interval> for IntervalNorm {
fn from(val: &Interval) -> IntervalNorm {
// grab the base values from the interval
let months = val.months;
Expand Down Expand Up @@ -62,7 +62,7 @@ impl IntervalNorm {
})?,
days: self.days,
microseconds: microseconds
.ok_or_else(|| ParseError::from_time("Invalid time interval overflow detected."))?,
.ok_or_else(|| ParseError::from_time("Invalid time interval overflow detected."))?,
})
}

Expand Down
Loading
Loading