Amazon-DynamoDB-Simple

 view release on metacpan or  search on metacpan

README.md  view on Meta::CPAN


    # returns a hash representing the whole table as key value pairs
    $table->items();

    # returns all the keys in the table
    $table->keys();

    # delete $old_key, create $new_key
    $table->rename($old_key, $new_key);

    # sync data between AWS regions using the 'last_updated' field to select
    # the newest data.  This method will permanently delete any items marked as
    # 'deleted'.
    $table->sync_regions();

    # This sets the value of the hosts attribute.  The value shown is the
    # default value.  You must use exactly two hosts for stuff to work atm.
    # Sorry.
    $table->hosts([qw/
            dynamodb.us-east-1.amazonaws.com
            dynamodb.us-west-1.amazonaws.com

lib/Amazon/DynamoDB/Simple.pm  view on Meta::CPAN


    # returns a hash representing the whole table as key value pairs
    $table->items();

    # returns all the keys in the table
    $table->keys();

    # delete $old_key, create $new_key
    $table->rename($old_key, $new_key);

    # sync data between AWS regions using the 'last_updated' field to select
    # the newest data.  This method will permanently delete any items marked as
    # 'deleted'.
    $table->sync_regions();

    # This sets the value of the hosts attribute.  The value shown is the
    # default value.  You must use exactly two hosts for stuff to work atm.
    # Sorry.
    $table->hosts([qw/
            dynamodb.us-east-1.amazonaws.com
            dynamodb.us-west-1.amazonaws.com

lib/Amazon/DynamoDB/Simple.pm  view on Meta::CPAN

            );
    }

    return \@dynamodbs;
}

sub put {
    my ($self, %item) = @_;

    # timestamp this transaction
    $item{last_updated} = DateTime->now . ""; # stringify datetime
    $item{deleted}    ||= 0;

    %item         = $self->deflate(%item);
    my $dynamodbs = $self->dynamodbs();
    my $success   = 0;

    for my $dynamodb (@$dynamodbs) {
        try { 
            $dynamodb->put_item(
                TableName => $self->table,

lib/Amazon/DynamoDB/Simple.pm  view on Meta::CPAN

    }

    confess "unable to connect and get item from any dynamodb" unless $success;

    my $most_recent;
    for my $item (@items) {
        next unless $item;

        $most_recent = $item 
            if !$most_recent ||
                $most_recent->{last_updated} le $item->{last_updated};
    }

    return if $most_recent->{deleted};

    return $self->inflate(%$most_recent);
}

sub scan {
    my ($self) = @_;

lib/Amazon/DynamoDB/Simple.pm  view on Meta::CPAN


sub _sync_items {
    my ($self, $from_ddb, $to_ddb, $from_items, $to_items) = @_;

    my $primary_key_name = $self->primary_key;

    for my $from_key (keys %$from_items) {
        my $from_value = $from_items->{$from_key};
        my $to_value = $to_items->{$from_key};
        if (!$to_value) {
            $to_value = {last_updated => '1900-01-01T00:00:00'};
            $to_items->{$from_key} = $to_value;
        }

        my $updated0 = $from_value->{last_updated};
        my $updated1 = $to_value->{last_updated};

        # don't need to sync if the items are the same age and not deleted
        next if $updated0 eq $updated1 && !$to_value->{deleted};

        # find the newest item
        my $newest = $updated0 gt $updated1
            ? $from_value
            : $to_value;

        # sync newest item to the other region
        if ($newest->{deleted}) {
            $self->permanent_delete( $newest->{$primary_key_name} );
        }
        else {
            # TODO: this could be more efficient by syncing to just the ddb
            # that needs it
            $self->put(%$newest);
        }

        # Lets say we are syncing from $dynamodb0 -> $dynamodb1. This prevents
        # us from re syncing this item when we sync in the other direction from
        # $dynamodb1 -> $dynamodb0
        $to_value->{last_updated} = $from_value->{last_updated};
    }
}

sub items {
    my ($self) = @_;

    my $human_items = {};

    my $items = $self->scan->{Items};
    my $primary_key_name = $self->primary_key;

xt/amazon/dynamodb/simple.t  view on Meta::CPAN

    region    => 'highlyavailable',
    zone      => 'highlyavailable',
    hashthing => [{
        a     => 'firstthing',
        b     => 2000,  
        c     => 200,
    }],
};
my $expected_item = {
    %$server_definition,
    last_updated => re(qr/^\d{4}-\d{2}\-\d{2}T\d{2}:\d{2}:\d{2}/),
    deleted      => bool(),
};

subtest 'put' => sub {

    $dynamodb->put(%$server_definition);

    my $ddbs = $dynamodb->dynamodbs();

    for my $ddb (@$ddbs) {

xt/amazon/dynamodb/simple.t  view on Meta::CPAN

    my %item = $dynamodb->get($node);

    cmp_deeply \%item, $expected_item, 'got item';

    # update item in one region
    my $ddb = $dynamodb->dynamodbs->[1];
    %item = $dynamodb->deflate(
        %$server_definition,
        flavor       => 'highlyavailable2',
        deleted      => 0,
        last_updated => DateTime->now . ""
    );
    $ddb->put_item(
        TableName => 'server_definitions',
        Item      => \%item,
    );

    %item = $dynamodb->get($node);
    is $item{flavor}, 'highlyavailable2', 'got most recent item';
};

xt/amazon/dynamodb/sync.t  view on Meta::CPAN

    $table->put(%item);
    sleep 1;

    # update one dynamodb
    $table->dynamodbs->[0]->put_item(
        TableName => 'server_definitions',
        Item      => {
            %item, 
            zone         => 'z',
            deleted      => 0,
            last_updated => DateTime->now() . "",
        },
    );

    # sync
    $table->sync_regions;

    # check that sync worked
    my $saved_items = {};
    for my $i (0, 1) {
        $saved_items->{$i} = $table->dynamodbs->[$i]->get_item(
            sub { shift },
            TableName => 'server_definitions',
            Key       => { node => $node },
        )->get();

        cmp_deeply $saved_items->{$i}, {
            %item,
            zone         => 'z',
            deleted      => 0,
            last_updated => re(qr/^\d{4}-\d{2}\-\d{2}T\d{2}:\d{2}:\d{2}/),
        }, "saved server definition to dynamodb $i";
    }

    # cleanup: permanently delete item from all dynamodbs
    $table->permanent_delete($node);
};

subtest 'sync: create new records' => sub {
    my %item = (
        node   => $node,

xt/amazon/dynamodb/sync.t  view on Meta::CPAN

        region => $cfg->{region},
        zone   => $cfg->{zone},
    );

    # create item on one dynamodb
    $table->dynamodbs->[0]->put_item(
        TableName => 'server_definitions',
        Item      => {
            %item, 
            deleted      => 0,
            last_updated => DateTime->now() . "",
        },
    );

    # sync
    $table->sync_regions;

    # check that sync worked
    my $saved_items = {};
    for my $i (0, 1) {
        $saved_items->{$i} = $table->dynamodbs->[$i]->get_item(
            sub { shift },
            TableName => 'server_definitions',
            Key       => { node => $node },
        )->get();

        cmp_deeply $saved_items->{$i}, { 
            %item,
            deleted      => 0,
            last_updated => re(qr/^\d{4}-\d{2}\-\d{2}T\d{2}:\d{2}:\d{2}/),
        }, "saved server definition to dynamodb $i";
    }

    # cleanup: permanently delete item from all dynamodbs
    $table->permanent_delete($node);
};

done_testing;



( run in 0.373 second using v1.01-cache-2.11-cpan-05444aca049 )