Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support $currentDate field update operator #662

Merged
merged 51 commits into from
Jun 7, 2022
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
695375d
added some tests
seeforschauer May 31, 2022
b2483ba
more $currentDate tests
seeforschauer May 31, 2022
083fdff
added one more integration mongo test
seeforschauer May 31, 2022
a0ad74d
Merge branch 'main' into issue-622-currentDate
seeforschauer Jun 1, 2022
57521bd
added more tests
seeforschauer Jun 1, 2022
b0a6ca2
wip
seeforschauer Jun 1, 2022
5a9760e
Merge branch 'main' into issue-622-currentDate
seeforschauer Jun 1, 2022
84d61f4
DocumentEmpty test ok
seeforschauer Jun 1, 2022
2c8c5b3
Array
seeforschauer Jun 1, 2022
22aa73a
WrongInt32
seeforschauer Jun 1, 2022
e29dacb
Nil
seeforschauer Jun 1, 2022
0ef3500
data comparison
seeforschauer Jun 1, 2022
23b5d28
wip
seeforschauer Jun 1, 2022
39d4c5a
Merge branch 'main' into issue-622-currentDate
seeforschauer Jun 1, 2022
730a100
wip
seeforschauer Jun 1, 2022
335b2f2
delta
seeforschauer Jun 1, 2022
8ad5c9f
UnrecognizedOption
seeforschauer Jun 1, 2022
bb78d82
Int32
seeforschauer Jun 1, 2022
88bc6a8
Merge branch 'main' into issue-622-currentDate
seeforschauer Jun 1, 2022
1de73f4
TimestampCapitalised
seeforschauer Jun 1, 2022
643475b
Merge branch 'main' into issue-622-currentDate
seeforschauer Jun 1, 2022
8318363
True
seeforschauer Jun 2, 2022
2ae3b39
False
seeforschauer Jun 2, 2022
2fd401f
Date
seeforschauer Jun 2, 2022
bbf9290
NoField
seeforschauer Jun 2, 2022
cb7fb1d
Merge branch 'main' into issue-622-currentDate
seeforschauer Jun 2, 2022
d9720f7
wip
seeforschauer Jun 2, 2022
6fd1c91
w/o timestamp
seeforschauer Jun 2, 2022
57a864a
add check
seeforschauer Jun 2, 2022
c098c36
remove debug log
seeforschauer Jun 2, 2022
f5293ff
Timestamp
seeforschauer Jun 2, 2022
8f3e8e5
merge
seeforschauer Jun 2, 2022
a88696d
Merge branch 'main' into issue-622-currentDate
seeforschauer Jun 2, 2022
45658ef
increase coverage
seeforschauer Jun 2, 2022
41971a7
change to assertion
seeforschauer Jun 3, 2022
b5094f4
simplify
seeforschauer Jun 3, 2022
28d4184
simplify
seeforschauer Jun 3, 2022
2df31f1
fix linters
seeforschauer Jun 3, 2022
c3ba437
UTC
seeforschauer Jun 4, 2022
53211ed
Merge branch 'main' into issue-622-currentDate
AlekSi Jun 6, 2022
7c3f006
rename
seeforschauer Jun 6, 2022
a0df3f8
shorter names
seeforschauer Jun 6, 2022
1ead17b
types change
seeforschauer Jun 6, 2022
ccacfef
Merge branch 'main' into issue-622-currentDate
seeforschauer Jun 6, 2022
72750ed
remove todo
seeforschauer Jun 6, 2022
0532c0f
Merge branch 'issue-622-currentDate' of github.com:seeforschauer/Ft push
seeforschauer Jun 6, 2022
6adc1e6
counter
seeforschauer Jun 6, 2022
4465653
Merge branch 'main' into issue-622-currentDate
seeforschauer Jun 6, 2022
9adda32
add 30 sec to max maxDifference
seeforschauer Jun 6, 2022
868ad12
time.Time
seeforschauer Jun 6, 2022
6ec104e
Merge branch 'main' into issue-622-currentDate
seeforschauer Jun 7, 2022
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
2 changes: 1 addition & 1 deletion integration/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func Convert(t testing.TB, v any) any {
case int32:
return v
case primitive.Timestamp:
return types.Timestamp(uint64(v.I)<<32 + uint64(v.T))
return types.NewTimestamp(uint64(v.T), uint64(v.I))
case int64:
return v
default:
Expand Down
212 changes: 212 additions & 0 deletions integration/update_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,18 @@ package integration
import (
"math"
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"

"github.com/FerretDB/FerretDB/integration/shareddata"
"github.com/FerretDB/FerretDB/internal/types"
"github.com/FerretDB/FerretDB/internal/util/testutil"
)

func TestUpdateUpsert(t *testing.T) {
Expand Down Expand Up @@ -673,3 +677,211 @@ func TestUpdateMany(t *testing.T) {
})
}
}

func TestCurrentDate(t *testing.T) {
t.Parallel()

// maxTimeDelta is a maximum amount of seconds can differ the value in placeholder from actual value
maxTimeDelta := time.Duration(30 * time.Second)

now := primitive.NewDateTimeFromTime(time.Now().UTC())
nowTimestamp := primitive.Timestamp{T: uint32(time.Now().UTC().Unix()), I: uint32(0)}
Comment on lines +728 to +729
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.UTC() does nothing there


for name, tc := range map[string]struct {
id string
update bson.D
result bson.D
paths []types.Path
err *mongo.WriteError
stat *mongo.UpdateResult
alt string
}{
"DocumentEmpty": {
id: "double",
update: bson.D{{"$currentDate", bson.D{}}},
stat: &mongo.UpdateResult{
MatchedCount: 1,
ModifiedCount: 0,
UpsertedCount: 0,
},
result: bson.D{{"_id", "double"}, {"value", float64(42.13)}},
},
"Array": {
id: "double",
update: bson.D{{"$currentDate", bson.A{}}},
err: &mongo.WriteError{
Code: 9,
Message: "Modifiers operate on fields but we found type array instead. " +
"For example: {$mod: {<field>: ...}} not {$currentDate: []}",
},
alt: "Modifiers operate on fields but we found another type instead",
},
"WrongInt32": {
id: "double",
update: bson.D{{"$currentDate", int32(1)}},
err: &mongo.WriteError{
Code: 9,
Message: "Modifiers operate on fields but we found type int instead. " +
"For example: {$mod: {<field>: ...}} not {$currentDate: 1}",
},
alt: "Modifiers operate on fields but we found another type instead",
},
"Nil": {
id: "double",
update: bson.D{{"$currentDate", nil}},
err: &mongo.WriteError{
Code: 9,
Message: "Modifiers operate on fields but we found type null instead. " +
"For example: {$mod: {<field>: ...}} not {$currentDate: null}",
},
alt: "Modifiers operate on fields but we found another type instead",
},
"True": {
id: "double",
update: bson.D{{"$currentDate", bson.D{{"value", true}}}},
stat: &mongo.UpdateResult{
MatchedCount: 1,
ModifiedCount: 1,
UpsertedCount: 0,
},
paths: []types.Path{types.NewPathFromString("value")},
result: bson.D{{"_id", "double"}, {"value", now}},
},
"TwoTrue": {
id: "double",
update: bson.D{{"$currentDate", bson.D{{"value", true}, {"unexistent", true}}}},
stat: &mongo.UpdateResult{
MatchedCount: 1,
ModifiedCount: 1,
UpsertedCount: 0,
},
paths: []types.Path{
types.NewPathFromString("value"),
types.NewPathFromString("unexistent"),
},
result: bson.D{{"_id", "double"}, {"value", now}, {"unexistent", now}},
},
"False": {
id: "double",
update: bson.D{{"$currentDate", bson.D{{"value", false}}}},
rumyantseva marked this conversation as resolved.
Show resolved Hide resolved
stat: &mongo.UpdateResult{
MatchedCount: 1,
ModifiedCount: 1,
UpsertedCount: 0,
},
paths: []types.Path{types.NewPathFromString("value")},
result: bson.D{{"_id", "double"}, {"value", now}},
},
"Int32": {
id: "double",
update: bson.D{{"$currentDate", bson.D{{"value", int32(1)}}}},
err: &mongo.WriteError{
Code: 2,
Message: "int is not valid type for $currentDate. Please use a boolean ('true') or a $type expression ({$type: 'timestamp/date'}).",
},
},
"Timestamp": {
id: "double",
update: bson.D{{"$currentDate", bson.D{{"value", bson.D{{"$type", "timestamp"}}}}}},
stat: &mongo.UpdateResult{
MatchedCount: 1,
ModifiedCount: 1,
UpsertedCount: 0,
},
paths: []types.Path{types.NewPathFromString("value")},
result: bson.D{{"_id", "double"}, {"value", nowTimestamp}},
},
"TimestampCapitalised": {
id: "double",
update: bson.D{{"$currentDate", bson.D{{"value", bson.D{{"$type", "Timestamp"}}}}}},
err: &mongo.WriteError{
Code: 2,
Message: "The '$type' string field is required to be 'date' or 'timestamp': {$currentDate: {field : {$type: 'date'}}}",
},
alt: "The '$type' string field is required to be 'date' or 'timestamp'",
},
"Date": {
id: "double",
update: bson.D{{"$currentDate", bson.D{{"value", bson.D{{"$type", "date"}}}}}},
stat: &mongo.UpdateResult{
MatchedCount: 1,
ModifiedCount: 1,
UpsertedCount: 0,
},
paths: []types.Path{types.NewPathFromString("value")},
result: bson.D{{"_id", "double"}, {"value", now}},
},
"WrongType": {
id: "double",
update: bson.D{{"$currentDate", bson.D{{"value", bson.D{{"$type", bson.D{{"abcd", int32(1)}}}}}}}},
err: &mongo.WriteError{
Code: 2,
Message: "The '$type' string field is required to be 'date' or 'timestamp': {$currentDate: {field : {$type: 'date'}}}",
},
alt: "The '$type' string field is required to be 'date' or 'timestamp'",
},
"NoField": {
id: "double",
update: bson.D{{"$currentDate", bson.D{{"unexsistent", bson.D{{"$type", "date"}}}}}},
stat: &mongo.UpdateResult{
MatchedCount: 1,
ModifiedCount: 1,
UpsertedCount: 0,
},
paths: []types.Path{types.NewPathFromString("unexsistent")},
result: bson.D{{"_id", "double"}, {"value", 42.13}, {"unexsistent", now}},
},
"UnrecognizedOption": {
id: "array",
update: bson.D{{
"$currentDate",
bson.D{{
"value",
bson.D{{
"array", bson.D{{"unexsistent", bson.D{}}},
}},
}},
}},
err: &mongo.WriteError{
Code: 2,
Message: "Unrecognized $currentDate option: array",
},
},
} {
name, tc := name, tc
t.Run(name, func(t *testing.T) {
t.Parallel()
ctx, collection := setup(t, shareddata.Scalars, shareddata.Composites)

res, err := collection.UpdateOne(ctx, bson.D{{"_id", tc.id}}, tc.update)
if tc.err != nil {
require.Nil(t, tc.paths)
require.Nil(t, tc.stat)
AssertEqualAltWriteError(t, *tc.err, tc.alt, err)
return
}
require.NoError(t, err)
require.Equal(t, tc.stat, res)

var actualB bson.D
err = collection.FindOne(ctx, bson.D{{"_id", tc.id}}).Decode(&actualB)
require.NoError(t, err)

expected := ConvertDocument(t, tc.result)
actual := ConvertDocument(t, actualB)

for _, path := range tc.paths {
testutil.CompareAndSetByPathTime(
t,
expected,
actual,
maxTimeDelta,
path,
)
expected.RemoveByPath(path)
actual.RemoveByPath(path)
Comment on lines +922 to +923
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do we set values by path only to remove them on the next line?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do we set values by path only to remove them on the next line?

There is assert.Equal(t, expected, actual) below, and it tests whether other document values are ok (not changed, not removed, not updated anyhow).

}
assert.Equal(t, expected, actual)
})
}
}
Loading