File Coverage

blib/lib/PawsX/DynamoDB/DocumentClient.pm
Criterion Covered Total %
statement 30 64 46.8
branch 10 14 71.4
condition 15 23 65.2
subroutine 6 15 40.0
pod 9 9 100.0
total 70 125 56.0


line stmt bran cond sub pod time code
1             package PawsX::DynamoDB::DocumentClient;
2              
3 1     1   971654 use strict;
  1         4  
  1         37  
4 1     1   30 use 5.008_005;
  1         4  
5              
6 1     1   6 use Module::Runtime qw(require_module);
  1         2  
  1         7  
7 1     1   45 use Scalar::Util qw(blessed);
  1         2  
  1         44  
8 1     1   6 use Paws;
  1         2  
  1         445  
9              
10             our $VERSION = '0.05';
11              
12             sub new {
13 5     5 1 17229 my ($class, %args) = @_;
14 5   100     33 my $region = $args{region} || $ENV{AWS_DEFAULT_REGION};
15 5         12 my $paws = $args{paws};
16 5         11 my $dynamodb = $args{dynamodb};
17              
18 5 50 33     30 if ($paws && !(blessed($paws) && $paws->isa('Paws'))) {
      66        
19 0         0 die "paws must be a Paws object";
20             }
21              
22 5 50 33     29 if ($dynamodb && !(blessed($dynamodb) && $dynamodb->isa('Paws::DynamoDB'))) {
      66        
23 0         0 die "dynamodb must be a Paws::DynamoDB object";
24             }
25              
26 5 100 100     25 if (!$region && $paws) {
27 1         24 $region = $paws->config->region;
28             }
29              
30 5 100 100     49 if (!($dynamodb || $region)) {
31 1         14 die "unable to determine region, and no dynamodb object provided";
32             }
33              
34 4 100       13 if (!$paws) {
35 3         26 $paws = Paws->new(config => { region => $region});
36             }
37              
38 4 100       4003 if (!$dynamodb) {
39 3         13 $dynamodb = $paws->service('DynamoDB');
40             }
41              
42 4         490244 my $self = {
43             paws => $paws,
44             dynamodb => $dynamodb,
45             };
46              
47 4         25 return bless $self, $class;
48             }
49              
50             sub batch_get {
51 0     0 1   my ($self, %args) = @_;
52 0           my $command_class = 'PawsX::DynamoDB::DocumentClient::BatchGet';
53 0           $self->_run_command($command_class, %args);
54             }
55              
56             sub batch_write {
57 0     0 1   my ($self, %args) = @_;
58 0           my $command_class = 'PawsX::DynamoDB::DocumentClient::BatchWrite';
59 0           $self->_run_command($command_class, %args);
60             }
61              
62             sub delete {
63 0     0 1   my ($self, %args) = @_;
64 0           my $command_class = 'PawsX::DynamoDB::DocumentClient::Delete';
65 0           $self->_run_command($command_class, %args);
66             }
67              
68             sub get {
69 0     0 1   my ($self, %args) = @_;
70 0           my $command_class = 'PawsX::DynamoDB::DocumentClient::Get';
71 0           $self->_run_command($command_class, %args);
72             }
73              
74             sub put {
75 0     0 1   my ($self, %args) = @_;
76 0           my $command_class = 'PawsX::DynamoDB::DocumentClient::Put';
77 0           $self->_run_command($command_class, %args);
78             }
79              
80             sub query {
81 0     0 1   my ($self, %args) = @_;
82 0           my $command_class = 'PawsX::DynamoDB::DocumentClient::Query';
83 0           $self->_run_command($command_class, %args);
84             }
85              
86             sub scan {
87 0     0 1   my ($self, %args) = @_;
88 0           my $command_class = 'PawsX::DynamoDB::DocumentClient::Scan';
89 0           $self->_run_command($command_class, %args);
90             }
91              
92             sub update {
93 0     0 1   my ($self, %args) = @_;
94 0           my $command_class = 'PawsX::DynamoDB::DocumentClient::Update';
95 0           $self->_run_command($command_class, %args);
96             }
97              
98             sub _run_command {
99 0     0     my ($self, $command_class, %args) = @_;
100 0   0       my $return_paws_output = delete $args{return_paws_output} || 0;
101              
102 0           require_module($command_class);
103              
104 0           my $service = $self->{dynamodb};
105 0           my %service_args = $command_class->transform_arguments(%args);
106 0           my $output = $command_class->run_service_command($service, %service_args);
107              
108 0 0         return $output if $return_paws_output;
109 0           return $command_class->transform_output($output);
110             }
111              
112             1;
113             __END__
114              
115             =encoding utf-8
116              
117             =head1 NAME
118              
119             PawsX::DynamoDB::DocumentClient - a simplified way of working with AWS DynamoDB items that uses Paws under the hood.
120              
121             =head1 SYNOPSIS
122              
123             use PawsX::DynamoDB::DocumentClient;
124              
125             my $dynamodb = PawsX::DynamoDB::DocumentClient->new();
126              
127             $dynamodb->put(
128             TableName => 'users',
129             Item => {
130             user_id => 24,
131             email => 'bob@example.com',
132             roles => ['admin', 'finance'],
133             },
134             );
135              
136             my $user = $dynamodb->get(
137             TableName => 'users',
138             Key => {
139             user_id => 24,
140             },
141             );
142              
143             =head1 DESCRIPTION
144              
145             Paws (in this author's opinion) is the best and most up-to-date way of working with AWS. However, reading and writing DynamoDB items via Paws' low-level API calls can involve a lot of busy work formatting your data structures to include DynamoDB types.
146              
147             This module simplifies some DynamoDB operations by automatically converting back and forth between simpler Perl data structures and the request/response data structures used by Paws.
148              
149             For more information about how types are mananged, see L<Net::Amazon::DynamoDB::Marshaler>.
150              
151             This module is based on a similar class in the L<AWS JavaScript SDK|http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html>.
152              
153             =head2 outputs
154              
155             By default, the methods below return plain values (or nothing) that make normal use cases simpler, as opposed to the output objects that Paws generates. For example, get() returns a hashref of the item's data, as opposed to a L<Paws::DynamoDB::GetItemOutput> object.
156              
157             For use cases where you need more extensive output data, every method supports a return_paws_output flag, which will return the Paws object instead.
158              
159             my $item = $dynamodb->get(
160             TableName => 'users',
161             Key => {
162             user_id => 1000,
163             },
164             );
165             # $item looks like { user_id => 1000, email => 'foo@bar.com', ... }
166              
167             my $output = $dynamodb->get(
168             TableName => 'users',
169             Key => {
170             user_id => 1000,
171             },
172             return_paws_output => 1,
173             );
174             # $output isa Paws::DynamoDB::GetItemOutput
175              
176             =head2 force_type
177              
178             All methods take in an optional force_type parameter, which gets passed to L<Net::Amazon::DynamoDB::Marshaler> for when you need to override its default typing. See the description of force_type in that module's documentation for more details.
179              
180             =head1 METHODS
181              
182             =head2 new
183              
184             my $dynamodb = PawsX::DynamoDB::DocumentClient->new(
185             region => 'us-east-1',
186             );
187              
188             This class method returns a new PawsX::DynamoDB::DocumentClient object. It accepts the following parameters:
189              
190             =head3 paws
191              
192             A Paws object to use to create the Paws::DynamoDB service object. Optional. Available in case you need to custom configuration of Paws (e.g. authentication).
193              
194             =head3 dynamodb
195              
196             Alternatively, you can provide a Paws::DynamoDB service object directly if you have one. Optional. If given, the 'paws' parameter will be ignored.
197              
198             =head3 region
199              
200             The AWS region to use when creating the Paws::DynamoDB service object. If not specified, will try to grab from the AWS_DEFAULT_REGION environment variable. Will be ignored if the object is constructed with a dynamodb object, or with a paws object that has a region configured.
201              
202             If the constructor can't figure out what region to use, an error will be thrown.
203              
204             =head2 batch_get
205              
206             my $result = $dynamodb->batch_get(
207             RequestItems => {
208             $table_name => {
209             Keys => [
210             { user_id => 1000 },
211             { user_id => 1001 },
212             ],
213             },
214             },
215             );
216              
217             Returns the attributes of one or more items from one or more tables by delegating to L<Paws::DynamoDB::BatchGetItem>.
218              
219             The following arguments are marshalled: values in 'RequestItems.$table_name.Keys'.
220              
221             By default (return_paws_output not set), returns a hashref that looks like:
222              
223             {
224             responses => {
225             $table_name => [
226             {...} # unmarshalled item
227             ...
228             ],
229             },
230             unprocessed_keys => {
231             $table_name => {
232             Keys => [
233             { ... }, # unmarshalled key
234             ...
235             ],
236             ProjectionExpression => '...',
237             ConsistentRead => $boolean,
238             }
239             }
240             }
241              
242             unprocessed_keys can be fed back into a new call to batch_get(). See L<Paws::DynamoDB::BatchGetItemOutput> for more infomation.
243              
244             A note on using force_type with batch_get() - force_type should be a hashref of hashrefs, whose parent key is the table name, e.g.:
245              
246             my $result = $dynamodb->batch_get(
247             RequestItems => {
248             users => {
249             Keys => [
250             { username => 'jdoe' },
251             { username => '2001' },
252             ],
253             },
254             zip_codes => {
255             Keys => [
256             { zip_code => '03456' },
257             ],
258             },
259             },
260             force_type => {
261             users => {
262             username => 'S',
263             },
264             zip_codes => {
265             zip_code => 'S',
266             },
267             }
268             );
269              
270             =head2 batch_write
271              
272             my $result = $dynamodb->batch_write(
273             RequestItems => {
274             $table_name => [
275             {
276             PutRequest => {
277             Item => {
278             user_id => 1000,
279             email => 'jdoe@example.com',
280             },
281             },
282             },
283             {
284             DeleteRequest => {
285             Key => {
286             user_id => 1001,
287             },
288             },
289             },
290             ],
291             },
292             );
293              
294             Puts or deletes multiple items in one or more tables by delegating to L<Paws::DynamoDB::BatchWriteItem>.
295              
296             The following arguments are marshalled: Items in PutRequests, Keys in DeleteRequests.
297              
298             By default (return_paws_output not set), returns a hashref of unprocessed items, in the same format as the RequestItems parameters. The unprocessed items are meant to be fed back into a new call to batch_write(). See L<Paws::DynamoDB::BatchWriteItemOutput> for more information.
299              
300             A note on using force_type with batch_write() - force_type should be a hashref of hashrefs, whose parent key is the table name, just like batch_get() above.
301              
302             =head2 delete
303              
304             my $result = $dynamodb->delete(
305             TableName => 'users',
306             Key => {
307             user_id => 1001,
308             },
309             );
310              
311             Deletes a single item in a table by primary key by delegating to L<Paws::DynamoDB::DeleteItem>.
312              
313             The following arguments are marshalled: 'ExpressionAttributeValues', 'Key'.
314              
315             By default (return_paws_output not set), returns undef, unless the 'ReturnValues' argument was set to 'ALL_OLD', in which case an unmarshalled hashref of how the item looked prior to deletion is returned.
316              
317             =head2 get
318              
319             my $result = $dynamodb->get(
320             TableName => 'users',
321             Key => {
322             user_id => 1000,
323             },
324             );
325              
326             Returns a set of attributes for the item with the given primary key by delegating to L<Paws::DynamoDB::GetItem>.
327              
328             The following arguments are marshalled: 'Key'.
329              
330             By default (return_paws_output not set), returns the fetched item as an unmarshalled hashref, or undef if the item was not found.
331              
332             =head2 put
333              
334             my $result = $dynamodb->put(
335             TableName => 'users',
336             Item => {
337             user_id => 1000,
338             email => 'jdoe@example.com',
339             tags => ['foo', 'bar', 'baz'],
340             },
341             );
342              
343             Creates a new item, or replaces an old item with a new item by delegating to L<Paws::DynamoDB::PutItem>.
344              
345             The following arguments are marshalled: 'ExpressionAttributeValues', 'Item'.
346              
347             By default (return_paws_output not set), returns undef. If 'ReturnValues' is set to 'ALL_OLD', returns an unmarshalled hashref of the item as it appeared before the put.
348              
349             =head2 query
350              
351             my $result = $dynamodb->query(
352             TableName => 'users',
353             IndexName => 'company_id',
354             KeyConditionExpression => 'company_id = :company_id',
355             ExpressionAttributeValues => {
356             ':company_id' => 25,
357             },
358             );
359              
360             Directly access items from a table by primary key or a secondary index by delegating to L<Paws::DynamoDB::Query>.
361              
362             The following arguments are marshalled: 'ExclusiveStartKey', 'ExpressionAttributeValues'.
363              
364             By default (return_paws_output not set), returns a hashref that looks like:
365              
366             {
367             items => [
368             { ... }, # unmarshalled item
369             ...
370             ],
371             last_evaluated_key => {
372             ... # unmarshalled key
373             },
374             count => $count,
375             }
376              
377             last_evaluated_key has a value if the query has more items to fetch. It can be used for the 'ExclusiveStartKey' value for a subsequent query.
378              
379             =head2 scan
380              
381             my $result = $dynamodb->scan(
382             TableName => 'users',
383             FilterExpression => 'first_name = :first_name',
384             ExpressionAttributeValues => {
385             ':first_name' => 'John',
386             },
387             );
388              
389             Returns one or more items and item attributes by accessing every item in a table or a secondary index by delegating to L<Paws::DynamoDB::Scan>.
390              
391             The following arguments are marshalled: 'ExclusiveStartKey', 'ExpressionAttributeValues'.
392              
393             Returns the same hashref as returned by query().
394              
395             =head2 update
396              
397             my $result = $dynamodb->update(
398             TableName => 'users',
399             Key: {
400             user_id => 1000,
401             },
402             UpdateExpression: 'SET status = :new_status',
403             ExpressionAttributeValues => {
404             ':new_status' => 'active',
405             },
406             );
407              
408             Edits an existing item's attributes, or adds a new item to the table if it does not already exist by delegating to L<Paws::DynamoDB::UpdateItem>.
409              
410             The following arguments are marshalled: 'ExpressionAttributeValues', 'Key'.
411              
412             By default (return_paws_output not set), returns undef. If 'ReturnValues' is set to something other than 'NONE', returns an unmarshalled hashref of the item as it appeared before the put.
413              
414             =head1 AUTHOR
415              
416             Steve Caldwell E<lt>scaldwell@gmail.comE<gt>
417              
418             =head1 COPYRIGHT
419              
420             Copyright 2017- Steve Caldwell
421              
422             =head1 LICENSE
423              
424             This library is free software; you can redistribute it and/or modify
425             it under the same terms as Perl itself.
426              
427             =head1 SEE ALSO
428              
429             =over 4
430              
431             =item L<Paws>
432              
433             =item L<Paws::DynamoDB>
434              
435             =item L<Net::Amazon::DynamoDB::Marshaler>
436              
437             =item L<DocumentClient|http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html> in the AWS JavaScript SDK.
438              
439             =back
440              
441             =head1 ACKNOWLEDGEMENTS
442              
443             Thanks to L<Campus Explorer|http://www.campusexplorer.com>, who allowed me to release this code as open source.
444              
445             Thanks to Jose Luis Martinez Torres (JLMARTIN), for suggestions (and for Paws!).
446              
447             =cut