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

fix: tagging for db, external_table, schema #795

Merged
merged 2 commits into from
Jan 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion pkg/resources/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ var databaseSchema = map[string]*schema.Schema{
"tag": tagReferenceSchema,
}

var databaseProperties = []string{"comment", "data_retention_time_in_days"}
var databaseProperties = []string{"comment", "data_retention_time_in_days", "tag"}

// Database returns a pointer to the resource representing a database
func Database() *schema.Resource {
Expand Down Expand Up @@ -152,6 +152,7 @@ func ReadDatabase(d *schema.ResourceData, meta interface{}) error {
}

func UpdateDatabase(d *schema.ResourceData, meta interface{}) error {
log.Printf("[DEBUG] updating database %v", d.Id())
return UpdateResource("database", databaseProperties, databaseSchema, snowflake.Database, ReadDatabase)(d, meta)
}

Expand Down
36 changes: 36 additions & 0 deletions pkg/resources/external_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ func ExternalTable() *schema.Resource {
return &schema.Resource{
Create: CreateExternalTable,
Read: ReadExternalTable,
Update: UpdateExternalTable,
Delete: DeleteExternalTable,

Schema: externalTableSchema,
Expand Down Expand Up @@ -291,6 +292,41 @@ func ReadExternalTable(data *schema.ResourceData, meta interface{}) error {
return nil
}

// UpdateExternalTable implements schema.UpdateFunc
func UpdateExternalTable(data *schema.ResourceData, meta interface{}) error {
db := meta.(*sql.DB)
database := data.Get("database").(string)
dbSchema := data.Get("schema").(string)
name := data.Get("name").(string)

builder := snowflake.ExternalTable(name, database, dbSchema)

if data.HasChange("tag") {
v := data.Get("tag")
tags := getTags(v)
builder.WithTags(tags.toSnowflakeTagValues())
}

stmt := builder.Update()
err := snowflake.Exec(db, stmt)
if err != nil {
return errors.Wrapf(err, "error updating externalTable %v", name)
}

externalTableID := &externalTableID{
DatabaseName: database,
SchemaName: dbSchema,
ExternalTableName: name,
}
dataIDInput, err := externalTableID.String()
if err != nil {
return err
}
data.SetId(dataIDInput)

return ReadExternalTable(data, meta)
}

// DeleteExternalTable implements schema.DeleteFunc
func DeleteExternalTable(data *schema.ResourceData, meta interface{}) error {
db := meta.(*sql.DB)
Expand Down
18 changes: 12 additions & 6 deletions pkg/resources/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package resources

import (
"database/sql"
"log"

"github.com/chanzuckerberg/terraform-provider-snowflake/pkg/snowflake"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
Expand Down Expand Up @@ -34,15 +35,13 @@ func CreateResource(
case schema.TypeInt:
valInt := val.(int)
qb.SetInt(field, valInt)
case schema.TypeList:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you getting rid of this?

Copy link
Collaborator Author

@sfc-gh-swinkler sfc-gh-swinkler Dec 23, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all that does is type conversion, but it wasn't actually converting the types properly. we already have a function getTags() that does work. so using that instead, added on line 41-44

tags, ok := val.([]snowflake.TagValue)
if !ok {
continue
}
qb.SetTags(tags)
}
}
}
if v, ok := d.GetOk("tag"); ok {
tags := getTags(v)
qb.SetTags(tags.toSnowflakeTagValues())
}
err := snowflake.Exec(db, qb.Statement())

if err != nil {
Expand Down Expand Up @@ -103,12 +102,19 @@ func UpdateResource(
qb.SetInt(field, valInt)
}
}
if d.HasChange("tag") {
log.Printf("[DEBUG] updating tags")
v := d.Get("tag")
tags := getTags(v)
qb.SetTags(tags.toSnowflakeTagValues())
}

err := snowflake.Exec(db, qb.Statement())
if err != nil {
return errors.Wrapf(err, "error altering %s", t)
}
}
log.Printf("[DEBUG] performing read")
return read(d, meta)
}
}
Expand Down
5 changes: 0 additions & 5 deletions pkg/resources/tag.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,35 +48,30 @@ var tagReferenceSchema = &schema.Schema{
Type: schema.TypeList,
Required: false,
Optional: true,
ForceNew: true,
MinItems: 0,
Description: "Definitions of a tag to associate with the resource.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "Tag name, e.g. department.",
},
"value": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "Tag value, e.g. marketing_info.",
},
"database": {
Type: schema.TypeString,
Required: false,
Optional: true,
ForceNew: true,
Description: "Name of the database that the tag was created in.",
},
"schema": {
Type: schema.TypeString,
Required: false,
Optional: true,
ForceNew: true,
Description: "Name of the schema that the tag was created in.",
},
},
Expand Down
32 changes: 32 additions & 0 deletions pkg/snowflake/external_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,22 @@ func (tb *ExternalTableBuilder) Create() string {
q.WriteString(fmt.Sprintf(` COMMENT = '%v'`, EscapeString(tb.comment)))
}

if len(tb.tags) > 0 {
q.WriteString(fmt.Sprintf(` WITH TAG (%s)`, tb.GetTagValueString()))
}

return q.String()
}

// Update returns the SQL statement required to update an externalTable
func (tb *ExternalTableBuilder) Update() string {
q := strings.Builder{}
q.WriteString(fmt.Sprintf(`ALTER EXTERNAL TABLE %v`, tb.QualifiedName()))

if len(tb.tags) > 0 {
q.WriteString(fmt.Sprintf(` TAG %s`, tb.GetTagValueString()))
}

return q.String()
}

Expand All @@ -168,6 +184,22 @@ func (tb *ExternalTableBuilder) Show() string {
return fmt.Sprintf(`SHOW EXTERNAL TABLES LIKE '%v' IN SCHEMA "%v"."%v"`, tb.name, tb.db, tb.schema)
}

func (tb *ExternalTableBuilder) GetTagValueString() string {
var q strings.Builder
for _, v := range tb.tags {
fmt.Println(v)
if v.Schema != "" {
if v.Database != "" {
q.WriteString(fmt.Sprintf(`"%v".`, v.Database))
}
q.WriteString(fmt.Sprintf(`"%v".`, v.Schema))
}
q.WriteString(fmt.Sprintf(`"%v" = "%v", `, v.Name, v.Value))
}
return strings.TrimSuffix(q.String(), ", ")
}


type externalTable struct {
CreatedOn sql.NullString `db:"created_on"`
ExternalTableName sql.NullString `db:"name"`
Expand Down
7 changes: 7 additions & 0 deletions pkg/snowflake/external_table_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ func TestExternalTableCreate(t *testing.T) {
r.Equal(s.Create(), `CREATE EXTERNAL TABLE "test_db"."test_schema"."test_table" ("column1" OBJECT AS expression1, "column2" VARCHAR AS expression2) WITH LOCATION = location REFRESH_ON_CREATE = false AUTO_REFRESH = false PATTERN = 'pattern' FILE_FORMAT = ( file format ) COMMENT = 'Test Comment'`)
}

func TestExternalTableUpdate(t *testing.T){
r := require.New(t)
s := ExternalTable("test_table", "test_db", "test_schema")
s.WithTags([]TagValue{{Name: "tag1", Value: "value1", Schema: "test_schema", Database: "test_db"}})
r.Equal(s.Update(), `ALTER EXTERNAL TABLE "test_db"."test_schema"."test_table" TAG "test_db"."test_schema"."tag1" = "value1"`)
}

func TestExternalTableDrop(t *testing.T) {
r := require.New(t)
s := ExternalTable("test_table", "test_db", "test_schema")
Expand Down
44 changes: 34 additions & 10 deletions pkg/snowflake/generic.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,21 @@ func (b *AlterPropertiesBuilder) SetTags(tags []TagValue) {
b.tags = tags
}

func (ab *AlterPropertiesBuilder) GetTagValueString() string {
var q strings.Builder
for _, v := range ab.tags {
fmt.Println(v)
if v.Schema != "" {
if v.Database != "" {
q.WriteString(fmt.Sprintf(`"%v".`, v.Database))
}
q.WriteString(fmt.Sprintf(`"%v".`, v.Schema))
}
q.WriteString(fmt.Sprintf(`"%v" = "%v", `, v.Name, v.Value))
}
return strings.TrimSuffix(q.String(), ", ")
}

func (ab *AlterPropertiesBuilder) Statement() string {
var sb strings.Builder
sb.WriteString(fmt.Sprintf(`ALTER %s "%s" SET`, ab.entityType, ab.name)) // TODO handle error
Expand All @@ -134,10 +149,9 @@ func (ab *AlterPropertiesBuilder) Statement() string {
sb.WriteString(fmt.Sprintf(" %s=%.2f", strings.ToUpper(k), ab.floatProperties[k]))
}

for _, t := range sortTags(ab.tags) {
sb.WriteString(fmt.Sprintf(` TAG "%v"."%v"."%v" = "%v"`, t.Database, t.Schema, t.Name, t.Value))
if len(ab.tags) > 0 {
sb.WriteString(fmt.Sprintf(` TAG %s`, ab.GetTagValueString()))
}

return sb.String()
}

Expand Down Expand Up @@ -195,6 +209,21 @@ func (b *CreateBuilder) SetTags(tags []TagValue) {
b.tags = tags
}

func (b *CreateBuilder) GetTagValueString() string {
var q strings.Builder
for _, v := range b.tags {
fmt.Println(v)
if v.Schema != "" {
if v.Database != "" {
q.WriteString(fmt.Sprintf(`"%v".`, v.Database))
}
q.WriteString(fmt.Sprintf(`"%v".`, v.Schema))
}
q.WriteString(fmt.Sprintf(`"%v" = "%v", `, v.Name, v.Value))
}
return strings.TrimSuffix(q.String(), ", ")
}

func (b *CreateBuilder) Statement() string {
var sb strings.Builder
sb.WriteString(fmt.Sprintf(`CREATE %s "%s"`, b.entityType, b.name)) // TODO handle error
Expand All @@ -221,13 +250,8 @@ func (b *CreateBuilder) Statement() string {
sb.WriteString(fmt.Sprintf(" %s=%.2f", strings.ToUpper(k), b.floatProperties[k]))
}

for i, t := range sortTags(b.tags) {
if i == 0 {
sb.WriteString(` TAG`)
} else if i < len(b.tags)-1 {
sb.WriteString(`, `)
}
sb.WriteString(fmt.Sprintf(`"%v"."%v"."%v" = "%v"`, t.Database, t.Schema, t.Name, t.Value))
if len(b.tags) > 0 {
sb.WriteString(fmt.Sprintf(` WITH TAG (%s)`, b.GetTagValueString()))
}

return sb.String()
Expand Down