From 896dbe43b560ce6c493a604c8882b5b112b5be50 Mon Sep 17 00:00:00 2001 From: David Flanagan Date: Wed, 2 Mar 2022 17:15:31 +0000 Subject: [PATCH] fix: handle referential integrity for lists of references --- content/repository.go | 23 ++++++++++++++--------- go.mod | 1 - go.sum | 2 -- internal/cuedb/engine.go | 17 ++++++++++++++--- internal/cuedb/engine_test.go | 1 + internal/cueutils/utils.go | 12 ------------ 6 files changed, 29 insertions(+), 27 deletions(-) diff --git a/content/repository.go b/content/repository.go index e5c7b16..717310b 100644 --- a/content/repository.go +++ b/content/repository.go @@ -11,6 +11,7 @@ import ( "path/filepath" "strings" + cueError "cuelang.org/go/cue/errors" "github.com/cueblox/blox" "github.com/graphql-go/graphql" @@ -18,7 +19,6 @@ import ( "github.com/cueblox/blox/internal/encoding/markdown" "github.com/cueblox/blox/internal/repository" "github.com/goccy/go-yaml" - "github.com/hashicorp/go-multierror" "github.com/hashicorp/go-plugin" "github.com/pterm/pterm" ) @@ -91,8 +91,6 @@ func NewService(bloxConfig string, referentialIntegrity bool) (*Service, error) } func (s *Service) build() error { - var errors error - err := s.parseRemotes() if err != nil { return err @@ -104,6 +102,8 @@ func (s *Service) build() error { return err } + var errors cueError.Error + for _, dataSet := range s.engine.GetDataSets() { pterm.Debug.Printf("\t\tBuilding Dataset: %s\n", dataSet.ID()) @@ -113,7 +113,7 @@ func (s *Service) build() error { err := os.MkdirAll(dataSetDirectory, 0o755) if err != nil { - errors = multierror.Append(err) + errors = cueError.Append(errors, cueError.Promote(err, "MkdirAll Failed")) continue } @@ -140,7 +140,7 @@ func (s *Service) build() error { pterm.Debug.Println(slug) bytes, err := ioutil.ReadFile(path) if err != nil { - return multierror.Append(err) + return cueError.Append(errors, cueError.Promote(err, "ReadFile Failed")) } // Loaders to get to YAML @@ -159,7 +159,7 @@ func (s *Service) build() error { err = yaml.Unmarshal(bytes, &istruct) if err != nil { - return multierror.Append(err) + return cueError.Append(errors, cueError.Promote(err, "YAML Unmarshal Failed")) } record := make(map[string]interface{}) @@ -167,7 +167,7 @@ func (s *Service) build() error { err = s.engine.Insert(dataSet, record) if err != nil { - return multierror.Append(err) + return cueError.Append(errors, cueError.Promote(err, "CueDB Insert Failed")) } return err @@ -175,14 +175,19 @@ func (s *Service) build() error { ) if err != nil { - errors = multierror.Append(err) + errors = cueError.Append(errors, cueError.Promote(err, "Data Walk Errors")) } } if s.ri { err := s.engine.ReferentialIntegrity() if err != nil { - errors = multierror.Append(err) + errors = cueError.Append(errors, cueError.Promote(err, "Referential Integrity Failed")) + for _, v := range cueError.Errors(errors) { + pterm.Error.ShowLineNumber = false + pterm.Error.Println(v) + pterm.Error.ShowLineNumber = true + } } } diff --git a/go.mod b/go.mod index 46f63c2..4807b38 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,6 @@ require ( github.com/graphql-go/handler v0.2.3 github.com/h2non/filetype v1.1.1 github.com/hashicorp/go-hclog v0.16.2 - github.com/hashicorp/go-multierror v1.0.0 github.com/hashicorp/go-plugin v1.4.2 github.com/heimdalr/dag v1.0.1 github.com/lib/pq v1.9.0 // indirect diff --git a/go.sum b/go.sum index b21545c..6b65af7 100644 --- a/go.sum +++ b/go.sum @@ -136,7 +136,6 @@ github.com/h2non/filetype v1.1.1 h1:xvOwnXKAckvtLWsN398qS9QhlxlnVXBjXBydK2/UFB4= github.com/h2non/filetype v1.1.1/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= @@ -144,7 +143,6 @@ github.com/hashicorp/go-hclog v0.16.2 h1:K4ev2ib4LdQETX5cSZBG0DVLk1jwGqSPXBjdah3 github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-plugin v1.4.2 h1:yFvG3ufXXpqiMiZx9HLcaK3XbIqQ1WJFR/F1a2CuVw0= github.com/hashicorp/go-plugin v1.4.2/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ= diff --git a/internal/cuedb/engine.go b/internal/cuedb/engine.go index b8a1b43..bf3f349 100644 --- a/internal/cuedb/engine.go +++ b/internal/cuedb/engine.go @@ -7,7 +7,6 @@ import ( "cuelang.org/go/cue" "github.com/cueblox/blox" - "github.com/hashicorp/go-multierror" "github.com/heimdalr/dag" "github.com/pterm/pterm" ) @@ -388,7 +387,17 @@ func (r *Engine) ReferentialIntegrity() error { optional = "?" } - value := r.CueContext.CompileString(fmt.Sprintf("{data: _\n%s: %s: %s%s: or([ for k, _ in data.%s {k}])}", dataSet.GetInlinePath(), dataSet.name, fields.Label(), optional, foreignTable.GetDataDirectory())) + var value cue.Value + switch fields.Value().IncompleteKind() { + case cue.StringKind: + value = r.CueContext.CompileString(fmt.Sprintf("{data: _\n%s: %s: %s%s: or([ for k, _ in data.%s {k}])}", dataSet.GetInlinePath(), dataSet.name, fields.Label(), optional, foreignTable.GetDataDirectory())) + case cue.ListKind: + value = r.CueContext.CompileString(fmt.Sprintf("{data: _\n%s: %s: %s%s: [...or([ for k, _ in data.%s {k}])]}", dataSet.GetInlinePath(), dataSet.name, fields.Label(), optional, foreignTable.GetDataDirectory())) + } + + // #names: ["Paul", "Marcel", "cueckoo"] + // #validname: or(#names) + // #name: #validname | [#validname] if value.Err() != nil { return value.Err() } @@ -397,6 +406,7 @@ func (r *Engine) ReferentialIntegrity() error { continue } + // TODO: This behaviour should probably be deprecated soon if strings.HasSuffix(fields.Label(), "_id") { foreignTable, err := r.GetDataSet(strings.TrimSuffix(fields.Label(), "_id")) if err != nil { @@ -419,8 +429,9 @@ func (r *Engine) ReferentialIntegrity() error { } err := r.Database.Validate() + if err != nil { - return multierror.Prefix(err, "Referential Integrity Failed") + return err } return nil diff --git a/internal/cuedb/engine_test.go b/internal/cuedb/engine_test.go index 573f2fb..6899aef 100644 --- a/internal/cuedb/engine_test.go +++ b/internal/cuedb/engine_test.go @@ -298,6 +298,7 @@ func TestRelationshipParsing(t *testing.T) { {cueLiteral: "name: string, profile: string", expected: []string{}}, {cueLiteral: "name: string, profile: string @relationship(Person)", expected: []string{"Person"}}, {cueLiteral: "name: string, profile: string, person: string @relationship(Person)", expected: []string{"Person"}}, + {cueLiteral: "name: string, profile: string, people: [...string] @relationship(Person)", expected: []string{"Person"}}, } cueContext := cuecontext.New() diff --git a/internal/cueutils/utils.go b/internal/cueutils/utils.go index fd93e24..c8a2f73 100644 --- a/internal/cueutils/utils.go +++ b/internal/cueutils/utils.go @@ -6,21 +6,9 @@ import ( "cuelang.org/go/cue" "cuelang.org/go/cue/ast" - "cuelang.org/go/cue/errors" - "github.com/hashicorp/go-multierror" "github.com/pterm/pterm" ) -// UsefulError returns an error that is concatenated from -// multiple cue errors -func UsefulError(err error) error { - var usefulError error - for _, err := range errors.Errors(err) { - usefulError = multierror.Append(usefulError, err) - } - return usefulError -} - // GetAcceptedValues returns the values constraints // for a cue node func GetAcceptedValues(node ast.Node) ([]string, error) {