Skip to content

Commit

Permalink
feat: Add a resource to manage sequences (#582)
Browse files Browse the repository at this point in the history
  • Loading branch information
Duncan Fedde authored Jun 23, 2021
1 parent 80b5cb9 commit 7fab82f
Show file tree
Hide file tree
Showing 10 changed files with 654 additions and 4 deletions.
51 changes: 51 additions & 0 deletions docs/resources/sequence.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "snowflake_sequence Resource - terraform-provider-snowflake"
subcategory: ""
description: |-
---

# snowflake_sequence (Resource)



## Example Usage

```terraform
resource "snowflake_database" "database" {
name = "things"
}
resource "snowflake_schema" "test_schema" {
name = "things"
database = snowflake_database.test_database.name
}
resource "snowflake_sequence" "test_sequence" {
database = snowflake_database.test_database.name
schema = snowflake_schema.test_schema.name
name = "thing_counter"
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- **database** (String) The database in which to create the sequence. Don't use the | character.
- **name** (String) Specifies the name for the sequence.
- **schema** (String) The schema in which to create the sequence. Don't use the | character.

### Optional

- **comment** (String) Specifies a comment for the sequence.
- **id** (String) The ID of this resource.
- **increment** (Number) The amount the sequence will increase by each time it is used

### Read-Only

- **next_value** (Number) The next value the sequence will provide.


14 changes: 14 additions & 0 deletions examples/resources/snowflake_sequence/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
resource "snowflake_database" "database" {
name = "things"
}

resource "snowflake_schema" "test_schema" {
name = "things"
database = snowflake_database.test_database.name
}

resource "snowflake_sequence" "test_sequence" {
database = snowflake_database.test_database.name
schema = snowflake_schema.test_schema.name
name = "thing_counter"
}
4 changes: 0 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1008,10 +1008,6 @@ golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/tools v0.1.1 h1:wGiQel/hW0NnEkJUk8lbzkX2gFJU6PFxf1v5OlCfuOs=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.2 h1:kRBLX7v7Af8W7Gdbbc908OJcdgtK8bOz9Uaj8/F1ACA=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.3 h1:L69ShwSZEyCsLKoAxDKeMvLDZkumEe8gXUZAjab0tX8=
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down
1 change: 1 addition & 0 deletions pkg/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ func getResources() map[string]*schema.Resource {
"snowflake_role_grants": resources.RoleGrants(),
"snowflake_schema": resources.Schema(),
"snowflake_scim_integration": resources.SCIMIntegration(),
"snowflake_sequence": resources.Sequence(),
"snowflake_share": resources.Share(),
"snowflake_stage": resources.Stage(),
"snowflake_storage_integration": resources.StorageIntegration(),
Expand Down
8 changes: 8 additions & 0 deletions pkg/resources/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,14 @@ func resourceMonitor(t *testing.T, id string, params map[string]interface{}) *sc
return d
}

func sequence(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData {
r := require.New(t)
d := schema.TestResourceDataRaw(t, resources.Sequence().Schema, params)
r.NotNil(d)
d.SetId(id)
return d
}

func share(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData {
r := require.New(t)
d := schema.TestResourceDataRaw(t, resources.Share().Schema, params)
Expand Down
200 changes: 200 additions & 0 deletions pkg/resources/sequence.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
package resources

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

"github.com/chanzuckerberg/terraform-provider-snowflake/pkg/snowflake"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/pkg/errors"
)

var sequenceSchema = map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
Description: "Specifies the name for the sequence.",
},
"comment": {
Type: schema.TypeString,
Optional: true,
Default: "",
Description: "Specifies a comment for the sequence.",
},
"increment": {
Type: schema.TypeInt,
Optional: true,
Default: 1,
Description: "The amount the sequence will increase by each time it is used",
},
"database": {
Type: schema.TypeString,
Required: true,
Description: "The database in which to create the sequence. Don't use the | character.",
},
"schema": {
Type: schema.TypeString,
Required: true,
Description: "The schema in which to create the sequence. Don't use the | character.",
},
"next_value": {
Type: schema.TypeInt,
Description: "The next value the sequence will provide.",
Computed: true,
},
}

var sequenceProperties = []string{"comment", "data_retention_time_in_days"}

// Sequence returns a pointer to the resource representing a sequence
func Sequence() *schema.Resource {
return &schema.Resource{
Create: CreateSequence,
Read: ReadSequence,
Delete: DeleteSequence,
Update: UpdateSequence,

Schema: sequenceSchema,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},
}
}

// CreateSequence implements schema.CreateFunc
func CreateSequence(d *schema.ResourceData, meta interface{}) error {
db := meta.(*sql.DB)
database := d.Get("database").(string)
schema := d.Get("schema").(string)
name := d.Get("name").(string)

sq := snowflake.Sequence(name, database, schema)

if i, ok := d.GetOk("increment"); ok {
sq.WithIncrement(i.(int))
}

if v, ok := d.GetOk("comment"); ok {
sq.WithComment(v.(string))
}

err := snowflake.Exec(db, sq.Create())
if err != nil {
return errors.Wrapf(err, "error creating sequence")
}

return ReadSequence(d, meta)
}

// ReadSequence implements schema.ReadFunc
func ReadSequence(d *schema.ResourceData, meta interface{}) error {
db := meta.(*sql.DB)
database := d.Get("database").(string)
schema := d.Get("schema").(string)
name := d.Get("name").(string)

stmt := snowflake.Sequence(name, database, schema).Show()
row := snowflake.QueryRow(db, stmt)

sequence, err := snowflake.ScanSequence(row)

if err != nil {
if err == sql.ErrNoRows {
// If not found, mark resource to be removed from statefile during apply or refresh
log.Printf("[DEBUG] sequence (%s) not found", d.Id())
d.SetId("")
return nil
}
return errors.Wrap(err, "unable to scan row for SHOW SEQUENCES")
}

err = d.Set("schema", sequence.SchemaName.String)
if err != nil {
return err
}

err = d.Set("database", sequence.DBName.String)
if err != nil {
return err
}

err = d.Set("comment", sequence.Comment.String)
if err != nil {
return err
}

i, err := strconv.ParseInt(sequence.Increment.String, 10, 64)
if err != nil {
return err
}

err = d.Set("increment", i)
if err != nil {
return err
}

i, err = strconv.ParseInt(sequence.NextValue.String, 10, 64)
if err != nil {
return err
}

err = d.Set("next_value", i)
if err != nil {
return err
}

d.SetId(fmt.Sprintf(`%v|%v|%v`, sequence.DBName.String, sequence.SchemaName.String, sequence.Name.String))
if err != nil {
return err
}

return err
}

func UpdateSequence(d *schema.ResourceData, meta interface{}) error {
db := meta.(*sql.DB)
database := d.Get("database").(string)
schema := d.Get("schema").(string)
name := d.Get("name").(string)
next := d.Get("next_value").(int)

DeleteSequence(d, meta)

sq := snowflake.Sequence(name, database, schema)

if i, ok := d.GetOk("increment"); ok {
sq.WithIncrement(i.(int))
}

if v, ok := d.GetOk("comment"); ok {
sq.WithComment(v.(string))
}

sq.WithStart(next)

err := snowflake.Exec(db, sq.Create())
if err != nil {
return errors.Wrapf(err, "error creating sequence")
}

return ReadSequence(d, meta)
}

func DeleteSequence(d *schema.ResourceData, meta interface{}) error {
db := meta.(*sql.DB)
database := d.Get("database").(string)
schema := d.Get("schema").(string)
name := d.Get("name").(string)

stmt := snowflake.Sequence(name, database, schema).Drop()

err := snowflake.Exec(db, stmt)
if err != nil {
return errors.Wrapf(err, "error dropping sequence %s", name)
}

d.SetId("")
return nil
}
Loading

0 comments on commit 7fab82f

Please sign in to comment.