Go driver for AWS DynamoDB which can be used with the standard database/sql package.
package main
import (
"database/sql"
"fmt"
_ "github.com/btnguyen2k/godynamo"
)
func main() {
driver := "godynamo"
dsn := "Region=<aws-region>;AkId=<access-key-id>;SecretKey=<secret-key>"
db, err := sql.Open(driver, dsn)
if err != nil {
panic(err)
}
defer db.Close()
// db instance is ready to use
dbRows, err := db.Query(`LIST TABLES`)
if err != nil {
panic(err)
}
for dbRows.Next() {
var val interface{}
err := dbRows.Scan(&val)
if err != nil {
panic(err)
}
fmt.Println(val)
}
}Note: line-break is for readability only!
Region=<aws-region>
;AkId=<aws-access-key-id>
;Secret_Key=<aws-secret-key>
[;Endpoint=<aws-dynamodb-endpoint>]
[TimeoutMs=<timeout-in-milliseconds>]
Region: AWS region, for exampleus-east-1. If not supplied, the value of the environmentAWS_REGIONis used.AkId: AWS Access Key ID, for exampleAKIA1234567890ABCDEF. If not supplied, the value of the environmentAWS_ACCESS_KEY_IDis used.Secret_Key: AWS Secret Key, for example0A1B2C3D4E5F. If not supplied, the value of the environmentAWS_SECRET_ACCESS_KEYis used.Endpoint: (optional) AWS DynamoDB endpoint, for examplehttp://localhost:8000; useful when AWS DynamoDB is running on local machine.TimeoutMs: (optional) timeout in milliseconds. If not specified, default value is10000.
Since v1.3.0, godynamo supports using aws.Config to create the connection to DynamoDB:
package main
import (
"database/sql"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/btnguyen2k/godynamo"
)
func main() {
driver := "godynamo"
awscfg := aws.Config{
Region: "<aws-region>",
Credentials: aws.StaticCredentialsProvider{
Value: aws.Credentials{
AccessKeyID: "<access-key-id>",
SecretAccessKey: "<secret-key>",
},
},
}
godynamo.RegisterAWSConfig(awscfg)
db, err := sql.Open(driver, "dummy")
if err != nil {
panic(err)
}
defer db.Close()
// db instance is ready to use
}-
CREATE TABLELIST TABLESDESCRIBE TABLEALTER TABLEDROP TABLE
-
DESCRIBE LSICREATE GSIDESCRIBE GSIALTER GSIDROP GSI
-
INSERTSELECTUPDATEDELETE
godynamo supports transactions that consist of write statements (e.g. INSERT, UPDATE and DELETE) since v0.2.0. Please note the following:
- Any limitation set by DynamoDB/PartiQL will apply.
- Table and Index statements are not supported.
UPDATE/DELETEwithRETURNINGandSELECTstatements are not supported.
Example:
tx, err := db.Begin()
if err != nil {
panic(err)
}
defer tx.Rollback()
result1, _ := tx.Exec(`INSERT INTO "tbltest" VALUE {'app': ?, 'user': ?, 'active': ?}`, "app0", "user1", true)
result2, _ := tx.Exec(`INSERT INTO "tbltest" VALUE {'app': ?, 'user': ?, 'duration': ?}`, "app0", "user2", 1.23)
err = tx.Commit()
if err != nil {
panic(err)
}
rowsAffected1, err1 := fmt.Println(result1.RowsAffected())
if err1 != nil {
panic(err1)
}
fmt.Println("RowsAffected:", rowsAffected1) // output "RowsAffected: 1"
rowsAffected2, err2 := fmt.Println(result2.RowsAffected())
if err2 != nil {
panic(err2)
}
fmt.Println("RowsAffected:", rowsAffected2) // output "RowsAffected: 1"If a statement's condition check fails (e.g. deleting non-existing item), the whole transaction will also fail. This behaviour is different from executing statements in non-transactional mode where failed condition check results in
0affected row without error.You can use EXISTS function for condition checking.
Notes on transactions:
- Results of
INSERT/UPDATE/DELETEstatements are not available until the transaction is committed. Which means, callingRowsAffected()beforeCommit()will return0, ErrInTx. - If the connection which has a non-commit/non-rollback transaction is used to execute another statement, the statement is
added to the transaction. If the transaction is being committed or rolled back, the execution of the statement will fail
with error
ErrInTx. For example:
conn, _ := db.Conn(context.Background())
tx, err := conn.BeginTx(context.Background(), nil)
if err != nil {
panic(err)
}
result1, _ := tx.Exec(`INSERT INTO "tbltest" VALUE {'app': ?, 'user': ?, 'active': ?}`, "app0", "user1", true)
// the statement is added to the existing transaction
// also, result2.RowsAffected() is not available until the transaction is committed
result2, _ := conn.ExecContext(context.Background(), `INSERT INTO "tbltest" VALUE {'app': ?, 'user': ?, 'duration': ?}`, "app0", "user2", 1.23)
err = tx.Commit()
if err != nil {
panic(err)
}
rowsAffected1, err1 := fmt.Println(result1.RowsAffected())
if err1 != nil {
panic(err1)
}
fmt.Println("RowsAffected:", rowsAffected1) // output "RowsAffected: 1"
rowsAffected2, err2 := fmt.Println(result2.RowsAffected())
if err2 != nil {
panic(err2)
}
fmt.Println("RowsAffected:", rowsAffected2) // output "RowsAffected: 1"Numerical values are stored in DynamoDB as floating point numbers. Hence, numbers are always read back as float64.
See DynamoDB document for details on DynamoDB's supported data types.
A single query can only return up to 1MB of data.
In the case of SELECT query, the driver automatically issues additional queries to fetch the remaining data if needed.
However, returned rows may not be in the expected order specified by ORDER BY clause.
That means, rows returned from the query SELECT * FROM table_name WHERE category='Laptop' ORDER BY id may not be in
the expected order if all matched rows do not fit in 1MB of data.
This project is licensed under the MIT License - see the LICENSE.md file for details.
Feel free to create pull requests or issues to report bugs or suggest new features. Please search the existing issues before filing new issues to avoid duplicates. For new issues, file your bug or feature request as a new issue.
If you find this project useful, please star it.