Skip to content
This repository was archived by the owner on Oct 9, 2023. It is now read-only.

Commit 267a75c

Browse files
committed
models impl for tag stealing
1 parent efb3e0c commit 267a75c

3 files changed

Lines changed: 81 additions & 8 deletions

File tree

pkg/repositories/gormimpl/tag.go

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ import (
44
"context"
55

66
"github.com/jinzhu/gorm"
7+
"github.com/lyft/datacatalog/pkg/common"
78
"github.com/lyft/datacatalog/pkg/repositories/errors"
89
"github.com/lyft/datacatalog/pkg/repositories/interfaces"
910
"github.com/lyft/datacatalog/pkg/repositories/models"
1011
idl_datacatalog "github.com/lyft/datacatalog/protos/gen"
12+
"github.com/lyft/flytestdlib/logger"
1113
"github.com/lyft/flytestdlib/promutils"
1214
)
1315

@@ -25,14 +27,79 @@ func NewTagRepo(db *gorm.DB, errorTransformer errors.ErrorTransformer, scope pro
2527
}
2628
}
2729

30+
// A tag is associated with a single artifact for each partition combination
31+
// When creating a tag, we remove the tag from any artifacts of the same partition
32+
// Then add the tag to the new artifact
2833
func (h *tagRepo) Create(ctx context.Context, tag models.Tag) error {
2934
timer := h.repoMetrics.CreateDuration.Start(ctx)
3035
defer timer.Stop()
3136

32-
db := h.db.Create(&tag)
37+
tx := h.db.Begin()
3338

34-
if db.Error != nil {
35-
return h.errorTransformer.ToDataCatalogError(db.Error)
39+
var artifactToTag models.Artifact
40+
tx = tx.Preload("Partitions").Find(&artifactToTag, models.Artifact{
41+
ArtifactKey: models.ArtifactKey{ArtifactID: tag.ArtifactID},
42+
})
43+
44+
// List artifacts with the same partitions and tag
45+
filters := make([]models.ModelValueFilter, 0, len(artifactToTag.Partitions)*2+1)
46+
for _, partition := range artifactToTag.Partitions {
47+
filters = append(filters, NewGormValueFilter(common.Partition, common.Equal, "key", partition.Key))
48+
filters = append(filters, NewGormValueFilter(common.Partition, common.Equal, "value", partition.Value))
49+
}
50+
51+
filters = append(filters, NewGormValueFilter(common.Artifact, common.Equal, "tag_name", tag.TagName))
52+
53+
listTaggedArtifacts := models.ListModelsInput{
54+
JoinEntityToConditionMap: map[common.Entity]models.ModelJoinCondition{
55+
common.Tag: NewGormJoinCondition(common.Artifact, common.Tag),
56+
common.Partition: NewGormJoinCondition(common.Artifact, common.Partition),
57+
},
58+
Filters: filters,
59+
}
60+
61+
tx, err := applyListModelsInput(tx, common.Artifact, listTaggedArtifacts)
62+
if err != nil {
63+
tx.Rollback()
64+
return err
65+
}
66+
67+
var artifacts []models.Artifact
68+
tx = tx.Find(&artifacts)
69+
if tx.Error != nil {
70+
logger.Errorf(ctx, "Unable to find previously tagged artifacts, rolling back, tag: [%v], err [%v]", tag, tx.Error)
71+
tx.Rollback()
72+
return h.errorTransformer.ToDataCatalogError(tx.Error)
73+
}
74+
75+
if len(artifacts) != 0 {
76+
// Soft-delete the existing tags on the artifacts that are tagged by this tag in the partition
77+
oldTags := make([]models.Tag, 0, len(artifacts))
78+
for _, artifact := range artifacts {
79+
oldTags = append(oldTags, models.Tag{
80+
TagKey: models.TagKey{TagName: tag.TagName},
81+
ArtifactID: artifact.ArtifactID,
82+
})
83+
}
84+
tx = tx.Delete(&models.Tag{}, oldTags)
85+
}
86+
87+
// Check if the artifact was ever previously tagged with this tag, if so undelete the record
88+
var previouslyTagged *models.Artifact
89+
tx.Unscoped().Find(previouslyTagged, tag)
90+
if previouslyTagged != nil {
91+
previouslyTagged.DeletedAt = nil
92+
tx = tx.Update(previouslyTagged)
93+
} else {
94+
// Tag the new artifact
95+
tx = tx.Create(&tag)
96+
}
97+
98+
tx = tx.Commit()
99+
if tx.Error != nil {
100+
logger.Errorf(ctx, "Unable to create tag, rolling back, tag: [%v], err [%v]", tag, tx.Error)
101+
tx.Rollback()
102+
return h.errorTransformer.ToDataCatalogError(tx.Error)
36103
}
37104
return nil
38105
}

pkg/repositories/gormimpl/tag_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ func TestCreateTag(t *testing.T) {
5050
GlobalMock.Logging = true
5151

5252
// Only match on queries that append expected filters
53+
GlobalMock.NewMock().WithQuery(
54+
`SELECT * FROM "artifacts" WHERE "artifacts"."deleted_at" IS NULL AND (("artifacts"."artifact_id" = 123))`).WithReply(getDBArtifactResponse(getTestArtifact()))
55+
56+
GlobalMock.NewMock().WithQuery(
57+
`SELECT * FROM "partitions" WHERE "partitions"."deleted_at" IS NULL AND (("artifact_id" IN (123)))`).WithReply(getDBArtifactResponse(getTestArtifact()))
58+
5359
GlobalMock.NewMock().WithQuery(
5460
`INSERT INTO "tags" ("created_at","updated_at","deleted_at","dataset_project","dataset_name","dataset_domain","dataset_version","tag_name","artifact_id","dataset_uuid") VALUES (?,?,?,?,?,?,?,?,?,?)`).WithCallback(
5561
func(s string, values []driver.NamedValue) {

pkg/repositories/models/tag.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
package models
22

33
type TagKey struct {
4-
DatasetProject string `gorm:"primary_key"`
5-
DatasetName string `gorm:"primary_key"`
6-
DatasetDomain string `gorm:"primary_key"`
7-
DatasetVersion string `gorm:"primary_key"`
4+
DatasetProject string
5+
DatasetName string
6+
DatasetDomain string
7+
DatasetVersion string
88
TagName string `gorm:"primary_key"`
99
}
1010

1111
type Tag struct {
1212
BaseModel
1313
TagKey
14-
ArtifactID string
14+
ArtifactID string `gorm:"primary_key"`
1515
DatasetUUID string `gorm:"type:uuid;index:tags_dataset_uuid_idx"`
1616
Artifact Artifact `gorm:"association_foreignkey:DatasetProject,DatasetName,DatasetDomain,DatasetVersion,ArtifactID;foreignkey:DatasetProject,DatasetName,DatasetDomain,DatasetVersion,ArtifactID"`
1717
}

0 commit comments

Comments
 (0)