Skip to content

Commit

Permalink
feat: support fetching specific asset version with URN (#207)
Browse files Browse the repository at this point in the history
Add functionality to existing endpoint.
  • Loading branch information
sudo-suhas authored Feb 21, 2023
1 parent 7fc4a82 commit c96e577
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 66 deletions.
3 changes: 2 additions & 1 deletion core/asset/asset.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ type Repository interface {
GetByID(ctx context.Context, id string) (Asset, error)
GetByURN(ctx context.Context, urn string) (Asset, error)
GetVersionHistory(ctx context.Context, flt Filter, id string) ([]Asset, error)
GetByVersion(ctx context.Context, id string, version string) (Asset, error)
GetByVersionWithID(ctx context.Context, id string, version string) (Asset, error)
GetByVersionWithURN(ctx context.Context, urn string, version string) (Asset, error)
GetTypes(ctx context.Context, flt Filter) (map[Type]int, error)
Upsert(ctx context.Context, ast *Asset) (string, error)
DeleteByID(ctx context.Context, id string) error
Expand Down
64 changes: 55 additions & 9 deletions core/asset/mocks/asset_repository.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion core/asset/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,11 @@ func (s *Service) GetAssetByID(ctx context.Context, id string) (ast Asset, err e
}

func (s *Service) GetAssetByVersion(ctx context.Context, id string, version string) (Asset, error) {
return s.assetRepository.GetByVersion(ctx, id, version)
if isValidUUID(id) {
return s.assetRepository.GetByVersionWithID(ctx, id, version)
}

return s.assetRepository.GetByVersionWithURN(ctx, id, version)
}

func (s *Service) GetAssetVersionHistory(ctx context.Context, flt Filter, id string) ([]Asset, error) {
Expand Down
27 changes: 23 additions & 4 deletions core/asset/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,7 @@ func TestService_GetAssetByID(t *testing.T) {

func TestService_GetAssetByVersion(t *testing.T) {
assetID := "f742aa61-1100-445c-8d72-355a42e2fb59"
urn := "my-test-urn"
type testCase struct {
Description string
ID string
Expand All @@ -518,18 +519,36 @@ func TestService_GetAssetByVersion(t *testing.T) {

var testCases = []testCase{
{
Description: `should return error if the GetByVersion function return error`,
Description: `should return error if the GetByVersionWithID function return error`,
ID: assetID,
Setup: func(ctx context.Context, ar *mocks.AssetRepository) {
ar.EXPECT().GetByVersion(ctx, assetID, "v0.0.2").Return(asset.Asset{}, errors.New("error fetching asset"))
ar.EXPECT().GetByVersionWithID(ctx, assetID, "v0.0.2").
Return(asset.Asset{}, errors.New("error fetching asset"))
},
ExpectedErr: errors.New("error fetching asset"),
},
{
Description: `should return error if the GetByVersionWithURN function return error`,
ID: urn,
Setup: func(ctx context.Context, ar *mocks.AssetRepository) {
ar.EXPECT().GetByVersionWithURN(ctx, urn, "v0.0.2").
Return(asset.Asset{}, errors.New("error fetching asset"))
},
ExpectedErr: errors.New("error fetching asset"),
},
{
Description: `should return no error if asset is found`,
Description: `should return no error if asset is found with ID`,
ID: assetID,
Setup: func(ctx context.Context, ar *mocks.AssetRepository) {
ar.EXPECT().GetByVersion(ctx, assetID, "v0.0.2").Return(asset.Asset{}, nil)
ar.EXPECT().GetByVersionWithID(ctx, assetID, "v0.0.2").Return(asset.Asset{}, nil)
},
ExpectedErr: nil,
},
{
Description: `should return no error if asset is found with URN`,
ID: urn,
Setup: func(ctx context.Context, ar *mocks.AssetRepository) {
ar.EXPECT().GetByVersionWithURN(ctx, urn, "v0.0.2").Return(asset.Asset{}, nil)
},
ExpectedErr: nil,
},
Expand Down
70 changes: 44 additions & 26 deletions internal/store/postgres/asset_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,51 +208,69 @@ func (r *AssetRepository) GetVersionHistory(ctx context.Context, flt asset.Filte
return avs, nil
}

// GetByVersion retrieves the specific asset version
func (r *AssetRepository) GetByVersion(ctx context.Context, id string, version string) (ast asset.Asset, err error) {
// GetByVersionWithID retrieves the specific asset version
func (r *AssetRepository) GetByVersionWithID(ctx context.Context, id string, version string) (asset.Asset, error) {
if !isValidUUID(id) {
err = asset.InvalidError{AssetID: id}
return
return asset.Asset{}, asset.InvalidError{AssetID: id}
}

latestAsset, err := r.GetByID(ctx, id)
ast, err := r.getByVersion(ctx, id, version, r.GetByID, sq.Eq{
"a.asset_id": id,
"a.version": version,
})
if errors.Is(err, sql.ErrNoRows) {
err = asset.NotFoundError{AssetID: id}
return
return asset.Asset{}, asset.NotFoundError{AssetID: id}
}

if err != nil {
return
return asset.Asset{}, err
}

if latestAsset.Version == version {
ast = latestAsset
return
return ast, nil
}

func (r *AssetRepository) GetByVersionWithURN(ctx context.Context, urn string, version string) (asset.Asset, error) {
ast, err := r.getByVersion(ctx, urn, version, r.GetByURN, sq.Eq{
"a.urn": urn,
"a.version": version,
})
if errors.Is(err, sql.ErrNoRows) {
return asset.Asset{}, asset.NotFoundError{URN: urn}
}
if err != nil {
return asset.Asset{}, err
}

var assetModel AssetModel
builder := r.getAssetVersionSQL().
Where(sq.Eq{"a.asset_id": id, "a.version": version})
query, args, err := r.buildSQL(builder)
return ast, nil
}

type getAssetFunc func(context.Context, string) (asset.Asset, error)

func (r *AssetRepository) getByVersion(
ctx context.Context, id, version string, get getAssetFunc, pred sq.Eq,
) (asset.Asset, error) {
latest, err := get(ctx, id)
if err != nil {
err = fmt.Errorf("error building query: %w", err)
return
return asset.Asset{}, err
}

err = r.client.db.GetContext(ctx, &assetModel, query, args...)
if errors.Is(err, sql.ErrNoRows) {
err = asset.NotFoundError{AssetID: id}
return
if latest.Version == version {
return latest, nil
}

var ast AssetModel
builder := r.getAssetVersionSQL().
Where(pred)
query, args, err := r.buildSQL(builder)
if err != nil {
err = fmt.Errorf("failed fetching asset version: %w", err)
return
return asset.Asset{}, fmt.Errorf("error building query: %w", err)
}

ast, err = assetModel.toVersionedAsset(latestAsset)
err = r.client.db.GetContext(ctx, &ast, query, args...)
if err != nil {
return asset.Asset{}, fmt.Errorf("failed fetching asset version: %w", err)
}

return
return ast.toVersionedAsset(latest)
}

// Upsert creates a new asset if it does not exist yet.
Expand Down
69 changes: 44 additions & 25 deletions internal/store/postgres/asset_repository_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -803,16 +803,13 @@ func (r *AssetRepositoryTestSuite) TestVersions() {
r.NoError(err)
// making updatedby user time empty to make ast comparable
for i := 0; i < len(assetVersions); i++ {
assetVersions[i].UpdatedBy.CreatedAt = time.Time{}
assetVersions[i].UpdatedBy.UpdatedAt = time.Time{}
assetVersions[i].CreatedAt = time.Time{}
assetVersions[i].UpdatedAt = time.Time{}
clearTimestamps(&assetVersions[i])
}
r.Equal(expectedAssetVersions, assetVersions)
})

r.Run("should return current version of an assets", func() {
expectedLatestVersion := asset.Asset{
expected := asset.Asset{
ID: astVersioning.ID,
URN: assetURN,
Type: "table",
Expand All @@ -830,17 +827,14 @@ func (r *AssetRepositoryTestSuite) TestVersions() {
ast.Owners = nil
r.NoError(err)
// making updatedby user time empty to make ast comparable
ast.UpdatedBy.CreatedAt = time.Time{}
ast.UpdatedBy.UpdatedAt = time.Time{}
ast.CreatedAt = time.Time{}
ast.UpdatedAt = time.Time{}
r.Equal(expectedLatestVersion, ast)
clearTimestamps(&ast)
r.Equal(expected, ast)

r.Len(astOwners, 2)
})

r.Run("should return current version of an assets with by version", func() {
expectedLatestVersion := asset.Asset{
expected := asset.Asset{
ID: astVersioning.ID,
URN: assetURN,
Type: "table",
Expand All @@ -852,24 +846,31 @@ func (r *AssetRepositoryTestSuite) TestVersions() {
UpdatedBy: r.users[1],
}

ast, err := r.repository.GetByVersion(r.ctx, astVersioning.ID, "0.5")
ast, err := r.repository.GetByVersionWithID(r.ctx, astVersioning.ID, "0.5")
// hard to get the internally generated user id, we exclude the owners from the assertion
astOwners := ast.Owners
ast.Owners = nil
r.NoError(err)
// making updatedby user time empty to make ast comparable
ast.UpdatedBy.CreatedAt = time.Time{}
ast.UpdatedBy.UpdatedAt = time.Time{}
ast.CreatedAt = time.Time{}
ast.UpdatedAt = time.Time{}
r.Equal(expectedLatestVersion, ast)
clearTimestamps(&ast)
r.Equal(expected, ast)

r.Len(astOwners, 2)

ast, err = r.repository.GetByVersionWithURN(r.ctx, astVersioning.URN, "0.5")
// hard to get the internally generated user id, we exclude the owners from the assertion
astOwners = ast.Owners
ast.Owners = nil
r.NoError(err)
// making updatedby user time empty to make ast comparable
clearTimestamps(&ast)
r.Equal(expected, ast)
r.Len(astOwners, 2)
})

r.Run("should return a specific version of an asset", func() {
selectedVersion := "0.3"
expectedAsset := asset.Asset{
version := "0.3"
expected := asset.Asset{
ID: astVersioning.ID,
URN: assetURN,
Type: "table",
Expand All @@ -891,17 +892,28 @@ func (r *AssetRepositoryTestSuite) TestVersions() {
Provider: "meteor",
},
}
astVer, err := r.repository.GetByVersion(r.ctx, astVersioning.ID, selectedVersion)
astVer, err := r.repository.GetByVersionWithID(r.ctx, astVersioning.ID, version)
// hard to get the internally generated user id, we exclude the owners from the assertion
astOwners := astVer.Owners
astVer.Owners = nil
r.Assert().NoError(err)
// making updatedby user time empty to make ast comparable
astVer.UpdatedBy.CreatedAt = time.Time{}
astVer.UpdatedBy.UpdatedAt = time.Time{}
astVer.CreatedAt = time.Time{}
astVer.UpdatedAt = time.Time{}
r.Assert().Equal(expectedAsset, astVer)
clearTimestamps(&astVer)
r.Assert().Equal(expected, astVer)

for i := 0; i < len(astOwners); i++ {
astOwners[i].ID = ""
}
r.Assert().Equal(expectedOwners, astOwners)

astVer, err = r.repository.GetByVersionWithURN(r.ctx, astVersioning.URN, version)
// hard to get the internally generated user id, we exclude the owners from the assertion
astOwners = astVer.Owners
astVer.Owners = nil
r.Assert().NoError(err)
// making updatedby user time empty to make ast comparable
clearTimestamps(&astVer)
r.Assert().Equal(expected, astVer)

for i := 0; i < len(astOwners); i++ {
astOwners[i].ID = ""
Expand Down Expand Up @@ -1767,6 +1779,13 @@ func (r *AssetRepositoryTestSuite) assertAsset(expectedAsset *asset.Asset, actua
return r.Equal(expectedAsset, actualAsset)
}

func clearTimestamps(ast *asset.Asset) {
ast.UpdatedBy.CreatedAt = time.Time{}
ast.UpdatedBy.UpdatedAt = time.Time{}
ast.CreatedAt = time.Time{}
ast.UpdatedAt = time.Time{}
}

func (r *AssetRepositoryTestSuite) assertProbe(t *testing.T, expected asset.Probe, actual asset.Probe) bool {
t.Helper()

Expand Down

0 comments on commit c96e577

Please sign in to comment.