dynmgrm

package module
v0.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 16, 2024 License: MIT Imports: 19 Imported by: 0

README

dynmgrm - GORM DynamoDB Driver

logo

Go Reference GitHub go.mod Go version (subdirectory of monorepo) GitHub release (latest by date) codecov Go Report Card GitHub License

Features

Supports the following PartiQL operations:

  • Select
    • With Secondary Index
    • With begins_with function
    • With contains function
    • With size function
    • With attribute_type function
    • With MISSING operator
  • Insert
  • Update
    • With SET clause
      • With list_append function
        • ListAppend()
      • With set_add function
      • With set_delete function
    • With REMOVE clause
  • Delete
  • Create (Table | Index)

Supports the following GORM features:

Query
  • Select
  • Find
  • Scan
Update
  • Update
  • Updates
  • Save
Create
  • Create
Delete
  • Delete
Condition
  • Where
  • Not
  • Or
Table/Model
  • Table
  • Model ※ Combination with Secondary Index are not supported.
Transaction
  • Begin
  • Commit
  • Rollback
  • Transaction

※ Supports only Insert, Update, and Delete.

Migration
  • AutoMigrate
  • CurrentDatabase
  • FullDataTypeOf
  • CreateTable
  • DropTable
  • HasTable
  • RenameTable
  • GetTables
  • AddColumn
  • DropColumn
  • AlterColumn
  • MigrateColumn
  • HasColumn
  • RenameColumn
  • ColumnTypes
  • CreateView
  • DropView
  • CreateConstraint
  • DropConstraint
  • HasConstraint
  • CreateIndex
  • DropIndex
  • HasIndex
  • RenameIndex

Custom Clause:

  • SecondaryIndex

Custom Data Types:

  • Set[string | int | float64 | []byte]

  • List

  • Map

  • TypedList[T]

Quick Start

Installation
go get github.com/miyamo2/dynmgrm
Usage
package main

import (
	"github.com/miyamo2/dynmgrm"
	"gorm.io/gorm"
)

type Event struct {
	Name  string `gorm:"primaryKey"`
	Date  string `gorm:"primaryKey"`
	Host  string
	Guest dynmgrm.Set[string]
}

func main() {
	db, err := gorm.Open(dynmgrm.New())
	if err != nil {
		panic(err)
	}

	var dynamoDBWorkshop Event
	db.Table("events").Where(`name=? AND date=?`, "DynamoDB Workshop", "2024/3/25").Scan(&dynamoDBWorkshop)

	dynamoDBWorkshop.Guest = append(dynamoDBWorkshop.Guest, "Alice")
	db.Save(&dynamoDBWorkshop)

	carolBirthday := Event{
		Name:  "Carol's Birthday",
		Date:  "2024/4/1",
		Host:  "Charlie",
		Guest: []string{"Alice", "Bob"},
	}
	db.Create(carolBirthday)

	var daveSchedule []Event
	db.Table("events").
		Where(`date=? AND ( host=? OR CONTAINS("guest", ?) )`, "2024/4/1", "Dave", "Dave").
		Scan(&daveSchedule)

	tx := db.Begin()
	for _, event := range daveSchedule {
		if event.Host == "Dave" {
			tx.Delete(&event)
		} else {
			tx.Model(&event).Update("guest", gorm.Expr("set_delete(guest, ?)", dynmgrm.Set[string]{"Dave"}))
		}
	}
	tx.Model(&carolBirthday).Update("guest", gorm.Expr("set_add(guest, ?)", dynmgrm.Set[string]{"Dave"}))
	tx.Commit()

	var hostDateIndex []Event
	db.Table("events").Clauses(
		dynmgrm.SecondaryIndex("host-date-index"),
	).Where(`host=?`, "Bob").Scan(&hostDateIndex)
}

Contributing

Feel free to open a PR or an Issue.

License

dynmgrm released under the MIT License

Credits

Go gopher

The Go gopher was designed by Renee French. The design is licensed under the Creative Commons 3.0 Attributions license. Read this article for more details

Special Thanks
  • JetBrainsMono

    JetBrainsMono is used for the caption of the dynmgrm logo.

Documentation

Overview

Example
package main

import (
	"github.com/miyamo2/dynmgrm"
	"gorm.io/gorm"
)

type Event struct {
	Name  string `gorm:"primaryKey"`
	Date  string `gorm:"primaryKey"`
	Host  string
	Guest dynmgrm.Set[string]
}

func main() {
	db, err := gorm.Open(dynmgrm.New())
	if err != nil {
		panic(err)
	}

	var dynamoDBWorkshop Event
	db.Table("events").Where(`name=? AND date=?`, "DynamoDB Workshop", "2024/3/25").Scan(&dynamoDBWorkshop)

	dynamoDBWorkshop.Guest = append(dynamoDBWorkshop.Guest, "Alice")
	db.Save(&dynamoDBWorkshop)

	carolBirthday := Event{
		Name:  "Carol's Birthday",
		Date:  "2024/4/1",
		Host:  "Charlie",
		Guest: []string{"Alice", "Bob"},
	}
	db.Create(carolBirthday)

	var daveSchedule []Event
	db.Table("events").
		Where(`date=? AND ( host=? OR CONTAINS("guest", ?) )`, "2024/4/1", "Dave", "Dave").
		Scan(&daveSchedule)

	tx := db.Begin()
	for _, event := range daveSchedule {
		if event.Host == "Dave" {
			tx.Delete(&event)
		} else {
			tx.Model(&event).Update("guest", gorm.Expr("set_delete(guest, ?)", dynmgrm.Set[string]{"Dave"}))
		}
	}
	tx.Model(&carolBirthday).Update("guest", gorm.Expr("set_add(guest, ?)", dynmgrm.Set[string]{"Dave"}))
	tx.Commit()

	var hostDateIndex []Event
	db.Table("events").Clauses(
		dynmgrm.SecondaryIndex("host-date-index"),
	).Where(`host=?`, "Bob").Scan(&hostDateIndex)
}
Output:

Index

Examples

Constants

View Source
const (
	// DriverName is the driver name for DynamoDB.
	DriverName = "godynamo"
	DBName     = "dynamodb"
)

Variables

View Source
var (
	ErrCollectionAlreadyContainsItem = errors.New("collection already contains item")
	ErrFailedToCast                  = errors.New("failed to cast")
	ErrDynmgrmAreNotSupported        = errors.New("dynmgrm are not supported this operation")
)
View Source
var (
	ErrValueIsIncompatibleOfStringSlice  = errors.New("value is incompatible of string slice")
	ErrValueIsIncompatibleOfIntSlice     = errors.New("value is incompatible of int slice")
	ErrValueIsIncompatibleOfFloat64Slice = errors.New("value is incompatible of float64 slice")
	ErrValueIsIncompatibleOfBinarySlice  = errors.New("value is incompatible of []byte slice")
)
View Source
var (
	ErrInvalidColumnName = errors.New("column name contains invalid characters")
)

Functions

func ListAppend added in v0.5.0

func ListAppend(item ...interface{}) *listAppend

ListAppend returns a functionForPartiQLUpdates implementation for `list_append` function.

Example
db, err := gorm.Open(
	dynmgrm.New(),
	&gorm.Config{
		SkipDefaultTransaction: true,
	})
if err != nil {
	log.Fatalf("failed to open database, got error %v", err)
}
db.Model(&TestTable{PK: "Partition1", SK: 1}).
	Update("list_type_attr",
		dynmgrm.ListAppend(dynmgrm.Map{"Foo": "Bar"}))
Output:

func New

func New(option ...DialectorOption) gorm.Dialector

New returns a new DynamoDB dialector with options.

Example
package main

import (
	"github.com/miyamo2/dynmgrm"
	"gorm.io/gorm"
)

func main() {
	gorm.Open(dynmgrm.New())
}
Output:

Example (WithAccessKeyID)
package main

import (
	"github.com/miyamo2/dynmgrm"
	"gorm.io/gorm"
)

func main() {
	gorm.Open(dynmgrm.New(dynmgrm.WithAccessKeyID("YourAccess")))
}
Output:

Example (WithEndpoint)
package main

import (
	"github.com/miyamo2/dynmgrm"
	"gorm.io/gorm"
)

func main() {
	gorm.Open(dynmgrm.New(dynmgrm.WithEndpoint("http://localhost:8000")))
}
Output:

Example (WithRegion)
package main

import (
	"github.com/miyamo2/dynmgrm"
	"gorm.io/gorm"
)

func main() {
	gorm.Open(dynmgrm.New(dynmgrm.WithRegion("ap-northeast-1")))
}
Output:

Example (WithSecretKey)
package main

import (
	"github.com/miyamo2/dynmgrm"
	"gorm.io/gorm"
)

func main() {
	gorm.Open(dynmgrm.New(dynmgrm.WithSecretKey("YourSecretKey")))
}
Output:

Example (WithTimeout)
package main

import (
	"github.com/miyamo2/dynmgrm"
	"gorm.io/gorm"
)

func main() {
	gorm.Open(dynmgrm.New(dynmgrm.WithTimeout(30000)))
}
Output:

func Open

func Open(dsn string) gorm.Dialector

Open returns a new DynamoDB dialector based on the DSN.

e.g. "region=ap-northeast-1;AkId=<YOUR_ACCESS_KEY_ID>;SecretKey=<YOUR_SECRET_KEY>"

Example
package main

import (
	"github.com/miyamo2/dynmgrm"
	"gorm.io/gorm"
)

func main() {
	gorm.Open(dynmgrm.Open("region=ap-northeast-1;AkId=YourAccessKeyID;SecretKey=YourSecretKey"))
}
Output:

func SecondaryIndex

func SecondaryIndex(indexName string, options ...SecondaryIndexOption) secondaryIndexExpression

SecondaryIndex enables queries using a secondary index

Example
package main

import (
	"github.com/miyamo2/dynmgrm"
	"gorm.io/gorm"
)

type TestTable struct {
	PK     string `gorm:"primaryKey"`
	SK     int    `gorm:"primaryKey"`
	GSIKey string
}

func main() {
	db, err := gorm.Open(dynmgrm.New(), &gorm.Config{})
	if err != nil {
		panic("failed to connect database")
	}

	result := TestTable{}
	db.Table("something").Clauses(
		dynmgrm.SecondaryIndex("gsi_key-sk-index")).
		Where(`gsi_key = ?`, "1").
		Scan(&result)
}
Output:

Example (WithSecondaryIndexOf_withString)
package main

import (
	"github.com/miyamo2/dynmgrm"
	"gorm.io/gorm"
)

type TestTable struct {
	PK     string `gorm:"primaryKey"`
	SK     int    `gorm:"primaryKey"`
	GSIKey string
}

func main() {
	db, err := gorm.Open(dynmgrm.New(), &gorm.Config{})
	if err != nil {
		panic("failed to connect database")
	}

	result := TestTable{}
	db.Clauses(
		dynmgrm.SecondaryIndex("gsi_key-sk-index",
			dynmgrm.SecondaryIndexOf("something"))).
		Where(`gsi_key = ?`, "1").
		Scan(&result)
}
Output:

Example (WithSecondaryIndexOf_withTableClause)
package main

import (
	"github.com/miyamo2/dynmgrm"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
)

type TestTable struct {
	PK     string `gorm:"primaryKey"`
	SK     int    `gorm:"primaryKey"`
	GSIKey string
}

func main() {
	db, err := gorm.Open(dynmgrm.New(), &gorm.Config{})
	if err != nil {
		panic("failed to connect database")
	}

	result := TestTable{}
	db.Clauses(
		dynmgrm.SecondaryIndex("gsi_key-sk-index",
			dynmgrm.SecondaryIndexOf(
				clause.Table{
					Name: "something",
				}))).
		Where(`gsi_key = ?`, "1").
		Scan(&result)
}
Output:

func WithAccessKeyID

func WithAccessKeyID(accessKeyId string) func(*config)

WithAccessKeyID sets the access key ID for the DynamoDB connection.

Default: https://github.com/btnguyen2k/godynamo?tab=readme-ov-file#data-source-name-dsn-format-for-aws-dynamodb

Example
package main

import (
	"github.com/miyamo2/dynmgrm"
)

func main() {
	dynmgrm.WithAccessKeyID("YourAccess")
}
Output:

func WithConnection

func WithConnection(conn gorm.ConnPool) func(*config)

WithConnection sets the exist connection for the DynamoDB.

func WithEndpoint

func WithEndpoint(endpoint string) func(*config)

WithEndpoint sets the endpoint for the DynamoDB connection.

Example
package main

import (
	"github.com/miyamo2/dynmgrm"
)

func main() {
	dynmgrm.WithEndpoint("http://localhost:8000")
}
Output:

func WithRegion

func WithRegion(region string) func(*config)

WithRegion sets the region for the DynamoDB connection.

Default: https://github.com/btnguyen2k/godynamo?tab=readme-ov-file#data-source-name-dsn-format-for-aws-dynamodb

Example
package main

import (
	"github.com/miyamo2/dynmgrm"
)

func main() {
	dynmgrm.WithRegion("ap-northeast-1")
}
Output:

func WithSecretKey

func WithSecretKey(secretKey string) func(*config)

WithSecretKey sets the secret key for the DynamoDB connection.

Default: https://github.com/btnguyen2k/godynamo?tab=readme-ov-file#data-source-name-dsn-format-for-aws-dynamodb

Example
package main

import (
	"github.com/miyamo2/dynmgrm"
)

func main() {
	dynmgrm.WithSecretKey("YourSecretKey")
}
Output:

func WithTimeout

func WithTimeout(timeout int) func(*config)

WithTimeout sets the timeout milliseconds for the DynamoDB connection.

Default: https://github.com/btnguyen2k/godynamo?tab=readme-ov-file#data-source-name-dsn-format-for-aws-dynamodb

Example
package main

import (
	"github.com/miyamo2/dynmgrm"
)

func main() {
	dynmgrm.WithTimeout(30000)
}
Output:

Types

type CallbacksRegisterer

type CallbacksRegisterer interface {
	Register(db *gorm.DB, config *callbacks.Config)
}

type DBOpener

type DBOpener interface {
	DSN() string
	DriverName() string
	Apply() (*sql.DB, error)
}

DBOpener is the interface for opening a database.

type Dialector

type Dialector struct {
	// contains filtered or unexported fields
}

Dialector gorm dialector for DynamoDB

func (Dialector) BindVarTo

func (dialector Dialector) BindVarTo(writer clause.Writer, stmt *gorm.Statement, v interface{})

BindVarTo writes the bind variable of goodynamo to clauses.Writer.

func (Dialector) DataTypeOf

func (dialector Dialector) DataTypeOf(field *schema.Field) string

DataTypeOf maps GORM's data types to DynamoDB's data types. DataTypeOf works only with migration, so it will not return data types that are not allowed in PK, SK.

func (Dialector) DefaultValueOf

func (dialector Dialector) DefaultValueOf(field *schema.Field) clause.Expression

DefaultValueOf returns the default value of the field.

func (Dialector) Explain

func (dialector Dialector) Explain(sql string, vars ...interface{}) string

Explain returns the SQL string with the variables replaced. Explain is typically used only for logging, dry runs, and migration.

func (Dialector) Initialize

func (dialector Dialector) Initialize(db *gorm.DB) (err error)

Initialize initializes the DynamoDB connection.

func (Dialector) Migrator deprecated

func (dialector Dialector) Migrator(db *gorm.DB) gorm.Migrator

Migrator returns the migrator for DynamoDB.

Deprecated: Migration feature is not implemented.

func (Dialector) Name

func (dialector Dialector) Name() string

Name returns the name of the db.

func (Dialector) QuoteTo

func (dialector Dialector) QuoteTo(writer clause.Writer, str string)

QuoteTo escapes identifiers in SQL queries

func (Dialector) Translate

func (dialector Dialector) Translate(err error) error

Translate it will translate the error to native gorm errors.

type DialectorOption

type DialectorOption func(*config)

DialectorOption is the option for the DynamoDB dialector.

type KeySchemaDataType added in v0.3.0

type KeySchemaDataType string

KeySchemaDataType is the data type for the DynamoDB key schema.

const (
	// KeySchemaDataTypeString is the data type for string.
	KeySchemaDataTypeString KeySchemaDataType = "string"
	// KeySchemaDataTypeNumber is the data type for number.
	KeySchemaDataTypeNumber KeySchemaDataType = "number"
	// KeySchemaDataTypeBinary is the data type for binary.
	KeySchemaDataTypeBinary KeySchemaDataType = "binary"
)

Define KeySchemaDataType

func (KeySchemaDataType) String added in v0.3.0

func (d KeySchemaDataType) String() string

String returns the string representation of the KeySchemaDataType.

type List

type List []interface{}

List is a DynamoDB list type.

See: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html

func (*List) GormDataType

func (l *List) GormDataType() string

GormDataType returns the data type for Gorm.

func (List) GormValue

func (l List) GormValue(_ context.Context, db *gorm.DB) clause.Expr

GormValue implements the gorm.Valuer interface.

func (*List) Scan

func (l *List) Scan(value interface{}) error

Scan implements the sql.Scanner#Scan

type Map

type Map map[string]interface{}

Map is a DynamoDB map type.

See: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html

func (Map) GormDataType

func (m Map) GormDataType() string

GormDataType returns the data type for Gorm.

func (Map) GormValue

func (m Map) GormValue(_ context.Context, db *gorm.DB) clause.Expr

GormValue implements the gorm.Valuer interface.

func (*Map) Scan

func (m *Map) Scan(value interface{}) error

Scan implements the sql.Scanner#Scan

type Migrator deprecated

type Migrator struct{}

Migrator is gorm.Migrator implementation for dynamodb

Deprecated: Migrator is not implemented.

func (Migrator) AddColumn

func (m Migrator) AddColumn(dst interface{}, field string) error

func (Migrator) AlterColumn

func (m Migrator) AlterColumn(dst interface{}, field string) error

func (Migrator) AutoMigrate

func (m Migrator) AutoMigrate(dst ...interface{}) error

func (Migrator) ColumnTypes

func (m Migrator) ColumnTypes(dst interface{}) ([]gorm.ColumnType, error)

func (Migrator) CreateConstraint

func (m Migrator) CreateConstraint(dst interface{}, name string) error

func (Migrator) CreateIndex

func (m Migrator) CreateIndex(dst interface{}, name string) error

func (Migrator) CreateTable

func (m Migrator) CreateTable(dst ...interface{}) error

func (Migrator) CreateView

func (m Migrator) CreateView(name string, option gorm.ViewOption) error

func (Migrator) CurrentDatabase

func (m Migrator) CurrentDatabase() string

func (Migrator) DropColumn

func (m Migrator) DropColumn(dst interface{}, field string) error

func (Migrator) DropConstraint

func (m Migrator) DropConstraint(dst interface{}, name string) error

func (Migrator) DropIndex

func (m Migrator) DropIndex(dst interface{}, name string) error

func (Migrator) DropTable

func (m Migrator) DropTable(dst ...interface{}) error

func (Migrator) DropView

func (m Migrator) DropView(name string) error

func (Migrator) FullDataTypeOf

func (m Migrator) FullDataTypeOf(field *schema.Field) clause.Expr

func (Migrator) GetIndexes

func (m Migrator) GetIndexes(dst interface{}) ([]gorm.Index, error)

func (Migrator) GetTables

func (m Migrator) GetTables() (tableList []string, err error)

func (Migrator) GetTypeAliases

func (m Migrator) GetTypeAliases(databaseTypeName string) []string

func (Migrator) HasColumn

func (m Migrator) HasColumn(dst interface{}, field string) bool

func (Migrator) HasConstraint

func (m Migrator) HasConstraint(dst interface{}, name string) bool

func (Migrator) HasIndex

func (m Migrator) HasIndex(dst interface{}, name string) bool

func (Migrator) HasTable

func (m Migrator) HasTable(dst interface{}) bool

func (Migrator) MigrateColumn

func (m Migrator) MigrateColumn(dst interface{}, field *schema.Field, columnType gorm.ColumnType) error

func (Migrator) MigrateColumnUnique

func (m Migrator) MigrateColumnUnique(dst interface{}, field *schema.Field, columnType gorm.ColumnType) error

func (Migrator) RenameColumn

func (m Migrator) RenameColumn(dst interface{}, oldName, field string) error

func (Migrator) RenameIndex

func (m Migrator) RenameIndex(dst interface{}, oldName, newName string) error

func (Migrator) RenameTable

func (m Migrator) RenameTable(oldName, newName interface{}) error

func (Migrator) TableType

func (m Migrator) TableType(dst interface{}) (gorm.TableType, error)

type SecondaryIndexOption

type SecondaryIndexOption func(*secondaryIndexExpression)

SecondaryIndexOption is a functional option for secondaryIndexExpression

func SecondaryIndexOf

func SecondaryIndexOf[T string | clause.Table](table T) SecondaryIndexOption

SecondaryIndexOf is the table with the index to be used.

type Set

type Set[T SetSupportable] []T

Set is a DynamoDB set type.

See: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html

func (*Set[T]) GormDataType

func (s *Set[T]) GormDataType() string

GormDataType returns the data type for Gorm.

func (Set[T]) GormValue

func (s Set[T]) GormValue(_ context.Context, db *gorm.DB) clause.Expr

GormValue implements the gorm.Valuer interface.

func (*Set[T]) Scan

func (s *Set[T]) Scan(value interface{}) error

Scan implements the sql.Scanner#Scan

type SetSupportable

type SetSupportable interface {
	string | []byte | int | float64
}

SetSupportable are the types that support the Set

type TypedList added in v0.4.0

type TypedList[T any] []T

TypedList is a DynamoDB list type with type specification.

See: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html

func (*TypedList[T]) GormDataType added in v0.4.0

func (l *TypedList[T]) GormDataType() string

GormDataType returns the data type for Gorm.

func (TypedList[T]) GormValue added in v0.4.0

func (l TypedList[T]) GormValue(_ context.Context, db *gorm.DB) clause.Expr

GormValue implements the gorm.Valuer interface.

func (*TypedList[T]) Scan added in v0.4.0

func (l *TypedList[T]) Scan(value interface{}) error

Scan implements the sql.Scanner#Scan

Directories

Path Synopsis
internal
mocks
Package mocks is a generated GoMock package.
Package mocks is a generated GoMock package.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL