-
-
Notifications
You must be signed in to change notification settings - Fork 140
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
feat: implement backend support for tag colors #4362
base: master
Are you sure you want to change the base?
Conversation
26d50d8
to
4654758
Compare
6bb4533
to
954abfa
Compare
79005c0
to
fdee49e
Compare
124a7b8
to
b5e4846
Compare
b5e4846
to
dc766ed
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also noticed that some of the newly added Tag
methods don’t have tests. Could you implement them?
api/services/utils.go
Outdated
for _, i := range list { | ||
if i.Name == item { | ||
return true | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use the ContainsFunc
method from the slices
package here.
tag, err := s.db.Collection("devices"). | ||
UpdateOne(ctx, bson.M{"uid": uid}, bson.M{"$set": bson.M{"tags": tags}}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We usually check if MatchedCount
is 0 and return an ErrNoDocuments
. I believe it’s appropriate to do the same here to maintain consistent behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have checked, this not use of the MatchedCount
has not been made by myself(and have not been intended to be changed), this could led for minimal changes in method behavior, they will remain consistent as to the rest of the other methods return value.
api/store/mongo/tags.go
Outdated
func (s *Store) VerifyTagExist(ctx context.Context, tagName, tenant string) (bool, error) { | ||
tag := new(models.Tags) | ||
|
||
cursor, err := s.db.Collection("tags").Find(ctx, | ||
bson.M{"name": tagName, "tenant_id": tenant}) | ||
if err != nil { | ||
return false, FromMongoError(err) | ||
} | ||
|
||
for cursor.Next(ctx) { | ||
err := cursor.Decode(tag) | ||
if err != nil { | ||
return false, err | ||
} | ||
|
||
if err != nil { | ||
return false, FromMongoError(err) | ||
} | ||
|
||
if tag.Name == "" { | ||
return false, nil | ||
} | ||
} | ||
|
||
return true, nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it expected to have multiple tags with the same name for the same namespace? If not, you could use FindOne
instead of Find
.
Additionally, there’s a duplicate err != nil
check here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually this has been the first idea, but if there is nothing that you are looking for, so they return a error, that means that there is 'no data on collection' and this is a ambiguous error, for a single data or not existing on the collection, so, by not trying to handle a error as empty return data, is better to use the find and deal with empty array; the additional check will be changed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMHO, using Find
here is an over-complicated solution and handling lists when we will always have at most one item is unnecessary. In the end, what you're doing is effectively the same as:
tag := new(models.Tags)
if err := s.db.Collection("tags").FindOne(ctx, bson.M{"name": tagName, "tenant_id": tenant}).Decode(tag); err != nil {
return false, FromMongoError(err)
}
And when using the method, you can simply check:
if _, err := store.VerifyTagExist(ctx, tagName, tenantID); err != nil {
if errors.Is(err, ErrNoDocuments) {
// The tag does not exist here
} else {
// Another error happens
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, this is understandable, but, this kind of defies the idea of VerifyTagExist
, the purpose of VerifyTagExist
is to return a boolean value indicating whether a tag exists, while we could just use error handling instead, that would go against the method's intended design, the method was created to simply check and return true/false, not to handle business logic through error handling passing, is understandable that this is the pattern on the code base (for the ErrNoDocuments alone), but still is awkward to use the error as the intended return since there is already a boolean return value to provide that information
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't believe that returning an error instead of a boolean constitutes handling business logic. I maintain my opinion that using an array to handle a tag that will always contain at most one item is overly complicated.
If the method name no longer aligns with its original purpose, you could rename it to TagsGetOne
and have it return the model itself instead of a boolean. In this case, you can simply check if the error is ErrNoDocuments
and ignore the tag. The behavior would remain the same.
If the goal is just to check for the tag's existence, you could return something like FromMongoError(err) == ErrNoDocuments
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
However, if you doesn't agree with that, feel free to resolve the conversation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, you can keep your opinion, but I must say that it's not 'overly complicated', since actually mixing an error with the intended information of a method is not a good pattern/idea (there is a clear separation of what is data, a boolean value, and what is an actual error). indeed, I also will keep the code on this way, if you wish so, since the behavior is the same, and you are just giving an opinion, but again, I'm not criticizing your opinion, just talking about the best interface and logic that fits VerifyTagExist
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed with @gustavosbarreto, please refactor this method to something like the following:
func (s *Store) TagGet(ctx context.Context, tagName, tenant string) (*models.Tags, error) {
tag := new(models.Tags)
if err := s.db.Collection("tags").FindOne(ctx, bson.M{"name": tagName, "tenant_id": tenant}).Decode(tag); err != nil {
return nil, FromMongoError(err)
}
return tag, nil
}
When checking whether the tag exists or not, do:
if _, err := store.TagGet(ctx, tagName, tenantID); err != nil {
if errors.Is(err, ErrNoDocuments) {
// Tag not found
} else {
// Another error happens
}
}
api/store/mongo/device_tags.go
Outdated
res, err := s.TagsBulkDeleteTag(sessCtx, tenant, currentTag) | ||
if err != nil { | ||
return res, FromMongoError(err) | ||
} | ||
|
||
tag.Name = newTag | ||
|
||
_, err2 := s.db.Collection("tags", options.Collection().SetWriteConcern(writeconcern.Majority())). | ||
InsertOne(sessCtx, tag) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you need to delete and reinsert a list of tags instead of updating them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This has to do with a way to simplify behavior in development as an atomic way and the old logic that no longer applies, since your observation, it really is better now to just update, thank you
dc766ed
to
e5193e7
Compare
api/store/mongo/tags.go
Outdated
} | ||
|
||
for cursor.Next(ctx) { | ||
if err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The err
variable is not updated within the loop
}) | ||
if err != nil { | ||
return int64(0), FromMongoError(err) | ||
} | ||
|
||
return count.(int64), nil | ||
} | ||
|
||
func (s *Store) VerifyTagExist(ctx context.Context, tagName, tenant string) (bool, error) { | ||
tag := new(models.Tags) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Decode
method is never called to populate the tag variable with the data retrieved from db.
api/store/mongo/tags.go
Outdated
return false, FromMongoError(err) | ||
} | ||
|
||
if tag.Name == "" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This check is unnecessary since the presence of a document inherently confirms the tag's existence.
api/store/mongo/tags.go
Outdated
func (s *Store) VerifyTagExist(ctx context.Context, tagName, tenant string) (bool, error) { | ||
tag := new(models.Tags) | ||
|
||
cursor, err := s.db.Collection("tags").Find(ctx, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cursor is not explicitly closed, which could lead to resource leaks.
9a3af19
to
f6b5f3e
Compare
f6b5f3e
to
f9e95ed
Compare
feat(devices): implement backend support for tag colors