Giter VIP home page Giter VIP logo

dynago's Introduction

Dynago

codecov

The aim of this package is to make it easier to work with AWS DynamoDB.

Documentation

For full documentation see pkg.go.dev.

Usage

Basic

package main

import (
	"fmt"
	"os"
	"time"

	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/dynamodb"
	"github.com/twharmon/dynago"
)

type Schema struct {}

func (s *Schema) PrimaryKeys() []string {
	return []string{"PK", "SK"}
}

type Post struct {
	// Embed a struct that implements the dynago.Keyer interface.
	*Schema

	// Set attribute name with `attr` tag if it needs to be different
	// than field name. Use `fmt:"Post#{}"` to indicate how the value
	// will be stored in DynamoDB.
	ID string `attr:"PK" fmt:"Post#{}"`

	Created  time.Time `attr:"SK" fmt:"Created#{}"`
	AuthorID string
	Title    string
	Body     string
}

func main() {
	// Get client.
	ddb := dynago.New(getDynamoDB(), &dynago.Config{
		DefaultTableName: "tmp",
	})

	// Put item in DynamoDB.
	p := Post{
		ID:      "hello-world",
		Title:   "Hi",
		Body:    "Hello world!",
		Created: time.Now(),
	}
	if err := ddb.PutItem(&p).Exec(); err != nil {
		panic(err)
	}

	// Get same item from DynamoDB. Fields used in the primary key
	// must be set.
	p2 := Post{
		ID:      p.ID,
		Created: p.Created,
	}
	if err := ddb.GetItem(&p2).Exec(); err != nil {
		panic(err)
	}
	fmt.Println(p2)
}

func getDynamoDB() *dynamodb.DynamoDB {
	os.Setenv("AWS_SDK_LOAD_CONFIG", "true")
	sess, err := session.NewSession()
	if err != nil {
		panic(err)
	}
	return dynamodb.New(sess)
}

Additional Attributes

package main

import (
	"fmt"
	"os"
	"reflect"
	"time"

	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/dynamodb"
	"github.com/twharmon/dynago"
)

type Schema struct {}

func (s *Schema) PrimaryKeys() []string {
	return []string{"PK", "SK"}
}

type Post struct {
	// Embed a struct that implements the dynago.Keyer interface.
	*Schema

	ID       string `attr:"PK" fmt:"Post#{}"`
	AuthorID string
	Title    string
	Body     string
	Created  time.Time `attr:"SK" fmt:"Created#{}"`
}

type Author struct {
	ID   string `attr:"PK" fmt:"Author#{}"`

	// Copy same value to attribute AltName by using `copy:"AltName"` in tag.
	Name string `copy:"AltName"`
}

func main() {
	// Get client.
	ddb := dynago.New(getDynamoDB(), &dynago.Config{
		DefaultTableName: "tmp",
		AdditionalAttrs:  additionalAttrs,
	})

	// ...
}

func additionalAttrs(item map[string]*dynamodb.AttributeValue, v reflect.Value) {
	ty := v.Type().Name()

	// Add a "Type" attribute to every item
	item["Type"] = &dynamodb.AttributeValue{S: &ty}

	// Add additional attributes for specific types
	switch val := v.Interface().(type) {
	case Author:
		// Add a fat partition or sparse global secondary index to
		// make querying for all authors possible
		author := fmt.Sprintf("Author#%s", val.ID)
		item["GSIPK"] = &dynamodb.AttributeValue{S: &ty}
		item["GSISK"] = &dynamodb.AttributeValue{S: &author}
	}
}

Compound Field Attributes

type Event struct {
	Org string `attr:"PK" fmt:"Org#{}"`

	// In this `fmt` tag, {} is equivalent to {Country}. You can
	// reference a different field name by putting it's name in
	// curly brackets.
	Country string `attr:"SK" fmt:"Country#{}#City#{City}"`

	// Since the City is specified in the "SK" attribute, we can
	// skip putting it in another attribute if we want.
	City    string `attr:"-"`
	Created time.Time
}

Contribute

Make a pull request.

dynago's People

Contributors

twharmon avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

dynago's Issues

Support for returned outputs

This needs to be implemented for:

  • DeleteItem
  • PutItem
  • UpdateItem
  • TransactionWriteItems
  • etc.

It needs to be backwards compatible. Perhaps something like this:

p := Post{
	ID:      1,
	Created: time.Now(),
}
var output dynago.PutOutput // or dynamodb.PutItemOutput
if err := ddb.Put(&p).Output(&output).Exec(); err != nil {
	panic(err)
}

Support for Go maps

Currently, marshaling and unmarshaling Go maps is not supported.

time.Time values will be marshaled to string, but it's not possible to try to parse string back to time.Time values, since the layout can not be known.

This can either be solved by a Marshaler interface that the user must implement themselves, or by establishing rules / restrictions / conventions on how Go maps can be used.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.