File Coverage

blib/lib/BerkeleyDB/Easy/Handle.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package BerkeleyDB::Easy::Handle;
2             our @ISA = qw(BerkeleyDB::Common);
3            
4 1     1   921 use strict;
  1         14  
  1         35  
5 1     1   5 use warnings;
  1         1  
  1         31  
6            
7 1     1   5 use BerkeleyDB::Easy::Common;
  1         2  
  1         266  
8 1     1   631 use BerkeleyDB::Easy::Error;
  1         3  
  1         137  
9 0           use BerkeleyDB qw(
10             DB_BTREE
11             DB_HASH
12             DB_RECNO
13             DB_QUEUE
14             DB_HEAP
15             DB_UNKNOWN
16             DB_NOTFOUND
17 1     1   117241 );
  0            
18            
19             sub _handle { shift }
20            
21             sub new {
22             my ($self, @args) = @_;
23             $self->_wrap(sub { $self->_new(@args) });
24             }
25            
26             sub _new {
27             my $self = shift;
28             my %opts = $self->_options(@_);
29            
30             # Ignore NOTFOUND by default, otherwise die
31             my $errors = delete $opts{Errors} || { DB_NOTFOUND() => BDB_IGNORE };
32             ref $errors eq 'HASH'
33             or $self->_throw(BDB_PARAM, q("Errors" option must be HASH ref));
34            
35             # What kind of handle are we? BTREE if not specified
36             my $type = $self->_type(delete $opts{Type} or DB_BTREE);
37             (my $class = ref $self || $self) =~ s/::Handle$/::$type/;
38            
39             NOTICE and $self->_notice(qq(Creating $type handle));
40            
41             my $handle = $self->_wrap(sub {
42             my $db = qq(BerkeleyDB::$type)->new(%opts)
43             or $self->_throw(BDB_HANDLE);
44             my $status = $db->status;
45             $status and $self->_throw($status);
46             $db;
47             });
48             bless $handle, $class;
49            
50             # Assign severity levels to errors if user passed any
51             $handle->_assign($_, $errors->{$_}) for keys %$errors;
52             $handle;
53             }
54            
55             sub _options {
56             my $self = shift;
57             my %opts;
58            
59             # Got a single param, must be hash of options
60             if (@_ == 1) {
61             $self->_throw(BDB_PLACE) unless ref $_[0] eq 'HASH';
62             %opts = %{$_[0]};
63             }
64            
65             # Got an even list of options
66             elsif (@_ > 1 and not @_ % 2) {
67             %opts = @_;
68             }
69            
70             # Got something else. Throw an error
71             elsif (@_ > 0) {
72             $self->_throw(BDB_PLACE);
73             }
74            
75             map { $self->_normalize($_) => $opts{$_} } keys %opts;
76             }
77            
78             #
79             # Convert underscore_flags to CamelCase for BerkeleyDB.pm
80             #
81             sub _normalize {
82             my $self = shift;
83             (my $key = shift) =~ s/^-//g;
84             join '', map { ucfirst lc } split /_/, $key;
85             }
86            
87             sub _type {
88             my ($self, $type) = @_;
89             (our $Types ||= {
90             &DB_BTREE => 'Btree',
91             &DB_HASH => 'Hash',
92             $self->_try(\&DB_RECNO) || '' => 'Recno', # v3
93             $self->_try(\&DB_QUEUE) || '' => 'Queue', # v3
94             $self->_try(\&DB_HEAP ) || '' => 'Heap', # v5.2
95             &DB_UNKNOWN => 'Unknown', # v? TODO
96             })->{$type} or $self->_throw(BDB_TYPE);
97             }
98            
99             # Each hash elem in %subs defines a wrapper specification. Look at Common.pm
100             # for how these work. Briefly, the key is our wrapper's name, and the value
101             # is an array ref with the following fields:
102             #
103             # 0 FUNC : the underlying BerkeleyDB.pm function we are wrapping
104             # 1 RECV : parameters to our wrapper, passed by the end user
105             # 2 SEND : arguments we call FUNC with, often carried thru from RECV
106             # 3 SUCC : what to return on success
107             # 4 FAIL : what to return on failure
108             # 5 OPTI : integer specifying optimization level
109             # 6 FLAG : default flag to FUNC
110             #
111             # Single-letter aliases expand as:
112             #
113             # K $key | R $return | X $x
114             # V $value | S $status | Y $y
115             # F $flags | T 1 ('True') | Z $z
116             # A @_ ('All') | N '' ('Nope') | U undef
117            
118             my %subs = (
119             db_get => ['db_get' ,[ ],[A ],[S ],[S],0, ],
120             get => ['db_get' ,[K,F ],[K,V,F],[V ],[ ],0, ],
121             db_put => ['db_put' ,[ ],[A ],[S ],[S],0, ],
122             put => ['db_put' ,[K,V,F],[K,V,F],[V ],[ ],0, ],
123             db_del => ['db_del' ,[ ],[A ],[S ],[S],0, ],
124             del => ['db_del' ,[K,F ],[K,F ],[K ],[ ],0, ],
125             db_sync => ['db_sync' ,[ ],[A ],[S ],[S],0, ],
126             sync => ['db_sync' ,[F ],[F ],[T ],[ ],0, ],
127             db_cursor => ['db_cursor',[ ],[A ],[R ],[R],0, ],
128             associate => ['associate',[ ],[A ],[S ],[S],0, ],
129             pget => ['db_pget' ,[X ],[X,K,V],[K,V],[ ],0, ],
130             );
131            
132             $subs{exists} = $BerkeleyDB::db_version >= 4.6
133             ? ['exists',[K,F],[K,F ],[T],[N],0]
134             : ['db_get',[K,F],[K,V,F],[T],[N],0];
135            
136             # Install the stubs
137             while (my ($name, $spec) = each %subs) {
138             __PACKAGE__->_install($name, $spec);
139             }
140            
141             #
142             # Constructor for a cursor to this DB handle. It could/should probably live
143             # at Cursor->new() but it's here for now.
144             #
145             sub cursor {
146             my ($self, $flags) = @_;
147             my $cursor = $self->db_cursor($flags);
148             my $class = $self->_Cursor;
149             (my $file = $class) =~ s(::)(\/)g;
150             require $file . q(.pm);
151             return bless $cursor, $class;
152             }
153            
154             # Method aliases for naming consistency
155             *delete = \&del;
156             *cur = \&cursor;
157            
158             INFO and __PACKAGE__->_info(q(Handle.pm finished loading));
159            
160             1;
161            
162             =encoding utf8
163            
164             =head1 NAME
165            
166             BerkeleyDB::Easy::Handle - Generic class for Btree, Hash, Recno, Queue, and
167             Heap handles.
168            
169             =head1 METHODS
170            
171             You can optionally provide flags for most methods, but first check to see
172             if there isn't a dedicated wrapper method to accomplish what you want.
173            
174             =head2 get
175            
176             $val = $db->get($key);
177            
178             =head2 put
179            
180             $val = $db->put($key, $val);
181            
182             =head2 exists
183            
184             $bool = $db->exists($key);
185            
186             =head2 sync
187            
188             $status = $db->sync();
189            
190             =head2 cursor
191            
192             $cursor = $db->cursor();
193            
194             =head1 BUGS
195            
196             This module is functional but unfinished.
197            
198             =head1 AUTHOR
199            
200             Rob Schaber, C<< >>
201            
202             =head1 LICENSE
203            
204             Copyright 2013 Rob Schaber.
205            
206             This program is free software; you can redistribute it and/or modify it
207             under the terms of either: the GNU General Public License as published
208             by the Free Software Foundation; or the Artistic License.
209            
210             See L for more information.