Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use funcs from sdk #2462

Merged
merged 3 commits into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/resources/function.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ resource "snowflake_function" "sql_test" {
- `name` (String) Specifies the identifier for the function; does not have to be unique for the schema in which the function is created. Don't use the | character.
- `return_type` (String) The return type of the function
- `schema` (String) The schema in which to create the function. Don't use the | character.
- `statement` (String) Specifies the javascript / java / sql / python code used to create the function.
- `statement` (String) Specifies the javascript / java / scala / sql / python code used to create the function.

### Optional

Expand All @@ -106,7 +106,7 @@ resource "snowflake_function" "sql_test" {
- `handler` (String) The handler method for Java / Python function.
- `imports` (List of String) Imports for Java / Python functions. For Java this a list of jar files, for Python this is a list of Python files.
- `is_secure` (Boolean) Specifies that the function is secure.
- `language` (String) The language of the statement
- `language` (String) Specifies the language of the stored function code.
- `null_input_behavior` (String) Specifies the behavior of the function when called with null inputs.
- `packages` (List of String) List of package imports to use for Java / Python functions. For Java, package imports should be of the form: package_name:version_number, where package_name is snowflake_domain:package. For Python use it should be: ('numpy','pandas','xgboost==1.5.0').
- `return_behavior` (String) Specifies the behavior of the function when returning results
Expand Down
66 changes: 39 additions & 27 deletions pkg/datasources/functions.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package datasources

import (
"context"
"database/sql"
"log"
"fmt"

"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake"
"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers"
"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

Expand Down Expand Up @@ -60,43 +63,52 @@ var functionsSchema = map[string]*schema.Schema{

func Functions() *schema.Resource {
return &schema.Resource{
Read: ReadFunctions,
Schema: functionsSchema,
ReadContext: ReadContextFunctions,
Schema: functionsSchema,
}
}

// todo: fix this. ListUserFunctions isn't using the right struct right now and also the signature of this doesn't support all the features it could for example, database and schema should be optional, and you could also list by account.
func ReadFunctions(d *schema.ResourceData, meta interface{}) error {
func ReadContextFunctions(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
db := meta.(*sql.DB)
client := sdk.NewClientFromDB(db)
databaseName := d.Get("database").(string)
schemaName := d.Get("schema").(string)

d.SetId("functions")
currentFunctions, err := snowflake.ListUserFunctions(databaseName, schemaName, db)
request := sdk.NewShowFunctionRequest()
request.WithIn(&sdk.In{Schema: sdk.NewDatabaseObjectIdentifier(databaseName, schemaName)})
functions, err := client.Functions.Show(ctx, request)
if err != nil {
log.Printf("[DEBUG] error listing functions: %v", err)
return nil
}

functions := []map[string]interface{}{}
id := d.Id()

for _, function := range currentFunctions {
functionMap := map[string]interface{}{}
d.SetId("")
return diag.Diagnostics{
diag.Diagnostic{
Severity: diag.Warning,
Summary: fmt.Sprintf("Unable to parse functions in schema (%s)", id),
Detail: "See our document on design decisions for functions: <LINK (coming soon)>",
},
}
}

functionSignatureMap, err := parseArguments(function.Arguments.String)
entities := []map[string]interface{}{}
for _, item := range functions {
signature, err := parseArguments(item.Arguments)
if err != nil {
return err
return diag.FromErr(err)
}
m := map[string]interface{}{}
m["name"] = item.Name
m["database"] = databaseName
m["schema"] = schemaName
m["comment"] = item.Description
m["argument_types"] = signature["argumentTypes"].([]string)
m["return_type"] = signature["returnType"].(string)

functionMap["name"] = function.Name.String
functionMap["database"] = databaseName
functionMap["schema"] = schemaName
functionMap["comment"] = function.Description.String
functionMap["argument_types"] = functionSignatureMap["argumentTypes"].([]string)
functionMap["return_type"] = functionSignatureMap["returnType"].(string)

functions = append(functions, functionMap)
entities = append(entities, m)
}

return d.Set("functions", functions)
d.SetId(helpers.EncodeSnowflakeID(databaseName, schemaName))
if err := d.Set("functions", entities); err != nil {
return diag.FromErr(err)
}
return nil
}
64 changes: 27 additions & 37 deletions pkg/datasources/functions_acceptance_test.go
Original file line number Diff line number Diff line change
@@ -1,57 +1,47 @@
package datasources_test

import (
"fmt"
"strings"
"testing"

acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance"
"github.com/hashicorp/terraform-plugin-testing/config"
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/tfversion"
)

func TestAcc_Functions(t *testing.T) {
databaseName := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
schemaName := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
functionName := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
resource.ParallelTest(t, resource.TestCase{
Providers: providers(),
functionNameOne := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
functionNameTwo := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
dataSourceName := "data.snowflake_functions.functions"

m := func() map[string]config.Variable {
return map[string]config.Variable{
"database": config.StringVariable(acc.TestDatabaseName),
"schema": config.StringVariable(acc.TestSchemaName),
"function_name_one": config.StringVariable(functionNameOne),
"function_name_two": config.StringVariable(functionNameTwo),
}
}
variableSet1 := m()
resource.Test(t, resource.TestCase{
ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories,
PreCheck: func() { acc.TestAccPreCheck(t) },
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
tfversion.RequireAbove(tfversion.Version1_5_0),
},
CheckDestroy: nil,
Steps: []resource.TestStep{
{
Config: functions(databaseName, schemaName, functionName),
ConfigDirectory: acc.ConfigurationDirectory("TestAcc_Functions/complete"),
ConfigVariables: variableSet1,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.snowflake_functions.t", "database", databaseName),
resource.TestCheckResourceAttr("data.snowflake_functions.t", "schema", schemaName),
resource.TestCheckResourceAttr(dataSourceName, "database", acc.TestDatabaseName),
resource.TestCheckResourceAttr(dataSourceName, "schema", acc.TestSchemaName),
resource.TestCheckResourceAttrSet(dataSourceName, "functions.#"),
),
},
},
})
}

func functions(databaseName string, schemaName string, functionName string) string {
s := `
resource "snowflake_database" "test_database" {
name = "%v"
comment = "Terraform acceptance test"
}
resource "snowflake_schema" "test_schema" {
name = "%v"
database = snowflake_database.test_database.name
comment = "Terraform acceptance test"
}
resource "snowflake_function" "test_funct_simple" {
name = "%s"
database = snowflake_database.test_database.name
schema = snowflake_schema.test_schema.name
return_type = "float"
statement = "3.141592654::FLOAT"
}

data snowflake_functions "t" {
database = snowflake_database.test_database.name
schema = snowflake_schema.test_schema.name
depends_on = [snowflake_function.test_funct_simple]
}
`
return fmt.Sprintf(s, databaseName, schemaName, functionName)
}
33 changes: 33 additions & 0 deletions pkg/datasources/testdata/TestAcc_Functions/complete/test.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
resource "snowflake_function" "test_function_one" {
name = var.function_name_one
database = var.database
schema = var.schema
return_type = "VARCHAR"
language = "JAVASCRIPT"
statement = <<-EOF
return "Hi"
EOF
}

resource "snowflake_function" "test_function_two" {
name = var.function_name_two
database = var.database
schema = var.schema
arguments {
name = "arg1"
type = "varchar"
}
comment = "Terraform acceptance test"
return_type = "varchar"
language = "JAVASCRIPT"
statement = <<-EOF
var x = 1
return x
EOF
}

data "snowflake_functions" "functions" {
database = var.database
schema = var.schema
depends_on = [snowflake_function.test_function_one, snowflake_function.test_function_two]
}
15 changes: 15 additions & 0 deletions pkg/datasources/testdata/TestAcc_Functions/complete/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
variable "function_name_one" {
type = string
}

variable "function_name_two" {
type = string
}

variable "database" {
type = string
}

variable "schema" {
type = string
}
Loading
Loading