File Coverage

blib/lib/DBIx/Class/Schema/KiokuDB.pm
Criterion Covered Total %
statement 80 83 96.3
branch 14 26 53.8
condition 2 6 33.3
subroutine 18 18 100.0
pod 0 4 0.0
total 114 137 83.2


line stmt bran cond sub pod time code
1             package DBIx::Class::Schema::KiokuDB;
2             BEGIN {
3 5     5   3449 $DBIx::Class::Schema::KiokuDB::AUTHORITY = 'cpan:NUFFIN';
4             }
5             # ABSTRACT: Hybrid KiokuDB/DBIx::Class::Schema schema support.
6             $DBIx::Class::Schema::KiokuDB::VERSION = '1.23';
7 5     5   37 use strict;
  5         10  
  5         98  
8 5     5   24 use warnings;
  5         9  
  5         139  
9              
10 5     5   24 use Carp qw(croak);
  5         18  
  5         348  
11              
12 5     5   32 use DBI 1.607 ();
  5         139  
  5         109  
13 5     5   25 use DBIx::Class 0.08127 ();
  5         117  
  5         99  
14 5     5   1572 use DBIx::Class::KiokuDB::EntryProxy;
  5         28  
  5         165  
15 5     5   927 use DBIx::Class::ResultSource::Table;
  5         129091  
  5         172  
16              
17 5     5   70 use Scalar::Util qw(weaken refaddr);
  5         10  
  5         309  
18              
19 5     5   35 use namespace::clean;
  5         10  
  5         29  
20              
21 5     5   1257 use base qw(Class::Accessor::Grouped);
  5         10  
  5         3721  
22              
23             __PACKAGE__->mk_group_accessors( inherited => "kiokudb_entries_source_name" );
24              
25             sub kiokudb_handle {
26 22     22 0 66423 my $self = shift;
27              
28 22 50       75 croak "Can't call kiokudb_handle on unconnected schema" unless ref $self;
29              
30 22 100       87 unless ( $self->{kiokudb_handle} ) {
31 1         14 require KiokuDB;
32 1         475 require KiokuDB::Backend::DBI;
33              
34 1 50       35 croak "Can't vivify KiokuDB handle without KiokuDB schema bits. " .
35             "Add __PACKAGE__->define_kiokudb_schema() to your schema class"
36             unless $self->kiokudb_entries_source_name;
37              
38 1         71 my $dir = KiokuDB->new(
39             backend => my $backend = KiokuDB::Backend::DBI->new(
40             connected_schema => $self,
41             ),
42             );
43              
44 1         13 $backend->meta->get_attribute('schema')->_weaken_value($backend); # FIXME proper MOP api?
45              
46             # not weak
47 1         165 $self->{kiokudb_handle} = $dir;
48             }
49              
50 22         119 $self->{kiokudb_handle};
51             }
52              
53             sub _kiokudb_handle {
54 63     63   220 my ( $self, $handle ) = @_;
55              
56 63 50       295 croak "Can't call _kiokudb_handle on unconnected schema" unless ref $self;
57              
58 63 50       1347 croak "Can't vivify KiokuDB handle without KiokuDB schema bits. " .
59             "Add __PACKAGE__->define_kiokudb_schema() to your schema class"
60             unless $self->kiokudb_entries_source_name;
61              
62 63 50       1495 if ( $self->{kiokudb_handle} ) {
63 0 0       0 if ( refaddr($self->{kiokudb_handle}) != refaddr($handle) ) {
64 0         0 croak "KiokuDB directory already registered";
65             }
66             } else {
67 63         255 $self->{kiokudb_handle} = $handle;
68 63         291 weaken($self->{kiokudb_handle});
69             }
70              
71 63         1442 return $handle;
72             }
73              
74             sub define_kiokudb_schema {
75 64     64 0 410 my ( $self, @args ) = @_;
76              
77 64         568 my %args = (
78             schema => $self,
79             entries_table => "entries",
80             gin_index_table => "gin_index",
81             result_class => "DBIx::Class::KiokuDB::EntryProxy",
82             gin_index => 1,
83             @args,
84             );
85              
86 64   33     416 my $entries_source_name = $args{entries_source} ||= $args{entries_table};
87 64   33     323 my $gin_index_source_name = $args{gin_index_source} ||= $args{gin_index_table};
88              
89 64         453 my $entries = $self->define_kiokudb_entries_resultsource(%args);
90              
91 64         225 my $schema = $args{schema};
92              
93 64         473 $schema->register_source( $entries_source_name => $entries );
94 64 50       16468 if ($args{gin_index}) {
95 64         493 my $gin_index = $self->define_kiokudb_gin_index_resultsource(%args);
96 64         274 $schema->register_source( $gin_index_source_name => $gin_index );
97             }
98              
99              
100 64 50       16575 $schema->kiokudb_entries_source_name($entries_source_name)
101             unless $schema->kiokudb_entries_source_name;
102             }
103              
104             sub define_kiokudb_entries_resultsource {
105 64     64 0 371 my ( $self, %args ) = @_;
106              
107 64         795 my $entries = DBIx::Class::ResultSource::Table->new({ name => $args{entries_table} });
108              
109             $entries->add_columns(
110             id => { data_type => "varchar" },
111             data => { data_type => "blob", is_nullable => 0 }, # FIXME longblob for mysql
112             class => { data_type => "varchar", is_nullable => 1 },
113             root => { data_type => "boolean", is_nullable => 0 },
114             tied => { data_type => "char", size => 1, is_nullable => 1 },
115 64 100       3359 @{ $args{extra_entries_columns} || [] },
  64         597  
116             );
117              
118 64         9002 $entries->set_primary_key("id");
119              
120             $entries->sqlt_deploy_callback(sub {
121 6     6   331324 my ($source, $sqlt_table) = @_;
122              
123 6         140 $sqlt_table->extra->{mysql_table_type} = "InnoDB";
124              
125 6 50       208 if ( $source->schema->storage->sqlt_type eq 'MySQL' ) {
126 0         0 $sqlt_table->get_field('data')->data_type('longblob');
127             }
128 64         9428 });
129              
130 64         2562 $entries->result_class($args{result_class});
131              
132 64         1427 return $entries;
133             }
134              
135             sub define_kiokudb_gin_index_resultsource {
136 64     64 0 410 my ( $self, %args ) = @_;
137              
138 64         395 my $gin_index = DBIx::Class::ResultSource::Table->new({ name => $args{gin_index_table} });
139              
140 64         2238 $gin_index->add_columns(
141             id => { data_type => "varchar", is_foreign_key => 1 },
142             value => { data_type => "varchar" },
143             );
144              
145 64         3828 $gin_index->add_relationship('entry_ids', $args{entries_source}, { 'foreign.id' => 'self.id' });
146              
147             $gin_index->sqlt_deploy_callback(sub {
148 6     6   4997 my ($source, $sqlt_table) = @_;
149              
150              
151 6         104 $sqlt_table->extra->{mysql_table_type} = "InnoDB";
152              
153 6 50       176 $sqlt_table->add_index( name => 'gin_index_ids', fields => ['id'] )
154             or die $sqlt_table->error;
155              
156 6 50       3205 $sqlt_table->add_index( name => 'gin_index_values', fields => ['value'] )
157             or die $sqlt_table->error;
158 64         5007 });
159              
160 64         1060 return $gin_index;
161             }
162              
163             # ex: set sw=4 et:
164              
165             __PACKAGE__
166              
167             __END__
168              
169             =pod
170              
171             =encoding UTF-8
172              
173             =head1 NAME
174              
175             DBIx::Class::Schema::KiokuDB - Hybrid KiokuDB/DBIx::Class::Schema schema support.
176              
177             =head1 VERSION
178              
179             version 1.23
180              
181             =head1 SYNOPSIS
182              
183             Load this component into the schema:
184              
185             package MyApp::DB;
186             use base qw(DBIx::Class::Schema);
187              
188             __PACKAGE__->load_components(qw(Schema::KiokuDB));
189              
190             __PAKCAGE__->load_namespaces;
191              
192             Then load the L<DBIx::Class::KiokuDB> component into every table that wants to
193             refer to arbitrary KiokuDB objects:
194              
195             package MyApp::DB::Result::Album;
196             use base qw(DBIx::Class::Core);
197              
198             __PACKAGE__->load_components(qw(KiokuDB));
199              
200             __PACKAGE__->table('album');
201              
202             __PACKAGE__->add_columns(
203             id => { data_type => "integer" },
204             title => { data_type => "varchar" },
205              
206             # the foreign key for the KiokuDB object:
207             metadata => { data_type => "varchar" },
208             );
209              
210             __PACKAGE__->set_primary_key('id');
211              
212             # enable a KiokuDB rel on the column:
213             __PACKAGE__->kiokudb_column('metadata');
214              
215             Connect to the DSN:
216              
217             my $dir = KiokuDB->connect(
218             'dbi:SQLite:dbname=:memory:',
219             schema => "MyApp::DB",
220             create => 1,
221             );
222              
223             # get the connect DBIC schema instance
224             my $schema = $dir->backend->schema;
225              
226             Then you can freely refer to KiokuDB objects from your C<Album> class:
227              
228             $dir->txn_do(scope => 1, body => sub {
229              
230             $schema->resultset("Album")->create({
231             title => "Blah blah",
232             metadata => $any_object,
233             });
234             });
235              
236             =head1 DESCRIPTION
237              
238             This class provides the schema definition support code required for integrating
239             an arbitrary L<DBIx::Class::Schema> with L<KiokuDB::Backend::DBI>.
240              
241             =head2 REUSING AN EXISTING DBIx::Class SCHEMA
242              
243             The example in the Synopis assumes that you want to first set up a
244             L<KiokuDB> and than link that to some L<DBIx::Class> classes. Another
245             use case is that you already have a configured L<DBIx::Class> Schema
246             and want to tack L<KiokuDB> onto it.
247              
248             The trick here is to make sure to load the L<KiokuDB> schema using
249             C<< __PACKAGE__->define_kiokudb_schema() >> in your Schema class:
250              
251             package MyApp::DB;
252             use base qw(DBIx::Class::Schema);
253              
254             __PACKAGE__->load_components(qw(Schema::KiokuDB));
255             __PACKAGE__->define_kiokudb_schema();
256              
257             __PAKCAGE__->load_namespaces;
258              
259             You can now get the L<KiokuDB> directory handle like so:
260              
261             my $dir = $schema->kiokudb_handle;
262              
263             For a complete example take a look at F<t/autovivify_handle.t>.
264              
265             =head1 USAGE AND LIMITATIONS
266              
267             L<KiokuDB> managed objects may hold references to row objects, resultsets
268             (treated as saved searches, or results or cursor state is saved), result source
269             handles, and the schema.
270              
271             Foreign L<DBIx::Class> objects, that is ones that originated from a schema that
272             isn't the underlying schema are currently not supported, but this limitation
273             may be lifted in the future.
274              
275             All DBIC operations which may implicitly cause a lookup of a L<KIokuDB> managed
276             object require live object scope management, just as normal.
277              
278             It is reccomended to use L<KiokuDB/txn_do> because that will invoke the
279             appropriate transaction hooks on both layers, as opposed to just in
280             L<DBIx::Class>.
281              
282             =head1 SEE ALSO
283              
284             L<DBIx::Class::KiokuDB>, L<KiokuDB::Backend::DBI>.
285              
286             =for Pod::Coverage define_kiokudb_entries_resultsource
287             define_kiokudb_gin_index_resultsource
288             define_kiokudb_schema
289             kiokudb_handle
290              
291             =head1 AUTHOR
292              
293             Yuval Kogman <nothingmuch@woobling.org>
294              
295             =head1 COPYRIGHT AND LICENSE
296              
297             This software is copyright (c) 2014 by Yuval Kogman, Infinity Interactive.
298              
299             This is free software; you can redistribute it and/or modify it under
300             the same terms as the Perl 5 programming language system itself.
301              
302             =cut