diff --git a/README.md b/README.md index e5b96dd7..76f88368 100644 --- a/README.md +++ b/README.md @@ -801,6 +801,11 @@ lint: enabled: true exclude: - schema_migrations + # checks if tables are included in at leaset one viewpoint + requireViewpoints: + enabled: true + exclued: + - schema_migrations ``` ### Filter tables diff --git a/config/lint.go b/config/lint.go index c7462bc6..822bcee0 100644 --- a/config/lint.go +++ b/config/lint.go @@ -23,6 +23,7 @@ type Lint struct { DuplicateRelations DuplicateRelations `yaml:"duplicateRelations"` RequireForeignKeyIndex RequireForeignKeyIndex `yaml:"requireForeignKeyIndex"` LabelStyleBigQuery LabelStyleBigQuery `yaml:"labelStyleBigQuery"` + RequireViewpoints RequireViewpoints `yaml:"requireViewpoints"` } // RuleWarn is struct of Rule error @@ -664,3 +665,48 @@ func checkLabelStyleBigQuery(label string) bool { } return true } + +// RequireViewpoints checks if the table is included in any viewpoints. +type RequireViewpoints struct { + Enabled bool `yaml:"enabled"` + Exclude []string `yaml:"exclude"` +} + +// IsEnabled return Rule is enabled or not +func (r RequireViewpoints) IsEnabled() bool { + return r.Enabled +} + +// Check if the table is included in any viewpoints. +func (r RequireViewpoints) Check(s *schema.Schema, exclude []string) []RuleWarn { + warns := []RuleWarn{} + if !r.IsEnabled() { + return warns + } + msgFmt := "table `%s` is not included in any viewpoints." + +T: + for _, t := range s.Tables { + if match(exclude, t.Name) { + continue + } + + if match(r.Exclude, t.Name) { + continue + } + + for _, v := range s.Viewpoints { + for _, vt := range v.Tables { + if vt == t.Name { + continue T + } + } + } + warns = append(warns, RuleWarn{ + Target: t.Name, + Message: fmt.Sprintf(msgFmt, t.Name), + }) + } + + return warns +} diff --git a/config/lint_test.go b/config/lint_test.go index 69ee807f..041a799b 100644 --- a/config/lint_test.go +++ b/config/lint_test.go @@ -642,6 +642,15 @@ func newTestSchema(t *testing.T) *schema.Schema { Name: "testdriver", DatabaseVersion: "1.0.0", }, + Viewpoints: []*schema.Viewpoint{ + &schema.Viewpoint{ + Name: "testviewpoint", + Desc: "testviewpoint desc", + Tables: []string{ + "table_c", // table_a and table_b is not included + }, + }, + }, } return s } @@ -679,3 +688,32 @@ func newTestNoRelationSchema(t *testing.T) *schema.Schema { s.Relations = nil return s } + +func TestRequireViewpoints(t *testing.T) { + tests := []struct { + enabled bool + lintExclude []string + exclude []string + want int + }{ + {true, []string{}, []string{}, 2}, + {false, []string{}, []string{}, 0}, + {true, []string{"table_a"}, []string{}, 1}, + {true, []string{"*_a"}, []string{}, 1}, + {true, []string{}, []string{"table_b"}, 1}, + } + + for i, tt := range tests { + r := RequireViewpoints{ + Enabled: tt.enabled, + Exclude: tt.exclude, + } + s := newTestSchema(t) + + s.Tables[0].Type = "VIEW" + warns := r.Check(s, tt.lintExclude) + if len(warns) != tt.want { + t.Errorf("TestRequireViewpoints(%d): got %v\nwant %v", i, len(warns), tt.want) + } + } +}