File Coverage

blib/lib/WebService/Amazon/DynamoDB/Server/Item.pm
Criterion Covered Total %
statement 41 60 68.3
branch 16 24 66.6
condition 1 3 33.3
subroutine 8 10 80.0
pod 5 5 100.0
total 71 102 69.6


line stmt bran cond sub pod time code
1             package WebService::Amazon::DynamoDB::Server::Item;
2             $WebService::Amazon::DynamoDB::Server::Item::VERSION = '0.001';
3 9     9   15897 use strict;
  9         10  
  9         315  
4 9     9   36 use warnings;
  9         11  
  9         188  
5              
6 9     9   607 use Future;
  9         9493  
  9         133  
7 9     9   1058 use Encode;
  9         17852  
  9         645  
8 9     9   43 use List::Util qw(sum);
  9         10  
  9         5195  
9              
10             =pod
11              
12             Attributes are each stored twice:
13              
14             attributes => [...]
15             attribute_by_key => { ... }
16              
17             An attribute is stored as a hashref:
18              
19             {
20             key => 'attribute_name',
21             type => S|SS|N|B|NULL|BOOL|M|L,
22             value => '...'
23             }
24              
25             =cut
26              
27             =head2 new
28              
29             Instantiate.
30              
31             =over 4
32              
33             =item * attributes - arrayref of attributes
34              
35             =back
36              
37             =cut
38              
39             sub new {
40 16     16 1 4555 my $class = shift;
41 16         74 bless {@_}, $class
42             }
43              
44             =head2 each_attribute
45              
46             Iterates through each attribute on this item.
47              
48             =cut
49              
50             sub each_attribute {
51 0     0 1 0 my ($self, $code) = @_;
52 0         0 my $f = Future->new;
53 0         0 $code->($_) for @{$self->{attributes}};
  0         0  
54 0         0 $f->done
55             }
56              
57             =head2 bytes_used
58              
59             Resolves to the total number of bytes used by this item.
60              
61             =cut
62              
63             sub bytes_used {
64 14     14 1 4392 my ($self) = @_;
65 14   33     51 $self->{bytes_used} //= do {
66 14         13 my $total = 0;
67 14         14 for my $attr (@{$self->{attributes}}) {
  14         27  
68 20         53 $total += length Encode::encode('UTF-8', $attr->{key});
69 20         833 $total += $self->bytes_for($attr->{type}, $attr->{value});
70             }
71 14         45 Future->done($total)
72             }
73             }
74              
75             =head2 bytes_for
76              
77             Calculates how many bytes are used for the given type and value. Used for
78             recursive size calculations (map/list etc.).
79              
80             Returns an immediate value.
81              
82             =cut
83              
84             sub bytes_for {
85 23     23 1 28 my ($self, $type, $v) = @_;
86 23 50       55 die 'no type' unless defined $type;
87 23         22 my $total = 0;
88 23 100       68 if($type eq 'S') { # String
    100          
    100          
    100          
    100          
    100          
    50          
    50          
    50          
    0          
89 14         21 $total += length Encode::encode('UTF-8', $v);
90             } elsif($type eq 'N') { # String
91 2         4 $total += length $v;
92             } elsif($type eq 'B') { # Binary
93 1         2 $total += length $v;
94             } elsif($type eq 'BOOL') { # Boolean
95 2         3 ++$total
96             } elsif($type eq 'NULL') { # Null
97 1         1 ++$total
98             } elsif($type eq 'SS') { # String set
99 2         2 $total += 3;
100 2         7 $total += length Encode::encode('UTF-8', $_) for @$v;
101             } elsif($type eq 'NS') { # Number set
102 0         0 $total += 3;
103 0         0 $total += length Encode::encode('UTF-8', $_) for @$v;
104             } elsif($type eq 'BS') { # Blob set
105 0         0 $total += 3;
106 0         0 $total += length $_ for @$v;
107             } elsif($type eq 'M') { # Map
108             # x => { key => 'x', value => 'y', type => 'z' }
109 1         2 $total += 3;
110 1         3 for my $attr (values %$v) {
111 3         7 $total += length Encode::encode('UTF-8', $attr->{key});
112 3         64 $total += $self->bytes_for($attr->{type}, $attr->{value});
113             }
114             } elsif($type eq 'L') { # List
115             # x => { key => 'x', value => 'y', type => 'z' }
116 0         0 $total += 3;
117 0         0 for my $attr (@$v) {
118 0         0 $total += length Encode::encode('UTF-8', $attr->{key});
119 0         0 $total += $self->bytes_for($attr->{type}, $attr->{value});
120             }
121             } else {
122 0         0 die 'invalid - ' . $type;
123             }
124 23         790 $total
125             }
126              
127             =head2 attribute_by_key
128              
129             Returns the given attribute via key lookup.
130              
131             =cut
132              
133             sub attribute_by_key {
134 0     0 1   my ($self, $k) = @_;
135 0 0         unless($self->{attribute_by_key}) {
136 0           $self->{attribute_by_key}{$_->{key}} = $_ for @{$self->{attributes}};
  0            
137             }
138 0           $self->{attribute_by_key}{$k}
139             }
140              
141             1;
142