~mna/bungee

a16253860039b0256fe64baed28c69e4c7149ab1 — Martin Angers 1 year, 9 months ago 643d0f0
pkg/commands/generate: add table, tests
M pkg/collect/resources.go => pkg/collect/resources.go +0 -3
@@ 217,9 217,6 @@ func newSchedule(pkg *packages.Package, obj types.Object) (*Schedule, error) {
// +bungee name,view_type
//
// The name must exist as a DynamoDB table collected by bungee.
// Alternatively, a Terraform variable may be specified as table name
// so that this is added as a stream Lambda handler to a table managed
// outside of bungee.
type Stream struct {
	ID       string
	Name     string

M pkg/commands/generate/resources.go => pkg/commands/generate/resources.go +167 -0
@@ 272,3 272,170 @@ func (s *schedule) encode(w io.Writer, indent string) error {
	_, err := io.Copy(w, &buf)
	return err
}

type table struct {
	ID                   string
	Name                 string
	BillingMode          string
	HashKey              string
	RangeKey             string
	TTL                  *tableTTL
	Attributes           []*tableAttribute
	LocalSecondaryIndex  *tableLocalSecondaryIndex
	GlobalSecondaryIndex *tableGlobalSecondaryIndex
	StreamEnabled        bool
	StreamViewType       string
}

func (t *table) encode(w io.Writer, indent string) error {
	var buf bytes.Buffer

	fmt.Fprintf(&buf, "%sresource \"aws_dynamodb_table\" %q {\n", indent, t.ID)
	if t.Name != "" {
		fmt.Fprintf(&buf, "%s\tname = %q\n", indent, t.Name)
	}
	if t.BillingMode != "" {
		fmt.Fprintf(&buf, "%s\tbilling_mode = %q\n", indent, t.BillingMode)
	}
	if t.HashKey != "" {
		fmt.Fprintf(&buf, "%s\thash_key = %q\n", indent, t.HashKey)
	}
	if t.RangeKey != "" {
		fmt.Fprintf(&buf, "%s\trange_key = %q\n", indent, t.RangeKey)
	}
	if t.TTL != nil {
		if err := t.TTL.encode(&buf, indent+"\t"); err != nil {
			return err
		}
	}
	for _, attr := range t.Attributes {
		if err := attr.encode(&buf, indent+"\t"); err != nil {
			return err
		}
	}
	if t.LocalSecondaryIndex != nil {
		if err := t.LocalSecondaryIndex.encode(&buf, indent+"\t"); err != nil {
			return err
		}
	}
	if t.GlobalSecondaryIndex != nil {
		if err := t.GlobalSecondaryIndex.encode(&buf, indent+"\t"); err != nil {
			return err
		}
	}
	fmt.Fprintf(&buf, "%s\tstream_enabled = %t\n", indent, t.StreamEnabled)
	if t.StreamViewType != "" {
		fmt.Fprintf(&buf, "%s\tstream_view_type = %q\n", indent, t.StreamViewType)
	}
	fmt.Fprintf(&buf, "%s}\n", indent)

	_, err := io.Copy(w, &buf)
	return err
}

type tableAttribute struct {
	Name string
	Type string
}

func (t *tableAttribute) encode(w io.Writer, indent string) error {
	var buf bytes.Buffer

	fmt.Fprintf(&buf, "%sattribute {\n", indent)
	if t.Name != "" {
		fmt.Fprintf(&buf, "%s\tname = %q\n", indent, t.Name)
	}
	if t.Type != "" {
		fmt.Fprintf(&buf, "%s\ttype = %q\n", indent, t.Type)
	}
	fmt.Fprintf(&buf, "%s}\n", indent)

	_, err := io.Copy(w, &buf)
	return err
}

type tableTTL struct {
	Enabled       bool
	AttributeName string
}

func (t *tableTTL) encode(w io.Writer, indent string) error {
	var buf bytes.Buffer

	fmt.Fprintf(&buf, "%sttl {\n", indent)
	fmt.Fprintf(&buf, "%s\tenabled = %t\n", indent, t.Enabled)
	if t.AttributeName != "" {
		fmt.Fprintf(&buf, "%s\tattribute_name = %q\n", indent, t.AttributeName)
	}
	fmt.Fprintf(&buf, "%s}\n", indent)

	_, err := io.Copy(w, &buf)
	return err
}

type tableSecondaryIndex struct {
	Name             string
	HashKey          string
	RangeKey         string
	ProjectionType   string
	NonKeyAttributes []string
}

func (t *tableSecondaryIndex) encode(w io.Writer, indent string) error {
	var buf bytes.Buffer

	if t.Name != "" {
		fmt.Fprintf(&buf, "%s\tname = %q\n", indent, t.Name)
	}
	if t.HashKey != "" {
		fmt.Fprintf(&buf, "%s\thash_key = %q\n", indent, t.HashKey)
	}
	if t.RangeKey != "" {
		fmt.Fprintf(&buf, "%s\trange_key = %q\n", indent, t.RangeKey)
	}
	if t.ProjectionType != "" {
		fmt.Fprintf(&buf, "%s\tprojection_type = %q\n", indent, t.ProjectionType)
	}
	if len(t.NonKeyAttributes) > 0 {
		fmt.Fprintf(&buf, "%s\tnon_key_attributes = [", indent)
		for i, attr := range t.NonKeyAttributes {
			if i > 0 {
				fmt.Fprint(&buf, ",")
			}
			fmt.Fprintf(&buf, "%q", attr)
		}
		fmt.Fprint(&buf, "]\n")
	}
	_, err := io.Copy(w, &buf)
	return err
}

type tableLocalSecondaryIndex struct {
	tableSecondaryIndex
}

func (t *tableLocalSecondaryIndex) encode(w io.Writer, indent string) error {
	var buf bytes.Buffer

	fmt.Fprintf(&buf, "%slocal_secondary_index {\n", indent)
	t.tableSecondaryIndex.encode(&buf, indent)
	fmt.Fprintf(&buf, "%s}\n", indent)

	_, err := io.Copy(w, &buf)
	return err
}

type tableGlobalSecondaryIndex struct {
	tableSecondaryIndex
}

func (t *tableGlobalSecondaryIndex) encode(w io.Writer, indent string) error {
	var buf bytes.Buffer

	fmt.Fprintf(&buf, "%sglobal_secondary_index {\n", indent)
	t.tableSecondaryIndex.encode(&buf, indent)
	fmt.Fprintf(&buf, "%s}\n", indent)

	_, err := io.Copy(w, &buf)
	return err
}

M pkg/commands/generate/resources_test.go => pkg/commands/generate/resources_test.go +15 -0
@@ 74,6 74,21 @@ func TestSchedule(t *testing.T) {
	}
}

func TestTable(t *testing.T) {
	cases := []*table{
		{ID: "t1", Name: "t1"},
		{ID: "t2", Name: "t2", BillingMode: "PAY_PER_REQUEST", HashKey: "K", RangeKey: "R", Attributes: []*tableAttribute{{Name: "K", Type: "S"}, {Name: "R", Type: "N"}}},
		{ID: "t3", Name: "t3", BillingMode: "PAY_PER_REQUEST", HashKey: "K", RangeKey: "R", Attributes: []*tableAttribute{{Name: "K", Type: "S"}, {Name: "R", Type: "N"}}, StreamEnabled: true, StreamViewType: "KEYS_ONLY"},
		{ID: "t4", Name: "t4", BillingMode: "PAY_PER_REQUEST", HashKey: "K", RangeKey: "R", Attributes: []*tableAttribute{{Name: "K", Type: "S"}, {Name: "R", Type: "N"}}, LocalSecondaryIndex: &tableLocalSecondaryIndex{tableSecondaryIndex{Name: "l1", RangeKey: "L", ProjectionType: "KEYS_ONLY"}}},
		{ID: "t5", Name: "t5", BillingMode: "PAY_PER_REQUEST", HashKey: "K", RangeKey: "R", Attributes: []*tableAttribute{{Name: "K", Type: "S"}, {Name: "R", Type: "N"}}, GlobalSecondaryIndex: &tableGlobalSecondaryIndex{tableSecondaryIndex{Name: "g1", HashKey: "GG", RangeKey: "G", ProjectionType: "INCLUDE", NonKeyAttributes: []string{"X", "Y", "Z"}}}},
		{ID: "t6", Name: "t6", BillingMode: "PAY_PER_REQUEST", HashKey: "K", RangeKey: "R", Attributes: []*tableAttribute{{Name: "K", Type: "S"}, {Name: "R", Type: "N"}}, TTL: &tableTTL{Enabled: true, AttributeName: "T"}},
	}

	for _, c := range cases {
		t.Run(c.ID, testResource("table", c.ID, c))
	}
}

func testResource(resource, id string, enc encoder) func(*testing.T) {
	return func(t *testing.T) {
		var buf bytes.Buffer

A pkg/commands/generate/testdata/table/t1.tf => pkg/commands/generate/testdata/table/t1.tf +4 -0
@@ 0,0 1,4 @@
resource "aws_dynamodb_table" "t1" {
	name = "t1"
	stream_enabled = false
}

A pkg/commands/generate/testdata/table/t2.tf => pkg/commands/generate/testdata/table/t2.tf +15 -0
@@ 0,0 1,15 @@
resource "aws_dynamodb_table" "t2" {
	name = "t2"
	billing_mode = "PAY_PER_REQUEST"
	hash_key = "K"
	range_key = "R"
	attribute {
		name = "K"
		type = "S"
	}
	attribute {
		name = "R"
		type = "N"
	}
	stream_enabled = false
}

A pkg/commands/generate/testdata/table/t3.tf => pkg/commands/generate/testdata/table/t3.tf +16 -0
@@ 0,0 1,16 @@
resource "aws_dynamodb_table" "t3" {
	name = "t3"
	billing_mode = "PAY_PER_REQUEST"
	hash_key = "K"
	range_key = "R"
	attribute {
		name = "K"
		type = "S"
	}
	attribute {
		name = "R"
		type = "N"
	}
	stream_enabled = true
	stream_view_type = "KEYS_ONLY"
}

A pkg/commands/generate/testdata/table/t4.tf => pkg/commands/generate/testdata/table/t4.tf +20 -0
@@ 0,0 1,20 @@
resource "aws_dynamodb_table" "t4" {
	name = "t4"
	billing_mode = "PAY_PER_REQUEST"
	hash_key = "K"
	range_key = "R"
	attribute {
		name = "K"
		type = "S"
	}
	attribute {
		name = "R"
		type = "N"
	}
	local_secondary_index {
		name = "l1"
		range_key = "L"
		projection_type = "KEYS_ONLY"
	}
	stream_enabled = false
}

A pkg/commands/generate/testdata/table/t5.tf => pkg/commands/generate/testdata/table/t5.tf +22 -0
@@ 0,0 1,22 @@
resource "aws_dynamodb_table" "t5" {
	name = "t5"
	billing_mode = "PAY_PER_REQUEST"
	hash_key = "K"
	range_key = "R"
	attribute {
		name = "K"
		type = "S"
	}
	attribute {
		name = "R"
		type = "N"
	}
	global_secondary_index {
		name = "g1"
		hash_key = "GG"
		range_key = "G"
		projection_type = "INCLUDE"
		non_key_attributes = ["X","Y","Z"]
	}
	stream_enabled = false
}

A pkg/commands/generate/testdata/table/t6.tf => pkg/commands/generate/testdata/table/t6.tf +19 -0
@@ 0,0 1,19 @@
resource "aws_dynamodb_table" "t6" {
	name = "t6"
	billing_mode = "PAY_PER_REQUEST"
	hash_key = "K"
	range_key = "R"
	ttl {
		enabled = true
		attribute_name = "T"
	}
	attribute {
		name = "K"
		type = "S"
	}
	attribute {
		name = "R"
		type = "N"
	}
	stream_enabled = false
}