Skip to content

Commit

Permalink
adds sequence parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
jtzero committed Aug 26, 2021
1 parent 2255fde commit 1522559
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 16 deletions.
127 changes: 113 additions & 14 deletions pkg/resources/sequence.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
package resources

import (
"bytes"
"database/sql"
"encoding/csv"
"fmt"
"log"
"strconv"
"strings"

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

const (
sequenceIDDelimiter = '|'
)

var sequenceSchema = map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Expand Down Expand Up @@ -53,6 +60,27 @@ var sequenceSchema = map[string]*schema.Schema{

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

type sequenceID struct {
DatabaseName string
SchemaName string
SequenceName string
}

//String() takes in a sequenceID object and returns a pipe-delimited string:
//DatabaseName|SchemaName|SequenceName
func (si *sequenceID) String() (string, error) {
var buf bytes.Buffer
csvWriter := csv.NewWriter(&buf)
csvWriter.Comma = pipeIDDelimiter
dataIdentifiers := [][]string{{si.DatabaseName, si.SchemaName, si.SequenceName}}
err := csvWriter.WriteAll(dataIdentifiers)
if err != nil {
return "", err
}
strSequenceID := strings.TrimSpace(buf.String())
return strSequenceID, nil
}

// Sequence returns a pointer to the resource representing a sequence
func Sequence() *schema.Resource {
return &schema.Resource{
Expand Down Expand Up @@ -90,15 +118,32 @@ func CreateSequence(d *schema.ResourceData, meta interface{}) error {
return errors.Wrapf(err, "error creating sequence")
}

sequenceID := &sequenceID{
DatabaseName: database,
SchemaName: schema,
SequenceName: name,
}

dataIDInput, err := sequenceID.String()
if err != nil {
return err
}
d.SetId(dataIDInput)

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)
sequenceID, err := sequenceIDFromString(d.Id())
if err != nil {
return err
}

database := sequenceID.DatabaseName
schema := sequenceID.SchemaName
name := sequenceID.SequenceName

seq := snowflake.Sequence(name, database, schema)
stmt := seq.Show()
Expand All @@ -116,6 +161,11 @@ func ReadSequence(d *schema.ResourceData, meta interface{}) error {
return errors.Wrap(err, "unable to scan row for SHOW SEQUENCES")
}

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

err = d.Set("schema", sequence.SchemaName.String)
if err != nil {
return err
Expand Down Expand Up @@ -166,14 +216,21 @@ func ReadSequence(d *schema.ResourceData, meta interface{}) error {

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)
sequenceID, err := sequenceIDFromString(d.Id())
if err != nil {
return err
}

DeleteSequence(d, meta)
database := sequenceID.DatabaseName
schema := sequenceID.SchemaName
name := sequenceID.SequenceName

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

sequence, err := snowflake.ScanSequence(row)
DeleteSequence(d, meta)

if i, ok := d.GetOk("increment"); ok {
sq.WithIncrement(i.(int))
Expand All @@ -183,9 +240,19 @@ func UpdateSequence(d *schema.ResourceData, meta interface{}) error {
sq.WithComment(v.(string))
}

sq.WithStart(next)
nextValue, err := strconv.Atoi(sequence.NextValue.String)
if err != nil {
return err
}

err := snowflake.Exec(db, sq.Create())
err = d.Set("next_value", nextValue)
if err != nil {
return err
}

sq.WithStart(nextValue)

err = snowflake.Exec(db, sq.Create())
if err != nil {
return errors.Wrapf(err, "error creating sequence")
}
Expand All @@ -195,17 +262,49 @@ func UpdateSequence(d *schema.ResourceData, meta interface{}) error {

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)
sequenceID, err := sequenceIDFromString(d.Id())
if err != nil {
return err
}

database := sequenceID.DatabaseName
schema := sequenceID.SchemaName
name := sequenceID.SequenceName

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

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

d.SetId("")
return nil
}

// sequenceIDFromString() takes in a pipe-delimited string: DatabaseName|SchemaName|PipeName
// and returns a sequenceID object
func sequenceIDFromString(stringID string) (*sequenceID, error) {
reader := csv.NewReader(strings.NewReader(stringID))
reader.Comma = sequenceIDDelimiter
lines, err := reader.ReadAll()
if err != nil {
return nil, fmt.Errorf("Not CSV compatible")
}

if len(lines) != 1 {
return nil, fmt.Errorf("1 line per sequence")
}

if len(lines[0]) != 3 {
return nil, fmt.Errorf("3 fields allowed")
}

sequenceResult := &sequenceID{
DatabaseName: lines[0][0],
SchemaName: lines[0][1],
SequenceName: lines[0][2],
}

return sequenceResult, nil
}
4 changes: 2 additions & 2 deletions pkg/resources/sequence_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func TestSequenceRead(t *testing.T) {
"database": "database",
}

d := sequence(t, "good_name", in)
d := sequence(t, "database|schema|good_name", in)

WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) {
rows := sqlmock.NewRows([]string{
Expand Down Expand Up @@ -111,7 +111,7 @@ func TestSequenceDelete(t *testing.T) {
"database": "database",
}

d := sequence(t, "drop_it", in)
d := sequence(t, "database|schema|drop_it", in)

WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) {
mock.ExpectExec(`DROP SEQUENCE "database"."schema"."drop_it"`).WillReturnResult(sqlmock.NewResult(1, 1))
Expand Down

0 comments on commit 1522559

Please sign in to comment.