Skip to content

pquerna/protoc-gen-dynamo

Repository files navigation

protoc-gen-dynamo: Storing protobuf objects in Amazon DynamoDB

protoc-gen-dynamo is used to generate Go ('golang') code for storing objects inside Amazon DynamoDB. It works by generating code for MarshalDyanmo* and UnmarshalDynamo* functions based on a Protocol Buffer message. These functions are interfaces in the AWS SDK for Go for serializing between Go and Amazon DynamoDB.

Contributions Welcome!

Please open issues in Github for pull requests, ideas, bugs, and general thoughts. Today the project today is focused on Go, but other languages are welcome!

Features

  • Performance: TODO: benchmarks
  • Compatible with AWS SDK for Go. Code is generated to implement MarshalDynamoDBAttributeValue(*dynamodb.AttributeValue) error and UnmarshalDynamoDBAttributeValue(*dynamodb.AttributeValue) error.
  • Compatible with guregu/dynamo, an expressive DynamoDB library for Go. Code is generated to implement MarshalDynamo() (*dynamodb.AttributeValue, error) and UnmarshalDynamo(*dynamodb.AttributeValue) error.

Installing protoc-gen-dynamo

go install -mod=vendor github.com/pquerna/protoc-gen-dynamo

Using protoc-gen-dynamo

  • Include dynamo.proto in your protobuf compiler include path.

Annotations

See the dynamo.proto for all possible annotations.

dynamo Annotations on Protobuf Messages

  • dynamo.disabled = <bool>: Disables generation of DynamoDB Marshalling for this message.

dynamo Annotations on Protobuf Fields

  • dynamo.skip = <bool>: Skips serializing and de-serializing this field.
  • dynamo.name = <string>: Sets the name of the field as stored in DynamoDB
  • dynamo.type.binary = <bool>: The field uses the protobuf native binary format, and is encoded into DynamoDB's Binary type as a base64 string. The binary annotation can be used on any field.
  • dynamo.type.set = <bool>: Set this field to be a String Set, Number Set, or Binary Set instead of a List. Only valid on repeated protobuf fields.
  • dynamo.type.unix_second = <bool>: Set this field to be a Number with the number of seconds since the unix epoch. Only valid for google.protobuf.Timestamp protobuf type.
  • dynamo.type.unix_milli = <bool>: Set this field to be a Number with the number of milliseconds (MS) since the unix epoch. Only valid for google.protobuf.Timestamp protobo type.
  • dynamo.type.unix_nano = <bool>: Set this field to be a Number with the number of nanoseconds (NS) since the unix epoch. Only valid for google.protobuf.Timestamp protobuf type.

Mapping Protocol Buffer types to DynamoDB Types

Amazon DynamoDB supports many types natively,

Amazon DynamoDB

.proto Type DynamoDB Type
double N – Number
float N – Number
int32 N – Number
int64 N – Number
uint32 N – Number
uint64 N – Number
sint32 N – Number
sint64 N – Number
fixed32 N – Number
fixed64 N – Number
sfixed32 N – Number
sfixed64 N – Number
bool BOOL – Boolean
string S – String
bytes B – Binary
map<K,V> M – Map 1
repeated V L – List 2
message M – Map 3
Timestamp S - String 4
Duration S - String 5

1: Maps: Keys must be a string or Numeric type. Value can be any type.

2: Lists: By default lists are mapped directly. The dynamo.type.set = true annotation can be used to convert the List into a String Set, Binary Set, or Number Set.

3: Nested Messages: By default nested messages are recursively turned into a Map. The dynamo.type.binary = true annotation can be used to serialize the nested message into the protobuf binary format.

4: Timestamps: By default timestamps are converted to an RFC 3339 string and stored as a String. The dynamo.type.binary = true annotation can be used to serialize the timestamp as a protobuf binary format. The dynamo.type.unix_seconds = true annotation can be used to serialize the timestamp as a Number, any partial seconds are truncated. The dynamo.type.unix_ms = true annotation can be used to serialize the timestamp as a Number, any partial seconds are converted to a floating point milliseconds.

4: Duration: By default durations are converted to a String. The dynamo.type.binary = true annotation can be used to serialize the duration as a protobuf binary format.

Example

syntax = "proto3";

package examplepb;

import "dynamo/dynamo.proto";

message Store {
  option [(dynamo.primary) = {
        name: "pk",
        prefix: "store",
        fields: ["id"],
  }];

  option [(dynamo.sort) = {
        name: "sk",
        fields: ["country", "region", "state", "city", "id"],
  }];

  string id = 1 [(dynamo.name) = "store_id"];

  string country  = 2;
  string region   = 3;
  string state    = 4;
  string city     = 5;

  bool closed = 6;

  google.protobuf.Timestamp opening_date = 7 [(dynamo.type).unix_seconds = true];

  repeated string best_employee_ids 8 [(dynamo.type).set = true];
}

When serialized, this will generate the following DynamodDB Attributes:

{
  "pk": {"S": "stores:best-buy"},
  "sk": {"S": "united_states:west:california:concord:1234"}, 
  "store_id": {"S":  "1234"},
  "country": {"S":  "united_states"},
  "region": {"S":  "west"},
  "state": {"S":  "california"},
  "city": {"S":  "concord"},
  "closed": {"B": false},
  "opening_date": {"N":  "1585453283"},
  "best_employee_ids": {"SS": [,"AAA", "BBB", "CCC"}
}

License

protoc-gen-dynamo is licensed under the Apache License, Version 2.0