File Coverage

blib/lib/DBIx/NoSQL.pm
Criterion Covered Total %
statement 13 13 100.0
branch n/a
condition n/a
subroutine 5 5 100.0
pod 1 2 50.0
total 19 20 95.0


line stmt bran cond sub pod time code
1             package DBIx::NoSQL;
2             our $AUTHORITY = 'cpan:YANICK';
3             $DBIx::NoSQL::VERSION = '0.0021';
4             # ABSTRACT: NoSQL-ish overlay for an SQL database
5              
6 8     8   858942 use strict;
  8         12  
  8         205  
7 8     8   29 use warnings;
  8         12  
  8         209  
8              
9 8     8   2830 use DBIx::NoSQL::Store;
  8         17  
  8         1009  
10              
11             sub new {
12 3     3 0 3039 my $class = shift;
13 3         40 return DBIx::NoSQL::Store->new( @_ );
14             }
15              
16             sub connect {
17 5     5 1 3536 my $class = shift;
18 5         42 return DBIx::NoSQL::Store->connect( @_ );
19             }
20              
21             1;
22              
23             __END__
24              
25             =pod
26              
27             =encoding UTF-8
28              
29             =head1 NAME
30              
31             DBIx::NoSQL - NoSQL-ish overlay for an SQL database
32              
33             =head1 VERSION
34              
35             version 0.0021
36              
37             =head1 SYNOPSIS
38              
39             use DBIx::NoSQL;
40              
41             my $store = DBIx::NoSQL->connect( 'store.sqlite' );
42              
43             $store->set( 'Artist' => 'Smashing Pumpkins' => {
44             name => 'Smashing Pumpkins',
45             genre => 'rock',
46             website => 'smashingpumpkins.com',
47             } );
48              
49             $store->exists( 'Artist' => 'Smashing Pumpkins' ); # 1
50              
51             $store->set( 'Artist' => 'Tool' => {
52             name => 'Tool',
53             genre => 'rock',
54             } );
55              
56             $store->search( 'Artist' )->count; # 2
57              
58             my $artist = $store->get( 'Artist' => 'Smashing Pumpkins' );
59              
60             # Set up a (searchable) index on the name field
61             $store->model( 'Artist' )->index( 'name' );
62             $store->model( 'Artist' )->reindex;
63              
64             for $artist ( $store->search( 'Artist' )->order_by( 'name DESC' )->all ) {
65             ...
66             }
67              
68             $store->model( 'Album' )->index( 'released' => ( isa => 'DateTime' ) );
69              
70             $store->set( 'Album' => 'Siamese Dream' => {
71             artist => 'Smashing Pumpkins',
72             released => DateTime->new( ... ),
73             } );
74              
75             my $album = $store->get( 'Album' => 'Siamese Dream' );
76             my $released = $album->{ released }; # The field is automatically inflated
77             print $release->strftime( ... );
78              
79             =head1 DESCRIPTION
80              
81             DBIx::NoSQL is a layer over DBI that presents a NoSQLish way to store and retrieve data. It does this by using a table called C<__Store__>. Once connected to a database, it will detect if this table is missing and create it if necessary
82              
83             When writing data to the store, the data (a HASH reference) is first serialized using L<JSON> and then inserted/updated via L<DBIx::Class> to (currently) an SQLite backend
84              
85             Retrieving data from the store is done by key lookup or by searching an SQL-based index. Once found, the data is deserialized via L<JSON> and returned
86              
87             The API is fairly sane, though still beta
88              
89             =head1 USAGE
90              
91             =head2 $store = DBIx::NoSQL->connect( $path )
92              
93             Returns a new DBIx::NoSQL store connected to the SQLite database located at C<$path>
94              
95             If the SQLite database file at C<$path> does not exist, it will be created
96              
97             =head2 $store->set( $model, $key, $value )
98              
99             Set C<$key> (a string) to C<$value> (a HASH reference) in C<$model>
100              
101             If C<$model> has index, this command will also update the index entry corresponding to C<$key>.
102              
103             The C<$key> can be omitted, in which case a UUID key will be auto-generated for the entry.
104              
105             Returns the new entry's key.
106              
107             =head2 $value = $store->exists( $model, $key )
108              
109             Returns true if some data for C<$key> is present in C<$model>
110              
111             =head2 $value = $store->get( $model, $key )
112              
113             Get C<$value> matching C<$key> in C<$model>
114              
115             =head2 $value = $store->delete( $model, $key )
116              
117             Delete the entry matching C<$key> in C<$model>
118              
119             If C<$model> has index, this command will also delete the index entry corresponding to C<$key>
120              
121             =head2 $store->reindex
122              
123             Reindex the searchable/orderable data in C<$store>
124              
125             This method is smart, in that it won't reindex a model unless the schema for $store is different/has changed. That is, if the schema for C<$store> is the same as it is in the database, this call will do nothing
126              
127             Refer to "Model USAGE" below for more information
128              
129             =head2 $store->dbh
130              
131             Return the L<DBI> database handle for the store, if you need/want to do your own thing
132              
133             =head1 Search USAGE
134              
135             To search on a model, you must have installed an index on the field you want to search on
136              
137             Refer to "Model USAGE" for indexing information
138              
139             =head2 $search = $store->search( $model, [ $where ] )
140              
141             $search = $store->search( 'Artist' => { name => { -like => 'Smashing%' } } )
142              
143             Return a L<DBIx::NoSQL::Search> object for C<$model>, filtering on the optional C<$where>
144              
145             An index is required for the filtering columns
146              
147             Refer to L<SQL::Abstract> for the format of C<$where> (actually uses L<DBIx::Class::SQLMaker> under the hood)
148              
149             =head2 @all = $search->all
150              
151             Returns every result for C<$search> in a list
152              
153             Returns an empty list if nothing is found
154              
155             =head2 $result = $search->next
156              
157             Returns the next item found for C<$search> via C<< $search->cursor >>
158              
159             Returns undef if nothing is left for C<$search>
160              
161             =head2 $sth = $search->cursor->sth
162              
163             Returns the L<DBI> sth (statement handle) for C<$search>
164              
165             =head2 $search = $search->search( $where )
166              
167             Further refine the search in the same way C<< $search->where( ... ) >> does
168              
169             =head2 $search = $search->where( $where )
170              
171             $search = $search->where( { genre => 'rock' } )
172              
173             Further refine C<$search> with the given C<$where>
174              
175             A new object is cloned from the original (the original C<$search> is left untouched)
176              
177             An index is required for the filtering columns
178              
179             Refer to L<SQL::Abstract> for the format of C<$where> (actually uses L<DBIx::Class::SQLMaker> under the hood)
180              
181             =head2 $search = $search->order_by( $order_by )
182              
183             $search->order_by( 'name DESC' )
184              
185             $search->order_by([ 'name DESC', 'age' ])
186              
187             Return the results in the given order
188              
189             A new object is cloned from the original, which is left untouched
190              
191             An index is required for the ordering columns
192              
193             Refer to L<SQL::Abstract> for the format of C<$order_by> (actually uses L<DBIx::Class::SQLMaker> under the hood)
194              
195             =head1 Model USAGE
196              
197             =head2 $model = $store->model( $model_name )
198              
199             Retrieve or create the C<$model_name> model object
200              
201             =head2 $model->index( $field_name )
202              
203             $store->model( 'Artist' )->index( 'name' ) # 'name' is now searchable/orderable, etc.
204              
205             Index C<$field_name> on C<$model>
206              
207             Every time the store for c<$model> is written to, the index will be updated with the value of C<$field>
208              
209             =head2 $model->index( $field_name, isa => $type )
210              
211             $store->model( 'Artist' )->index( 'website', isa => 'URI' )
212             $store->model( 'Artist' )->index( 'founded', isa => 'DateTime' )
213              
214             Index C<$field_name> on C<$model> as a special type/object (e.g. L<DateTime> or L<URI>)
215              
216             Every time the store for c<$model> is written to, the index will be updated with the deflated value of C<$field> (since
217             L<JSON> can not trivially serialize blessed references)
218              
219             =head2 $model->reindex
220              
221             Reindex the C<$model> data in the store after making a field indexing change:
222              
223             1. Rebuild the DBIx::Class::ResultSource
224             2. Drop and recreate the search table for $model
225             3. Iterate through all the data for $model, repopulating the search table
226              
227             If C<$model> does not have an index, this method will simply return
228              
229             To rebuild the index for _every_ model (on startup, for example), you can do:
230              
231             $store->reindex
232              
233             =head1 In the future
234              
235             Create a better interface for stashing and document it
236              
237             Wrap things in transactions that need it
238              
239             More tests: Always. Be. Testing.
240              
241             =head1 SEE ALSO
242              
243             L<KiokuDB>
244              
245             L<DBIx::Class>
246              
247             L<DBD::SQLite>
248              
249             =head1 AUTHORS
250              
251             =over 4
252              
253             =item *
254              
255             Robert Krimen <robertkrimen@gmail.com>
256              
257             =item *
258              
259             Yanick Champoux <yanick@cpan.org>
260              
261             =back
262              
263             =head1 COPYRIGHT AND LICENSE
264              
265             This software is copyright (c) 2017 by Robert Krimen.
266              
267             This is free software; you can redistribute it and/or modify it under
268             the same terms as the Perl 5 programming language system itself.
269              
270             =cut