File Coverage

blib/lib/Presto.pm
Criterion Covered Total %
statement 16 18 88.8
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 22 24 91.6


line stmt bran cond sub pod time code
1             package Presto;
2              
3 3     3   113464 use 5.6.0;
  3         11  
  3         143  
4              
5 3     3   17 use strict;
  3         7  
  3         122  
6 3     3   15 use warnings;
  3         9  
  3         155  
7              
8             our $VERSION = '0.01';
9              
10             #use lib '/home/rob/DBM-Deep/tags/0-981_02/lib';
11 3     3   16149 use DBM::Deep '0.982';
  3         57342  
  3         28  
12 3     3   8138 use Class::MOP;
  3         523496  
  3         189  
13 3     3   1499 use Data::Structure::Util qw( get_blessed );
  0            
  0            
14              
15             sub new {
16             my $class = shift;
17             my ($filename) = @_;
18              
19             my $db = DBM::Deep->new({
20             file => $filename,
21             locking => 1,
22             autobless => 1,
23             autoflush => 1,
24             });
25              
26             unless ( exists $db->{data} ) {
27             $db->{data} = {};
28             }
29              
30             return bless {
31             db => $db,
32             classes => {},
33             } => $class;
34             }
35              
36              
37             sub register_class {
38             my $presto = shift;
39             my ($pkg) = @_;
40              
41             $presto->{classes}{$pkg} = undef;
42              
43             my $meta = Class::MOP::Class->initialize($pkg);
44              
45             my $db = $presto->{db};
46              
47             $meta->add_method('find' => sub {
48             my $class = shift;
49             my ($req) = @_;
50              
51             my @ret;
52             OBJ: foreach my $obj ( @{$db->{data}{$class}} ) {
53             foreach my $k ( keys %$req ) {
54             next OBJ if !exists $obj->{$k};
55             if ( defined $req->{$k} ) {
56             next OBJ if !defined $obj->{$k}
57             || $obj->{$k} ne $req->{$k};
58             }
59             else {
60             next OBJ if defined $obj->{$k};
61             }
62             }
63              
64             #XXX This is what it should be, but there's a bug in DBM::Deep.
65             #push @ret, tied(%$obj)->export;
66             push @ret, bless tied(%$obj)->export, Scalar::Util::blessed($obj);
67             }
68              
69             return wantarray ? @ret : $ret[0];
70             });
71              
72             $meta->add_method( 'save' => sub {
73             my $self = shift;
74              
75             # get_blessed() is a depth-first traversal. We need to handle the
76             # children first in order to make sure that we don't get duplicates.
77             # Hence, the use of shift() instead of pop().
78              
79             my $objects = get_blessed( $self );
80             while ( my $obj = shift @$objects ) {
81             my $c = Scalar::Util::blessed($obj);
82             next unless exists $presto->{classes}{$c};
83              
84             if ( exists $obj->{oid} ) {
85             $db->{data}{$c}[$obj->{oid}] = $obj;
86             }
87             else {
88             $db->{data}{$c} ||= [];
89             $obj->{oid} = $db->{data}{$c}->length;
90             push @{$db->{data}{$c}}, $obj;
91             }
92             }
93              
94             return 1;
95             });
96              
97             $meta->add_method( 'delete' => sub {
98             my $self = shift;
99              
100             my $c = Scalar::Util::blessed( $self );
101             if ( exists $self->{oid} ) {
102             delete $db->{data}{$c}[$self->{oid}];
103             delete $self->{oid};
104             }
105              
106             return 1;
107             });
108              
109             return 1;
110             }
111              
112             1;
113             __END__
114              
115             =pod
116              
117             =head1 NAME
118              
119             Presto - An Object Oriented Database System for Perl
120              
121             =head1 SYNOPSIS
122              
123             my $presto = Presto->new( $db_file );
124              
125             $presto->register_class( 'Class1', 'Class2' );
126              
127             my $obj = Class1->new( ... );
128              
129             $obj->save;
130              
131             $obj->delete;
132              
133             my @objs = Class1->find( {
134             key1 => value1,
135             key2 => value2,
136             } );
137              
138             $objs[0]->delete;
139              
140             =head1 WARNING
141              
142             This is completely and utterly alpha software. If you love your job, don't
143             make it depend on this version of this module. This is being released solely
144             for community comment.
145              
146             If you like this module, please provide me with failing tests and API
147             suggestions. I'll take patches, but I prefer faiilng tests demonstrating what
148             you want Presto to do and how it's not doing it. You might find that, in the
149             process of writing the failing test, Presto already does what you want. Plus,
150             with the failing test, I see what you're trying to do. A patch doesn't tell me
151             that.
152              
153             =head1 DESCRIPTION
154              
155             Presto is an object datastore, or OODBMS. There is nothing relational about it
156             at all. You put objects in and you get objects out. Unlike L<Pixie/>, there is
157             no magic cookie. Unlike L<DBM::Deep/> (which is the underlying engine), there is
158             DBMS management provided for you, including indexing.
159              
160             =head1 METHODS
161              
162             =over 4
163              
164             =item B<new>
165              
166             This is the constructor to create a new Presto object. It accepts one
167             parameter, which is the filename of the Presto database.
168              
169             =item B<register_class>
170              
171             This accepts a single class name. It will add the following methods to it:
172              
173             =over 4
174              
175             =item * find()
176              
177             This is a class method. It accepts a hashref of the key/value pairs you wish
178             to find objects that match.
179              
180             =item * save()
181              
182             This is an instance method. It will save that object and any children it has
183             to the database. It will only call save() on children that are blessed into a
184             registered class. When it is done, it will set the I<oid> key to the object id.
185              
186             If the object has no OID, it will perform an insertion. If it does, it will
187             perform an update.
188              
189             B<NOTE>: The oid can be 0. Do B<NOT> check the OID for truth. Instead, check to
190             make sure that the I<oid> key exists.
191              
192             if ( exists $obj->{oid} ) {
193             # Do something here
194             }
195              
196             =item * delete()
197              
198             This is an instance method. It will make sure that there is no object in the
199             datastore with that object's OID. It will I<only> delete that object, not any
200             children.
201              
202             =back
203              
204             =back
205              
206             =head1 TODO
207              
208             =over 4
209              
210             =item * Indices
211              
212             Currently, there is B<NO> indexing done. Every find() does the equivalent of a
213             full-table scan. This will be added in version 0.02.
214              
215             =back
216              
217             =head1 RESTRICTIONS
218              
219             =over 4
220              
221             =item * Hashes only
222              
223             All objects B<must> be blessed hashes. This restriction will go away in a later
224             release. If you don't use blessed hashes and it blows up on you, don't complain.
225             You've been warned.
226              
227             =back
228              
229             =head1 SEE ALSO
230              
231             L<Presto::WTF/>, L<DBM::Deep/>
232              
233             =head1 CODE COVERAGE
234              
235             We use L<Devel::Cover/> to test the code coverage of our test suite. Here is
236             the current coverage report:
237              
238             ---------------------------- ------ ------ ------ ------ ------ ------ ------
239             File stmt bran cond sub pod time total
240             ---------------------------- ------ ------ ------ ------ ------ ------ ------
241             blib/lib/Presto.pm 98.4 66.7 88.9 100.0 100.0 100.0 92.3
242             Total 98.4 66.7 88.9 100.0 100.0 100.0 92.3
243             ---------------------------- ------ ------ ------ ------ ------ ------ ------
244              
245             =head1 AUTHOR
246              
247             Rob Kinyon E<lt>rob@iinteractive.comE<gt>
248              
249             Stevan Little E<lt>stevan@iinteractive.comE<gt>
250              
251             =head1 COPYRIGHT AND LICENSE
252              
253             Copyright 2006 by Infinity Interactive, Inc.
254              
255             L<http://www.iinteractive.com>
256              
257             This library is free software; you can redistribute it and/or modify
258             it under the same terms as Perl itself.
259              
260             =cut