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: Support DIRECTORY option on stage create #872

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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/resources/stage.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ resource "snowflake_stage_grant" "grant_example_stage" {
- **comment** (String) Specifies a comment for the stage.
- **copy_options** (String) Specifies the copy options for the stage.
- **credentials** (String, Sensitive) Specifies the credentials for the stage.
- **directory** (String) Specifies the directory settings for the stage.
- **encryption** (String) Specifies the encryption settings for the stage.
- **file_format** (String) Specifies the file format for the stage.
- **id** (String) The ID of this resource.
Expand Down
15 changes: 15 additions & 0 deletions pkg/resources/stage.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ var stageSchema = map[string]*schema.Schema{
Optional: true,
Description: "Specifies a comment for the stage.",
},
"directory": {
Type: schema.TypeString,
ForceNew: true,
Optional: true,
Description: "Specifies the directory settings for the stage.",
},
"aws_external_id": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -176,6 +182,10 @@ func CreateStage(d *schema.ResourceData, meta interface{}) error {
builder.WithCopyOptions(v.(string))
}

if v, ok := d.GetOk("directory"); ok {
builder.WithDirectory(v.(string))
}

if v, ok := d.GetOk("encryption"); ok {
builder.WithEncryption(v.(string))
}
Expand Down Expand Up @@ -273,6 +283,11 @@ func ReadStage(d *schema.ResourceData, meta interface{}) error {
return err
}

err = d.Set("directory", stageDesc.Directory)
if err != nil {
return err
}

err = d.Set("storage_integration", s.StorageIntegration)
if err != nil {
return err
Expand Down
3 changes: 2 additions & 1 deletion pkg/resources/stage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ func expectReadStage(mock sqlmock.Sqlmock) {
"parent_property", "property", "property_type", "property_value", "property_default"},
).AddRow("STAGE_LOCATION", "URL", "string", `["s3://load/test/"]`, "").
AddRow("STAGE_CREDENTIALS", "AWS_EXTERNAL_ID", "string", "test", "").
AddRow("STAGE_FILE_FORMAT", "FORMAT_NAME", "string", "CSV", "")
AddRow("STAGE_FILE_FORMAT", "FORMAT_NAME", "string", "CSV", "").
AddRow("DIRECTORY", "ENABLED", "Boolean", true, false)
mock.ExpectQuery(`^DESCRIBE STAGE "test_db"."test_schema"."test_stage"$`).WillReturnRows(rows)
}

Expand Down
18 changes: 18 additions & 0 deletions pkg/snowflake/stage.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type StageBuilder struct {
schema string
url string
credentials string
directory string
storageIntegration string
encryption string
fileFormat string
Expand Down Expand Up @@ -74,6 +75,12 @@ func (sb *StageBuilder) WithCopyOptions(c string) *StageBuilder {
return sb
}

// WithDirectory adds directory option to the StageBuilder
func (sb *StageBuilder) WithDirectory(d string) *StageBuilder {
sb.directory = d
return sb
}

// WithComment adds a comment to the StageBuilder
func (sb *StageBuilder) WithComment(c string) *StageBuilder {
sb.comment = c
Expand Down Expand Up @@ -150,6 +157,10 @@ func (sb *StageBuilder) Create() string {
q.WriteString(fmt.Sprintf(` COPY_OPTIONS = (%v)`, sb.copyOptions))
}

if sb.directory != "" {
q.WriteString(fmt.Sprintf(` DIRECTORY = (%v)`, sb.directory))
}

if sb.comment != "" {
q.WriteString(fmt.Sprintf(` COMMENT = '%v'`, EscapeString(sb.comment)))
}
Expand Down Expand Up @@ -242,6 +253,7 @@ type descStageResult struct {
SnowflakeIamUser string
FileFormat string
CopyOptions string
Directory string
}

type descStageRow struct {
Expand All @@ -255,6 +267,7 @@ func DescStage(db *sql.DB, query string) (*descStageResult, error) {
r := &descStageResult{}
var ff []string
var co []string
var dir []string
rows, err := Query(db, query)
if err != nil {
return r, err
Expand Down Expand Up @@ -286,11 +299,16 @@ func DescStage(db *sql.DB, query string) (*descStageResult, error) {
if row.PropertyValue != row.PropertyDefault {
co = append(co, fmt.Sprintf("%s = %s", row.Property, row.PropertyValue))
}
case "DIRECTORY":
if row.PropertyValue != row.PropertyDefault {
dir = append(dir, fmt.Sprintf("%s = %s", row.Property, row.PropertyValue))
}
}
}

r.FileFormat = strings.Join(ff, " ")
r.CopyOptions = strings.Join(co, " ")
r.Directory = strings.Join(dir, " ")
return r, nil
}

Expand Down
7 changes: 5 additions & 2 deletions pkg/snowflake/stage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,14 @@ func TestStageCreate(t *testing.T) {
s.WithCopyOptions("on_error='skip_file'")
r.Equal(s.Create(), `CREATE STAGE "test_db"."test_schema"."test_stage" URL = 's3://load/encrypted_files/' CREDENTIALS = (aws_role='arn:aws:iam::001234567890:role/mysnowflakerole') ENCRYPTION = (type='AWS_SSE_KMS' kms_key_id = 'aws/key') FILE_FORMAT = (format_name=my_csv_format) COPY_OPTIONS = (on_error='skip_file')`)

s.WithDirectory("ENABLE=TRUE")
r.Equal(s.Create(), `CREATE STAGE "test_db"."test_schema"."test_stage" URL = 's3://load/encrypted_files/' CREDENTIALS = (aws_role='arn:aws:iam::001234567890:role/mysnowflakerole') ENCRYPTION = (type='AWS_SSE_KMS' kms_key_id = 'aws/key') FILE_FORMAT = (format_name=my_csv_format) COPY_OPTIONS = (on_error='skip_file') DIRECTORY = (ENABLE=TRUE)`)

s.WithComment("Yee'haw")
r.Equal(`CREATE STAGE "test_db"."test_schema"."test_stage" URL = 's3://load/encrypted_files/' CREDENTIALS = (aws_role='arn:aws:iam::001234567890:role/mysnowflakerole') ENCRYPTION = (type='AWS_SSE_KMS' kms_key_id = 'aws/key') FILE_FORMAT = (format_name=my_csv_format) COPY_OPTIONS = (on_error='skip_file') COMMENT = 'Yee\'haw'`, s.Create())
r.Equal(`CREATE STAGE "test_db"."test_schema"."test_stage" URL = 's3://load/encrypted_files/' CREDENTIALS = (aws_role='arn:aws:iam::001234567890:role/mysnowflakerole') ENCRYPTION = (type='AWS_SSE_KMS' kms_key_id = 'aws/key') FILE_FORMAT = (format_name=my_csv_format) COPY_OPTIONS = (on_error='skip_file') DIRECTORY = (ENABLE=TRUE) COMMENT = 'Yee\'haw'`, s.Create())

s.WithStorageIntegration("MY_INTEGRATION")
r.Equal(`CREATE STAGE "test_db"."test_schema"."test_stage" URL = 's3://load/encrypted_files/' CREDENTIALS = (aws_role='arn:aws:iam::001234567890:role/mysnowflakerole') STORAGE_INTEGRATION = MY_INTEGRATION ENCRYPTION = (type='AWS_SSE_KMS' kms_key_id = 'aws/key') FILE_FORMAT = (format_name=my_csv_format) COPY_OPTIONS = (on_error='skip_file') COMMENT = 'Yee\'haw'`, s.Create())
r.Equal(`CREATE STAGE "test_db"."test_schema"."test_stage" URL = 's3://load/encrypted_files/' CREDENTIALS = (aws_role='arn:aws:iam::001234567890:role/mysnowflakerole') STORAGE_INTEGRATION = MY_INTEGRATION ENCRYPTION = (type='AWS_SSE_KMS' kms_key_id = 'aws/key') FILE_FORMAT = (format_name=my_csv_format) COPY_OPTIONS = (on_error='skip_file') DIRECTORY = (ENABLE=TRUE) COMMENT = 'Yee\'haw'`, s.Create())
}

func TestStageRename(t *testing.T) {
Expand Down