From e542b67f761850e812114ce593fa5f6deca941cb Mon Sep 17 00:00:00 2001 From: Scott Winkler Date: Thu, 21 Dec 2023 02:24:10 -0800 Subject: [PATCH] feat: add functions to sdk (#2205) * add functions to sdk * update * update functions * update error func * add todo * add todo * update * fmt * add validations * add unit tests for desc --- pkg/sdk/client.go | 2 + pkg/sdk/common_types.go | 22 + pkg/sdk/functions_def.go | 316 +++++++++ pkg/sdk/functions_dto_builders_gen.go | 575 ++++++++++++++++ pkg/sdk/functions_dto_gen.go | 176 +++++ pkg/sdk/functions_gen.go | 261 +++++++ pkg/sdk/functions_gen_test.go | 649 ++++++++++++++++++ pkg/sdk/functions_impl_gen.go | 448 ++++++++++++ pkg/sdk/functions_validations_gen.go | 189 +++++ pkg/sdk/poc/generator/field_transformers.go | 5 + pkg/sdk/poc/main.go | 1 + pkg/sdk/testint/functions_integration_test.go | 462 +++++++++++++ 12 files changed, 3106 insertions(+) create mode 100644 pkg/sdk/functions_def.go create mode 100644 pkg/sdk/functions_dto_builders_gen.go create mode 100644 pkg/sdk/functions_dto_gen.go create mode 100644 pkg/sdk/functions_gen.go create mode 100644 pkg/sdk/functions_gen_test.go create mode 100644 pkg/sdk/functions_impl_gen.go create mode 100644 pkg/sdk/functions_validations_gen.go create mode 100644 pkg/sdk/testint/functions_integration_test.go diff --git a/pkg/sdk/client.go b/pkg/sdk/client.go index 6f790f84d3..b8170d81e8 100644 --- a/pkg/sdk/client.go +++ b/pkg/sdk/client.go @@ -49,6 +49,7 @@ type Client struct { EventTables EventTables FailoverGroups FailoverGroups FileFormats FileFormats + Functions Functions Grants Grants MaskingPolicies MaskingPolicies NetworkPolicies NetworkPolicies @@ -189,6 +190,7 @@ func (c *Client) initialize() { c.EventTables = &eventTables{client: c} c.FailoverGroups = &failoverGroups{client: c} c.FileFormats = &fileFormats{client: c} + c.Functions = &functions{client: c} c.Grants = &grants{client: c} c.MaskingPolicies = &maskingPolicies{client: c} c.NetworkPolicies = &networkPolicies{client: c} diff --git a/pkg/sdk/common_types.go b/pkg/sdk/common_types.go index 2c5061767f..4a93ac05bc 100644 --- a/pkg/sdk/common_types.go +++ b/pkg/sdk/common_types.go @@ -172,6 +172,28 @@ const ( NullInputBehaviorStrict NullInputBehavior = "STRICT" ) +type ReturnResultsBehavior string + +var ( + ReturnResultsBehaviorVolatile ReturnResultsBehavior = "VOLATILE" + ReturnResultsBehaviorImmutable ReturnResultsBehavior = "IMMUTABLE" +) + +func ReturnResultsBehaviorPointer(v ReturnResultsBehavior) *ReturnResultsBehavior { + return &v +} + +type ReturnNullValues string + +var ( + ReturnNullValuesNull ReturnNullValues = "NULL" + ReturnNullValuesNotNull ReturnNullValues = "NOT NULL" +) + +func ReturnNullValuesPointer(v ReturnNullValues) *ReturnNullValues { + return &v +} + type Secret struct { VariableName string `ddl:"keyword,single_quotes"` Name string `ddl:"parameter,no_quotes"` diff --git a/pkg/sdk/functions_def.go b/pkg/sdk/functions_def.go new file mode 100644 index 0000000000..81ac15c91d --- /dev/null +++ b/pkg/sdk/functions_def.go @@ -0,0 +1,316 @@ +package sdk + +import g "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk/poc/generator" + +//go:generate go run ./poc/main.go + +var functionArgument = g.NewQueryStruct("FunctionArgument"). + Text("ArgName", g.KeywordOptions().NoQuotes().Required()). + PredefinedQueryStructField("ArgDataType", "DataType", g.KeywordOptions().NoQuotes().Required()). + PredefinedQueryStructField("DefaultValue", "*string", g.ParameterOptions().NoEquals().SQL("DEFAULT")) + +var functionColumn = g.NewQueryStruct("FunctionColumn"). + Text("ColumnName", g.KeywordOptions().NoQuotes().Required()). + PredefinedQueryStructField("ColumnDataType", "DataType", g.KeywordOptions().NoQuotes().Required()) + +var functionReturns = g.NewQueryStruct("FunctionReturns"). + OptionalQueryStructField( + "ResultDataType", + g.NewQueryStruct("FunctionReturnsResultDataType"). + PredefinedQueryStructField("ResultDataType", "DataType", g.KeywordOptions().NoQuotes().Required()), + g.KeywordOptions(), + ). + OptionalQueryStructField( + "Table", + g.NewQueryStruct("FunctionReturnsTable"). + ListQueryStructField( + "Columns", + functionColumn, + g.ParameterOptions().Parentheses().NoEquals(), + ), + g.KeywordOptions().SQL("TABLE"), + ).WithValidation(g.ExactlyOneValueSet, "ResultDataType", "Table") + +var ( + functionImports = g.NewQueryStruct("FunctionImport").Text("Import", g.KeywordOptions().SingleQuotes()) + functionPackages = g.NewQueryStruct("FunctionPackage").Text("Package", g.KeywordOptions().SingleQuotes()) +) + +var FunctionsDef = g.NewInterface( + "Functions", + "Function", + g.KindOfT[SchemaObjectIdentifier](), +).CustomOperation( + "CreateForJava", + "https://docs.snowflake.com/en/sql-reference/sql/create-function#java-handler", + g.NewQueryStruct("CreateForJava"). + Create(). + OrReplace(). + OptionalSQL("TEMPORARY"). + OptionalSQL("SECURE"). + SQL("FUNCTION"). + IfNotExists(). + Name(). + ListQueryStructField( + "Arguments", + functionArgument, + g.ListOptions().MustParentheses()). + OptionalSQL("COPY GRANTS"). + QueryStructField( + "Returns", + functionReturns, + g.KeywordOptions().SQL("RETURNS").Required(), + ). + PredefinedQueryStructField("ReturnNullValues", "*ReturnNullValues", g.KeywordOptions()). + SQL("LANGUAGE JAVA"). + PredefinedQueryStructField("NullInputBehavior", "*NullInputBehavior", g.KeywordOptions()). + PredefinedQueryStructField("ReturnResultsBehavior", "*ReturnResultsBehavior", g.KeywordOptions()). + OptionalTextAssignment("RUNTIME_VERSION", g.ParameterOptions().SingleQuotes()). + OptionalTextAssignment("COMMENT", g.ParameterOptions().SingleQuotes()). + ListQueryStructField( + "Imports", + functionImports, + g.ParameterOptions().Parentheses().SQL("IMPORTS"), + ). + ListQueryStructField( + "Packages", + functionPackages, + g.ParameterOptions().Parentheses().SQL("PACKAGES"), + ). + TextAssignment("HANDLER", g.ParameterOptions().SingleQuotes().Required()). + ListAssignment("EXTERNAL_ACCESS_INTEGRATIONS", "AccountObjectIdentifier", g.ParameterOptions().Parentheses()). + ListAssignment("SECRETS", "Secret", g.ParameterOptions().Parentheses()). + OptionalTextAssignment("TARGET_PATH", g.ParameterOptions().SingleQuotes()). + PredefinedQueryStructField("FunctionDefinition", "*string", g.ParameterOptions().NoEquals().SingleQuotes().SQL("AS")). + WithValidation(g.ValidIdentifier, "name"). + WithValidation(g.ValidateValueSet, "Handler"). + WithValidation(g.ConflictingFields, "OrReplace", "IfNotExists"), +).CustomOperation( + "CreateForJavascript", + "https://docs.snowflake.com/en/sql-reference/sql/create-function#javascript-handler", + g.NewQueryStruct("CreateForJavascript"). + Create(). + OrReplace(). + OptionalSQL("TEMPORARY"). + OptionalSQL("SECURE"). + SQL("FUNCTION"). + Name(). + ListQueryStructField( + "Arguments", + functionArgument, + g.ListOptions().MustParentheses()). + OptionalSQL("COPY GRANTS"). + QueryStructField( + "Returns", + functionReturns, + g.KeywordOptions().SQL("RETURNS").Required(), + ). + PredefinedQueryStructField("ReturnNullValues", "*ReturnNullValues", g.KeywordOptions()). + SQL("LANGUAGE JAVASCRIPT"). + PredefinedQueryStructField("NullInputBehavior", "*NullInputBehavior", g.KeywordOptions()). + PredefinedQueryStructField("ReturnResultsBehavior", "*ReturnResultsBehavior", g.KeywordOptions()). + OptionalTextAssignment("COMMENT", g.ParameterOptions().SingleQuotes()). + PredefinedQueryStructField("FunctionDefinition", "string", g.ParameterOptions().NoEquals().SingleQuotes().SQL("AS").Required()). + WithValidation(g.ValidateValueSet, "FunctionDefinition"). + WithValidation(g.ValidIdentifier, "name"), +).CustomOperation( + "CreateForPython", + "https://docs.snowflake.com/en/sql-reference/sql/create-function#python-handler", + g.NewQueryStruct("CreateForPython"). + Create(). + OrReplace(). + OptionalSQL("TEMPORARY"). + OptionalSQL("SECURE"). + SQL("FUNCTION"). + IfNotExists(). + Name(). + ListQueryStructField( + "Arguments", + functionArgument, + g.ListOptions().MustParentheses()). + OptionalSQL("COPY GRANTS"). + QueryStructField( + "Returns", + functionReturns, + g.KeywordOptions().SQL("RETURNS").Required(), + ). + PredefinedQueryStructField("ReturnNullValues", "*ReturnNullValues", g.KeywordOptions()). + SQL("LANGUAGE PYTHON"). + PredefinedQueryStructField("NullInputBehavior", "*NullInputBehavior", g.KeywordOptions()). + PredefinedQueryStructField("ReturnResultsBehavior", "*ReturnResultsBehavior", g.KeywordOptions()). + TextAssignment("RUNTIME_VERSION", g.ParameterOptions().SingleQuotes().Required()). + OptionalTextAssignment("COMMENT", g.ParameterOptions().SingleQuotes()). + ListQueryStructField( + "Imports", + functionImports, + g.ParameterOptions().Parentheses().SQL("IMPORTS"), + ). + ListQueryStructField( + "Packages", + functionPackages, + g.ParameterOptions().Parentheses().SQL("PACKAGES"), + ). + TextAssignment("HANDLER", g.ParameterOptions().SingleQuotes().Required()). + ListAssignment("EXTERNAL_ACCESS_INTEGRATIONS", "AccountObjectIdentifier", g.ParameterOptions().Parentheses()). + ListAssignment("SECRETS", "Secret", g.ParameterOptions().Parentheses()). + PredefinedQueryStructField("FunctionDefinition", "*string", g.ParameterOptions().NoEquals().SingleQuotes().SQL("AS")). + WithValidation(g.ValidIdentifier, "name"). + WithValidation(g.ValidateValueSet, "RuntimeVersion"). + WithValidation(g.ValidateValueSet, "Handler"). + WithValidation(g.ConflictingFields, "OrReplace", "IfNotExists"), +).CustomOperation( + "CreateForScala", + "https://docs.snowflake.com/en/sql-reference/sql/create-function#scala-handler", + g.NewQueryStruct("CreateForScala"). + Create(). + OrReplace(). + OptionalSQL("TEMPORARY"). + OptionalSQL("SECURE"). + SQL("FUNCTION"). + IfNotExists(). + Name(). + ListQueryStructField( + "Arguments", + functionArgument, + g.ListOptions().MustParentheses()). + OptionalSQL("COPY GRANTS"). + PredefinedQueryStructField("ResultDataType", "DataType", g.ParameterOptions().NoEquals().SQL("RETURNS").Required()). + PredefinedQueryStructField("ReturnNullValues", "*ReturnNullValues", g.KeywordOptions()). + SQL("LANGUAGE SCALA"). + PredefinedQueryStructField("NullInputBehavior", "*NullInputBehavior", g.KeywordOptions()). + PredefinedQueryStructField("ReturnResultsBehavior", "*ReturnResultsBehavior", g.KeywordOptions()). + OptionalTextAssignment("RUNTIME_VERSION", g.ParameterOptions().SingleQuotes()). + OptionalTextAssignment("COMMENT", g.ParameterOptions().SingleQuotes()). + ListQueryStructField( + "Imports", + functionImports, + g.ParameterOptions().Parentheses().SQL("IMPORTS"), + ). + ListQueryStructField( + "Packages", + functionPackages, + g.ParameterOptions().Parentheses().SQL("PACKAGES"), + ). + TextAssignment("HANDLER", g.ParameterOptions().SingleQuotes().Required()). + OptionalTextAssignment("TARGET_PATH", g.ParameterOptions().SingleQuotes()). + PredefinedQueryStructField("FunctionDefinition", "*string", g.ParameterOptions().NoEquals().SingleQuotes().SQL("AS")). + WithValidation(g.ValidIdentifier, "name"). + WithValidation(g.ValidateValueSet, "Handler"). + WithValidation(g.ConflictingFields, "OrReplace", "IfNotExists"), +).CustomOperation( + "CreateForSQL", + "https://docs.snowflake.com/en/sql-reference/sql/create-function#sql-handler", + g.NewQueryStruct("CreateForSQL"). + Create(). + OrReplace(). + OptionalSQL("TEMPORARY"). + OptionalSQL("SECURE"). + SQL("FUNCTION"). + Name(). + ListQueryStructField( + "Arguments", + functionArgument, + g.ListOptions().MustParentheses()). + OptionalSQL("COPY GRANTS"). + QueryStructField( + "Returns", + functionReturns, + g.KeywordOptions().SQL("RETURNS").Required(), + ). + PredefinedQueryStructField("ReturnNullValues", "*ReturnNullValues", g.KeywordOptions()). + PredefinedQueryStructField("ReturnResultsBehavior", "*ReturnResultsBehavior", g.KeywordOptions()). + OptionalSQL("MEMOIZABLE"). + OptionalTextAssignment("COMMENT", g.ParameterOptions().SingleQuotes()). + PredefinedQueryStructField("FunctionDefinition", "string", g.ParameterOptions().NoEquals().SingleQuotes().SQL("AS").Required()). + WithValidation(g.ValidateValueSet, "FunctionDefinition"). + WithValidation(g.ValidIdentifier, "name"), +).AlterOperation( + "https://docs.snowflake.com/en/sql-reference/sql/alter-function", + g.NewQueryStruct("AlterFunction"). + Alter(). + SQL("FUNCTION"). + IfExists(). + Name(). + PredefinedQueryStructField("ArgumentDataTypes", "[]DataType", g.KeywordOptions().MustParentheses().Required()). + Identifier("RenameTo", g.KindOfTPointer[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("SET SECURE"). + OptionalSQL("UNSET SECURE"). + OptionalSQL("UNSET LOG_LEVEL"). + OptionalSQL("UNSET TRACE_LEVEL"). + OptionalSQL("UNSET COMMENT"). + OptionalSetTags(). + OptionalUnsetTags(). + WithValidation(g.ValidIdentifier, "name"). + WithValidation(g.ValidIdentifierIfSet, "RenameTo"). + WithValidation(g.ExactlyOneValueSet, "RenameTo", "SetComment", "SetLogLevel", "SetTraceLevel", "SetSecure", "UnsetLogLevel", "UnsetTraceLevel", "UnsetSecure", "UnsetComment", "SetTags", "UnsetTags"), +).DropOperation( + "https://docs.snowflake.com/en/sql-reference/sql/drop-function", + g.NewQueryStruct("DropFunction"). + Drop(). + SQL("FUNCTION"). + IfExists(). + Name(). + PredefinedQueryStructField("ArgumentDataTypes", "[]DataType", g.KeywordOptions().MustParentheses().Required()). + WithValidation(g.ValidIdentifier, "name"), +).ShowOperation( + "https://docs.snowflake.com/en/sql-reference/sql/show-user-functions", + g.DbStruct("functionRow"). + Field("created_on", "string"). + Field("name", "string"). + Field("schema_name", "string"). + Field("is_builtin", "string"). + Field("is_aggregate", "string"). + Field("is_ansi", "string"). + Field("min_num_arguments", "int"). + Field("max_num_arguments", "int"). + Field("arguments", "string"). + Field("description", "string"). + Field("catalog_name", "string"). + Field("is_table_function", "string"). + Field("valid_for_clustering", "string"). + Field("is_secure", "sql.NullString"). + Field("is_external_function", "string"). + Field("language", "string"). + Field("is_memoizable", "sql.NullString"), + g.PlainStruct("Function"). + Field("CreatedOn", "string"). + Field("Name", "string"). + Field("SchemaName", "string"). + Field("IsBuiltin", "bool"). + Field("IsAggregate", "bool"). + Field("IsAnsi", "bool"). + Field("MinNumArguments", "int"). + Field("MaxNumArguments", "int"). + Field("Arguments", "string"). + Field("Description", "string"). + Field("CatalogName", "string"). + Field("IsTableFunction", "bool"). + Field("ValidForClustering", "bool"). + Field("IsSecure", "bool"). + Field("IsExternalFunction", "bool"). + Field("Language", "string"). + Field("IsMemoizable", "bool"), + g.NewQueryStruct("ShowFunctions"). + Show(). + SQL("USER FUNCTIONS"). + OptionalLike(). + OptionalIn(), +).ShowByIdOperation().DescribeOperation( + g.DescriptionMappingKindSlice, + "https://docs.snowflake.com/en/sql-reference/sql/desc-function", + g.DbStruct("functionDetailRow"). + Field("property", "string"). + Field("value", "string"), + g.PlainStruct("FunctionDetail"). + Field("Property", "string"). + Field("Value", "string"), + g.NewQueryStruct("DescribeFunction"). + Describe(). + SQL("FUNCTION"). + Name(). + PredefinedQueryStructField("ArgumentDataTypes", "[]DataType", g.KeywordOptions().MustParentheses().Required()). + WithValidation(g.ValidIdentifier, "name"), +) diff --git a/pkg/sdk/functions_dto_builders_gen.go b/pkg/sdk/functions_dto_builders_gen.go new file mode 100644 index 0000000000..4cb8f160fa --- /dev/null +++ b/pkg/sdk/functions_dto_builders_gen.go @@ -0,0 +1,575 @@ +// Code generated by dto builder generator; DO NOT EDIT. + +package sdk + +import () + +func NewCreateForJavaFunctionRequest( + name SchemaObjectIdentifier, + Returns FunctionReturnsRequest, + Handler string, +) *CreateForJavaFunctionRequest { + s := CreateForJavaFunctionRequest{} + s.name = name + s.Returns = Returns + s.Handler = Handler + return &s +} + +func (s *CreateForJavaFunctionRequest) WithOrReplace(OrReplace *bool) *CreateForJavaFunctionRequest { + s.OrReplace = OrReplace + return s +} + +func (s *CreateForJavaFunctionRequest) WithTemporary(Temporary *bool) *CreateForJavaFunctionRequest { + s.Temporary = Temporary + return s +} + +func (s *CreateForJavaFunctionRequest) WithSecure(Secure *bool) *CreateForJavaFunctionRequest { + s.Secure = Secure + return s +} + +func (s *CreateForJavaFunctionRequest) WithIfNotExists(IfNotExists *bool) *CreateForJavaFunctionRequest { + s.IfNotExists = IfNotExists + return s +} + +func (s *CreateForJavaFunctionRequest) WithArguments(Arguments []FunctionArgumentRequest) *CreateForJavaFunctionRequest { + s.Arguments = Arguments + return s +} + +func (s *CreateForJavaFunctionRequest) WithCopyGrants(CopyGrants *bool) *CreateForJavaFunctionRequest { + s.CopyGrants = CopyGrants + return s +} + +func (s *CreateForJavaFunctionRequest) WithReturnNullValues(ReturnNullValues *ReturnNullValues) *CreateForJavaFunctionRequest { + s.ReturnNullValues = ReturnNullValues + return s +} + +func (s *CreateForJavaFunctionRequest) WithNullInputBehavior(NullInputBehavior *NullInputBehavior) *CreateForJavaFunctionRequest { + s.NullInputBehavior = NullInputBehavior + return s +} + +func (s *CreateForJavaFunctionRequest) WithReturnResultsBehavior(ReturnResultsBehavior *ReturnResultsBehavior) *CreateForJavaFunctionRequest { + s.ReturnResultsBehavior = ReturnResultsBehavior + return s +} + +func (s *CreateForJavaFunctionRequest) WithRuntimeVersion(RuntimeVersion *string) *CreateForJavaFunctionRequest { + s.RuntimeVersion = RuntimeVersion + return s +} + +func (s *CreateForJavaFunctionRequest) WithComment(Comment *string) *CreateForJavaFunctionRequest { + s.Comment = Comment + return s +} + +func (s *CreateForJavaFunctionRequest) WithImports(Imports []FunctionImportRequest) *CreateForJavaFunctionRequest { + s.Imports = Imports + return s +} + +func (s *CreateForJavaFunctionRequest) WithPackages(Packages []FunctionPackageRequest) *CreateForJavaFunctionRequest { + s.Packages = Packages + return s +} + +func (s *CreateForJavaFunctionRequest) WithExternalAccessIntegrations(ExternalAccessIntegrations []AccountObjectIdentifier) *CreateForJavaFunctionRequest { + s.ExternalAccessIntegrations = ExternalAccessIntegrations + return s +} + +func (s *CreateForJavaFunctionRequest) WithSecrets(Secrets []Secret) *CreateForJavaFunctionRequest { + s.Secrets = Secrets + return s +} + +func (s *CreateForJavaFunctionRequest) WithTargetPath(TargetPath *string) *CreateForJavaFunctionRequest { + s.TargetPath = TargetPath + return s +} + +func (s *CreateForJavaFunctionRequest) WithFunctionDefinition(FunctionDefinition *string) *CreateForJavaFunctionRequest { + s.FunctionDefinition = FunctionDefinition + return s +} + +func NewFunctionArgumentRequest( + ArgName string, + ArgDataType DataType, +) *FunctionArgumentRequest { + s := FunctionArgumentRequest{} + s.ArgName = ArgName + s.ArgDataType = ArgDataType + return &s +} + +func (s *FunctionArgumentRequest) WithDefaultValue(DefaultValue *string) *FunctionArgumentRequest { + s.DefaultValue = DefaultValue + return s +} + +func NewFunctionReturnsRequest() *FunctionReturnsRequest { + return &FunctionReturnsRequest{} +} + +func (s *FunctionReturnsRequest) WithResultDataType(ResultDataType *FunctionReturnsResultDataTypeRequest) *FunctionReturnsRequest { + s.ResultDataType = ResultDataType + return s +} + +func (s *FunctionReturnsRequest) WithTable(Table *FunctionReturnsTableRequest) *FunctionReturnsRequest { + s.Table = Table + return s +} + +func NewFunctionReturnsResultDataTypeRequest( + ResultDataType DataType, +) *FunctionReturnsResultDataTypeRequest { + s := FunctionReturnsResultDataTypeRequest{} + s.ResultDataType = ResultDataType + return &s +} + +func NewFunctionReturnsTableRequest() *FunctionReturnsTableRequest { + return &FunctionReturnsTableRequest{} +} + +func (s *FunctionReturnsTableRequest) WithColumns(Columns []FunctionColumnRequest) *FunctionReturnsTableRequest { + s.Columns = Columns + return s +} + +func NewFunctionColumnRequest( + ColumnName string, + ColumnDataType DataType, +) *FunctionColumnRequest { + s := FunctionColumnRequest{} + s.ColumnName = ColumnName + s.ColumnDataType = ColumnDataType + return &s +} + +func NewFunctionImportRequest() *FunctionImportRequest { + return &FunctionImportRequest{} +} + +func (s *FunctionImportRequest) WithImport(Import string) *FunctionImportRequest { + s.Import = Import + return s +} + +func NewFunctionPackageRequest() *FunctionPackageRequest { + return &FunctionPackageRequest{} +} + +func (s *FunctionPackageRequest) WithPackage(Package string) *FunctionPackageRequest { + s.Package = Package + return s +} + +func NewCreateForJavascriptFunctionRequest( + name SchemaObjectIdentifier, + Returns FunctionReturnsRequest, + FunctionDefinition string, +) *CreateForJavascriptFunctionRequest { + s := CreateForJavascriptFunctionRequest{} + s.name = name + s.Returns = Returns + s.FunctionDefinition = FunctionDefinition + return &s +} + +func (s *CreateForJavascriptFunctionRequest) WithOrReplace(OrReplace *bool) *CreateForJavascriptFunctionRequest { + s.OrReplace = OrReplace + return s +} + +func (s *CreateForJavascriptFunctionRequest) WithTemporary(Temporary *bool) *CreateForJavascriptFunctionRequest { + s.Temporary = Temporary + return s +} + +func (s *CreateForJavascriptFunctionRequest) WithSecure(Secure *bool) *CreateForJavascriptFunctionRequest { + s.Secure = Secure + return s +} + +func (s *CreateForJavascriptFunctionRequest) WithArguments(Arguments []FunctionArgumentRequest) *CreateForJavascriptFunctionRequest { + s.Arguments = Arguments + return s +} + +func (s *CreateForJavascriptFunctionRequest) WithCopyGrants(CopyGrants *bool) *CreateForJavascriptFunctionRequest { + s.CopyGrants = CopyGrants + return s +} + +func (s *CreateForJavascriptFunctionRequest) WithReturnNullValues(ReturnNullValues *ReturnNullValues) *CreateForJavascriptFunctionRequest { + s.ReturnNullValues = ReturnNullValues + return s +} + +func (s *CreateForJavascriptFunctionRequest) WithNullInputBehavior(NullInputBehavior *NullInputBehavior) *CreateForJavascriptFunctionRequest { + s.NullInputBehavior = NullInputBehavior + return s +} + +func (s *CreateForJavascriptFunctionRequest) WithReturnResultsBehavior(ReturnResultsBehavior *ReturnResultsBehavior) *CreateForJavascriptFunctionRequest { + s.ReturnResultsBehavior = ReturnResultsBehavior + return s +} + +func (s *CreateForJavascriptFunctionRequest) WithComment(Comment *string) *CreateForJavascriptFunctionRequest { + s.Comment = Comment + return s +} + +func NewCreateForPythonFunctionRequest( + name SchemaObjectIdentifier, + Returns FunctionReturnsRequest, + RuntimeVersion string, + Handler string, +) *CreateForPythonFunctionRequest { + s := CreateForPythonFunctionRequest{} + s.name = name + s.Returns = Returns + s.RuntimeVersion = RuntimeVersion + s.Handler = Handler + return &s +} + +func (s *CreateForPythonFunctionRequest) WithOrReplace(OrReplace *bool) *CreateForPythonFunctionRequest { + s.OrReplace = OrReplace + return s +} + +func (s *CreateForPythonFunctionRequest) WithTemporary(Temporary *bool) *CreateForPythonFunctionRequest { + s.Temporary = Temporary + return s +} + +func (s *CreateForPythonFunctionRequest) WithSecure(Secure *bool) *CreateForPythonFunctionRequest { + s.Secure = Secure + return s +} + +func (s *CreateForPythonFunctionRequest) WithIfNotExists(IfNotExists *bool) *CreateForPythonFunctionRequest { + s.IfNotExists = IfNotExists + return s +} + +func (s *CreateForPythonFunctionRequest) WithArguments(Arguments []FunctionArgumentRequest) *CreateForPythonFunctionRequest { + s.Arguments = Arguments + return s +} + +func (s *CreateForPythonFunctionRequest) WithCopyGrants(CopyGrants *bool) *CreateForPythonFunctionRequest { + s.CopyGrants = CopyGrants + return s +} + +func (s *CreateForPythonFunctionRequest) WithReturnNullValues(ReturnNullValues *ReturnNullValues) *CreateForPythonFunctionRequest { + s.ReturnNullValues = ReturnNullValues + return s +} + +func (s *CreateForPythonFunctionRequest) WithNullInputBehavior(NullInputBehavior *NullInputBehavior) *CreateForPythonFunctionRequest { + s.NullInputBehavior = NullInputBehavior + return s +} + +func (s *CreateForPythonFunctionRequest) WithReturnResultsBehavior(ReturnResultsBehavior *ReturnResultsBehavior) *CreateForPythonFunctionRequest { + s.ReturnResultsBehavior = ReturnResultsBehavior + return s +} + +func (s *CreateForPythonFunctionRequest) WithComment(Comment *string) *CreateForPythonFunctionRequest { + s.Comment = Comment + return s +} + +func (s *CreateForPythonFunctionRequest) WithImports(Imports []FunctionImportRequest) *CreateForPythonFunctionRequest { + s.Imports = Imports + return s +} + +func (s *CreateForPythonFunctionRequest) WithPackages(Packages []FunctionPackageRequest) *CreateForPythonFunctionRequest { + s.Packages = Packages + return s +} + +func (s *CreateForPythonFunctionRequest) WithExternalAccessIntegrations(ExternalAccessIntegrations []AccountObjectIdentifier) *CreateForPythonFunctionRequest { + s.ExternalAccessIntegrations = ExternalAccessIntegrations + return s +} + +func (s *CreateForPythonFunctionRequest) WithSecrets(Secrets []Secret) *CreateForPythonFunctionRequest { + s.Secrets = Secrets + return s +} + +func (s *CreateForPythonFunctionRequest) WithFunctionDefinition(FunctionDefinition *string) *CreateForPythonFunctionRequest { + s.FunctionDefinition = FunctionDefinition + return s +} + +func NewCreateForScalaFunctionRequest( + name SchemaObjectIdentifier, + ResultDataType DataType, + Handler string, +) *CreateForScalaFunctionRequest { + s := CreateForScalaFunctionRequest{} + s.name = name + s.ResultDataType = ResultDataType + s.Handler = Handler + return &s +} + +func (s *CreateForScalaFunctionRequest) WithOrReplace(OrReplace *bool) *CreateForScalaFunctionRequest { + s.OrReplace = OrReplace + return s +} + +func (s *CreateForScalaFunctionRequest) WithTemporary(Temporary *bool) *CreateForScalaFunctionRequest { + s.Temporary = Temporary + return s +} + +func (s *CreateForScalaFunctionRequest) WithSecure(Secure *bool) *CreateForScalaFunctionRequest { + s.Secure = Secure + return s +} + +func (s *CreateForScalaFunctionRequest) WithIfNotExists(IfNotExists *bool) *CreateForScalaFunctionRequest { + s.IfNotExists = IfNotExists + return s +} + +func (s *CreateForScalaFunctionRequest) WithArguments(Arguments []FunctionArgumentRequest) *CreateForScalaFunctionRequest { + s.Arguments = Arguments + return s +} + +func (s *CreateForScalaFunctionRequest) WithCopyGrants(CopyGrants *bool) *CreateForScalaFunctionRequest { + s.CopyGrants = CopyGrants + return s +} + +func (s *CreateForScalaFunctionRequest) WithReturnNullValues(ReturnNullValues *ReturnNullValues) *CreateForScalaFunctionRequest { + s.ReturnNullValues = ReturnNullValues + return s +} + +func (s *CreateForScalaFunctionRequest) WithNullInputBehavior(NullInputBehavior *NullInputBehavior) *CreateForScalaFunctionRequest { + s.NullInputBehavior = NullInputBehavior + return s +} + +func (s *CreateForScalaFunctionRequest) WithReturnResultsBehavior(ReturnResultsBehavior *ReturnResultsBehavior) *CreateForScalaFunctionRequest { + s.ReturnResultsBehavior = ReturnResultsBehavior + return s +} + +func (s *CreateForScalaFunctionRequest) WithRuntimeVersion(RuntimeVersion *string) *CreateForScalaFunctionRequest { + s.RuntimeVersion = RuntimeVersion + return s +} + +func (s *CreateForScalaFunctionRequest) WithComment(Comment *string) *CreateForScalaFunctionRequest { + s.Comment = Comment + return s +} + +func (s *CreateForScalaFunctionRequest) WithImports(Imports []FunctionImportRequest) *CreateForScalaFunctionRequest { + s.Imports = Imports + return s +} + +func (s *CreateForScalaFunctionRequest) WithPackages(Packages []FunctionPackageRequest) *CreateForScalaFunctionRequest { + s.Packages = Packages + return s +} + +func (s *CreateForScalaFunctionRequest) WithTargetPath(TargetPath *string) *CreateForScalaFunctionRequest { + s.TargetPath = TargetPath + return s +} + +func (s *CreateForScalaFunctionRequest) WithFunctionDefinition(FunctionDefinition *string) *CreateForScalaFunctionRequest { + s.FunctionDefinition = FunctionDefinition + return s +} + +func NewCreateForSQLFunctionRequest( + name SchemaObjectIdentifier, + Returns FunctionReturnsRequest, + FunctionDefinition string, +) *CreateForSQLFunctionRequest { + s := CreateForSQLFunctionRequest{} + s.name = name + s.Returns = Returns + s.FunctionDefinition = FunctionDefinition + return &s +} + +func (s *CreateForSQLFunctionRequest) WithOrReplace(OrReplace *bool) *CreateForSQLFunctionRequest { + s.OrReplace = OrReplace + return s +} + +func (s *CreateForSQLFunctionRequest) WithTemporary(Temporary *bool) *CreateForSQLFunctionRequest { + s.Temporary = Temporary + return s +} + +func (s *CreateForSQLFunctionRequest) WithSecure(Secure *bool) *CreateForSQLFunctionRequest { + s.Secure = Secure + return s +} + +func (s *CreateForSQLFunctionRequest) WithArguments(Arguments []FunctionArgumentRequest) *CreateForSQLFunctionRequest { + s.Arguments = Arguments + return s +} + +func (s *CreateForSQLFunctionRequest) WithCopyGrants(CopyGrants *bool) *CreateForSQLFunctionRequest { + s.CopyGrants = CopyGrants + return s +} + +func (s *CreateForSQLFunctionRequest) WithReturnNullValues(ReturnNullValues *ReturnNullValues) *CreateForSQLFunctionRequest { + s.ReturnNullValues = ReturnNullValues + return s +} + +func (s *CreateForSQLFunctionRequest) WithReturnResultsBehavior(ReturnResultsBehavior *ReturnResultsBehavior) *CreateForSQLFunctionRequest { + s.ReturnResultsBehavior = ReturnResultsBehavior + return s +} + +func (s *CreateForSQLFunctionRequest) WithMemoizable(Memoizable *bool) *CreateForSQLFunctionRequest { + s.Memoizable = Memoizable + return s +} + +func (s *CreateForSQLFunctionRequest) WithComment(Comment *string) *CreateForSQLFunctionRequest { + s.Comment = Comment + return s +} + +func NewAlterFunctionRequest( + name SchemaObjectIdentifier, + ArgumentDataTypes []DataType, +) *AlterFunctionRequest { + s := AlterFunctionRequest{} + s.name = name + s.ArgumentDataTypes = ArgumentDataTypes + return &s +} + +func (s *AlterFunctionRequest) WithIfExists(IfExists *bool) *AlterFunctionRequest { + s.IfExists = IfExists + return s +} + +func (s *AlterFunctionRequest) WithRenameTo(RenameTo *SchemaObjectIdentifier) *AlterFunctionRequest { + s.RenameTo = RenameTo + return s +} + +func (s *AlterFunctionRequest) WithSetComment(SetComment *string) *AlterFunctionRequest { + s.SetComment = SetComment + return s +} + +func (s *AlterFunctionRequest) WithSetLogLevel(SetLogLevel *string) *AlterFunctionRequest { + s.SetLogLevel = SetLogLevel + return s +} + +func (s *AlterFunctionRequest) WithSetTraceLevel(SetTraceLevel *string) *AlterFunctionRequest { + s.SetTraceLevel = SetTraceLevel + return s +} + +func (s *AlterFunctionRequest) WithSetSecure(SetSecure *bool) *AlterFunctionRequest { + s.SetSecure = SetSecure + return s +} + +func (s *AlterFunctionRequest) WithUnsetSecure(UnsetSecure *bool) *AlterFunctionRequest { + s.UnsetSecure = UnsetSecure + return s +} + +func (s *AlterFunctionRequest) WithUnsetLogLevel(UnsetLogLevel *bool) *AlterFunctionRequest { + s.UnsetLogLevel = UnsetLogLevel + return s +} + +func (s *AlterFunctionRequest) WithUnsetTraceLevel(UnsetTraceLevel *bool) *AlterFunctionRequest { + s.UnsetTraceLevel = UnsetTraceLevel + return s +} + +func (s *AlterFunctionRequest) WithUnsetComment(UnsetComment *bool) *AlterFunctionRequest { + s.UnsetComment = UnsetComment + return s +} + +func (s *AlterFunctionRequest) WithSetTags(SetTags []TagAssociation) *AlterFunctionRequest { + s.SetTags = SetTags + return s +} + +func (s *AlterFunctionRequest) WithUnsetTags(UnsetTags []ObjectIdentifier) *AlterFunctionRequest { + s.UnsetTags = UnsetTags + return s +} + +func NewDropFunctionRequest( + name SchemaObjectIdentifier, + ArgumentDataTypes []DataType, +) *DropFunctionRequest { + s := DropFunctionRequest{} + s.name = name + s.ArgumentDataTypes = ArgumentDataTypes + return &s +} + +func (s *DropFunctionRequest) WithIfExists(IfExists *bool) *DropFunctionRequest { + s.IfExists = IfExists + return s +} + +func NewShowFunctionRequest() *ShowFunctionRequest { + return &ShowFunctionRequest{} +} + +func (s *ShowFunctionRequest) WithLike(Like *Like) *ShowFunctionRequest { + s.Like = Like + return s +} + +func (s *ShowFunctionRequest) WithIn(In *In) *ShowFunctionRequest { + s.In = In + return s +} + +func NewDescribeFunctionRequest( + name SchemaObjectIdentifier, + ArgumentDataTypes []DataType, +) *DescribeFunctionRequest { + s := DescribeFunctionRequest{} + s.name = name + s.ArgumentDataTypes = ArgumentDataTypes + return &s +} diff --git a/pkg/sdk/functions_dto_gen.go b/pkg/sdk/functions_dto_gen.go new file mode 100644 index 0000000000..78b8224c1a --- /dev/null +++ b/pkg/sdk/functions_dto_gen.go @@ -0,0 +1,176 @@ +package sdk + +//go:generate go run ./dto-builder-generator/main.go + +var ( + _ optionsProvider[CreateForJavaFunctionOptions] = new(CreateForJavaFunctionRequest) + _ optionsProvider[CreateForJavascriptFunctionOptions] = new(CreateForJavascriptFunctionRequest) + _ optionsProvider[CreateForPythonFunctionOptions] = new(CreateForPythonFunctionRequest) + _ optionsProvider[CreateForScalaFunctionOptions] = new(CreateForScalaFunctionRequest) + _ optionsProvider[CreateForSQLFunctionOptions] = new(CreateForSQLFunctionRequest) + _ optionsProvider[AlterFunctionOptions] = new(AlterFunctionRequest) + _ optionsProvider[DropFunctionOptions] = new(DropFunctionRequest) + _ optionsProvider[ShowFunctionOptions] = new(ShowFunctionRequest) + _ optionsProvider[DescribeFunctionOptions] = new(DescribeFunctionRequest) +) + +type CreateForJavaFunctionRequest struct { + OrReplace *bool + Temporary *bool + Secure *bool + IfNotExists *bool + name SchemaObjectIdentifier // required + Arguments []FunctionArgumentRequest + CopyGrants *bool + Returns FunctionReturnsRequest // required + ReturnNullValues *ReturnNullValues + NullInputBehavior *NullInputBehavior + ReturnResultsBehavior *ReturnResultsBehavior + RuntimeVersion *string + Comment *string + Imports []FunctionImportRequest + Packages []FunctionPackageRequest + Handler string // required + ExternalAccessIntegrations []AccountObjectIdentifier + Secrets []Secret + TargetPath *string + FunctionDefinition *string +} + +type FunctionArgumentRequest struct { + ArgName string // required + ArgDataType DataType // required + DefaultValue *string +} + +type FunctionReturnsRequest struct { + ResultDataType *FunctionReturnsResultDataTypeRequest + Table *FunctionReturnsTableRequest +} + +type FunctionReturnsResultDataTypeRequest struct { + ResultDataType DataType // required +} + +type FunctionReturnsTableRequest struct { + Columns []FunctionColumnRequest +} + +type FunctionColumnRequest struct { + ColumnName string // required + ColumnDataType DataType // required +} + +type FunctionImportRequest struct { + Import string +} + +type FunctionPackageRequest struct { + Package string +} + +type CreateForJavascriptFunctionRequest struct { + OrReplace *bool + Temporary *bool + Secure *bool + name SchemaObjectIdentifier // required + Arguments []FunctionArgumentRequest + CopyGrants *bool + Returns FunctionReturnsRequest // required + ReturnNullValues *ReturnNullValues + NullInputBehavior *NullInputBehavior + ReturnResultsBehavior *ReturnResultsBehavior + Comment *string + FunctionDefinition string // required +} + +type CreateForPythonFunctionRequest struct { + OrReplace *bool + Temporary *bool + Secure *bool + IfNotExists *bool + name SchemaObjectIdentifier // required + Arguments []FunctionArgumentRequest + CopyGrants *bool + Returns FunctionReturnsRequest // required + ReturnNullValues *ReturnNullValues + NullInputBehavior *NullInputBehavior + ReturnResultsBehavior *ReturnResultsBehavior + RuntimeVersion string // required + Comment *string + Imports []FunctionImportRequest + Packages []FunctionPackageRequest + Handler string // required + ExternalAccessIntegrations []AccountObjectIdentifier + Secrets []Secret + FunctionDefinition *string +} + +type CreateForScalaFunctionRequest struct { + OrReplace *bool + Temporary *bool + Secure *bool + IfNotExists *bool + name SchemaObjectIdentifier // required + Arguments []FunctionArgumentRequest + CopyGrants *bool + ResultDataType DataType // required + ReturnNullValues *ReturnNullValues + NullInputBehavior *NullInputBehavior + ReturnResultsBehavior *ReturnResultsBehavior + RuntimeVersion *string + Comment *string + Imports []FunctionImportRequest + Packages []FunctionPackageRequest + Handler string // required + TargetPath *string + FunctionDefinition *string +} + +type CreateForSQLFunctionRequest struct { + OrReplace *bool + Temporary *bool + Secure *bool + name SchemaObjectIdentifier // required + Arguments []FunctionArgumentRequest + CopyGrants *bool + Returns FunctionReturnsRequest // required + ReturnNullValues *ReturnNullValues + ReturnResultsBehavior *ReturnResultsBehavior + Memoizable *bool + Comment *string + FunctionDefinition string // required +} + +type AlterFunctionRequest struct { + IfExists *bool + name SchemaObjectIdentifier // required + ArgumentDataTypes []DataType // required + RenameTo *SchemaObjectIdentifier + SetComment *string + SetLogLevel *string + SetTraceLevel *string + SetSecure *bool + UnsetSecure *bool + UnsetLogLevel *bool + UnsetTraceLevel *bool + UnsetComment *bool + SetTags []TagAssociation + UnsetTags []ObjectIdentifier +} + +type DropFunctionRequest struct { + IfExists *bool + name SchemaObjectIdentifier // required + ArgumentDataTypes []DataType // required +} + +type ShowFunctionRequest struct { + Like *Like + In *In +} + +type DescribeFunctionRequest struct { + name SchemaObjectIdentifier // required + ArgumentDataTypes []DataType // required +} diff --git a/pkg/sdk/functions_gen.go b/pkg/sdk/functions_gen.go new file mode 100644 index 0000000000..8d62e8c4b2 --- /dev/null +++ b/pkg/sdk/functions_gen.go @@ -0,0 +1,261 @@ +package sdk + +import ( + "context" + "database/sql" +) + +type Functions interface { + CreateForJava(ctx context.Context, request *CreateForJavaFunctionRequest) error + CreateForJavascript(ctx context.Context, request *CreateForJavascriptFunctionRequest) error + CreateForPython(ctx context.Context, request *CreateForPythonFunctionRequest) error + CreateForScala(ctx context.Context, request *CreateForScalaFunctionRequest) error + CreateForSQL(ctx context.Context, request *CreateForSQLFunctionRequest) error + Alter(ctx context.Context, request *AlterFunctionRequest) error + Drop(ctx context.Context, request *DropFunctionRequest) error + Show(ctx context.Context, request *ShowFunctionRequest) ([]Function, error) + ShowByID(ctx context.Context, id SchemaObjectIdentifier) (*Function, error) + Describe(ctx context.Context, request *DescribeFunctionRequest) ([]FunctionDetail, error) +} + +// CreateForJavaFunctionOptions is based on https://docs.snowflake.com/en/sql-reference/sql/create-function#java-handler. +type CreateForJavaFunctionOptions struct { + create bool `ddl:"static" sql:"CREATE"` + OrReplace *bool `ddl:"keyword" sql:"OR REPLACE"` + Temporary *bool `ddl:"keyword" sql:"TEMPORARY"` + Secure *bool `ddl:"keyword" sql:"SECURE"` + function bool `ddl:"static" sql:"FUNCTION"` + IfNotExists *bool `ddl:"keyword" sql:"IF NOT EXISTS"` + name SchemaObjectIdentifier `ddl:"identifier"` + Arguments []FunctionArgument `ddl:"list,must_parentheses"` + CopyGrants *bool `ddl:"keyword" sql:"COPY GRANTS"` + Returns FunctionReturns `ddl:"keyword" sql:"RETURNS"` + ReturnNullValues *ReturnNullValues `ddl:"keyword"` + languageJava bool `ddl:"static" sql:"LANGUAGE JAVA"` + NullInputBehavior *NullInputBehavior `ddl:"keyword"` + ReturnResultsBehavior *ReturnResultsBehavior `ddl:"keyword"` + RuntimeVersion *string `ddl:"parameter,single_quotes" sql:"RUNTIME_VERSION"` + Comment *string `ddl:"parameter,single_quotes" sql:"COMMENT"` + Imports []FunctionImport `ddl:"parameter,parentheses" sql:"IMPORTS"` + Packages []FunctionPackage `ddl:"parameter,parentheses" sql:"PACKAGES"` + Handler string `ddl:"parameter,single_quotes" sql:"HANDLER"` + ExternalAccessIntegrations []AccountObjectIdentifier `ddl:"parameter,parentheses" sql:"EXTERNAL_ACCESS_INTEGRATIONS"` + Secrets []Secret `ddl:"parameter,parentheses" sql:"SECRETS"` + TargetPath *string `ddl:"parameter,single_quotes" sql:"TARGET_PATH"` + FunctionDefinition *string `ddl:"parameter,single_quotes,no_equals" sql:"AS"` +} + +type FunctionArgument struct { + ArgName string `ddl:"keyword,no_quotes"` + ArgDataType DataType `ddl:"keyword,no_quotes"` + DefaultValue *string `ddl:"parameter,no_equals" sql:"DEFAULT"` +} + +type FunctionReturns struct { + ResultDataType *FunctionReturnsResultDataType `ddl:"keyword"` + Table *FunctionReturnsTable `ddl:"keyword" sql:"TABLE"` +} + +type FunctionReturnsResultDataType struct { + ResultDataType DataType `ddl:"keyword,no_quotes"` +} + +type FunctionReturnsTable struct { + Columns []FunctionColumn `ddl:"parameter,parentheses,no_equals"` +} + +type FunctionColumn struct { + ColumnName string `ddl:"keyword,no_quotes"` + ColumnDataType DataType `ddl:"keyword,no_quotes"` +} + +type FunctionImport struct { + Import string `ddl:"keyword,single_quotes"` +} + +type FunctionPackage struct { + Package string `ddl:"keyword,single_quotes"` +} + +// CreateForJavascriptFunctionOptions is based on https://docs.snowflake.com/en/sql-reference/sql/create-function#javascript-handler. +type CreateForJavascriptFunctionOptions struct { + create bool `ddl:"static" sql:"CREATE"` + OrReplace *bool `ddl:"keyword" sql:"OR REPLACE"` + Temporary *bool `ddl:"keyword" sql:"TEMPORARY"` + Secure *bool `ddl:"keyword" sql:"SECURE"` + function bool `ddl:"static" sql:"FUNCTION"` + name SchemaObjectIdentifier `ddl:"identifier"` + Arguments []FunctionArgument `ddl:"list,must_parentheses"` + CopyGrants *bool `ddl:"keyword" sql:"COPY GRANTS"` + Returns FunctionReturns `ddl:"keyword" sql:"RETURNS"` + ReturnNullValues *ReturnNullValues `ddl:"keyword"` + languageJavascript bool `ddl:"static" sql:"LANGUAGE JAVASCRIPT"` + NullInputBehavior *NullInputBehavior `ddl:"keyword"` + ReturnResultsBehavior *ReturnResultsBehavior `ddl:"keyword"` + Comment *string `ddl:"parameter,single_quotes" sql:"COMMENT"` + FunctionDefinition string `ddl:"parameter,single_quotes,no_equals" sql:"AS"` +} + +// CreateForPythonFunctionOptions is based on https://docs.snowflake.com/en/sql-reference/sql/create-function#python-handler. +type CreateForPythonFunctionOptions struct { + create bool `ddl:"static" sql:"CREATE"` + OrReplace *bool `ddl:"keyword" sql:"OR REPLACE"` + Temporary *bool `ddl:"keyword" sql:"TEMPORARY"` + Secure *bool `ddl:"keyword" sql:"SECURE"` + function bool `ddl:"static" sql:"FUNCTION"` + IfNotExists *bool `ddl:"keyword" sql:"IF NOT EXISTS"` + name SchemaObjectIdentifier `ddl:"identifier"` + Arguments []FunctionArgument `ddl:"list,must_parentheses"` + CopyGrants *bool `ddl:"keyword" sql:"COPY GRANTS"` + Returns FunctionReturns `ddl:"keyword" sql:"RETURNS"` + ReturnNullValues *ReturnNullValues `ddl:"keyword"` + languagePython bool `ddl:"static" sql:"LANGUAGE PYTHON"` + NullInputBehavior *NullInputBehavior `ddl:"keyword"` + ReturnResultsBehavior *ReturnResultsBehavior `ddl:"keyword"` + RuntimeVersion string `ddl:"parameter,single_quotes" sql:"RUNTIME_VERSION"` + Comment *string `ddl:"parameter,single_quotes" sql:"COMMENT"` + Imports []FunctionImport `ddl:"parameter,parentheses" sql:"IMPORTS"` + Packages []FunctionPackage `ddl:"parameter,parentheses" sql:"PACKAGES"` + Handler string `ddl:"parameter,single_quotes" sql:"HANDLER"` + ExternalAccessIntegrations []AccountObjectIdentifier `ddl:"parameter,parentheses" sql:"EXTERNAL_ACCESS_INTEGRATIONS"` + Secrets []Secret `ddl:"parameter,parentheses" sql:"SECRETS"` + FunctionDefinition *string `ddl:"parameter,single_quotes,no_equals" sql:"AS"` +} + +// CreateForScalaFunctionOptions is based on https://docs.snowflake.com/en/sql-reference/sql/create-function#scala-handler. +type CreateForScalaFunctionOptions struct { + create bool `ddl:"static" sql:"CREATE"` + OrReplace *bool `ddl:"keyword" sql:"OR REPLACE"` + Temporary *bool `ddl:"keyword" sql:"TEMPORARY"` + Secure *bool `ddl:"keyword" sql:"SECURE"` + function bool `ddl:"static" sql:"FUNCTION"` + IfNotExists *bool `ddl:"keyword" sql:"IF NOT EXISTS"` + name SchemaObjectIdentifier `ddl:"identifier"` + Arguments []FunctionArgument `ddl:"list,must_parentheses"` + CopyGrants *bool `ddl:"keyword" sql:"COPY GRANTS"` + ResultDataType DataType `ddl:"parameter,no_equals" sql:"RETURNS"` + ReturnNullValues *ReturnNullValues `ddl:"keyword"` + languageScala bool `ddl:"static" sql:"LANGUAGE SCALA"` + NullInputBehavior *NullInputBehavior `ddl:"keyword"` + ReturnResultsBehavior *ReturnResultsBehavior `ddl:"keyword"` + RuntimeVersion *string `ddl:"parameter,single_quotes" sql:"RUNTIME_VERSION"` + Comment *string `ddl:"parameter,single_quotes" sql:"COMMENT"` + Imports []FunctionImport `ddl:"parameter,parentheses" sql:"IMPORTS"` + Packages []FunctionPackage `ddl:"parameter,parentheses" sql:"PACKAGES"` + Handler string `ddl:"parameter,single_quotes" sql:"HANDLER"` + TargetPath *string `ddl:"parameter,single_quotes" sql:"TARGET_PATH"` + FunctionDefinition *string `ddl:"parameter,single_quotes,no_equals" sql:"AS"` +} + +// CreateForSQLFunctionOptions is based on https://docs.snowflake.com/en/sql-reference/sql/create-function#sql-handler. +type CreateForSQLFunctionOptions struct { + create bool `ddl:"static" sql:"CREATE"` + OrReplace *bool `ddl:"keyword" sql:"OR REPLACE"` + Temporary *bool `ddl:"keyword" sql:"TEMPORARY"` + Secure *bool `ddl:"keyword" sql:"SECURE"` + function bool `ddl:"static" sql:"FUNCTION"` + name SchemaObjectIdentifier `ddl:"identifier"` + Arguments []FunctionArgument `ddl:"list,must_parentheses"` + CopyGrants *bool `ddl:"keyword" sql:"COPY GRANTS"` + Returns FunctionReturns `ddl:"keyword" sql:"RETURNS"` + ReturnNullValues *ReturnNullValues `ddl:"keyword"` + ReturnResultsBehavior *ReturnResultsBehavior `ddl:"keyword"` + Memoizable *bool `ddl:"keyword" sql:"MEMOIZABLE"` + Comment *string `ddl:"parameter,single_quotes" sql:"COMMENT"` + FunctionDefinition string `ddl:"parameter,single_quotes,no_equals" sql:"AS"` +} + +// AlterFunctionOptions is based on https://docs.snowflake.com/en/sql-reference/sql/alter-function. +type AlterFunctionOptions struct { + alter bool `ddl:"static" sql:"ALTER"` + function bool `ddl:"static" sql:"FUNCTION"` + IfExists *bool `ddl:"keyword" sql:"IF EXISTS"` + name SchemaObjectIdentifier `ddl:"identifier"` + ArgumentDataTypes []DataType `ddl:"keyword,must_parentheses"` + 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"` + SetSecure *bool `ddl:"keyword" sql:"SET SECURE"` + UnsetSecure *bool `ddl:"keyword" sql:"UNSET SECURE"` + UnsetLogLevel *bool `ddl:"keyword" sql:"UNSET LOG_LEVEL"` + UnsetTraceLevel *bool `ddl:"keyword" sql:"UNSET TRACE_LEVEL"` + UnsetComment *bool `ddl:"keyword" sql:"UNSET COMMENT"` + SetTags []TagAssociation `ddl:"keyword" sql:"SET TAG"` + UnsetTags []ObjectIdentifier `ddl:"keyword" sql:"UNSET TAG"` +} + +// DropFunctionOptions is based on https://docs.snowflake.com/en/sql-reference/sql/drop-function. +type DropFunctionOptions struct { + drop bool `ddl:"static" sql:"DROP"` + function bool `ddl:"static" sql:"FUNCTION"` + IfExists *bool `ddl:"keyword" sql:"IF EXISTS"` + name SchemaObjectIdentifier `ddl:"identifier"` + ArgumentDataTypes []DataType `ddl:"keyword,must_parentheses"` +} + +// ShowFunctionOptions is based on https://docs.snowflake.com/en/sql-reference/sql/show-user-functions. +type ShowFunctionOptions struct { + show bool `ddl:"static" sql:"SHOW"` + userFunctions bool `ddl:"static" sql:"USER FUNCTIONS"` + Like *Like `ddl:"keyword" sql:"LIKE"` + In *In `ddl:"keyword" sql:"IN"` +} + +type functionRow 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"` + IsExternalFunction string `db:"is_external_function"` + Language string `db:"language"` + IsMemoizable sql.NullString `db:"is_memoizable"` +} + +type Function struct { + CreatedOn string + Name string + SchemaName string + IsBuiltin bool + IsAggregate bool + IsAnsi bool + MinNumArguments int + MaxNumArguments int + Arguments string + Description string + CatalogName string + IsTableFunction bool + ValidForClustering bool + IsSecure bool + IsExternalFunction bool + Language string + IsMemoizable bool +} + +// DescribeFunctionOptions is based on https://docs.snowflake.com/en/sql-reference/sql/desc-function. +type DescribeFunctionOptions struct { + describe bool `ddl:"static" sql:"DESCRIBE"` + function bool `ddl:"static" sql:"FUNCTION"` + name SchemaObjectIdentifier `ddl:"identifier"` + ArgumentDataTypes []DataType `ddl:"keyword,must_parentheses"` +} + +type functionDetailRow struct { + Property string `db:"property"` + Value string `db:"value"` +} + +type FunctionDetail struct { + Property string + Value string +} diff --git a/pkg/sdk/functions_gen_test.go b/pkg/sdk/functions_gen_test.go new file mode 100644 index 0000000000..19e552b2cd --- /dev/null +++ b/pkg/sdk/functions_gen_test.go @@ -0,0 +1,649 @@ +package sdk + +import ( + "testing" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk/internal/random" +) + +func TestFunctions_CreateForJava(t *testing.T) { + id := RandomSchemaObjectIdentifier() + + defaultOpts := func() *CreateForJavaFunctionOptions { + return &CreateForJavaFunctionOptions{ + name: id, + } + } + + t.Run("validation: nil options", func(t *testing.T) { + opts := (*CreateForJavaFunctionOptions)(nil) + assertOptsInvalidJoinedErrors(t, opts, ErrNilOptions) + }) + + t.Run("validation: incorrect identifier", func(t *testing.T) { + opts := defaultOpts() + opts.name = NewSchemaObjectIdentifier("", "", "") + assertOptsInvalidJoinedErrors(t, opts, ErrInvalidObjectIdentifier) + }) + + t.Run("validation: returns", func(t *testing.T) { + opts := defaultOpts() + opts.Returns = FunctionReturns{} + assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("CreateForJavaFunctionOptions.Returns", "ResultDataType", "Table")) + }) + + t.Run("validation: function definition", func(t *testing.T) { + opts := defaultOpts() + opts.TargetPath = String("@~/testfunc.jar") + opts.Packages = []FunctionPackage{ + { + Package: "com.snowflake:snowpark:1.2.0", + }, + } + assertOptsInvalidJoinedErrors(t, opts, NewError("TARGET_PATH must be nil when AS is nil")) + assertOptsInvalidJoinedErrors(t, opts, NewError("PACKAGES must be empty when AS is nil")) + assertOptsInvalidJoinedErrors(t, opts, NewError("IMPORTS must not be empty when AS is nil")) + }) + + t.Run("validation: options are missing", func(t *testing.T) { + opts := defaultOpts() + opts.Returns = FunctionReturns{ + ResultDataType: &FunctionReturnsResultDataType{ + ResultDataType: DataTypeVARCHAR, + }, + } + assertOptsInvalidJoinedErrors(t, opts, errNotSet("CreateForJavaFunctionOptions", "Handler")) + }) + + t.Run("all options", func(t *testing.T) { + opts := defaultOpts() + opts.OrReplace = Bool(true) + opts.Temporary = Bool(true) + opts.Secure = Bool(true) + opts.Arguments = []FunctionArgument{ + { + ArgName: "id", + ArgDataType: DataTypeNumber, + }, + { + ArgName: "name", + ArgDataType: DataTypeVARCHAR, + DefaultValue: String("'test'"), + }, + } + opts.CopyGrants = Bool(true) + opts.Returns = FunctionReturns{ + Table: &FunctionReturnsTable{ + Columns: []FunctionColumn{ + { + ColumnName: "country_code", + ColumnDataType: DataTypeVARCHAR, + }, + { + ColumnName: "country_name", + ColumnDataType: DataTypeVARCHAR, + }, + }, + }, + } + opts.ReturnNullValues = ReturnNullValuesPointer(ReturnNullValuesNotNull) + opts.NullInputBehavior = NullInputBehaviorPointer(NullInputBehaviorCalledOnNullInput) + opts.ReturnResultsBehavior = ReturnResultsBehaviorPointer(ReturnResultsBehaviorImmutable) + opts.RuntimeVersion = String("2.0") + opts.Comment = String("comment") + opts.Imports = []FunctionImport{ + { + Import: "@~/my_decrement_udf_package_dir/my_decrement_udf_jar.jar", + }, + } + opts.Packages = []FunctionPackage{ + { + Package: "com.snowflake:snowpark:1.2.0", + }, + } + opts.Handler = "TestFunc.echoVarchar" + opts.ExternalAccessIntegrations = []AccountObjectIdentifier{ + NewAccountObjectIdentifier("ext_integration"), + } + opts.Secrets = []Secret{ + { + VariableName: "variable1", + Name: "name1", + }, + { + VariableName: "variable2", + Name: "name2", + }, + } + opts.TargetPath = String("@~/testfunc.jar") + opts.FunctionDefinition = String("return id + name;") + assertOptsValidAndSQLEquals(t, opts, `CREATE OR REPLACE TEMPORARY SECURE FUNCTION %s (id NUMBER, name VARCHAR DEFAULT 'test') COPY GRANTS RETURNS TABLE (country_code VARCHAR, country_name VARCHAR) NOT NULL LANGUAGE JAVA CALLED ON NULL INPUT IMMUTABLE RUNTIME_VERSION = '2.0' COMMENT = 'comment' IMPORTS = ('@~/my_decrement_udf_package_dir/my_decrement_udf_jar.jar') PACKAGES = ('com.snowflake:snowpark:1.2.0') HANDLER = 'TestFunc.echoVarchar' EXTERNAL_ACCESS_INTEGRATIONS = ("ext_integration") SECRETS = ('variable1' = name1, 'variable2' = name2) TARGET_PATH = '@~/testfunc.jar' AS 'return id + name;'`, id.FullyQualifiedName()) + }) +} + +func TestFunctions_CreateForJavascript(t *testing.T) { + id := RandomSchemaObjectIdentifier() + + defaultOpts := func() *CreateForJavascriptFunctionOptions { + return &CreateForJavascriptFunctionOptions{ + name: id, + } + } + + t.Run("validation: nil options", func(t *testing.T) { + opts := (*CreateForJavascriptFunctionOptions)(nil) + assertOptsInvalidJoinedErrors(t, opts, ErrNilOptions) + }) + + t.Run("validation: incorrect identifier", func(t *testing.T) { + opts := defaultOpts() + opts.name = NewSchemaObjectIdentifier("", "", "") + assertOptsInvalidJoinedErrors(t, opts, ErrInvalidObjectIdentifier) + }) + + t.Run("validation: returns", func(t *testing.T) { + opts := defaultOpts() + opts.Returns = FunctionReturns{} + assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("CreateForJavascriptFunctionOptions.Returns", "ResultDataType", "Table")) + }) + + t.Run("validation: options are missing", func(t *testing.T) { + opts := defaultOpts() + opts.Returns = FunctionReturns{ + ResultDataType: &FunctionReturnsResultDataType{ + ResultDataType: DataTypeVARCHAR, + }, + } + assertOptsInvalidJoinedErrors(t, opts, errNotSet("CreateForJavascriptFunctionOptions", "FunctionDefinition")) + }) + + t.Run("all options", func(t *testing.T) { + opts := defaultOpts() + opts.OrReplace = Bool(true) + opts.Temporary = Bool(true) + opts.Secure = Bool(true) + opts.Arguments = []FunctionArgument{ + { + ArgName: "d", + ArgDataType: DataTypeFloat, + DefaultValue: String("1.0"), + }, + } + opts.CopyGrants = Bool(true) + opts.Returns = FunctionReturns{ + ResultDataType: &FunctionReturnsResultDataType{ + ResultDataType: DataTypeFloat, + }, + } + opts.ReturnNullValues = ReturnNullValuesPointer(ReturnNullValuesNotNull) + opts.NullInputBehavior = NullInputBehaviorPointer(NullInputBehaviorCalledOnNullInput) + opts.ReturnResultsBehavior = ReturnResultsBehaviorPointer(ReturnResultsBehaviorImmutable) + opts.Comment = String("comment") + opts.FunctionDefinition = "return 1;" + assertOptsValidAndSQLEquals(t, opts, `CREATE OR REPLACE TEMPORARY SECURE FUNCTION %s (d FLOAT DEFAULT 1.0) COPY GRANTS RETURNS FLOAT NOT NULL LANGUAGE JAVASCRIPT CALLED ON NULL INPUT IMMUTABLE COMMENT = 'comment' AS 'return 1;'`, id.FullyQualifiedName()) + }) +} + +func TestFunctions_CreateForPython(t *testing.T) { + id := RandomSchemaObjectIdentifier() + + defaultOpts := func() *CreateForPythonFunctionOptions { + return &CreateForPythonFunctionOptions{ + name: id, + } + } + + t.Run("validation: nil options", func(t *testing.T) { + opts := (*CreateForPythonFunctionOptions)(nil) + assertOptsInvalidJoinedErrors(t, opts, ErrNilOptions) + }) + + t.Run("validation: incorrect identifier", func(t *testing.T) { + opts := defaultOpts() + opts.name = NewSchemaObjectIdentifier("", "", "") + assertOptsInvalidJoinedErrors(t, opts, ErrInvalidObjectIdentifier) + }) + + t.Run("validation: returns", func(t *testing.T) { + opts := defaultOpts() + opts.Returns = FunctionReturns{} + assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("CreateForPythonFunctionOptions.Returns", "ResultDataType", "Table")) + }) + + t.Run("validation: options are missing", func(t *testing.T) { + opts := defaultOpts() + opts.Returns = FunctionReturns{ + ResultDataType: &FunctionReturnsResultDataType{ + ResultDataType: DataTypeVARCHAR, + }, + } + assertOptsInvalidJoinedErrors(t, opts, errNotSet("CreateForPythonFunctionOptions", "RuntimeVersion")) + assertOptsInvalidJoinedErrors(t, opts, errNotSet("CreateForPythonFunctionOptions", "Handler")) + }) + + t.Run("validation: function definition", func(t *testing.T) { + opts := defaultOpts() + opts.Packages = []FunctionPackage{ + { + Package: "com.snowflake:snowpark:1.2.0", + }, + } + assertOptsInvalidJoinedErrors(t, opts, NewError("IMPORTS must not be empty when AS is nil")) + }) + + t.Run("all options", func(t *testing.T) { + opts := defaultOpts() + opts.OrReplace = Bool(true) + opts.Temporary = Bool(true) + opts.Secure = Bool(true) + opts.Arguments = []FunctionArgument{ + { + ArgName: "i", + ArgDataType: DataTypeNumber, + DefaultValue: String("1"), + }, + } + opts.CopyGrants = Bool(true) + opts.Returns = FunctionReturns{ + ResultDataType: &FunctionReturnsResultDataType{ + ResultDataType: DataTypeVariant, + }, + } + opts.ReturnNullValues = ReturnNullValuesPointer(ReturnNullValuesNotNull) + opts.NullInputBehavior = NullInputBehaviorPointer(NullInputBehaviorCalledOnNullInput) + opts.ReturnResultsBehavior = ReturnResultsBehaviorPointer(ReturnResultsBehaviorImmutable) + opts.RuntimeVersion = "3.8" + opts.Comment = String("comment") + opts.Imports = []FunctionImport{ + { + Import: "numpy", + }, + { + Import: "pandas", + }, + } + opts.Packages = []FunctionPackage{ + { + Package: "numpy", + }, + { + Package: "pandas", + }, + } + opts.Handler = "udf" + opts.ExternalAccessIntegrations = []AccountObjectIdentifier{ + NewAccountObjectIdentifier("ext_integration"), + } + opts.Secrets = []Secret{ + { + VariableName: "variable1", + Name: "name1", + }, + { + VariableName: "variable2", + Name: "name2", + }, + } + opts.FunctionDefinition = String("import numpy as np") + assertOptsValidAndSQLEquals(t, opts, `CREATE OR REPLACE TEMPORARY SECURE FUNCTION %s (i NUMBER DEFAULT 1) COPY GRANTS RETURNS VARIANT NOT NULL LANGUAGE PYTHON CALLED ON NULL INPUT IMMUTABLE RUNTIME_VERSION = '3.8' COMMENT = 'comment' IMPORTS = ('numpy', 'pandas') PACKAGES = ('numpy', 'pandas') HANDLER = 'udf' EXTERNAL_ACCESS_INTEGRATIONS = ("ext_integration") SECRETS = ('variable1' = name1, 'variable2' = name2) AS 'import numpy as np'`, id.FullyQualifiedName()) + }) +} + +func TestFunctions_CreateForScala(t *testing.T) { + id := RandomSchemaObjectIdentifier() + + defaultOpts := func() *CreateForScalaFunctionOptions { + return &CreateForScalaFunctionOptions{ + name: id, + } + } + + t.Run("validation: nil options", func(t *testing.T) { + opts := (*CreateForScalaFunctionOptions)(nil) + assertOptsInvalidJoinedErrors(t, opts, ErrNilOptions) + }) + + t.Run("validation: incorrect identifier", func(t *testing.T) { + opts := defaultOpts() + opts.name = NewSchemaObjectIdentifier("", "", "") + assertOptsInvalidJoinedErrors(t, opts, ErrInvalidObjectIdentifier) + }) + + t.Run("validation: function definition", func(t *testing.T) { + opts := defaultOpts() + opts.TargetPath = String("@~/testfunc.jar") + opts.Packages = []FunctionPackage{ + { + Package: "com.snowflake:snowpark:1.2.0", + }, + } + assertOptsInvalidJoinedErrors(t, opts, NewError("TARGET_PATH must be nil when AS is nil")) + assertOptsInvalidJoinedErrors(t, opts, NewError("PACKAGES must be empty when AS is nil")) + assertOptsInvalidJoinedErrors(t, opts, NewError("IMPORTS must not be empty when AS is nil")) + }) + + t.Run("validation: options are missing", func(t *testing.T) { + opts := defaultOpts() + opts.ResultDataType = DataTypeVARCHAR + assertOptsInvalidJoinedErrors(t, opts, errNotSet("CreateForScalaFunctionOptions", "Handler")) + }) + + t.Run("all options", func(t *testing.T) { + opts := defaultOpts() + opts.OrReplace = Bool(true) + opts.Temporary = Bool(true) + opts.Secure = Bool(true) + opts.Arguments = []FunctionArgument{ + { + ArgName: "x", + ArgDataType: DataTypeVARCHAR, + DefaultValue: String("'test'"), + }, + } + opts.CopyGrants = Bool(true) + opts.ResultDataType = DataTypeVARCHAR + opts.ReturnNullValues = ReturnNullValuesPointer(ReturnNullValuesNotNull) + opts.NullInputBehavior = NullInputBehaviorPointer(NullInputBehaviorCalledOnNullInput) + opts.ReturnResultsBehavior = ReturnResultsBehaviorPointer(ReturnResultsBehaviorImmutable) + opts.RuntimeVersion = String("2.0") + opts.Comment = String("comment") + opts.Imports = []FunctionImport{ + { + Import: "@udf_libs/echohandler.jar", + }, + } + opts.Handler = "Echo.echoVarchar" + opts.FunctionDefinition = String("return x") + assertOptsValidAndSQLEquals(t, opts, `CREATE OR REPLACE TEMPORARY SECURE FUNCTION %s (x VARCHAR DEFAULT 'test') COPY GRANTS RETURNS VARCHAR NOT NULL LANGUAGE SCALA CALLED ON NULL INPUT IMMUTABLE RUNTIME_VERSION = '2.0' COMMENT = 'comment' IMPORTS = ('@udf_libs/echohandler.jar') HANDLER = 'Echo.echoVarchar' AS 'return x'`, id.FullyQualifiedName()) + }) +} + +func TestFunctions_CreateForSQL(t *testing.T) { + id := RandomSchemaObjectIdentifier() + + defaultOpts := func() *CreateForSQLFunctionOptions { + return &CreateForSQLFunctionOptions{ + name: id, + } + } + + t.Run("validation: nil options", func(t *testing.T) { + opts := (*CreateForSQLFunctionOptions)(nil) + assertOptsInvalidJoinedErrors(t, opts, ErrNilOptions) + }) + + t.Run("validation: incorrect identifier", func(t *testing.T) { + opts := defaultOpts() + opts.name = NewSchemaObjectIdentifier("", "", "") + assertOptsInvalidJoinedErrors(t, opts, ErrInvalidObjectIdentifier) + }) + + t.Run("validation: returns", func(t *testing.T) { + opts := defaultOpts() + opts.Returns = FunctionReturns{} + assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("CreateForSQLFunctionOptions.Returns", "ResultDataType", "Table")) + }) + + t.Run("validation: options are missing", func(t *testing.T) { + opts := defaultOpts() + opts.Returns = FunctionReturns{ + ResultDataType: &FunctionReturnsResultDataType{ + ResultDataType: DataTypeVARCHAR, + }, + } + assertOptsInvalidJoinedErrors(t, opts, errNotSet("CreateForSQLFunctionOptions", "FunctionDefinition")) + }) + + t.Run("create with no arguments", func(t *testing.T) { + opts := defaultOpts() + opts.Returns = FunctionReturns{ + ResultDataType: &FunctionReturnsResultDataType{ + ResultDataType: DataTypeFloat, + }, + } + opts.FunctionDefinition = "3.141592654::FLOAT" + assertOptsValidAndSQLEquals(t, opts, `CREATE FUNCTION %s () RETURNS FLOAT AS '3.141592654::FLOAT'`, id.FullyQualifiedName()) + }) + + t.Run("all options", func(t *testing.T) { + opts := defaultOpts() + opts.OrReplace = Bool(true) + opts.Temporary = Bool(true) + opts.Secure = Bool(true) + opts.Arguments = []FunctionArgument{ + { + ArgName: "message", + ArgDataType: "VARCHAR", + DefaultValue: String("'test'"), + }, + } + opts.CopyGrants = Bool(true) + opts.Returns = FunctionReturns{ + ResultDataType: &FunctionReturnsResultDataType{ + ResultDataType: DataTypeFloat, + }, + } + opts.ReturnNullValues = ReturnNullValuesPointer(ReturnNullValuesNotNull) + opts.ReturnResultsBehavior = ReturnResultsBehaviorPointer(ReturnResultsBehaviorImmutable) + opts.Memoizable = Bool(true) + opts.Comment = String("comment") + opts.FunctionDefinition = "3.141592654::FLOAT" + assertOptsValidAndSQLEquals(t, opts, `CREATE OR REPLACE TEMPORARY SECURE FUNCTION %s (message VARCHAR DEFAULT 'test') COPY GRANTS RETURNS FLOAT NOT NULL IMMUTABLE MEMOIZABLE COMMENT = 'comment' AS '3.141592654::FLOAT'`, id.FullyQualifiedName()) + }) +} + +func TestFunctions_Drop(t *testing.T) { + id := RandomSchemaObjectIdentifier() + + defaultOpts := func() *DropFunctionOptions { + return &DropFunctionOptions{ + name: id, + } + } + + t.Run("validation: nil options", func(t *testing.T) { + opts := (*DropFunctionOptions)(nil) + assertOptsInvalidJoinedErrors(t, opts, ErrNilOptions) + }) + + t.Run("validation: incorrect identifier", func(t *testing.T) { + opts := defaultOpts() + opts.name = NewSchemaObjectIdentifier("", "", "") + assertOptsInvalidJoinedErrors(t, opts, ErrInvalidObjectIdentifier) + }) + + t.Run("no arguments", func(t *testing.T) { + opts := defaultOpts() + assertOptsValidAndSQLEquals(t, opts, `DROP FUNCTION %s ()`, id.FullyQualifiedName()) + }) + + t.Run("all options", func(t *testing.T) { + opts := &DropFunctionOptions{ + name: id, + } + opts.IfExists = Bool(true) + opts.ArgumentDataTypes = []DataType{DataTypeVARCHAR, DataTypeNumber} + assertOptsValidAndSQLEquals(t, opts, `DROP FUNCTION IF EXISTS %s (VARCHAR, NUMBER)`, id.FullyQualifiedName()) + }) +} + +func TestFunctions_Alter(t *testing.T) { + id := RandomSchemaObjectIdentifier() + + defaultOpts := func() *AlterFunctionOptions { + return &AlterFunctionOptions{ + name: id, + IfExists: Bool(true), + ArgumentDataTypes: []DataType{DataTypeVARCHAR, DataTypeNumber}, + } + } + + t.Run("validation: nil options", func(t *testing.T) { + opts := (*AlterFunctionOptions)(nil) + assertOptsInvalidJoinedErrors(t, opts, ErrNilOptions) + }) + + t.Run("validation: incorrect identifier", func(t *testing.T) { + opts := defaultOpts() + opts.name = NewSchemaObjectIdentifier("", "", "") + assertOptsInvalidJoinedErrors(t, opts, ErrInvalidObjectIdentifier) + }) + + t.Run("validation: exactly one field should be present", func(t *testing.T) { + opts := defaultOpts() + assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("AlterFunctionOptions", "RenameTo", "SetComment", "SetLogLevel", "SetTraceLevel", "SetSecure", "UnsetLogLevel", "UnsetTraceLevel", "UnsetSecure", "UnsetComment", "SetTags", "UnsetTags")) + }) + + t.Run("validation: exactly one field should be present", func(t *testing.T) { + opts := defaultOpts() + opts.SetLogLevel = String("DEBUG") + opts.UnsetComment = Bool(true) + assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("AlterFunctionOptions", "RenameTo", "SetComment", "SetLogLevel", "SetTraceLevel", "SetSecure", "UnsetLogLevel", "UnsetTraceLevel", "UnsetSecure", "UnsetComment", "SetTags", "UnsetTags")) + }) + + t.Run("alter: rename to", func(t *testing.T) { + opts := defaultOpts() + target := NewSchemaObjectIdentifier(id.DatabaseName(), id.SchemaName(), random.StringN(12)) + opts.RenameTo = &target + assertOptsValidAndSQLEquals(t, opts, `ALTER FUNCTION IF EXISTS %s (VARCHAR, NUMBER) RENAME TO %s`, id.FullyQualifiedName(), opts.RenameTo.FullyQualifiedName()) + }) + + t.Run("alter: set log level with no arguments", func(t *testing.T) { + opts := defaultOpts() + opts.ArgumentDataTypes = nil + opts.SetLogLevel = String("DEBUG") + assertOptsValidAndSQLEquals(t, opts, `ALTER FUNCTION IF EXISTS %s () SET LOG_LEVEL = 'DEBUG'`, id.FullyQualifiedName()) + }) + + t.Run("alter: set log level", func(t *testing.T) { + opts := defaultOpts() + opts.SetLogLevel = String("DEBUG") + assertOptsValidAndSQLEquals(t, opts, `ALTER FUNCTION IF EXISTS %s (VARCHAR, NUMBER) SET LOG_LEVEL = 'DEBUG'`, id.FullyQualifiedName()) + }) + + t.Run("alter: set trace level", func(t *testing.T) { + opts := defaultOpts() + opts.SetTraceLevel = String("DEBUG") + assertOptsValidAndSQLEquals(t, opts, `ALTER FUNCTION IF EXISTS %s (VARCHAR, NUMBER) SET TRACE_LEVEL = 'DEBUG'`, id.FullyQualifiedName()) + }) + + t.Run("alter: set comment", func(t *testing.T) { + opts := defaultOpts() + opts.SetComment = String("comment") + assertOptsValidAndSQLEquals(t, opts, `ALTER FUNCTION IF EXISTS %s (VARCHAR, NUMBER) SET COMMENT = 'comment'`, id.FullyQualifiedName()) + }) + + t.Run("alter: set secure", func(t *testing.T) { + opts := defaultOpts() + opts.SetSecure = Bool(true) + assertOptsValidAndSQLEquals(t, opts, `ALTER FUNCTION IF EXISTS %s (VARCHAR, NUMBER) SET SECURE`, id.FullyQualifiedName()) + }) + + t.Run("alter: unset log level", func(t *testing.T) { + opts := defaultOpts() + opts.UnsetLogLevel = Bool(true) + assertOptsValidAndSQLEquals(t, opts, `ALTER FUNCTION IF EXISTS %s (VARCHAR, NUMBER) UNSET LOG_LEVEL`, id.FullyQualifiedName()) + }) + + t.Run("alter: unset trace level", func(t *testing.T) { + opts := defaultOpts() + opts.UnsetTraceLevel = Bool(true) + assertOptsValidAndSQLEquals(t, opts, `ALTER FUNCTION IF EXISTS %s (VARCHAR, NUMBER) UNSET TRACE_LEVEL`, id.FullyQualifiedName()) + }) + + t.Run("alter: unset secure", func(t *testing.T) { + opts := defaultOpts() + opts.UnsetSecure = Bool(true) + assertOptsValidAndSQLEquals(t, opts, `ALTER FUNCTION IF EXISTS %s (VARCHAR, NUMBER) UNSET SECURE`, id.FullyQualifiedName()) + }) + + t.Run("alter: unset comment", func(t *testing.T) { + opts := defaultOpts() + opts.UnsetComment = Bool(true) + assertOptsValidAndSQLEquals(t, opts, `ALTER FUNCTION IF EXISTS %s (VARCHAR, NUMBER) UNSET COMMENT`, id.FullyQualifiedName()) + }) + + t.Run("alter: set tags", func(t *testing.T) { + opts := defaultOpts() + opts.SetTags = []TagAssociation{ + { + Name: NewAccountObjectIdentifier("tag1"), + Value: "value1", + }, + } + assertOptsValidAndSQLEquals(t, opts, `ALTER FUNCTION IF EXISTS %s (VARCHAR, NUMBER) SET TAG "tag1" = 'value1'`, id.FullyQualifiedName()) + }) + + t.Run("alter: unset tags", func(t *testing.T) { + opts := defaultOpts() + opts.UnsetTags = []ObjectIdentifier{ + NewAccountObjectIdentifier("tag1"), + NewAccountObjectIdentifier("tag2"), + } + assertOptsValidAndSQLEquals(t, opts, `ALTER FUNCTION IF EXISTS %s (VARCHAR, NUMBER) UNSET TAG "tag1", "tag2"`, id.FullyQualifiedName()) + }) +} + +func TestFunctions_Show(t *testing.T) { + defaultOpts := func() *ShowFunctionOptions { + return &ShowFunctionOptions{} + } + + t.Run("validation: nil options", func(t *testing.T) { + opts := (*ShowFunctionOptions)(nil) + assertOptsInvalidJoinedErrors(t, opts, ErrNilOptions) + }) + + t.Run("show with empty options", func(t *testing.T) { + opts := defaultOpts() + assertOptsValidAndSQLEquals(t, opts, `SHOW USER FUNCTIONS`) + }) + + t.Run("show with like", func(t *testing.T) { + opts := defaultOpts() + opts.Like = &Like{ + Pattern: String("pattern"), + } + assertOptsValidAndSQLEquals(t, opts, `SHOW USER FUNCTIONS LIKE 'pattern'`) + }) + + t.Run("show with in", func(t *testing.T) { + opts := defaultOpts() + opts.In = &In{ + Account: Bool(true), + } + assertOptsValidAndSQLEquals(t, opts, `SHOW USER FUNCTIONS IN ACCOUNT`) + }) +} + +func TestFunctions_Describe(t *testing.T) { + id := RandomSchemaObjectIdentifier() + + defaultOpts := func() *DescribeFunctionOptions { + return &DescribeFunctionOptions{ + name: id, + } + } + + t.Run("validation: nil options", func(t *testing.T) { + opts := (*DescribeFunctionOptions)(nil) + assertOptsInvalidJoinedErrors(t, opts, ErrNilOptions) + }) + + t.Run("validation: incorrect identifier", func(t *testing.T) { + opts := defaultOpts() + opts.name = NewSchemaObjectIdentifier("", "", "") + assertOptsInvalidJoinedErrors(t, opts, ErrInvalidObjectIdentifier) + }) + + t.Run("no arguments", func(t *testing.T) { + opts := defaultOpts() + assertOptsValidAndSQLEquals(t, opts, `DESCRIBE FUNCTION %s ()`, id.FullyQualifiedName()) + }) + + t.Run("all options", func(t *testing.T) { + opts := defaultOpts() + opts.ArgumentDataTypes = []DataType{DataTypeVARCHAR, DataTypeNumber} + assertOptsValidAndSQLEquals(t, opts, `DESCRIBE FUNCTION %s (VARCHAR, NUMBER)`, id.FullyQualifiedName()) + }) +} diff --git a/pkg/sdk/functions_impl_gen.go b/pkg/sdk/functions_impl_gen.go new file mode 100644 index 0000000000..650aef62e9 --- /dev/null +++ b/pkg/sdk/functions_impl_gen.go @@ -0,0 +1,448 @@ +package sdk + +import ( + "context" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk/internal/collections" +) + +var _ Functions = (*functions)(nil) + +type functions struct { + client *Client +} + +func (v *functions) CreateForJava(ctx context.Context, request *CreateForJavaFunctionRequest) error { + opts := request.toOpts() + return validateAndExec(v.client, ctx, opts) +} + +func (v *functions) CreateForJavascript(ctx context.Context, request *CreateForJavascriptFunctionRequest) error { + opts := request.toOpts() + return validateAndExec(v.client, ctx, opts) +} + +func (v *functions) CreateForPython(ctx context.Context, request *CreateForPythonFunctionRequest) error { + opts := request.toOpts() + return validateAndExec(v.client, ctx, opts) +} + +func (v *functions) CreateForScala(ctx context.Context, request *CreateForScalaFunctionRequest) error { + opts := request.toOpts() + return validateAndExec(v.client, ctx, opts) +} + +func (v *functions) CreateForSQL(ctx context.Context, request *CreateForSQLFunctionRequest) error { + opts := request.toOpts() + return validateAndExec(v.client, ctx, opts) +} + +func (v *functions) Alter(ctx context.Context, request *AlterFunctionRequest) error { + opts := request.toOpts() + return validateAndExec(v.client, ctx, opts) +} + +func (v *functions) Drop(ctx context.Context, request *DropFunctionRequest) error { + opts := request.toOpts() + return validateAndExec(v.client, ctx, opts) +} + +func (v *functions) Show(ctx context.Context, request *ShowFunctionRequest) ([]Function, error) { + opts := request.toOpts() + dbRows, err := validateAndQuery[functionRow](v.client, ctx, opts) + if err != nil { + return nil, err + } + resultList := convertRows[functionRow, Function](dbRows) + return resultList, nil +} + +func (v *functions) ShowByID(ctx context.Context, id SchemaObjectIdentifier) (*Function, error) { + request := NewShowFunctionRequest().WithIn(&In{Database: NewAccountObjectIdentifier(id.DatabaseName())}).WithLike(&Like{String(id.Name())}) + functions, err := v.Show(ctx, request) + if err != nil { + return nil, err + } + return collections.FindOne(functions, func(r Function) bool { return r.Name == id.Name() }) +} + +func (v *functions) Describe(ctx context.Context, request *DescribeFunctionRequest) ([]FunctionDetail, error) { + opts := request.toOpts() + rows, err := validateAndQuery[functionDetailRow](v.client, ctx, opts) + if err != nil { + return nil, err + } + return convertRows[functionDetailRow, FunctionDetail](rows), nil +} + +func (r *CreateForJavaFunctionRequest) toOpts() *CreateForJavaFunctionOptions { + opts := &CreateForJavaFunctionOptions{ + OrReplace: r.OrReplace, + Temporary: r.Temporary, + Secure: r.Secure, + IfNotExists: r.IfNotExists, + name: r.name, + + CopyGrants: r.CopyGrants, + + ReturnNullValues: r.ReturnNullValues, + NullInputBehavior: r.NullInputBehavior, + ReturnResultsBehavior: r.ReturnResultsBehavior, + RuntimeVersion: r.RuntimeVersion, + Comment: r.Comment, + + Handler: r.Handler, + ExternalAccessIntegrations: r.ExternalAccessIntegrations, + Secrets: r.Secrets, + TargetPath: r.TargetPath, + FunctionDefinition: r.FunctionDefinition, + } + if r.Arguments != nil { + s := make([]FunctionArgument, len(r.Arguments)) + for i, v := range r.Arguments { + s[i] = FunctionArgument{ + ArgName: v.ArgName, + ArgDataType: v.ArgDataType, + DefaultValue: v.DefaultValue, + } + } + opts.Arguments = s + } + opts.Returns = FunctionReturns{} + if r.Returns.ResultDataType != nil { + opts.Returns.ResultDataType = &FunctionReturnsResultDataType{ + ResultDataType: r.Returns.ResultDataType.ResultDataType, + } + } + if r.Returns.Table != nil { + opts.Returns.Table = &FunctionReturnsTable{} + if r.Returns.Table.Columns != nil { + s := make([]FunctionColumn, len(r.Returns.Table.Columns)) + for i, v := range r.Returns.Table.Columns { + s[i] = FunctionColumn{ + ColumnName: v.ColumnName, + ColumnDataType: v.ColumnDataType, + } + } + opts.Returns.Table.Columns = s + } + } + if r.Imports != nil { + s := make([]FunctionImport, len(r.Imports)) + for i, v := range r.Imports { + s[i] = FunctionImport{ + Import: v.Import, + } + } + opts.Imports = s + } + if r.Packages != nil { + s := make([]FunctionPackage, len(r.Packages)) + for i, v := range r.Packages { + s[i] = FunctionPackage{ + Package: v.Package, + } + } + opts.Packages = s + } + return opts +} + +func (r *CreateForJavascriptFunctionRequest) toOpts() *CreateForJavascriptFunctionOptions { + opts := &CreateForJavascriptFunctionOptions{ + OrReplace: r.OrReplace, + Temporary: r.Temporary, + Secure: r.Secure, + name: r.name, + + CopyGrants: r.CopyGrants, + + ReturnNullValues: r.ReturnNullValues, + NullInputBehavior: r.NullInputBehavior, + ReturnResultsBehavior: r.ReturnResultsBehavior, + Comment: r.Comment, + FunctionDefinition: r.FunctionDefinition, + } + if r.Arguments != nil { + s := make([]FunctionArgument, len(r.Arguments)) + for i, v := range r.Arguments { + s[i] = FunctionArgument{ + ArgName: v.ArgName, + ArgDataType: v.ArgDataType, + DefaultValue: v.DefaultValue, + } + } + opts.Arguments = s + } + opts.Returns = FunctionReturns{} + if r.Returns.ResultDataType != nil { + opts.Returns.ResultDataType = &FunctionReturnsResultDataType{ + ResultDataType: r.Returns.ResultDataType.ResultDataType, + } + } + if r.Returns.Table != nil { + opts.Returns.Table = &FunctionReturnsTable{} + if r.Returns.Table.Columns != nil { + s := make([]FunctionColumn, len(r.Returns.Table.Columns)) + for i, v := range r.Returns.Table.Columns { + s[i] = FunctionColumn{ + ColumnName: v.ColumnName, + ColumnDataType: v.ColumnDataType, + } + } + opts.Returns.Table.Columns = s + } + } + return opts +} + +func (r *CreateForPythonFunctionRequest) toOpts() *CreateForPythonFunctionOptions { + opts := &CreateForPythonFunctionOptions{ + OrReplace: r.OrReplace, + Temporary: r.Temporary, + Secure: r.Secure, + IfNotExists: r.IfNotExists, + name: r.name, + + CopyGrants: r.CopyGrants, + + ReturnNullValues: r.ReturnNullValues, + NullInputBehavior: r.NullInputBehavior, + ReturnResultsBehavior: r.ReturnResultsBehavior, + RuntimeVersion: r.RuntimeVersion, + Comment: r.Comment, + + Handler: r.Handler, + ExternalAccessIntegrations: r.ExternalAccessIntegrations, + Secrets: r.Secrets, + FunctionDefinition: r.FunctionDefinition, + } + if r.Arguments != nil { + s := make([]FunctionArgument, len(r.Arguments)) + for i, v := range r.Arguments { + s[i] = FunctionArgument{ + ArgName: v.ArgName, + ArgDataType: v.ArgDataType, + DefaultValue: v.DefaultValue, + } + } + opts.Arguments = s + } + opts.Returns = FunctionReturns{} + if r.Returns.ResultDataType != nil { + opts.Returns.ResultDataType = &FunctionReturnsResultDataType{ + ResultDataType: r.Returns.ResultDataType.ResultDataType, + } + } + if r.Returns.Table != nil { + opts.Returns.Table = &FunctionReturnsTable{} + if r.Returns.Table.Columns != nil { + s := make([]FunctionColumn, len(r.Returns.Table.Columns)) + for i, v := range r.Returns.Table.Columns { + s[i] = FunctionColumn{ + ColumnName: v.ColumnName, + ColumnDataType: v.ColumnDataType, + } + } + opts.Returns.Table.Columns = s + } + } + if r.Imports != nil { + s := make([]FunctionImport, len(r.Imports)) + for i, v := range r.Imports { + s[i] = FunctionImport{ + Import: v.Import, + } + } + opts.Imports = s + } + if r.Packages != nil { + s := make([]FunctionPackage, len(r.Packages)) + for i, v := range r.Packages { + s[i] = FunctionPackage{ + Package: v.Package, + } + } + opts.Packages = s + } + return opts +} + +func (r *CreateForScalaFunctionRequest) toOpts() *CreateForScalaFunctionOptions { + opts := &CreateForScalaFunctionOptions{ + OrReplace: r.OrReplace, + Temporary: r.Temporary, + Secure: r.Secure, + IfNotExists: r.IfNotExists, + name: r.name, + + CopyGrants: r.CopyGrants, + ResultDataType: r.ResultDataType, + ReturnNullValues: r.ReturnNullValues, + NullInputBehavior: r.NullInputBehavior, + ReturnResultsBehavior: r.ReturnResultsBehavior, + RuntimeVersion: r.RuntimeVersion, + Comment: r.Comment, + + Handler: r.Handler, + TargetPath: r.TargetPath, + FunctionDefinition: r.FunctionDefinition, + } + if r.Arguments != nil { + s := make([]FunctionArgument, len(r.Arguments)) + for i, v := range r.Arguments { + s[i] = FunctionArgument{ + ArgName: v.ArgName, + ArgDataType: v.ArgDataType, + DefaultValue: v.DefaultValue, + } + } + opts.Arguments = s + } + if r.Imports != nil { + s := make([]FunctionImport, len(r.Imports)) + for i, v := range r.Imports { + s[i] = FunctionImport{ + Import: v.Import, + } + } + opts.Imports = s + } + if r.Packages != nil { + s := make([]FunctionPackage, len(r.Packages)) + for i, v := range r.Packages { + s[i] = FunctionPackage{ + Package: v.Package, + } + } + opts.Packages = s + } + return opts +} + +func (r *CreateForSQLFunctionRequest) toOpts() *CreateForSQLFunctionOptions { + opts := &CreateForSQLFunctionOptions{ + OrReplace: r.OrReplace, + Temporary: r.Temporary, + Secure: r.Secure, + name: r.name, + + CopyGrants: r.CopyGrants, + + ReturnNullValues: r.ReturnNullValues, + ReturnResultsBehavior: r.ReturnResultsBehavior, + Memoizable: r.Memoizable, + Comment: r.Comment, + FunctionDefinition: r.FunctionDefinition, + } + if r.Arguments != nil { + s := make([]FunctionArgument, len(r.Arguments)) + for i, v := range r.Arguments { + s[i] = FunctionArgument{ + ArgName: v.ArgName, + ArgDataType: v.ArgDataType, + DefaultValue: v.DefaultValue, + } + } + opts.Arguments = s + } + opts.Returns = FunctionReturns{} + if r.Returns.ResultDataType != nil { + opts.Returns.ResultDataType = &FunctionReturnsResultDataType{ + ResultDataType: r.Returns.ResultDataType.ResultDataType, + } + } + if r.Returns.Table != nil { + opts.Returns.Table = &FunctionReturnsTable{} + if r.Returns.Table.Columns != nil { + s := make([]FunctionColumn, len(r.Returns.Table.Columns)) + for i, v := range r.Returns.Table.Columns { + s[i] = FunctionColumn{ + ColumnName: v.ColumnName, + ColumnDataType: v.ColumnDataType, + } + } + opts.Returns.Table.Columns = s + } + } + return opts +} + +func (r *AlterFunctionRequest) toOpts() *AlterFunctionOptions { + opts := &AlterFunctionOptions{ + IfExists: r.IfExists, + name: r.name, + ArgumentDataTypes: r.ArgumentDataTypes, + RenameTo: r.RenameTo, + SetComment: r.SetComment, + SetLogLevel: r.SetLogLevel, + SetTraceLevel: r.SetTraceLevel, + SetSecure: r.SetSecure, + UnsetSecure: r.UnsetSecure, + UnsetLogLevel: r.UnsetLogLevel, + UnsetTraceLevel: r.UnsetTraceLevel, + UnsetComment: r.UnsetComment, + SetTags: r.SetTags, + UnsetTags: r.UnsetTags, + } + return opts +} + +func (r *DropFunctionRequest) toOpts() *DropFunctionOptions { + opts := &DropFunctionOptions{ + IfExists: r.IfExists, + name: r.name, + ArgumentDataTypes: r.ArgumentDataTypes, + } + return opts +} + +func (r *ShowFunctionRequest) toOpts() *ShowFunctionOptions { + opts := &ShowFunctionOptions{ + Like: r.Like, + In: r.In, + } + return opts +} + +func (r functionRow) convert() *Function { + e := &Function{ + CreatedOn: r.CreatedOn, + Name: r.Name, + SchemaName: r.SchemaName, + IsBuiltin: r.IsBuiltin == "Y", + IsAggregate: r.IsAggregate == "Y", + IsAnsi: r.IsAnsi == "Y", + MinNumArguments: r.MinNumArguments, + MaxNumArguments: r.MaxNumArguments, + Arguments: r.Arguments, + Description: r.Description, + CatalogName: r.CatalogName, + IsTableFunction: r.IsTableFunction == "Y", + ValidForClustering: r.ValidForClustering == "Y", + IsExternalFunction: r.IsExternalFunction == "Y", + Language: r.Language, + } + if r.IsSecure.Valid { + e.IsSecure = r.IsSecure.String == "Y" + } + if r.IsMemoizable.Valid { + e.IsMemoizable = r.IsMemoizable.String == "Y" + } + return e +} + +func (r *DescribeFunctionRequest) toOpts() *DescribeFunctionOptions { + opts := &DescribeFunctionOptions{ + name: r.name, + ArgumentDataTypes: r.ArgumentDataTypes, + } + return opts +} + +func (r functionDetailRow) convert() *FunctionDetail { + return &FunctionDetail{ + Property: r.Property, + Value: r.Value, + } +} diff --git a/pkg/sdk/functions_validations_gen.go b/pkg/sdk/functions_validations_gen.go new file mode 100644 index 0000000000..3bf1a29ff9 --- /dev/null +++ b/pkg/sdk/functions_validations_gen.go @@ -0,0 +1,189 @@ +package sdk + +var ( + _ validatable = new(CreateForJavaFunctionOptions) + _ validatable = new(CreateForJavascriptFunctionOptions) + _ validatable = new(CreateForPythonFunctionOptions) + _ validatable = new(CreateForScalaFunctionOptions) + _ validatable = new(CreateForSQLFunctionOptions) + _ validatable = new(AlterFunctionOptions) + _ validatable = new(DropFunctionOptions) + _ validatable = new(ShowFunctionOptions) + _ validatable = new(DescribeFunctionOptions) +) + +func (opts *CreateForJavaFunctionOptions) validate() error { + if opts == nil { + return ErrNilOptions + } + var errs []error + if !ValidObjectIdentifier(opts.name) { + errs = append(errs, ErrInvalidObjectIdentifier) + } + if !valueSet(opts.Handler) { + errs = append(errs, errNotSet("CreateForJavaFunctionOptions", "Handler")) + } + if everyValueSet(opts.OrReplace, opts.IfNotExists) { + errs = append(errs, errOneOf("CreateForJavaFunctionOptions", "OrReplace", "IfNotExists")) + } + if valueSet(opts.Returns) { + if !exactlyOneValueSet(opts.Returns.ResultDataType, opts.Returns.Table) { + errs = append(errs, errExactlyOneOf("CreateForJavaFunctionOptions.Returns", "ResultDataType", "Table")) + } + } + if opts.FunctionDefinition == nil { + if opts.TargetPath != nil { + errs = append(errs, NewError("TARGET_PATH must be nil when AS is nil")) + } + if len(opts.Packages) > 0 { + errs = append(errs, NewError("PACKAGES must be empty when AS is nil")) + } + if len(opts.Imports) == 0 { + errs = append(errs, NewError("IMPORTS must not be empty when AS is nil")) + } + } + return JoinErrors(errs...) +} + +func (opts *CreateForJavascriptFunctionOptions) validate() error { + if opts == nil { + return ErrNilOptions + } + var errs []error + if !valueSet(opts.FunctionDefinition) { + errs = append(errs, errNotSet("CreateForJavascriptFunctionOptions", "FunctionDefinition")) + } + if !ValidObjectIdentifier(opts.name) { + errs = append(errs, ErrInvalidObjectIdentifier) + } + if valueSet(opts.Returns) { + if !exactlyOneValueSet(opts.Returns.ResultDataType, opts.Returns.Table) { + errs = append(errs, errExactlyOneOf("CreateForJavascriptFunctionOptions.Returns", "ResultDataType", "Table")) + } + } + return JoinErrors(errs...) +} + +func (opts *CreateForPythonFunctionOptions) validate() error { + if opts == nil { + return ErrNilOptions + } + var errs []error + if !ValidObjectIdentifier(opts.name) { + errs = append(errs, ErrInvalidObjectIdentifier) + } + if !valueSet(opts.RuntimeVersion) { + errs = append(errs, errNotSet("CreateForPythonFunctionOptions", "RuntimeVersion")) + } + if !valueSet(opts.Handler) { + errs = append(errs, errNotSet("CreateForPythonFunctionOptions", "Handler")) + } + if everyValueSet(opts.OrReplace, opts.IfNotExists) { + errs = append(errs, errOneOf("CreateForPythonFunctionOptions", "OrReplace", "IfNotExists")) + } + if valueSet(opts.Returns) { + if !exactlyOneValueSet(opts.Returns.ResultDataType, opts.Returns.Table) { + errs = append(errs, errExactlyOneOf("CreateForPythonFunctionOptions.Returns", "ResultDataType", "Table")) + } + } + if opts.FunctionDefinition == nil { + if len(opts.Imports) == 0 { + errs = append(errs, NewError("IMPORTS must not be empty when AS is nil")) + } + } + return JoinErrors(errs...) +} + +func (opts *CreateForScalaFunctionOptions) validate() error { + if opts == nil { + return ErrNilOptions + } + var errs []error + if !ValidObjectIdentifier(opts.name) { + errs = append(errs, ErrInvalidObjectIdentifier) + } + if !valueSet(opts.Handler) { + errs = append(errs, errNotSet("CreateForScalaFunctionOptions", "Handler")) + } + if everyValueSet(opts.OrReplace, opts.IfNotExists) { + errs = append(errs, errOneOf("CreateForScalaFunctionOptions", "OrReplace", "IfNotExists")) + } + if opts.FunctionDefinition == nil { + if opts.TargetPath != nil { + errs = append(errs, NewError("TARGET_PATH must be nil when AS is nil")) + } + if len(opts.Packages) > 0 { + errs = append(errs, NewError("PACKAGES must be empty when AS is nil")) + } + if len(opts.Imports) == 0 { + errs = append(errs, NewError("IMPORTS must not be empty when AS is nil")) + } + } + return JoinErrors(errs...) +} + +func (opts *CreateForSQLFunctionOptions) validate() error { + if opts == nil { + return ErrNilOptions + } + var errs []error + if !valueSet(opts.FunctionDefinition) { + errs = append(errs, errNotSet("CreateForSQLFunctionOptions", "FunctionDefinition")) + } + if !ValidObjectIdentifier(opts.name) { + errs = append(errs, ErrInvalidObjectIdentifier) + } + if valueSet(opts.Returns) { + if !exactlyOneValueSet(opts.Returns.ResultDataType, opts.Returns.Table) { + errs = append(errs, errExactlyOneOf("CreateForSQLFunctionOptions.Returns", "ResultDataType", "Table")) + } + } + return JoinErrors(errs...) +} + +func (opts *AlterFunctionOptions) validate() error { + if opts == nil { + return ErrNilOptions + } + var errs []error + if !ValidObjectIdentifier(opts.name) { + errs = append(errs, ErrInvalidObjectIdentifier) + } + if opts.RenameTo != nil && !ValidObjectIdentifier(opts.RenameTo) { + errs = append(errs, ErrInvalidObjectIdentifier) + } + if !exactlyOneValueSet(opts.RenameTo, opts.SetComment, opts.SetLogLevel, opts.SetTraceLevel, opts.SetSecure, opts.UnsetLogLevel, opts.UnsetTraceLevel, opts.UnsetSecure, opts.UnsetComment, opts.SetTags, opts.UnsetTags) { + errs = append(errs, errExactlyOneOf("AlterFunctionOptions", "RenameTo", "SetComment", "SetLogLevel", "SetTraceLevel", "SetSecure", "UnsetLogLevel", "UnsetTraceLevel", "UnsetSecure", "UnsetComment", "SetTags", "UnsetTags")) + } + return JoinErrors(errs...) +} + +func (opts *DropFunctionOptions) validate() error { + if opts == nil { + return ErrNilOptions + } + var errs []error + if !ValidObjectIdentifier(opts.name) { + errs = append(errs, ErrInvalidObjectIdentifier) + } + return JoinErrors(errs...) +} + +func (opts *ShowFunctionOptions) validate() error { + if opts == nil { + return ErrNilOptions + } + var errs []error + return JoinErrors(errs...) +} + +func (opts *DescribeFunctionOptions) validate() error { + if opts == nil { + return ErrNilOptions + } + var errs []error + if !ValidObjectIdentifier(opts.name) { + errs = append(errs, ErrInvalidObjectIdentifier) + } + return JoinErrors(errs...) +} diff --git a/pkg/sdk/poc/generator/field_transformers.go b/pkg/sdk/poc/generator/field_transformers.go index 9e4ebd9f14..f0a3be6513 100644 --- a/pkg/sdk/poc/generator/field_transformers.go +++ b/pkg/sdk/poc/generator/field_transformers.go @@ -47,6 +47,11 @@ func (v *KeywordTransformer) Parentheses() *KeywordTransformer { return v } +func (v *KeywordTransformer) MustParentheses() *KeywordTransformer { + v.parentheses = "must_parentheses" + return v +} + func (v *KeywordTransformer) Transform(f *Field) *Field { addTagIfMissing(f.Tags, "ddl", "keyword") if v.required { diff --git a/pkg/sdk/poc/main.go b/pkg/sdk/poc/main.go index 697714125b..0d9ebbb5fe 100644 --- a/pkg/sdk/poc/main.go +++ b/pkg/sdk/poc/main.go @@ -24,6 +24,7 @@ var definitionMapping = map[string]*generator.Interface{ "application_roles_def.go": sdk.ApplicationRolesDef, "views_def.go": sdk.ViewsDef, "stages_def.go": sdk.StagesDef, + "functions_def.go": sdk.FunctionsDef, "procedures_def.go": sdk.ProceduresDef, "event_tables_def.go": sdk.EventTablesDef, } diff --git a/pkg/sdk/testint/functions_integration_test.go b/pkg/sdk/testint/functions_integration_test.go new file mode 100644 index 0000000000..e4645b6661 --- /dev/null +++ b/pkg/sdk/testint/functions_integration_test.go @@ -0,0 +1,462 @@ +package testint + +import ( + "context" + "errors" + "fmt" + "testing" + "time" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk/internal/collections" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk/internal/random" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +/* +todo: add tests for: + - creating functions with different languages (java, javascript, python, scala, sql) from stages using [ TARGET_PATH = '' ] + - execute and execute-immediate for scripting https://docs.snowflake.com/en/sql-reference/sql/execute-immediate +*/ + +func TestInt_CreateFunctions(t *testing.T) { + client := testClient(t) + ctx := context.Background() + + databaseTest, schemaTest := testDb(t), testSchema(t) + + cleanupFunctionHandle := func(id sdk.SchemaObjectIdentifier, dts []sdk.DataType) func() { + return func() { + err := client.Functions.Drop(ctx, sdk.NewDropFunctionRequest(id, dts)) + if errors.Is(err, sdk.ErrObjectNotExistOrAuthorized) { + return + } + require.NoError(t, err) + } + } + + t.Run("create function for Java", func(t *testing.T) { + name := "echo_varchar" + id := sdk.NewSchemaObjectIdentifier(databaseTest.Name, schemaTest.Name, name) + + definition := ` + class TestFunc { + public static String echoVarchar(String x) { + return x; + } + }` + target := fmt.Sprintf("@~/tf-%d.jar", time.Now().Unix()) + dt := sdk.NewFunctionReturnsResultDataTypeRequest(sdk.DataTypeVARCHAR) + returns := sdk.NewFunctionReturnsRequest().WithResultDataType(dt) + argument := sdk.NewFunctionArgumentRequest("x", sdk.DataTypeVARCHAR).WithDefaultValue(sdk.String("'abc'")) + request := sdk.NewCreateForJavaFunctionRequest(id, *returns, "TestFunc.echoVarchar"). + WithOrReplace(sdk.Bool(true)). + WithArguments([]sdk.FunctionArgumentRequest{*argument}). + WithNullInputBehavior(sdk.NullInputBehaviorPointer(sdk.NullInputBehaviorCalledOnNullInput)). + WithTargetPath(&target). + WithFunctionDefinition(&definition) + err := client.Functions.CreateForJava(ctx, request) + require.NoError(t, err) + t.Cleanup(cleanupFunctionHandle(id, []sdk.DataType{"VARCHAR"})) + + function, err := client.Functions.ShowByID(ctx, id) + require.NoError(t, err) + require.Equal(t, id.Name(), function.Name) + require.Equal(t, "JAVA", function.Language) + }) + + t.Run("create function for Javascript", func(t *testing.T) { + name := "js_factorial" + id := sdk.NewSchemaObjectIdentifier(databaseTest.Name, schemaTest.Name, name) + + definition := ` + if (D <= 0) { + return 1; + } else { + var result = 1; + for (var i = 2; i <= D; i++) { + result = result * i; + } + return result; + }` + + dt := sdk.NewFunctionReturnsResultDataTypeRequest(sdk.DataTypeFloat) + returns := sdk.NewFunctionReturnsRequest().WithResultDataType(dt) + argument := sdk.NewFunctionArgumentRequest("d", sdk.DataTypeFloat) + request := sdk.NewCreateForJavascriptFunctionRequest(id, *returns, definition). + WithOrReplace(sdk.Bool(true)). + WithArguments([]sdk.FunctionArgumentRequest{*argument}). + WithNullInputBehavior(sdk.NullInputBehaviorPointer(sdk.NullInputBehaviorCalledOnNullInput)) + err := client.Functions.CreateForJavascript(ctx, request) + require.NoError(t, err) + t.Cleanup(cleanupFunctionHandle(id, []sdk.DataType{sdk.DataTypeFloat})) + + function, err := client.Functions.ShowByID(ctx, id) + require.NoError(t, err) + require.Equal(t, id.Name(), function.Name) + require.Equal(t, "JAVASCRIPT", function.Language) + }) + + t.Run("create function for Python", func(t *testing.T) { + name := random.StringN(8) + id := sdk.NewSchemaObjectIdentifier(databaseTest.Name, schemaTest.Name, name) + + definition := ` +def dump(i): + print("Hello World!")` + dt := sdk.NewFunctionReturnsResultDataTypeRequest(sdk.DataTypeVariant) + returns := sdk.NewFunctionReturnsRequest().WithResultDataType(dt) + argument := sdk.NewFunctionArgumentRequest("i", sdk.DataTypeNumber) + request := sdk.NewCreateForPythonFunctionRequest(id, *returns, "3.8", "dump"). + WithOrReplace(sdk.Bool(true)). + WithArguments([]sdk.FunctionArgumentRequest{*argument}). + WithFunctionDefinition(&definition) + err := client.Functions.CreateForPython(ctx, request) + require.NoError(t, err) + t.Cleanup(cleanupFunctionHandle(id, []sdk.DataType{"int"})) + + function, err := client.Functions.ShowByID(ctx, id) + require.NoError(t, err) + require.Equal(t, id.Name(), function.Name) + require.Equal(t, "PYTHON", function.Language) + }) + + t.Run("create function for Scala", func(t *testing.T) { + name := "echo_varchar" + id := sdk.NewSchemaObjectIdentifier(databaseTest.Name, schemaTest.Name, name) + + definition := ` + class Echo { + def echoVarchar(x : String): String = { + return x + } + }` + + argument := sdk.NewFunctionArgumentRequest("x", sdk.DataTypeVARCHAR) + request := sdk.NewCreateForScalaFunctionRequest(id, sdk.DataTypeVARCHAR, "Echo.echoVarchar"). + WithOrReplace(sdk.Bool(true)). + WithArguments([]sdk.FunctionArgumentRequest{*argument}). + WithRuntimeVersion(sdk.String("2.12")). + WithFunctionDefinition(&definition) + err := client.Functions.CreateForScala(ctx, request) + require.NoError(t, err) + t.Cleanup(cleanupFunctionHandle(id, []sdk.DataType{sdk.DataTypeVARCHAR})) + + function, err := client.Functions.ShowByID(ctx, id) + require.NoError(t, err) + require.Equal(t, id.Name(), function.Name) + require.Equal(t, "SCALA", function.Language) + }) + + t.Run("create function for SQL", func(t *testing.T) { + name := random.String() + id := sdk.NewSchemaObjectIdentifier(databaseTest.Name, schemaTest.Name, name) + + definition := "3.141592654::FLOAT" + + dt := sdk.NewFunctionReturnsResultDataTypeRequest(sdk.DataTypeFloat) + returns := sdk.NewFunctionReturnsRequest().WithResultDataType(dt) + argument := sdk.NewFunctionArgumentRequest("x", sdk.DataTypeFloat) + request := sdk.NewCreateForSQLFunctionRequest(id, *returns, definition). + WithArguments([]sdk.FunctionArgumentRequest{*argument}). + WithOrReplace(sdk.Bool(true)). + WithComment(sdk.String("comment")) + err := client.Functions.CreateForSQL(ctx, request) + require.NoError(t, err) + t.Cleanup(cleanupFunctionHandle(id, []sdk.DataType{sdk.DataTypeFloat})) + + function, err := client.Functions.ShowByID(ctx, id) + require.NoError(t, err) + require.Equal(t, id.Name(), function.Name) + require.Equal(t, "SQL", function.Language) + }) + + t.Run("create function for SQL with no arguments", func(t *testing.T) { + name := random.String() + id := sdk.NewSchemaObjectIdentifier(databaseTest.Name, schemaTest.Name, name) + + definition := "3.141592654::FLOAT" + + dt := sdk.NewFunctionReturnsResultDataTypeRequest(sdk.DataTypeFloat) + returns := sdk.NewFunctionReturnsRequest().WithResultDataType(dt) + request := sdk.NewCreateForSQLFunctionRequest(id, *returns, definition). + WithOrReplace(sdk.Bool(true)). + WithComment(sdk.String("comment")) + err := client.Functions.CreateForSQL(ctx, request) + require.NoError(t, err) + t.Cleanup(cleanupFunctionHandle(id, nil)) + + function, err := client.Functions.ShowByID(ctx, id) + require.NoError(t, err) + require.Equal(t, id.Name(), function.Name) + require.Equal(t, "SQL", function.Language) + }) +} + +func TestInt_OtherFunctions(t *testing.T) { + client := testClient(t) + ctx := testContext(t) + + databaseTest, schemaTest := testDb(t), testSchema(t) + tagTest, tagCleanup := createTag(t, client, databaseTest, schemaTest) + t.Cleanup(tagCleanup) + + assertFunction := func(t *testing.T, id sdk.SchemaObjectIdentifier, secure bool, withArguments bool) { + t.Helper() + + function, err := client.Functions.ShowByID(ctx, id) + require.NoError(t, err) + + assert.NotEmpty(t, function.CreatedOn) + assert.Equal(t, id.Name(), function.Name) + assert.Equal(t, false, function.IsBuiltin) + assert.Equal(t, false, function.IsAggregate) + assert.Equal(t, false, function.IsAnsi) + if withArguments { + assert.Equal(t, 1, function.MinNumArguments) + assert.Equal(t, 1, function.MaxNumArguments) + } else { + assert.Equal(t, 0, function.MinNumArguments) + assert.Equal(t, 0, function.MaxNumArguments) + } + assert.NotEmpty(t, function.Arguments) + assert.NotEmpty(t, function.Description) + assert.NotEmpty(t, function.CatalogName) + assert.Equal(t, false, function.IsTableFunction) + assert.Equal(t, false, function.ValidForClustering) + assert.Equal(t, secure, function.IsSecure) + assert.Equal(t, false, function.IsExternalFunction) + assert.Equal(t, "SQL", function.Language) + assert.Equal(t, false, function.IsMemoizable) + } + + cleanupFunctionHandle := func(id sdk.SchemaObjectIdentifier, dts []sdk.DataType) func() { + return func() { + err := client.Functions.Drop(ctx, sdk.NewDropFunctionRequest(id, dts)) + if errors.Is(err, sdk.ErrObjectNotExistOrAuthorized) { + return + } + require.NoError(t, err) + } + } + + createFunctionForSQLHandle := func(t *testing.T, cleanup bool, withArguments bool) *sdk.Function { + t.Helper() + id := sdk.NewSchemaObjectIdentifier(databaseTest.Name, schemaTest.Name, random.StringN(4)) + + definition := "3.141592654::FLOAT" + + dt := sdk.NewFunctionReturnsResultDataTypeRequest(sdk.DataTypeFloat) + returns := sdk.NewFunctionReturnsRequest().WithResultDataType(dt) + request := sdk.NewCreateForSQLFunctionRequest(id, *returns, definition). + WithOrReplace(sdk.Bool(true)) + if withArguments { + argument := sdk.NewFunctionArgumentRequest("x", sdk.DataTypeFloat) + request = request.WithArguments([]sdk.FunctionArgumentRequest{*argument}) + } + err := client.Functions.CreateForSQL(ctx, request) + require.NoError(t, err) + if cleanup { + if withArguments { + t.Cleanup(cleanupFunctionHandle(id, []sdk.DataType{sdk.DataTypeFloat})) + } else { + t.Cleanup(cleanupFunctionHandle(id, nil)) + } + } + function, err := client.Functions.ShowByID(ctx, id) + require.NoError(t, err) + return function + } + + defaultAlterRequest := func(id sdk.SchemaObjectIdentifier) *sdk.AlterFunctionRequest { + return sdk.NewAlterFunctionRequest(id, []sdk.DataType{sdk.DataTypeFloat}) + } + + t.Run("alter function: rename", func(t *testing.T) { + f := createFunctionForSQLHandle(t, false, true) + + id := sdk.NewSchemaObjectIdentifier(databaseTest.Name, schemaTest.Name, f.Name) + nid := sdk.NewSchemaObjectIdentifier(databaseTest.Name, schemaTest.Name, random.StringN(3)) + err := client.Functions.Alter(ctx, defaultAlterRequest(id).WithRenameTo(&nid)) + if err != nil { + t.Cleanup(cleanupFunctionHandle(id, []sdk.DataType{sdk.DataTypeFloat})) + } else { + t.Cleanup(cleanupFunctionHandle(nid, []sdk.DataType{sdk.DataTypeFloat})) + } + require.NoError(t, err) + + _, err = client.Functions.ShowByID(ctx, id) + assert.ErrorIs(t, err, collections.ErrObjectNotFound) + + e, err := client.Functions.ShowByID(ctx, nid) + require.NoError(t, err) + require.Equal(t, nid.Name(), e.Name) + }) + + t.Run("alter function: set log level", func(t *testing.T) { + f := createFunctionForSQLHandle(t, true, true) + + id := sdk.NewSchemaObjectIdentifier(databaseTest.Name, schemaTest.Name, f.Name) + err := client.Functions.Alter(ctx, defaultAlterRequest(id).WithSetLogLevel(sdk.String("DEBUG"))) + require.NoError(t, err) + assertFunction(t, id, false, true) + }) + + t.Run("alter function: unset log level", func(t *testing.T) { + f := createFunctionForSQLHandle(t, true, true) + + id := sdk.NewSchemaObjectIdentifier(databaseTest.Name, schemaTest.Name, f.Name) + err := client.Functions.Alter(ctx, defaultAlterRequest(id).WithUnsetLogLevel(sdk.Bool(true))) + require.NoError(t, err) + assertFunction(t, id, false, true) + }) + + t.Run("alter function: set trace level", func(t *testing.T) { + f := createFunctionForSQLHandle(t, true, true) + + id := sdk.NewSchemaObjectIdentifier(databaseTest.Name, schemaTest.Name, f.Name) + err := client.Functions.Alter(ctx, defaultAlterRequest(id).WithSetTraceLevel(sdk.String("ALWAYS"))) + require.NoError(t, err) + assertFunction(t, id, false, true) + }) + + t.Run("alter function: unset trace level", func(t *testing.T) { + f := createFunctionForSQLHandle(t, true, true) + + id := sdk.NewSchemaObjectIdentifier(databaseTest.Name, schemaTest.Name, f.Name) + err := client.Functions.Alter(ctx, defaultAlterRequest(id).WithUnsetTraceLevel(sdk.Bool(true))) + require.NoError(t, err) + assertFunction(t, id, false, true) + }) + + t.Run("alter function: set comment", func(t *testing.T) { + f := createFunctionForSQLHandle(t, true, true) + + id := sdk.NewSchemaObjectIdentifier(databaseTest.Name, schemaTest.Name, f.Name) + err := client.Functions.Alter(ctx, defaultAlterRequest(id).WithSetComment(sdk.String("test comment"))) + require.NoError(t, err) + assertFunction(t, id, false, true) + }) + + t.Run("alter function: unset comment", func(t *testing.T) { + f := createFunctionForSQLHandle(t, true, true) + + id := sdk.NewSchemaObjectIdentifier(databaseTest.Name, schemaTest.Name, f.Name) + err := client.Functions.Alter(ctx, defaultAlterRequest(id).WithUnsetComment(sdk.Bool(true))) + require.NoError(t, err) + assertFunction(t, id, false, true) + }) + + t.Run("alter function: set secure", func(t *testing.T) { + f := createFunctionForSQLHandle(t, true, true) + + id := sdk.NewSchemaObjectIdentifier(databaseTest.Name, schemaTest.Name, f.Name) + err := client.Functions.Alter(ctx, defaultAlterRequest(id).WithSetSecure(sdk.Bool(true))) + require.NoError(t, err) + assertFunction(t, id, true, true) + }) + + t.Run("alter function: set secure with no arguments", func(t *testing.T) { + f := createFunctionForSQLHandle(t, true, false) + id := sdk.NewSchemaObjectIdentifier(databaseTest.Name, schemaTest.Name, f.Name) + err := client.Functions.Alter(ctx, sdk.NewAlterFunctionRequest(id, nil).WithSetSecure(sdk.Bool(true))) + require.NoError(t, err) + assertFunction(t, id, true, false) + }) + + t.Run("alter function: unset secure", func(t *testing.T) { + f := createFunctionForSQLHandle(t, true, true) + + id := sdk.NewSchemaObjectIdentifier(databaseTest.Name, schemaTest.Name, f.Name) + err := client.Functions.Alter(ctx, defaultAlterRequest(id).WithUnsetSecure(sdk.Bool(true))) + require.NoError(t, err) + assertFunction(t, id, false, true) + }) + + t.Run("alter function: set and unset tags", func(t *testing.T) { + f := createFunctionForSQLHandle(t, true, true) + + id := sdk.NewSchemaObjectIdentifier(databaseTest.Name, schemaTest.Name, f.Name) + setTags := []sdk.TagAssociation{ + { + Name: tagTest.ID(), + Value: "v1", + }, + } + err := client.Functions.Alter(ctx, defaultAlterRequest(id).WithSetTags(setTags)) + require.NoError(t, err) + assertFunction(t, id, false, true) + + unsetTags := []sdk.ObjectIdentifier{ + tagTest.ID(), + } + err = client.Functions.Alter(ctx, defaultAlterRequest(id).WithUnsetTags(unsetTags)) + require.NoError(t, err) + assertFunction(t, id, false, true) + }) + + t.Run("show function for SQL: without like", func(t *testing.T) { + f1 := createFunctionForSQLHandle(t, true, true) + f2 := createFunctionForSQLHandle(t, true, true) + + functions, err := client.Functions.Show(ctx, sdk.NewShowFunctionRequest()) + require.NoError(t, err) + + require.Equal(t, 2, len(functions)) + require.Contains(t, functions, *f1) + require.Contains(t, functions, *f2) + }) + + t.Run("show function for SQL: with like", func(t *testing.T) { + f1 := createFunctionForSQLHandle(t, true, true) + f2 := createFunctionForSQLHandle(t, true, true) + + functions, err := client.Functions.Show(ctx, sdk.NewShowFunctionRequest().WithLike(&sdk.Like{Pattern: &f1.Name})) + require.NoError(t, err) + + require.Equal(t, 1, len(functions)) + require.Contains(t, functions, *f1) + require.NotContains(t, functions, *f2) + }) + + t.Run("show function for SQL: no matches", func(t *testing.T) { + functions, err := client.Functions.Show(ctx, sdk.NewShowFunctionRequest().WithLike(&sdk.Like{Pattern: sdk.String(random.String())})) + require.NoError(t, err) + require.Equal(t, 0, len(functions)) + }) + + t.Run("describe function for SQL", func(t *testing.T) { + f := createFunctionForSQLHandle(t, true, true) + id := sdk.NewSchemaObjectIdentifier(databaseTest.Name, schemaTest.Name, f.Name) + + request := sdk.NewDescribeFunctionRequest(id, []sdk.DataType{sdk.DataTypeFloat}) + details, err := client.Functions.Describe(ctx, request) + require.NoError(t, err) + pairs := make(map[string]string) + for _, detail := range details { + pairs[detail.Property] = detail.Value + } + require.Equal(t, "SQL", pairs["language"]) + require.Equal(t, "FLOAT", pairs["returns"]) + require.Equal(t, "3.141592654::FLOAT", pairs["body"]) + require.Equal(t, "(X FLOAT)", pairs["signature"]) + }) + + t.Run("describe function for SQL: no arguments", func(t *testing.T) { + f := createFunctionForSQLHandle(t, true, false) + id := sdk.NewSchemaObjectIdentifier(databaseTest.Name, schemaTest.Name, f.Name) + + request := sdk.NewDescribeFunctionRequest(id, nil) + details, err := client.Functions.Describe(ctx, request) + require.NoError(t, err) + pairs := make(map[string]string) + for _, detail := range details { + pairs[detail.Property] = detail.Value + } + require.Equal(t, "SQL", pairs["language"]) + require.Equal(t, "FLOAT", pairs["returns"]) + require.Equal(t, "3.141592654::FLOAT", pairs["body"]) + require.Equal(t, "()", pairs["signature"]) + }) +}