Skip to content

Commit

Permalink
Add convenience functions to transform between edgedb.Duration and ti…
Browse files Browse the repository at this point in the history
…me.Duration (#304)
  • Loading branch information
lsdch authored Mar 22, 2024
1 parent 71fd7ab commit d4da926
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 0 deletions.
4 changes: 4 additions & 0 deletions export.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,10 @@ var (
// The following options are recognized: host, port, user, database, password.
CreateClientDSN = edgedb.CreateClientDSN

// DurationFromNanoseconds creates a Duration represented as microseconds
// from a [time.Duration] represented as nanoseconds.
DurationFromNanoseconds = edgedbtypes.DurationFromNanoseconds

// NewDateDuration returns a new DateDuration
NewDateDuration = edgedbtypes.NewDateDuration

Expand Down
20 changes: 20 additions & 0 deletions internal/edgedbtypes/datetime.go
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,26 @@ func (d Duration) String() string {
return strings.Join(buf, "")
}

// AsNanoseconds returns [time.Duration] represented as nanoseconds,
// after transforming from Duration microsecond representation.
// Returns an error if the Duration is too long and would cause an overflow of
// the internal int64 representation.
func (d Duration) AsNanoseconds() (time.Duration, error) {
if int64(d) > math.MaxInt64/int64(time.Microsecond) ||
int64(d) < math.MinInt64/int64(time.Microsecond) {
return time.Duration(0), fmt.Errorf(
"Duration is too large to be represented as nanoseconds",
)
}
return time.Duration(d) * time.Microsecond, nil
}

// DurationFromNanoseconds creates a Duration represented as microseconds
// from a [time.Duration] represented as nanoseconds.
func DurationFromNanoseconds(d time.Duration) Duration {
return Duration(math.RoundToEven(float64(d) / 1e3))
}

// NewOptionalDuration is a convenience function for creating an
// OptionalDuration with its value set to v.
func NewOptionalDuration(v Duration) OptionalDuration {
Expand Down
45 changes: 45 additions & 0 deletions internal/edgedbtypes/datetime_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package edgedbtypes
import (
"encoding/json"
"fmt"
"math"
"strings"
"testing"
"time"
Expand Down Expand Up @@ -758,6 +759,50 @@ func TestUnmarshalDuration(t *testing.T) {
}
}

func TestAsNanosecondsDuration(t *testing.T) {
var durationTruncMicroseconds = func(i int64) time.Duration {
return time.Duration(time.Duration(i).Microseconds() * 1000)
}

cases := []struct {
input Duration
mustFail bool
expected time.Duration
}{
{Duration(math.MaxInt64), true, time.Duration(0)},
{Duration(math.MaxInt64 / 100), true, time.Duration(0)},
{Duration(math.MaxInt64/1000 + 1), true, time.Duration(0)},
// Maximum possible value:
{Duration(math.MaxInt64 / 1000), false,
durationTruncMicroseconds(math.MaxInt64)},
// Some arbitrary value within range
{Duration(math.MaxInt64 / 1452), false,
durationTruncMicroseconds(math.MaxInt64 / 1452 * 1000)},
{Duration(0), false, time.Duration(0)},
{Duration(math.MinInt64), true, time.Duration(0)},
{Duration(math.MinInt64 / 100), true, time.Duration(0)},
{Duration(math.MinInt64/1000 - 1), true, time.Duration(0)},
// Minimum possible value
{Duration(math.MinInt64 / 1000), false,
durationTruncMicroseconds(math.MinInt64)},
// Some arbitrary value within range
{Duration(math.MinInt64 / 6946), false,
durationTruncMicroseconds(math.MinInt64 / 6946 * 1000)},
}

for _, c := range cases {
t.Run(c.input.String(), func(t *testing.T) {
d, err := c.input.AsNanoseconds()
if c.mustFail {
require.Error(t, err)
} else {
require.NoError(t, err)
}
assert.Equal(t, c.expected, d)
})
}
}

func TestMarshalOptionalDuration(t *testing.T) {
cases := []struct {
input OptionalDuration
Expand Down
28 changes: 28 additions & 0 deletions rstdocs/types.rst
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,19 @@ as an int64 microsecond count.
type Duration int64
*function* DurationFromNanoseconds
..................................

.. code-block:: go
func DurationFromNanoseconds(d time.Duration) Duration
DurationFromNanoseconds creates a Duration represented as microseconds
from a `time.Duration <https://pkg.go.dev/time>`_ represented as nanoseconds.




*function* ParseDuration
........................

Expand All @@ -87,6 +100,21 @@ ParseDuration parses an EdgeDB duration string.



*method* AsNanoseconds
......................

.. code-block:: go
func (d Duration) AsNanoseconds() (time.Duration, error)
AsNanoseconds returns `time.Duration <https://pkg.go.dev/time>`_ represented as nanoseconds,
after transforming from Duration microsecond representation.
Returns an error if the Duration is too long and would cause an overflow of
the internal int64 representation.




*method* String
...............

Expand Down

0 comments on commit d4da926

Please sign in to comment.