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

fix: Resolve column diags not returned #213

Merged
merged 2 commits into from
Mar 23, 2022
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
11 changes: 11 additions & 0 deletions provider/diag/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ func (e BaseError) Unwrap() error {
type BaseErrorOption func(*BaseError)

// WithNoOverwrite sets the noOverwrite flag of BaseError, active for the duration of the application of options
// Deprecated: Prefer using WithOptionalSeverity on the opposite side instead
func WithNoOverwrite() BaseErrorOption {
return func(e *BaseError) {
e.noOverwrite = true
Expand All @@ -127,6 +128,16 @@ func WithSeverity(s Severity) BaseErrorOption {
}
}

func WithOptionalSeverity(s Severity) BaseErrorOption {
return func(e *BaseError) {
if e.noOverwrite || e.severitySet {
return
}
// we keep as e.severitySet = false
e.severity = s
}
}

func WithType(dt DiagnosticType) BaseErrorOption {
return func(e *BaseError) {
if !e.noOverwrite || dt > e.diagnosticType {
Expand Down
41 changes: 25 additions & 16 deletions provider/execution/execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,9 +274,10 @@ func (e TableExecutor) resolveResources(ctx context.Context, meta schema.ClientM
for _, o := range objects {
resource := schema.NewResourceData(e.Db.Dialect(), e.Table, parent, o, e.metadata, e.executionStart)
// Before inserting resolve all table column resolvers
if err := e.resolveResourceValues(ctx, meta, resource); err != nil {
e.Logger.Warn("skipping failed resolved resource", "reason", err.Error())
diags = diags.Add(err)
resolveDiags := e.resolveResourceValues(ctx, meta, resource)
diags = diags.Add(resolveDiags)
if resolveDiags.HasErrors() {
e.Logger.Warn("skipping failed resolved resource", "reason", resolveDiags.Error())
continue
}
resources = append(resources, resource)
Expand Down Expand Up @@ -345,26 +346,31 @@ func (e TableExecutor) resolveResourceValues(ctx context.Context, meta schema.Cl
diag.WithSummary("resolve table %q recovered from panic.", e.Table.Name), diag.WithDetails("%s", stack))
}
}()
if err := e.resolveColumns(ctx, meta, resource, e.columns[0]); err != nil {
return err

diags = diags.Add(e.resolveColumns(ctx, meta, resource, e.columns[0]))
if diags.HasErrors() {
return diags
}

// call PostRowResolver if defined after columns have been resolved
if e.Table.PostResourceResolver != nil {
if err := e.Table.PostResourceResolver(ctx, meta, resource); err != nil {
return e.handleResolveError(meta, resource, err, diag.WithSummary("post resource resolver failed for %q", e.Table.Name))
return diags.Add(e.handleResolveError(meta, resource, err, diag.WithSummary("post resource resolver failed for %q", e.Table.Name)))
}
}
// Finally, resolve columns internal to the SDK
for _, c := range e.columns[1] {
if err := c.Resolver(ctx, meta, resource, c); err != nil {
return fromError(err, diag.WithResourceName(e.ResourceName), WithResource(resource), diag.WithType(diag.INTERNAL), diag.WithSummary("default column %q resolver execution", c.Name))
return diags.Add(fromError(err, diag.WithResourceName(e.ResourceName), WithResource(resource), diag.WithType(diag.INTERNAL), diag.WithSummary("default column %q resolver execution", c.Name)))
}
}
return diags
}

// resolveColumns resolves each column in the table and adds them to the resource.
func (e TableExecutor) resolveColumns(ctx context.Context, meta schema.ClientMeta, resource *schema.Resource, cols []schema.Column) diag.Diagnostics {

var diags diag.Diagnostics
for _, c := range cols {
if c.Resolver != nil {
meta.Logger().Trace("using custom column resolver", "column", c.Name, "table", e.Table.Name)
Expand All @@ -374,20 +380,23 @@ func (e TableExecutor) resolveColumns(ctx context.Context, meta schema.ClientMet
}
// Not allowed ignoring PK resolver errors
if funk.ContainsString(e.Db.Dialect().PrimaryKeys(e.Table), c.Name) {
return ClassifyError(err, diag.WithResourceName(e.ResourceName), WithResource(resource), diag.WithSummary("failed to resolve column %s@%s", e.Table.Name, c.Name))
return diags.Add(ClassifyError(err, diag.WithResourceName(e.ResourceName), WithResource(resource), diag.WithSummary("failed to resolve column %s@%s", e.Table.Name, c.Name)))
}
// check if column resolver defined an IgnoreError function, if it does check if ignore should be ignored.
if c.IgnoreError == nil || !c.IgnoreError(err) {
return e.handleResolveError(meta, resource, err, diag.WithSummary("column resolver %q failed for table %q", c.Name, e.Table.Name))
if c.IgnoreError != nil && c.IgnoreError(err) {
diags = diags.Add(e.handleResolveError(meta, resource, err, diag.WithSeverity(diag.IGNORE), diag.WithSummary("column resolver %q failed for table %q", c.Name, e.Table.Name)))
} else {
diags = diags.Add(e.handleResolveError(meta, resource, err, diag.WithSummary("column resolver %q failed for table %q", c.Name, e.Table.Name)))
}

// TODO: double check logic here
if reflect2.IsNil(c.Default) {
continue
}
// Set default value if defined, otherwise it will be nil
if err := resource.Set(c.Name, c.Default); err != nil {
return fromError(err, diag.WithResourceName(e.ResourceName), diag.WithType(diag.INTERNAL),
diag.WithSummary("failed to set resource default value for %s@%s", e.Table.Name, c.Name))
diags = diags.Add(fromError(err, diag.WithResourceName(e.ResourceName), diag.WithType(diag.INTERNAL),
diag.WithSummary("failed to set resource default value for %s@%s", e.Table.Name, c.Name)))
}
continue
}
Expand All @@ -400,19 +409,19 @@ func (e TableExecutor) resolveColumns(ctx context.Context, meta schema.ClientMet
}
meta.Logger().Trace("setting column value", "column", c.Name, "value", v, "table", e.Table.Name)
if err := resource.Set(c.Name, v); err != nil {
return fromError(err, diag.WithResourceName(e.ResourceName), diag.WithType(diag.INTERNAL),
diag.WithSummary("failed to set resource value for column %s@%s", e.Table.Name, c.Name))
diags = diags.Add(fromError(err, diag.WithResourceName(e.ResourceName), diag.WithType(diag.INTERNAL),
diag.WithSummary("failed to set resource value for column %s@%s", e.Table.Name, c.Name)))
}
}
return nil
return diags
}

// handleResolveError handles errors returned by user defined functions, using the ErrorClassifiers if defined.
func (e TableExecutor) handleResolveError(meta schema.ClientMeta, r *schema.Resource, err error, opts ...diag.BaseErrorOption) diag.Diagnostics {
errAsDiags := fromError(err, append(opts,
diag.WithResourceName(e.ResourceName),
WithResource(r),
diag.WithSeverity(diag.ERROR),
diag.WithOptionalSeverity(diag.ERROR),
diag.WithType(diag.RESOLVING),
diag.WithSummary("failed to resolve table %q", e.Table.Name),
)...)
Expand Down