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

Added resource set validation #20

Merged
merged 5 commits into from
May 4, 2021
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
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)
}