Skip to content

Commit ed27292

Browse files
authored
feat: Add way to get Configtype time value for hashing (#2077)
#### Summary First option was using exported fields, but even that would require additional logic- e.g. what should happen, if the user provided input is `50 minutes ago` and the sync is run twice at different times? I think this approach makes more sense, but let me know if there are any other ideas or comments to consider. --- closes https://github.com/cloudquery/cloudquery-private/issues/6478
1 parent da8e9b6 commit ed27292

File tree

4 files changed

+81
-3
lines changed

4 files changed

+81
-3
lines changed

configtype/time.go

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@ import (
1515
// when a time type is required. We wrap the time.Time type so that
1616
// the spec can be extended in the future to support other types of times
1717
type Time struct {
18-
input string
19-
time time.Time
20-
duration *timeDuration
18+
input string
19+
time time.Time
20+
duration *timeDuration
21+
hashNowFunc func() time.Time
2122
}
2223

2324
func ParseTime(s string) (Time, error) {
@@ -130,6 +131,19 @@ func (t Time) String() string {
130131
return t.input
131132
}
132133

134+
func (t Time) Hash() (uint64, error) {
135+
nowFunc := t.hashNowFunc
136+
if nowFunc == nil {
137+
nowFunc = time.Now
138+
}
139+
at := t.AsTime(nowFunc())
140+
return uint64(at.UnixNano()), nil
141+
}
142+
143+
func (t *Time) SetHashNowFunc(f func() time.Time) {
144+
t.hashNowFunc = f
145+
}
146+
133147
type timeDuration struct {
134148
input string
135149

configtype/time_test.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/cloudquery/plugin-sdk/v4/configtype"
1010
"github.com/cloudquery/plugin-sdk/v4/plugin"
1111
"github.com/invopop/jsonschema"
12+
"github.com/mitchellh/hashstructure/v2"
1213
"github.com/stretchr/testify/require"
1314
)
1415

@@ -151,3 +152,63 @@ func TestTime_JSONSchema(t *testing.T) {
151152
})
152153
}
153154
}
155+
156+
func TestTime_Hashing(t *testing.T) {
157+
hnf := func() time.Time { return time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC) }
158+
cases := []struct {
159+
a configtype.Time
160+
b configtype.Time
161+
hashNowFunc func() time.Time
162+
equal bool
163+
}{
164+
{
165+
a: func() configtype.Time { ct, _ := configtype.ParseTime("10m"); return ct }(),
166+
b: func() configtype.Time { ct, _ := configtype.ParseTime("10m"); return ct }(),
167+
hashNowFunc: hnf,
168+
equal: true,
169+
},
170+
{
171+
a: func() configtype.Time { ct, _ := configtype.ParseTime("10m"); return ct }(),
172+
b: func() configtype.Time { ct, _ := configtype.ParseTime("10m"); return ct }(),
173+
equal: false,
174+
},
175+
{
176+
a: func() configtype.Time { ct, _ := configtype.ParseTime("10m"); return ct }(),
177+
b: func() configtype.Time { ct, _ := configtype.ParseTime("1m"); return ct }(),
178+
equal: false,
179+
},
180+
{
181+
a: func() configtype.Time { ct, _ := configtype.ParseTime("2021-09-01T00:00:00Z"); return ct }(),
182+
b: func() configtype.Time { ct, _ := configtype.ParseTime("2012-01-02T01:02:03Z"); return ct }(),
183+
hashNowFunc: hnf,
184+
equal: false,
185+
},
186+
{
187+
a: func() configtype.Time { ct, _ := configtype.ParseTime("-50m30s"); return ct }(),
188+
b: func() configtype.Time { ct, _ := configtype.ParseTime("50 minutes 30 seconds ago"); return ct }(),
189+
hashNowFunc: hnf,
190+
equal: true,
191+
},
192+
{
193+
a: func() configtype.Time { ct, _ := configtype.ParseTime("50m30s"); return ct }(),
194+
b: func() configtype.Time { ct, _ := configtype.ParseTime("50 minutes 30 seconds from now"); return ct }(),
195+
hashNowFunc: hnf,
196+
equal: true,
197+
},
198+
}
199+
for _, tc := range cases {
200+
tc.a.SetHashNowFunc(tc.hashNowFunc)
201+
hashA, err := hashstructure.Hash(tc.a, hashstructure.FormatV2, nil)
202+
require.NoError(t, err)
203+
time.Sleep(1 * time.Second)
204+
tc.b.SetHashNowFunc(tc.hashNowFunc)
205+
hashB, err := hashstructure.Hash(tc.b, hashstructure.FormatV2, nil)
206+
require.NoError(t, err)
207+
208+
if tc.equal {
209+
require.Equal(t, hashA, hashB)
210+
continue
211+
}
212+
require.NotEqual(t, hashA, hashB)
213+
}
214+
}

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ require (
2121
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.2.0
2222
github.com/hashicorp/go-retryablehttp v0.7.7
2323
github.com/invopop/jsonschema v0.13.0
24+
github.com/mitchellh/hashstructure/v2 v2.0.2
2425
github.com/rs/zerolog v1.33.0
2526
github.com/samber/lo v1.47.0
2627
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 h1:AMFGa4R4MiIpsp
125125
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY=
126126
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 h1:+n/aFZefKZp7spd8DFdX7uMikMLXX4oubIzJF4kv/wI=
127127
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE=
128+
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
129+
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
128130
github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro=
129131
github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg=
130132
github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=

0 commit comments

Comments
 (0)