Skip to content
This repository has been archived by the owner on Aug 12, 2022. It is now read-only.

Commit

Permalink
Added resource set validation (#20)
Browse files Browse the repository at this point in the history
* Added resource set validation #7
* Added TableValidation to enforce column/table name longer than 63 char #9
  • Loading branch information
zagronitay authored May 4, 2021
1 parent a143680 commit 7d8a9a3
Show file tree
Hide file tree
Showing 10 changed files with 156 additions and 13 deletions.
5 changes: 4 additions & 1 deletion provider/migrator.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ type Migrator struct {
}

func NewMigrator(db schema.Database, log hclog.Logger) Migrator {
return Migrator{db, log}
return Migrator{
db,
log,
}
}

func (m Migrator) upgradeTable(ctx context.Context, t *schema.Table) error {
Expand Down
8 changes: 8 additions & 0 deletions provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,14 @@ func (p *Provider) Init(_ string, dsn string, _ bool) error {
// Create tables
m := NewMigrator(p.db, p.Logger)
for _, t := range p.ResourceMap {

// validate table
validationErr := schema.ValidateTable(t)
if validationErr != nil {
p.Logger.Error("table validation failed", "table", t.Name, "error", err)
return err
}

err := m.CreateTable(context.Background(), t, nil)
if err != nil {
p.Logger.Error("failed to create table", "table", t.Name, "error", err)
Expand Down
5 changes: 4 additions & 1 deletion provider/schema/execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,10 @@ func (e ExecutionData) resolveColumns(ctx context.Context, meta ClientMeta, reso
if v == nil {
v = c.Default
}
resource.Set(c.Name, v)
err := resource.Set(c.Name, v)
if err != nil {
return err
}
}
return nil
}
3 changes: 2 additions & 1 deletion provider/schema/execution_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,8 @@ func TestExecutionData_ResolveTable(t *testing.T) {
testTable.Resolver = dataReturningSingleResolver
var expectedResource *Resource
testTable.PostResourceResolver = func(ctx context.Context, meta ClientMeta, parent *Resource) error {
parent.Set("name", "other")
err := parent.Set("name", "other")
assert.Nil(t, err)
expectedResource = parent
return nil
}
Expand Down
6 changes: 2 additions & 4 deletions provider/schema/resolvers.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,12 @@ import (

func PathResolver(path string) ColumnResolver {
return func(_ context.Context, meta ClientMeta, r *Resource, c Column) error {
r.Set(c.Name, funk.GetAllowZero(r.Item, path))
return nil
return r.Set(c.Name, funk.GetAllowZero(r.Item, path))
}
}

func ParentIdResolver(_ context.Context, _ ClientMeta, r *Resource, c Column) error {
r.Set(c.Name, r.Parent.Id())
return nil
return r.Set(c.Name, r.Parent.Id())
}

func interfaceSlice(slice interface{}) []interface{} {
Expand Down
16 changes: 16 additions & 0 deletions provider/schema/resolvers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,22 @@ func TestPathResolver(t *testing.T) {
resource := &Resource{
Item: testStruct{Inner: innerStruct{Value: "bla"}, Value: 5, unexported: false},
data: map[string]interface{}{},
table: &Table{
Columns: []Column{
{
Name: "test",
Type: TypeString,
},
{
Name: "int_value",
Type: TypeInt,
},
{
Name: "unexported",
Type: TypeBool,
},
},
},
}
err := r1(context.TODO(), nil, resource, Column{Name: "test"})

Expand Down
10 changes: 9 additions & 1 deletion provider/schema/resource.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package schema

import (
"fmt"

"github.com/cloudquery/go-funk"
"github.com/google/uuid"
)

Expand Down Expand Up @@ -31,8 +34,13 @@ func (r Resource) Get(key string) interface{} {
return r.data[key]
}

func (r Resource) Set(key string, value interface{}) {
func (r Resource) Set(key string, value interface{}) error {
columnExists := funk.ContainsString(r.table.ColumnNames(), key)
if !columnExists {
return fmt.Errorf("column %s does not exits", key)
}
r.data[key] = value
return nil
}

func (r Resource) Id() uuid.UUID {
Expand Down
19 changes: 14 additions & 5 deletions provider/schema/resources_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,24 +57,33 @@ type zeroValuedStruct struct {
func TestResourceColumns(t *testing.T) {

r := NewResourceData(testTable, nil, nil)
r.Set("name", "test")
errf := r.Set("name", "test")
assert.Nil(t, errf)
assert.Equal(t, r.Get("name"), "test")
v, err := r.Values()
assert.Nil(t, err)
assert.Equal(t, v, []interface{}{r.id, "test", nil, nil})
// Set invalid type to resource
r.Set("name", 5)
errf = r.Set("name", 5)
assert.Nil(t, errf)
v, err = r.Values()
assert.Error(t, err)
assert.Nil(t, v)

// Set resource fully
r.Set("name", "test")
r.Set("name_no_prefix", "name_no_prefix")
r.Set("prefix_name", "prefix_name")
errf = r.Set("name", "test")
assert.Nil(t, errf)
errf = r.Set("name_no_prefix", "name_no_prefix")
assert.Nil(t, errf)
errf = r.Set("prefix_name", "prefix_name")
assert.Nil(t, errf)
v, err = r.Values()
assert.Nil(t, err)
assert.Equal(t, v, []interface{}{r.id, "test", "name_no_prefix", "prefix_name"})

// check non existing col
err = r.Set("non_exist_col", "test")
assert.Error(t, err)
}

func TestResourceResolveColumns(t *testing.T) {
Expand Down
54 changes: 54 additions & 0 deletions provider/schema/validators.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package schema

import (
"errors"
"fmt"
)

const maxTableName = 63

const maxColumnName = 63

var defaultValidators = []TableValidator{
LengthTableValidator{},
}

func ValidateTable(t *Table) error {
for _, validator := range defaultValidators {
return validator.Validate(t)
}
return nil
}

type TableValidator interface {
Validate(t *Table) error
}

type LengthTableValidator struct{}

func validateTableAttributesNameLength(t *Table) error {
// validate table name
if len(t.Name) > maxTableName {
return errors.New("table name has exceeded max length")
}

// validate table columns
for _, col := range t.ColumnNames() {
if len(col) > maxColumnName {
return fmt.Errorf("column name %s has exceeded max length", col)
}
}

// validate table relations
for _, rel := range t.Relations {
err := validateTableAttributesNameLength(rel)
if err != nil {
return err
}
}
return nil
}

func (tv LengthTableValidator) Validate(t *Table) error {
return validateTableAttributesNameLength(t)
}
43 changes: 43 additions & 0 deletions provider/schema/validators_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package schema

import (
"github.com/stretchr/testify/assert"

"testing"
)

var testTableValidators = Table{
Name: "test_table_validator",
Columns: []Column{
{
Name: "zero_bool",
Type: TypeBool,
},
{
Name: "zero_int",
Type: TypeBigInt,
},
{
Name: "not_zero_bool",
Type: TypeBool,
},
},
}

func TestTableValidators(t *testing.T) {
// table has passed all validators
err := ValidateTable(&testTableValidators)
assert.Nil(t, err)

// table name is too long
tableWithLongName := testTableValidators
tableWithLongName.Name = "WithLongNametableWithLongNametableWithLongNametableWithLongNamet"
err = ValidateTable(&tableWithLongName)
assert.Error(t, err)

// column name is too long
tableWithLongColumnName := testTableValidators
tableWithLongName.Columns[0].Name = "tableWithLongColumnNametableWithLongColumnNametableWithLongColumnName"
err = ValidateTable(&tableWithLongColumnName)
assert.Error(t, err)
}

0 comments on commit 7d8a9a3

Please sign in to comment.