Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 8 additions & 4 deletions datacomparison/entitytype_enumer.go

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

11 changes: 11 additions & 0 deletions datacomparison/reference.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package datacomparison

import (
"context"
"errors"
"fmt"

"github.com/collibra/go-bexpression/base"
Expand All @@ -13,14 +14,24 @@ type EntityType int
const (
EntityTypeDataObject EntityType = iota
EntityTypeColumnReferenceByName
EntityTypeColumnReferenceByTag
)

var ErrTagKeyRequired = errors.New("tagKey is required for a ColumnReferenceByTag reference")

type Reference struct {
EntityType EntityType `json:"entityType,omitempty" yaml:"entityType,omitempty" gqlgen:"entityType"`
EntityID string `json:"entityId,omitempty" yaml:"entityId,omitempty" gqlgen:"entityId"`
// TagKey and TagValue select the column for EntityTypeColumnReferenceByTag. An empty TagValue matches any value.
TagKey string `json:"tagKey,omitempty" yaml:"tagKey,omitempty" gqlgen:"tagKey"`
TagValue string `json:"tagValue,omitempty" yaml:"tagValue,omitempty" gqlgen:"tagValue"`
}

func (r *Reference) Validate(_ context.Context) error {
if r.EntityType == EntityTypeColumnReferenceByTag && r.TagKey == "" {
return ErrTagKeyRequired
}

return nil
}

Expand Down
123 changes: 121 additions & 2 deletions datacomparison/reference_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package datacomparison

import (
"context"
"encoding/json"
"errors"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"gopkg.in/yaml.v3"

"github.com/collibra/go-bexpression/base"
)
Expand All @@ -15,6 +17,8 @@ func TestReference_Accept(t *testing.T) {
type fields struct {
EntityType EntityType
EntityID string
TagKey string
TagValue string
}
type args struct {
ctx context.Context
Expand All @@ -40,6 +44,21 @@ func TestReference_Accept(t *testing.T) {
},
wantErr: false,
},
{
name: "tag reference",
fields: fields{
EntityType: EntityTypeColumnReferenceByTag,
TagKey: "Country",
TagValue: "DE",
},
args: args{
ctx: context.Background(),
visitorSetup: func(visitor *base.MockVisitor) {
visitor.EXPECT().Literal(mock.Anything, &Reference{EntityType: EntityTypeColumnReferenceByTag, TagKey: "Country", TagValue: "DE"}).Return(nil).Once()
},
},
wantErr: false,
},
{
name: "visitor failed",
fields: fields{
Expand All @@ -63,6 +82,8 @@ func TestReference_Accept(t *testing.T) {
r := &Reference{
EntityType: tt.fields.EntityType,
EntityID: tt.fields.EntityID,
TagKey: tt.fields.TagKey,
TagValue: tt.fields.TagValue,
}
if err := r.Accept(tt.args.ctx, visitorMock); (err != nil) != tt.wantErr {
t.Errorf("Accept() error = %v, wantErr %v", err, tt.wantErr)
Expand All @@ -72,7 +93,105 @@ func TestReference_Accept(t *testing.T) {
}

func TestReference_Validate(t *testing.T) {
r := Reference{}
tests := []struct {
name string
ref Reference
wantErr error
}{
{name: "empty reference", ref: Reference{}},
{name: "column reference by name", ref: Reference{EntityType: EntityTypeColumnReferenceByName, EntityID: "COUNTRY"}},
{name: "tag reference with key", ref: Reference{EntityType: EntityTypeColumnReferenceByTag, TagKey: "Country"}},
{name: "tag reference with key and value", ref: Reference{EntityType: EntityTypeColumnReferenceByTag, TagKey: "Country", TagValue: "DE"}},
{name: "tag reference without key", ref: Reference{EntityType: EntityTypeColumnReferenceByTag}, wantErr: ErrTagKeyRequired},
{name: "tag reference with value only", ref: Reference{EntityType: EntityTypeColumnReferenceByTag, TagValue: "DE"}, wantErr: ErrTagKeyRequired},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.ref.Validate(context.Background())

if tt.wantErr == nil {
assert.NoError(t, err)
return
}
assert.ErrorIs(t, err, tt.wantErr)
})
}
}

func TestReference_JSONRoundTrip(t *testing.T) {
tests := []struct {
name string
ref Reference
wantJSON string
}{
{
name: "tag key and value",
ref: Reference{EntityType: EntityTypeColumnReferenceByTag, TagKey: "Country", TagValue: "DE"},
wantJSON: `{"entityType":"ColumnReferenceByTag","tagKey":"Country","tagValue":"DE"}`,
},
{
name: "tag key only omits the value",
ref: Reference{EntityType: EntityTypeColumnReferenceByTag, TagKey: "Country"},
wantJSON: `{"entityType":"ColumnReferenceByTag","tagKey":"Country"}`,
},
{
name: "column reference by name omits the tag fields",
ref: Reference{EntityType: EntityTypeColumnReferenceByName, EntityID: "COUNTRY"},
wantJSON: `{"entityType":"ColumnReferenceByName","entityId":"COUNTRY"}`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := json.Marshal(tt.ref)
assert.NoError(t, err)
assert.JSONEq(t, tt.wantJSON, string(got))

var back Reference
assert.NoError(t, json.Unmarshal(got, &back))
assert.Equal(t, tt.ref, back)
})
}
}

func TestReference_YAMLRoundTrip(t *testing.T) {
tests := []struct {
name string
ref Reference
wantYAML string
}{
{
name: "tag key and value",
ref: Reference{EntityType: EntityTypeColumnReferenceByTag, TagKey: "Country", TagValue: "DE"},
wantYAML: "entityType: ColumnReferenceByTag\ntagKey: Country\ntagValue: DE\n",
},
{
name: "tag key only omits the value",
ref: Reference{EntityType: EntityTypeColumnReferenceByTag, TagKey: "Country"},
wantYAML: "entityType: ColumnReferenceByTag\ntagKey: Country\n",
},
{
name: "column reference by name omits the tag fields",
ref: Reference{EntityType: EntityTypeColumnReferenceByName, EntityID: "COUNTRY"},
wantYAML: "entityType: ColumnReferenceByName\nentityId: COUNTRY\n",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := yaml.Marshal(tt.ref)
assert.NoError(t, err)
assert.Equal(t, tt.wantYAML, string(got))

var back Reference
assert.NoError(t, yaml.Unmarshal(got, &back))
assert.Equal(t, tt.ref, back)
})
}
}

func TestEntityType_ColumnReferenceByTag(t *testing.T) {
assert.Equal(t, "ColumnReferenceByTag", EntityTypeColumnReferenceByTag.String())

assert.NoError(t, r.Validate(context.Background()))
got, err := EntityTypeString("ColumnReferenceByTag")
assert.NoError(t, err)
assert.Equal(t, EntityTypeColumnReferenceByTag, got)
}
6 changes: 4 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ tool (
github.com/vektra/mockery/v3
)

require github.com/stretchr/testify v1.11.1
require (
github.com/stretchr/testify v1.11.1
gopkg.in/yaml.v3 v3.0.1
)

require (
github.com/brunoga/deep v1.2.5 // indirect
Expand Down Expand Up @@ -50,5 +53,4 @@ require (
golang.org/x/term v0.35.0 // indirect
golang.org/x/text v0.29.0 // indirect
golang.org/x/tools v0.37.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
2 changes: 1 addition & 1 deletion language
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ BinaryOperand:
<Reference>|<Literal>

Reference:
ENTITYTYPE ENTITYID
ENTITYTYPE ENTITYID | ColumnReferenceByTag TAGKEY [TAGVALUE]

Literal:
BOOL|INT|FLOAT|STRING|TIMESTAMP
Expand Down
Loading