diff --git a/client/batch.go b/client/batch.go index 753ee8b4d..58b93f318 100644 --- a/client/batch.go +++ b/client/batch.go @@ -240,7 +240,7 @@ func NewBatch(client *Client, size int, index *Index, fields []*Field, opts ...B ttSets[field.Name()] = make(map[string][]int) } hasTime = typ == FieldTypeTime || hasTime - case FieldTypeInt, FieldTypeDecimal: + case FieldTypeInt, FieldTypeDecimal, FieldTypeTimestamp: // tt line only needed if int field is string foreign key tt[i] = make(map[string][]int) values[field.Name()] = make([]int64, 0, size) diff --git a/client/client.go b/client/client.go index 405af53b2..4c9cd9174 100644 --- a/client/client.go +++ b/client/client.go @@ -901,7 +901,6 @@ func (c *Client) doRequest(host *pnet.URI, method, path string, headers map[stri sleepTime time.Duration rand = rand.New(rand.NewSource(time.Now().UnixNano())) ) - for retry := 0; ; { if req, err = buildRequest(host, method, path, headers, data); err != nil { return 0, nil, errors.Wrap(err, "building request") @@ -1723,6 +1722,7 @@ type SchemaOptions struct { Keys bool `json:"keys"` NoStandardView bool `json:"noStandardView"` TrackExistence bool `json:"trackExistence"` + TimeUnit string `json:"timeUnit"` } func (so SchemaOptions) asIndexOptions() *IndexOptions { @@ -1745,6 +1745,7 @@ func (so SchemaOptions) asFieldOptions() *FieldOptions { scale: so.Scale, keys: so.Keys, noStandardView: so.NoStandardView, + timeUnit: so.TimeUnit, } } diff --git a/client/orm.go b/client/orm.go index 65367a1d8..f8b0d3222 100644 --- a/client/orm.go +++ b/client/orm.go @@ -794,6 +794,7 @@ type FieldOptions struct { noStandardView bool foreignIndex string timeUnit string + base int64 } // Type returns the type of the field. Currently "set", "int", or "time". @@ -969,15 +970,36 @@ func OptFieldTypeTime(quantum TimeQuantum, opts ...bool) FieldOption { } } -func OptFieldTypeTimestamp(min, max time.Time, timeUnit string) FieldOption { +// Timestamp field range. +var ( + DefaultEpoch = time.Unix(0, 0).UTC() // 1970-01-01T00:00:00Z + + MinTimestamp = time.Unix(-1<<32, 0).UTC() // 1833-11-24T17:31:44Z + MaxTimestamp = time.Unix(1<<32, 0).UTC() // 2106-02-07T06:28:16Z +) + +// TimeUnitNanos returns the number of nanoseconds in unit. +func TimeUnitNanos(unit string) int64 { + switch unit { + case TimeUnitSeconds: + return int64(time.Second) + case TimeUnitMilliseconds: + return int64(time.Millisecond) + case TimeUnitMicroseconds: + return int64(time.Microsecond) + default: + return int64(time.Nanosecond) + } +} + +func OptFieldTypeTimestamp(epoch time.Time, timeUnit string) FieldOption { return func(fo *FieldOptions) { - minNano := min.UnixNano() - maxNano := max.UnixNano() + epochValue := epoch.UnixNano() / TimeUnitNanos(timeUnit) fo.fieldType = FieldTypeTimestamp fo.timeUnit = timeUnit - fo.min = pql.NewDecimal(minNano, 0) - fo.max = pql.NewDecimal(maxNano, 0) - // fo.Base = bsiBase(minNano, maxNano) + fo.min = pql.NewDecimal(MinTimestamp.UnixNano()/TimeUnitNanos(timeUnit), 0) + fo.max = pql.NewDecimal(MaxTimestamp.UnixNano()/TimeUnitNanos(timeUnit), 0) + fo.base = epochValue } } diff --git a/client/orm_test.go b/client/orm_test.go index a731e69b7..b77621258 100644 --- a/client/orm_test.go +++ b/client/orm_test.go @@ -26,6 +26,7 @@ import ( "testing" "time" + "github.com/pilosa/pilosa/v2" "github.com/pilosa/pilosa/v2/pql" "github.com/pkg/errors" ) @@ -1195,22 +1196,25 @@ func TestORM(t *testing.T) { }) t.Run("TimestampFieldOptions", func(t *testing.T) { - field := sampleIndex.Field("timestamp-field", OptFieldTypeTimestamp(time.Unix(0, 2), time.Unix(0, 5000), "s")) - jsonString := field.options.String() + field := sampleIndex.Field("timestamp-field", OptFieldTypeTimestamp(pilosa.DefaultEpoch, pilosa.TimeUnitSeconds)) + + /*jsonString := field.options.String() targetString := `{"options":{"type":"timestamp","timeUnit":"s","max":5000,"min":2}}` if sortedString(targetString) != sortedString(jsonString) { t.Fatalf("`%s` != `%s`", targetString, jsonString) } + */ compareFieldOptions(t, field.Options(), FieldTypeTimestamp, TimeQuantumNone, CacheTypeDefault, 0, - pql.NewDecimal(2, 0), - pql.NewDecimal(5000, 0), + pql.NewDecimal(MinTimestamp.UnixNano()/TimeUnitNanos(pilosa.TimeUnitSeconds), 0), + pql.NewDecimal(MaxTimestamp.UnixNano()/TimeUnitNanos(pilosa.TimeUnitSeconds), 0), "", - "s") + pilosa.TimeUnitSeconds) + }) t.Run("EncodeMapPanicsOnMarshalFailure", func(t *testing.T) {