diff --git a/pkg/acceptance/bettertestspoc/assert/objectassert/function_describe_snowflake_ext.go b/pkg/acceptance/bettertestspoc/assert/objectassert/function_describe_snowflake_ext.go index c1b241aa1d..f540d487bd 100644 --- a/pkg/acceptance/bettertestspoc/assert/objectassert/function_describe_snowflake_ext.go +++ b/pkg/acceptance/bettertestspoc/assert/objectassert/function_describe_snowflake_ext.go @@ -2,11 +2,13 @@ package objectassert import ( "fmt" + "strings" "testing" acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/collections" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" ) @@ -368,3 +370,38 @@ func (f *FunctionDetailsAssert) HasInstalledPackagesNotEmpty() *FunctionDetailsA }) return f } + +func (f *FunctionDetailsAssert) HasExactlyExternalAccessIntegrations(integrations ...sdk.AccountObjectIdentifier) *FunctionDetailsAssert { + f.AddAssertion(func(t *testing.T, o *sdk.FunctionDetails) error { + t.Helper() + if o.ExternalAccessIntegrations == nil { + return fmt.Errorf("expected external access integrations to have value; got: nil") + } + joined := strings.Join(collections.Map(integrations, func(ex sdk.AccountObjectIdentifier) string { return ex.FullyQualifiedName() }), ",") + expected := fmt.Sprintf(`[%s]`, joined) + if *o.ExternalAccessIntegrations != expected { + return fmt.Errorf("expected external access integrations: %v; got: %v", expected, *o.ExternalAccessIntegrations) + } + return nil + }) + return f +} + +func (f *FunctionDetailsAssert) HasExactlySecrets(expectedSecrets map[string]sdk.SchemaObjectIdentifier) *FunctionDetailsAssert { + f.AddAssertion(func(t *testing.T, o *sdk.FunctionDetails) error { + t.Helper() + if o.Secrets == nil { + return fmt.Errorf("expected secrets to have value; got: nil") + } + var parts []string + for k, v := range expectedSecrets { + parts = append(parts, fmt.Sprintf(`"%s":"\"%s\".\"%s\".%s"`, k, v.DatabaseName(), v.SchemaName(), v.Name())) + } + expected := fmt.Sprintf(`{%s}`, strings.Join(parts, ",")) + if *o.Secrets != expected { + return fmt.Errorf("expected secrets: %v; got: %v", expected, *o.Secrets) + } + return nil + }) + return f +} diff --git a/pkg/acceptance/bettertestspoc/assert/objectassert/function_snowflake_ext.go b/pkg/acceptance/bettertestspoc/assert/objectassert/function_snowflake_ext.go index 66e4253d20..aa8d17a022 100644 --- a/pkg/acceptance/bettertestspoc/assert/objectassert/function_snowflake_ext.go +++ b/pkg/acceptance/bettertestspoc/assert/objectassert/function_snowflake_ext.go @@ -2,8 +2,10 @@ package objectassert import ( "fmt" + "strings" "testing" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/collections" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" ) @@ -28,3 +30,38 @@ func (a *FunctionAssert) HasExternalAccessIntegrationsNil() *FunctionAssert { }) return a } + +func (f *FunctionAssert) HasExactlyExternalAccessIntegrations(integrations ...sdk.AccountObjectIdentifier) *FunctionAssert { + f.AddAssertion(func(t *testing.T, o *sdk.Function) error { + t.Helper() + if o.ExternalAccessIntegrations == nil { + return fmt.Errorf("expected external access integrations to have value; got: nil") + } + joined := strings.Join(collections.Map(integrations, func(ex sdk.AccountObjectIdentifier) string { return ex.FullyQualifiedName() }), ",") + expected := fmt.Sprintf(`[%s]`, joined) + if *o.ExternalAccessIntegrations != expected { + return fmt.Errorf("expected external access integrations: %v; got: %v", expected, *o.ExternalAccessIntegrations) + } + return nil + }) + return f +} + +func (f *FunctionAssert) HasExactlySecrets(expectedSecrets map[string]sdk.SchemaObjectIdentifier) *FunctionAssert { + f.AddAssertion(func(t *testing.T, o *sdk.Function) error { + t.Helper() + if o.Secrets == nil { + return fmt.Errorf("expected secrets to have value; got: nil") + } + var parts []string + for k, v := range expectedSecrets { + parts = append(parts, fmt.Sprintf(`"%s":"\"%s\".\"%s\".%s"`, k, v.DatabaseName(), v.SchemaName(), v.Name())) + } + expected := fmt.Sprintf(`{%s}`, strings.Join(parts, ",")) + if *o.Secrets != expected { + return fmt.Errorf("expected secrets: %v; got: %v", expected, *o.Secrets) + } + return nil + }) + return f +} diff --git a/pkg/acceptance/bettertestspoc/assert/objectassert/gen/sdk_object_def.go b/pkg/acceptance/bettertestspoc/assert/objectassert/gen/sdk_object_def.go index 3f5a88e827..06ab381d2d 100644 --- a/pkg/acceptance/bettertestspoc/assert/objectassert/gen/sdk_object_def.go +++ b/pkg/acceptance/bettertestspoc/assert/objectassert/gen/sdk_object_def.go @@ -97,6 +97,11 @@ var allStructs = []SdkObjectDef{ ObjectType: sdk.ObjectTypeFunction, ObjectStruct: sdk.Function{}, }, + { + IdType: "sdk.SchemaObjectIdentifierWithArguments", + ObjectType: sdk.ObjectTypeProcedure, + ObjectStruct: sdk.Procedure{}, + }, } func GetSdkObjectDetails() []genhelpers.SdkObjectDetails { diff --git a/pkg/acceptance/bettertestspoc/assert/objectassert/procedure_describe_snowflake_ext.go b/pkg/acceptance/bettertestspoc/assert/objectassert/procedure_describe_snowflake_ext.go new file mode 100644 index 0000000000..64011d14f9 --- /dev/null +++ b/pkg/acceptance/bettertestspoc/assert/objectassert/procedure_describe_snowflake_ext.go @@ -0,0 +1,393 @@ +package objectassert + +import ( + "fmt" + "strings" + "testing" + + acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/collections" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" +) + +// TODO [SNOW-1501905]: this file should be fully regenerated when adding and option to assert the results of describe +type ProcedureDetailsAssert struct { + *assert.SnowflakeObjectAssert[sdk.ProcedureDetails, sdk.SchemaObjectIdentifierWithArguments] +} + +func ProcedureDetails(t *testing.T, id sdk.SchemaObjectIdentifierWithArguments) *ProcedureDetailsAssert { + t.Helper() + return &ProcedureDetailsAssert{ + assert.NewSnowflakeObjectAssertWithProvider(sdk.ObjectType("PROCEDURE_DETAILS"), id, acc.TestClient().Procedure.DescribeDetails), + } +} + +func (f *ProcedureDetailsAssert) HasSignature(expected string) *ProcedureDetailsAssert { + f.AddAssertion(func(t *testing.T, o *sdk.ProcedureDetails) error { + t.Helper() + if o.Signature != expected { + return fmt.Errorf("expected signature: %v; got: %v", expected, o.Signature) + } + return nil + }) + return f +} + +func (f *ProcedureDetailsAssert) HasReturns(expected string) *ProcedureDetailsAssert { + f.AddAssertion(func(t *testing.T, o *sdk.ProcedureDetails) error { + t.Helper() + if o.Returns != expected { + return fmt.Errorf("expected returns: %v; got: %v", expected, o.Returns) + } + return nil + }) + return f +} + +func (f *ProcedureDetailsAssert) HasLanguage(expected string) *ProcedureDetailsAssert { + f.AddAssertion(func(t *testing.T, o *sdk.ProcedureDetails) error { + t.Helper() + if o.Language != expected { + return fmt.Errorf("expected language: %v; got: %v", expected, o.Language) + } + return nil + }) + return f +} + +func (f *ProcedureDetailsAssert) HasBody(expected string) *ProcedureDetailsAssert { + f.AddAssertion(func(t *testing.T, o *sdk.ProcedureDetails) error { + t.Helper() + if o.Body == nil { + return fmt.Errorf("expected body to have value; got: nil") + } + if *o.Body != expected { + return fmt.Errorf("expected body: %v; got: %v", expected, *o.Body) + } + return nil + }) + return f +} + +func (f *ProcedureDetailsAssert) HasNullHandling(expected string) *ProcedureDetailsAssert { + f.AddAssertion(func(t *testing.T, o *sdk.ProcedureDetails) error { + t.Helper() + if o.NullHandling == nil { + return fmt.Errorf("expected null handling to have value; got: nil") + } + if *o.NullHandling != expected { + return fmt.Errorf("expected null handling: %v; got: %v", expected, *o.NullHandling) + } + return nil + }) + return f +} + +func (f *ProcedureDetailsAssert) HasVolatility(expected string) *ProcedureDetailsAssert { + f.AddAssertion(func(t *testing.T, o *sdk.ProcedureDetails) error { + t.Helper() + if o.Volatility == nil { + return fmt.Errorf("expected volatility to have value; got: nil") + } + if *o.Volatility != expected { + return fmt.Errorf("expected volatility: %v; got: %v", expected, *o.Volatility) + } + return nil + }) + return f +} + +func (f *ProcedureDetailsAssert) HasExternalAccessIntegrations(expected string) *ProcedureDetailsAssert { + f.AddAssertion(func(t *testing.T, o *sdk.ProcedureDetails) error { + t.Helper() + if o.ExternalAccessIntegrations == nil { + return fmt.Errorf("expected external access integrations to have value; got: nil") + } + if *o.ExternalAccessIntegrations != expected { + return fmt.Errorf("expected external access integrations: %v; got: %v", expected, *o.ExternalAccessIntegrations) + } + return nil + }) + return f +} + +func (f *ProcedureDetailsAssert) HasSecrets(expected string) *ProcedureDetailsAssert { + f.AddAssertion(func(t *testing.T, o *sdk.ProcedureDetails) error { + t.Helper() + if o.Secrets == nil { + return fmt.Errorf("expected secrets to have value; got: nil") + } + if *o.Secrets != expected { + return fmt.Errorf("expected secrets: %v; got: %v", expected, *o.Secrets) + } + return nil + }) + return f +} + +func (f *ProcedureDetailsAssert) HasImports(expected string) *ProcedureDetailsAssert { + f.AddAssertion(func(t *testing.T, o *sdk.ProcedureDetails) error { + t.Helper() + if o.Imports == nil { + return fmt.Errorf("expected imports to have value; got: nil") + } + if *o.Imports != expected { + return fmt.Errorf("expected imports: %v; got: %v", expected, *o.Imports) + } + return nil + }) + return f +} + +func (f *ProcedureDetailsAssert) HasHandler(expected string) *ProcedureDetailsAssert { + f.AddAssertion(func(t *testing.T, o *sdk.ProcedureDetails) error { + t.Helper() + if o.Handler == nil { + return fmt.Errorf("expected handler to have value; got: nil") + } + if *o.Handler != expected { + return fmt.Errorf("expected handler: %v; got: %v", expected, *o.Handler) + } + return nil + }) + return f +} + +func (f *ProcedureDetailsAssert) HasRuntimeVersion(expected string) *ProcedureDetailsAssert { + f.AddAssertion(func(t *testing.T, o *sdk.ProcedureDetails) error { + t.Helper() + if o.RuntimeVersion == nil { + return fmt.Errorf("expected runtime version to have value; got: nil") + } + if *o.RuntimeVersion != expected { + return fmt.Errorf("expected runtime version: %v; got: %v", expected, *o.RuntimeVersion) + } + return nil + }) + return f +} + +func (f *ProcedureDetailsAssert) HasPackages(expected string) *ProcedureDetailsAssert { + f.AddAssertion(func(t *testing.T, o *sdk.ProcedureDetails) error { + t.Helper() + if o.Packages == nil { + return fmt.Errorf("expected packages to have value; got: nil") + } + if *o.Packages != expected { + return fmt.Errorf("expected packages: %v; got: %v", expected, *o.Packages) + } + return nil + }) + return f +} + +func (f *ProcedureDetailsAssert) HasTargetPath(expected string) *ProcedureDetailsAssert { + f.AddAssertion(func(t *testing.T, o *sdk.ProcedureDetails) error { + t.Helper() + if o.TargetPath == nil { + return fmt.Errorf("expected target path to have value; got: nil") + } + if *o.TargetPath != expected { + return fmt.Errorf("expected target path: %v; got: %v", expected, *o.TargetPath) + } + return nil + }) + return f +} + +func (f *ProcedureDetailsAssert) HasInstalledPackages(expected string) *ProcedureDetailsAssert { + f.AddAssertion(func(t *testing.T, o *sdk.ProcedureDetails) error { + t.Helper() + if o.InstalledPackages == nil { + return fmt.Errorf("expected installed packages to have value; got: nil") + } + if *o.InstalledPackages != expected { + return fmt.Errorf("expected installed packages: %v; got: %v", expected, *o.InstalledPackages) + } + return nil + }) + return f +} + +func (f *ProcedureDetailsAssert) HasExecuteAs(expected string) *ProcedureDetailsAssert { + f.AddAssertion(func(t *testing.T, o *sdk.ProcedureDetails) error { + t.Helper() + if o.ExecuteAs != expected { + return fmt.Errorf("expected execute as: %v; got: %v", expected, o.ExecuteAs) + } + return nil + }) + return f +} + +func (f *ProcedureDetailsAssert) HasBodyNil() *ProcedureDetailsAssert { + f.AddAssertion(func(t *testing.T, o *sdk.ProcedureDetails) error { + t.Helper() + if o.Body != nil { + return fmt.Errorf("expected body to be nil, was %v", *o.Body) + } + return nil + }) + return f +} + +func (f *ProcedureDetailsAssert) HasNullHandlingNil() *ProcedureDetailsAssert { + f.AddAssertion(func(t *testing.T, o *sdk.ProcedureDetails) error { + t.Helper() + if o.NullHandling != nil { + return fmt.Errorf("expected null handling to be nil, was %v", *o.NullHandling) + } + return nil + }) + return f +} + +func (f *ProcedureDetailsAssert) HasVolatilityNil() *ProcedureDetailsAssert { + f.AddAssertion(func(t *testing.T, o *sdk.ProcedureDetails) error { + t.Helper() + if o.Volatility != nil { + return fmt.Errorf("expected volatility to be nil, was %v", *o.Volatility) + } + return nil + }) + return f +} + +func (f *ProcedureDetailsAssert) HasExternalAccessIntegrationsNil() *ProcedureDetailsAssert { + f.AddAssertion(func(t *testing.T, o *sdk.ProcedureDetails) error { + t.Helper() + if o.ExternalAccessIntegrations != nil { + return fmt.Errorf("expected external access integrations to be nil, was %v", *o.ExternalAccessIntegrations) + } + return nil + }) + return f +} + +func (f *ProcedureDetailsAssert) HasSecretsNil() *ProcedureDetailsAssert { + f.AddAssertion(func(t *testing.T, o *sdk.ProcedureDetails) error { + t.Helper() + if o.Secrets != nil { + return fmt.Errorf("expected secrets to be nil, was %v", *o.Secrets) + } + return nil + }) + return f +} + +func (f *ProcedureDetailsAssert) HasImportsNil() *ProcedureDetailsAssert { + f.AddAssertion(func(t *testing.T, o *sdk.ProcedureDetails) error { + t.Helper() + if o.Imports != nil { + return fmt.Errorf("expected imports to be nil, was %v", *o.Imports) + } + return nil + }) + return f +} + +func (f *ProcedureDetailsAssert) HasHandlerNil() *ProcedureDetailsAssert { + f.AddAssertion(func(t *testing.T, o *sdk.ProcedureDetails) error { + t.Helper() + if o.Handler != nil { + return fmt.Errorf("expected handler to be nil, was %v", *o.Handler) + } + return nil + }) + return f +} + +func (f *ProcedureDetailsAssert) HasRuntimeVersionNil() *ProcedureDetailsAssert { + f.AddAssertion(func(t *testing.T, o *sdk.ProcedureDetails) error { + t.Helper() + if o.RuntimeVersion != nil { + return fmt.Errorf("expected runtime version to be nil, was %v", *o.RuntimeVersion) + } + return nil + }) + return f +} + +func (f *ProcedureDetailsAssert) HasPackagesNil() *ProcedureDetailsAssert { + f.AddAssertion(func(t *testing.T, o *sdk.ProcedureDetails) error { + t.Helper() + if o.Packages != nil { + return fmt.Errorf("expected packages to be nil, was %v", *o.Packages) + } + return nil + }) + return f +} + +func (f *ProcedureDetailsAssert) HasTargetPathNil() *ProcedureDetailsAssert { + f.AddAssertion(func(t *testing.T, o *sdk.ProcedureDetails) error { + t.Helper() + if o.TargetPath != nil { + return fmt.Errorf("expected target path to be nil, was %v", *o.TargetPath) + } + return nil + }) + return f +} + +func (f *ProcedureDetailsAssert) HasInstalledPackagesNil() *ProcedureDetailsAssert { + f.AddAssertion(func(t *testing.T, o *sdk.ProcedureDetails) error { + t.Helper() + if o.InstalledPackages != nil { + return fmt.Errorf("expected installed packages to be nil, was %v", *o.InstalledPackages) + } + return nil + }) + return f +} + +func (f *ProcedureDetailsAssert) HasInstalledPackagesNotEmpty() *ProcedureDetailsAssert { + f.AddAssertion(func(t *testing.T, o *sdk.ProcedureDetails) error { + t.Helper() + if o.InstalledPackages == nil { + return fmt.Errorf("expected installed packages to not be nil") + } + if *o.InstalledPackages == "" { + return fmt.Errorf("expected installed packages to not be empty") + } + return nil + }) + return f +} + +func (f *ProcedureDetailsAssert) HasExactlyExternalAccessIntegrations(integrations ...sdk.AccountObjectIdentifier) *ProcedureDetailsAssert { + f.AddAssertion(func(t *testing.T, o *sdk.ProcedureDetails) error { + t.Helper() + if o.ExternalAccessIntegrations == nil { + return fmt.Errorf("expected external access integrations to have value; got: nil") + } + joined := strings.Join(collections.Map(integrations, func(ex sdk.AccountObjectIdentifier) string { return ex.FullyQualifiedName() }), ",") + expected := fmt.Sprintf(`[%s]`, joined) + if *o.ExternalAccessIntegrations != expected { + return fmt.Errorf("expected external access integrations: %v; got: %v", expected, *o.ExternalAccessIntegrations) + } + return nil + }) + return f +} + +func (f *ProcedureDetailsAssert) HasExactlySecrets(expectedSecrets map[string]sdk.SchemaObjectIdentifier) *ProcedureDetailsAssert { + f.AddAssertion(func(t *testing.T, o *sdk.ProcedureDetails) error { + t.Helper() + if o.Secrets == nil { + return fmt.Errorf("expected secrets to have value; got: nil") + } + var parts []string + for k, v := range expectedSecrets { + parts = append(parts, fmt.Sprintf(`"%s":"\"%s\".\"%s\".%s"`, k, v.DatabaseName(), v.SchemaName(), v.Name())) + } + expected := fmt.Sprintf(`{%s}`, strings.Join(parts, ",")) + if *o.Secrets != expected { + return fmt.Errorf("expected secrets: %v; got: %v", expected, *o.Secrets) + } + return nil + }) + return f +} diff --git a/pkg/acceptance/bettertestspoc/assert/objectassert/procedure_snowflake_ext.go b/pkg/acceptance/bettertestspoc/assert/objectassert/procedure_snowflake_ext.go new file mode 100644 index 0000000000..12d5a384cf --- /dev/null +++ b/pkg/acceptance/bettertestspoc/assert/objectassert/procedure_snowflake_ext.go @@ -0,0 +1,59 @@ +package objectassert + +import ( + "fmt" + "strings" + "testing" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/collections" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" +) + +func (a *ProcedureAssert) HasCreatedOnNotEmpty() *ProcedureAssert { + a.AddAssertion(func(t *testing.T, o *sdk.Procedure) error { + t.Helper() + if o.CreatedOn == "" { + return fmt.Errorf("expected create_on to be not empty") + } + return nil + }) + return a +} + +func (a *ProcedureAssert) HasExternalAccessIntegrationsNil() *ProcedureAssert { + a.AddAssertion(func(t *testing.T, o *sdk.Procedure) error { + t.Helper() + if o.ExternalAccessIntegrations != nil { + return fmt.Errorf("expected external_access_integrations to be nil but was: %v", *o.ExternalAccessIntegrations) + } + return nil + }) + return a +} + +func (a *ProcedureAssert) HasSecretsNil() *ProcedureAssert { + a.AddAssertion(func(t *testing.T, o *sdk.Procedure) error { + t.Helper() + if o.Secrets != nil { + return fmt.Errorf("expected secrets to be nil but was: %v", *o.Secrets) + } + return nil + }) + return a +} + +func (f *ProcedureAssert) HasExactlyExternalAccessIntegrations(integrations ...sdk.AccountObjectIdentifier) *ProcedureAssert { + f.AddAssertion(func(t *testing.T, o *sdk.Procedure) error { + t.Helper() + if o.ExternalAccessIntegrations == nil { + return fmt.Errorf("expected external access integrations to have value; got: nil") + } + joined := strings.Join(collections.Map(integrations, func(ex sdk.AccountObjectIdentifier) string { return ex.FullyQualifiedName() }), ",") + expected := fmt.Sprintf(`[%s]`, joined) + if *o.ExternalAccessIntegrations != expected { + return fmt.Errorf("expected external access integrations: %v; got: %v", expected, *o.ExternalAccessIntegrations) + } + return nil + }) + return f +} diff --git a/pkg/acceptance/bettertestspoc/assert/objectassert/procedure_snowflake_gen.go b/pkg/acceptance/bettertestspoc/assert/objectassert/procedure_snowflake_gen.go new file mode 100644 index 0000000000..ef1d4c83cf --- /dev/null +++ b/pkg/acceptance/bettertestspoc/assert/objectassert/procedure_snowflake_gen.go @@ -0,0 +1,227 @@ +// Code generated by assertions generator; DO NOT EDIT. + +package objectassert + +// imports edited manually +import ( + "fmt" + "slices" + "testing" + + acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" +) + +type ProcedureAssert struct { + *assert.SnowflakeObjectAssert[sdk.Procedure, sdk.SchemaObjectIdentifierWithArguments] +} + +func Procedure(t *testing.T, id sdk.SchemaObjectIdentifierWithArguments) *ProcedureAssert { + t.Helper() + return &ProcedureAssert{ + assert.NewSnowflakeObjectAssertWithProvider(sdk.ObjectTypeProcedure, id, acc.TestClient().Procedure.Show), + } +} + +func ProcedureFromObject(t *testing.T, procedure *sdk.Procedure) *ProcedureAssert { + t.Helper() + return &ProcedureAssert{ + assert.NewSnowflakeObjectAssertWithObject(sdk.ObjectTypeProcedure, procedure.ID(), procedure), + } +} + +func (p *ProcedureAssert) HasCreatedOn(expected string) *ProcedureAssert { + p.AddAssertion(func(t *testing.T, o *sdk.Procedure) error { + t.Helper() + if o.CreatedOn != expected { + return fmt.Errorf("expected created on: %v; got: %v", expected, o.CreatedOn) + } + return nil + }) + return p +} + +func (p *ProcedureAssert) HasName(expected string) *ProcedureAssert { + p.AddAssertion(func(t *testing.T, o *sdk.Procedure) error { + t.Helper() + if o.Name != expected { + return fmt.Errorf("expected name: %v; got: %v", expected, o.Name) + } + return nil + }) + return p +} + +func (p *ProcedureAssert) HasSchemaName(expected string) *ProcedureAssert { + p.AddAssertion(func(t *testing.T, o *sdk.Procedure) error { + t.Helper() + if o.SchemaName != expected { + return fmt.Errorf("expected schema name: %v; got: %v", expected, o.SchemaName) + } + return nil + }) + return p +} + +func (p *ProcedureAssert) HasIsBuiltin(expected bool) *ProcedureAssert { + p.AddAssertion(func(t *testing.T, o *sdk.Procedure) error { + t.Helper() + if o.IsBuiltin != expected { + return fmt.Errorf("expected is builtin: %v; got: %v", expected, o.IsBuiltin) + } + return nil + }) + return p +} + +func (p *ProcedureAssert) HasIsAggregate(expected bool) *ProcedureAssert { + p.AddAssertion(func(t *testing.T, o *sdk.Procedure) error { + t.Helper() + if o.IsAggregate != expected { + return fmt.Errorf("expected is aggregate: %v; got: %v", expected, o.IsAggregate) + } + return nil + }) + return p +} + +func (p *ProcedureAssert) HasIsAnsi(expected bool) *ProcedureAssert { + p.AddAssertion(func(t *testing.T, o *sdk.Procedure) error { + t.Helper() + if o.IsAnsi != expected { + return fmt.Errorf("expected is ansi: %v; got: %v", expected, o.IsAnsi) + } + return nil + }) + return p +} + +func (p *ProcedureAssert) HasMinNumArguments(expected int) *ProcedureAssert { + p.AddAssertion(func(t *testing.T, o *sdk.Procedure) error { + t.Helper() + if o.MinNumArguments != expected { + return fmt.Errorf("expected min num arguments: %v; got: %v", expected, o.MinNumArguments) + } + return nil + }) + return p +} + +func (p *ProcedureAssert) HasMaxNumArguments(expected int) *ProcedureAssert { + p.AddAssertion(func(t *testing.T, o *sdk.Procedure) error { + t.Helper() + if o.MaxNumArguments != expected { + return fmt.Errorf("expected max num arguments: %v; got: %v", expected, o.MaxNumArguments) + } + return nil + }) + return p +} + +func (p *ProcedureAssert) HasArgumentsOld(expected []sdk.DataType) *ProcedureAssert { + p.AddAssertion(func(t *testing.T, o *sdk.Procedure) error { + t.Helper() + // edited manually + if !slices.Equal(o.ArgumentsOld, expected) { + return fmt.Errorf("expected arguments old: %v; got: %v", expected, o.ArgumentsOld) + } + return nil + }) + return p +} + +func (p *ProcedureAssert) HasArgumentsRaw(expected string) *ProcedureAssert { + p.AddAssertion(func(t *testing.T, o *sdk.Procedure) error { + t.Helper() + if o.ArgumentsRaw != expected { + return fmt.Errorf("expected arguments raw: %v; got: %v", expected, o.ArgumentsRaw) + } + return nil + }) + return p +} + +func (p *ProcedureAssert) HasDescription(expected string) *ProcedureAssert { + p.AddAssertion(func(t *testing.T, o *sdk.Procedure) error { + t.Helper() + if o.Description != expected { + return fmt.Errorf("expected description: %v; got: %v", expected, o.Description) + } + return nil + }) + return p +} + +func (p *ProcedureAssert) HasCatalogName(expected string) *ProcedureAssert { + p.AddAssertion(func(t *testing.T, o *sdk.Procedure) error { + t.Helper() + if o.CatalogName != expected { + return fmt.Errorf("expected catalog name: %v; got: %v", expected, o.CatalogName) + } + return nil + }) + return p +} + +func (p *ProcedureAssert) HasIsTableFunction(expected bool) *ProcedureAssert { + p.AddAssertion(func(t *testing.T, o *sdk.Procedure) error { + t.Helper() + if o.IsTableFunction != expected { + return fmt.Errorf("expected is table function: %v; got: %v", expected, o.IsTableFunction) + } + return nil + }) + return p +} + +func (p *ProcedureAssert) HasValidForClustering(expected bool) *ProcedureAssert { + p.AddAssertion(func(t *testing.T, o *sdk.Procedure) error { + t.Helper() + if o.ValidForClustering != expected { + return fmt.Errorf("expected valid for clustering: %v; got: %v", expected, o.ValidForClustering) + } + return nil + }) + return p +} + +func (p *ProcedureAssert) HasIsSecure(expected bool) *ProcedureAssert { + p.AddAssertion(func(t *testing.T, o *sdk.Procedure) error { + t.Helper() + if o.IsSecure != expected { + return fmt.Errorf("expected is secure: %v; got: %v", expected, o.IsSecure) + } + return nil + }) + return p +} + +func (p *ProcedureAssert) HasSecrets(expected string) *ProcedureAssert { + p.AddAssertion(func(t *testing.T, o *sdk.Procedure) error { + t.Helper() + if o.Secrets == nil { + return fmt.Errorf("expected secrets to have value; got: nil") + } + if *o.Secrets != expected { + return fmt.Errorf("expected secrets: %v; got: %v", expected, *o.Secrets) + } + return nil + }) + return p +} + +func (p *ProcedureAssert) HasExternalAccessIntegrations(expected string) *ProcedureAssert { + p.AddAssertion(func(t *testing.T, o *sdk.Procedure) error { + t.Helper() + if o.ExternalAccessIntegrations == nil { + return fmt.Errorf("expected external access integrations to have value; got: nil") + } + if *o.ExternalAccessIntegrations != expected { + return fmt.Errorf("expected external access integrations: %v; got: %v", expected, *o.ExternalAccessIntegrations) + } + return nil + }) + return p +} diff --git a/pkg/acceptance/bettertestspoc/assert/objectparametersassert/gen/object_parameters_def.go b/pkg/acceptance/bettertestspoc/assert/objectparametersassert/gen/object_parameters_def.go index 7db9f72c07..fd716a8993 100644 --- a/pkg/acceptance/bettertestspoc/assert/objectparametersassert/gen/object_parameters_def.go +++ b/pkg/acceptance/bettertestspoc/assert/objectparametersassert/gen/object_parameters_def.go @@ -216,4 +216,16 @@ var allObjectsParameters = []SnowflakeObjectParameters{ {ParameterName: string(sdk.FunctionParameterTraceLevel), ParameterType: "sdk.TraceLevel", DefaultValue: "sdk.TraceLevelOff", DefaultLevel: "sdk.ParameterTypeSnowflakeDefault"}, }, }, + { + Name: "Procedure", + IdType: "sdk.SchemaObjectIdentifierWithArguments", + Level: sdk.ParameterTypeProcedure, + Parameters: []SnowflakeParameter{ + {ParameterName: string(sdk.ProcedureParameterAutoEventLogging), ParameterType: "sdk.AutoEventLogging", DefaultValue: "sdk.AutoEventLoggingOff", DefaultLevel: "sdk.ParameterTypeSnowflakeDefault"}, + {ParameterName: string(sdk.ProcedureParameterEnableConsoleOutput), ParameterType: "bool", DefaultValue: "false", DefaultLevel: "sdk.ParameterTypeSnowflakeDefault"}, + {ParameterName: string(sdk.ProcedureParameterLogLevel), ParameterType: "sdk.LogLevel", DefaultValue: "sdk.LogLevelOff", DefaultLevel: "sdk.ParameterTypeSnowflakeDefault"}, + {ParameterName: string(sdk.ProcedureParameterMetricLevel), ParameterType: "sdk.MetricLevel", DefaultValue: "sdk.MetricLevelNone", DefaultLevel: "sdk.ParameterTypeSnowflakeDefault"}, + {ParameterName: string(sdk.ProcedureParameterTraceLevel), ParameterType: "sdk.TraceLevel", DefaultValue: "sdk.TraceLevelOff", DefaultLevel: "sdk.ParameterTypeSnowflakeDefault"}, + }, + }, } diff --git a/pkg/acceptance/bettertestspoc/assert/objectparametersassert/procedure_parameters_snowflake_gen.go b/pkg/acceptance/bettertestspoc/assert/objectparametersassert/procedure_parameters_snowflake_gen.go new file mode 100644 index 0000000000..b425119010 --- /dev/null +++ b/pkg/acceptance/bettertestspoc/assert/objectparametersassert/procedure_parameters_snowflake_gen.go @@ -0,0 +1,190 @@ +// Code generated by assertions generator; DO NOT EDIT. + +package objectparametersassert + +import ( + "testing" + + acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" +) + +type ProcedureParametersAssert struct { + *assert.SnowflakeParametersAssert[sdk.SchemaObjectIdentifierWithArguments] +} + +func ProcedureParameters(t *testing.T, id sdk.SchemaObjectIdentifierWithArguments) *ProcedureParametersAssert { + t.Helper() + return &ProcedureParametersAssert{ + assert.NewSnowflakeParametersAssertWithProvider(id, sdk.ObjectTypeProcedure, acc.TestClient().Parameter.ShowProcedureParameters), + } +} + +func ProcedureParametersPrefetched(t *testing.T, id sdk.SchemaObjectIdentifierWithArguments, parameters []*sdk.Parameter) *ProcedureParametersAssert { + t.Helper() + return &ProcedureParametersAssert{ + assert.NewSnowflakeParametersAssertWithParameters(id, sdk.ObjectTypeProcedure, parameters), + } +} + +////////////////////////////// +// Generic parameter checks // +////////////////////////////// + +func (p *ProcedureParametersAssert) HasBoolParameterValue(parameterName sdk.ProcedureParameter, expected bool) *ProcedureParametersAssert { + p.AddAssertion(assert.SnowflakeParameterBoolValueSet(parameterName, expected)) + return p +} + +func (p *ProcedureParametersAssert) HasIntParameterValue(parameterName sdk.ProcedureParameter, expected int) *ProcedureParametersAssert { + p.AddAssertion(assert.SnowflakeParameterIntValueSet(parameterName, expected)) + return p +} + +func (p *ProcedureParametersAssert) HasStringParameterValue(parameterName sdk.ProcedureParameter, expected string) *ProcedureParametersAssert { + p.AddAssertion(assert.SnowflakeParameterValueSet(parameterName, expected)) + return p +} + +func (p *ProcedureParametersAssert) HasDefaultParameterValue(parameterName sdk.ProcedureParameter) *ProcedureParametersAssert { + p.AddAssertion(assert.SnowflakeParameterDefaultValueSet(parameterName)) + return p +} + +func (p *ProcedureParametersAssert) HasDefaultParameterValueOnLevel(parameterName sdk.ProcedureParameter, parameterType sdk.ParameterType) *ProcedureParametersAssert { + p.AddAssertion(assert.SnowflakeParameterDefaultValueOnLevelSet(parameterName, parameterType)) + return p +} + +/////////////////////////////// +// Aggregated generic checks // +/////////////////////////////// + +// HasAllDefaults checks if all the parameters: +// - have a default value by comparing current value of the sdk.Parameter with its default +// - have an expected level +func (p *ProcedureParametersAssert) HasAllDefaults() *ProcedureParametersAssert { + return p. + HasDefaultParameterValueOnLevel(sdk.ProcedureParameterAutoEventLogging, sdk.ParameterTypeSnowflakeDefault). + HasDefaultParameterValueOnLevel(sdk.ProcedureParameterEnableConsoleOutput, sdk.ParameterTypeSnowflakeDefault). + HasDefaultParameterValueOnLevel(sdk.ProcedureParameterLogLevel, sdk.ParameterTypeSnowflakeDefault). + HasDefaultParameterValueOnLevel(sdk.ProcedureParameterMetricLevel, sdk.ParameterTypeSnowflakeDefault). + HasDefaultParameterValueOnLevel(sdk.ProcedureParameterTraceLevel, sdk.ParameterTypeSnowflakeDefault) +} + +func (p *ProcedureParametersAssert) HasAllDefaultsExplicit() *ProcedureParametersAssert { + return p. + HasDefaultAutoEventLoggingValueExplicit(). + HasDefaultEnableConsoleOutputValueExplicit(). + HasDefaultLogLevelValueExplicit(). + HasDefaultMetricLevelValueExplicit(). + HasDefaultTraceLevelValueExplicit() +} + +//////////////////////////// +// Parameter value checks // +//////////////////////////// + +func (p *ProcedureParametersAssert) HasAutoEventLogging(expected sdk.AutoEventLogging) *ProcedureParametersAssert { + p.AddAssertion(assert.SnowflakeParameterStringUnderlyingValueSet(sdk.ProcedureParameterAutoEventLogging, expected)) + return p +} + +func (p *ProcedureParametersAssert) HasEnableConsoleOutput(expected bool) *ProcedureParametersAssert { + p.AddAssertion(assert.SnowflakeParameterBoolValueSet(sdk.ProcedureParameterEnableConsoleOutput, expected)) + return p +} + +func (p *ProcedureParametersAssert) HasLogLevel(expected sdk.LogLevel) *ProcedureParametersAssert { + p.AddAssertion(assert.SnowflakeParameterStringUnderlyingValueSet(sdk.ProcedureParameterLogLevel, expected)) + return p +} + +func (p *ProcedureParametersAssert) HasMetricLevel(expected sdk.MetricLevel) *ProcedureParametersAssert { + p.AddAssertion(assert.SnowflakeParameterStringUnderlyingValueSet(sdk.ProcedureParameterMetricLevel, expected)) + return p +} + +func (p *ProcedureParametersAssert) HasTraceLevel(expected sdk.TraceLevel) *ProcedureParametersAssert { + p.AddAssertion(assert.SnowflakeParameterStringUnderlyingValueSet(sdk.ProcedureParameterTraceLevel, expected)) + return p +} + +//////////////////////////// +// Parameter level checks // +//////////////////////////// + +func (p *ProcedureParametersAssert) HasAutoEventLoggingLevel(expected sdk.ParameterType) *ProcedureParametersAssert { + p.AddAssertion(assert.SnowflakeParameterLevelSet(sdk.ProcedureParameterAutoEventLogging, expected)) + return p +} + +func (p *ProcedureParametersAssert) HasEnableConsoleOutputLevel(expected sdk.ParameterType) *ProcedureParametersAssert { + p.AddAssertion(assert.SnowflakeParameterLevelSet(sdk.ProcedureParameterEnableConsoleOutput, expected)) + return p +} + +func (p *ProcedureParametersAssert) HasLogLevelLevel(expected sdk.ParameterType) *ProcedureParametersAssert { + p.AddAssertion(assert.SnowflakeParameterLevelSet(sdk.ProcedureParameterLogLevel, expected)) + return p +} + +func (p *ProcedureParametersAssert) HasMetricLevelLevel(expected sdk.ParameterType) *ProcedureParametersAssert { + p.AddAssertion(assert.SnowflakeParameterLevelSet(sdk.ProcedureParameterMetricLevel, expected)) + return p +} + +func (p *ProcedureParametersAssert) HasTraceLevelLevel(expected sdk.ParameterType) *ProcedureParametersAssert { + p.AddAssertion(assert.SnowflakeParameterLevelSet(sdk.ProcedureParameterTraceLevel, expected)) + return p +} + +//////////////////////////////////// +// Parameter default value checks // +//////////////////////////////////// + +func (p *ProcedureParametersAssert) HasDefaultAutoEventLoggingValue() *ProcedureParametersAssert { + return p.HasDefaultParameterValue(sdk.ProcedureParameterAutoEventLogging) +} + +func (p *ProcedureParametersAssert) HasDefaultEnableConsoleOutputValue() *ProcedureParametersAssert { + return p.HasDefaultParameterValue(sdk.ProcedureParameterEnableConsoleOutput) +} + +func (p *ProcedureParametersAssert) HasDefaultLogLevelValue() *ProcedureParametersAssert { + return p.HasDefaultParameterValue(sdk.ProcedureParameterLogLevel) +} + +func (p *ProcedureParametersAssert) HasDefaultMetricLevelValue() *ProcedureParametersAssert { + return p.HasDefaultParameterValue(sdk.ProcedureParameterMetricLevel) +} + +func (p *ProcedureParametersAssert) HasDefaultTraceLevelValue() *ProcedureParametersAssert { + return p.HasDefaultParameterValue(sdk.ProcedureParameterTraceLevel) +} + +///////////////////////////////////////////// +// Parameter explicit default value checks // +///////////////////////////////////////////// + +func (p *ProcedureParametersAssert) HasDefaultAutoEventLoggingValueExplicit() *ProcedureParametersAssert { + return p.HasAutoEventLogging(sdk.AutoEventLoggingOff) +} + +func (p *ProcedureParametersAssert) HasDefaultEnableConsoleOutputValueExplicit() *ProcedureParametersAssert { + return p.HasEnableConsoleOutput(false) +} + +func (p *ProcedureParametersAssert) HasDefaultLogLevelValueExplicit() *ProcedureParametersAssert { + return p.HasLogLevel(sdk.LogLevelOff) +} + +func (p *ProcedureParametersAssert) HasDefaultMetricLevelValueExplicit() *ProcedureParametersAssert { + return p.HasMetricLevel(sdk.MetricLevelNone) +} + +func (p *ProcedureParametersAssert) HasDefaultTraceLevelValueExplicit() *ProcedureParametersAssert { + return p.HasTraceLevel(sdk.TraceLevelOff) +} diff --git a/pkg/acceptance/helpers/function_client.go b/pkg/acceptance/helpers/function_client.go index ef8fde637b..4d9bf35aaa 100644 --- a/pkg/acceptance/helpers/function_client.go +++ b/pkg/acceptance/helpers/function_client.go @@ -232,6 +232,7 @@ func (c *FunctionClient) SampleScalaDefinition(t *testing.T, className string, f `, className, funcName, argName) } +// TODO [SNOW-1850370]: use input argument like in other samples func (c *FunctionClient) SampleSqlDefinition(t *testing.T) string { t.Helper() diff --git a/pkg/acceptance/helpers/function_setup_helpers.go b/pkg/acceptance/helpers/function_setup_helpers.go index ca4d29dd86..8f0447e443 100644 --- a/pkg/acceptance/helpers/function_setup_helpers.go +++ b/pkg/acceptance/helpers/function_setup_helpers.go @@ -54,6 +54,45 @@ func (c *TestClient) CreateSampleJavaFunctionAndJar(t *testing.T) *TmpFunction { } } +func (c *TestClient) CreateSampleJavaProcedureAndJar(t *testing.T) *TmpFunction { + t.Helper() + ctx := context.Background() + + className := fmt.Sprintf("TestClassAbc%s", random.AlphaLowerN(3)) + funcName := fmt.Sprintf("echoVarchar%s", random.AlphaLowerN(3)) + argName := fmt.Sprintf("arg%s", random.AlphaLowerN(3)) + dataType := testdatatypes.DataTypeVarchar_100 + + id := c.Ids.RandomSchemaObjectIdentifierWithArguments(sdk.LegacyDataTypeFrom(dataType)) + argument := sdk.NewProcedureArgumentRequest(argName, dataType) + dt := sdk.NewProcedureReturnsResultDataTypeRequest(dataType) + returns := sdk.NewProcedureReturnsRequest().WithResultDataType(*dt) + handler := fmt.Sprintf("%s.%s", className, funcName) + definition := c.Procedure.SampleJavaDefinition(t, className, funcName, argName) + jarName := fmt.Sprintf("tf-%d-%s.jar", time.Now().Unix(), random.AlphaN(5)) + targetPath := fmt.Sprintf("@~/%s", jarName) + packages := []sdk.ProcedurePackageRequest{*sdk.NewProcedurePackageRequest("com.snowflake:snowpark:1.14.0")} + + request := sdk.NewCreateForJavaProcedureRequest(id.SchemaObjectId(), *returns, "11", packages, handler). + WithArguments([]sdk.ProcedureArgumentRequest{*argument}). + WithTargetPath(targetPath). + WithProcedureDefinitionWrapped(definition) + + err := c.context.client.Procedures.CreateForJava(ctx, request) + require.NoError(t, err) + t.Cleanup(c.Procedure.DropProcedureFunc(t, id)) + t.Cleanup(c.Stage.RemoveFromUserStageFunc(t, jarName)) + + return &TmpFunction{ + FunctionId: id, + ClassName: className, + FuncName: funcName, + ArgName: argName, + ArgType: dataType, + JarName: jarName, + } +} + func (c *TestClient) CreateSamplePythonFunctionAndModule(t *testing.T) *TmpFunction { t.Helper() ctx := context.Background() @@ -83,7 +122,7 @@ func (c *TestClient) CreateSamplePythonFunctionAndModule(t *testing.T) *TmpFunct return &TmpFunction{ FunctionId: id, - ModuleName: strings.ReplaceAll(moduleFileName, ".py", ""), + ModuleName: strings.TrimSuffix(moduleFileName, ".py"), FuncName: funcName, ArgName: argName, ArgType: dataType, diff --git a/pkg/acceptance/helpers/parameter_client.go b/pkg/acceptance/helpers/parameter_client.go index 902201d2ca..1e3a24da0b 100644 --- a/pkg/acceptance/helpers/parameter_client.go +++ b/pkg/acceptance/helpers/parameter_client.go @@ -102,6 +102,17 @@ func (c *ParameterClient) ShowFunctionParameters(t *testing.T, id sdk.SchemaObje return params } +func (c *ParameterClient) ShowProcedureParameters(t *testing.T, id sdk.SchemaObjectIdentifierWithArguments) []*sdk.Parameter { + t.Helper() + params, err := c.client().ShowParameters(context.Background(), &sdk.ShowParametersOptions{ + In: &sdk.ParametersIn{ + Procedure: id, + }, + }) + require.NoError(t, err) + return params +} + func (c *ParameterClient) UpdateAccountParameterTemporarily(t *testing.T, parameter sdk.AccountParameter, newValue string) func() { t.Helper() ctx := context.Background() diff --git a/pkg/acceptance/helpers/procedure_client.go b/pkg/acceptance/helpers/procedure_client.go index 34aec170f7..019d5f9299 100644 --- a/pkg/acceptance/helpers/procedure_client.go +++ b/pkg/acceptance/helpers/procedure_client.go @@ -2,9 +2,12 @@ package helpers import ( "context" + "fmt" "testing" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/testdatatypes" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk/datatypes" "github.com/stretchr/testify/require" ) @@ -24,6 +27,66 @@ func (c *ProcedureClient) client() sdk.Procedures { return c.context.client.Procedures } +func (c *ProcedureClient) CreateSql(t *testing.T) (*sdk.Procedure, func()) { + t.Helper() + dataType := testdatatypes.DataTypeFloat + id := c.ids.RandomSchemaObjectIdentifierWithArguments(sdk.LegacyDataTypeFrom(dataType)) + definition := c.SampleSqlDefinition(t) + return c.CreateSqlWithIdentifierAndArgument(t, id.SchemaObjectId(), dataType, definition) +} + +func (c *ProcedureClient) CreateSqlWithIdentifierAndArgument(t *testing.T, id sdk.SchemaObjectIdentifier, dataType datatypes.DataType, definition string) (*sdk.Procedure, func()) { + t.Helper() + ctx := context.Background() + + idWithArgs := sdk.NewSchemaObjectIdentifierWithArgumentsInSchema(id.SchemaId(), id.Name(), sdk.LegacyDataTypeFrom(dataType)) + argName := "x" + dt := sdk.NewProcedureReturnsResultDataTypeRequest(dataType) + returns := sdk.NewProcedureSQLReturnsRequest().WithResultDataType(*dt) + argument := sdk.NewProcedureArgumentRequest(argName, dataType) + + request := sdk.NewCreateForSQLProcedureRequestDefinitionWrapped(id, *returns, definition). + WithArguments([]sdk.ProcedureArgumentRequest{*argument}) + + err := c.client().CreateForSQL(ctx, request) + require.NoError(t, err) + + procedure, err := c.client().ShowByID(ctx, idWithArgs) + require.NoError(t, err) + + return procedure, c.DropProcedureFunc(t, idWithArgs) +} + +func (c *ProcedureClient) CreateJava(t *testing.T) (*sdk.Procedure, func()) { + t.Helper() + ctx := context.Background() + + className := "TestFunc" + funcName := "echoVarchar" + argName := "x" + dataType := testdatatypes.DataTypeVarchar_100 + + id := c.ids.RandomSchemaObjectIdentifierWithArguments(sdk.LegacyDataTypeFrom(dataType)) + argument := sdk.NewProcedureArgumentRequest(argName, dataType) + dt := sdk.NewProcedureReturnsResultDataTypeRequest(dataType) + returns := sdk.NewProcedureReturnsRequest().WithResultDataType(*dt) + handler := fmt.Sprintf("%s.%s", className, funcName) + definition := c.SampleJavaDefinition(t, className, funcName, argName) + packages := []sdk.ProcedurePackageRequest{*sdk.NewProcedurePackageRequest("com.snowflake:snowpark:1.14.0")} + + request := sdk.NewCreateForJavaProcedureRequest(id.SchemaObjectId(), *returns, "11", packages, handler). + WithArguments([]sdk.ProcedureArgumentRequest{*argument}). + WithProcedureDefinitionWrapped(definition) + + err := c.client().CreateForJava(ctx, request) + require.NoError(t, err) + + function, err := c.client().ShowByID(ctx, id) + require.NoError(t, err) + + return function, c.DropProcedureFunc(t, id) +} + func (c *ProcedureClient) Create(t *testing.T, arguments ...sdk.DataType) *sdk.Procedure { t.Helper() return c.CreateWithIdentifier(t, c.ids.RandomSchemaObjectIdentifierWithArguments(arguments...)) @@ -37,7 +100,7 @@ func (c *ProcedureClient) CreateWithIdentifier(t *testing.T, id sdk.SchemaObject argumentRequests[i] = *sdk.NewProcedureArgumentRequest(c.ids.Alpha(), nil).WithArgDataTypeOld(argumentDataType) } err := c.client().CreateForSQL(ctx, - sdk.NewCreateForSQLProcedureRequest( + sdk.NewCreateForSQLProcedureRequestDefinitionWrapped( id.SchemaObjectId(), *sdk.NewProcedureSQLReturnsRequest().WithResultDataType(*sdk.NewProcedureReturnsResultDataTypeRequest(nil).WithResultDataTypeOld(sdk.DataTypeInt)), `BEGIN RETURN 1; END`).WithArguments(argumentRequests), @@ -53,3 +116,96 @@ func (c *ProcedureClient) CreateWithIdentifier(t *testing.T, id sdk.SchemaObject return procedure } + +func (c *ProcedureClient) DropProcedureFunc(t *testing.T, id sdk.SchemaObjectIdentifierWithArguments) func() { + t.Helper() + ctx := context.Background() + + return func() { + err := c.client().Drop(ctx, sdk.NewDropProcedureRequest(id).WithIfExists(true)) + require.NoError(t, err) + } +} + +func (c *ProcedureClient) Show(t *testing.T, id sdk.SchemaObjectIdentifierWithArguments) (*sdk.Procedure, error) { + t.Helper() + ctx := context.Background() + + return c.client().ShowByID(ctx, id) +} + +func (c *ProcedureClient) DescribeDetails(t *testing.T, id sdk.SchemaObjectIdentifierWithArguments) (*sdk.ProcedureDetails, error) { + t.Helper() + ctx := context.Background() + + return c.client().DescribeDetails(ctx, id) +} + +// Session argument is needed: https://docs.snowflake.com/en/developer-guide/stored-procedure/stored-procedures-java#data-access-example +// More references: https://docs.snowflake.com/en/developer-guide/stored-procedure/stored-procedures-java +func (c *ProcedureClient) SampleJavaDefinition(t *testing.T, className string, funcName string, argName string) string { + t.Helper() + + return fmt.Sprintf(` + import com.snowflake.snowpark_java.*; + class %[1]s { + public static String %[2]s(Session session, String %[3]s) { + return %[3]s; + } + } +`, className, funcName, argName) +} + +// For more references: https://docs.snowflake.com/en/developer-guide/stored-procedure/stored-procedures-javascript +func (c *ProcedureClient) SampleJavascriptDefinition(t *testing.T, argName string) string { + t.Helper() + + return fmt.Sprintf(` + if (%[1]s <= 0) { + return 1; + } else { + var result = 1; + for (var i = 2; i <= %[1]s; i++) { + result = result * i; + } + return result; + } +`, argName) +} + +func (c *ProcedureClient) SamplePythonDefinition(t *testing.T, funcName string, argName string) string { + t.Helper() + + return fmt.Sprintf(` +def %[1]s(%[2]s): + result = "" + for a in range(5): + result += %[2]s + return result +`, funcName, argName) +} + +// https://docs.snowflake.com/en/developer-guide/stored-procedure/stored-procedures-scala +func (c *ProcedureClient) SampleScalaDefinition(t *testing.T, className string, funcName string, argName string) string { + t.Helper() + + return fmt.Sprintf(` + import com.snowflake.snowpark_java.Session + + class %[1]s { + def %[2]s(session : Session, %[3]s : String): String = { + return %[3]s + } + } +`, className, funcName, argName) +} + +func (c *ProcedureClient) SampleSqlDefinition(t *testing.T) string { + t.Helper() + + return ` +BEGIN + RETURN 3.141592654::FLOAT; +END; +` +} diff --git a/pkg/acceptance/testdatatypes/testdatatypes.go b/pkg/acceptance/testdatatypes/testdatatypes.go index dc11e82f0e..48aa8fde51 100644 --- a/pkg/acceptance/testdatatypes/testdatatypes.go +++ b/pkg/acceptance/testdatatypes/testdatatypes.go @@ -2,6 +2,7 @@ package testdatatypes import "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk/datatypes" +// TODO [SNOW-1843440]: create using constructors (when we add them)? var ( DataTypeNumber_36_2, _ = datatypes.ParseDataType("NUMBER(36, 2)") DataTypeVarchar_100, _ = datatypes.ParseDataType("VARCHAR(100)") diff --git a/pkg/datasources/procedures.go b/pkg/datasources/procedures.go index a20c338a68..c0dd714ff1 100644 --- a/pkg/datasources/procedures.go +++ b/pkg/datasources/procedures.go @@ -79,10 +79,10 @@ func ReadContextProcedures(ctx context.Context, d *schema.ResourceData, meta int req := sdk.NewShowProcedureRequest() if databaseName != "" { - req.WithIn(sdk.In{Database: sdk.NewAccountObjectIdentifier(databaseName)}) + req.WithIn(sdk.ExtendedIn{In: sdk.In{Database: sdk.NewAccountObjectIdentifier(databaseName)}}) } if schemaName != "" { - req.WithIn(sdk.In{Schema: sdk.NewDatabaseObjectIdentifier(databaseName, schemaName)}) + req.WithIn(sdk.ExtendedIn{In: sdk.In{Schema: sdk.NewDatabaseObjectIdentifier(databaseName, schemaName)}}) } procedures, err := client.Procedures.Show(ctx, req) if err != nil { diff --git a/pkg/resources/external_function.go b/pkg/resources/external_function.go index 7ff5270ae2..5330787394 100644 --- a/pkg/resources/external_function.go +++ b/pkg/resources/external_function.go @@ -275,7 +275,7 @@ func CreateContextExternalFunction(ctx context.Context, d *schema.ResourceData, case v.(string) == "CALLED ON NULL INPUT": req.WithNullInputBehavior(sdk.NullInputBehaviorCalledOnNullInput) case v.(string) == "RETURNS NULL ON NULL INPUT": - req.WithNullInputBehavior(sdk.NullInputBehaviorReturnNullInput) + req.WithNullInputBehavior(sdk.NullInputBehaviorReturnsNullInput) default: req.WithNullInputBehavior(sdk.NullInputBehaviorStrict) } diff --git a/pkg/resources/function.go b/pkg/resources/function.go index a0440d33f2..38c6619a37 100644 --- a/pkg/resources/function.go +++ b/pkg/resources/function.go @@ -313,6 +313,8 @@ func createScalaFunction(ctx context.Context, d *schema.ResourceData, meta inter var runtimeVersion string if v, ok := d.GetOk("runtime_version"); ok { runtimeVersion = v.(string) + } else { + return diag.Errorf("Runtime version is required for Scala function") } // create request with required @@ -570,6 +572,9 @@ func ReadContextFunction(ctx context.Context, d *schema.ResourceData, meta inter } } for _, desc := range functionDetails { + if desc.Value == nil { + continue + } switch desc.Property { case "signature": // Format in Snowflake DB is: (argName argType, argName argType, ...) @@ -590,15 +595,15 @@ func ReadContextFunction(ctx context.Context, d *schema.ResourceData, meta inter } } case "null handling": - if err := d.Set("null_input_behavior", desc.Value); err != nil { + if err := d.Set("null_input_behavior", *desc.Value); err != nil { diag.FromErr(err) } case "volatility": - if err := d.Set("return_behavior", desc.Value); err != nil { + if err := d.Set("return_behavior", *desc.Value); err != nil { diag.FromErr(err) } case "body": - if err := d.Set("statement", desc.Value); err != nil { + if err := d.Set("statement", *desc.Value); err != nil { diag.FromErr(err) } case "returns": @@ -614,11 +619,11 @@ func ReadContextFunction(ctx context.Context, d *schema.ResourceData, meta inter } case "language": if snowflake.Contains(languages, strings.ToLower(*desc.Value)) { - if err := d.Set("language", desc.Value); err != nil { + if err := d.Set("language", *desc.Value); err != nil { diag.FromErr(err) } } else { - log.Printf("[INFO] Unexpected language for function %v returned from Snowflake", desc.Value) + log.Printf("[INFO] Unexpected language for function %v returned from Snowflake", *desc.Value) } case "packages": value := strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(*desc.Value, "[", ""), "]", ""), "'", "") @@ -637,19 +642,19 @@ func ReadContextFunction(ctx context.Context, d *schema.ResourceData, meta inter } } case "handler": - if err := d.Set("handler", desc.Value); err != nil { + if err := d.Set("handler", *desc.Value); err != nil { diag.FromErr(err) } case "target_path": - if err := d.Set("target_path", desc.Value); err != nil { + if err := d.Set("target_path", *desc.Value); err != nil { diag.FromErr(err) } case "runtime_version": - if err := d.Set("runtime_version", desc.Value); err != nil { + if err := d.Set("runtime_version", *desc.Value); err != nil { diag.FromErr(err) } default: - log.Printf("[INFO] Unexpected function property %v returned from Snowflake with value %v", desc.Property, desc.Value) + log.Printf("[INFO] Unexpected function property %v returned from Snowflake with value %v", desc.Property, *desc.Value) } } diff --git a/pkg/resources/procedure.go b/pkg/resources/procedure.go index f7577833f9..8665f71d09 100644 --- a/pkg/resources/procedure.go +++ b/pkg/resources/procedure.go @@ -267,7 +267,7 @@ func createJavaProcedure(ctx context.Context, d *schema.ResourceData, meta inter } handler := d.Get("handler").(string) req := sdk.NewCreateForJavaProcedureRequest(id.SchemaObjectId(), *returns, runtimeVersion, packages, handler) - req.WithProcedureDefinition(procedureDefinition) + req.WithProcedureDefinitionWrapped(procedureDefinition) if len(args) > 0 { req.WithArguments(args) } @@ -322,7 +322,7 @@ func createJavaScriptProcedure(ctx context.Context, d *schema.ResourceData, meta return diags } procedureDefinition := d.Get("statement").(string) - req := sdk.NewCreateForJavaScriptProcedureRequest(id.SchemaObjectId(), nil, procedureDefinition).WithResultDataTypeOld(sdk.LegacyDataTypeFrom(returnDataType)) + req := sdk.NewCreateForJavaScriptProcedureRequestDefinitionWrapped(id.SchemaObjectId(), nil, procedureDefinition).WithResultDataTypeOld(sdk.LegacyDataTypeFrom(returnDataType)) if len(args) > 0 { req.WithArguments(args) } @@ -379,7 +379,7 @@ func createScalaProcedure(ctx context.Context, d *schema.ResourceData, meta inte } handler := d.Get("handler").(string) req := sdk.NewCreateForScalaProcedureRequest(id.SchemaObjectId(), *returns, runtimeVersion, packages, handler) - req.WithProcedureDefinition(procedureDefinition) + req.WithProcedureDefinitionWrapped(procedureDefinition) if len(args) > 0 { req.WithArguments(args) } @@ -433,7 +433,7 @@ func createSQLProcedure(ctx context.Context, d *schema.ResourceData, meta interf return diags } procedureDefinition := d.Get("statement").(string) - req := sdk.NewCreateForSQLProcedureRequest(id.SchemaObjectId(), *returns, procedureDefinition) + req := sdk.NewCreateForSQLProcedureRequestDefinitionWrapped(id.SchemaObjectId(), *returns, procedureDefinition) if len(args) > 0 { req.WithArguments(args) } @@ -490,7 +490,7 @@ func createPythonProcedure(ctx context.Context, d *schema.ResourceData, meta int } handler := d.Get("handler").(string) req := sdk.NewCreateForPythonProcedureRequest(id.SchemaObjectId(), *returns, runtimeVersion, packages, handler) - req.WithProcedureDefinition(procedureDefinition) + req.WithProcedureDefinitionWrapped(procedureDefinition) if len(args) > 0 { req.WithArguments(args) } @@ -570,10 +570,13 @@ func ReadContextProcedure(ctx context.Context, d *schema.ResourceData, meta inte } } for _, desc := range procedureDetails { + if desc.Value == nil { + continue + } switch desc.Property { case "signature": // Format in Snowflake DB is: (argName argType, argName argType, ...) - args := strings.ReplaceAll(strings.ReplaceAll(desc.Value, "(", ""), ")", "") + args := strings.ReplaceAll(strings.ReplaceAll(*desc.Value, "(", ""), ")", "") if args != "" { // Do nothing for functions without arguments argPairs := strings.Split(args, ", ") @@ -593,31 +596,31 @@ func ReadContextProcedure(ctx context.Context, d *schema.ResourceData, meta inte } } case "null handling": - if err := d.Set("null_input_behavior", desc.Value); err != nil { + if err := d.Set("null_input_behavior", *desc.Value); err != nil { return diag.FromErr(err) } case "body": - if err := d.Set("statement", desc.Value); err != nil { + if err := d.Set("statement", *desc.Value); err != nil { return diag.FromErr(err) } case "execute as": - if err := d.Set("execute_as", desc.Value); err != nil { + if err := d.Set("execute_as", *desc.Value); err != nil { return diag.FromErr(err) } case "returns": - if err := d.Set("return_type", desc.Value); err != nil { + if err := d.Set("return_type", *desc.Value); err != nil { return diag.FromErr(err) } case "language": - if err := d.Set("language", desc.Value); err != nil { + if err := d.Set("language", *desc.Value); err != nil { return diag.FromErr(err) } case "runtime_version": - if err := d.Set("runtime_version", desc.Value); err != nil { + if err := d.Set("runtime_version", *desc.Value); err != nil { return diag.FromErr(err) } case "packages": - packagesString := strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(desc.Value, "[", ""), "]", ""), "'", "") + packagesString := strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(*desc.Value, "[", ""), "]", ""), "'", "") if packagesString != "" { // Do nothing for Java / Python functions without packages packages := strings.Split(packagesString, ",") if err := d.Set("packages", packages); err != nil { @@ -625,7 +628,7 @@ func ReadContextProcedure(ctx context.Context, d *schema.ResourceData, meta inte } } case "imports": - importsString := strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(desc.Value, "[", ""), "]", ""), "'", ""), " ", "") + importsString := strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(*desc.Value, "[", ""), "]", ""), "'", ""), " ", "") if importsString != "" { // Do nothing for Java functions without imports imports := strings.Split(importsString, ",") if err := d.Set("imports", imports); err != nil { @@ -633,15 +636,15 @@ func ReadContextProcedure(ctx context.Context, d *schema.ResourceData, meta inte } } case "handler": - if err := d.Set("handler", desc.Value); err != nil { + if err := d.Set("handler", *desc.Value); err != nil { return diag.FromErr(err) } case "volatility": - if err := d.Set("return_behavior", desc.Value); err != nil { + if err := d.Set("return_behavior", *desc.Value); err != nil { return diag.FromErr(err) } default: - log.Printf("[INFO] Unexpected procedure property %v returned from Snowflake with value %v", desc.Property, desc.Value) + log.Printf("[INFO] Unexpected procedure property %v returned from Snowflake with value %v", desc.Property, *desc.Value) } } @@ -685,11 +688,11 @@ func UpdateContextProcedure(ctx context.Context, d *schema.ResourceData, meta in if d.HasChange("comment") { comment := d.Get("comment") if comment != "" { - if err := client.Procedures.Alter(ctx, sdk.NewAlterProcedureRequest(id).WithSetComment(comment.(string))); err != nil { + if err := client.Procedures.Alter(ctx, sdk.NewAlterProcedureRequest(id).WithSet(*sdk.NewProcedureSetRequest().WithComment(comment.(string)))); err != nil { return diag.FromErr(err) } } else { - if err := client.Procedures.Alter(ctx, sdk.NewAlterProcedureRequest(id).WithUnsetComment(true)); err != nil { + if err := client.Procedures.Alter(ctx, sdk.NewAlterProcedureRequest(id).WithUnset(*sdk.NewProcedureUnsetRequest().WithComment(true))); err != nil { return diag.FromErr(err) } } diff --git a/pkg/resources/procedure_acceptance_test.go b/pkg/resources/procedure_acceptance_test.go index 05cbfbfd73..1039ebc459 100644 --- a/pkg/resources/procedure_acceptance_test.go +++ b/pkg/resources/procedure_acceptance_test.go @@ -157,9 +157,9 @@ func TestAcc_Procedure_complex(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "statement", statement), resource.TestCheckResourceAttr(resourceName, "execute_as", "CALLER"), resource.TestCheckResourceAttr(resourceName, "arguments.#", "2"), - resource.TestCheckResourceAttr(resourceName, "arguments.0.name", "ARG1"), + resource.TestCheckResourceAttr(resourceName, "arguments.0.name", "arg1"), resource.TestCheckResourceAttr(resourceName, "arguments.0.type", "VARCHAR"), - resource.TestCheckResourceAttr(resourceName, "arguments.1.name", "ARG2"), + resource.TestCheckResourceAttr(resourceName, "arguments.1.name", "arg2"), resource.TestCheckResourceAttr(resourceName, "arguments.1.type", "DATE"), resource.TestCheckResourceAttr(resourceName, "null_input_behavior", "RETURNS NULL ON NULL INPUT"), diff --git a/pkg/sdk/common_types.go b/pkg/sdk/common_types.go index ca2bc6b9b3..3678fe4e05 100644 --- a/pkg/sdk/common_types.go +++ b/pkg/sdk/common_types.go @@ -233,7 +233,7 @@ func NullInputBehaviorPointer(v NullInputBehavior) *NullInputBehavior { const ( NullInputBehaviorCalledOnNullInput NullInputBehavior = "CALLED ON NULL INPUT" - NullInputBehaviorReturnNullInput NullInputBehavior = "RETURNS NULL ON NULL INPUT" + NullInputBehaviorReturnsNullInput NullInputBehavior = "RETURNS NULL ON NULL INPUT" NullInputBehaviorStrict NullInputBehavior = "STRICT" ) @@ -380,6 +380,37 @@ var AllMetricLevels = []MetricLevel{ MetricLevelNone, } +type AutoEventLogging string + +const ( + AutoEventLoggingLogging AutoEventLogging = "LOGGING" + AutoEventLoggingTracing AutoEventLogging = "TRACING" + AutoEventLoggingAll AutoEventLogging = "ALL" + AutoEventLoggingOff AutoEventLogging = "OFF" +) + +func ToAutoEventLogging(value string) (AutoEventLogging, error) { + switch strings.ToUpper(value) { + case string(AutoEventLoggingLogging): + return AutoEventLoggingLogging, nil + case string(AutoEventLoggingTracing): + return AutoEventLoggingTracing, nil + case string(AutoEventLoggingAll): + return AutoEventLoggingAll, nil + case string(AutoEventLoggingOff): + return AutoEventLoggingOff, nil + default: + return "", fmt.Errorf("unknown auto event logging: %s", value) + } +} + +var AllAutoEventLoggings = []AutoEventLogging{ + AutoEventLoggingLogging, + AutoEventLoggingTracing, + AutoEventLoggingAll, + AutoEventLoggingOff, +} + // StringAllowEmpty is a wrapper on string to allow using empty strings in SQL. type StringAllowEmpty struct { Value string `ddl:"keyword,single_quotes"` diff --git a/pkg/sdk/common_types_test.go b/pkg/sdk/common_types_test.go index 1b5e5ecf9f..263d02ad2c 100644 --- a/pkg/sdk/common_types_test.go +++ b/pkg/sdk/common_types_test.go @@ -327,3 +327,38 @@ func Test_ToMetricLevel(t *testing.T) { }) } } + +func Test_ToAutoEventLogging(t *testing.T) { + testCases := []struct { + Name string + Input string + Expected AutoEventLogging + ExpectedError string + }{ + {Input: string(AutoEventLoggingLogging), Expected: AutoEventLoggingLogging}, + {Input: string(AutoEventLoggingTracing), Expected: AutoEventLoggingTracing}, + {Input: string(AutoEventLoggingAll), Expected: AutoEventLoggingAll}, + {Input: string(AutoEventLoggingOff), Expected: AutoEventLoggingOff}, + {Name: "validation: incorrect auto event logging", Input: "incorrect", ExpectedError: "unknown auto event logging: incorrect"}, + {Name: "validation: empty input", Input: "", ExpectedError: "unknown auto event logging: "}, + {Name: "validation: lower case input", Input: "all", Expected: AutoEventLoggingAll}, + } + + for _, tc := range testCases { + tc := tc + name := tc.Name + if name == "" { + name = fmt.Sprintf("%v auto event logging", tc.Input) + } + t.Run(name, func(t *testing.T) { + value, err := ToAutoEventLogging(tc.Input) + if tc.ExpectedError != "" { + assert.Empty(t, value) + assert.ErrorContains(t, err, tc.ExpectedError) + } else { + assert.NoError(t, err) + assert.Equal(t, tc.Expected, value) + } + }) + } +} diff --git a/pkg/sdk/functions_impl_gen.go b/pkg/sdk/functions_impl_gen.go index 8d9dbd1606..051a8fc994 100644 --- a/pkg/sdk/functions_impl_gen.go +++ b/pkg/sdk/functions_impl_gen.go @@ -467,7 +467,7 @@ func (r functionRow) convert() *Function { e := &Function{ CreatedOn: r.CreatedOn, Name: r.Name, - SchemaName: r.SchemaName, + SchemaName: strings.Trim(r.SchemaName, `"`), IsBuiltin: r.IsBuiltin == "Y", IsAggregate: r.IsAggregate == "Y", IsAnsi: r.IsAnsi == "Y", @@ -475,7 +475,7 @@ func (r functionRow) convert() *Function { MaxNumArguments: r.MaxNumArguments, ArgumentsRaw: r.Arguments, Description: r.Description, - CatalogName: r.CatalogName, + CatalogName: strings.Trim(r.CatalogName, `"`), IsTableFunction: r.IsTableFunction == "Y", ValidForClustering: r.ValidForClustering == "Y", IsExternalFunction: r.IsExternalFunction == "Y", diff --git a/pkg/sdk/identifier_helpers.go b/pkg/sdk/identifier_helpers.go index 90d1acdf44..7e857fb8de 100644 --- a/pkg/sdk/identifier_helpers.go +++ b/pkg/sdk/identifier_helpers.go @@ -324,7 +324,12 @@ func NewSchemaObjectIdentifierWithArguments(databaseName, schemaName, name strin if err != nil { log.Printf("[DEBUG] failed to normalize argument %d: %v, err = %v", i, argument, err) } - normalizedArguments[i] = LegacyDataTypeFrom(normalizedArgument) + // TODO [SNOW-1348103]: temporary workaround to fix panic resulting from TestAcc_Grants_To_AccountRole test (because of unsupported TABLE data type) + if normalizedArgument != nil { + normalizedArguments[i] = LegacyDataTypeFrom(normalizedArgument) + } else { + normalizedArguments[i] = "" + } } return SchemaObjectIdentifierWithArguments{ databaseName: strings.Trim(databaseName, `"`), diff --git a/pkg/sdk/parameters.go b/pkg/sdk/parameters.go index b651b673f3..4940f4ed0b 100644 --- a/pkg/sdk/parameters.go +++ b/pkg/sdk/parameters.go @@ -842,6 +842,16 @@ const ( FunctionParameterTraceLevel FunctionParameter = "TRACE_LEVEL" ) +type ProcedureParameter string + +const ( + ProcedureParameterAutoEventLogging ProcedureParameter = "AUTO_EVENT_LOGGING" + ProcedureParameterEnableConsoleOutput ProcedureParameter = "ENABLE_CONSOLE_OUTPUT" + ProcedureParameterLogLevel ProcedureParameter = "LOG_LEVEL" + ProcedureParameterMetricLevel ProcedureParameter = "METRIC_LEVEL" + ProcedureParameterTraceLevel ProcedureParameter = "TRACE_LEVEL" +) + // AccountParameters is based on https://docs.snowflake.com/en/sql-reference/parameters#account-parameters. type AccountParameters struct { // Account Parameters @@ -1359,11 +1369,12 @@ type ParametersIn struct { Task SchemaObjectIdentifier `ddl:"identifier" sql:"TASK"` Table SchemaObjectIdentifier `ddl:"identifier" sql:"TABLE"` Function SchemaObjectIdentifierWithArguments `ddl:"identifier" sql:"FUNCTION"` + Procedure SchemaObjectIdentifierWithArguments `ddl:"identifier" sql:"PROCEDURE"` } func (v *ParametersIn) validate() error { - if !anyValueSet(v.Session, v.Account, v.User, v.Warehouse, v.Database, v.Schema, v.Task, v.Table, v.Function) { - return errors.Join(errAtLeastOneOf("Session", "Account", "User", "Warehouse", "Database", "Schema", "Task", "Table", "Function")) + if !anyValueSet(v.Session, v.Account, v.User, v.Warehouse, v.Database, v.Schema, v.Task, v.Table, v.Function, v.Procedure) { + return errors.Join(errAtLeastOneOf("Session", "Account", "User", "Warehouse", "Database", "Schema", "Task", "Table", "Function", "Procedure")) } return nil } @@ -1381,6 +1392,7 @@ const ( ParameterTypeSchema ParameterType = "SCHEMA" ParameterTypeTask ParameterType = "TASK" ParameterTypeFunction ParameterType = "FUNCTION" + ParameterTypeProcedure ParameterType = "PROCEDURE" ) type Parameter struct { @@ -1511,6 +1523,8 @@ func (v *parameters) ShowObjectParameter(ctx context.Context, parameter ObjectPa opts.In.User = object.Name.(AccountObjectIdentifier) case ObjectTypeFunction: opts.In.Function = object.Name.(SchemaObjectIdentifierWithArguments) + case ObjectTypeProcedure: + opts.In.Procedure = object.Name.(SchemaObjectIdentifierWithArguments) default: return nil, fmt.Errorf("unsupported object type %s", object.Name) } diff --git a/pkg/sdk/poc/README.md b/pkg/sdk/poc/README.md index 46cb6e16b9..eabaf74e55 100644 --- a/pkg/sdk/poc/README.md +++ b/pkg/sdk/poc/README.md @@ -110,6 +110,7 @@ find a better solution to solve the issue (add more logic to the templates ?) - more clear definition of lists that can be empty vs cannot be empty - add empty ids in generated tests (TODO in random_test.go) - add optional imports (currently they have to be added manually, e.g. `datatypes.DataType`) +- add fourth type of quotes - double dollars ($$..$$) -> used for functions, procedures, and tasks ##### Known issues - generating two converts when Show and Desc use the same data structure diff --git a/pkg/sdk/procedures_def.go b/pkg/sdk/procedures_def.go index 0485b7711b..636da06187 100644 --- a/pkg/sdk/procedures_def.go +++ b/pkg/sdk/procedures_def.go @@ -5,14 +5,14 @@ import g "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk/poc/gen //go:generate go run ./poc/main.go var procedureArgument = g.NewQueryStruct("ProcedureArgument"). - Text("ArgName", g.KeywordOptions().NoQuotes().Required()). + Text("ArgName", g.KeywordOptions().DoubleQuotes().Required()). PredefinedQueryStructField("ArgDataTypeOld", "DataType", g.KeywordOptions().NoQuotes()). PredefinedQueryStructField("ArgDataType", "datatypes.DataType", g.ParameterOptions().NoQuotes().NoEquals().Required()). PredefinedQueryStructField("DefaultValue", "*string", g.ParameterOptions().NoEquals().SQL("DEFAULT")). WithValidation(g.ExactlyOneValueSet, "ArgDataTypeOld", "ArgDataType") var procedureColumn = g.NewQueryStruct("ProcedureColumn"). - Text("ColumnName", g.KeywordOptions().NoQuotes().Required()). + Text("ColumnName", g.KeywordOptions().DoubleQuotes().Required()). PredefinedQueryStructField("ColumnDataTypeOld", "DataType", g.KeywordOptions().NoQuotes()). PredefinedQueryStructField("ColumnDataType", "datatypes.DataType", g.ParameterOptions().NoQuotes().NoEquals().Required()). WithValidation(g.ExactlyOneValueSet, "ColumnDataTypeOld", "ColumnDataType") @@ -96,6 +96,8 @@ var ProceduresDef = g.NewInterface( g.KeywordOptions().SQL("RETURNS").Required(), ). SQL("LANGUAGE JAVA"). + PredefinedQueryStructField("NullInputBehavior", "*NullInputBehavior", g.KeywordOptions()). + PredefinedQueryStructField("ReturnResultsBehavior", "*ReturnResultsBehavior", g.KeywordOptions()). TextAssignment("RUNTIME_VERSION", g.ParameterOptions().SingleQuotes().Required()). ListQueryStructField( "Packages", @@ -111,10 +113,9 @@ var ProceduresDef = g.NewInterface( ListAssignment("EXTERNAL_ACCESS_INTEGRATIONS", "AccountObjectIdentifier", g.ParameterOptions().Parentheses()). ListAssignment("SECRETS", "SecretReference", g.ParameterOptions().Parentheses()). OptionalTextAssignment("TARGET_PATH", g.ParameterOptions().SingleQuotes()). - PredefinedQueryStructField("NullInputBehavior", "*NullInputBehavior", g.KeywordOptions()). OptionalTextAssignment("COMMENT", g.ParameterOptions().SingleQuotes()). PredefinedQueryStructField("ExecuteAs", "*ExecuteAs", g.KeywordOptions()). - PredefinedQueryStructField("ProcedureDefinition", "*string", g.ParameterOptions().NoEquals().SingleQuotes().SQL("AS")). + PredefinedQueryStructField("ProcedureDefinition", "*string", g.ParameterOptions().NoEquals().SQL("AS")). WithValidation(g.ValidateValueSet, "RuntimeVersion"). WithValidation(g.ValidateValueSet, "Packages"). WithValidation(g.ValidateValueSet, "Handler"). @@ -140,9 +141,10 @@ var ProceduresDef = g.NewInterface( OptionalSQL("NOT NULL"). SQL("LANGUAGE JAVASCRIPT"). PredefinedQueryStructField("NullInputBehavior", "*NullInputBehavior", g.KeywordOptions()). + PredefinedQueryStructField("ReturnResultsBehavior", "*ReturnResultsBehavior", g.KeywordOptions()). OptionalTextAssignment("COMMENT", g.ParameterOptions().SingleQuotes()). PredefinedQueryStructField("ExecuteAs", "*ExecuteAs", g.KeywordOptions()). - PredefinedQueryStructField("ProcedureDefinition", "string", g.ParameterOptions().NoEquals().SingleQuotes().SQL("AS").Required()). + PredefinedQueryStructField("ProcedureDefinition", "string", g.ParameterOptions().NoEquals().SQL("AS").Required()). WithValidation(g.ValidateValueSet, "ProcedureDefinition"). WithValidation(g.ValidIdentifier, "name"). WithValidation(g.ExactlyOneValueSet, "ResultDataTypeOld", "ResultDataType"), @@ -167,6 +169,8 @@ var ProceduresDef = g.NewInterface( g.KeywordOptions().SQL("RETURNS").Required(), ). SQL("LANGUAGE PYTHON"). + PredefinedQueryStructField("NullInputBehavior", "*NullInputBehavior", g.KeywordOptions()). + PredefinedQueryStructField("ReturnResultsBehavior", "*ReturnResultsBehavior", g.KeywordOptions()). TextAssignment("RUNTIME_VERSION", g.ParameterOptions().SingleQuotes().Required()). ListQueryStructField( "Packages", @@ -181,10 +185,9 @@ var ProceduresDef = g.NewInterface( TextAssignment("HANDLER", g.ParameterOptions().SingleQuotes().Required()). ListAssignment("EXTERNAL_ACCESS_INTEGRATIONS", "AccountObjectIdentifier", g.ParameterOptions().Parentheses()). ListAssignment("SECRETS", "SecretReference", g.ParameterOptions().Parentheses()). - PredefinedQueryStructField("NullInputBehavior", "*NullInputBehavior", g.KeywordOptions()). OptionalTextAssignment("COMMENT", g.ParameterOptions().SingleQuotes()). PredefinedQueryStructField("ExecuteAs", "*ExecuteAs", g.KeywordOptions()). - PredefinedQueryStructField("ProcedureDefinition", "*string", g.ParameterOptions().NoEquals().SingleQuotes().SQL("AS")). + PredefinedQueryStructField("ProcedureDefinition", "*string", g.ParameterOptions().NoEquals().SQL("AS")). WithValidation(g.ValidateValueSet, "RuntimeVersion"). WithValidation(g.ValidateValueSet, "Packages"). WithValidation(g.ValidateValueSet, "Handler"). @@ -210,6 +213,8 @@ var ProceduresDef = g.NewInterface( g.KeywordOptions().SQL("RETURNS").Required(), ). SQL("LANGUAGE SCALA"). + PredefinedQueryStructField("NullInputBehavior", "*NullInputBehavior", g.KeywordOptions()). + PredefinedQueryStructField("ReturnResultsBehavior", "*ReturnResultsBehavior", g.KeywordOptions()). TextAssignment("RUNTIME_VERSION", g.ParameterOptions().SingleQuotes().Required()). ListQueryStructField( "Packages", @@ -222,11 +227,12 @@ var ProceduresDef = g.NewInterface( g.ParameterOptions().Parentheses().SQL("IMPORTS"), ). TextAssignment("HANDLER", g.ParameterOptions().SingleQuotes().Required()). + ListAssignment("EXTERNAL_ACCESS_INTEGRATIONS", "AccountObjectIdentifier", g.ParameterOptions().Parentheses()). + ListAssignment("SECRETS", "SecretReference", g.ParameterOptions().Parentheses()). OptionalTextAssignment("TARGET_PATH", g.ParameterOptions().SingleQuotes()). - PredefinedQueryStructField("NullInputBehavior", "*NullInputBehavior", g.KeywordOptions()). OptionalTextAssignment("COMMENT", g.ParameterOptions().SingleQuotes()). PredefinedQueryStructField("ExecuteAs", "*ExecuteAs", g.KeywordOptions()). - PredefinedQueryStructField("ProcedureDefinition", "*string", g.ParameterOptions().NoEquals().SingleQuotes().SQL("AS")). + PredefinedQueryStructField("ProcedureDefinition", "*string", g.ParameterOptions().NoEquals().SQL("AS")). WithValidation(g.ValidateValueSet, "RuntimeVersion"). WithValidation(g.ValidateValueSet, "Packages"). WithValidation(g.ValidateValueSet, "Handler"). @@ -253,9 +259,10 @@ var ProceduresDef = g.NewInterface( ). SQL("LANGUAGE SQL"). PredefinedQueryStructField("NullInputBehavior", "*NullInputBehavior", g.KeywordOptions()). + PredefinedQueryStructField("ReturnResultsBehavior", "*ReturnResultsBehavior", g.KeywordOptions()). OptionalTextAssignment("COMMENT", g.ParameterOptions().SingleQuotes()). PredefinedQueryStructField("ExecuteAs", "*ExecuteAs", g.KeywordOptions()). - PredefinedQueryStructField("ProcedureDefinition", "string", g.ParameterOptions().NoEquals().SingleQuotes().SQL("AS").Required()). + PredefinedQueryStructField("ProcedureDefinition", "string", g.ParameterOptions().NoEquals().SQL("AS").Required()). WithValidation(g.ValidateValueSet, "ProcedureDefinition"). WithValidation(g.ValidIdentifier, "name"), ).AlterOperation( @@ -266,16 +273,39 @@ var ProceduresDef = g.NewInterface( IfExists(). Name(). OptionalIdentifier("RenameTo", g.KindOfT[SchemaObjectIdentifier](), g.IdentifierOptions().SQL("RENAME TO")). - OptionalTextAssignment("SET COMMENT", g.ParameterOptions().SingleQuotes()). - OptionalTextAssignment("SET LOG_LEVEL", g.ParameterOptions().SingleQuotes()). - OptionalTextAssignment("SET TRACE_LEVEL", g.ParameterOptions().SingleQuotes()). - OptionalSQL("UNSET COMMENT"). + OptionalQueryStructField( + "Set", + g.NewQueryStruct("ProcedureSet"). + OptionalTextAssignment("COMMENT", g.ParameterOptions().SingleQuotes()). + ListAssignment("EXTERNAL_ACCESS_INTEGRATIONS", "AccountObjectIdentifier", g.ParameterOptions().Parentheses()). + OptionalQueryStructField("SecretsList", functionSecretsListWrapper, g.ParameterOptions().SQL("SECRETS").Parentheses()). + OptionalAssignment("AUTO_EVENT_LOGGING", g.KindOfTPointer[AutoEventLogging](), g.ParameterOptions().SingleQuotes()). + OptionalBooleanAssignment("ENABLE_CONSOLE_OUTPUT", nil). + OptionalAssignment("LOG_LEVEL", g.KindOfTPointer[LogLevel](), g.ParameterOptions().SingleQuotes()). + OptionalAssignment("METRIC_LEVEL", g.KindOfTPointer[MetricLevel](), g.ParameterOptions().SingleQuotes()). + OptionalAssignment("TRACE_LEVEL", g.KindOfTPointer[TraceLevel](), g.ParameterOptions().SingleQuotes()). + WithValidation(g.AtLeastOneValueSet, "Comment", "ExternalAccessIntegrations", "SecretsList", "AutoEventLogging", "EnableConsoleOutput", "LogLevel", "MetricLevel", "TraceLevel"), + g.ListOptions().SQL("SET"), + ). + OptionalQueryStructField( + "Unset", + g.NewQueryStruct("ProcedureUnset"). + OptionalSQL("COMMENT"). + OptionalSQL("EXTERNAL_ACCESS_INTEGRATIONS"). + OptionalSQL("AUTO_EVENT_LOGGING"). + OptionalSQL("ENABLE_CONSOLE_OUTPUT"). + OptionalSQL("LOG_LEVEL"). + OptionalSQL("METRIC_LEVEL"). + OptionalSQL("TRACE_LEVEL"). + WithValidation(g.AtLeastOneValueSet, "Comment", "ExternalAccessIntegrations", "AutoEventLogging", "EnableConsoleOutput", "LogLevel", "MetricLevel", "TraceLevel"), + g.ListOptions().SQL("UNSET"), + ). OptionalSetTags(). OptionalUnsetTags(). PredefinedQueryStructField("ExecuteAs", "*ExecuteAs", g.KeywordOptions()). WithValidation(g.ValidIdentifier, "name"). WithValidation(g.ValidIdentifierIfSet, "RenameTo"). - WithValidation(g.ExactlyOneValueSet, "RenameTo", "SetComment", "SetLogLevel", "SetTraceLevel", "UnsetComment", "SetTags", "UnsetTags", "ExecuteAs"), + WithValidation(g.ExactlyOneValueSet, "RenameTo", "Set", "Unset", "SetTags", "UnsetTags", "ExecuteAs"), ).DropOperation( "https://docs.snowflake.com/en/sql-reference/sql/drop-procedure", g.NewQueryStruct("DropProcedure"). @@ -300,7 +330,9 @@ var ProceduresDef = g.NewInterface( Field("catalog_name", "string"). Field("is_table_function", "string"). Field("valid_for_clustering", "string"). - Field("is_secure", "sql.NullString"), + Field("is_secure", "sql.NullString"). + OptionalText("secrets"). + OptionalText("external_access_integrations"), g.PlainStruct("Procedure"). Field("CreatedOn", "string"). Field("Name", "string"). @@ -315,12 +347,14 @@ var ProceduresDef = g.NewInterface( Field("CatalogName", "string"). Field("IsTableFunction", "bool"). Field("ValidForClustering", "bool"). - Field("IsSecure", "bool"), + Field("IsSecure", "bool"). + OptionalText("Secrets"). + OptionalText("ExternalAccessIntegrations"), g.NewQueryStruct("ShowProcedures"). Show(). SQL("PROCEDURES"). OptionalLike(). - OptionalIn(), // TODO: 'In' struct for procedures not support keyword "CLASS" now + OptionalExtendedIn(), ).ShowByIdOperation().DescribeOperation( g.DescriptionMappingKindSlice, "https://docs.snowflake.com/en/sql-reference/sql/desc-procedure", @@ -329,7 +363,7 @@ var ProceduresDef = g.NewInterface( Field("value", "sql.NullString"), g.PlainStruct("ProcedureDetail"). Field("Property", "string"). - Field("Value", "string"), + OptionalText("Value"), g.NewQueryStruct("DescribeProcedure"). Describe(). SQL("PROCEDURE"). @@ -362,6 +396,8 @@ var ProceduresDef = g.NewInterface( g.KeywordOptions().SQL("RETURNS").Required(), ). SQL("LANGUAGE JAVA"). + PredefinedQueryStructField("NullInputBehavior", "*NullInputBehavior", g.KeywordOptions()). + PredefinedQueryStructField("ProcedureDefinition", "*string", g.ParameterOptions().NoEquals().SingleQuotes().SQL("AS")). TextAssignment("RUNTIME_VERSION", g.ParameterOptions().SingleQuotes().Required()). ListQueryStructField( "Packages", @@ -374,8 +410,6 @@ var ProceduresDef = g.NewInterface( g.ParameterOptions().Parentheses().SQL("IMPORTS"), ). TextAssignment("HANDLER", g.ParameterOptions().SingleQuotes().Required()). - PredefinedQueryStructField("NullInputBehavior", "*NullInputBehavior", g.KeywordOptions()). - PredefinedQueryStructField("ProcedureDefinition", "*string", g.ParameterOptions().NoEquals().SingleQuotes().SQL("AS")). OptionalQueryStructField( "WithClause", procedureWithClause, @@ -408,6 +442,8 @@ var ProceduresDef = g.NewInterface( g.KeywordOptions().SQL("RETURNS").Required(), ). SQL("LANGUAGE SCALA"). + PredefinedQueryStructField("NullInputBehavior", "*NullInputBehavior", g.KeywordOptions()). + PredefinedQueryStructField("ProcedureDefinition", "*string", g.ParameterOptions().NoEquals().SingleQuotes().SQL("AS")). TextAssignment("RUNTIME_VERSION", g.ParameterOptions().SingleQuotes().Required()). ListQueryStructField( "Packages", @@ -420,8 +456,6 @@ var ProceduresDef = g.NewInterface( g.ParameterOptions().Parentheses().SQL("IMPORTS"), ). TextAssignment("HANDLER", g.ParameterOptions().SingleQuotes().Required()). - PredefinedQueryStructField("NullInputBehavior", "*NullInputBehavior", g.KeywordOptions()). - PredefinedQueryStructField("ProcedureDefinition", "*string", g.ParameterOptions().NoEquals().SingleQuotes().SQL("AS")). ListQueryStructField( "WithClauses", procedureWithClause, @@ -486,6 +520,8 @@ var ProceduresDef = g.NewInterface( g.KeywordOptions().SQL("RETURNS").Required(), ). SQL("LANGUAGE PYTHON"). + PredefinedQueryStructField("NullInputBehavior", "*NullInputBehavior", g.KeywordOptions()). + PredefinedQueryStructField("ProcedureDefinition", "*string", g.ParameterOptions().NoEquals().SingleQuotes().SQL("AS")). TextAssignment("RUNTIME_VERSION", g.ParameterOptions().SingleQuotes().Required()). ListQueryStructField( "Packages", @@ -498,8 +534,6 @@ var ProceduresDef = g.NewInterface( g.ParameterOptions().Parentheses().SQL("IMPORTS"), ). TextAssignment("HANDLER", g.ParameterOptions().SingleQuotes().Required()). - PredefinedQueryStructField("NullInputBehavior", "*NullInputBehavior", g.KeywordOptions()). - PredefinedQueryStructField("ProcedureDefinition", "*string", g.ParameterOptions().NoEquals().SingleQuotes().SQL("AS")). ListQueryStructField( "WithClauses", procedureWithClause, diff --git a/pkg/sdk/procedures_dto_builders_gen.go b/pkg/sdk/procedures_dto_builders_gen.go index 373852a62a..c9be49ffce 100644 --- a/pkg/sdk/procedures_dto_builders_gen.go +++ b/pkg/sdk/procedures_dto_builders_gen.go @@ -68,6 +68,11 @@ func (s *CreateForJavaProcedureRequest) WithNullInputBehavior(NullInputBehavior return s } +func (s *CreateForJavaProcedureRequest) WithReturnResultsBehavior(ReturnResultsBehavior ReturnResultsBehavior) *CreateForJavaProcedureRequest { + s.ReturnResultsBehavior = &ReturnResultsBehavior + return s +} + func (s *CreateForJavaProcedureRequest) WithComment(Comment string) *CreateForJavaProcedureRequest { s.Comment = &Comment return s @@ -227,6 +232,11 @@ func (s *CreateForJavaScriptProcedureRequest) WithNullInputBehavior(NullInputBeh return s } +func (s *CreateForJavaScriptProcedureRequest) WithReturnResultsBehavior(ReturnResultsBehavior ReturnResultsBehavior) *CreateForJavaScriptProcedureRequest { + s.ReturnResultsBehavior = &ReturnResultsBehavior + return s +} + func (s *CreateForJavaScriptProcedureRequest) WithComment(Comment string) *CreateForJavaScriptProcedureRequest { s.Comment = &Comment return s @@ -293,6 +303,11 @@ func (s *CreateForPythonProcedureRequest) WithNullInputBehavior(NullInputBehavio return s } +func (s *CreateForPythonProcedureRequest) WithReturnResultsBehavior(ReturnResultsBehavior ReturnResultsBehavior) *CreateForPythonProcedureRequest { + s.ReturnResultsBehavior = &ReturnResultsBehavior + return s +} + func (s *CreateForPythonProcedureRequest) WithComment(Comment string) *CreateForPythonProcedureRequest { s.Comment = &Comment return s @@ -349,6 +364,16 @@ func (s *CreateForScalaProcedureRequest) WithImports(Imports []ProcedureImportRe return s } +func (s *CreateForScalaProcedureRequest) WithExternalAccessIntegrations(ExternalAccessIntegrations []AccountObjectIdentifier) *CreateForScalaProcedureRequest { + s.ExternalAccessIntegrations = ExternalAccessIntegrations + return s +} + +func (s *CreateForScalaProcedureRequest) WithSecrets(Secrets []SecretReference) *CreateForScalaProcedureRequest { + s.Secrets = Secrets + return s +} + func (s *CreateForScalaProcedureRequest) WithTargetPath(TargetPath string) *CreateForScalaProcedureRequest { s.TargetPath = &TargetPath return s @@ -359,6 +384,11 @@ func (s *CreateForScalaProcedureRequest) WithNullInputBehavior(NullInputBehavior return s } +func (s *CreateForScalaProcedureRequest) WithReturnResultsBehavior(ReturnResultsBehavior ReturnResultsBehavior) *CreateForScalaProcedureRequest { + s.ReturnResultsBehavior = &ReturnResultsBehavior + return s +} + func (s *CreateForScalaProcedureRequest) WithComment(Comment string) *CreateForScalaProcedureRequest { s.Comment = &Comment return s @@ -411,6 +441,11 @@ func (s *CreateForSQLProcedureRequest) WithNullInputBehavior(NullInputBehavior N return s } +func (s *CreateForSQLProcedureRequest) WithReturnResultsBehavior(ReturnResultsBehavior ReturnResultsBehavior) *CreateForSQLProcedureRequest { + s.ReturnResultsBehavior = &ReturnResultsBehavior + return s +} + func (s *CreateForSQLProcedureRequest) WithComment(Comment string) *CreateForSQLProcedureRequest { s.Comment = &Comment return s @@ -458,23 +493,13 @@ func (s *AlterProcedureRequest) WithRenameTo(RenameTo SchemaObjectIdentifier) *A return s } -func (s *AlterProcedureRequest) WithSetComment(SetComment string) *AlterProcedureRequest { - s.SetComment = &SetComment - return s -} - -func (s *AlterProcedureRequest) WithSetLogLevel(SetLogLevel string) *AlterProcedureRequest { - s.SetLogLevel = &SetLogLevel +func (s *AlterProcedureRequest) WithSet(Set ProcedureSetRequest) *AlterProcedureRequest { + s.Set = &Set return s } -func (s *AlterProcedureRequest) WithSetTraceLevel(SetTraceLevel string) *AlterProcedureRequest { - s.SetTraceLevel = &SetTraceLevel - return s -} - -func (s *AlterProcedureRequest) WithUnsetComment(UnsetComment bool) *AlterProcedureRequest { - s.UnsetComment = &UnsetComment +func (s *AlterProcedureRequest) WithUnset(Unset ProcedureUnsetRequest) *AlterProcedureRequest { + s.Unset = &Unset return s } @@ -493,6 +518,91 @@ func (s *AlterProcedureRequest) WithExecuteAs(ExecuteAs ExecuteAs) *AlterProcedu return s } +func NewProcedureSetRequest() *ProcedureSetRequest { + return &ProcedureSetRequest{} +} + +func (s *ProcedureSetRequest) WithComment(Comment string) *ProcedureSetRequest { + s.Comment = &Comment + return s +} + +func (s *ProcedureSetRequest) WithExternalAccessIntegrations(ExternalAccessIntegrations []AccountObjectIdentifier) *ProcedureSetRequest { + s.ExternalAccessIntegrations = ExternalAccessIntegrations + return s +} + +func (s *ProcedureSetRequest) WithSecretsList(SecretsList SecretsListRequest) *ProcedureSetRequest { + s.SecretsList = &SecretsList + return s +} + +func (s *ProcedureSetRequest) WithAutoEventLogging(AutoEventLogging AutoEventLogging) *ProcedureSetRequest { + s.AutoEventLogging = &AutoEventLogging + return s +} + +func (s *ProcedureSetRequest) WithEnableConsoleOutput(EnableConsoleOutput bool) *ProcedureSetRequest { + s.EnableConsoleOutput = &EnableConsoleOutput + return s +} + +func (s *ProcedureSetRequest) WithLogLevel(LogLevel LogLevel) *ProcedureSetRequest { + s.LogLevel = &LogLevel + return s +} + +func (s *ProcedureSetRequest) WithMetricLevel(MetricLevel MetricLevel) *ProcedureSetRequest { + s.MetricLevel = &MetricLevel + return s +} + +func (s *ProcedureSetRequest) WithTraceLevel(TraceLevel TraceLevel) *ProcedureSetRequest { + s.TraceLevel = &TraceLevel + return s +} + +// NewSecretsListRequest removed manually - redeclared in functions + +func NewProcedureUnsetRequest() *ProcedureUnsetRequest { + return &ProcedureUnsetRequest{} +} + +func (s *ProcedureUnsetRequest) WithComment(Comment bool) *ProcedureUnsetRequest { + s.Comment = &Comment + return s +} + +func (s *ProcedureUnsetRequest) WithExternalAccessIntegrations(ExternalAccessIntegrations bool) *ProcedureUnsetRequest { + s.ExternalAccessIntegrations = &ExternalAccessIntegrations + return s +} + +func (s *ProcedureUnsetRequest) WithAutoEventLogging(AutoEventLogging bool) *ProcedureUnsetRequest { + s.AutoEventLogging = &AutoEventLogging + return s +} + +func (s *ProcedureUnsetRequest) WithEnableConsoleOutput(EnableConsoleOutput bool) *ProcedureUnsetRequest { + s.EnableConsoleOutput = &EnableConsoleOutput + return s +} + +func (s *ProcedureUnsetRequest) WithLogLevel(LogLevel bool) *ProcedureUnsetRequest { + s.LogLevel = &LogLevel + return s +} + +func (s *ProcedureUnsetRequest) WithMetricLevel(MetricLevel bool) *ProcedureUnsetRequest { + s.MetricLevel = &MetricLevel + return s +} + +func (s *ProcedureUnsetRequest) WithTraceLevel(TraceLevel bool) *ProcedureUnsetRequest { + s.TraceLevel = &TraceLevel + return s +} + func NewDropProcedureRequest( name SchemaObjectIdentifierWithArguments, ) *DropProcedureRequest { @@ -515,7 +625,7 @@ func (s *ShowProcedureRequest) WithLike(Like Like) *ShowProcedureRequest { return s } -func (s *ShowProcedureRequest) WithIn(In In) *ShowProcedureRequest { +func (s *ShowProcedureRequest) WithIn(In ExtendedIn) *ShowProcedureRequest { s.In = &In return s } diff --git a/pkg/sdk/procedures_dto_gen.go b/pkg/sdk/procedures_dto_gen.go index bf3e0a8d72..75d57c2448 100644 --- a/pkg/sdk/procedures_dto_gen.go +++ b/pkg/sdk/procedures_dto_gen.go @@ -38,6 +38,7 @@ type CreateForJavaProcedureRequest struct { Secrets []SecretReference TargetPath *string NullInputBehavior *NullInputBehavior + ReturnResultsBehavior *ReturnResultsBehavior Comment *string ExecuteAs *ExecuteAs ProcedureDefinition *string @@ -81,18 +82,19 @@ type ProcedureImportRequest struct { } type CreateForJavaScriptProcedureRequest struct { - OrReplace *bool - Secure *bool - name SchemaObjectIdentifier // required - Arguments []ProcedureArgumentRequest - CopyGrants *bool - ResultDataTypeOld DataType - ResultDataType datatypes.DataType // required - NotNull *bool - NullInputBehavior *NullInputBehavior - Comment *string - ExecuteAs *ExecuteAs - ProcedureDefinition string // required + OrReplace *bool + Secure *bool + name SchemaObjectIdentifier // required + Arguments []ProcedureArgumentRequest + CopyGrants *bool + ResultDataTypeOld DataType + ResultDataType datatypes.DataType // required + NotNull *bool + NullInputBehavior *NullInputBehavior + ReturnResultsBehavior *ReturnResultsBehavior + Comment *string + ExecuteAs *ExecuteAs + ProcedureDefinition string // required } type CreateForPythonProcedureRequest struct { @@ -109,40 +111,45 @@ type CreateForPythonProcedureRequest struct { ExternalAccessIntegrations []AccountObjectIdentifier Secrets []SecretReference NullInputBehavior *NullInputBehavior + ReturnResultsBehavior *ReturnResultsBehavior Comment *string ExecuteAs *ExecuteAs ProcedureDefinition *string } type CreateForScalaProcedureRequest struct { - OrReplace *bool - Secure *bool - name SchemaObjectIdentifier // required - Arguments []ProcedureArgumentRequest - CopyGrants *bool - Returns ProcedureReturnsRequest // required - RuntimeVersion string // required - Packages []ProcedurePackageRequest // required - Imports []ProcedureImportRequest - Handler string // required - TargetPath *string - NullInputBehavior *NullInputBehavior - Comment *string - ExecuteAs *ExecuteAs - ProcedureDefinition *string + OrReplace *bool + Secure *bool + name SchemaObjectIdentifier // required + Arguments []ProcedureArgumentRequest + CopyGrants *bool + Returns ProcedureReturnsRequest // required + RuntimeVersion string // required + Packages []ProcedurePackageRequest // required + Imports []ProcedureImportRequest + Handler string // required + ExternalAccessIntegrations []AccountObjectIdentifier + Secrets []SecretReference + TargetPath *string + NullInputBehavior *NullInputBehavior + ReturnResultsBehavior *ReturnResultsBehavior + Comment *string + ExecuteAs *ExecuteAs + ProcedureDefinition *string } type CreateForSQLProcedureRequest struct { - OrReplace *bool - Secure *bool - name SchemaObjectIdentifier // required - Arguments []ProcedureArgumentRequest - CopyGrants *bool - Returns ProcedureSQLReturnsRequest // required - NullInputBehavior *NullInputBehavior - Comment *string - ExecuteAs *ExecuteAs - ProcedureDefinition string // required + OrReplace *bool + Secure *bool + name SchemaObjectIdentifier // required + Arguments []ProcedureArgumentRequest + CopyGrants *bool + Returns ProcedureSQLReturnsRequest // required + NullInputBehavior *NullInputBehavior + ReturnResultsBehavior *ReturnResultsBehavior + Comment *string + ExecuteAs *ExecuteAs + ProcedureDefinition string // required } type ProcedureSQLReturnsRequest struct { @@ -152,16 +159,37 @@ type ProcedureSQLReturnsRequest struct { } type AlterProcedureRequest struct { - IfExists *bool - name SchemaObjectIdentifierWithArguments // required - RenameTo *SchemaObjectIdentifier - SetComment *string - SetLogLevel *string - SetTraceLevel *string - UnsetComment *bool - SetTags []TagAssociation - UnsetTags []ObjectIdentifier - ExecuteAs *ExecuteAs + IfExists *bool + name SchemaObjectIdentifierWithArguments // required + RenameTo *SchemaObjectIdentifier + Set *ProcedureSetRequest + Unset *ProcedureUnsetRequest + SetTags []TagAssociation + UnsetTags []ObjectIdentifier + ExecuteAs *ExecuteAs +} + +type ProcedureSetRequest struct { + Comment *string + ExternalAccessIntegrations []AccountObjectIdentifier + SecretsList *SecretsListRequest + AutoEventLogging *AutoEventLogging + EnableConsoleOutput *bool + LogLevel *LogLevel + MetricLevel *MetricLevel + TraceLevel *TraceLevel +} + +// SecretsListRequest removed manually - redeclaration with function + +type ProcedureUnsetRequest struct { + Comment *bool + ExternalAccessIntegrations *bool + AutoEventLogging *bool + EnableConsoleOutput *bool + LogLevel *bool + MetricLevel *bool + TraceLevel *bool } type DropProcedureRequest struct { @@ -171,7 +199,7 @@ type DropProcedureRequest struct { type ShowProcedureRequest struct { Like *Like - In *In + In *ExtendedIn } type DescribeProcedureRequest struct { diff --git a/pkg/sdk/procedures_ext.go b/pkg/sdk/procedures_ext.go index 31307bc2fb..a8ee2844bf 100644 --- a/pkg/sdk/procedures_ext.go +++ b/pkg/sdk/procedures_ext.go @@ -1,5 +1,151 @@ package sdk +import ( + "context" + "errors" + "fmt" + "strconv" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk/datatypes" +) + +const DefaultProcedureComment = "user-defined procedure" + func (v *Procedure) ID() SchemaObjectIdentifierWithArguments { return NewSchemaObjectIdentifierWithArguments(v.CatalogName, v.SchemaName, v.Name, v.ArgumentsOld...) } + +// ProcedureDetails contains aggregated describe results for the given procedure. +type ProcedureDetails struct { + Signature string // present for all procedure types + Returns string // present for all procedure types + Language string // present for all procedure types + NullHandling *string // present for all procedure types but SQL + Body *string // present for all procedure types (hidden when SECURE) + Volatility *string // present for all procedure types but SQL + ExternalAccessIntegrations *string // list present for python, java, and scala + Secrets *string // map present for python, java, and scala + Imports *string // list present for python, java, and scala (hidden when SECURE) + Handler *string // present for python, java, and scala (hidden when SECURE) + RuntimeVersion *string // present for python, java, and scala (hidden when SECURE) + Packages *string // list // present for python, java, and scala (hidden when SECURE) + TargetPath *string // list present for scala and java (hidden when SECURE) + InstalledPackages *string // list present for python (hidden when SECURE) + ExecuteAs string // present for all procedure types +} + +func procedureDetailsFromRows(rows []ProcedureDetail) (*ProcedureDetails, error) { + v := &ProcedureDetails{} + var errs []error + for _, row := range rows { + switch row.Property { + case "signature": + errs = append(errs, row.setStringValueOrError("signature", &v.Signature)) + case "returns": + errs = append(errs, row.setStringValueOrError("returns", &v.Returns)) + case "language": + errs = append(errs, row.setStringValueOrError("language", &v.Language)) + case "execute as": + errs = append(errs, row.setStringValueOrError("execute as", &v.ExecuteAs)) + case "null handling": + v.NullHandling = row.Value + case "volatility": + v.Volatility = row.Value + case "body": + v.Body = row.Value + case "external_access_integrations": + v.ExternalAccessIntegrations = row.Value + case "secrets": + v.Secrets = row.Value + case "imports": + v.Imports = row.Value + case "handler": + v.Handler = row.Value + case "runtime_version": + v.RuntimeVersion = row.Value + case "packages": + v.Packages = row.Value + case "installed_packages": + v.InstalledPackages = row.Value + case "target_path": + v.TargetPath = row.Value + } + } + return v, errors.Join(errs...) +} + +func (d *ProcedureDetail) setStringValueOrError(property string, field *string) error { + if d.Value == nil { + return fmt.Errorf("value expected for field %s", property) + } else { + *field = *d.Value + } + return nil +} + +func (d *ProcedureDetail) setOptionalBoolValueOrError(property string, field **bool) error { + if d.Value != nil && *d.Value != "" { + v, err := strconv.ParseBool(*d.Value) + if err != nil { + return fmt.Errorf("invalid value for field %s, err: %w", property, err) + } else { + *field = Bool(v) + } + } + return nil +} + +func (v *procedures) DescribeDetails(ctx context.Context, id SchemaObjectIdentifierWithArguments) (*ProcedureDetails, error) { + rows, err := v.Describe(ctx, id) + if err != nil { + return nil, err + } + return procedureDetailsFromRows(rows) +} + +func (v *procedures) ShowParameters(ctx context.Context, id SchemaObjectIdentifierWithArguments) ([]*Parameter, error) { + return v.client.Parameters.ShowParameters(ctx, &ShowParametersOptions{ + In: &ParametersIn{ + Procedure: id, + }, + }) +} + +func (s *CreateForJavaProcedureRequest) WithProcedureDefinitionWrapped(procedureDefinition string) *CreateForJavaProcedureRequest { + s.ProcedureDefinition = String(fmt.Sprintf(`$$%s$$`, procedureDefinition)) + return s +} + +func (s *CreateForPythonProcedureRequest) WithProcedureDefinitionWrapped(procedureDefinition string) *CreateForPythonProcedureRequest { + s.ProcedureDefinition = String(fmt.Sprintf(`$$%s$$`, procedureDefinition)) + return s +} + +func (s *CreateForScalaProcedureRequest) WithProcedureDefinitionWrapped(procedureDefinition string) *CreateForScalaProcedureRequest { + s.ProcedureDefinition = String(fmt.Sprintf(`$$%s$$`, procedureDefinition)) + return s +} + +func NewCreateForSQLProcedureRequestDefinitionWrapped( + name SchemaObjectIdentifier, + returns ProcedureSQLReturnsRequest, + procedureDefinition string, +) *CreateForSQLProcedureRequest { + s := CreateForSQLProcedureRequest{} + s.name = name + s.Returns = returns + s.ProcedureDefinition = fmt.Sprintf(`$$%s$$`, procedureDefinition) + return &s +} + +func NewCreateForJavaScriptProcedureRequestDefinitionWrapped( + name SchemaObjectIdentifier, + resultDataType datatypes.DataType, + procedureDefinition string, +) *CreateForJavaScriptProcedureRequest { + s := CreateForJavaScriptProcedureRequest{} + s.name = name + s.ResultDataType = resultDataType + s.ProcedureDefinition = fmt.Sprintf(`$$%s$$`, procedureDefinition) + return &s +} diff --git a/pkg/sdk/procedures_gen.go b/pkg/sdk/procedures_gen.go index c65e95e94a..0dbbf8f5a1 100644 --- a/pkg/sdk/procedures_gen.go +++ b/pkg/sdk/procedures_gen.go @@ -25,6 +25,10 @@ type Procedures interface { CreateAndCallForJavaScript(ctx context.Context, request *CreateAndCallForJavaScriptProcedureRequest) error CreateAndCallForPython(ctx context.Context, request *CreateAndCallForPythonProcedureRequest) error CreateAndCallForSQL(ctx context.Context, request *CreateAndCallForSQLProcedureRequest) error + + // DescribeDetails is added manually; it returns aggregated describe results for the given procedure. + DescribeDetails(ctx context.Context, id SchemaObjectIdentifierWithArguments) (*ProcedureDetails, error) + ShowParameters(ctx context.Context, id SchemaObjectIdentifierWithArguments) ([]*Parameter, error) } // CreateForJavaProcedureOptions is based on https://docs.snowflake.com/en/sql-reference/sql/create-procedure#java-handler. @@ -38,6 +42,8 @@ type CreateForJavaProcedureOptions struct { CopyGrants *bool `ddl:"keyword" sql:"COPY GRANTS"` Returns ProcedureReturns `ddl:"keyword" sql:"RETURNS"` languageJava bool `ddl:"static" sql:"LANGUAGE JAVA"` + NullInputBehavior *NullInputBehavior `ddl:"keyword"` + ReturnResultsBehavior *ReturnResultsBehavior `ddl:"keyword"` RuntimeVersion string `ddl:"parameter,single_quotes" sql:"RUNTIME_VERSION"` Packages []ProcedurePackage `ddl:"parameter,parentheses" sql:"PACKAGES"` Imports []ProcedureImport `ddl:"parameter,parentheses" sql:"IMPORTS"` @@ -45,14 +51,13 @@ type CreateForJavaProcedureOptions struct { ExternalAccessIntegrations []AccountObjectIdentifier `ddl:"parameter,parentheses" sql:"EXTERNAL_ACCESS_INTEGRATIONS"` Secrets []SecretReference `ddl:"parameter,parentheses" sql:"SECRETS"` TargetPath *string `ddl:"parameter,single_quotes" sql:"TARGET_PATH"` - NullInputBehavior *NullInputBehavior `ddl:"keyword"` Comment *string `ddl:"parameter,single_quotes" sql:"COMMENT"` ExecuteAs *ExecuteAs `ddl:"keyword"` - ProcedureDefinition *string `ddl:"parameter,single_quotes,no_equals" sql:"AS"` + ProcedureDefinition *string `ddl:"parameter,no_equals" sql:"AS"` } type ProcedureArgument struct { - ArgName string `ddl:"keyword,no_quotes"` + ArgName string `ddl:"keyword,double_quotes"` ArgDataTypeOld DataType `ddl:"keyword,no_quotes"` ArgDataType datatypes.DataType `ddl:"parameter,no_quotes,no_equals"` DefaultValue *string `ddl:"parameter,no_equals" sql:"DEFAULT"` @@ -75,7 +80,7 @@ type ProcedureReturnsTable struct { } type ProcedureColumn struct { - ColumnName string `ddl:"keyword,no_quotes"` + ColumnName string `ddl:"keyword,double_quotes"` ColumnDataTypeOld DataType `ddl:"keyword,no_quotes"` ColumnDataType datatypes.DataType `ddl:"parameter,no_quotes,no_equals"` } @@ -90,22 +95,23 @@ type ProcedureImport struct { // CreateForJavaScriptProcedureOptions is based on https://docs.snowflake.com/en/sql-reference/sql/create-procedure#javascript-handler. type CreateForJavaScriptProcedureOptions struct { - create bool `ddl:"static" sql:"CREATE"` - OrReplace *bool `ddl:"keyword" sql:"OR REPLACE"` - Secure *bool `ddl:"keyword" sql:"SECURE"` - procedure bool `ddl:"static" sql:"PROCEDURE"` - name SchemaObjectIdentifier `ddl:"identifier"` - Arguments []ProcedureArgument `ddl:"list,must_parentheses"` - CopyGrants *bool `ddl:"keyword" sql:"COPY GRANTS"` - returns bool `ddl:"static" sql:"RETURNS"` - ResultDataTypeOld DataType `ddl:"parameter,no_equals"` - ResultDataType datatypes.DataType `ddl:"parameter,no_quotes,no_equals"` - NotNull *bool `ddl:"keyword" sql:"NOT NULL"` - languageJavascript bool `ddl:"static" sql:"LANGUAGE JAVASCRIPT"` - NullInputBehavior *NullInputBehavior `ddl:"keyword"` - Comment *string `ddl:"parameter,single_quotes" sql:"COMMENT"` - ExecuteAs *ExecuteAs `ddl:"keyword"` - ProcedureDefinition string `ddl:"parameter,single_quotes,no_equals" sql:"AS"` + create bool `ddl:"static" sql:"CREATE"` + OrReplace *bool `ddl:"keyword" sql:"OR REPLACE"` + Secure *bool `ddl:"keyword" sql:"SECURE"` + procedure bool `ddl:"static" sql:"PROCEDURE"` + name SchemaObjectIdentifier `ddl:"identifier"` + Arguments []ProcedureArgument `ddl:"list,must_parentheses"` + CopyGrants *bool `ddl:"keyword" sql:"COPY GRANTS"` + returns bool `ddl:"static" sql:"RETURNS"` + ResultDataTypeOld DataType `ddl:"parameter,no_equals"` + ResultDataType datatypes.DataType `ddl:"parameter,no_quotes,no_equals"` + NotNull *bool `ddl:"keyword" sql:"NOT NULL"` + languageJavascript bool `ddl:"static" sql:"LANGUAGE JAVASCRIPT"` + NullInputBehavior *NullInputBehavior `ddl:"keyword"` + ReturnResultsBehavior *ReturnResultsBehavior `ddl:"keyword"` + Comment *string `ddl:"parameter,single_quotes" sql:"COMMENT"` + ExecuteAs *ExecuteAs `ddl:"keyword"` + ProcedureDefinition string `ddl:"parameter,no_equals" sql:"AS"` } // CreateForPythonProcedureOptions is based on https://docs.snowflake.com/en/sql-reference/sql/create-procedure#python-handler. @@ -119,55 +125,60 @@ type CreateForPythonProcedureOptions struct { CopyGrants *bool `ddl:"keyword" sql:"COPY GRANTS"` Returns ProcedureReturns `ddl:"keyword" sql:"RETURNS"` languagePython bool `ddl:"static" sql:"LANGUAGE PYTHON"` + NullInputBehavior *NullInputBehavior `ddl:"keyword"` + ReturnResultsBehavior *ReturnResultsBehavior `ddl:"keyword"` RuntimeVersion string `ddl:"parameter,single_quotes" sql:"RUNTIME_VERSION"` Packages []ProcedurePackage `ddl:"parameter,parentheses" sql:"PACKAGES"` Imports []ProcedureImport `ddl:"parameter,parentheses" sql:"IMPORTS"` Handler string `ddl:"parameter,single_quotes" sql:"HANDLER"` ExternalAccessIntegrations []AccountObjectIdentifier `ddl:"parameter,parentheses" sql:"EXTERNAL_ACCESS_INTEGRATIONS"` Secrets []SecretReference `ddl:"parameter,parentheses" sql:"SECRETS"` - NullInputBehavior *NullInputBehavior `ddl:"keyword"` Comment *string `ddl:"parameter,single_quotes" sql:"COMMENT"` ExecuteAs *ExecuteAs `ddl:"keyword"` - ProcedureDefinition *string `ddl:"parameter,single_quotes,no_equals" sql:"AS"` + ProcedureDefinition *string `ddl:"parameter,no_equals" sql:"AS"` } // CreateForScalaProcedureOptions is based on https://docs.snowflake.com/en/sql-reference/sql/create-procedure#scala-handler. type CreateForScalaProcedureOptions struct { - create bool `ddl:"static" sql:"CREATE"` - OrReplace *bool `ddl:"keyword" sql:"OR REPLACE"` - Secure *bool `ddl:"keyword" sql:"SECURE"` - procedure bool `ddl:"static" sql:"PROCEDURE"` - name SchemaObjectIdentifier `ddl:"identifier"` - Arguments []ProcedureArgument `ddl:"list,must_parentheses"` - CopyGrants *bool `ddl:"keyword" sql:"COPY GRANTS"` - Returns ProcedureReturns `ddl:"keyword" sql:"RETURNS"` - languageScala bool `ddl:"static" sql:"LANGUAGE SCALA"` - RuntimeVersion string `ddl:"parameter,single_quotes" sql:"RUNTIME_VERSION"` - Packages []ProcedurePackage `ddl:"parameter,parentheses" sql:"PACKAGES"` - Imports []ProcedureImport `ddl:"parameter,parentheses" sql:"IMPORTS"` - Handler string `ddl:"parameter,single_quotes" sql:"HANDLER"` - TargetPath *string `ddl:"parameter,single_quotes" sql:"TARGET_PATH"` - NullInputBehavior *NullInputBehavior `ddl:"keyword"` - Comment *string `ddl:"parameter,single_quotes" sql:"COMMENT"` - ExecuteAs *ExecuteAs `ddl:"keyword"` - ProcedureDefinition *string `ddl:"parameter,single_quotes,no_equals" sql:"AS"` + create bool `ddl:"static" sql:"CREATE"` + OrReplace *bool `ddl:"keyword" sql:"OR REPLACE"` + Secure *bool `ddl:"keyword" sql:"SECURE"` + procedure bool `ddl:"static" sql:"PROCEDURE"` + name SchemaObjectIdentifier `ddl:"identifier"` + Arguments []ProcedureArgument `ddl:"list,must_parentheses"` + CopyGrants *bool `ddl:"keyword" sql:"COPY GRANTS"` + Returns ProcedureReturns `ddl:"keyword" sql:"RETURNS"` + languageScala bool `ddl:"static" sql:"LANGUAGE SCALA"` + NullInputBehavior *NullInputBehavior `ddl:"keyword"` + ReturnResultsBehavior *ReturnResultsBehavior `ddl:"keyword"` + RuntimeVersion string `ddl:"parameter,single_quotes" sql:"RUNTIME_VERSION"` + Packages []ProcedurePackage `ddl:"parameter,parentheses" sql:"PACKAGES"` + Imports []ProcedureImport `ddl:"parameter,parentheses" sql:"IMPORTS"` + Handler string `ddl:"parameter,single_quotes" sql:"HANDLER"` + ExternalAccessIntegrations []AccountObjectIdentifier `ddl:"parameter,parentheses" sql:"EXTERNAL_ACCESS_INTEGRATIONS"` + Secrets []SecretReference `ddl:"parameter,parentheses" sql:"SECRETS"` + TargetPath *string `ddl:"parameter,single_quotes" sql:"TARGET_PATH"` + Comment *string `ddl:"parameter,single_quotes" sql:"COMMENT"` + ExecuteAs *ExecuteAs `ddl:"keyword"` + ProcedureDefinition *string `ddl:"parameter,no_equals" sql:"AS"` } // CreateForSQLProcedureOptions is based on https://docs.snowflake.com/en/sql-reference/sql/create-procedure#snowflake-scripting-handler. type CreateForSQLProcedureOptions struct { - create bool `ddl:"static" sql:"CREATE"` - OrReplace *bool `ddl:"keyword" sql:"OR REPLACE"` - Secure *bool `ddl:"keyword" sql:"SECURE"` - procedure bool `ddl:"static" sql:"PROCEDURE"` - name SchemaObjectIdentifier `ddl:"identifier"` - Arguments []ProcedureArgument `ddl:"list,must_parentheses"` - CopyGrants *bool `ddl:"keyword" sql:"COPY GRANTS"` - Returns ProcedureSQLReturns `ddl:"keyword" sql:"RETURNS"` - languageSql bool `ddl:"static" sql:"LANGUAGE SQL"` - NullInputBehavior *NullInputBehavior `ddl:"keyword"` - Comment *string `ddl:"parameter,single_quotes" sql:"COMMENT"` - ExecuteAs *ExecuteAs `ddl:"keyword"` - ProcedureDefinition string `ddl:"parameter,single_quotes,no_equals" sql:"AS"` + create bool `ddl:"static" sql:"CREATE"` + OrReplace *bool `ddl:"keyword" sql:"OR REPLACE"` + Secure *bool `ddl:"keyword" sql:"SECURE"` + procedure bool `ddl:"static" sql:"PROCEDURE"` + name SchemaObjectIdentifier `ddl:"identifier"` + Arguments []ProcedureArgument `ddl:"list,must_parentheses"` + CopyGrants *bool `ddl:"keyword" sql:"COPY GRANTS"` + Returns ProcedureSQLReturns `ddl:"keyword" sql:"RETURNS"` + languageSql bool `ddl:"static" sql:"LANGUAGE SQL"` + NullInputBehavior *NullInputBehavior `ddl:"keyword"` + ReturnResultsBehavior *ReturnResultsBehavior `ddl:"keyword"` + Comment *string `ddl:"parameter,single_quotes" sql:"COMMENT"` + ExecuteAs *ExecuteAs `ddl:"keyword"` + ProcedureDefinition string `ddl:"parameter,no_equals" sql:"AS"` } type ProcedureSQLReturns struct { @@ -178,18 +189,39 @@ type ProcedureSQLReturns struct { // AlterProcedureOptions is based on https://docs.snowflake.com/en/sql-reference/sql/alter-procedure. type AlterProcedureOptions struct { - alter bool `ddl:"static" sql:"ALTER"` - procedure bool `ddl:"static" sql:"PROCEDURE"` - IfExists *bool `ddl:"keyword" sql:"IF EXISTS"` - name SchemaObjectIdentifierWithArguments `ddl:"identifier"` - RenameTo *SchemaObjectIdentifier `ddl:"identifier" sql:"RENAME TO"` - SetComment *string `ddl:"parameter,single_quotes" sql:"SET COMMENT"` - SetLogLevel *string `ddl:"parameter,single_quotes" sql:"SET LOG_LEVEL"` - SetTraceLevel *string `ddl:"parameter,single_quotes" sql:"SET TRACE_LEVEL"` - UnsetComment *bool `ddl:"keyword" sql:"UNSET COMMENT"` - SetTags []TagAssociation `ddl:"keyword" sql:"SET TAG"` - UnsetTags []ObjectIdentifier `ddl:"keyword" sql:"UNSET TAG"` - ExecuteAs *ExecuteAs `ddl:"keyword"` + alter bool `ddl:"static" sql:"ALTER"` + procedure bool `ddl:"static" sql:"PROCEDURE"` + IfExists *bool `ddl:"keyword" sql:"IF EXISTS"` + name SchemaObjectIdentifierWithArguments `ddl:"identifier"` + RenameTo *SchemaObjectIdentifier `ddl:"identifier" sql:"RENAME TO"` + Set *ProcedureSet `ddl:"list" sql:"SET"` + Unset *ProcedureUnset `ddl:"list" sql:"UNSET"` + SetTags []TagAssociation `ddl:"keyword" sql:"SET TAG"` + UnsetTags []ObjectIdentifier `ddl:"keyword" sql:"UNSET TAG"` + ExecuteAs *ExecuteAs `ddl:"keyword"` +} + +type ProcedureSet struct { + Comment *string `ddl:"parameter,single_quotes" sql:"COMMENT"` + ExternalAccessIntegrations []AccountObjectIdentifier `ddl:"parameter,parentheses" sql:"EXTERNAL_ACCESS_INTEGRATIONS"` + SecretsList *SecretsList `ddl:"parameter,parentheses" sql:"SECRETS"` + AutoEventLogging *AutoEventLogging `ddl:"parameter,single_quotes" sql:"AUTO_EVENT_LOGGING"` + EnableConsoleOutput *bool `ddl:"parameter" sql:"ENABLE_CONSOLE_OUTPUT"` + LogLevel *LogLevel `ddl:"parameter,single_quotes" sql:"LOG_LEVEL"` + MetricLevel *MetricLevel `ddl:"parameter,single_quotes" sql:"METRIC_LEVEL"` + TraceLevel *TraceLevel `ddl:"parameter,single_quotes" sql:"TRACE_LEVEL"` +} + +// SecretsList removed manually - redeclared in functions + +type ProcedureUnset struct { + Comment *bool `ddl:"keyword" sql:"COMMENT"` + ExternalAccessIntegrations *bool `ddl:"keyword" sql:"EXTERNAL_ACCESS_INTEGRATIONS"` + AutoEventLogging *bool `ddl:"keyword" sql:"AUTO_EVENT_LOGGING"` + EnableConsoleOutput *bool `ddl:"keyword" sql:"ENABLE_CONSOLE_OUTPUT"` + LogLevel *bool `ddl:"keyword" sql:"LOG_LEVEL"` + MetricLevel *bool `ddl:"keyword" sql:"METRIC_LEVEL"` + TraceLevel *bool `ddl:"keyword" sql:"TRACE_LEVEL"` } // DropProcedureOptions is based on https://docs.snowflake.com/en/sql-reference/sql/drop-procedure. @@ -202,45 +234,49 @@ type DropProcedureOptions struct { // ShowProcedureOptions is based on https://docs.snowflake.com/en/sql-reference/sql/show-procedures. type ShowProcedureOptions struct { - show bool `ddl:"static" sql:"SHOW"` - procedures bool `ddl:"static" sql:"PROCEDURES"` - Like *Like `ddl:"keyword" sql:"LIKE"` - In *In `ddl:"keyword" sql:"IN"` + show bool `ddl:"static" sql:"SHOW"` + procedures bool `ddl:"static" sql:"PROCEDURES"` + Like *Like `ddl:"keyword" sql:"LIKE"` + In *ExtendedIn `ddl:"keyword" sql:"IN"` } type procedureRow struct { - CreatedOn string `db:"created_on"` - Name string `db:"name"` - SchemaName string `db:"schema_name"` - IsBuiltin string `db:"is_builtin"` - IsAggregate string `db:"is_aggregate"` - IsAnsi string `db:"is_ansi"` - MinNumArguments int `db:"min_num_arguments"` - MaxNumArguments int `db:"max_num_arguments"` - Arguments string `db:"arguments"` - Description string `db:"description"` - CatalogName string `db:"catalog_name"` - IsTableFunction string `db:"is_table_function"` - ValidForClustering string `db:"valid_for_clustering"` - IsSecure sql.NullString `db:"is_secure"` + CreatedOn string `db:"created_on"` + Name string `db:"name"` + SchemaName string `db:"schema_name"` + IsBuiltin string `db:"is_builtin"` + IsAggregate string `db:"is_aggregate"` + IsAnsi string `db:"is_ansi"` + MinNumArguments int `db:"min_num_arguments"` + MaxNumArguments int `db:"max_num_arguments"` + Arguments string `db:"arguments"` + Description string `db:"description"` + CatalogName string `db:"catalog_name"` + IsTableFunction string `db:"is_table_function"` + ValidForClustering string `db:"valid_for_clustering"` + IsSecure sql.NullString `db:"is_secure"` + Secrets sql.NullString `db:"secrets"` + ExternalAccessIntegrations sql.NullString `db:"external_access_integrations"` } type Procedure struct { - CreatedOn string - Name string - SchemaName string - IsBuiltin bool - IsAggregate bool - IsAnsi bool - MinNumArguments int - MaxNumArguments int - ArgumentsOld []DataType - ArgumentsRaw string - Description string - CatalogName string - IsTableFunction bool - ValidForClustering bool - IsSecure bool + CreatedOn string + Name string + SchemaName string + IsBuiltin bool + IsAggregate bool + IsAnsi bool + MinNumArguments int + MaxNumArguments int + ArgumentsOld []DataType + ArgumentsRaw string + Description string + CatalogName string + IsTableFunction bool + ValidForClustering bool + IsSecure bool + Secrets *string + ExternalAccessIntegrations *string } // DescribeProcedureOptions is based on https://docs.snowflake.com/en/sql-reference/sql/desc-procedure. @@ -257,7 +293,7 @@ type procedureDetailRow struct { type ProcedureDetail struct { Property string - Value string + Value *string } // CallProcedureOptions is based on https://docs.snowflake.com/en/sql-reference/sql/call. @@ -276,11 +312,11 @@ type CreateAndCallForJavaProcedureOptions struct { Arguments []ProcedureArgument `ddl:"list,must_parentheses"` Returns ProcedureReturns `ddl:"keyword" sql:"RETURNS"` languageJava bool `ddl:"static" sql:"LANGUAGE JAVA"` + NullInputBehavior *NullInputBehavior `ddl:"keyword"` RuntimeVersion string `ddl:"parameter,single_quotes" sql:"RUNTIME_VERSION"` Packages []ProcedurePackage `ddl:"parameter,parentheses" sql:"PACKAGES"` Imports []ProcedureImport `ddl:"parameter,parentheses" sql:"IMPORTS"` Handler string `ddl:"parameter,single_quotes" sql:"HANDLER"` - NullInputBehavior *NullInputBehavior `ddl:"keyword"` ProcedureDefinition *string `ddl:"parameter,single_quotes,no_equals" sql:"AS"` WithClause *ProcedureWithClause `ddl:"keyword"` call bool `ddl:"static" sql:"CALL"` @@ -288,6 +324,7 @@ type CreateAndCallForJavaProcedureOptions struct { CallArguments []string `ddl:"keyword,must_parentheses"` ScriptingVariable *string `ddl:"parameter,no_quotes,no_equals" sql:"INTO"` } + type ProcedureWithClause struct { prefix bool `ddl:"static" sql:","` CteName AccountObjectIdentifier `ddl:"identifier"` @@ -303,11 +340,11 @@ type CreateAndCallForScalaProcedureOptions struct { Arguments []ProcedureArgument `ddl:"list,must_parentheses"` Returns ProcedureReturns `ddl:"keyword" sql:"RETURNS"` languageScala bool `ddl:"static" sql:"LANGUAGE SCALA"` + NullInputBehavior *NullInputBehavior `ddl:"keyword"` RuntimeVersion string `ddl:"parameter,single_quotes" sql:"RUNTIME_VERSION"` Packages []ProcedurePackage `ddl:"parameter,parentheses" sql:"PACKAGES"` Imports []ProcedureImport `ddl:"parameter,parentheses" sql:"IMPORTS"` Handler string `ddl:"parameter,single_quotes" sql:"HANDLER"` - NullInputBehavior *NullInputBehavior `ddl:"keyword"` ProcedureDefinition *string `ddl:"parameter,single_quotes,no_equals" sql:"AS"` WithClauses []ProcedureWithClause `ddl:"keyword"` call bool `ddl:"static" sql:"CALL"` @@ -344,11 +381,11 @@ type CreateAndCallForPythonProcedureOptions struct { Arguments []ProcedureArgument `ddl:"list,must_parentheses"` Returns ProcedureReturns `ddl:"keyword" sql:"RETURNS"` languagePython bool `ddl:"static" sql:"LANGUAGE PYTHON"` + NullInputBehavior *NullInputBehavior `ddl:"keyword"` RuntimeVersion string `ddl:"parameter,single_quotes" sql:"RUNTIME_VERSION"` Packages []ProcedurePackage `ddl:"parameter,parentheses" sql:"PACKAGES"` Imports []ProcedureImport `ddl:"parameter,parentheses" sql:"IMPORTS"` Handler string `ddl:"parameter,single_quotes" sql:"HANDLER"` - NullInputBehavior *NullInputBehavior `ddl:"keyword"` ProcedureDefinition *string `ddl:"parameter,single_quotes,no_equals" sql:"AS"` WithClauses []ProcedureWithClause `ddl:"keyword"` call bool `ddl:"static" sql:"CALL"` diff --git a/pkg/sdk/procedures_gen_test.go b/pkg/sdk/procedures_gen_test.go index 12a3d030c4..f7e84503d2 100644 --- a/pkg/sdk/procedures_gen_test.go +++ b/pkg/sdk/procedures_gen_test.go @@ -27,12 +27,6 @@ func TestProcedures_CreateForJava(t *testing.T) { assertOptsInvalidJoinedErrors(t, opts, ErrNilOptions) }) - t.Run("validation: incorrect identifier", func(t *testing.T) { - opts := defaultOpts() - opts.name = emptySchemaObjectIdentifier - assertOptsInvalidJoinedErrors(t, opts, ErrInvalidObjectIdentifier) - }) - t.Run("validation: [opts.RuntimeVersion] should be set", func(t *testing.T) { opts := defaultOpts() opts.RuntimeVersion = "" @@ -51,6 +45,12 @@ func TestProcedures_CreateForJava(t *testing.T) { assertOptsInvalidJoinedErrors(t, opts, errNotSet("CreateForJavaProcedureOptions", "Handler")) }) + t.Run("validation: valid identifier for [opts.name]", func(t *testing.T) { + opts := defaultOpts() + opts.name = emptySchemaObjectIdentifier + assertOptsInvalidJoinedErrors(t, opts, ErrInvalidObjectIdentifier) + }) + t.Run("validation: exactly one field from [opts.Arguments.ArgDataTypeOld opts.Arguments.ArgDataType] should be present", func(t *testing.T) { opts := defaultOpts() opts.Arguments = []ProcedureArgument{ @@ -84,6 +84,12 @@ func TestProcedures_CreateForJava(t *testing.T) { assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("CreateAndCallForSQLProcedureOptions.Returns.ResultDataType", "ResultDataTypeOld", "ResultDataType")) }) + t.Run("validation: exactly one field from [opts.Returns.ResultDataType opts.Returns.Table] should be present", func(t *testing.T) { + opts := defaultOpts() + opts.Returns = ProcedureReturns{} + assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("CreateForJavaProcedureOptions.Returns", "ResultDataType", "Table")) + }) + t.Run("validation: exactly one field from [opts.Returns.ResultDataType.ResultDataTypeOld opts.Returns.ResultDataType.ResultDataType] should be present - two present", func(t *testing.T) { opts := defaultOpts() opts.Returns = ProcedureReturns{ @@ -132,13 +138,7 @@ func TestProcedures_CreateForJava(t *testing.T) { assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("CreateAndCallForSQLProcedureOptions.Returns.Table.Columns", "ColumnDataTypeOld", "ColumnDataType")) }) - t.Run("validation: exactly one field from [opts.Returns.ResultDataType opts.Returns.Table] should be present", func(t *testing.T) { - opts := defaultOpts() - opts.Returns = ProcedureReturns{} - assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("CreateForJavaProcedureOptions.Returns", "ResultDataType", "Table")) - }) - - t.Run("validation: function definition", func(t *testing.T) { + t.Run("validation: procedure definition", func(t *testing.T) { opts := defaultOpts() opts.TargetPath = String("@~/testfunc.jar") opts.Packages = []ProcedurePackage{ @@ -203,10 +203,11 @@ func TestProcedures_CreateForJava(t *testing.T) { } opts.TargetPath = String("@~/testfunc.jar") opts.NullInputBehavior = NullInputBehaviorPointer(NullInputBehaviorStrict) + opts.ReturnResultsBehavior = Pointer(ReturnResultsBehaviorImmutable) opts.Comment = String("test comment") opts.ExecuteAs = ExecuteAsPointer(ExecuteAsCaller) opts.ProcedureDefinition = String("return id + name;") - assertOptsValidAndSQLEquals(t, opts, `CREATE OR REPLACE SECURE PROCEDURE %s (id NUMBER, name VARCHAR DEFAULT 'test') COPY GRANTS RETURNS TABLE (country_code VARCHAR) LANGUAGE JAVA RUNTIME_VERSION = '1.8' PACKAGES = ('com.snowflake:snowpark:1.2.0') IMPORTS = ('test_jar.jar') HANDLER = 'TestFunc.echoVarchar' EXTERNAL_ACCESS_INTEGRATIONS = ("ext_integration") SECRETS = ('variable1' = %s, 'variable2' = %s) TARGET_PATH = '@~/testfunc.jar' STRICT COMMENT = 'test comment' EXECUTE AS CALLER AS 'return id + name;'`, id.FullyQualifiedName(), secretId.FullyQualifiedName(), secretId2.FullyQualifiedName()) + assertOptsValidAndSQLEquals(t, opts, `CREATE OR REPLACE SECURE PROCEDURE %s ("id" NUMBER, "name" VARCHAR DEFAULT 'test') COPY GRANTS RETURNS TABLE ("country_code" VARCHAR) LANGUAGE JAVA STRICT IMMUTABLE RUNTIME_VERSION = '1.8' PACKAGES = ('com.snowflake:snowpark:1.2.0') IMPORTS = ('test_jar.jar') HANDLER = 'TestFunc.echoVarchar' EXTERNAL_ACCESS_INTEGRATIONS = ("ext_integration") SECRETS = ('variable1' = %s, 'variable2' = %s) TARGET_PATH = '@~/testfunc.jar' COMMENT = 'test comment' EXECUTE AS CALLER AS return id + name;`, id.FullyQualifiedName(), secretId.FullyQualifiedName(), secretId2.FullyQualifiedName()) }) t.Run("all options", func(t *testing.T) { @@ -262,10 +263,11 @@ func TestProcedures_CreateForJava(t *testing.T) { } opts.TargetPath = String("@~/testfunc.jar") opts.NullInputBehavior = NullInputBehaviorPointer(NullInputBehaviorStrict) + opts.ReturnResultsBehavior = Pointer(ReturnResultsBehaviorImmutable) opts.Comment = String("test comment") opts.ExecuteAs = ExecuteAsPointer(ExecuteAsCaller) opts.ProcedureDefinition = String("return id + name;") - assertOptsValidAndSQLEquals(t, opts, `CREATE OR REPLACE SECURE PROCEDURE %s (id NUMBER(36, 2), name VARCHAR(100) DEFAULT 'test') COPY GRANTS RETURNS TABLE (country_code VARCHAR(100)) LANGUAGE JAVA RUNTIME_VERSION = '1.8' PACKAGES = ('com.snowflake:snowpark:1.2.0') IMPORTS = ('test_jar.jar') HANDLER = 'TestFunc.echoVarchar' EXTERNAL_ACCESS_INTEGRATIONS = ("ext_integration") SECRETS = ('variable1' = %s, 'variable2' = %s) TARGET_PATH = '@~/testfunc.jar' STRICT COMMENT = 'test comment' EXECUTE AS CALLER AS 'return id + name;'`, id.FullyQualifiedName(), secretId.FullyQualifiedName(), secretId2.FullyQualifiedName()) + assertOptsValidAndSQLEquals(t, opts, `CREATE OR REPLACE SECURE PROCEDURE %s ("id" NUMBER(36, 2), "name" VARCHAR(100) DEFAULT 'test') COPY GRANTS RETURNS TABLE ("country_code" VARCHAR(100)) LANGUAGE JAVA STRICT IMMUTABLE RUNTIME_VERSION = '1.8' PACKAGES = ('com.snowflake:snowpark:1.2.0') IMPORTS = ('test_jar.jar') HANDLER = 'TestFunc.echoVarchar' EXTERNAL_ACCESS_INTEGRATIONS = ("ext_integration") SECRETS = ('variable1' = %s, 'variable2' = %s) TARGET_PATH = '@~/testfunc.jar' COMMENT = 'test comment' EXECUTE AS CALLER AS return id + name;`, id.FullyQualifiedName(), secretId.FullyQualifiedName(), secretId2.FullyQualifiedName()) }) } @@ -290,6 +292,12 @@ func TestProcedures_CreateForJavaScript(t *testing.T) { assertOptsInvalidJoinedErrors(t, opts, errNotSet("CreateForJavaScriptProcedureOptions", "ProcedureDefinition")) }) + t.Run("validation: valid identifier for [opts.name]", func(t *testing.T) { + opts := defaultOpts() + opts.name = emptySchemaObjectIdentifier + assertOptsInvalidJoinedErrors(t, opts, ErrInvalidObjectIdentifier) + }) + t.Run("validation: exactly one field from [opts.ResultDataTypeOld opts.ResultDataType] should be present", func(t *testing.T) { opts := defaultOpts() assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("CreateForJavaScriptProcedureOptions", "ResultDataTypeOld", "ResultDataType")) @@ -327,12 +335,6 @@ func TestProcedures_CreateForJavaScript(t *testing.T) { assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("CreateForJavaScriptProcedureOptions.Arguments", "ArgDataTypeOld", "ArgDataType")) }) - t.Run("validation: incorrect identifier", func(t *testing.T) { - opts := defaultOpts() - opts.name = emptySchemaObjectIdentifier - assertOptsInvalidJoinedErrors(t, opts, ErrInvalidObjectIdentifier) - }) - // TODO [SNOW-1348106]: remove with old procedure removal for V1 t.Run("all options - old data types", func(t *testing.T) { opts := defaultOpts() @@ -349,10 +351,11 @@ func TestProcedures_CreateForJavaScript(t *testing.T) { opts.ResultDataTypeOld = "DOUBLE" opts.NotNull = Bool(true) opts.NullInputBehavior = NullInputBehaviorPointer(NullInputBehaviorStrict) + opts.ReturnResultsBehavior = Pointer(ReturnResultsBehaviorImmutable) opts.Comment = String("test comment") opts.ExecuteAs = ExecuteAsPointer(ExecuteAsCaller) opts.ProcedureDefinition = "return 1;" - assertOptsValidAndSQLEquals(t, opts, `CREATE OR REPLACE SECURE PROCEDURE %s (d DOUBLE DEFAULT 1.0) COPY GRANTS RETURNS DOUBLE NOT NULL LANGUAGE JAVASCRIPT STRICT COMMENT = 'test comment' EXECUTE AS CALLER AS 'return 1;'`, id.FullyQualifiedName()) + assertOptsValidAndSQLEquals(t, opts, `CREATE OR REPLACE SECURE PROCEDURE %s ("d" DOUBLE DEFAULT 1.0) COPY GRANTS RETURNS DOUBLE NOT NULL LANGUAGE JAVASCRIPT STRICT IMMUTABLE COMMENT = 'test comment' EXECUTE AS CALLER AS return 1;`, id.FullyQualifiedName()) }) t.Run("all options", func(t *testing.T) { @@ -370,10 +373,11 @@ func TestProcedures_CreateForJavaScript(t *testing.T) { opts.ResultDataType = dataTypeFloat opts.NotNull = Bool(true) opts.NullInputBehavior = NullInputBehaviorPointer(NullInputBehaviorStrict) + opts.ReturnResultsBehavior = Pointer(ReturnResultsBehaviorImmutable) opts.Comment = String("test comment") opts.ExecuteAs = ExecuteAsPointer(ExecuteAsCaller) opts.ProcedureDefinition = "return 1;" - assertOptsValidAndSQLEquals(t, opts, `CREATE OR REPLACE SECURE PROCEDURE %s (d FLOAT DEFAULT 1.0) COPY GRANTS RETURNS FLOAT NOT NULL LANGUAGE JAVASCRIPT STRICT COMMENT = 'test comment' EXECUTE AS CALLER AS 'return 1;'`, id.FullyQualifiedName()) + assertOptsValidAndSQLEquals(t, opts, `CREATE OR REPLACE SECURE PROCEDURE %s ("d" FLOAT DEFAULT 1.0) COPY GRANTS RETURNS FLOAT NOT NULL LANGUAGE JAVASCRIPT STRICT IMMUTABLE COMMENT = 'test comment' EXECUTE AS CALLER AS return 1;`, id.FullyQualifiedName()) }) } @@ -418,7 +422,7 @@ func TestProcedures_CreateForPython(t *testing.T) { assertOptsInvalidJoinedErrors(t, opts, errNotSet("CreateForPythonProcedureOptions", "Handler")) }) - t.Run("validation: incorrect identifier", func(t *testing.T) { + t.Run("validation: valid identifier for [opts.name]", func(t *testing.T) { opts := defaultOpts() opts.name = emptySchemaObjectIdentifier assertOptsInvalidJoinedErrors(t, opts, ErrInvalidObjectIdentifier) @@ -449,6 +453,21 @@ func TestProcedures_CreateForPython(t *testing.T) { assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("CreateForPythonProcedureOptions.Arguments", "ArgDataTypeOld", "ArgDataType")) }) + t.Run("validation: exactly one field from [opts.Returns.ResultDataType opts.Returns.Table] should be present", func(t *testing.T) { + opts := defaultOpts() + opts.Returns = ProcedureReturns{} + assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("CreateForPythonProcedureOptions.Returns", "ResultDataType", "Table")) + }) + + t.Run("validation: exactly one field from [opts.Returns.ResultDataType opts.Returns.Table] should be present - two present", func(t *testing.T) { + opts := defaultOpts() + opts.Returns = ProcedureReturns{ + ResultDataType: &ProcedureReturnsResultDataType{}, + Table: &ProcedureReturnsTable{}, + } + assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("CreateForPythonProcedureOptions.Returns", "ResultDataType", "Table")) + }) + t.Run("validation: exactly one field from [opts.Returns.ResultDataType.ResultDataTypeOld opts.Returns.ResultDataType.ResultDataType] should be present", func(t *testing.T) { opts := defaultOpts() opts.Returns = ProcedureReturns{ @@ -505,12 +524,6 @@ func TestProcedures_CreateForPython(t *testing.T) { assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("CreateAndCallForSQLProcedureOptions.Returns.Table.Columns", "ColumnDataTypeOld", "ColumnDataType")) }) - t.Run("validation: exactly one field from [opts.Returns.ResultDataType opts.Returns.Table] should be present", func(t *testing.T) { - opts := defaultOpts() - opts.Returns = ProcedureReturns{} - assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("CreateForPythonProcedureOptions.Returns", "ResultDataType", "Table")) - }) - // TODO [SNOW-1348106]: remove with old procedure removal for V1 t.Run("all options - old data types", func(t *testing.T) { opts := defaultOpts() @@ -562,10 +575,11 @@ func TestProcedures_CreateForPython(t *testing.T) { }, } opts.NullInputBehavior = NullInputBehaviorPointer(NullInputBehaviorStrict) + opts.ReturnResultsBehavior = Pointer(ReturnResultsBehaviorImmutable) opts.Comment = String("test comment") opts.ExecuteAs = ExecuteAsPointer(ExecuteAsCaller) opts.ProcedureDefinition = String("import numpy as np") - assertOptsValidAndSQLEquals(t, opts, `CREATE OR REPLACE SECURE PROCEDURE %s (i int DEFAULT 1) COPY GRANTS RETURNS VARIANT NULL LANGUAGE PYTHON RUNTIME_VERSION = '3.8' PACKAGES = ('numpy', 'pandas') IMPORTS = ('numpy', 'pandas') HANDLER = 'udf' EXTERNAL_ACCESS_INTEGRATIONS = ("ext_integration") SECRETS = ('variable1' = %s, 'variable2' = %s) STRICT COMMENT = 'test comment' EXECUTE AS CALLER AS 'import numpy as np'`, id.FullyQualifiedName(), secretId.FullyQualifiedName(), secretId2.FullyQualifiedName()) + assertOptsValidAndSQLEquals(t, opts, `CREATE OR REPLACE SECURE PROCEDURE %s ("i" int DEFAULT 1) COPY GRANTS RETURNS VARIANT NULL LANGUAGE PYTHON STRICT IMMUTABLE RUNTIME_VERSION = '3.8' PACKAGES = ('numpy', 'pandas') IMPORTS = ('numpy', 'pandas') HANDLER = 'udf' EXTERNAL_ACCESS_INTEGRATIONS = ("ext_integration") SECRETS = ('variable1' = %s, 'variable2' = %s) COMMENT = 'test comment' EXECUTE AS CALLER AS import numpy as np`, id.FullyQualifiedName(), secretId.FullyQualifiedName(), secretId2.FullyQualifiedName()) }) t.Run("all options", func(t *testing.T) { @@ -618,10 +632,11 @@ func TestProcedures_CreateForPython(t *testing.T) { }, } opts.NullInputBehavior = NullInputBehaviorPointer(NullInputBehaviorStrict) + opts.ReturnResultsBehavior = Pointer(ReturnResultsBehaviorImmutable) opts.Comment = String("test comment") opts.ExecuteAs = ExecuteAsPointer(ExecuteAsCaller) opts.ProcedureDefinition = String("import numpy as np") - assertOptsValidAndSQLEquals(t, opts, `CREATE OR REPLACE SECURE PROCEDURE %s (i NUMBER(36, 2) DEFAULT 1) COPY GRANTS RETURNS VARIANT NULL LANGUAGE PYTHON RUNTIME_VERSION = '3.8' PACKAGES = ('numpy', 'pandas') IMPORTS = ('numpy', 'pandas') HANDLER = 'udf' EXTERNAL_ACCESS_INTEGRATIONS = ("ext_integration") SECRETS = ('variable1' = %s, 'variable2' = %s) STRICT COMMENT = 'test comment' EXECUTE AS CALLER AS 'import numpy as np'`, id.FullyQualifiedName(), secretId.FullyQualifiedName(), secretId2.FullyQualifiedName()) + assertOptsValidAndSQLEquals(t, opts, `CREATE OR REPLACE SECURE PROCEDURE %s ("i" NUMBER(36, 2) DEFAULT 1) COPY GRANTS RETURNS VARIANT NULL LANGUAGE PYTHON STRICT IMMUTABLE RUNTIME_VERSION = '3.8' PACKAGES = ('numpy', 'pandas') IMPORTS = ('numpy', 'pandas') HANDLER = 'udf' EXTERNAL_ACCESS_INTEGRATIONS = ("ext_integration") SECRETS = ('variable1' = %s, 'variable2' = %s) COMMENT = 'test comment' EXECUTE AS CALLER AS import numpy as np`, id.FullyQualifiedName(), secretId.FullyQualifiedName(), secretId2.FullyQualifiedName()) }) } @@ -664,7 +679,7 @@ func TestProcedures_CreateForScala(t *testing.T) { assertOptsInvalidJoinedErrors(t, opts, errNotSet("CreateForScalaProcedureOptions", "Handler")) }) - t.Run("validation: incorrect identifier", func(t *testing.T) { + t.Run("validation: valid identifier for [opts.name]", func(t *testing.T) { opts := defaultOpts() opts.name = emptySchemaObjectIdentifier assertOptsInvalidJoinedErrors(t, opts, ErrInvalidObjectIdentifier) @@ -695,6 +710,21 @@ func TestProcedures_CreateForScala(t *testing.T) { assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("CreateForScalaProcedureOptions.Arguments", "ArgDataTypeOld", "ArgDataType")) }) + t.Run("validation: exactly one field from [opts.Returns.ResultDataType opts.Returns.Table] should be present", func(t *testing.T) { + opts := defaultOpts() + opts.Returns = ProcedureReturns{} + assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("CreateForScalaProcedureOptions.Returns", "ResultDataType", "Table")) + }) + + t.Run("validation: exactly one field from [opts.Returns.ResultDataType opts.Returns.Table] should be present - two present", func(t *testing.T) { + opts := defaultOpts() + opts.Returns = ProcedureReturns{ + ResultDataType: &ProcedureReturnsResultDataType{}, + Table: &ProcedureReturnsTable{}, + } + assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("CreateForScalaProcedureOptions.Returns", "ResultDataType", "Table")) + }) + t.Run("validation: exactly one field from [opts.Returns.ResultDataType.ResultDataTypeOld opts.Returns.ResultDataType.ResultDataType] should be present", func(t *testing.T) { opts := defaultOpts() opts.Returns = ProcedureReturns{ @@ -751,13 +781,7 @@ func TestProcedures_CreateForScala(t *testing.T) { assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("CreateAndCallForSQLProcedureOptions.Returns.Table.Columns", "ColumnDataTypeOld", "ColumnDataType")) }) - t.Run("validation: exactly one field from [opts.Returns.ResultDataType opts.Returns.Table] should be present", func(t *testing.T) { - opts := defaultOpts() - opts.Returns = ProcedureReturns{} - assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("CreateForScalaProcedureOptions.Returns", "ResultDataType", "Table")) - }) - - t.Run("validation: function definition", func(t *testing.T) { + t.Run("validation: procedure definition", func(t *testing.T) { opts := defaultOpts() opts.TargetPath = String("@~/testfunc.jar") opts.Packages = []ProcedurePackage{ @@ -801,10 +825,11 @@ func TestProcedures_CreateForScala(t *testing.T) { opts.Handler = "Echo.echoVarchar" opts.TargetPath = String("@~/testfunc.jar") opts.NullInputBehavior = NullInputBehaviorPointer(NullInputBehaviorStrict) + opts.ReturnResultsBehavior = Pointer(ReturnResultsBehaviorImmutable) opts.Comment = String("test comment") opts.ExecuteAs = ExecuteAsPointer(ExecuteAsCaller) opts.ProcedureDefinition = String("return x") - assertOptsValidAndSQLEquals(t, opts, `CREATE OR REPLACE SECURE PROCEDURE %s (x VARCHAR DEFAULT 'test') COPY GRANTS RETURNS VARCHAR NOT NULL LANGUAGE SCALA RUNTIME_VERSION = '2.0' PACKAGES = ('com.snowflake:snowpark:1.2.0') IMPORTS = ('@udf_libs/echohandler.jar') HANDLER = 'Echo.echoVarchar' TARGET_PATH = '@~/testfunc.jar' STRICT COMMENT = 'test comment' EXECUTE AS CALLER AS 'return x'`, id.FullyQualifiedName()) + assertOptsValidAndSQLEquals(t, opts, `CREATE OR REPLACE SECURE PROCEDURE %s ("x" VARCHAR DEFAULT 'test') COPY GRANTS RETURNS VARCHAR NOT NULL LANGUAGE SCALA STRICT IMMUTABLE RUNTIME_VERSION = '2.0' PACKAGES = ('com.snowflake:snowpark:1.2.0') IMPORTS = ('@udf_libs/echohandler.jar') HANDLER = 'Echo.echoVarchar' TARGET_PATH = '@~/testfunc.jar' COMMENT = 'test comment' EXECUTE AS CALLER AS return x`, id.FullyQualifiedName()) }) t.Run("all options", func(t *testing.T) { @@ -839,10 +864,11 @@ func TestProcedures_CreateForScala(t *testing.T) { opts.Handler = "Echo.echoVarchar" opts.TargetPath = String("@~/testfunc.jar") opts.NullInputBehavior = NullInputBehaviorPointer(NullInputBehaviorStrict) + opts.ReturnResultsBehavior = Pointer(ReturnResultsBehaviorImmutable) opts.Comment = String("test comment") opts.ExecuteAs = ExecuteAsPointer(ExecuteAsCaller) opts.ProcedureDefinition = String("return x") - assertOptsValidAndSQLEquals(t, opts, `CREATE OR REPLACE SECURE PROCEDURE %s (x VARCHAR(100) DEFAULT 'test') COPY GRANTS RETURNS VARCHAR(100) NOT NULL LANGUAGE SCALA RUNTIME_VERSION = '2.0' PACKAGES = ('com.snowflake:snowpark:1.2.0') IMPORTS = ('@udf_libs/echohandler.jar') HANDLER = 'Echo.echoVarchar' TARGET_PATH = '@~/testfunc.jar' STRICT COMMENT = 'test comment' EXECUTE AS CALLER AS 'return x'`, id.FullyQualifiedName()) + assertOptsValidAndSQLEquals(t, opts, `CREATE OR REPLACE SECURE PROCEDURE %s ("x" VARCHAR(100) DEFAULT 'test') COPY GRANTS RETURNS VARCHAR(100) NOT NULL LANGUAGE SCALA STRICT IMMUTABLE RUNTIME_VERSION = '2.0' PACKAGES = ('com.snowflake:snowpark:1.2.0') IMPORTS = ('@udf_libs/echohandler.jar') HANDLER = 'Echo.echoVarchar' TARGET_PATH = '@~/testfunc.jar' COMMENT = 'test comment' EXECUTE AS CALLER AS return x`, id.FullyQualifiedName()) }) } @@ -872,23 +898,12 @@ func TestProcedures_CreateForSQL(t *testing.T) { assertOptsInvalidJoinedErrors(t, opts, errNotSet("CreateForSQLProcedureOptions", "ProcedureDefinition")) }) - t.Run("validation: incorrect identifier", func(t *testing.T) { + t.Run("validation: valid identifier for [opts.name]", func(t *testing.T) { opts := defaultOpts() opts.name = emptySchemaObjectIdentifier assertOptsInvalidJoinedErrors(t, opts, ErrInvalidObjectIdentifier) }) - t.Run("create with no arguments", func(t *testing.T) { - opts := defaultOpts() - opts.Returns = ProcedureSQLReturns{ - ResultDataType: &ProcedureReturnsResultDataType{ - ResultDataType: dataTypeFloat, - }, - } - opts.ProcedureDefinition = "3.141592654::FLOAT" - assertOptsValidAndSQLEquals(t, opts, `CREATE PROCEDURE %s () RETURNS FLOAT LANGUAGE SQL AS '3.141592654::FLOAT'`, id.FullyQualifiedName()) - }) - t.Run("validation: exactly one field from [opts.Arguments.ArgDataTypeOld opts.Arguments.ArgDataType] should be present", func(t *testing.T) { opts := defaultOpts() opts.Arguments = []ProcedureArgument{ @@ -914,6 +929,21 @@ func TestProcedures_CreateForSQL(t *testing.T) { assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("CreateForSQLProcedureOptions.Arguments", "ArgDataTypeOld", "ArgDataType")) }) + t.Run("validation: exactly one field from [opts.Returns.ResultDataType opts.Returns.Table] should be present", func(t *testing.T) { + opts := defaultOpts() + opts.Returns = ProcedureSQLReturns{} + assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("CreateForSQLProcedureOptions.Returns", "ResultDataType", "Table")) + }) + + t.Run("validation: exactly one field from [opts.Returns.ResultDataType opts.Returns.Table] should be present - two present", func(t *testing.T) { + opts := defaultOpts() + opts.Returns = ProcedureSQLReturns{ + ResultDataType: &ProcedureReturnsResultDataType{}, + Table: &ProcedureReturnsTable{}, + } + assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("CreateForSQLProcedureOptions.Returns", "ResultDataType", "Table")) + }) + t.Run("validation: exactly one field from [opts.Returns.ResultDataType.ResultDataTypeOld opts.Returns.ResultDataType.ResultDataType] should be present", func(t *testing.T) { opts := defaultOpts() opts.Returns = ProcedureSQLReturns{ @@ -970,12 +1000,6 @@ func TestProcedures_CreateForSQL(t *testing.T) { assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("CreateForSQLProcedureOptions.Returns.Table.Columns", "ColumnDataTypeOld", "ColumnDataType")) }) - t.Run("validation: exactly one field from [opts.Returns.ResultDataType opts.Returns.Table] should be present", func(t *testing.T) { - opts := defaultOpts() - opts.Returns = ProcedureSQLReturns{} - assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("CreateForSQLProcedureOptions.Returns", "ResultDataType", "Table")) - }) - // TODO [SNOW-1348106]: remove with old procedure removal for V1 t.Run("all options - old data types", func(t *testing.T) { opts := defaultOpts() @@ -996,10 +1020,11 @@ func TestProcedures_CreateForSQL(t *testing.T) { NotNull: Bool(true), } opts.NullInputBehavior = NullInputBehaviorPointer(NullInputBehaviorStrict) + opts.ReturnResultsBehavior = Pointer(ReturnResultsBehaviorImmutable) opts.Comment = String("test comment") opts.ExecuteAs = ExecuteAsPointer(ExecuteAsCaller) opts.ProcedureDefinition = "3.141592654::FLOAT" - assertOptsValidAndSQLEquals(t, opts, `CREATE OR REPLACE SECURE PROCEDURE %s (message VARCHAR DEFAULT 'test') COPY GRANTS RETURNS VARCHAR NOT NULL LANGUAGE SQL STRICT COMMENT = 'test comment' EXECUTE AS CALLER AS '3.141592654::FLOAT'`, id.FullyQualifiedName()) + assertOptsValidAndSQLEquals(t, opts, `CREATE OR REPLACE SECURE PROCEDURE %s ("message" VARCHAR DEFAULT 'test') COPY GRANTS RETURNS VARCHAR NOT NULL LANGUAGE SQL STRICT IMMUTABLE COMMENT = 'test comment' EXECUTE AS CALLER AS 3.141592654::FLOAT`, id.FullyQualifiedName()) }) t.Run("all options", func(t *testing.T) { @@ -1021,10 +1046,22 @@ func TestProcedures_CreateForSQL(t *testing.T) { NotNull: Bool(true), } opts.NullInputBehavior = NullInputBehaviorPointer(NullInputBehaviorStrict) + opts.ReturnResultsBehavior = Pointer(ReturnResultsBehaviorImmutable) opts.Comment = String("test comment") opts.ExecuteAs = ExecuteAsPointer(ExecuteAsCaller) opts.ProcedureDefinition = "3.141592654::FLOAT" - assertOptsValidAndSQLEquals(t, opts, `CREATE OR REPLACE SECURE PROCEDURE %s (message VARCHAR(100) DEFAULT 'test') COPY GRANTS RETURNS VARCHAR(100) NOT NULL LANGUAGE SQL STRICT COMMENT = 'test comment' EXECUTE AS CALLER AS '3.141592654::FLOAT'`, id.FullyQualifiedName()) + assertOptsValidAndSQLEquals(t, opts, `CREATE OR REPLACE SECURE PROCEDURE %s ("message" VARCHAR(100) DEFAULT 'test') COPY GRANTS RETURNS VARCHAR(100) NOT NULL LANGUAGE SQL STRICT IMMUTABLE COMMENT = 'test comment' EXECUTE AS CALLER AS 3.141592654::FLOAT`, id.FullyQualifiedName()) + }) + + t.Run("create with no arguments", func(t *testing.T) { + opts := defaultOpts() + opts.Returns = ProcedureSQLReturns{ + ResultDataType: &ProcedureReturnsResultDataType{ + ResultDataType: dataTypeFloat, + }, + } + opts.ProcedureDefinition = "3.141592654::FLOAT" + assertOptsValidAndSQLEquals(t, opts, `CREATE PROCEDURE %s () RETURNS FLOAT LANGUAGE SQL AS 3.141592654::FLOAT`, id.FullyQualifiedName()) }) } @@ -1042,7 +1079,7 @@ func TestProcedures_Drop(t *testing.T) { assertOptsInvalidJoinedErrors(t, opts, ErrNilOptions) }) - t.Run("validation: incorrect identifier", func(t *testing.T) { + t.Run("validation: valid identifier for [opts.name]", func(t *testing.T) { opts := defaultOpts() opts.name = emptySchemaObjectIdentifierWithArguments assertOptsInvalidJoinedErrors(t, opts, ErrInvalidObjectIdentifier) @@ -1062,8 +1099,8 @@ func TestProcedures_Drop(t *testing.T) { } func TestProcedures_Alter(t *testing.T) { - noArgsId := randomSchemaObjectIdentifierWithArguments() id := randomSchemaObjectIdentifierWithArguments(DataTypeVARCHAR, DataTypeNumber) + secretId := randomSchemaObjectIdentifier() defaultOpts := func() *AlterProcedureOptions { return &AlterProcedureOptions{ @@ -1077,17 +1114,40 @@ func TestProcedures_Alter(t *testing.T) { assertOptsInvalidJoinedErrors(t, opts, ErrNilOptions) }) - t.Run("validation: incorrect identifier", func(t *testing.T) { + t.Run("validation: valid identifier for [opts.name]", func(t *testing.T) { opts := defaultOpts() opts.name = emptySchemaObjectIdentifierWithArguments assertOptsInvalidJoinedErrors(t, opts, ErrInvalidObjectIdentifier) }) - t.Run("validation: exactly one field should be present", func(t *testing.T) { + t.Run("validation: valid identifier for [opts.RenameTo] if set", func(t *testing.T) { opts := defaultOpts() - opts.SetLogLevel = String("DEBUG") - opts.UnsetComment = Bool(true) - assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("AlterProcedureOptions", "RenameTo", "SetComment", "SetLogLevel", "SetTraceLevel", "UnsetComment", "SetTags", "UnsetTags", "ExecuteAs")) + opts.RenameTo = Pointer(emptySchemaObjectIdentifier) + assertOptsInvalidJoinedErrors(t, opts, ErrInvalidObjectIdentifier) + }) + + t.Run("validation: exactly one field from [opts.RenameTo opts.Set opts.Unset opts.SetTags opts.UnsetTags opts.ExecuteAs] should be present", func(t *testing.T) { + opts := defaultOpts() + assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("AlterProcedureOptions", "RenameTo", "Set", "Unset", "SetTags", "UnsetTags", "ExecuteAs")) + }) + + t.Run("validation: exactly one field from [opts.RenameTo opts.Set opts.Unset opts.SetTags opts.UnsetTags opts.ExecuteAs] should be present - two present", func(t *testing.T) { + opts := defaultOpts() + opts.Set = &ProcedureSet{} + opts.Unset = &ProcedureUnset{} + assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("AlterProcedureOptions", "RenameTo", "Set", "Unset", "SetTags", "UnsetTags", "ExecuteAs")) + }) + + t.Run("validation: at least one of the fields [opts.Set.Comment opts.Set.ExternalAccessIntegrations opts.Set.SecretsList opts.Set.AutoEventLogging opts.Set.EnableConsoleOutput opts.Set.LogLevel opts.Set.MetricLevel opts.Set.TraceLevel] should be set", func(t *testing.T) { + opts := defaultOpts() + opts.Set = &ProcedureSet{} + assertOptsInvalidJoinedErrors(t, opts, errAtLeastOneOf("AlterProcedureOptions.Set", "Comment", "ExternalAccessIntegrations", "SecretsList", "AutoEventLogging", "EnableConsoleOutput", "LogLevel", "MetricLevel", "TraceLevel")) + }) + + t.Run("validation: at least one of the fields [opts.Unset.Comment opts.Unset.ExternalAccessIntegrations opts.Unset.AutoEventLogging opts.Unset.EnableConsoleOutput opts.Unset.LogLevel opts.Unset.MetricLevel opts.Unset.TraceLevel] should be set", func(t *testing.T) { + opts := defaultOpts() + opts.Unset = &ProcedureUnset{} + assertOptsInvalidJoinedErrors(t, opts, errAtLeastOneOf("AlterProcedureOptions.Unset", "Comment", "ExternalAccessIntegrations", "AutoEventLogging", "EnableConsoleOutput", "LogLevel", "MetricLevel", "TraceLevel")) }) t.Run("alter: rename to", func(t *testing.T) { @@ -1104,35 +1164,42 @@ func TestProcedures_Alter(t *testing.T) { assertOptsValidAndSQLEquals(t, opts, `ALTER PROCEDURE IF EXISTS %s EXECUTE AS CALLER`, id.FullyQualifiedName()) }) - t.Run("alter: set log level", func(t *testing.T) { + t.Run("alter: set", func(t *testing.T) { opts := defaultOpts() - opts.SetLogLevel = String("DEBUG") - assertOptsValidAndSQLEquals(t, opts, `ALTER PROCEDURE IF EXISTS %s SET LOG_LEVEL = 'DEBUG'`, id.FullyQualifiedName()) - }) - - t.Run("alter: set log level with no arguments", func(t *testing.T) { - opts := defaultOpts() - opts.name = noArgsId - opts.SetLogLevel = String("DEBUG") - assertOptsValidAndSQLEquals(t, opts, `ALTER PROCEDURE IF EXISTS %s SET LOG_LEVEL = 'DEBUG'`, noArgsId.FullyQualifiedName()) + opts.Set = &ProcedureSet{ + Comment: String("comment"), + TraceLevel: Pointer(TraceLevelOff), + } + assertOptsValidAndSQLEquals(t, opts, `ALTER PROCEDURE IF EXISTS %s SET COMMENT = 'comment', TRACE_LEVEL = 'OFF'`, id.FullyQualifiedName()) }) - t.Run("alter: set trace level", func(t *testing.T) { + t.Run("alter: set empty secrets", func(t *testing.T) { opts := defaultOpts() - opts.SetTraceLevel = String("DEBUG") - assertOptsValidAndSQLEquals(t, opts, `ALTER PROCEDURE IF EXISTS %s SET TRACE_LEVEL = 'DEBUG'`, id.FullyQualifiedName()) + opts.Set = &ProcedureSet{ + SecretsList: &SecretsList{}, + } + assertOptsValidAndSQLEquals(t, opts, `ALTER PROCEDURE IF EXISTS %s SET SECRETS = ()`, id.FullyQualifiedName()) }) - t.Run("alter: set comment", func(t *testing.T) { + t.Run("alter: set non-empty secrets", func(t *testing.T) { opts := defaultOpts() - opts.SetComment = String("comment") - assertOptsValidAndSQLEquals(t, opts, `ALTER PROCEDURE IF EXISTS %s SET COMMENT = 'comment'`, id.FullyQualifiedName()) + opts.Set = &ProcedureSet{ + SecretsList: &SecretsList{ + []SecretReference{ + {VariableName: "abc", Name: secretId}, + }, + }, + } + assertOptsValidAndSQLEquals(t, opts, `ALTER PROCEDURE IF EXISTS %s SET SECRETS = ('abc' = %s)`, id.FullyQualifiedName(), secretId.FullyQualifiedName()) }) - t.Run("alter: unset comment", func(t *testing.T) { + t.Run("alter: unset", func(t *testing.T) { opts := defaultOpts() - opts.UnsetComment = Bool(true) - assertOptsValidAndSQLEquals(t, opts, `ALTER PROCEDURE IF EXISTS %s UNSET COMMENT`, id.FullyQualifiedName()) + opts.Unset = &ProcedureUnset{ + Comment: Bool(true), + TraceLevel: Bool(true), + } + assertOptsValidAndSQLEquals(t, opts, `ALTER PROCEDURE IF EXISTS %s UNSET COMMENT, TRACE_LEVEL`, id.FullyQualifiedName()) }) t.Run("alter: set tags", func(t *testing.T) { @@ -1181,15 +1248,16 @@ func TestProcedures_Show(t *testing.T) { t.Run("show with in", func(t *testing.T) { opts := defaultOpts() - opts.In = &In{ - Account: Bool(true), + opts.In = &ExtendedIn{ + In: In{ + Account: Bool(true), + }, } assertOptsValidAndSQLEquals(t, opts, `SHOW PROCEDURES IN ACCOUNT`) }) } func TestProcedures_Describe(t *testing.T) { - noArgsId := randomSchemaObjectIdentifierWithArguments() id := randomSchemaObjectIdentifierWithArguments(DataTypeVARCHAR, DataTypeNumber) defaultOpts := func() *DescribeProcedureOptions { @@ -1203,18 +1271,12 @@ func TestProcedures_Describe(t *testing.T) { assertOptsInvalidJoinedErrors(t, opts, ErrNilOptions) }) - t.Run("validation: incorrect identifier", func(t *testing.T) { + t.Run("validation: valid identifier for [opts.name]", func(t *testing.T) { opts := defaultOpts() opts.name = emptySchemaObjectIdentifierWithArguments assertOptsInvalidJoinedErrors(t, opts, ErrInvalidObjectIdentifier) }) - t.Run("no arguments", func(t *testing.T) { - opts := defaultOpts() - opts.name = noArgsId - assertOptsValidAndSQLEquals(t, opts, `DESCRIBE PROCEDURE %s`, noArgsId.FullyQualifiedName()) - }) - t.Run("all options", func(t *testing.T) { opts := defaultOpts() assertOptsValidAndSQLEquals(t, opts, `DESCRIBE PROCEDURE %s`, id.FullyQualifiedName()) @@ -1235,7 +1297,7 @@ func TestProcedures_Call(t *testing.T) { assertOptsInvalidJoinedErrors(t, opts, ErrNilOptions) }) - t.Run("validation: incorrect identifier", func(t *testing.T) { + t.Run("validation: valid identifier for [opts.name]", func(t *testing.T) { opts := defaultOpts() opts.name = emptySchemaObjectIdentifier assertOptsInvalidJoinedErrors(t, opts, ErrInvalidObjectIdentifier) @@ -1265,7 +1327,14 @@ func TestProcedures_CreateAndCallForJava(t *testing.T) { defaultOpts := func() *CreateAndCallForJavaProcedureOptions { return &CreateAndCallForJavaProcedureOptions{ - Name: id, + Name: id, + Handler: "TestFunc.echoVarchar", + Packages: []ProcedurePackage{ + { + Package: "com.snowflake:snowpark:1.2.0", + }, + }, + RuntimeVersion: "1.8", } } @@ -1274,18 +1343,51 @@ func TestProcedures_CreateAndCallForJava(t *testing.T) { assertOptsInvalidJoinedErrors(t, opts, ErrNilOptions) }) - t.Run("validation: incorrect identifier", func(t *testing.T) { + t.Run("validation: [opts.RuntimeVersion] should be set", func(t *testing.T) { + opts := defaultOpts() + opts.RuntimeVersion = "" + assertOptsInvalidJoinedErrors(t, opts, errNotSet("CreateAndCallForJavaProcedureOptions", "RuntimeVersion")) + }) + + t.Run("validation: [opts.Packages] should be set", func(t *testing.T) { + opts := defaultOpts() + opts.Packages = nil + assertOptsInvalidJoinedErrors(t, opts, errNotSet("CreateAndCallForJavaProcedureOptions", "Packages")) + }) + + t.Run("validation: [opts.Handler] should be set", func(t *testing.T) { + opts := defaultOpts() + opts.Handler = "" + assertOptsInvalidJoinedErrors(t, opts, errNotSet("CreateAndCallForJavaProcedureOptions", "Handler")) + }) + + t.Run("validation: valid identifier for [opts.ProcedureName]", func(t *testing.T) { + opts := defaultOpts() + opts.ProcedureName = emptyAccountObjectIdentifier + assertOptsInvalidJoinedErrors(t, opts, ErrInvalidObjectIdentifier) + }) + + t.Run("validation: valid identifier for [opts.Name]", func(t *testing.T) { opts := defaultOpts() opts.Name = emptyAccountObjectIdentifier assertOptsInvalidJoinedErrors(t, opts, ErrInvalidObjectIdentifier) }) - t.Run("validation: returns", func(t *testing.T) { + t.Run("validation: exactly one field from [opts.Returns.ResultDataType opts.Returns.Table] should be present", func(t *testing.T) { opts := defaultOpts() opts.Returns = ProcedureReturns{} assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("CreateAndCallForJavaProcedureOptions.Returns", "ResultDataType", "Table")) }) + t.Run("validation: exactly one field from [opts.Returns.ResultDataType opts.Returns.Table] should be present - both present", func(t *testing.T) { + opts := defaultOpts() + opts.Returns = ProcedureReturns{ + ResultDataType: &ProcedureReturnsResultDataType{}, + Table: &ProcedureReturnsTable{}, + } + assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("CreateAndCallForJavaProcedureOptions.Returns", "ResultDataType", "Table")) + }) + t.Run("validation: exactly one field should be present", func(t *testing.T) { opts := defaultOpts() opts.Returns = ProcedureReturns{ @@ -1304,18 +1406,6 @@ func TestProcedures_CreateAndCallForJava(t *testing.T) { assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("CreateAndCallForJavaProcedureOptions.Returns", "ResultDataType", "Table")) }) - t.Run("validation: options are missing", func(t *testing.T) { - opts := defaultOpts() - opts.Returns = ProcedureReturns{ - ResultDataType: &ProcedureReturnsResultDataType{ - ResultDataType: dataTypeVarchar, - }, - } - assertOptsInvalidJoinedErrors(t, opts, errNotSet("CreateAndCallForJavaProcedureOptions", "Handler")) - assertOptsInvalidJoinedErrors(t, opts, errNotSet("CreateAndCallForJavaProcedureOptions", "RuntimeVersion")) - assertOptsInvalidJoinedErrors(t, opts, ErrInvalidObjectIdentifier) - }) - t.Run("no arguments", func(t *testing.T) { opts := defaultOpts() opts.Returns = ProcedureReturns{ @@ -1378,7 +1468,7 @@ func TestProcedures_CreateAndCallForJava(t *testing.T) { opts.ProcedureName = id opts.ScriptingVariable = String(":ret") opts.CallArguments = []string{"1", "rnd"} - assertOptsValidAndSQLEquals(t, opts, `WITH %s AS PROCEDURE (id NUMBER, name VARCHAR) RETURNS TABLE (country_code VARCHAR) LANGUAGE JAVA RUNTIME_VERSION = '1.8' PACKAGES = ('com.snowflake:snowpark:1.2.0') IMPORTS = ('test_jar.jar') HANDLER = 'TestFunc.echoVarchar' STRICT AS 'return id + name;' , %s (x, y) AS (select m.album_ID, m.album_name, b.band_name from music_albums) CALL %s (1, rnd) INTO :ret`, id.FullyQualifiedName(), cte.FullyQualifiedName(), id.FullyQualifiedName()) + assertOptsValidAndSQLEquals(t, opts, `WITH %s AS PROCEDURE ("id" NUMBER, "name" VARCHAR) RETURNS TABLE ("country_code" VARCHAR) LANGUAGE JAVA STRICT RUNTIME_VERSION = '1.8' PACKAGES = ('com.snowflake:snowpark:1.2.0') IMPORTS = ('test_jar.jar') HANDLER = 'TestFunc.echoVarchar' AS 'return id + name;' , %s (x, y) AS (select m.album_ID, m.album_name, b.band_name from music_albums) CALL %s (1, rnd) INTO :ret`, id.FullyQualifiedName(), cte.FullyQualifiedName(), id.FullyQualifiedName()) }) t.Run("all options", func(t *testing.T) { @@ -1426,7 +1516,7 @@ func TestProcedures_CreateAndCallForJava(t *testing.T) { opts.ProcedureName = id opts.ScriptingVariable = String(":ret") opts.CallArguments = []string{"1", "rnd"} - assertOptsValidAndSQLEquals(t, opts, `WITH %s AS PROCEDURE (id NUMBER(36, 2), name VARCHAR(100)) RETURNS TABLE (country_code VARCHAR(100)) LANGUAGE JAVA RUNTIME_VERSION = '1.8' PACKAGES = ('com.snowflake:snowpark:1.2.0') IMPORTS = ('test_jar.jar') HANDLER = 'TestFunc.echoVarchar' STRICT AS 'return id + name;' , %s (x, y) AS (select m.album_ID, m.album_name, b.band_name from music_albums) CALL %s (1, rnd) INTO :ret`, id.FullyQualifiedName(), cte.FullyQualifiedName(), id.FullyQualifiedName()) + assertOptsValidAndSQLEquals(t, opts, `WITH %s AS PROCEDURE ("id" NUMBER(36, 2), "name" VARCHAR(100)) RETURNS TABLE ("country_code" VARCHAR(100)) LANGUAGE JAVA STRICT RUNTIME_VERSION = '1.8' PACKAGES = ('com.snowflake:snowpark:1.2.0') IMPORTS = ('test_jar.jar') HANDLER = 'TestFunc.echoVarchar' AS 'return id + name;' , %s (x, y) AS (select m.album_ID, m.album_name, b.band_name from music_albums) CALL %s (1, rnd) INTO :ret`, id.FullyQualifiedName(), cte.FullyQualifiedName(), id.FullyQualifiedName()) }) } @@ -1550,7 +1640,7 @@ func TestProcedures_CreateAndCallForScala(t *testing.T) { opts.ProcedureName = id opts.ScriptingVariable = String(":ret") opts.CallArguments = []string{"1", "rnd"} - assertOptsValidAndSQLEquals(t, opts, `WITH %s AS PROCEDURE (id NUMBER, name VARCHAR) RETURNS TABLE (country_code VARCHAR) LANGUAGE SCALA RUNTIME_VERSION = '2.12' PACKAGES = ('com.snowflake:snowpark:1.2.0') IMPORTS = ('test_jar.jar') HANDLER = 'TestFunc.echoVarchar' STRICT AS 'return id + name;' , %s (x, y) AS (select m.album_ID, m.album_name, b.band_name from music_albums) CALL %s (1, rnd) INTO :ret`, id.FullyQualifiedName(), cte.FullyQualifiedName(), id.FullyQualifiedName()) + assertOptsValidAndSQLEquals(t, opts, `WITH %s AS PROCEDURE ("id" NUMBER, "name" VARCHAR) RETURNS TABLE ("country_code" VARCHAR) LANGUAGE SCALA STRICT RUNTIME_VERSION = '2.12' PACKAGES = ('com.snowflake:snowpark:1.2.0') IMPORTS = ('test_jar.jar') HANDLER = 'TestFunc.echoVarchar' AS 'return id + name;' , %s (x, y) AS (select m.album_ID, m.album_name, b.band_name from music_albums) CALL %s (1, rnd) INTO :ret`, id.FullyQualifiedName(), cte.FullyQualifiedName(), id.FullyQualifiedName()) }) t.Run("all options", func(t *testing.T) { @@ -1600,7 +1690,7 @@ func TestProcedures_CreateAndCallForScala(t *testing.T) { opts.ProcedureName = id opts.ScriptingVariable = String(":ret") opts.CallArguments = []string{"1", "rnd"} - assertOptsValidAndSQLEquals(t, opts, `WITH %s AS PROCEDURE (id NUMBER(36, 2), name VARCHAR(100)) RETURNS TABLE (country_code VARCHAR(100)) LANGUAGE SCALA RUNTIME_VERSION = '2.12' PACKAGES = ('com.snowflake:snowpark:1.2.0') IMPORTS = ('test_jar.jar') HANDLER = 'TestFunc.echoVarchar' STRICT AS 'return id + name;' , %s (x, y) AS (select m.album_ID, m.album_name, b.band_name from music_albums) CALL %s (1, rnd) INTO :ret`, id.FullyQualifiedName(), cte.FullyQualifiedName(), id.FullyQualifiedName()) + assertOptsValidAndSQLEquals(t, opts, `WITH %s AS PROCEDURE ("id" NUMBER(36, 2), "name" VARCHAR(100)) RETURNS TABLE ("country_code" VARCHAR(100)) LANGUAGE SCALA STRICT RUNTIME_VERSION = '2.12' PACKAGES = ('com.snowflake:snowpark:1.2.0') IMPORTS = ('test_jar.jar') HANDLER = 'TestFunc.echoVarchar' AS 'return id + name;' , %s (x, y) AS (select m.album_ID, m.album_name, b.band_name from music_albums) CALL %s (1, rnd) INTO :ret`, id.FullyQualifiedName(), cte.FullyQualifiedName(), id.FullyQualifiedName()) }) } @@ -1723,7 +1813,7 @@ func TestProcedures_CreateAndCallForPython(t *testing.T) { opts.ProcedureName = id opts.ScriptingVariable = String(":ret") opts.CallArguments = []string{"1"} - assertOptsValidAndSQLEquals(t, opts, `WITH %s AS PROCEDURE (i int DEFAULT 1) RETURNS VARIANT NULL LANGUAGE PYTHON RUNTIME_VERSION = '3.8' PACKAGES = ('numpy', 'pandas') IMPORTS = ('numpy', 'pandas') HANDLER = 'udf' STRICT AS 'import numpy as np' , %s (x, y) AS (select m.album_ID, m.album_name, b.band_name from music_albums) CALL %s (1) INTO :ret`, id.FullyQualifiedName(), cte.FullyQualifiedName(), id.FullyQualifiedName()) + assertOptsValidAndSQLEquals(t, opts, `WITH %s AS PROCEDURE ("i" int DEFAULT 1) RETURNS VARIANT NULL LANGUAGE PYTHON STRICT RUNTIME_VERSION = '3.8' PACKAGES = ('numpy', 'pandas') IMPORTS = ('numpy', 'pandas') HANDLER = 'udf' AS 'import numpy as np' , %s (x, y) AS (select m.album_ID, m.album_name, b.band_name from music_albums) CALL %s (1) INTO :ret`, id.FullyQualifiedName(), cte.FullyQualifiedName(), id.FullyQualifiedName()) }) t.Run("all options", func(t *testing.T) { @@ -1772,7 +1862,7 @@ func TestProcedures_CreateAndCallForPython(t *testing.T) { opts.ProcedureName = id opts.ScriptingVariable = String(":ret") opts.CallArguments = []string{"1"} - assertOptsValidAndSQLEquals(t, opts, `WITH %s AS PROCEDURE (i NUMBER(36, 2) DEFAULT 1) RETURNS VARIANT NULL LANGUAGE PYTHON RUNTIME_VERSION = '3.8' PACKAGES = ('numpy', 'pandas') IMPORTS = ('numpy', 'pandas') HANDLER = 'udf' STRICT AS 'import numpy as np' , %s (x, y) AS (select m.album_ID, m.album_name, b.band_name from music_albums) CALL %s (1) INTO :ret`, id.FullyQualifiedName(), cte.FullyQualifiedName(), id.FullyQualifiedName()) + assertOptsValidAndSQLEquals(t, opts, `WITH %s AS PROCEDURE ("i" NUMBER(36, 2) DEFAULT 1) RETURNS VARIANT NULL LANGUAGE PYTHON STRICT RUNTIME_VERSION = '3.8' PACKAGES = ('numpy', 'pandas') IMPORTS = ('numpy', 'pandas') HANDLER = 'udf' AS 'import numpy as np' , %s (x, y) AS (select m.album_ID, m.album_name, b.band_name from music_albums) CALL %s (1) INTO :ret`, id.FullyQualifiedName(), cte.FullyQualifiedName(), id.FullyQualifiedName()) }) } @@ -1835,7 +1925,7 @@ func TestProcedures_CreateAndCallForJavaScript(t *testing.T) { opts.ProcedureName = id opts.ScriptingVariable = String(":ret") opts.CallArguments = []string{"1"} - assertOptsValidAndSQLEquals(t, opts, `WITH %s AS PROCEDURE (d DOUBLE DEFAULT 1.0) RETURNS DOUBLE NOT NULL LANGUAGE JAVASCRIPT STRICT AS 'return 1;' , %s (x, y) AS (select m.album_ID, m.album_name, b.band_name from music_albums) CALL %s (1) INTO :ret`, id.FullyQualifiedName(), cte.FullyQualifiedName(), id.FullyQualifiedName()) + assertOptsValidAndSQLEquals(t, opts, `WITH %s AS PROCEDURE ("d" DOUBLE DEFAULT 1.0) RETURNS DOUBLE NOT NULL LANGUAGE JAVASCRIPT STRICT AS 'return 1;' , %s (x, y) AS (select m.album_ID, m.album_name, b.band_name from music_albums) CALL %s (1) INTO :ret`, id.FullyQualifiedName(), cte.FullyQualifiedName(), id.FullyQualifiedName()) }) t.Run("all options", func(t *testing.T) { @@ -1862,7 +1952,7 @@ func TestProcedures_CreateAndCallForJavaScript(t *testing.T) { opts.ProcedureName = id opts.ScriptingVariable = String(":ret") opts.CallArguments = []string{"1"} - assertOptsValidAndSQLEquals(t, opts, `WITH %s AS PROCEDURE (d FLOAT DEFAULT 1.0) RETURNS FLOAT NOT NULL LANGUAGE JAVASCRIPT STRICT AS 'return 1;' , %s (x, y) AS (select m.album_ID, m.album_name, b.band_name from music_albums) CALL %s (1) INTO :ret`, id.FullyQualifiedName(), cte.FullyQualifiedName(), id.FullyQualifiedName()) + assertOptsValidAndSQLEquals(t, opts, `WITH %s AS PROCEDURE ("d" FLOAT DEFAULT 1.0) RETURNS FLOAT NOT NULL LANGUAGE JAVASCRIPT STRICT AS 'return 1;' , %s (x, y) AS (select m.album_ID, m.album_name, b.band_name from music_albums) CALL %s (1) INTO :ret`, id.FullyQualifiedName(), cte.FullyQualifiedName(), id.FullyQualifiedName()) }) } @@ -1954,7 +2044,7 @@ func TestProcedures_CreateAndCallForSQL(t *testing.T) { opts.ProcedureName = id opts.ScriptingVariable = String(":ret") opts.CallArguments = []string{"1"} - assertOptsValidAndSQLEquals(t, opts, `WITH %s AS PROCEDURE (message VARCHAR DEFAULT 'test') RETURNS FLOAT LANGUAGE SQL STRICT AS '3.141592654::FLOAT' , %s (x, y) AS (select m.album_ID, m.album_name, b.band_name from music_albums) CALL %s (1) INTO :ret`, id.FullyQualifiedName(), cte.FullyQualifiedName(), id.FullyQualifiedName()) + assertOptsValidAndSQLEquals(t, opts, `WITH %s AS PROCEDURE ("message" VARCHAR DEFAULT 'test') RETURNS FLOAT LANGUAGE SQL STRICT AS '3.141592654::FLOAT' , %s (x, y) AS (select m.album_ID, m.album_name, b.band_name from music_albums) CALL %s (1) INTO :ret`, id.FullyQualifiedName(), cte.FullyQualifiedName(), id.FullyQualifiedName()) }) t.Run("all options", func(t *testing.T) { @@ -1984,6 +2074,6 @@ func TestProcedures_CreateAndCallForSQL(t *testing.T) { opts.ProcedureName = id opts.ScriptingVariable = String(":ret") opts.CallArguments = []string{"1"} - assertOptsValidAndSQLEquals(t, opts, `WITH %s AS PROCEDURE (message VARCHAR(100) DEFAULT 'test') RETURNS FLOAT LANGUAGE SQL STRICT AS '3.141592654::FLOAT' , %s (x, y) AS (select m.album_ID, m.album_name, b.band_name from music_albums) CALL %s (1) INTO :ret`, id.FullyQualifiedName(), cte.FullyQualifiedName(), id.FullyQualifiedName()) + assertOptsValidAndSQLEquals(t, opts, `WITH %s AS PROCEDURE ("message" VARCHAR(100) DEFAULT 'test') RETURNS FLOAT LANGUAGE SQL STRICT AS '3.141592654::FLOAT' , %s (x, y) AS (select m.album_ID, m.album_name, b.band_name from music_albums) CALL %s (1) INTO :ret`, id.FullyQualifiedName(), cte.FullyQualifiedName(), id.FullyQualifiedName()) }) } diff --git a/pkg/sdk/procedures_impl_gen.go b/pkg/sdk/procedures_impl_gen.go index e63cf1f386..5a7e1ce84e 100644 --- a/pkg/sdk/procedures_impl_gen.go +++ b/pkg/sdk/procedures_impl_gen.go @@ -60,7 +60,7 @@ func (v *procedures) Show(ctx context.Context, request *ShowProcedureRequest) ([ } func (v *procedures) ShowByID(ctx context.Context, id SchemaObjectIdentifierWithArguments) (*Procedure, error) { - procedures, err := v.Show(ctx, NewShowProcedureRequest().WithIn(In{Schema: id.SchemaId()}).WithLike(Like{String(id.Name())})) + procedures, err := v.Show(ctx, NewShowProcedureRequest().WithIn(ExtendedIn{In: In{Schema: id.SchemaId()}}).WithLike(Like{String(id.Name())})) if err != nil { return nil, err } @@ -123,6 +123,7 @@ func (r *CreateForJavaProcedureRequest) toOpts() *CreateForJavaProcedureOptions Secrets: r.Secrets, TargetPath: r.TargetPath, NullInputBehavior: r.NullInputBehavior, + ReturnResultsBehavior: r.ReturnResultsBehavior, Comment: r.Comment, ExecuteAs: r.ExecuteAs, ProcedureDefinition: r.ProcedureDefinition, @@ -130,7 +131,12 @@ func (r *CreateForJavaProcedureRequest) toOpts() *CreateForJavaProcedureOptions if r.Arguments != nil { s := make([]ProcedureArgument, len(r.Arguments)) for i, v := range r.Arguments { - s[i] = ProcedureArgument(v) + s[i] = ProcedureArgument{ + ArgName: v.ArgName, + ArgDataTypeOld: v.ArgDataTypeOld, + ArgDataType: v.ArgDataType, + DefaultValue: v.DefaultValue, + } } opts.Arguments = s } @@ -148,7 +154,11 @@ func (r *CreateForJavaProcedureRequest) toOpts() *CreateForJavaProcedureOptions if r.Returns.Table.Columns != nil { s := make([]ProcedureColumn, len(r.Returns.Table.Columns)) for i, v := range r.Returns.Table.Columns { - s[i] = ProcedureColumn(v) + s[i] = ProcedureColumn{ + ColumnName: v.ColumnName, + ColumnDataTypeOld: v.ColumnDataTypeOld, + ColumnDataType: v.ColumnDataType, + } } opts.Returns.Table.Columns = s } @@ -156,14 +166,18 @@ func (r *CreateForJavaProcedureRequest) toOpts() *CreateForJavaProcedureOptions if r.Packages != nil { s := make([]ProcedurePackage, len(r.Packages)) for i, v := range r.Packages { - s[i] = ProcedurePackage(v) + s[i] = ProcedurePackage{ + Package: v.Package, + } } opts.Packages = s } if r.Imports != nil { s := make([]ProcedureImport, len(r.Imports)) for i, v := range r.Imports { - s[i] = ProcedureImport(v) + s[i] = ProcedureImport{ + Import: v.Import, + } } opts.Imports = s } @@ -176,19 +190,25 @@ func (r *CreateForJavaScriptProcedureRequest) toOpts() *CreateForJavaScriptProce Secure: r.Secure, name: r.name, - CopyGrants: r.CopyGrants, - ResultDataTypeOld: r.ResultDataTypeOld, - ResultDataType: r.ResultDataType, - NotNull: r.NotNull, - NullInputBehavior: r.NullInputBehavior, - Comment: r.Comment, - ExecuteAs: r.ExecuteAs, - ProcedureDefinition: r.ProcedureDefinition, + CopyGrants: r.CopyGrants, + ResultDataTypeOld: r.ResultDataTypeOld, + ResultDataType: r.ResultDataType, + NotNull: r.NotNull, + NullInputBehavior: r.NullInputBehavior, + ReturnResultsBehavior: r.ReturnResultsBehavior, + Comment: r.Comment, + ExecuteAs: r.ExecuteAs, + ProcedureDefinition: r.ProcedureDefinition, } if r.Arguments != nil { s := make([]ProcedureArgument, len(r.Arguments)) for i, v := range r.Arguments { - s[i] = ProcedureArgument(v) + s[i] = ProcedureArgument{ + ArgName: v.ArgName, + ArgDataTypeOld: v.ArgDataTypeOld, + ArgDataType: v.ArgDataType, + DefaultValue: v.DefaultValue, + } } opts.Arguments = s } @@ -209,6 +229,7 @@ func (r *CreateForPythonProcedureRequest) toOpts() *CreateForPythonProcedureOpti ExternalAccessIntegrations: r.ExternalAccessIntegrations, Secrets: r.Secrets, NullInputBehavior: r.NullInputBehavior, + ReturnResultsBehavior: r.ReturnResultsBehavior, Comment: r.Comment, ExecuteAs: r.ExecuteAs, ProcedureDefinition: r.ProcedureDefinition, @@ -216,7 +237,12 @@ func (r *CreateForPythonProcedureRequest) toOpts() *CreateForPythonProcedureOpti if r.Arguments != nil { s := make([]ProcedureArgument, len(r.Arguments)) for i, v := range r.Arguments { - s[i] = ProcedureArgument(v) + s[i] = ProcedureArgument{ + ArgName: v.ArgName, + ArgDataTypeOld: v.ArgDataTypeOld, + ArgDataType: v.ArgDataType, + DefaultValue: v.DefaultValue, + } } opts.Arguments = s } @@ -234,7 +260,11 @@ func (r *CreateForPythonProcedureRequest) toOpts() *CreateForPythonProcedureOpti if r.Returns.Table.Columns != nil { s := make([]ProcedureColumn, len(r.Returns.Table.Columns)) for i, v := range r.Returns.Table.Columns { - s[i] = ProcedureColumn(v) + s[i] = ProcedureColumn{ + ColumnName: v.ColumnName, + ColumnDataTypeOld: v.ColumnDataTypeOld, + ColumnDataType: v.ColumnDataType, + } } opts.Returns.Table.Columns = s } @@ -242,14 +272,18 @@ func (r *CreateForPythonProcedureRequest) toOpts() *CreateForPythonProcedureOpti if r.Packages != nil { s := make([]ProcedurePackage, len(r.Packages)) for i, v := range r.Packages { - s[i] = ProcedurePackage(v) + s[i] = ProcedurePackage{ + Package: v.Package, + } } opts.Packages = s } if r.Imports != nil { s := make([]ProcedureImport, len(r.Imports)) for i, v := range r.Imports { - s[i] = ProcedureImport(v) + s[i] = ProcedureImport{ + Import: v.Import, + } } opts.Imports = s } @@ -266,17 +300,25 @@ func (r *CreateForScalaProcedureRequest) toOpts() *CreateForScalaProcedureOption RuntimeVersion: r.RuntimeVersion, - Handler: r.Handler, - TargetPath: r.TargetPath, - NullInputBehavior: r.NullInputBehavior, - Comment: r.Comment, - ExecuteAs: r.ExecuteAs, - ProcedureDefinition: r.ProcedureDefinition, + Handler: r.Handler, + ExternalAccessIntegrations: r.ExternalAccessIntegrations, + Secrets: r.Secrets, + TargetPath: r.TargetPath, + NullInputBehavior: r.NullInputBehavior, + ReturnResultsBehavior: r.ReturnResultsBehavior, + Comment: r.Comment, + ExecuteAs: r.ExecuteAs, + ProcedureDefinition: r.ProcedureDefinition, } if r.Arguments != nil { s := make([]ProcedureArgument, len(r.Arguments)) for i, v := range r.Arguments { - s[i] = ProcedureArgument(v) + s[i] = ProcedureArgument{ + ArgName: v.ArgName, + ArgDataTypeOld: v.ArgDataTypeOld, + ArgDataType: v.ArgDataType, + DefaultValue: v.DefaultValue, + } } opts.Arguments = s } @@ -294,7 +336,11 @@ func (r *CreateForScalaProcedureRequest) toOpts() *CreateForScalaProcedureOption if r.Returns.Table.Columns != nil { s := make([]ProcedureColumn, len(r.Returns.Table.Columns)) for i, v := range r.Returns.Table.Columns { - s[i] = ProcedureColumn(v) + s[i] = ProcedureColumn{ + ColumnName: v.ColumnName, + ColumnDataTypeOld: v.ColumnDataTypeOld, + ColumnDataType: v.ColumnDataType, + } } opts.Returns.Table.Columns = s } @@ -302,14 +348,18 @@ func (r *CreateForScalaProcedureRequest) toOpts() *CreateForScalaProcedureOption if r.Packages != nil { s := make([]ProcedurePackage, len(r.Packages)) for i, v := range r.Packages { - s[i] = ProcedurePackage(v) + s[i] = ProcedurePackage{ + Package: v.Package, + } } opts.Packages = s } if r.Imports != nil { s := make([]ProcedureImport, len(r.Imports)) for i, v := range r.Imports { - s[i] = ProcedureImport(v) + s[i] = ProcedureImport{ + Import: v.Import, + } } opts.Imports = s } @@ -324,15 +374,21 @@ func (r *CreateForSQLProcedureRequest) toOpts() *CreateForSQLProcedureOptions { CopyGrants: r.CopyGrants, - NullInputBehavior: r.NullInputBehavior, - Comment: r.Comment, - ExecuteAs: r.ExecuteAs, - ProcedureDefinition: r.ProcedureDefinition, + NullInputBehavior: r.NullInputBehavior, + ReturnResultsBehavior: r.ReturnResultsBehavior, + Comment: r.Comment, + ExecuteAs: r.ExecuteAs, + ProcedureDefinition: r.ProcedureDefinition, } if r.Arguments != nil { s := make([]ProcedureArgument, len(r.Arguments)) for i, v := range r.Arguments { - s[i] = ProcedureArgument(v) + s[i] = ProcedureArgument{ + ArgName: v.ArgName, + ArgDataTypeOld: v.ArgDataTypeOld, + ArgDataType: v.ArgDataType, + DefaultValue: v.DefaultValue, + } } opts.Arguments = s } @@ -343,6 +399,8 @@ func (r *CreateForSQLProcedureRequest) toOpts() *CreateForSQLProcedureOptions { opts.Returns.ResultDataType = &ProcedureReturnsResultDataType{ ResultDataTypeOld: r.Returns.ResultDataType.ResultDataTypeOld, ResultDataType: r.Returns.ResultDataType.ResultDataType, + Null: r.Returns.ResultDataType.Null, + NotNull: r.Returns.ResultDataType.NotNull, } } if r.Returns.Table != nil { @@ -350,7 +408,11 @@ func (r *CreateForSQLProcedureRequest) toOpts() *CreateForSQLProcedureOptions { if r.Returns.Table.Columns != nil { s := make([]ProcedureColumn, len(r.Returns.Table.Columns)) for i, v := range r.Returns.Table.Columns { - s[i] = ProcedureColumn(v) + s[i] = ProcedureColumn{ + ColumnName: v.ColumnName, + ColumnDataTypeOld: v.ColumnDataTypeOld, + ColumnDataType: v.ColumnDataType, + } } opts.Returns.Table.Columns = s } @@ -360,16 +422,41 @@ func (r *CreateForSQLProcedureRequest) toOpts() *CreateForSQLProcedureOptions { func (r *AlterProcedureRequest) toOpts() *AlterProcedureOptions { opts := &AlterProcedureOptions{ - IfExists: r.IfExists, - name: r.name, - RenameTo: r.RenameTo, - SetComment: r.SetComment, - SetLogLevel: r.SetLogLevel, - SetTraceLevel: r.SetTraceLevel, - UnsetComment: r.UnsetComment, - SetTags: r.SetTags, - UnsetTags: r.UnsetTags, - ExecuteAs: r.ExecuteAs, + IfExists: r.IfExists, + name: r.name, + RenameTo: r.RenameTo, + + SetTags: r.SetTags, + UnsetTags: r.UnsetTags, + ExecuteAs: r.ExecuteAs, + } + if r.Set != nil { + opts.Set = &ProcedureSet{ + Comment: r.Set.Comment, + ExternalAccessIntegrations: r.Set.ExternalAccessIntegrations, + + AutoEventLogging: r.Set.AutoEventLogging, + EnableConsoleOutput: r.Set.EnableConsoleOutput, + LogLevel: r.Set.LogLevel, + MetricLevel: r.Set.MetricLevel, + TraceLevel: r.Set.TraceLevel, + } + if r.Set.SecretsList != nil { + opts.Set.SecretsList = &SecretsList{ + SecretsList: r.Set.SecretsList.SecretsList, + } + } + } + if r.Unset != nil { + opts.Unset = &ProcedureUnset{ + Comment: r.Unset.Comment, + ExternalAccessIntegrations: r.Unset.ExternalAccessIntegrations, + AutoEventLogging: r.Unset.AutoEventLogging, + EnableConsoleOutput: r.Unset.EnableConsoleOutput, + LogLevel: r.Unset.LogLevel, + MetricLevel: r.Unset.MetricLevel, + TraceLevel: r.Unset.TraceLevel, + } } return opts } @@ -394,7 +481,7 @@ func (r procedureRow) convert() *Procedure { e := &Procedure{ CreatedOn: r.CreatedOn, Name: r.Name, - SchemaName: r.SchemaName, + SchemaName: strings.Trim(r.SchemaName, `"`), IsBuiltin: r.IsBuiltin == "Y", IsAggregate: r.IsAggregate == "Y", IsAnsi: r.IsAnsi == "Y", @@ -402,7 +489,7 @@ func (r procedureRow) convert() *Procedure { MaxNumArguments: r.MaxNumArguments, ArgumentsRaw: r.Arguments, Description: r.Description, - CatalogName: r.CatalogName, + CatalogName: strings.Trim(r.CatalogName, `"`), IsTableFunction: r.IsTableFunction == "Y", ValidForClustering: r.ValidForClustering == "Y", } @@ -431,8 +518,8 @@ func (r procedureDetailRow) convert() *ProcedureDetail { e := &ProcedureDetail{ Property: r.Property, } - if r.Value.Valid { - e.Value = r.Value.String + if r.Value.Valid && r.Value.String != "null" { + e.Value = String(r.Value.String) } return e } @@ -464,7 +551,12 @@ func (r *CreateAndCallForJavaProcedureRequest) toOpts() *CreateAndCallForJavaPro if r.Arguments != nil { s := make([]ProcedureArgument, len(r.Arguments)) for i, v := range r.Arguments { - s[i] = ProcedureArgument(v) + s[i] = ProcedureArgument{ + ArgName: v.ArgName, + ArgDataTypeOld: v.ArgDataTypeOld, + ArgDataType: v.ArgDataType, + DefaultValue: v.DefaultValue, + } } opts.Arguments = s } @@ -482,7 +574,11 @@ func (r *CreateAndCallForJavaProcedureRequest) toOpts() *CreateAndCallForJavaPro if r.Returns.Table.Columns != nil { s := make([]ProcedureColumn, len(r.Returns.Table.Columns)) for i, v := range r.Returns.Table.Columns { - s[i] = ProcedureColumn(v) + s[i] = ProcedureColumn{ + ColumnName: v.ColumnName, + ColumnDataTypeOld: v.ColumnDataTypeOld, + ColumnDataType: v.ColumnDataType, + } } opts.Returns.Table.Columns = s } @@ -490,14 +586,18 @@ func (r *CreateAndCallForJavaProcedureRequest) toOpts() *CreateAndCallForJavaPro if r.Packages != nil { s := make([]ProcedurePackage, len(r.Packages)) for i, v := range r.Packages { - s[i] = ProcedurePackage(v) + s[i] = ProcedurePackage{ + Package: v.Package, + } } opts.Packages = s } if r.Imports != nil { s := make([]ProcedureImport, len(r.Imports)) for i, v := range r.Imports { - s[i] = ProcedureImport(v) + s[i] = ProcedureImport{ + Import: v.Import, + } } opts.Imports = s } @@ -528,7 +628,12 @@ func (r *CreateAndCallForScalaProcedureRequest) toOpts() *CreateAndCallForScalaP if r.Arguments != nil { s := make([]ProcedureArgument, len(r.Arguments)) for i, v := range r.Arguments { - s[i] = ProcedureArgument(v) + s[i] = ProcedureArgument{ + ArgName: v.ArgName, + ArgDataTypeOld: v.ArgDataTypeOld, + ArgDataType: v.ArgDataType, + DefaultValue: v.DefaultValue, + } } opts.Arguments = s } @@ -546,7 +651,11 @@ func (r *CreateAndCallForScalaProcedureRequest) toOpts() *CreateAndCallForScalaP if r.Returns.Table.Columns != nil { s := make([]ProcedureColumn, len(r.Returns.Table.Columns)) for i, v := range r.Returns.Table.Columns { - s[i] = ProcedureColumn(v) + s[i] = ProcedureColumn{ + ColumnName: v.ColumnName, + ColumnDataTypeOld: v.ColumnDataTypeOld, + ColumnDataType: v.ColumnDataType, + } } opts.Returns.Table.Columns = s } @@ -554,14 +663,18 @@ func (r *CreateAndCallForScalaProcedureRequest) toOpts() *CreateAndCallForScalaP if r.Packages != nil { s := make([]ProcedurePackage, len(r.Packages)) for i, v := range r.Packages { - s[i] = ProcedurePackage(v) + s[i] = ProcedurePackage{ + Package: v.Package, + } } opts.Packages = s } if r.Imports != nil { s := make([]ProcedureImport, len(r.Imports)) for i, v := range r.Imports { - s[i] = ProcedureImport(v) + s[i] = ProcedureImport{ + Import: v.Import, + } } opts.Imports = s } @@ -596,7 +709,12 @@ func (r *CreateAndCallForJavaScriptProcedureRequest) toOpts() *CreateAndCallForJ if r.Arguments != nil { s := make([]ProcedureArgument, len(r.Arguments)) for i, v := range r.Arguments { - s[i] = ProcedureArgument(v) + s[i] = ProcedureArgument{ + ArgName: v.ArgName, + ArgDataTypeOld: v.ArgDataTypeOld, + ArgDataType: v.ArgDataType, + DefaultValue: v.DefaultValue, + } } opts.Arguments = s } @@ -631,7 +749,12 @@ func (r *CreateAndCallForPythonProcedureRequest) toOpts() *CreateAndCallForPytho if r.Arguments != nil { s := make([]ProcedureArgument, len(r.Arguments)) for i, v := range r.Arguments { - s[i] = ProcedureArgument(v) + s[i] = ProcedureArgument{ + ArgName: v.ArgName, + ArgDataTypeOld: v.ArgDataTypeOld, + ArgDataType: v.ArgDataType, + DefaultValue: v.DefaultValue, + } } opts.Arguments = s } @@ -649,7 +772,11 @@ func (r *CreateAndCallForPythonProcedureRequest) toOpts() *CreateAndCallForPytho if r.Returns.Table.Columns != nil { s := make([]ProcedureColumn, len(r.Returns.Table.Columns)) for i, v := range r.Returns.Table.Columns { - s[i] = ProcedureColumn(v) + s[i] = ProcedureColumn{ + ColumnName: v.ColumnName, + ColumnDataTypeOld: v.ColumnDataTypeOld, + ColumnDataType: v.ColumnDataType, + } } opts.Returns.Table.Columns = s } @@ -657,14 +784,18 @@ func (r *CreateAndCallForPythonProcedureRequest) toOpts() *CreateAndCallForPytho if r.Packages != nil { s := make([]ProcedurePackage, len(r.Packages)) for i, v := range r.Packages { - s[i] = ProcedurePackage(v) + s[i] = ProcedurePackage{ + Package: v.Package, + } } opts.Packages = s } if r.Imports != nil { s := make([]ProcedureImport, len(r.Imports)) for i, v := range r.Imports { - s[i] = ProcedureImport(v) + s[i] = ProcedureImport{ + Import: v.Import, + } } opts.Imports = s } @@ -696,7 +827,12 @@ func (r *CreateAndCallForSQLProcedureRequest) toOpts() *CreateAndCallForSQLProce if r.Arguments != nil { s := make([]ProcedureArgument, len(r.Arguments)) for i, v := range r.Arguments { - s[i] = ProcedureArgument(v) + s[i] = ProcedureArgument{ + ArgName: v.ArgName, + ArgDataTypeOld: v.ArgDataTypeOld, + ArgDataType: v.ArgDataType, + DefaultValue: v.DefaultValue, + } } opts.Arguments = s } @@ -714,7 +850,11 @@ func (r *CreateAndCallForSQLProcedureRequest) toOpts() *CreateAndCallForSQLProce if r.Returns.Table.Columns != nil { s := make([]ProcedureColumn, len(r.Returns.Table.Columns)) for i, v := range r.Returns.Table.Columns { - s[i] = ProcedureColumn(v) + s[i] = ProcedureColumn{ + ColumnName: v.ColumnName, + ColumnDataTypeOld: v.ColumnDataTypeOld, + ColumnDataType: v.ColumnDataType, + } } opts.Returns.Table.Columns = s } diff --git a/pkg/sdk/procedures_validations_gen.go b/pkg/sdk/procedures_validations_gen.go index 5e7557176f..8298767264 100644 --- a/pkg/sdk/procedures_validations_gen.go +++ b/pkg/sdk/procedures_validations_gen.go @@ -248,8 +248,18 @@ func (opts *AlterProcedureOptions) validate() error { if opts.RenameTo != nil && !ValidObjectIdentifier(opts.RenameTo) { errs = append(errs, ErrInvalidObjectIdentifier) } - if !exactlyOneValueSet(opts.RenameTo, opts.SetComment, opts.SetLogLevel, opts.SetTraceLevel, opts.UnsetComment, opts.SetTags, opts.UnsetTags, opts.ExecuteAs) { - errs = append(errs, errExactlyOneOf("AlterProcedureOptions", "RenameTo", "SetComment", "SetLogLevel", "SetTraceLevel", "UnsetComment", "SetTags", "UnsetTags", "ExecuteAs")) + if !exactlyOneValueSet(opts.RenameTo, opts.Set, opts.Unset, opts.SetTags, opts.UnsetTags, opts.ExecuteAs) { + errs = append(errs, errExactlyOneOf("AlterProcedureOptions", "RenameTo", "Set", "Unset", "SetTags", "UnsetTags", "ExecuteAs")) + } + if valueSet(opts.Set) { + if !anyValueSet(opts.Set.Comment, opts.Set.ExternalAccessIntegrations, opts.Set.SecretsList, opts.Set.AutoEventLogging, opts.Set.EnableConsoleOutput, opts.Set.LogLevel, opts.Set.MetricLevel, opts.Set.TraceLevel) { + errs = append(errs, errAtLeastOneOf("AlterProcedureOptions.Set", "Comment", "ExternalAccessIntegrations", "SecretsList", "AutoEventLogging", "EnableConsoleOutput", "LogLevel", "MetricLevel", "TraceLevel")) + } + } + if valueSet(opts.Unset) { + if !anyValueSet(opts.Unset.Comment, opts.Unset.ExternalAccessIntegrations, opts.Unset.AutoEventLogging, opts.Unset.EnableConsoleOutput, opts.Unset.LogLevel, opts.Unset.MetricLevel, opts.Unset.TraceLevel) { + errs = append(errs, errAtLeastOneOf("AlterProcedureOptions.Unset", "Comment", "ExternalAccessIntegrations", "AutoEventLogging", "EnableConsoleOutput", "LogLevel", "MetricLevel", "TraceLevel")) + } } return JoinErrors(errs...) } diff --git a/pkg/sdk/testint/functions_integration_test.go b/pkg/sdk/testint/functions_integration_test.go index fa5196dc95..4f7220062c 100644 --- a/pkg/sdk/testint/functions_integration_test.go +++ b/pkg/sdk/testint/functions_integration_test.go @@ -87,7 +87,7 @@ func TestInt_Functions(t *testing.T) { assertions.AssertThatObject(t, objectassert.FunctionFromObject(t, function). HasCreatedOnNotEmpty(). HasName(id.Name()). - HasSchemaName(fmt.Sprintf(`"%s"`, id.SchemaName())). + HasSchemaName(id.SchemaName()). HasIsBuiltin(false). HasIsAggregate(false). HasIsAnsi(false). @@ -96,7 +96,7 @@ func TestInt_Functions(t *testing.T) { HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). HasDescription(sdk.DefaultFunctionComment). - HasCatalogName(fmt.Sprintf(`"%s"`, id.DatabaseName())). + HasCatalogName(id.DatabaseName()). HasIsTableFunction(false). HasValidForClustering(false). HasIsSecure(false). @@ -151,7 +151,7 @@ func TestInt_Functions(t *testing.T) { WithOrReplace(true). WithArguments([]sdk.FunctionArgumentRequest{*argument}). WithCopyGrants(true). - WithNullInputBehavior(*sdk.NullInputBehaviorPointer(sdk.NullInputBehaviorReturnNullInput)). + WithNullInputBehavior(*sdk.NullInputBehaviorPointer(sdk.NullInputBehaviorReturnsNullInput)). WithReturnResultsBehavior(sdk.ReturnResultsBehaviorImmutable). WithReturnNullValues(sdk.ReturnNullValuesNotNull). WithRuntimeVersion("11"). @@ -181,7 +181,7 @@ func TestInt_Functions(t *testing.T) { assertions.AssertThatObject(t, objectassert.FunctionFromObject(t, function). HasCreatedOnNotEmpty(). HasName(id.Name()). - HasSchemaName(fmt.Sprintf(`"%s"`, id.SchemaName())). + HasSchemaName(id.SchemaName()). HasIsBuiltin(false). HasIsAggregate(false). HasIsAnsi(false). @@ -190,12 +190,12 @@ func TestInt_Functions(t *testing.T) { HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). HasDescription("comment"). - HasCatalogName(fmt.Sprintf(`"%s"`, id.DatabaseName())). + HasCatalogName(id.DatabaseName()). HasIsTableFunction(false). HasValidForClustering(false). HasIsSecure(false). - HasExternalAccessIntegrations(fmt.Sprintf(`[%s]`, externalAccessIntegration.FullyQualifiedName())). - HasSecrets(fmt.Sprintf(`{"abc":"\"%s\".\"%s\".%s"}`, secretId.DatabaseName(), secretId.SchemaName(), secretId.Name())). + HasExactlyExternalAccessIntegrations(externalAccessIntegration). + HasExactlySecrets(map[string]sdk.SchemaObjectIdentifier{"abc": secretId}). HasIsExternalFunction(false). HasLanguage("JAVA"). HasIsMemoizable(false). @@ -207,12 +207,12 @@ func TestInt_Functions(t *testing.T) { HasReturns(fmt.Sprintf(`%s NOT NULL`, dataType.ToSql())). HasLanguage("JAVA"). HasBody(definition). - HasNullHandling(string(sdk.NullInputBehaviorReturnNullInput)). + HasNullHandling(string(sdk.NullInputBehaviorReturnsNullInput)). HasVolatility(string(sdk.ReturnResultsBehaviorImmutable)). - HasExternalAccessIntegrations(fmt.Sprintf(`[%s]`, externalAccessIntegration.FullyQualifiedName())). + HasExactlyExternalAccessIntegrations(externalAccessIntegration). // TODO [SNOW-1348103]: parse to identifier list // TODO [SNOW-1348103]: check multiple secrets (to know how to parse) - HasSecrets(fmt.Sprintf(`{"abc":"\"%s\".\"%s\".%s"}`, secretId.DatabaseName(), secretId.SchemaName(), secretId.Name())). + HasExactlySecrets(map[string]sdk.SchemaObjectIdentifier{"abc": secretId}). HasImports(fmt.Sprintf(`[%s]`, tmpJavaFunction.JarLocation())). HasHandler(handler). HasRuntimeVersion("11"). @@ -253,7 +253,7 @@ func TestInt_Functions(t *testing.T) { assertions.AssertThatObject(t, objectassert.FunctionFromObject(t, function). HasCreatedOnNotEmpty(). HasName(id.Name()). - HasSchemaName(fmt.Sprintf(`"%s"`, id.SchemaName())). + HasSchemaName(id.SchemaName()). HasIsBuiltin(false). HasIsAggregate(false). HasIsAnsi(false). @@ -262,7 +262,7 @@ func TestInt_Functions(t *testing.T) { HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). HasDescription(sdk.DefaultFunctionComment). - HasCatalogName(fmt.Sprintf(`"%s"`, id.DatabaseName())). + HasCatalogName(id.DatabaseName()). HasIsTableFunction(false). HasValidForClustering(false). HasIsSecure(false). @@ -312,7 +312,7 @@ func TestInt_Functions(t *testing.T) { WithOrReplace(true). WithArguments([]sdk.FunctionArgumentRequest{*argument}). WithCopyGrants(true). - WithNullInputBehavior(*sdk.NullInputBehaviorPointer(sdk.NullInputBehaviorReturnNullInput)). + WithNullInputBehavior(*sdk.NullInputBehaviorPointer(sdk.NullInputBehaviorReturnsNullInput)). WithReturnResultsBehavior(sdk.ReturnResultsBehaviorImmutable). WithReturnNullValues(sdk.ReturnNullValuesNotNull). WithRuntimeVersion("11"). @@ -335,7 +335,7 @@ func TestInt_Functions(t *testing.T) { assertions.AssertThatObject(t, objectassert.FunctionFromObject(t, function). HasCreatedOnNotEmpty(). HasName(id.Name()). - HasSchemaName(fmt.Sprintf(`"%s"`, id.SchemaName())). + HasSchemaName(id.SchemaName()). HasIsBuiltin(false). HasIsAggregate(false). HasIsAnsi(false). @@ -344,12 +344,12 @@ func TestInt_Functions(t *testing.T) { HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). HasDescription("comment"). - HasCatalogName(fmt.Sprintf(`"%s"`, id.DatabaseName())). + HasCatalogName(id.DatabaseName()). HasIsTableFunction(false). HasValidForClustering(false). HasIsSecure(false). - HasExternalAccessIntegrations(fmt.Sprintf(`[%s]`, externalAccessIntegration.FullyQualifiedName())). - HasSecrets(fmt.Sprintf(`{"abc":"\"%s\".\"%s\".%s"}`, secretId.DatabaseName(), secretId.SchemaName(), secretId.Name())). + HasExactlyExternalAccessIntegrations(externalAccessIntegration). + HasExactlySecrets(map[string]sdk.SchemaObjectIdentifier{"abc": secretId}). HasIsExternalFunction(false). HasLanguage("JAVA"). HasIsMemoizable(false). @@ -361,10 +361,10 @@ func TestInt_Functions(t *testing.T) { HasReturns(fmt.Sprintf(`%s NOT NULL`, dataType.ToSql())). HasLanguage("JAVA"). HasBodyNil(). - HasNullHandling(string(sdk.NullInputBehaviorReturnNullInput)). + HasNullHandling(string(sdk.NullInputBehaviorReturnsNullInput)). HasVolatility(string(sdk.ReturnResultsBehaviorImmutable)). - HasExternalAccessIntegrations(fmt.Sprintf(`[%s]`, externalAccessIntegration.FullyQualifiedName())). - HasSecrets(fmt.Sprintf(`{"abc":"\"%s\".\"%s\".%s"}`, secretId.DatabaseName(), secretId.SchemaName(), secretId.Name())). + HasExactlyExternalAccessIntegrations(externalAccessIntegration). + HasExactlySecrets(map[string]sdk.SchemaObjectIdentifier{"abc": secretId}). HasImports(fmt.Sprintf(`[%s]`, tmpJavaFunction.JarLocation())). HasHandler(handler). HasRuntimeVersion("11"). @@ -403,7 +403,7 @@ func TestInt_Functions(t *testing.T) { assertions.AssertThatObject(t, objectassert.FunctionFromObject(t, function). HasCreatedOnNotEmpty(). HasName(id.Name()). - HasSchemaName(fmt.Sprintf(`"%s"`, id.SchemaName())). + HasSchemaName(id.SchemaName()). HasIsBuiltin(false). HasIsAggregate(false). HasIsAnsi(false). @@ -412,7 +412,7 @@ func TestInt_Functions(t *testing.T) { HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). HasDescription(sdk.DefaultFunctionComment). - HasCatalogName(fmt.Sprintf(`"%s"`, id.DatabaseName())). + HasCatalogName(id.DatabaseName()). HasIsTableFunction(false). HasValidForClustering(false). HasIsSecure(false). @@ -462,7 +462,7 @@ func TestInt_Functions(t *testing.T) { WithArguments([]sdk.FunctionArgumentRequest{*argument}). WithCopyGrants(true). WithReturnNullValues(sdk.ReturnNullValuesNotNull). - WithNullInputBehavior(*sdk.NullInputBehaviorPointer(sdk.NullInputBehaviorReturnNullInput)). + WithNullInputBehavior(*sdk.NullInputBehaviorPointer(sdk.NullInputBehaviorReturnsNullInput)). WithReturnResultsBehavior(sdk.ReturnResultsBehaviorImmutable). WithComment("comment") @@ -476,7 +476,7 @@ func TestInt_Functions(t *testing.T) { assertions.AssertThatObject(t, objectassert.FunctionFromObject(t, function). HasCreatedOnNotEmpty(). HasName(id.Name()). - HasSchemaName(fmt.Sprintf(`"%s"`, id.SchemaName())). + HasSchemaName(id.SchemaName()). HasIsBuiltin(false). HasIsAggregate(false). HasIsAnsi(false). @@ -485,7 +485,7 @@ func TestInt_Functions(t *testing.T) { HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). HasDescription("comment"). - HasCatalogName(fmt.Sprintf(`"%s"`, id.DatabaseName())). + HasCatalogName(id.DatabaseName()). HasIsTableFunction(false). HasValidForClustering(false). HasIsSecure(false). @@ -502,7 +502,7 @@ func TestInt_Functions(t *testing.T) { HasReturns(fmt.Sprintf(`%s NOT NULL`, dataType.ToSql())). HasLanguage("JAVASCRIPT"). HasBody(definition). - HasNullHandling(string(sdk.NullInputBehaviorReturnNullInput)). + HasNullHandling(string(sdk.NullInputBehaviorReturnsNullInput)). HasVolatility(string(sdk.ReturnResultsBehaviorImmutable)). HasExternalAccessIntegrationsNil(). HasSecretsNil(). @@ -545,7 +545,7 @@ func TestInt_Functions(t *testing.T) { assertions.AssertThatObject(t, objectassert.FunctionFromObject(t, function). HasCreatedOnNotEmpty(). HasName(id.Name()). - HasSchemaName(fmt.Sprintf(`"%s"`, id.SchemaName())). + HasSchemaName(id.SchemaName()). HasIsBuiltin(false). HasIsAggregate(false). HasIsAnsi(false). @@ -554,7 +554,7 @@ func TestInt_Functions(t *testing.T) { HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). HasDescription(sdk.DefaultFunctionComment). - HasCatalogName(fmt.Sprintf(`"%s"`, id.DatabaseName())). + HasCatalogName(id.DatabaseName()). HasIsTableFunction(false). HasValidForClustering(false). HasIsSecure(false). @@ -605,7 +605,7 @@ func TestInt_Functions(t *testing.T) { WithArguments([]sdk.FunctionArgumentRequest{*argument}). WithCopyGrants(true). WithReturnNullValues(sdk.ReturnNullValuesNotNull). - WithNullInputBehavior(*sdk.NullInputBehaviorPointer(sdk.NullInputBehaviorReturnNullInput)). + WithNullInputBehavior(*sdk.NullInputBehaviorPointer(sdk.NullInputBehaviorReturnsNullInput)). WithReturnResultsBehavior(sdk.ReturnResultsBehaviorImmutable). WithComment("comment"). WithImports([]sdk.FunctionImportRequest{*sdk.NewFunctionImportRequest().WithImport(tmpPythonFunction.PythonModuleLocation())}). @@ -627,7 +627,7 @@ func TestInt_Functions(t *testing.T) { assertions.AssertThatObject(t, objectassert.FunctionFromObject(t, function). HasCreatedOnNotEmpty(). HasName(id.Name()). - HasSchemaName(fmt.Sprintf(`"%s"`, id.SchemaName())). + HasSchemaName(id.SchemaName()). HasIsBuiltin(false). HasIsAggregate(false). HasIsAnsi(false). @@ -636,12 +636,12 @@ func TestInt_Functions(t *testing.T) { HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). HasDescription("comment"). - HasCatalogName(fmt.Sprintf(`"%s"`, id.DatabaseName())). + HasCatalogName(id.DatabaseName()). HasIsTableFunction(false). HasValidForClustering(false). HasIsSecure(false). - HasExternalAccessIntegrations(fmt.Sprintf(`[%s]`, externalAccessIntegration.FullyQualifiedName())). - HasSecrets(fmt.Sprintf(`{"abc":"\"%s\".\"%s\".%s"}`, secretId.DatabaseName(), secretId.SchemaName(), secretId.Name())). + HasExactlyExternalAccessIntegrations(externalAccessIntegration). + HasExactlySecrets(map[string]sdk.SchemaObjectIdentifier{"abc": secretId}). HasIsExternalFunction(false). HasLanguage("PYTHON"). HasIsMemoizable(false). @@ -653,10 +653,10 @@ func TestInt_Functions(t *testing.T) { HasReturns(strings.ReplaceAll(dataType.ToSql(), " ", "")+" NOT NULL"). // TODO [SNOW-1348103]: do we care about this whitespace? HasLanguage("PYTHON"). HasBody(definition). - HasNullHandling(string(sdk.NullInputBehaviorReturnNullInput)). + HasNullHandling(string(sdk.NullInputBehaviorReturnsNullInput)). HasVolatility(string(sdk.ReturnResultsBehaviorImmutable)). - HasExternalAccessIntegrations(fmt.Sprintf(`[%s]`, externalAccessIntegration.FullyQualifiedName())). - HasSecrets(fmt.Sprintf(`{"abc":"\"%s\".\"%s\".%s"}`, secretId.DatabaseName(), secretId.SchemaName(), secretId.Name())). + HasExactlyExternalAccessIntegrations(externalAccessIntegration). + HasExactlySecrets(map[string]sdk.SchemaObjectIdentifier{"abc": secretId}). HasImports(fmt.Sprintf(`[%s]`, tmpPythonFunction.PythonModuleLocation())). HasHandler(funcName). HasRuntimeVersion("3.8"). @@ -694,7 +694,7 @@ func TestInt_Functions(t *testing.T) { assertions.AssertThatObject(t, objectassert.FunctionFromObject(t, function). HasCreatedOnNotEmpty(). HasName(id.Name()). - HasSchemaName(fmt.Sprintf(`"%s"`, id.SchemaName())). + HasSchemaName(id.SchemaName()). HasIsBuiltin(false). HasIsAggregate(false). HasIsAnsi(false). @@ -703,7 +703,7 @@ func TestInt_Functions(t *testing.T) { HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). HasDescription(sdk.DefaultFunctionComment). - HasCatalogName(fmt.Sprintf(`"%s"`, id.DatabaseName())). + HasCatalogName(id.DatabaseName()). HasIsTableFunction(false). HasValidForClustering(false). HasIsSecure(false). @@ -752,7 +752,7 @@ func TestInt_Functions(t *testing.T) { WithArguments([]sdk.FunctionArgumentRequest{*argument}). WithCopyGrants(true). WithReturnNullValues(sdk.ReturnNullValuesNotNull). - WithNullInputBehavior(*sdk.NullInputBehaviorPointer(sdk.NullInputBehaviorReturnNullInput)). + WithNullInputBehavior(*sdk.NullInputBehaviorPointer(sdk.NullInputBehaviorReturnsNullInput)). WithReturnResultsBehavior(sdk.ReturnResultsBehaviorImmutable). WithComment("comment"). WithPackages([]sdk.FunctionPackageRequest{ @@ -773,7 +773,7 @@ func TestInt_Functions(t *testing.T) { assertions.AssertThatObject(t, objectassert.FunctionFromObject(t, function). HasCreatedOnNotEmpty(). HasName(id.Name()). - HasSchemaName(fmt.Sprintf(`"%s"`, id.SchemaName())). + HasSchemaName(id.SchemaName()). HasIsBuiltin(false). HasIsAggregate(false). HasIsAnsi(false). @@ -782,12 +782,12 @@ func TestInt_Functions(t *testing.T) { HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). HasDescription("comment"). - HasCatalogName(fmt.Sprintf(`"%s"`, id.DatabaseName())). + HasCatalogName(id.DatabaseName()). HasIsTableFunction(false). HasValidForClustering(false). HasIsSecure(false). - HasExternalAccessIntegrations(fmt.Sprintf(`[%s]`, externalAccessIntegration.FullyQualifiedName())). - HasSecrets(fmt.Sprintf(`{"abc":"\"%s\".\"%s\".%s"}`, secretId.DatabaseName(), secretId.SchemaName(), secretId.Name())). + HasExactlyExternalAccessIntegrations(externalAccessIntegration). + HasExactlySecrets(map[string]sdk.SchemaObjectIdentifier{"abc": secretId}). HasIsExternalFunction(false). HasLanguage("PYTHON"). HasIsMemoizable(false). @@ -799,10 +799,10 @@ func TestInt_Functions(t *testing.T) { HasReturns(strings.ReplaceAll(dataType.ToSql(), " ", "")+" NOT NULL"). HasLanguage("PYTHON"). HasBodyNil(). - HasNullHandling(string(sdk.NullInputBehaviorReturnNullInput)). + HasNullHandling(string(sdk.NullInputBehaviorReturnsNullInput)). HasVolatility(string(sdk.ReturnResultsBehaviorImmutable)). - HasExternalAccessIntegrations(fmt.Sprintf(`[%s]`, externalAccessIntegration.FullyQualifiedName())). - HasSecrets(fmt.Sprintf(`{"abc":"\"%s\".\"%s\".%s"}`, secretId.DatabaseName(), secretId.SchemaName(), secretId.Name())). + HasExactlyExternalAccessIntegrations(externalAccessIntegration). + HasExactlySecrets(map[string]sdk.SchemaObjectIdentifier{"abc": secretId}). HasImports(fmt.Sprintf(`[%s]`, tmpPythonFunction.PythonModuleLocation())). HasHandler(tmpPythonFunction.PythonHandler()). HasRuntimeVersion("3.8"). @@ -843,7 +843,7 @@ func TestInt_Functions(t *testing.T) { assertions.AssertThatObject(t, objectassert.FunctionFromObject(t, function). HasCreatedOnNotEmpty(). HasName(id.Name()). - HasSchemaName(fmt.Sprintf(`"%s"`, id.SchemaName())). + HasSchemaName(id.SchemaName()). HasIsBuiltin(false). HasIsAggregate(false). HasIsAnsi(false). @@ -852,7 +852,7 @@ func TestInt_Functions(t *testing.T) { HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). HasDescription(sdk.DefaultFunctionComment). - HasCatalogName(fmt.Sprintf(`"%s"`, id.DatabaseName())). + HasCatalogName(id.DatabaseName()). HasIsTableFunction(false). HasValidForClustering(false). HasIsSecure(false). @@ -905,7 +905,7 @@ func TestInt_Functions(t *testing.T) { WithOrReplace(true). WithArguments([]sdk.FunctionArgumentRequest{*argument}). WithCopyGrants(true). - WithNullInputBehavior(*sdk.NullInputBehaviorPointer(sdk.NullInputBehaviorReturnNullInput)). + WithNullInputBehavior(*sdk.NullInputBehaviorPointer(sdk.NullInputBehaviorReturnsNullInput)). WithReturnResultsBehavior(sdk.ReturnResultsBehaviorImmutable). WithReturnNullValues(sdk.ReturnNullValuesNotNull). WithComment("comment"). @@ -934,7 +934,7 @@ func TestInt_Functions(t *testing.T) { assertions.AssertThatObject(t, objectassert.FunctionFromObject(t, function). HasCreatedOnNotEmpty(). HasName(id.Name()). - HasSchemaName(fmt.Sprintf(`"%s"`, id.SchemaName())). + HasSchemaName(id.SchemaName()). HasIsBuiltin(false). HasIsAggregate(false). HasIsAnsi(false). @@ -943,12 +943,12 @@ func TestInt_Functions(t *testing.T) { HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). HasDescription("comment"). - HasCatalogName(fmt.Sprintf(`"%s"`, id.DatabaseName())). + HasCatalogName(id.DatabaseName()). HasIsTableFunction(false). HasValidForClustering(false). HasIsSecure(false). - HasExternalAccessIntegrations(fmt.Sprintf(`[%s]`, externalAccessIntegration.FullyQualifiedName())). - HasSecrets(fmt.Sprintf(`{"abc":"\"%s\".\"%s\".%s"}`, secretId.DatabaseName(), secretId.SchemaName(), secretId.Name())). + HasExactlyExternalAccessIntegrations(externalAccessIntegration). + HasExactlySecrets(map[string]sdk.SchemaObjectIdentifier{"abc": secretId}). HasIsExternalFunction(false). HasLanguage("SCALA"). HasIsMemoizable(false). @@ -960,10 +960,10 @@ func TestInt_Functions(t *testing.T) { HasReturns(fmt.Sprintf(`%s NOT NULL`, dataType.ToSql())). HasLanguage("SCALA"). HasBody(definition). - HasNullHandling(string(sdk.NullInputBehaviorReturnNullInput)). + HasNullHandling(string(sdk.NullInputBehaviorReturnsNullInput)). HasVolatility(string(sdk.ReturnResultsBehaviorImmutable)). - HasExternalAccessIntegrations(fmt.Sprintf(`[%s]`, externalAccessIntegration.FullyQualifiedName())). - HasSecrets(fmt.Sprintf(`{"abc":"\"%s\".\"%s\".%s"}`, secretId.DatabaseName(), secretId.SchemaName(), secretId.Name())). + HasExactlyExternalAccessIntegrations(externalAccessIntegration). + HasExactlySecrets(map[string]sdk.SchemaObjectIdentifier{"abc": secretId}). HasImports(fmt.Sprintf(`[%s]`, tmpJavaFunction.JarLocation())). HasHandler(handler). HasRuntimeVersion("2.12"). @@ -1002,7 +1002,7 @@ func TestInt_Functions(t *testing.T) { assertions.AssertThatObject(t, objectassert.FunctionFromObject(t, function). HasCreatedOnNotEmpty(). HasName(id.Name()). - HasSchemaName(fmt.Sprintf(`"%s"`, id.SchemaName())). + HasSchemaName(id.SchemaName()). HasIsBuiltin(false). HasIsAggregate(false). HasIsAnsi(false). @@ -1011,7 +1011,7 @@ func TestInt_Functions(t *testing.T) { HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). HasDescription(sdk.DefaultFunctionComment). - HasCatalogName(fmt.Sprintf(`"%s"`, id.DatabaseName())). + HasCatalogName(id.DatabaseName()). HasIsTableFunction(false). HasValidForClustering(false). HasIsSecure(false). @@ -1059,7 +1059,7 @@ func TestInt_Functions(t *testing.T) { WithOrReplace(true). WithArguments([]sdk.FunctionArgumentRequest{*argument}). WithCopyGrants(true). - WithNullInputBehavior(*sdk.NullInputBehaviorPointer(sdk.NullInputBehaviorReturnNullInput)). + WithNullInputBehavior(*sdk.NullInputBehaviorPointer(sdk.NullInputBehaviorReturnsNullInput)). WithReturnResultsBehavior(sdk.ReturnResultsBehaviorImmutable). WithReturnNullValues(sdk.ReturnNullValuesNotNull). WithComment("comment"). @@ -1081,7 +1081,7 @@ func TestInt_Functions(t *testing.T) { assertions.AssertThatObject(t, objectassert.FunctionFromObject(t, function). HasCreatedOnNotEmpty(). HasName(id.Name()). - HasSchemaName(fmt.Sprintf(`"%s"`, id.SchemaName())). + HasSchemaName(id.SchemaName()). HasIsBuiltin(false). HasIsAggregate(false). HasIsAnsi(false). @@ -1090,13 +1090,13 @@ func TestInt_Functions(t *testing.T) { HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). HasDescription("comment"). - HasCatalogName(fmt.Sprintf(`"%s"`, id.DatabaseName())). + HasCatalogName(id.DatabaseName()). HasIsTableFunction(false). HasValidForClustering(false). HasIsSecure(false). HasIsExternalFunction(false). - HasExternalAccessIntegrations(fmt.Sprintf(`[%s]`, externalAccessIntegration.FullyQualifiedName())). - HasSecrets(fmt.Sprintf(`{"abc":"\"%s\".\"%s\".%s"}`, secretId.DatabaseName(), secretId.SchemaName(), secretId.Name())). + HasExactlyExternalAccessIntegrations(externalAccessIntegration). + HasExactlySecrets(map[string]sdk.SchemaObjectIdentifier{"abc": secretId}). HasLanguage("SCALA"). HasIsMemoizable(false). HasIsDataMetric(false), @@ -1107,10 +1107,10 @@ func TestInt_Functions(t *testing.T) { HasReturns(fmt.Sprintf(`%s NOT NULL`, dataType.ToSql())). HasLanguage("SCALA"). HasBodyNil(). - HasNullHandling(string(sdk.NullInputBehaviorReturnNullInput)). + HasNullHandling(string(sdk.NullInputBehaviorReturnsNullInput)). HasVolatility(string(sdk.ReturnResultsBehaviorImmutable)). - HasExternalAccessIntegrations(fmt.Sprintf(`[%s]`, externalAccessIntegration.FullyQualifiedName())). - HasSecrets(fmt.Sprintf(`{"abc":"\"%s\".\"%s\".%s"}`, secretId.DatabaseName(), secretId.SchemaName(), secretId.Name())). + HasExactlyExternalAccessIntegrations(externalAccessIntegration). + HasExactlySecrets(map[string]sdk.SchemaObjectIdentifier{"abc": secretId}). HasImports(fmt.Sprintf(`[%s]`, tmpJavaFunction.JarLocation())). HasHandler(handler). HasRuntimeVersion("2.12"). @@ -1148,7 +1148,7 @@ func TestInt_Functions(t *testing.T) { assertions.AssertThatObject(t, objectassert.FunctionFromObject(t, function). HasCreatedOnNotEmpty(). HasName(id.Name()). - HasSchemaName(fmt.Sprintf(`"%s"`, id.SchemaName())). + HasSchemaName(id.SchemaName()). HasIsBuiltin(false). HasIsAggregate(false). HasIsAnsi(false). @@ -1157,7 +1157,7 @@ func TestInt_Functions(t *testing.T) { HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). HasDescription(sdk.DefaultFunctionComment). - HasCatalogName(fmt.Sprintf(`"%s"`, id.DatabaseName())). + HasCatalogName(id.DatabaseName()). HasIsTableFunction(false). HasValidForClustering(false). HasIsSecure(false). @@ -1221,7 +1221,7 @@ func TestInt_Functions(t *testing.T) { assertions.AssertThatObject(t, objectassert.FunctionFromObject(t, function). HasCreatedOnNotEmpty(). HasName(id.Name()). - HasSchemaName(fmt.Sprintf(`"%s"`, id.SchemaName())). + HasSchemaName(id.SchemaName()). HasIsBuiltin(false). HasIsAggregate(false). HasIsAnsi(false). @@ -1230,7 +1230,7 @@ func TestInt_Functions(t *testing.T) { HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). HasDescription("comment"). - HasCatalogName(fmt.Sprintf(`"%s"`, id.DatabaseName())). + HasCatalogName(id.DatabaseName()). HasIsTableFunction(false). HasValidForClustering(false). HasIsSecure(false). @@ -1287,7 +1287,7 @@ func TestInt_Functions(t *testing.T) { assertions.AssertThatObject(t, objectassert.FunctionFromObject(t, function). HasCreatedOnNotEmpty(). HasName(id.Name()). - HasSchemaName(fmt.Sprintf(`"%s"`, id.SchemaName())). + HasSchemaName(id.SchemaName()). HasIsBuiltin(false). HasIsAggregate(false). HasIsAnsi(false). @@ -1296,7 +1296,7 @@ func TestInt_Functions(t *testing.T) { HasArgumentsOld([]sdk.DataType{}). HasArgumentsRaw(fmt.Sprintf(`%[1]s() RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). HasDescription(sdk.DefaultFunctionComment). - HasCatalogName(fmt.Sprintf(`"%s"`, id.DatabaseName())). + HasCatalogName(id.DatabaseName()). HasIsTableFunction(false). HasValidForClustering(false). HasIsSecure(false). @@ -1420,8 +1420,8 @@ func TestInt_Functions(t *testing.T) { ) assertions.AssertThatObject(t, objectassert.FunctionDetails(t, id). - HasExternalAccessIntegrations(fmt.Sprintf(`[%s]`, externalAccessIntegration.FullyQualifiedName())). - HasSecrets(fmt.Sprintf(`{"abc":"\"%s\".\"%s\".%s"}`, secretId.DatabaseName(), secretId.SchemaName(), secretId.Name())), + HasExactlyExternalAccessIntegrations(externalAccessIntegration). + HasExactlySecrets(map[string]sdk.SchemaObjectIdentifier{"abc": secretId}), ) assertParametersSet(t, objectparametersassert.FunctionParameters(t, id)) @@ -1442,8 +1442,8 @@ func TestInt_Functions(t *testing.T) { assertions.AssertThatObject(t, objectassert.Function(t, id). HasName(id.Name()). HasDescription(sdk.DefaultFunctionComment). - HasExternalAccessIntegrations("[]"). - HasSecrets(fmt.Sprintf(`{"abc":"\"%s\".\"%s\".%s"}`, secretId.DatabaseName(), secretId.SchemaName(), secretId.Name())), + HasExactlyExternalAccessIntegrations(). + HasExactlySecrets(map[string]sdk.SchemaObjectIdentifier{"abc": secretId}), ) assertions.AssertThatObject(t, objectassert.FunctionDetails(t, id). diff --git a/pkg/sdk/testint/procedures_integration_test.go b/pkg/sdk/testint/procedures_integration_test.go index 4543791c4d..2a69ef42c2 100644 --- a/pkg/sdk/testint/procedures_integration_test.go +++ b/pkg/sdk/testint/procedures_integration_test.go @@ -3,8 +3,16 @@ package testint import ( "errors" "fmt" + "strings" "testing" + "time" + assertions "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert/objectassert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert/objectparametersassert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/helpers/random" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/testdatatypes" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/collections" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk/datatypes" @@ -12,59 +20,1203 @@ import ( "github.com/stretchr/testify/require" ) -// todo: add tests for: -// - creating procedure with different languages from stages - -func TestInt_CreateProcedures(t *testing.T) { +// TODO [SNOW-1850370]: 'ExtendedIn' struct for procedures not support keyword "CLASS" now +// TODO [SNOW-1850370]: Call/CreateAndCall methods were not updated before V1 because we are not using them +func TestInt_Procedures(t *testing.T) { client := testClient(t) ctx := testContext(t) - cleanupProcedureHandle := func(id sdk.SchemaObjectIdentifierWithArguments) func() { - return func() { - err := client.Procedures.Drop(ctx, sdk.NewDropProcedureRequest(id)) - if errors.Is(err, sdk.ErrObjectNotExistOrAuthorized) { - return - } - require.NoError(t, err) - } + secretId := testClientHelper().Ids.RandomSchemaObjectIdentifier() + + networkRule, networkRuleCleanup := testClientHelper().NetworkRule.Create(t) + t.Cleanup(networkRuleCleanup) + + secret, secretCleanup := testClientHelper().Secret.CreateWithGenericString(t, secretId, "test_secret_string") + t.Cleanup(secretCleanup) + + externalAccessIntegration, externalAccessIntegrationCleanup := testClientHelper().ExternalAccessIntegration.CreateExternalAccessIntegrationWithNetworkRuleAndSecret(t, networkRule.ID(), secret.ID()) + t.Cleanup(externalAccessIntegrationCleanup) + + tmpJavaProcedure := testClientHelper().CreateSampleJavaProcedureAndJar(t) + tmpPythonFunction := testClientHelper().CreateSamplePythonFunctionAndModule(t) + + assertParametersSet := func(t *testing.T, procedureParametersAssert *objectparametersassert.ProcedureParametersAssert) { + t.Helper() + assertions.AssertThatObject(t, procedureParametersAssert. + // TODO [SNOW-1850370]: every value end with invalid value [OFF] for parameter 'AUTO_EVENT_LOGGING' + // HasAutoEventLogging(sdk.AutoEventLoggingTracing). + HasEnableConsoleOutput(true). + HasLogLevel(sdk.LogLevelWarn). + HasMetricLevel(sdk.MetricLevelAll). + HasTraceLevel(sdk.TraceLevelAlways), + ) } - t.Run("create procedure for Java: returns result data type", func(t *testing.T) { - // https://docs.snowflake.com/en/developer-guide/stored-procedure/stored-procedures-java#reading-a-dynamically-specified-file-with-inputstream - name := "file_reader_java_proc_snowflakefile" - id := testClientHelper().Ids.NewSchemaObjectIdentifierWithArguments(name, sdk.DataTypeVARCHAR) + t.Run("create procedure for Java - inline minimal", func(t *testing.T) { + className := "TestFunc" + funcName := "echoVarchar" + argName := "x" + dataType := testdatatypes.DataTypeVarchar_100 - definition := ` - import java.io.InputStream; - import java.io.IOException; - import java.nio.charset.StandardCharsets; - import com.snowflake.snowpark_java.types.SnowflakeFile; - import com.snowflake.snowpark_java.Session; - class FileReader { - public String execute(Session session, String fileName) throws IOException { - InputStream input = SnowflakeFile.newInstance(fileName).getInputStream(); - return new String(input.readAllBytes(), StandardCharsets.UTF_8); - } - }` + id := testClientHelper().Ids.RandomSchemaObjectIdentifierWithArguments(sdk.LegacyDataTypeFrom(dataType)) + argument := sdk.NewProcedureArgumentRequest(argName, dataType) + dt := sdk.NewProcedureReturnsResultDataTypeRequest(dataType) + returns := sdk.NewProcedureReturnsRequest().WithResultDataType(*dt) + handler := fmt.Sprintf("%s.%s", className, funcName) + definition := testClientHelper().Procedure.SampleJavaDefinition(t, className, funcName, argName) + packages := []sdk.ProcedurePackageRequest{*sdk.NewProcedurePackageRequest("com.snowflake:snowpark:1.14.0")} - dt := sdk.NewProcedureReturnsResultDataTypeRequest(nil).WithResultDataTypeOld(sdk.DataTypeVARCHAR) + request := sdk.NewCreateForJavaProcedureRequest(id.SchemaObjectId(), *returns, "11", packages, handler). + WithArguments([]sdk.ProcedureArgumentRequest{*argument}). + WithProcedureDefinitionWrapped(definition) + + err := client.Procedures.CreateForJava(ctx, request) + require.NoError(t, err) + t.Cleanup(testClientHelper().Procedure.DropProcedureFunc(t, id)) + + procedure, err := client.Procedures.ShowByID(ctx, id) + require.NoError(t, err) + + assertions.AssertThatObject(t, objectassert.ProcedureFromObject(t, procedure). + HasCreatedOnNotEmpty(). + HasName(id.Name()). + HasSchemaName(id.SchemaName()). + HasIsBuiltin(false). + HasIsAggregate(false). + HasIsAnsi(false). + HasMinNumArguments(1). + HasMaxNumArguments(1). + HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). + HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, procedure.ID().Name(), dataType.ToLegacyDataTypeSql())). + HasDescription(sdk.DefaultProcedureComment). + HasCatalogName(id.DatabaseName()). + HasIsTableFunction(false). + HasValidForClustering(false). + HasIsSecure(false). + HasExternalAccessIntegrationsNil(). + HasSecretsNil(), + ) + + assertions.AssertThatObject(t, objectassert.ProcedureDetails(t, procedure.ID()). + HasSignature(fmt.Sprintf(`(%s %s)`, argName, dataType.ToLegacyDataTypeSql())). + HasReturns(dataType.ToSql()). + HasLanguage("JAVA"). + HasBody(definition). + HasNullHandling(string(sdk.NullInputBehaviorCalledOnNullInput)). + HasVolatility(string(sdk.ReturnResultsBehaviorVolatile)). + HasExternalAccessIntegrationsNil(). + HasSecretsNil(). + HasImports(`[]`). + HasHandler(handler). + HasRuntimeVersion("11"). + HasPackages(`[com.snowflake:snowpark:1.14.0]`). + HasTargetPathNil(). + HasInstalledPackagesNil(). + HasExecuteAs("OWNER"), + ) + + assertions.AssertThatObject(t, objectparametersassert.ProcedureParameters(t, id). + HasAllDefaults(). + HasAllDefaultsExplicit(), + ) + }) + + t.Run("create procedure for Java - inline full", func(t *testing.T) { + className := "TestFunc" + funcName := "echoVarchar" + argName := "x" + dataType := testdatatypes.DataTypeVarchar_100 + + id := testClientHelper().Ids.RandomSchemaObjectIdentifierWithArguments(sdk.LegacyDataTypeFrom(dataType)) + argument := sdk.NewProcedureArgumentRequest(argName, dataType) + dt := sdk.NewProcedureReturnsResultDataTypeRequest(dataType). + WithNotNull(true) returns := sdk.NewProcedureReturnsRequest().WithResultDataType(*dt) - argument := sdk.NewProcedureArgumentRequest("input", nil).WithArgDataTypeOld(sdk.DataTypeVARCHAR) - packages := []sdk.ProcedurePackageRequest{*sdk.NewProcedurePackageRequest("com.snowflake:snowpark:latest")} - request := sdk.NewCreateForJavaProcedureRequest(id.SchemaObjectId(), *returns, "11", packages, "FileReader.execute"). + handler := fmt.Sprintf("%s.%s", className, funcName) + definition := testClientHelper().Procedure.SampleJavaDefinition(t, className, funcName, argName) + jarName := fmt.Sprintf("tf-%d-%s.jar", time.Now().Unix(), random.AlphaN(5)) + targetPath := fmt.Sprintf("@~/%s", jarName) + packages := []sdk.ProcedurePackageRequest{ + *sdk.NewProcedurePackageRequest("com.snowflake:snowpark:1.14.0"), + *sdk.NewProcedurePackageRequest("com.snowflake:telemetry:0.1.0"), + } + + request := sdk.NewCreateForJavaProcedureRequest(id.SchemaObjectId(), *returns, "11", packages, handler). WithOrReplace(true). WithArguments([]sdk.ProcedureArgumentRequest{*argument}). - WithProcedureDefinition(definition) + WithCopyGrants(true). + WithNullInputBehavior(*sdk.NullInputBehaviorPointer(sdk.NullInputBehaviorReturnsNullInput)). + WithReturnResultsBehavior(sdk.ReturnResultsBehaviorImmutable). + WithComment("comment"). + WithImports([]sdk.ProcedureImportRequest{*sdk.NewProcedureImportRequest(tmpJavaProcedure.JarLocation())}). + WithExternalAccessIntegrations([]sdk.AccountObjectIdentifier{externalAccessIntegration}). + WithSecrets([]sdk.SecretReference{{VariableName: "abc", Name: secretId}}). + WithTargetPath(targetPath). + WithProcedureDefinitionWrapped(definition) + err := client.Procedures.CreateForJava(ctx, request) require.NoError(t, err) - t.Cleanup(cleanupProcedureHandle(id)) + t.Cleanup(testClientHelper().Procedure.DropProcedureFunc(t, id)) + t.Cleanup(testClientHelper().Stage.RemoveFromUserStageFunc(t, jarName)) + + function, err := client.Procedures.ShowByID(ctx, id) + require.NoError(t, err) + + assertions.AssertThatObject(t, objectassert.ProcedureFromObject(t, function). + HasCreatedOnNotEmpty(). + HasName(id.Name()). + HasSchemaName(id.SchemaName()). + HasIsBuiltin(false). + HasIsAggregate(false). + HasIsAnsi(false). + HasMinNumArguments(1). + HasMaxNumArguments(1). + HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). + HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). + HasDescription("comment"). + HasCatalogName(id.DatabaseName()). + HasIsTableFunction(false). + HasValidForClustering(false). + HasIsSecure(false). + // TODO [SNOW-1850370]: apparently external access integrations and secrets are not filled out correctly for procedures + HasExternalAccessIntegrationsNil(). + HasSecretsNil(), + ) + + assertions.AssertThatObject(t, objectassert.ProcedureDetails(t, function.ID()). + HasSignature(fmt.Sprintf(`(%s %s)`, argName, dataType.ToLegacyDataTypeSql())). + HasReturns(fmt.Sprintf(`%s NOT NULL`, dataType.ToSql())). + HasLanguage("JAVA"). + HasBody(definition). + HasNullHandling(string(sdk.NullInputBehaviorReturnsNullInput)). + HasVolatility(string(sdk.ReturnResultsBehaviorImmutable)). + HasExactlyExternalAccessIntegrations(externalAccessIntegration). + HasExactlySecrets(map[string]sdk.SchemaObjectIdentifier{"abc": secretId}). + HasImports(fmt.Sprintf(`[%s]`, tmpJavaProcedure.JarLocation())). + HasHandler(handler). + HasRuntimeVersion("11"). + HasPackages(`[com.snowflake:snowpark:1.14.0,com.snowflake:telemetry:0.1.0]`). + HasTargetPath(targetPath). + HasInstalledPackagesNil(). + HasExecuteAs("OWNER"), + ) + + assertions.AssertThatObject(t, objectparametersassert.ProcedureParameters(t, id). + HasAllDefaults(). + HasAllDefaultsExplicit(), + ) + }) - procedures, err := client.Procedures.Show(ctx, sdk.NewShowProcedureRequest()) + t.Run("create procedure for Java - staged minimal", func(t *testing.T) { + dataType := tmpJavaProcedure.ArgType + id := testClientHelper().Ids.RandomSchemaObjectIdentifierWithArguments(sdk.LegacyDataTypeFrom(dataType)) + + argName := "x" + argument := sdk.NewProcedureArgumentRequest(argName, dataType) + dt := sdk.NewProcedureReturnsResultDataTypeRequest(dataType) + returns := sdk.NewProcedureReturnsRequest().WithResultDataType(*dt) + handler := tmpJavaProcedure.JavaHandler() + importPath := tmpJavaProcedure.JarLocation() + packages := []sdk.ProcedurePackageRequest{ + *sdk.NewProcedurePackageRequest("com.snowflake:snowpark:1.14.0"), + *sdk.NewProcedurePackageRequest("com.snowflake:telemetry:0.1.0"), + } + + requestStaged := sdk.NewCreateForJavaProcedureRequest(id.SchemaObjectId(), *returns, "11", packages, handler). + WithArguments([]sdk.ProcedureArgumentRequest{*argument}). + WithImports([]sdk.ProcedureImportRequest{*sdk.NewProcedureImportRequest(importPath)}) + + err := client.Procedures.CreateForJava(ctx, requestStaged) + require.NoError(t, err) + t.Cleanup(testClientHelper().Procedure.DropProcedureFunc(t, id)) + + function, err := client.Procedures.ShowByID(ctx, id) + require.NoError(t, err) + + assertions.AssertThatObject(t, objectassert.ProcedureFromObject(t, function). + HasCreatedOnNotEmpty(). + HasName(id.Name()). + HasSchemaName(id.SchemaName()). + HasIsBuiltin(false). + HasIsAggregate(false). + HasIsAnsi(false). + HasMinNumArguments(1). + HasMaxNumArguments(1). + HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). + HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). + HasDescription(sdk.DefaultProcedureComment). + HasCatalogName(id.DatabaseName()). + HasIsTableFunction(false). + HasValidForClustering(false). + HasIsSecure(false). + HasExternalAccessIntegrationsNil(). + HasSecretsNil(), + ) + + assertions.AssertThatObject(t, objectassert.ProcedureDetails(t, function.ID()). + HasSignature(fmt.Sprintf(`(%s %s)`, argName, dataType.ToLegacyDataTypeSql())). + HasReturns(dataType.ToSql()). + HasLanguage("JAVA"). + HasBodyNil(). + HasNullHandling(string(sdk.NullInputBehaviorCalledOnNullInput)). + HasVolatility(string(sdk.ReturnResultsBehaviorVolatile)). + HasExternalAccessIntegrationsNil(). + HasSecretsNil(). + HasImports(fmt.Sprintf(`[%s]`, importPath)). + HasHandler(handler). + HasRuntimeVersion("11"). + HasPackages(`[com.snowflake:snowpark:1.14.0,com.snowflake:telemetry:0.1.0]`). + HasTargetPathNil(). + HasInstalledPackagesNil(). + HasExecuteAs("OWNER"), + ) + + assertions.AssertThatObject(t, objectparametersassert.ProcedureParameters(t, id). + HasAllDefaults(). + HasAllDefaultsExplicit(), + ) + }) + + t.Run("create procedure for Java - staged full", func(t *testing.T) { + dataType := tmpJavaProcedure.ArgType + id := testClientHelper().Ids.RandomSchemaObjectIdentifierWithArguments(sdk.LegacyDataTypeFrom(dataType)) + + argName := "x" + argument := sdk.NewProcedureArgumentRequest(argName, dataType) + dt := sdk.NewProcedureReturnsResultDataTypeRequest(dataType). + WithNotNull(true) + returns := sdk.NewProcedureReturnsRequest().WithResultDataType(*dt) + handler := tmpJavaProcedure.JavaHandler() + packages := []sdk.ProcedurePackageRequest{ + *sdk.NewProcedurePackageRequest("com.snowflake:snowpark:1.14.0"), + *sdk.NewProcedurePackageRequest("com.snowflake:telemetry:0.1.0"), + } + + requestStaged := sdk.NewCreateForJavaProcedureRequest(id.SchemaObjectId(), *returns, "11", packages, handler). + WithOrReplace(true). + WithArguments([]sdk.ProcedureArgumentRequest{*argument}). + WithCopyGrants(true). + WithNullInputBehavior(*sdk.NullInputBehaviorPointer(sdk.NullInputBehaviorReturnsNullInput)). + WithReturnResultsBehavior(sdk.ReturnResultsBehaviorImmutable). + WithComment("comment"). + WithImports([]sdk.ProcedureImportRequest{*sdk.NewProcedureImportRequest(tmpJavaProcedure.JarLocation())}). + WithExternalAccessIntegrations([]sdk.AccountObjectIdentifier{externalAccessIntegration}). + WithSecrets([]sdk.SecretReference{{VariableName: "abc", Name: secretId}}) + + err := client.Procedures.CreateForJava(ctx, requestStaged) + require.NoError(t, err) + t.Cleanup(testClientHelper().Procedure.DropProcedureFunc(t, id)) + + function, err := client.Procedures.ShowByID(ctx, id) + require.NoError(t, err) + + assertions.AssertThatObject(t, objectassert.ProcedureFromObject(t, function). + HasCreatedOnNotEmpty(). + HasName(id.Name()). + HasSchemaName(id.SchemaName()). + HasIsBuiltin(false). + HasIsAggregate(false). + HasIsAnsi(false). + HasMinNumArguments(1). + HasMaxNumArguments(1). + HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). + HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). + HasDescription("comment"). + HasCatalogName(id.DatabaseName()). + HasIsTableFunction(false). + HasValidForClustering(false). + HasIsSecure(false). + HasExternalAccessIntegrationsNil(). + HasSecretsNil(), + ) + + assertions.AssertThatObject(t, objectassert.ProcedureDetails(t, function.ID()). + HasSignature(fmt.Sprintf(`(%s %s)`, argName, dataType.ToLegacyDataTypeSql())). + HasReturns(fmt.Sprintf(`%s NOT NULL`, dataType.ToSql())). + HasLanguage("JAVA"). + HasBodyNil(). + HasNullHandling(string(sdk.NullInputBehaviorReturnsNullInput)). + HasVolatility(string(sdk.ReturnResultsBehaviorImmutable)). + HasExactlyExternalAccessIntegrations(externalAccessIntegration). + HasExactlySecrets(map[string]sdk.SchemaObjectIdentifier{"abc": secretId}). + HasImports(fmt.Sprintf(`[%s]`, tmpJavaProcedure.JarLocation())). + HasHandler(handler). + HasRuntimeVersion("11"). + HasPackages(`[com.snowflake:snowpark:1.14.0,com.snowflake:telemetry:0.1.0]`). + HasTargetPathNil(). + HasInstalledPackagesNil(). + HasExecuteAs("OWNER"), + ) + + assertions.AssertThatObject(t, objectparametersassert.ProcedureParameters(t, id). + HasAllDefaults(). + HasAllDefaultsExplicit(), + ) + }) + + t.Run("create procedure for Javascript - inline minimal", func(t *testing.T) { + dataType := testdatatypes.DataTypeFloat + id := testClientHelper().Ids.RandomSchemaObjectIdentifierWithArguments(sdk.LegacyDataTypeFrom(dataType)) + + argName := "d" + definition := testClientHelper().Procedure.SampleJavascriptDefinition(t, argName) + argument := sdk.NewProcedureArgumentRequest(argName, dataType) + + request := sdk.NewCreateForJavaScriptProcedureRequestDefinitionWrapped(id.SchemaObjectId(), dataType, definition). + WithArguments([]sdk.ProcedureArgumentRequest{*argument}) + + err := client.Procedures.CreateForJavaScript(ctx, request) require.NoError(t, err) - require.GreaterOrEqual(t, len(procedures), 1) + t.Cleanup(testClientHelper().Procedure.DropProcedureFunc(t, id)) + + function, err := client.Procedures.ShowByID(ctx, id) + require.NoError(t, err) + + assertions.AssertThatObject(t, objectassert.ProcedureFromObject(t, function). + HasCreatedOnNotEmpty(). + HasName(id.Name()). + HasSchemaName(id.SchemaName()). + HasIsBuiltin(false). + HasIsAggregate(false). + HasIsAnsi(false). + HasMinNumArguments(1). + HasMaxNumArguments(1). + HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). + HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). + HasDescription(sdk.DefaultProcedureComment). + HasCatalogName(id.DatabaseName()). + HasIsTableFunction(false). + HasValidForClustering(false). + HasIsSecure(false). + HasExternalAccessIntegrationsNil(). + HasSecretsNil(), + ) + + assertions.AssertThatObject(t, objectassert.ProcedureDetails(t, function.ID()). + HasSignature(fmt.Sprintf(`(%s %s)`, argName, dataType.ToLegacyDataTypeSql())). + HasReturns(dataType.ToSql()). + HasLanguage("JAVASCRIPT"). + HasBody(definition). + HasNullHandling(string(sdk.NullInputBehaviorCalledOnNullInput)). + HasVolatility(string(sdk.ReturnResultsBehaviorVolatile)). + HasExternalAccessIntegrationsNil(). + HasSecretsNil(). + HasImportsNil(). + HasHandlerNil(). + HasRuntimeVersionNil(). + HasPackagesNil(). + HasTargetPathNil(). + HasInstalledPackagesNil(). + HasExecuteAs("OWNER"), + ) + + assertions.AssertThatObject(t, objectparametersassert.ProcedureParameters(t, id). + HasAllDefaults(). + HasAllDefaultsExplicit(), + ) + }) + + t.Run("create procedure for Javascript - inline full", func(t *testing.T) { + dataType := testdatatypes.DataTypeFloat + id := testClientHelper().Ids.RandomSchemaObjectIdentifierWithArguments(sdk.LegacyDataTypeFrom(dataType)) + + argName := "d" + definition := testClientHelper().Procedure.SampleJavascriptDefinition(t, argName) + argument := sdk.NewProcedureArgumentRequest(argName, dataType) + request := sdk.NewCreateForJavaScriptProcedureRequestDefinitionWrapped(id.SchemaObjectId(), dataType, definition). + WithOrReplace(true). + WithArguments([]sdk.ProcedureArgumentRequest{*argument}). + WithCopyGrants(true). + WithNotNull(true). + WithNullInputBehavior(*sdk.NullInputBehaviorPointer(sdk.NullInputBehaviorReturnsNullInput)). + WithReturnResultsBehavior(sdk.ReturnResultsBehaviorImmutable). + WithExecuteAs(sdk.ExecuteAsCaller). + WithComment("comment") + + err := client.Procedures.CreateForJavaScript(ctx, request) + require.NoError(t, err) + t.Cleanup(testClientHelper().Procedure.DropProcedureFunc(t, id)) + + function, err := client.Procedures.ShowByID(ctx, id) + require.NoError(t, err) + + assertions.AssertThatObject(t, objectassert.ProcedureFromObject(t, function). + HasCreatedOnNotEmpty(). + HasName(id.Name()). + HasSchemaName(id.SchemaName()). + HasIsBuiltin(false). + HasIsAggregate(false). + HasIsAnsi(false). + HasMinNumArguments(1). + HasMaxNumArguments(1). + HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). + HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). + HasDescription("comment"). + HasCatalogName(id.DatabaseName()). + HasIsTableFunction(false). + HasValidForClustering(false). + HasIsSecure(false). + HasExternalAccessIntegrationsNil(). + HasSecretsNil(), + ) + + assertions.AssertThatObject(t, objectassert.ProcedureDetails(t, function.ID()). + HasSignature(fmt.Sprintf(`(%s %s)`, argName, dataType.ToLegacyDataTypeSql())). + HasReturns(fmt.Sprintf(`%s NOT NULL`, dataType.ToSql())). + HasLanguage("JAVASCRIPT"). + HasBody(definition). + HasNullHandling(string(sdk.NullInputBehaviorReturnsNullInput)). + HasVolatility(string(sdk.ReturnResultsBehaviorImmutable)). + HasExternalAccessIntegrationsNil(). + HasSecretsNil(). + HasImportsNil(). + HasHandlerNil(). + HasRuntimeVersionNil(). + HasPackagesNil(). + HasTargetPathNil(). + HasInstalledPackagesNil(). + HasExecuteAs("CALLER"), + ) + + assertions.AssertThatObject(t, objectparametersassert.ProcedureParameters(t, id). + HasAllDefaults(). + HasAllDefaultsExplicit(), + ) + }) + + t.Run("create procedure for Python - inline minimal", func(t *testing.T) { + dataType := testdatatypes.DataTypeNumber_36_2 + id := testClientHelper().Ids.RandomSchemaObjectIdentifierWithArguments(sdk.LegacyDataTypeFrom(dataType)) + + argName := "i" + funcName := "dump" + definition := testClientHelper().Procedure.SamplePythonDefinition(t, funcName, argName) + dt := sdk.NewProcedureReturnsResultDataTypeRequest(dataType) + returns := sdk.NewProcedureReturnsRequest().WithResultDataType(*dt) + argument := sdk.NewProcedureArgumentRequest(argName, dataType) + packages := []sdk.ProcedurePackageRequest{ + *sdk.NewProcedurePackageRequest("snowflake-snowpark-python==1.14.0"), + } + request := sdk.NewCreateForPythonProcedureRequest(id.SchemaObjectId(), *returns, "3.8", packages, funcName). + WithArguments([]sdk.ProcedureArgumentRequest{*argument}). + WithProcedureDefinitionWrapped(definition) + + err := client.Procedures.CreateForPython(ctx, request) + require.NoError(t, err) + t.Cleanup(testClientHelper().Procedure.DropProcedureFunc(t, id)) + + function, err := client.Procedures.ShowByID(ctx, id) + require.NoError(t, err) + + assertions.AssertThatObject(t, objectassert.ProcedureFromObject(t, function). + HasCreatedOnNotEmpty(). + HasName(id.Name()). + HasSchemaName(id.SchemaName()). + HasIsBuiltin(false). + HasIsAggregate(false). + HasIsAnsi(false). + HasMinNumArguments(1). + HasMaxNumArguments(1). + HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). + HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). + HasDescription(sdk.DefaultProcedureComment). + HasCatalogName(id.DatabaseName()). + HasIsTableFunction(false). + HasValidForClustering(false). + HasIsSecure(false). + HasExternalAccessIntegrationsNil(). + HasSecretsNil(), + ) + + assertions.AssertThatObject(t, objectassert.ProcedureDetails(t, function.ID()). + HasSignature(fmt.Sprintf(`(%s %s)`, argName, dataType.ToLegacyDataTypeSql())). + HasReturns(strings.ReplaceAll(dataType.ToSql(), " ", "")). + HasLanguage("PYTHON"). + HasBody(definition). + HasNullHandling(string(sdk.NullInputBehaviorCalledOnNullInput)). + HasVolatility(string(sdk.ReturnResultsBehaviorVolatile)). + HasExternalAccessIntegrationsNil(). + HasSecretsNil(). + HasImports(`[]`). + HasHandler(funcName). + HasRuntimeVersion("3.8"). + HasPackages(`['snowflake-snowpark-python==1.14.0']`). + HasTargetPathNil(). + HasInstalledPackagesNotEmpty(). + HasExecuteAs("OWNER"), + ) + + assertions.AssertThatObject(t, objectparametersassert.ProcedureParameters(t, id). + HasAllDefaults(). + HasAllDefaultsExplicit(), + ) + }) + + t.Run("create procedure for Python - inline full", func(t *testing.T) { + dataType := testdatatypes.DataTypeNumber_36_2 + id := testClientHelper().Ids.RandomSchemaObjectIdentifierWithArguments(sdk.LegacyDataTypeFrom(dataType)) + + argName := "i" + funcName := "dump" + definition := testClientHelper().Procedure.SamplePythonDefinition(t, funcName, argName) + dt := sdk.NewProcedureReturnsResultDataTypeRequest(dataType). + WithNotNull(true) + returns := sdk.NewProcedureReturnsRequest().WithResultDataType(*dt) + argument := sdk.NewProcedureArgumentRequest(argName, dataType) + packages := []sdk.ProcedurePackageRequest{ + *sdk.NewProcedurePackageRequest("snowflake-snowpark-python==1.14.0"), + *sdk.NewProcedurePackageRequest("absl-py==0.10.0"), + } + + request := sdk.NewCreateForPythonProcedureRequest(id.SchemaObjectId(), *returns, "3.8", packages, funcName). + WithOrReplace(true). + WithArguments([]sdk.ProcedureArgumentRequest{*argument}). + WithCopyGrants(true). + WithNullInputBehavior(*sdk.NullInputBehaviorPointer(sdk.NullInputBehaviorReturnsNullInput)). + WithReturnResultsBehavior(sdk.ReturnResultsBehaviorImmutable). + WithComment("comment"). + WithImports([]sdk.ProcedureImportRequest{*sdk.NewProcedureImportRequest(tmpPythonFunction.PythonModuleLocation())}). + WithExternalAccessIntegrations([]sdk.AccountObjectIdentifier{externalAccessIntegration}). + WithSecrets([]sdk.SecretReference{{VariableName: "abc", Name: secretId}}). + WithExecuteAs(sdk.ExecuteAsCaller). + WithProcedureDefinitionWrapped(definition) + + err := client.Procedures.CreateForPython(ctx, request) + require.NoError(t, err) + t.Cleanup(testClientHelper().Procedure.DropProcedureFunc(t, id)) + + function, err := client.Procedures.ShowByID(ctx, id) + require.NoError(t, err) + + assertions.AssertThatObject(t, objectassert.ProcedureFromObject(t, function). + HasCreatedOnNotEmpty(). + HasName(id.Name()). + HasSchemaName(id.SchemaName()). + HasIsBuiltin(false). + HasIsAggregate(false). + HasIsAnsi(false). + HasMinNumArguments(1). + HasMaxNumArguments(1). + HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). + HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). + HasDescription("comment"). + HasCatalogName(id.DatabaseName()). + HasIsTableFunction(false). + HasValidForClustering(false). + HasIsSecure(false). + HasExternalAccessIntegrationsNil(). + HasSecretsNil(), + ) + + assertions.AssertThatObject(t, objectassert.ProcedureDetails(t, function.ID()). + HasSignature(fmt.Sprintf(`(%s %s)`, argName, dataType.ToLegacyDataTypeSql())). + HasReturns(strings.ReplaceAll(dataType.ToSql(), " ", "")+" NOT NULL"). + HasLanguage("PYTHON"). + HasBody(definition). + HasNullHandling(string(sdk.NullInputBehaviorReturnsNullInput)). + HasVolatility(string(sdk.ReturnResultsBehaviorImmutable)). + HasExactlyExternalAccessIntegrations(externalAccessIntegration). + HasExactlySecrets(map[string]sdk.SchemaObjectIdentifier{"abc": secretId}). + HasImports(fmt.Sprintf(`[%s]`, tmpPythonFunction.PythonModuleLocation())). + HasHandler(funcName). + HasRuntimeVersion("3.8"). + HasPackages(`['snowflake-snowpark-python==1.14.0','absl-py==0.10.0']`). + HasTargetPathNil(). + HasInstalledPackagesNotEmpty(). + HasExecuteAs("CALLER"), + ) + + assertions.AssertThatObject(t, objectparametersassert.ProcedureParameters(t, id). + HasAllDefaults(). + HasAllDefaultsExplicit(), + ) + }) + + t.Run("create procedure for Python - staged minimal", func(t *testing.T) { + dataType := testdatatypes.DataTypeVarchar_100 + id := testClientHelper().Ids.RandomSchemaObjectIdentifierWithArguments(sdk.LegacyDataTypeFrom(dataType)) + + argName := "i" + dt := sdk.NewProcedureReturnsResultDataTypeRequest(dataType) + returns := sdk.NewProcedureReturnsRequest().WithResultDataType(*dt) + argument := sdk.NewProcedureArgumentRequest(argName, dataType) + packages := []sdk.ProcedurePackageRequest{ + *sdk.NewProcedurePackageRequest("snowflake-snowpark-python==1.14.0"), + } + request := sdk.NewCreateForPythonProcedureRequest(id.SchemaObjectId(), *returns, "3.8", packages, tmpPythonFunction.PythonHandler()). + WithArguments([]sdk.ProcedureArgumentRequest{*argument}). + WithImports([]sdk.ProcedureImportRequest{*sdk.NewProcedureImportRequest(tmpPythonFunction.PythonModuleLocation())}) + + err := client.Procedures.CreateForPython(ctx, request) + require.NoError(t, err) + t.Cleanup(testClientHelper().Procedure.DropProcedureFunc(t, id)) + + function, err := client.Procedures.ShowByID(ctx, id) + require.NoError(t, err) + + assertions.AssertThatObject(t, objectassert.ProcedureFromObject(t, function). + HasCreatedOnNotEmpty(). + HasName(id.Name()). + HasSchemaName(id.SchemaName()). + HasIsBuiltin(false). + HasIsAggregate(false). + HasIsAnsi(false). + HasMinNumArguments(1). + HasMaxNumArguments(1). + HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). + HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). + HasDescription(sdk.DefaultProcedureComment). + HasCatalogName(id.DatabaseName()). + HasIsTableFunction(false). + HasValidForClustering(false). + HasIsSecure(false). + HasExternalAccessIntegrationsNil(). + HasSecretsNil(), + ) + + assertions.AssertThatObject(t, objectassert.ProcedureDetails(t, function.ID()). + HasSignature(fmt.Sprintf(`(%s %s)`, argName, dataType.ToLegacyDataTypeSql())). + HasReturns(strings.ReplaceAll(dataType.ToSql(), " ", "")). + HasLanguage("PYTHON"). + HasBodyNil(). + HasNullHandling(string(sdk.NullInputBehaviorCalledOnNullInput)). + HasVolatility(string(sdk.ReturnResultsBehaviorVolatile)). + HasExternalAccessIntegrationsNil(). + HasSecretsNil(). + HasImports(fmt.Sprintf(`[%s]`, tmpPythonFunction.PythonModuleLocation())). + HasHandler(tmpPythonFunction.PythonHandler()). + HasRuntimeVersion("3.8"). + HasPackages(`['snowflake-snowpark-python==1.14.0']`). + HasTargetPathNil(). + HasInstalledPackagesNotEmpty(). + HasExecuteAs("OWNER"), + ) + + assertions.AssertThatObject(t, objectparametersassert.ProcedureParameters(t, id). + HasAllDefaults(). + HasAllDefaultsExplicit(), + ) + }) + + t.Run("create procedure for Python - staged full", func(t *testing.T) { + dataType := testdatatypes.DataTypeVarchar_100 + id := testClientHelper().Ids.RandomSchemaObjectIdentifierWithArguments(sdk.LegacyDataTypeFrom(dataType)) + + argName := "i" + dt := sdk.NewProcedureReturnsResultDataTypeRequest(dataType). + WithNotNull(true) + returns := sdk.NewProcedureReturnsRequest().WithResultDataType(*dt) + argument := sdk.NewProcedureArgumentRequest(argName, dataType) + packages := []sdk.ProcedurePackageRequest{ + *sdk.NewProcedurePackageRequest("snowflake-snowpark-python==1.14.0"), + *sdk.NewProcedurePackageRequest("absl-py==0.10.0"), + } + + request := sdk.NewCreateForPythonProcedureRequest(id.SchemaObjectId(), *returns, "3.8", packages, tmpPythonFunction.PythonHandler()). + WithOrReplace(true). + WithArguments([]sdk.ProcedureArgumentRequest{*argument}). + WithCopyGrants(true). + WithNullInputBehavior(*sdk.NullInputBehaviorPointer(sdk.NullInputBehaviorReturnsNullInput)). + WithReturnResultsBehavior(sdk.ReturnResultsBehaviorImmutable). + WithComment("comment"). + WithExternalAccessIntegrations([]sdk.AccountObjectIdentifier{externalAccessIntegration}). + WithSecrets([]sdk.SecretReference{{VariableName: "abc", Name: secretId}}). + WithImports([]sdk.ProcedureImportRequest{*sdk.NewProcedureImportRequest(tmpPythonFunction.PythonModuleLocation())}). + WithExecuteAs(sdk.ExecuteAsCaller) + + err := client.Procedures.CreateForPython(ctx, request) + require.NoError(t, err) + t.Cleanup(testClientHelper().Procedure.DropProcedureFunc(t, id)) + + function, err := client.Procedures.ShowByID(ctx, id) + require.NoError(t, err) + + assertions.AssertThatObject(t, objectassert.ProcedureFromObject(t, function). + HasCreatedOnNotEmpty(). + HasName(id.Name()). + HasSchemaName(id.SchemaName()). + HasIsBuiltin(false). + HasIsAggregate(false). + HasIsAnsi(false). + HasMinNumArguments(1). + HasMaxNumArguments(1). + HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). + HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). + HasDescription("comment"). + HasCatalogName(id.DatabaseName()). + HasIsTableFunction(false). + HasValidForClustering(false). + HasIsSecure(false). + HasExternalAccessIntegrationsNil(). + HasSecretsNil(), + ) + + assertions.AssertThatObject(t, objectassert.ProcedureDetails(t, function.ID()). + HasSignature(fmt.Sprintf(`(%s %s)`, argName, dataType.ToLegacyDataTypeSql())). + HasReturns(strings.ReplaceAll(dataType.ToSql(), " ", "")+" NOT NULL"). + HasLanguage("PYTHON"). + HasBodyNil(). + HasNullHandling(string(sdk.NullInputBehaviorReturnsNullInput)). + HasVolatility(string(sdk.ReturnResultsBehaviorImmutable)). + HasExactlyExternalAccessIntegrations(externalAccessIntegration). + HasExactlySecrets(map[string]sdk.SchemaObjectIdentifier{"abc": secretId}). + HasImports(fmt.Sprintf(`[%s]`, tmpPythonFunction.PythonModuleLocation())). + HasHandler(tmpPythonFunction.PythonHandler()). + HasRuntimeVersion("3.8"). + HasPackages(`['snowflake-snowpark-python==1.14.0','absl-py==0.10.0']`). + HasTargetPathNil(). + HasInstalledPackagesNotEmpty(). + HasExecuteAs("CALLER"), + ) + + assertions.AssertThatObject(t, objectparametersassert.ProcedureParameters(t, id). + HasAllDefaults(). + HasAllDefaultsExplicit(), + ) + }) + + t.Run("create procedure for Scala - inline minimal", func(t *testing.T) { + className := "TestFunc" + funcName := "echoVarchar" + argName := "x" + dataType := testdatatypes.DataTypeVarchar_100 + + id := testClientHelper().Ids.RandomSchemaObjectIdentifierWithArguments(sdk.LegacyDataTypeFrom(dataType)) + + dt := sdk.NewProcedureReturnsResultDataTypeRequest(dataType) + returns := sdk.NewProcedureReturnsRequest().WithResultDataType(*dt) + definition := testClientHelper().Procedure.SampleScalaDefinition(t, className, funcName, argName) + argument := sdk.NewProcedureArgumentRequest(argName, dataType) + handler := fmt.Sprintf("%s.%s", className, funcName) + packages := []sdk.ProcedurePackageRequest{*sdk.NewProcedurePackageRequest("com.snowflake:snowpark:1.14.0")} + + request := sdk.NewCreateForScalaProcedureRequest(id.SchemaObjectId(), *returns, "2.12", packages, handler). + WithArguments([]sdk.ProcedureArgumentRequest{*argument}). + WithProcedureDefinitionWrapped(definition) + + err := client.Procedures.CreateForScala(ctx, request) + require.NoError(t, err) + t.Cleanup(testClientHelper().Procedure.DropProcedureFunc(t, id)) + + function, err := client.Procedures.ShowByID(ctx, id) + require.NoError(t, err) + + assertions.AssertThatObject(t, objectassert.ProcedureFromObject(t, function). + HasCreatedOnNotEmpty(). + HasName(id.Name()). + HasSchemaName(id.SchemaName()). + HasIsBuiltin(false). + HasIsAggregate(false). + HasIsAnsi(false). + HasMinNumArguments(1). + HasMaxNumArguments(1). + HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). + HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). + HasDescription(sdk.DefaultProcedureComment). + HasCatalogName(id.DatabaseName()). + HasIsTableFunction(false). + HasValidForClustering(false). + HasIsSecure(false). + HasExternalAccessIntegrationsNil(). + HasSecretsNil(), + ) + + assertions.AssertThatObject(t, objectassert.ProcedureDetails(t, function.ID()). + HasSignature(fmt.Sprintf(`(%s %s)`, argName, dataType.ToLegacyDataTypeSql())). + HasReturns(dataType.ToSql()). + HasLanguage("SCALA"). + HasBody(definition). + HasNullHandling(string(sdk.NullInputBehaviorCalledOnNullInput)). + HasVolatility(string(sdk.ReturnResultsBehaviorVolatile)). + HasExternalAccessIntegrationsNil(). + HasSecretsNil(). + HasImports(`[]`). + HasHandler(handler). + HasRuntimeVersion("2.12"). + HasPackages(`[com.snowflake:snowpark:1.14.0]`). + HasTargetPathNil(). + HasInstalledPackagesNil(). + HasExecuteAs("OWNER"), + ) + + assertions.AssertThatObject(t, objectparametersassert.ProcedureParameters(t, id). + HasAllDefaults(). + HasAllDefaultsExplicit(), + ) + }) + + t.Run("create procedure for Scala - inline full", func(t *testing.T) { + className := "TestFunc" + funcName := "echoVarchar" + argName := "x" + dataType := testdatatypes.DataTypeVarchar_100 + + id := testClientHelper().Ids.RandomSchemaObjectIdentifierWithArguments(sdk.LegacyDataTypeFrom(dataType)) + + dt := sdk.NewProcedureReturnsResultDataTypeRequest(dataType). + WithNotNull(true) + returns := sdk.NewProcedureReturnsRequest().WithResultDataType(*dt) + definition := testClientHelper().Procedure.SampleScalaDefinition(t, className, funcName, argName) + argument := sdk.NewProcedureArgumentRequest(argName, dataType) + handler := fmt.Sprintf("%s.%s", className, funcName) + jarName := fmt.Sprintf("tf-%d-%s.jar", time.Now().Unix(), random.AlphaN(5)) + targetPath := fmt.Sprintf("@~/%s", jarName) + packages := []sdk.ProcedurePackageRequest{ + *sdk.NewProcedurePackageRequest("com.snowflake:snowpark:1.14.0"), + *sdk.NewProcedurePackageRequest("com.snowflake:telemetry:0.1.0"), + } + + request := sdk.NewCreateForScalaProcedureRequest(id.SchemaObjectId(), *returns, "2.12", packages, handler). + WithOrReplace(true). + WithArguments([]sdk.ProcedureArgumentRequest{*argument}). + WithCopyGrants(true). + WithNullInputBehavior(*sdk.NullInputBehaviorPointer(sdk.NullInputBehaviorReturnsNullInput)). + WithReturnResultsBehavior(sdk.ReturnResultsBehaviorImmutable). + WithComment("comment"). + WithImports([]sdk.ProcedureImportRequest{*sdk.NewProcedureImportRequest(tmpJavaProcedure.JarLocation())}). + WithTargetPath(targetPath). + WithExecuteAs(sdk.ExecuteAsCaller). + WithExternalAccessIntegrations([]sdk.AccountObjectIdentifier{externalAccessIntegration}). + WithSecrets([]sdk.SecretReference{{VariableName: "abc", Name: secretId}}). + WithProcedureDefinitionWrapped(definition) + + err := client.Procedures.CreateForScala(ctx, request) + require.NoError(t, err) + t.Cleanup(testClientHelper().Procedure.DropProcedureFunc(t, id)) + t.Cleanup(testClientHelper().Stage.RemoveFromUserStageFunc(t, jarName)) + + function, err := client.Procedures.ShowByID(ctx, id) + require.NoError(t, err) + + assertions.AssertThatObject(t, objectassert.ProcedureFromObject(t, function). + HasCreatedOnNotEmpty(). + HasName(id.Name()). + HasSchemaName(id.SchemaName()). + HasIsBuiltin(false). + HasIsAggregate(false). + HasIsAnsi(false). + HasMinNumArguments(1). + HasMaxNumArguments(1). + HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). + HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). + HasDescription("comment"). + HasCatalogName(id.DatabaseName()). + HasIsTableFunction(false). + HasValidForClustering(false). + HasIsSecure(false). + HasExternalAccessIntegrationsNil(). + HasSecretsNil(), + ) + + assertions.AssertThatObject(t, objectassert.ProcedureDetails(t, function.ID()). + HasSignature(fmt.Sprintf(`(%s %s)`, argName, dataType.ToLegacyDataTypeSql())). + HasReturns(fmt.Sprintf(`%s NOT NULL`, dataType.ToSql())). + HasLanguage("SCALA"). + HasBody(definition). + HasNullHandling(string(sdk.NullInputBehaviorReturnsNullInput)). + HasVolatility(string(sdk.ReturnResultsBehaviorImmutable)). + HasExactlyExternalAccessIntegrations(externalAccessIntegration). + HasExactlySecrets(map[string]sdk.SchemaObjectIdentifier{"abc": secretId}). + HasImports(fmt.Sprintf(`[%s]`, tmpJavaProcedure.JarLocation())). + HasHandler(handler). + HasRuntimeVersion("2.12"). + HasPackages(`[com.snowflake:snowpark:1.14.0,com.snowflake:telemetry:0.1.0]`). + HasTargetPath(targetPath). + HasInstalledPackagesNil(). + HasExecuteAs("CALLER"), + ) + + assertions.AssertThatObject(t, objectparametersassert.ProcedureParameters(t, id). + HasAllDefaults(). + HasAllDefaultsExplicit(), + ) + }) + + t.Run("create procedure for Scala - staged minimal", func(t *testing.T) { + dataType := tmpJavaProcedure.ArgType + id := testClientHelper().Ids.RandomSchemaObjectIdentifierWithArguments(sdk.LegacyDataTypeFrom(dataType)) + + argName := "x" + argument := sdk.NewProcedureArgumentRequest(argName, dataType) + dt := sdk.NewProcedureReturnsResultDataTypeRequest(dataType) + returns := sdk.NewProcedureReturnsRequest().WithResultDataType(*dt) + handler := tmpJavaProcedure.JavaHandler() + importPath := tmpJavaProcedure.JarLocation() + packages := []sdk.ProcedurePackageRequest{*sdk.NewProcedurePackageRequest("com.snowflake:snowpark:1.14.0")} + + requestStaged := sdk.NewCreateForScalaProcedureRequest(id.SchemaObjectId(), *returns, "2.12", packages, handler). + WithArguments([]sdk.ProcedureArgumentRequest{*argument}). + WithImports([]sdk.ProcedureImportRequest{*sdk.NewProcedureImportRequest(importPath)}) + + err := client.Procedures.CreateForScala(ctx, requestStaged) + require.NoError(t, err) + t.Cleanup(testClientHelper().Procedure.DropProcedureFunc(t, id)) + + function, err := client.Procedures.ShowByID(ctx, id) + require.NoError(t, err) + + assertions.AssertThatObject(t, objectassert.ProcedureFromObject(t, function). + HasCreatedOnNotEmpty(). + HasName(id.Name()). + HasSchemaName(id.SchemaName()). + HasIsBuiltin(false). + HasIsAggregate(false). + HasIsAnsi(false). + HasMinNumArguments(1). + HasMaxNumArguments(1). + HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). + HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). + HasDescription(sdk.DefaultProcedureComment). + HasCatalogName(id.DatabaseName()). + HasIsTableFunction(false). + HasValidForClustering(false). + HasIsSecure(false). + HasExternalAccessIntegrationsNil(). + HasSecretsNil(), + ) + + assertions.AssertThatObject(t, objectassert.ProcedureDetails(t, function.ID()). + HasSignature(fmt.Sprintf(`(%s %s)`, argName, dataType.ToLegacyDataTypeSql())). + HasReturns(dataType.ToSql()). + HasLanguage("SCALA"). + HasBodyNil(). + HasNullHandling(string(sdk.NullInputBehaviorCalledOnNullInput)). + HasVolatility(string(sdk.ReturnResultsBehaviorVolatile)). + HasExternalAccessIntegrationsNil(). + HasSecretsNil(). + HasImports(fmt.Sprintf(`[%s]`, importPath)). + HasHandler(handler). + HasRuntimeVersion("2.12"). + HasPackages(`[com.snowflake:snowpark:1.14.0]`). + HasTargetPathNil(). + HasInstalledPackagesNil(). + HasExecuteAs("OWNER"), + ) + + assertions.AssertThatObject(t, objectparametersassert.ProcedureParameters(t, id). + HasAllDefaults(). + HasAllDefaultsExplicit(), + ) + }) + + t.Run("create procedure for Scala - staged full", func(t *testing.T) { + dataType := tmpJavaProcedure.ArgType + id := testClientHelper().Ids.RandomSchemaObjectIdentifierWithArguments(sdk.LegacyDataTypeFrom(dataType)) + + argName := "x" + argument := sdk.NewProcedureArgumentRequest(argName, dataType) + handler := tmpJavaProcedure.JavaHandler() + + dt := sdk.NewProcedureReturnsResultDataTypeRequest(dataType). + WithNotNull(true) + returns := sdk.NewProcedureReturnsRequest().WithResultDataType(*dt) + packages := []sdk.ProcedurePackageRequest{ + *sdk.NewProcedurePackageRequest("com.snowflake:snowpark:1.14.0"), + *sdk.NewProcedurePackageRequest("com.snowflake:telemetry:0.1.0"), + } + + requestStaged := sdk.NewCreateForScalaProcedureRequest(id.SchemaObjectId(), *returns, "2.12", packages, handler). + WithOrReplace(true). + WithArguments([]sdk.ProcedureArgumentRequest{*argument}). + WithCopyGrants(true). + WithNullInputBehavior(*sdk.NullInputBehaviorPointer(sdk.NullInputBehaviorReturnsNullInput)). + WithReturnResultsBehavior(sdk.ReturnResultsBehaviorImmutable). + WithComment("comment"). + WithExecuteAs(sdk.ExecuteAsCaller). + WithExternalAccessIntegrations([]sdk.AccountObjectIdentifier{externalAccessIntegration}). + WithSecrets([]sdk.SecretReference{{VariableName: "abc", Name: secretId}}). + WithImports([]sdk.ProcedureImportRequest{*sdk.NewProcedureImportRequest(tmpJavaProcedure.JarLocation())}) + + err := client.Procedures.CreateForScala(ctx, requestStaged) + require.NoError(t, err) + t.Cleanup(testClientHelper().Procedure.DropProcedureFunc(t, id)) + + function, err := client.Procedures.ShowByID(ctx, id) + require.NoError(t, err) + + assertions.AssertThatObject(t, objectassert.ProcedureFromObject(t, function). + HasCreatedOnNotEmpty(). + HasName(id.Name()). + HasSchemaName(id.SchemaName()). + HasIsBuiltin(false). + HasIsAggregate(false). + HasIsAnsi(false). + HasMinNumArguments(1). + HasMaxNumArguments(1). + HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). + HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). + HasDescription("comment"). + HasCatalogName(id.DatabaseName()). + HasIsTableFunction(false). + HasValidForClustering(false). + HasIsSecure(false). + HasExternalAccessIntegrationsNil(). + HasSecretsNil(), + ) + + assertions.AssertThatObject(t, objectassert.ProcedureDetails(t, function.ID()). + HasSignature(fmt.Sprintf(`(%s %s)`, argName, dataType.ToLegacyDataTypeSql())). + HasReturns(fmt.Sprintf(`%s NOT NULL`, dataType.ToSql())). + HasLanguage("SCALA"). + HasBodyNil(). + HasNullHandling(string(sdk.NullInputBehaviorReturnsNullInput)). + HasVolatility(string(sdk.ReturnResultsBehaviorImmutable)). + HasExactlyExternalAccessIntegrations(externalAccessIntegration). + HasExactlySecrets(map[string]sdk.SchemaObjectIdentifier{"abc": secretId}). + HasImports(fmt.Sprintf(`[%s]`, tmpJavaProcedure.JarLocation())). + HasHandler(handler). + HasRuntimeVersion("2.12"). + HasPackages(`[com.snowflake:snowpark:1.14.0,com.snowflake:telemetry:0.1.0]`). + HasTargetPathNil(). + HasInstalledPackagesNil(). + HasExecuteAs("CALLER"), + ) + + assertions.AssertThatObject(t, objectparametersassert.ProcedureParameters(t, id). + HasAllDefaults(). + HasAllDefaultsExplicit(), + ) + }) + + t.Run("create procedure for SQL - inline minimal", func(t *testing.T) { + argName := "x" + dataType := testdatatypes.DataTypeFloat + id := testClientHelper().Ids.RandomSchemaObjectIdentifierWithArguments(sdk.LegacyDataTypeFrom(dataType)) + + definition := testClientHelper().Procedure.SampleSqlDefinition(t) + dt := sdk.NewProcedureReturnsResultDataTypeRequest(dataType) + returns := sdk.NewProcedureSQLReturnsRequest().WithResultDataType(*dt) + argument := sdk.NewProcedureArgumentRequest(argName, dataType) + request := sdk.NewCreateForSQLProcedureRequestDefinitionWrapped(id.SchemaObjectId(), *returns, definition). + WithArguments([]sdk.ProcedureArgumentRequest{*argument}) + + err := client.Procedures.CreateForSQL(ctx, request) + require.NoError(t, err) + t.Cleanup(testClientHelper().Procedure.DropProcedureFunc(t, id)) + + function, err := client.Procedures.ShowByID(ctx, id) + require.NoError(t, err) + + assertions.AssertThatObject(t, objectassert.ProcedureFromObject(t, function). + HasCreatedOnNotEmpty(). + HasName(id.Name()). + HasSchemaName(id.SchemaName()). + HasIsBuiltin(false). + HasIsAggregate(false). + HasIsAnsi(false). + HasMinNumArguments(1). + HasMaxNumArguments(1). + HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). + HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). + HasDescription(sdk.DefaultProcedureComment). + HasCatalogName(id.DatabaseName()). + HasIsTableFunction(false). + HasValidForClustering(false). + HasIsSecure(false). + HasExternalAccessIntegrationsNil(). + HasSecretsNil(), + ) + + assertions.AssertThatObject(t, objectassert.ProcedureDetails(t, function.ID()). + HasSignature(fmt.Sprintf(`(%s %s)`, argName, dataType.ToLegacyDataTypeSql())). + HasReturns(dataType.ToSql()). + HasLanguage("SQL"). + HasBody(definition). + HasNullHandlingNil(). + HasVolatilityNil(). + HasExternalAccessIntegrationsNil(). + HasSecretsNil(). + HasImportsNil(). + HasHandlerNil(). + HasRuntimeVersionNil(). + HasPackagesNil(). + HasTargetPathNil(). + HasInstalledPackagesNil(). + HasExecuteAs("OWNER"), + ) + + assertions.AssertThatObject(t, objectparametersassert.ProcedureParameters(t, id). + HasAllDefaults(). + HasAllDefaultsExplicit(), + ) + }) + + t.Run("create procedure for SQL - inline full", func(t *testing.T) { + argName := "x" + dataType := testdatatypes.DataTypeFloat + id := testClientHelper().Ids.RandomSchemaObjectIdentifierWithArguments(sdk.LegacyDataTypeFrom(dataType)) + + definition := testClientHelper().Procedure.SampleSqlDefinition(t) + dt := sdk.NewProcedureReturnsResultDataTypeRequest(dataType). + WithNotNull(true) + returns := sdk.NewProcedureSQLReturnsRequest().WithResultDataType(*dt) + argument := sdk.NewProcedureArgumentRequest(argName, dataType) + request := sdk.NewCreateForSQLProcedureRequestDefinitionWrapped(id.SchemaObjectId(), *returns, definition). + WithOrReplace(true). + WithArguments([]sdk.ProcedureArgumentRequest{*argument}). + WithCopyGrants(true). + WithNullInputBehavior(*sdk.NullInputBehaviorPointer(sdk.NullInputBehaviorReturnsNullInput)). + WithReturnResultsBehavior(sdk.ReturnResultsBehaviorImmutable). + WithExecuteAs(sdk.ExecuteAsCaller). + WithComment("comment") + + err := client.Procedures.CreateForSQL(ctx, request) + require.NoError(t, err) + t.Cleanup(testClientHelper().Procedure.DropProcedureFunc(t, id)) + + function, err := client.Procedures.ShowByID(ctx, id) + require.NoError(t, err) + + assertions.AssertThatObject(t, objectassert.ProcedureFromObject(t, function). + HasCreatedOnNotEmpty(). + HasName(id.Name()). + HasSchemaName(id.SchemaName()). + HasIsBuiltin(false). + HasIsAggregate(false). + HasIsAnsi(false). + HasMinNumArguments(1). + HasMaxNumArguments(1). + HasArgumentsOld([]sdk.DataType{sdk.LegacyDataTypeFrom(dataType)}). + HasArgumentsRaw(fmt.Sprintf(`%[1]s(%[2]s) RETURN %[2]s`, function.ID().Name(), dataType.ToLegacyDataTypeSql())). + HasDescription("comment"). + HasCatalogName(id.DatabaseName()). + HasIsTableFunction(false). + HasValidForClustering(false). + HasIsSecure(false). + HasExternalAccessIntegrationsNil(). + HasSecretsNil(), + ) + + assertions.AssertThatObject(t, objectassert.ProcedureDetails(t, function.ID()). + HasSignature(fmt.Sprintf(`(%s %s)`, argName, dataType.ToLegacyDataTypeSql())). + HasReturns(fmt.Sprintf(`%s NOT NULL`, dataType.ToSql())). + HasLanguage("SQL"). + HasBody(definition). + // TODO [SNOW-1348103]: null handling and volatility are not returned and is present in create syntax + HasNullHandlingNil(). + HasVolatilityNil(). + HasVolatilityNil(). + HasExternalAccessIntegrationsNil(). + HasSecretsNil(). + HasImportsNil(). + HasHandlerNil(). + HasRuntimeVersionNil(). + HasPackagesNil(). + HasTargetPathNil(). + HasInstalledPackagesNil(). + HasExecuteAs("CALLER"), + ) + + assertions.AssertThatObject(t, objectparametersassert.ProcedureParameters(t, id). + HasAllDefaults(). + HasAllDefaultsExplicit(), + ) }) + // TODO [SNOW-1348103]: adjust or remove t.Run("create procedure for Java: returns table", func(t *testing.T) { + t.Skipf("Skipped for now; left as inspiration for resource rework as part of SNOW-1348103") + // https://docs.snowflake.com/en/developer-guide/stored-procedure/stored-procedures-java#specifying-return-column-names-and-types name := "filter_by_role" id := testClientHelper().Ids.NewSchemaObjectIdentifierWithArguments(name, sdk.DataTypeVARCHAR, sdk.DataTypeVARCHAR) @@ -89,17 +1241,20 @@ func TestInt_CreateProcedures(t *testing.T) { request := sdk.NewCreateForJavaProcedureRequest(id.SchemaObjectId(), *returns, "11", packages, "Filter.filterByRole"). WithOrReplace(true). WithArguments([]sdk.ProcedureArgumentRequest{*arg1, *arg2}). - WithProcedureDefinition(definition) + WithProcedureDefinitionWrapped(definition) err := client.Procedures.CreateForJava(ctx, request) require.NoError(t, err) - t.Cleanup(cleanupProcedureHandle(id)) + t.Cleanup(testClientHelper().Procedure.DropProcedureFunc(t, id)) procedures, err := client.Procedures.Show(ctx, sdk.NewShowProcedureRequest()) require.NoError(t, err) require.GreaterOrEqual(t, len(procedures), 1) }) + // TODO [SNOW-1348103]: adjust or remove t.Run("create procedure for Javascript", func(t *testing.T) { + t.Skipf("Skipped for now; left as inspiration for resource rework as part of SNOW-1348103") + // https://docs.snowflake.com/en/developer-guide/stored-procedure/stored-procedures-javascript#basic-examples name := "stproc1" id := testClientHelper().Ids.NewSchemaObjectIdentifierWithArguments(name, sdk.DataTypeFloat) @@ -116,37 +1271,43 @@ func TestInt_CreateProcedures(t *testing.T) { return "Failed: " + err; // Return a success/error indicator. }` argument := sdk.NewProcedureArgumentRequest("FLOAT_PARAM1", nil).WithArgDataTypeOld(sdk.DataTypeFloat) - request := sdk.NewCreateForJavaScriptProcedureRequest(id.SchemaObjectId(), nil, definition). + request := sdk.NewCreateForJavaScriptProcedureRequestDefinitionWrapped(id.SchemaObjectId(), nil, definition). WithResultDataTypeOld(sdk.DataTypeString). WithArguments([]sdk.ProcedureArgumentRequest{*argument}). WithNullInputBehavior(*sdk.NullInputBehaviorPointer(sdk.NullInputBehaviorStrict)). WithExecuteAs(*sdk.ExecuteAsPointer(sdk.ExecuteAsCaller)) err := client.Procedures.CreateForJavaScript(ctx, request) require.NoError(t, err) - t.Cleanup(cleanupProcedureHandle(id)) + t.Cleanup(testClientHelper().Procedure.DropProcedureFunc(t, id)) procedures, err := client.Procedures.Show(ctx, sdk.NewShowProcedureRequest()) require.NoError(t, err) require.GreaterOrEqual(t, len(procedures), 1) }) + // TODO [SNOW-1348103]: adjust or remove t.Run("create procedure for Javascript: no arguments", func(t *testing.T) { + t.Skipf("Skipped for now; left as inspiration for resource rework as part of SNOW-1348103") + // https://docs.snowflake.com/en/developer-guide/stored-procedure/stored-procedures-javascript#basic-examples name := "sp_pi" id := testClientHelper().Ids.NewSchemaObjectIdentifierWithArguments(name) definition := `return 3.1415926;` - request := sdk.NewCreateForJavaScriptProcedureRequest(id.SchemaObjectId(), nil, definition).WithResultDataTypeOld(sdk.DataTypeFloat).WithNotNull(true).WithOrReplace(true) + request := sdk.NewCreateForJavaScriptProcedureRequestDefinitionWrapped(id.SchemaObjectId(), nil, definition).WithResultDataTypeOld(sdk.DataTypeFloat).WithNotNull(true).WithOrReplace(true) err := client.Procedures.CreateForJavaScript(ctx, request) require.NoError(t, err) - t.Cleanup(cleanupProcedureHandle(id)) + t.Cleanup(testClientHelper().Procedure.DropProcedureFunc(t, id)) procedures, err := client.Procedures.Show(ctx, sdk.NewShowProcedureRequest()) require.NoError(t, err) require.GreaterOrEqual(t, len(procedures), 1) }) + // TODO [SNOW-1348103]: adjust or remove t.Run("create procedure for Scala: returns result data type", func(t *testing.T) { + t.Skipf("Skipped for now; left as inspiration for resource rework as part of SNOW-1348103") + // https://docs.snowflake.com/en/developer-guide/stored-procedure/stored-procedures-scala#reading-a-dynamically-specified-file-with-snowflakefile name := "file_reader_scala_proc_snowflakefile" id := testClientHelper().Ids.NewSchemaObjectIdentifierWithArguments(name, sdk.DataTypeVARCHAR) @@ -169,17 +1330,20 @@ func TestInt_CreateProcedures(t *testing.T) { request := sdk.NewCreateForScalaProcedureRequest(id.SchemaObjectId(), *returns, "2.12", packages, "FileReader.execute"). WithOrReplace(true). WithArguments([]sdk.ProcedureArgumentRequest{*argument}). - WithProcedureDefinition(definition) + WithProcedureDefinitionWrapped(definition) err := client.Procedures.CreateForScala(ctx, request) require.NoError(t, err) - t.Cleanup(cleanupProcedureHandle(id)) + t.Cleanup(testClientHelper().Procedure.DropProcedureFunc(t, id)) procedures, err := client.Procedures.Show(ctx, sdk.NewShowProcedureRequest()) require.NoError(t, err) require.GreaterOrEqual(t, len(procedures), 1) }) + // TODO [SNOW-1348103]: adjust or remove t.Run("create procedure for Scala: returns table", func(t *testing.T) { + t.Skipf("Skipped for now; left as inspiration for resource rework as part of SNOW-1348103") + // https://docs.snowflake.com/en/developer-guide/stored-procedure/stored-procedures-scala#specifying-return-column-names-and-types name := "filter_by_role" id := testClientHelper().Ids.NewSchemaObjectIdentifierWithArguments(name, sdk.DataTypeVARCHAR, sdk.DataTypeVARCHAR) @@ -205,17 +1369,20 @@ func TestInt_CreateProcedures(t *testing.T) { request := sdk.NewCreateForScalaProcedureRequest(id.SchemaObjectId(), *returns, "2.12", packages, "Filter.filterByRole"). WithOrReplace(true). WithArguments([]sdk.ProcedureArgumentRequest{*arg1, *arg2}). - WithProcedureDefinition(definition) + WithProcedureDefinitionWrapped(definition) err := client.Procedures.CreateForScala(ctx, request) require.NoError(t, err) - t.Cleanup(cleanupProcedureHandle(id)) + t.Cleanup(testClientHelper().Procedure.DropProcedureFunc(t, id)) procedures, err := client.Procedures.Show(ctx, sdk.NewShowProcedureRequest()) require.NoError(t, err) require.GreaterOrEqual(t, len(procedures), 1) }) + // TODO [SNOW-1348103]: adjust or remove t.Run("create procedure for Python: returns result data type", func(t *testing.T) { + t.Skipf("Skipped for now; left as inspiration for resource rework as part of SNOW-1348103") + // https://docs.snowflake.com/en/developer-guide/stored-procedure/stored-procedures-python#running-concurrent-tasks-with-worker-processes name := "joblib_multiprocessing_proc" id := testClientHelper().Ids.NewSchemaObjectIdentifierWithArguments(name, sdk.DataTypeInt) @@ -237,17 +1404,20 @@ def joblib_multiprocessing(session, i): request := sdk.NewCreateForPythonProcedureRequest(id.SchemaObjectId(), *returns, "3.8", packages, "joblib_multiprocessing"). WithOrReplace(true). WithArguments([]sdk.ProcedureArgumentRequest{*argument}). - WithProcedureDefinition(definition) + WithProcedureDefinitionWrapped(definition) err := client.Procedures.CreateForPython(ctx, request) require.NoError(t, err) - t.Cleanup(cleanupProcedureHandle(id)) + t.Cleanup(testClientHelper().Procedure.DropProcedureFunc(t, id)) procedures, err := client.Procedures.Show(ctx, sdk.NewShowProcedureRequest()) require.NoError(t, err) require.GreaterOrEqual(t, len(procedures), 1) }) + // TODO [SNOW-1348103]: adjust or remove t.Run("create procedure for Python: returns table", func(t *testing.T) { + t.Skipf("Skipped for now; left as inspiration for resource rework as part of SNOW-1348103") + // https://docs.snowflake.com/en/developer-guide/stored-procedure/stored-procedures-python#specifying-return-column-names-and-types name := "filterByRole" id := testClientHelper().Ids.NewSchemaObjectIdentifierWithArguments(name, sdk.DataTypeVARCHAR, sdk.DataTypeVARCHAR) @@ -268,17 +1438,20 @@ def filter_by_role(session, table_name, role): request := sdk.NewCreateForPythonProcedureRequest(id.SchemaObjectId(), *returns, "3.8", packages, "filter_by_role"). WithOrReplace(true). WithArguments([]sdk.ProcedureArgumentRequest{*arg1, *arg2}). - WithProcedureDefinition(definition) + WithProcedureDefinitionWrapped(definition) err := client.Procedures.CreateForPython(ctx, request) require.NoError(t, err) - t.Cleanup(cleanupProcedureHandle(id)) + t.Cleanup(testClientHelper().Procedure.DropProcedureFunc(t, id)) procedures, err := client.Procedures.Show(ctx, sdk.NewShowProcedureRequest()) require.NoError(t, err) require.GreaterOrEqual(t, len(procedures), 1) }) + // TODO [SNOW-1348103]: adjust or remove t.Run("create procedure for SQL: returns result data type", func(t *testing.T) { + t.Skipf("Skipped for now; left as inspiration for resource rework as part of SNOW-1348103") + // https://docs.snowflake.com/en/developer-guide/stored-procedure/stored-procedures-snowflake-scripting name := "output_message" id := testClientHelper().Ids.NewSchemaObjectIdentifierWithArguments(name, sdk.DataTypeVARCHAR) @@ -291,7 +1464,7 @@ def filter_by_role(session, table_name, role): dt := sdk.NewProcedureReturnsResultDataTypeRequest(nil).WithResultDataTypeOld(sdk.DataTypeVARCHAR) returns := sdk.NewProcedureSQLReturnsRequest().WithResultDataType(*dt).WithNotNull(true) argument := sdk.NewProcedureArgumentRequest("message", nil).WithArgDataTypeOld(sdk.DataTypeVARCHAR) - request := sdk.NewCreateForSQLProcedureRequest(id.SchemaObjectId(), *returns, definition). + request := sdk.NewCreateForSQLProcedureRequestDefinitionWrapped(id.SchemaObjectId(), *returns, definition). WithOrReplace(true). // Suddenly this is erroring out, when it used to not have an problem. Must be an error with the Snowflake API. // Created issue in docs-discuss channel. https://snowflake.slack.com/archives/C6380540P/p1707511734666249 @@ -299,18 +1472,21 @@ def filter_by_role(session, table_name, role): // 001003 (42000): SQL compilation error: // syntax error line 1 at position 210 unexpected 'NULL'. // syntax error line 1 at position 215 unexpected 'ON'. - // WithNullInputBehavior(sdk.NullInputBehaviorPointer(sdk.NullInputBehaviorReturnNullInput)). + // WithNullInputBehavior(sdk.NullInputBehaviorPointer(sdk.NullInputBehaviorReturnsNullInput)). WithArguments([]sdk.ProcedureArgumentRequest{*argument}) err := client.Procedures.CreateForSQL(ctx, request) require.NoError(t, err) - t.Cleanup(cleanupProcedureHandle(id)) + t.Cleanup(testClientHelper().Procedure.DropProcedureFunc(t, id)) procedures, err := client.Procedures.Show(ctx, sdk.NewShowProcedureRequest()) require.NoError(t, err) require.GreaterOrEqual(t, len(procedures), 1) }) + // TODO [SNOW-1348103]: adjust or remove t.Run("create procedure for SQL: returns table", func(t *testing.T) { + t.Skipf("Skipped for now; left as inspiration for resource rework as part of SNOW-1348103") + name := "find_invoice_by_id" id := testClientHelper().Ids.NewSchemaObjectIdentifierWithArguments(name, sdk.DataTypeVARCHAR) @@ -325,216 +1501,443 @@ def filter_by_role(session, table_name, role): returnsTable := sdk.NewProcedureReturnsTableRequest().WithColumns([]sdk.ProcedureColumnRequest{*column1, *column2}) returns := sdk.NewProcedureSQLReturnsRequest().WithTable(*returnsTable) argument := sdk.NewProcedureArgumentRequest("id", nil).WithArgDataTypeOld(sdk.DataTypeVARCHAR) - request := sdk.NewCreateForSQLProcedureRequest(id.SchemaObjectId(), *returns, definition). + request := sdk.NewCreateForSQLProcedureRequestDefinitionWrapped(id.SchemaObjectId(), *returns, definition). WithOrReplace(true). // SNOW-1051627 todo: uncomment once null input behavior working again - // WithNullInputBehavior(sdk.NullInputBehaviorPointer(sdk.NullInputBehaviorReturnNullInput)). + // WithNullInputBehavior(sdk.NullInputBehaviorPointer(sdk.NullInputBehaviorReturnsNullInput)). WithArguments([]sdk.ProcedureArgumentRequest{*argument}) err := client.Procedures.CreateForSQL(ctx, request) require.NoError(t, err) - t.Cleanup(cleanupProcedureHandle(id)) + t.Cleanup(testClientHelper().Procedure.DropProcedureFunc(t, id)) procedures, err := client.Procedures.Show(ctx, sdk.NewShowProcedureRequest()) require.NoError(t, err) require.GreaterOrEqual(t, len(procedures), 1) }) -} - -func TestInt_OtherProcedureFunctions(t *testing.T) { - client := testClient(t) - ctx := testContext(t) - assertProcedure := func(t *testing.T, id sdk.SchemaObjectIdentifierWithArguments, secure bool) { - t.Helper() + t.Run("show parameters", func(t *testing.T) { + p, pCleanup := testClientHelper().Procedure.CreateSql(t) + t.Cleanup(pCleanup) + id := p.ID() - procedure, err := client.Procedures.ShowByID(ctx, id) + param, err := client.Parameters.ShowObjectParameter(ctx, sdk.ObjectParameterLogLevel, sdk.Object{ObjectType: sdk.ObjectTypeProcedure, Name: id}) require.NoError(t, err) + assert.Equal(t, string(sdk.LogLevelOff), param.Value) - assert.NotEmpty(t, procedure.CreatedOn) - assert.Equal(t, id.Name(), procedure.Name) - assert.Equal(t, false, procedure.IsBuiltin) - assert.Equal(t, false, procedure.IsAggregate) - assert.Equal(t, false, procedure.IsAnsi) - assert.Equal(t, 1, procedure.MinNumArguments) - assert.Equal(t, 1, procedure.MaxNumArguments) - assert.NotEmpty(t, procedure.ArgumentsOld) - assert.NotEmpty(t, procedure.ArgumentsRaw) - assert.NotEmpty(t, procedure.Description) - assert.NotEmpty(t, procedure.CatalogName) - assert.Equal(t, false, procedure.IsTableFunction) - assert.Equal(t, false, procedure.ValidForClustering) - assert.Equal(t, secure, procedure.IsSecure) - } - - cleanupProcedureHandle := func(id sdk.SchemaObjectIdentifierWithArguments) func() { - return func() { - err := client.Procedures.Drop(ctx, sdk.NewDropProcedureRequest(id)) - if errors.Is(err, sdk.ErrObjectNotExistOrAuthorized) { - return - } - require.NoError(t, err) - } - } + parameters, err := client.Parameters.ShowParameters(ctx, &sdk.ShowParametersOptions{ + In: &sdk.ParametersIn{ + Procedure: id, + }, + }) + require.NoError(t, err) - createProcedureForSQLHandle := func(t *testing.T, cleanup bool) *sdk.Procedure { - t.Helper() + assertions.AssertThatObject(t, objectparametersassert.ProcedureParametersPrefetched(t, id, parameters). + HasAllDefaults(). + HasAllDefaultsExplicit(), + ) - definition := ` - BEGIN - RETURN message; - END;` - id := testClientHelper().Ids.RandomSchemaObjectIdentifierWithArguments(sdk.DataTypeVARCHAR) - dt := sdk.NewProcedureReturnsResultDataTypeRequest(nil).WithResultDataTypeOld(sdk.DataTypeVARCHAR) - returns := sdk.NewProcedureSQLReturnsRequest().WithResultDataType(*dt).WithNotNull(true) - argument := sdk.NewProcedureArgumentRequest("message", nil).WithArgDataTypeOld(sdk.DataTypeVARCHAR) - request := sdk.NewCreateForSQLProcedureRequest(id.SchemaObjectId(), *returns, definition). - WithSecure(true). - WithOrReplace(true). - WithArguments([]sdk.ProcedureArgumentRequest{*argument}). - WithExecuteAs(*sdk.ExecuteAsPointer(sdk.ExecuteAsCaller)) - err := client.Procedures.CreateForSQL(ctx, request) - require.NoError(t, err) - if cleanup { - t.Cleanup(cleanupProcedureHandle(id)) - } - procedure, err := client.Procedures.ShowByID(ctx, id) + // check that ShowParameters on procedure level works too + parameters, err = client.Procedures.ShowParameters(ctx, id) require.NoError(t, err) - return procedure - } + + assertions.AssertThatObject(t, objectparametersassert.ProcedureParametersPrefetched(t, id, parameters). + HasAllDefaults(). + HasAllDefaultsExplicit(), + ) + }) t.Run("alter procedure: rename", func(t *testing.T) { - f := createProcedureForSQLHandle(t, false) + p, pCleanup := testClientHelper().Procedure.CreateSql(t) + t.Cleanup(pCleanup) + id := p.ID() - id := f.ID() - nid := testClientHelper().Ids.RandomSchemaObjectIdentifier() - nidWithArguments := sdk.NewSchemaObjectIdentifierWithArguments(nid.DatabaseName(), nid.SchemaName(), nid.Name(), id.ArgumentDataTypes()...) + nid := testClientHelper().Ids.RandomSchemaObjectIdentifierWithArguments(id.ArgumentDataTypes()...) - err := client.Procedures.Alter(ctx, sdk.NewAlterProcedureRequest(id).WithRenameTo(nid)) - if err != nil { - t.Cleanup(cleanupProcedureHandle(id)) - } else { - t.Cleanup(cleanupProcedureHandle(nidWithArguments)) - } + err := client.Procedures.Alter(ctx, sdk.NewAlterProcedureRequest(id).WithRenameTo(nid.SchemaObjectId())) require.NoError(t, err) + t.Cleanup(testClientHelper().Procedure.DropProcedureFunc(t, nid)) _, err = client.Procedures.ShowByID(ctx, id) assert.ErrorIs(t, err, collections.ErrObjectNotFound) - e, err := client.Procedures.ShowByID(ctx, nidWithArguments) + e, err := client.Procedures.ShowByID(ctx, nid) require.NoError(t, err) require.Equal(t, nid.Name(), e.Name) }) - t.Run("alter procedure: set log level", func(t *testing.T) { - f := createProcedureForSQLHandle(t, true) - - id := f.ID() - err := client.Procedures.Alter(ctx, sdk.NewAlterProcedureRequest(id).WithSetLogLevel("DEBUG")) - require.NoError(t, err) - assertProcedure(t, id, true) + t.Run("alter procedure: set and unset all for Java", func(t *testing.T) { + p, pCleanup := testClientHelper().Procedure.CreateJava(t) + t.Cleanup(pCleanup) + id := p.ID() + + assertions.AssertThatObject(t, objectassert.Procedure(t, id). + HasName(id.Name()). + HasDescription(sdk.DefaultProcedureComment), + ) + + assertions.AssertThatObject(t, objectassert.ProcedureDetails(t, id). + HasExternalAccessIntegrationsNil(). + HasSecretsNil(), + ) + + assertions.AssertThatObject(t, objectparametersassert.ProcedureParameters(t, id). + HasAllDefaults(). + HasAllDefaultsExplicit(), + ) + + request := sdk.NewAlterProcedureRequest(id).WithSet(*sdk.NewProcedureSetRequest(). + WithExternalAccessIntegrations([]sdk.AccountObjectIdentifier{externalAccessIntegration}). + WithSecretsList(*sdk.NewSecretsListRequest([]sdk.SecretReference{{VariableName: "abc", Name: secretId}})). + // TODO [SNOW-1850370]: every value end with invalid value [OFF] for parameter 'AUTO_EVENT_LOGGING' + // WithAutoEventLogging(sdk.AutoEventLoggingAll). + WithEnableConsoleOutput(true). + WithLogLevel(sdk.LogLevelWarn). + WithMetricLevel(sdk.MetricLevelAll). + WithTraceLevel(sdk.TraceLevelAlways). + WithComment("new comment"), + ) + + err := client.Procedures.Alter(ctx, request) + require.NoError(t, err) + + assertions.AssertThatObject(t, objectassert.Procedure(t, id). + HasName(id.Name()). + HasDescription("new comment"), + ) + + assertions.AssertThatObject(t, objectassert.ProcedureDetails(t, id). + HasExactlyExternalAccessIntegrations(externalAccessIntegration). + HasExactlySecrets(map[string]sdk.SchemaObjectIdentifier{"abc": secretId}), + ) + + assertParametersSet(t, objectparametersassert.ProcedureParameters(t, id)) + + unsetRequest := sdk.NewAlterProcedureRequest(id).WithUnset(*sdk.NewProcedureUnsetRequest(). + WithExternalAccessIntegrations(true). + // WithAutoEventLogging(true). + WithEnableConsoleOutput(true). + WithLogLevel(true). + WithMetricLevel(true). + WithTraceLevel(true). + WithComment(true), + ) + + err = client.Procedures.Alter(ctx, unsetRequest) + require.NoError(t, err) + + assertions.AssertThatObject(t, objectassert.Procedure(t, id). + HasName(id.Name()). + HasDescription(sdk.DefaultProcedureComment). + // both nil, because they are always nil in SHOW for procedures + HasExternalAccessIntegrationsNil(). + HasSecretsNil(), + ) + + assertions.AssertThatObject(t, objectassert.ProcedureDetails(t, id). + HasExternalAccessIntegrationsNil(). + // TODO [SNOW-1850370]: apparently UNSET external access integrations cleans out secrets in the describe but leaves it in SHOW + HasSecretsNil(), + ) + + assertions.AssertThatObject(t, objectparametersassert.ProcedureParameters(t, id). + HasAllDefaults(). + HasAllDefaultsExplicit(), + ) + + unsetSecretsRequest := sdk.NewAlterProcedureRequest(id).WithSet(*sdk.NewProcedureSetRequest(). + WithSecretsList(*sdk.NewSecretsListRequest([]sdk.SecretReference{})), + ) + + err = client.Procedures.Alter(ctx, unsetSecretsRequest) + require.NoError(t, err) + + assertions.AssertThatObject(t, objectassert.ProcedureDetails(t, id). + HasSecretsNil(), + ) }) - t.Run("alter procedure: set trace level", func(t *testing.T) { - f := createProcedureForSQLHandle(t, true) - - id := f.ID() - err := client.Procedures.Alter(ctx, sdk.NewAlterProcedureRequest(id).WithSetTraceLevel("ALWAYS")) - require.NoError(t, err) - assertProcedure(t, id, true) + t.Run("alter procedure: set and unset all for SQL", func(t *testing.T) { + p, pCleanup := testClientHelper().Procedure.CreateSql(t) + t.Cleanup(pCleanup) + id := p.ID() + + assertions.AssertThatObject(t, objectparametersassert.ProcedureParameters(t, id). + HasAllDefaults(). + HasAllDefaultsExplicit(), + ) + + request := sdk.NewAlterProcedureRequest(id).WithSet(*sdk.NewProcedureSetRequest(). + // WithAutoEventLogging(sdk.AutoEventLoggingTracing). + WithEnableConsoleOutput(true). + WithLogLevel(sdk.LogLevelWarn). + WithMetricLevel(sdk.MetricLevelAll). + WithTraceLevel(sdk.TraceLevelAlways). + WithComment("new comment"), + ) + + err := client.Procedures.Alter(ctx, request) + require.NoError(t, err) + + assertions.AssertThatObject(t, objectassert.Procedure(t, id). + HasName(id.Name()). + HasDescription("new comment"), + ) + + assertParametersSet(t, objectparametersassert.ProcedureParameters(t, id)) + + unsetRequest := sdk.NewAlterProcedureRequest(id).WithUnset(*sdk.NewProcedureUnsetRequest(). + // WithAutoEventLogging(true). + WithEnableConsoleOutput(true). + WithLogLevel(true). + WithMetricLevel(true). + WithTraceLevel(true). + WithComment(true), + ) + + err = client.Procedures.Alter(ctx, unsetRequest) + require.NoError(t, err) + + assertions.AssertThatObject(t, objectassert.Procedure(t, id). + HasCreatedOnNotEmpty(). + HasName(id.Name()). + HasDescription(sdk.DefaultProcedureComment), + ) + + assertions.AssertThatObject(t, objectparametersassert.ProcedureParameters(t, id). + HasAllDefaults(). + HasAllDefaultsExplicit(), + ) }) - t.Run("alter procedure: set comment", func(t *testing.T) { - f := createProcedureForSQLHandle(t, true) - - id := f.ID() - err := client.Procedures.Alter(ctx, sdk.NewAlterProcedureRequest(id).WithSetComment("comment")) - require.NoError(t, err) - assertProcedure(t, id, true) - }) + t.Run("alter procedure: set execute as", func(t *testing.T) { + p, pCleanup := testClientHelper().Procedure.CreateSql(t) + t.Cleanup(pCleanup) + id := p.ID() - t.Run("alter procedure: unset comment", func(t *testing.T) { - f := createProcedureForSQLHandle(t, true) + assertions.AssertThatObject(t, objectassert.ProcedureDetails(t, id). + HasExecuteAs("OWNER"), + ) - id := f.ID() - err := client.Procedures.Alter(ctx, sdk.NewAlterProcedureRequest(id).WithUnsetComment(true)) + err := client.Procedures.Alter(ctx, sdk.NewAlterProcedureRequest(id).WithExecuteAs(*sdk.ExecuteAsPointer(sdk.ExecuteAsCaller))) require.NoError(t, err) - assertProcedure(t, id, true) - }) - t.Run("alter procedure: set execute as", func(t *testing.T) { - f := createProcedureForSQLHandle(t, true) + assertions.AssertThatObject(t, objectassert.ProcedureDetails(t, id). + HasExecuteAs("CALLER"), + ) - id := f.ID() - err := client.Procedures.Alter(ctx, sdk.NewAlterProcedureRequest(id).WithExecuteAs(*sdk.ExecuteAsPointer(sdk.ExecuteAsOwner))) + err = client.Procedures.Alter(ctx, sdk.NewAlterProcedureRequest(id).WithExecuteAs(*sdk.ExecuteAsPointer(sdk.ExecuteAsOwner))) require.NoError(t, err) - assertProcedure(t, id, true) + + assertions.AssertThatObject(t, objectassert.ProcedureDetails(t, id). + HasExecuteAs("OWNER"), + ) }) - t.Run("show procedure for SQL: without like", func(t *testing.T) { - f1 := createProcedureForSQLHandle(t, true) - f2 := createProcedureForSQLHandle(t, true) + t.Run("show procedure: without like", func(t *testing.T) { + p1, pCleanup := testClientHelper().Procedure.CreateSql(t) + t.Cleanup(pCleanup) + p2, pCleanup2 := testClientHelper().Procedure.CreateSql(t) + t.Cleanup(pCleanup2) procedures, err := client.Procedures.Show(ctx, sdk.NewShowProcedureRequest()) require.NoError(t, err) require.GreaterOrEqual(t, len(procedures), 1) - require.Contains(t, procedures, *f1) - require.Contains(t, procedures, *f2) + require.Contains(t, procedures, *p1) + require.Contains(t, procedures, *p2) }) - t.Run("show procedure for SQL: with like", func(t *testing.T) { - f1 := createProcedureForSQLHandle(t, true) - f2 := createProcedureForSQLHandle(t, true) + t.Run("show procedure: with like", func(t *testing.T) { + p1, pCleanup := testClientHelper().Procedure.CreateSql(t) + t.Cleanup(pCleanup) + p2, pCleanup2 := testClientHelper().Procedure.CreateSql(t) + t.Cleanup(pCleanup2) - procedures, err := client.Procedures.Show(ctx, sdk.NewShowProcedureRequest().WithLike(sdk.Like{Pattern: &f1.Name})) + procedures, err := client.Procedures.Show(ctx, sdk.NewShowProcedureRequest().WithLike(sdk.Like{Pattern: &p1.Name})) require.NoError(t, err) require.Equal(t, 1, len(procedures)) - require.Contains(t, procedures, *f1) - require.NotContains(t, procedures, *f2) + require.Contains(t, procedures, *p1) + require.NotContains(t, procedures, *p2) }) - t.Run("show procedure for SQL: no matches", func(t *testing.T) { - procedures, err := client.Procedures.Show(ctx, sdk.NewShowProcedureRequest().WithLike(sdk.Like{Pattern: sdk.String("non-existing-id-pattern")})) + t.Run("show procedure: no matches", func(t *testing.T) { + procedures, err := client.Procedures.Show(ctx, sdk.NewShowProcedureRequest(). + WithIn(sdk.ExtendedIn{In: sdk.In{Schema: testClientHelper().Ids.SchemaId()}}). + WithLike(sdk.Like{Pattern: sdk.String(NonExistingSchemaObjectIdentifier.Name())})) require.NoError(t, err) require.Equal(t, 0, len(procedures)) }) - t.Run("describe procedure for SQL", func(t *testing.T) { - f := createProcedureForSQLHandle(t, true) - id := f.ID() + t.Run("describe procedure: for SQL", func(t *testing.T) { + p, pCleanup := testClientHelper().Procedure.CreateSql(t) + t.Cleanup(pCleanup) + id := p.ID() details, err := client.Procedures.Describe(ctx, id) require.NoError(t, err) - pairs := make(map[string]string) + assert.Len(t, details, 5) + + pairs := make(map[string]*string) for _, detail := range details { pairs[detail.Property] = detail.Value } - require.Equal(t, "SQL", pairs["language"]) - require.Equal(t, "CALLER", pairs["execute as"]) - require.Equal(t, "(MESSAGE VARCHAR)", pairs["signature"]) - require.Equal(t, "\n\tBEGIN\n\t\tRETURN message;\n\tEND;", pairs["body"]) + assert.Equal(t, "(x FLOAT)", *pairs["signature"]) + assert.Equal(t, "FLOAT", *pairs["returns"]) + assert.Equal(t, "SQL", *pairs["language"]) + assert.Equal(t, "\nBEGIN\n\tRETURN 3.141592654::FLOAT;\nEND;\n", *pairs["body"]) + assert.Equal(t, "OWNER", *pairs["execute as"]) + }) + + t.Run("describe procedure: for Java", func(t *testing.T) { + p, pCleanup := testClientHelper().Procedure.CreateJava(t) + t.Cleanup(pCleanup) + id := p.ID() + + details, err := client.Procedures.Describe(ctx, id) + require.NoError(t, err) + assert.Len(t, details, 12) + + pairs := make(map[string]*string) + for _, detail := range details { + pairs[detail.Property] = detail.Value + } + assert.Equal(t, "(x VARCHAR)", *pairs["signature"]) + assert.Equal(t, "VARCHAR(100)", *pairs["returns"]) + assert.Equal(t, "JAVA", *pairs["language"]) + assert.NotEmpty(t, *pairs["body"]) + assert.Equal(t, string(sdk.NullInputBehaviorCalledOnNullInput), *pairs["null handling"]) + assert.Equal(t, string(sdk.VolatileTableKind), *pairs["volatility"]) + assert.Nil(t, pairs["external_access_integration"]) + assert.Nil(t, pairs["secrets"]) + assert.Equal(t, "[]", *pairs["imports"]) + assert.Equal(t, "TestFunc.echoVarchar", *pairs["handler"]) + assert.Equal(t, "11", *pairs["runtime_version"]) + assert.Equal(t, "OWNER", *pairs["execute as"]) }) t.Run("drop procedure for SQL", func(t *testing.T) { - definition := ` - BEGIN - RETURN message; - END;` - id := testClientHelper().Ids.RandomSchemaObjectIdentifierWithArguments(sdk.DataTypeVARCHAR) - dt := sdk.NewProcedureReturnsResultDataTypeRequest(nil).WithResultDataTypeOld(sdk.DataTypeVARCHAR) - returns := sdk.NewProcedureSQLReturnsRequest().WithResultDataType(*dt).WithNotNull(true) - argument := sdk.NewProcedureArgumentRequest("message", nil).WithArgDataTypeOld(sdk.DataTypeVARCHAR) - request := sdk.NewCreateForSQLProcedureRequest(id.SchemaObjectId(), *returns, definition). - WithOrReplace(true). - WithArguments([]sdk.ProcedureArgumentRequest{*argument}). - WithExecuteAs(*sdk.ExecuteAsPointer(sdk.ExecuteAsCaller)) - err := client.Procedures.CreateForSQL(ctx, request) + p, pCleanup := testClientHelper().Procedure.CreateJava(t) + t.Cleanup(pCleanup) + id := p.ID() + + err := client.Procedures.Drop(ctx, sdk.NewDropProcedureRequest(id)) + require.NoError(t, err) + }) + + t.Run("show by id - same name in different schemas", func(t *testing.T) { + schema, schemaCleanup := testClientHelper().Schema.CreateSchema(t) + t.Cleanup(schemaCleanup) + + dataType := testdatatypes.DataTypeFloat + id1 := testClientHelper().Ids.RandomSchemaObjectIdentifierWithArguments(sdk.LegacyDataTypeFrom(dataType)) + id2 := testClientHelper().Ids.NewSchemaObjectIdentifierWithArgumentsInSchema(id1.Name(), schema.ID(), sdk.LegacyDataTypeFrom(dataType)) + + _, pCleanup1 := testClientHelper().Procedure.CreateSqlWithIdentifierAndArgument(t, id1.SchemaObjectId(), dataType, testClientHelper().Procedure.SampleSqlDefinition(t)) + t.Cleanup(pCleanup1) + _, pCleanup2 := testClientHelper().Procedure.CreateSqlWithIdentifierAndArgument(t, id2.SchemaObjectId(), dataType, testClientHelper().Procedure.SampleSqlDefinition(t)) + t.Cleanup(pCleanup2) + + e1, err := client.Procedures.ShowByID(ctx, id1) require.NoError(t, err) + require.Equal(t, id1, e1.ID()) + + e2, err := client.Procedures.ShowByID(ctx, id2) + require.NoError(t, err) + require.Equal(t, id2, e2.ID()) + }) + + t.Run("show procedure by id - same name, different arguments", func(t *testing.T) { + dataType := testdatatypes.DataTypeFloat + name := testClientHelper().Ids.Alpha() + + id1 := testClientHelper().Ids.NewSchemaObjectIdentifierWithArgumentsInSchema(name, testClientHelper().Ids.SchemaId(), sdk.LegacyDataTypeFrom(dataType)) + id2 := testClientHelper().Ids.NewSchemaObjectIdentifierWithArgumentsInSchema(name, testClientHelper().Ids.SchemaId(), sdk.DataTypeInt, sdk.DataTypeVARCHAR) + + e := testClientHelper().Procedure.CreateWithIdentifier(t, id1) + testClientHelper().Procedure.CreateWithIdentifier(t, id2) - err = client.Procedures.Drop(ctx, sdk.NewDropProcedureRequest(id)) + es, err := client.Procedures.ShowByID(ctx, id1) require.NoError(t, err) + require.Equal(t, *e, *es) }) + + // This test shows behavior of detailed types (e.g. VARCHAR(20) and NUMBER(10, 0)) on Snowflake side for procedures. + // For SHOW, data type is generalized both for argument and return type (to e.g. VARCHAR and NUMBER). + // FOR DESCRIBE, data type is generalized for argument and works weirdly for the return type: type is generalized to the canonical one, but we also get the attributes. + for _, tc := range []string{ + "NUMBER(36, 5)", + "NUMBER(36)", + "NUMBER", + "DECIMAL", + "INTEGER", + "FLOAT", + "DOUBLE", + "VARCHAR", + "VARCHAR(20)", + "CHAR", + "CHAR(10)", + "TEXT", + "BINARY", + "BINARY(1000)", + "VARBINARY", + "BOOLEAN", + "DATE", + "DATETIME", + "TIME", + "TIMESTAMP_LTZ", + "TIMESTAMP_NTZ", + "TIMESTAMP_TZ", + "VARIANT", + "OBJECT", + "ARRAY", + "GEOGRAPHY", + "GEOMETRY", + "VECTOR(INT, 16)", + "VECTOR(FLOAT, 8)", + } { + tc := tc + t.Run(fmt.Sprintf("procedure returns non detailed data types of arguments for %s", tc), func(t *testing.T) { + procName := "add" + argName := "A" + dataType, err := datatypes.ParseDataType(tc) + require.NoError(t, err) + args := []sdk.ProcedureArgumentRequest{ + *sdk.NewProcedureArgumentRequest(argName, dataType), + } + oldDataType := sdk.LegacyDataTypeFrom(dataType) + idWithArguments := testClientHelper().Ids.RandomSchemaObjectIdentifierWithArguments(oldDataType) + + packages := []sdk.ProcedurePackageRequest{*sdk.NewProcedurePackageRequest("snowflake-snowpark-python")} + definition := fmt.Sprintf("def add(%[1]s): %[1]s", argName) + + err = client.Procedures.CreateForPython(ctx, sdk.NewCreateForPythonProcedureRequest( + idWithArguments.SchemaObjectId(), + *sdk.NewProcedureReturnsRequest().WithResultDataType(*sdk.NewProcedureReturnsResultDataTypeRequest(dataType)), + "3.8", + packages, + procName, + ). + WithArguments(args). + WithProcedureDefinitionWrapped(definition), + ) + require.NoError(t, err) + + procedure, err := client.Procedures.ShowByID(ctx, idWithArguments) + require.NoError(t, err) + assert.Equal(t, []sdk.DataType{oldDataType}, procedure.ArgumentsOld) + assert.Equal(t, fmt.Sprintf("%[1]s(%[2]s) RETURN %[2]s", idWithArguments.Name(), oldDataType), procedure.ArgumentsRaw) + + details, err := client.Procedures.Describe(ctx, idWithArguments) + require.NoError(t, err) + pairs := make(map[string]string) + for _, detail := range details { + pairs[detail.Property] = *detail.Value + } + assert.Equal(t, fmt.Sprintf("(%s %s)", argName, oldDataType), pairs["signature"]) + assert.Equal(t, dataType.Canonical(), pairs["returns"]) + }) + } } func TestInt_CallProcedure(t *testing.T) { @@ -574,13 +1977,13 @@ func TestInt_CallProcedure(t *testing.T) { definition := ` BEGIN - RETURN message; + RETURN MESSAGE; END;` id := testClientHelper().Ids.RandomSchemaObjectIdentifierWithArguments(sdk.DataTypeVARCHAR) dt := sdk.NewProcedureReturnsResultDataTypeRequest(nil).WithResultDataTypeOld(sdk.DataTypeVARCHAR) returns := sdk.NewProcedureSQLReturnsRequest().WithResultDataType(*dt).WithNotNull(true) - argument := sdk.NewProcedureArgumentRequest("message", nil).WithArgDataTypeOld(sdk.DataTypeVARCHAR) - request := sdk.NewCreateForSQLProcedureRequest(id.SchemaObjectId(), *returns, definition). + argument := sdk.NewProcedureArgumentRequest("MESSAGE", nil).WithArgDataTypeOld(sdk.DataTypeVARCHAR) + request := sdk.NewCreateForSQLProcedureRequestDefinitionWrapped(id.SchemaObjectId(), *returns, definition). WithSecure(true). WithOrReplace(true). WithArguments([]sdk.ProcedureArgumentRequest{*argument}). @@ -603,7 +2006,7 @@ func TestInt_CallProcedure(t *testing.T) { t.Run("call procedure for SQL: argument names", func(t *testing.T) { f := createProcedureForSQLHandle(t, true) - err := client.Procedures.Call(ctx, sdk.NewCallProcedureRequest(f.ID().SchemaObjectId()).WithCallArguments([]string{"message => 'hi'"})) + err := client.Procedures.Call(ctx, sdk.NewCallProcedureRequest(f.ID().SchemaObjectId()).WithCallArguments([]string{"MESSAGE => 'hi'"})) require.NoError(t, err) }) @@ -632,7 +2035,7 @@ func TestInt_CallProcedure(t *testing.T) { request := sdk.NewCreateForJavaProcedureRequest(id.SchemaObjectId(), *returns, "11", packages, "Filter.filterByRole"). WithOrReplace(true). WithArguments([]sdk.ProcedureArgumentRequest{*arg1, *arg2}). - WithProcedureDefinition(definition) + WithProcedureDefinitionWrapped(definition) err := client.Procedures.CreateForJava(ctx, request) require.NoError(t, err) t.Cleanup(cleanupProcedureHandle(id)) @@ -666,7 +2069,7 @@ func TestInt_CallProcedure(t *testing.T) { request := sdk.NewCreateForScalaProcedureRequest(id.SchemaObjectId(), *returns, "2.12", packages, "Filter.filterByRole"). WithOrReplace(true). WithArguments([]sdk.ProcedureArgumentRequest{*arg1, *arg2}). - WithProcedureDefinition(definition) + WithProcedureDefinitionWrapped(definition) err := client.Procedures.CreateForScala(ctx, request) require.NoError(t, err) t.Cleanup(cleanupProcedureHandle(id)) @@ -693,7 +2096,7 @@ func TestInt_CallProcedure(t *testing.T) { return "Failed: " + err; // Return a success/error indicator. }` arg := sdk.NewProcedureArgumentRequest("FLOAT_PARAM1", nil).WithArgDataTypeOld(sdk.DataTypeFloat) - request := sdk.NewCreateForJavaScriptProcedureRequest(id.SchemaObjectId(), nil, definition). + request := sdk.NewCreateForJavaScriptProcedureRequestDefinitionWrapped(id.SchemaObjectId(), nil, definition). WithResultDataTypeOld(sdk.DataTypeString). WithOrReplace(true). WithArguments([]sdk.ProcedureArgumentRequest{*arg}). @@ -713,7 +2116,7 @@ func TestInt_CallProcedure(t *testing.T) { id := sdk.NewSchemaObjectIdentifierWithArguments(databaseId.Name(), schemaId.Name(), name) definition := `return 3.1415926;` - request := sdk.NewCreateForJavaScriptProcedureRequest(id.SchemaObjectId(), nil, definition).WithResultDataTypeOld(sdk.DataTypeFloat).WithNotNull(true).WithOrReplace(true) + request := sdk.NewCreateForJavaScriptProcedureRequestDefinitionWrapped(id.SchemaObjectId(), nil, definition).WithResultDataTypeOld(sdk.DataTypeFloat).WithNotNull(true).WithOrReplace(true) err := client.Procedures.CreateForJavaScript(ctx, request) require.NoError(t, err) t.Cleanup(cleanupProcedureHandle(id)) @@ -739,7 +2142,7 @@ def filter_by_role(session, name, role): request := sdk.NewCreateForPythonProcedureRequest(id.SchemaObjectId(), *returns, "3.8", packages, "filter_by_role"). WithOrReplace(true). WithArguments([]sdk.ProcedureArgumentRequest{*arg1, *arg2}). - WithProcedureDefinition(definition) + WithProcedureDefinitionWrapped(definition) err := client.Procedures.CreateForPython(ctx, request) require.NoError(t, err) t.Cleanup(cleanupProcedureHandle(id)) @@ -876,13 +2279,13 @@ func TestInt_CreateAndCallProcedures(t *testing.T) { t.Run("create and call procedure for SQL: argument positions", func(t *testing.T) { definition := ` BEGIN - RETURN message; + RETURN MESSAGE; END;` name := testClientHelper().Ids.RandomAccountObjectIdentifier() dt := sdk.NewProcedureReturnsResultDataTypeRequest(nil).WithResultDataTypeOld(sdk.DataTypeVARCHAR) returns := sdk.NewProcedureReturnsRequest().WithResultDataType(*dt) - argument := sdk.NewProcedureArgumentRequest("message", nil).WithArgDataTypeOld(sdk.DataTypeVARCHAR) + argument := sdk.NewProcedureArgumentRequest("MESSAGE", nil).WithArgDataTypeOld(sdk.DataTypeVARCHAR) request := sdk.NewCreateAndCallForSQLProcedureRequest(name, *returns, definition, name). WithArguments([]sdk.ProcedureArgumentRequest{*argument}). WithCallArguments([]string{"message => 'hi'"}) @@ -949,155 +2352,3 @@ def filter_by_role(session, name, role): require.NoError(t, err) }) } - -func TestInt_ProceduresShowByID(t *testing.T) { - client := testClient(t) - ctx := testContext(t) - - cleanupProcedureHandle := func(id sdk.SchemaObjectIdentifierWithArguments) func() { - return func() { - err := client.Procedures.Drop(ctx, sdk.NewDropProcedureRequest(id)) - if errors.Is(err, sdk.ErrObjectNotExistOrAuthorized) { - return - } - require.NoError(t, err) - } - } - - createProcedureForSQLHandle := func(t *testing.T, id sdk.SchemaObjectIdentifierWithArguments) { - t.Helper() - - definition := ` - BEGIN - RETURN message; - END;` - dt := sdk.NewProcedureReturnsResultDataTypeRequest(nil).WithResultDataTypeOld(sdk.DataTypeVARCHAR) - returns := sdk.NewProcedureSQLReturnsRequest().WithResultDataType(*dt).WithNotNull(true) - argument := sdk.NewProcedureArgumentRequest("message", nil).WithArgDataTypeOld(sdk.DataTypeVARCHAR) - request := sdk.NewCreateForSQLProcedureRequest(id.SchemaObjectId(), *returns, definition). - WithArguments([]sdk.ProcedureArgumentRequest{*argument}). - WithExecuteAs(*sdk.ExecuteAsPointer(sdk.ExecuteAsCaller)) - err := client.Procedures.CreateForSQL(ctx, request) - require.NoError(t, err) - t.Cleanup(cleanupProcedureHandle(id)) - } - - t.Run("show by id - same name in different schemas", func(t *testing.T) { - schema, schemaCleanup := testClientHelper().Schema.CreateSchema(t) - t.Cleanup(schemaCleanup) - - id1 := testClientHelper().Ids.RandomSchemaObjectIdentifierWithArguments(sdk.DataTypeVARCHAR) - id2 := testClientHelper().Ids.NewSchemaObjectIdentifierWithArgumentsInSchema(id1.Name(), schema.ID(), sdk.DataTypeVARCHAR) - - createProcedureForSQLHandle(t, id1) - createProcedureForSQLHandle(t, id2) - - e1, err := client.Procedures.ShowByID(ctx, id1) - require.NoError(t, err) - require.Equal(t, id1, e1.ID()) - - e2, err := client.Procedures.ShowByID(ctx, id2) - require.NoError(t, err) - require.Equal(t, id2, e2.ID()) - }) - - t.Run("show procedure by id - different name, same arguments", func(t *testing.T) { - id1 := testClientHelper().Ids.RandomSchemaObjectIdentifierWithArguments(sdk.DataTypeInt, sdk.DataTypeFloat, sdk.DataTypeVARCHAR) - id2 := testClientHelper().Ids.RandomSchemaObjectIdentifierWithArguments(sdk.DataTypeInt, sdk.DataTypeFloat, sdk.DataTypeVARCHAR) - e := testClientHelper().Procedure.CreateWithIdentifier(t, id1) - testClientHelper().Procedure.CreateWithIdentifier(t, id2) - - es, err := client.Procedures.ShowByID(ctx, id1) - require.NoError(t, err) - require.Equal(t, *e, *es) - }) - - t.Run("show procedure by id - same name, different arguments", func(t *testing.T) { - name := testClientHelper().Ids.Alpha() - id1 := testClientHelper().Ids.NewSchemaObjectIdentifierWithArgumentsInSchema(name, testClientHelper().Ids.SchemaId(), sdk.DataTypeInt, sdk.DataTypeFloat, sdk.DataTypeVARCHAR) - id2 := testClientHelper().Ids.NewSchemaObjectIdentifierWithArgumentsInSchema(name, testClientHelper().Ids.SchemaId(), sdk.DataTypeInt, sdk.DataTypeVARCHAR) - e := testClientHelper().Procedure.CreateWithIdentifier(t, id1) - testClientHelper().Procedure.CreateWithIdentifier(t, id2) - - es, err := client.Procedures.ShowByID(ctx, id1) - require.NoError(t, err) - require.Equal(t, *e, *es) - }) - - // This test shows behavior of detailed types (e.g. VARCHAR(20) and NUMBER(10, 0)) on Snowflake side for procedures. - // For SHOW, data type is generalized both for argument and return type (to e.g. VARCHAR and NUMBER). - // FOR DESCRIBE, data type is generalized for argument and works weirdly for the return type: type is generalized to the canonical one, but we also get the attributes. - for _, tc := range []string{ - "NUMBER(36, 5)", - "NUMBER(36)", - "NUMBER", - "DECIMAL", - "INTEGER", - "FLOAT", - "DOUBLE", - "VARCHAR", - "VARCHAR(20)", - "CHAR", - "CHAR(10)", - "TEXT", - "BINARY", - "BINARY(1000)", - "VARBINARY", - "BOOLEAN", - "DATE", - "DATETIME", - "TIME", - "TIMESTAMP_LTZ", - "TIMESTAMP_NTZ", - "TIMESTAMP_TZ", - "VARIANT", - "OBJECT", - "ARRAY", - "GEOGRAPHY", - "GEOMETRY", - "VECTOR(INT, 16)", - "VECTOR(FLOAT, 8)", - } { - tc := tc - t.Run(fmt.Sprintf("procedure returns non detailed data types of arguments for %s", tc), func(t *testing.T) { - procName := "add" - argName := "A" - dataType, err := datatypes.ParseDataType(tc) - require.NoError(t, err) - args := []sdk.ProcedureArgumentRequest{ - *sdk.NewProcedureArgumentRequest(argName, dataType), - } - oldDataType := sdk.LegacyDataTypeFrom(dataType) - idWithArguments := testClientHelper().Ids.RandomSchemaObjectIdentifierWithArguments(oldDataType) - - packages := []sdk.ProcedurePackageRequest{*sdk.NewProcedurePackageRequest("snowflake-snowpark-python")} - definition := fmt.Sprintf("def add(%[1]s): %[1]s", argName) - - err = client.Procedures.CreateForPython(ctx, sdk.NewCreateForPythonProcedureRequest( - idWithArguments.SchemaObjectId(), - *sdk.NewProcedureReturnsRequest().WithResultDataType(*sdk.NewProcedureReturnsResultDataTypeRequest(dataType)), - "3.8", - packages, - procName, - ). - WithArguments(args). - WithProcedureDefinition(definition), - ) - require.NoError(t, err) - - procedure, err := client.Procedures.ShowByID(ctx, idWithArguments) - require.NoError(t, err) - assert.Equal(t, []sdk.DataType{oldDataType}, procedure.ArgumentsOld) - assert.Equal(t, fmt.Sprintf("%[1]s(%[2]s) RETURN %[2]s", idWithArguments.Name(), oldDataType), procedure.ArgumentsRaw) - - details, err := client.Procedures.Describe(ctx, idWithArguments) - require.NoError(t, err) - pairs := make(map[string]string) - for _, detail := range details { - pairs[detail.Property] = detail.Value - } - assert.Equal(t, fmt.Sprintf("(%s %s)", argName, oldDataType), pairs["signature"]) - assert.Equal(t, dataType.Canonical(), pairs["returns"]) - }) - } -}