File Coverage

blib/lib/KiokuDB/Util.pm
Criterion Covered Total %
statement 30 99 30.3
branch 1 28 3.5
condition 1 11 9.0
subroutine 9 20 45.0
pod 4 9 44.4
total 45 167 26.9


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2              
3             package KiokuDB::Util;
4              
5 21     21   93 use strict;
  21         221  
  21         667  
6 21     21   87 use warnings;
  21         30  
  21         443  
7              
8 21     21   8313 use Path::Class;
  21         642076  
  21         1298  
9              
10 21     21   149 use Carp qw(croak);
  21         35  
  21         953  
11 21     21   92 use Scalar::Util qw(blessed);
  21         40  
  21         798  
12              
13 21     21   165 use namespace::clean;
  21         43  
  21         199  
14              
15 21         266 use Sub::Exporter -setup => {
16             exports => [qw(set weak_set dsn_to_backend import_yaml deprecate)],
17 21     21   3990 };
  21         81  
18              
19             sub weak_set {
20 0     0 1 0 require KiokuDB::Set::Transient;
21 0         0 KiokuDB::Set::Transient->new( set => Set::Object::Weak->new(@_) )
22             }
23              
24             sub set {
25 0     0 1 0 require KiokuDB::Set::Transient;
26 0         0 KiokuDB::Set::Transient->new( set => Set::Object->new(@_) );
27             }
28              
29             my %monikers = (
30             "hash" => "Hash",
31             "bdb" => "BDB",
32             "bdb-gin" => "BDB::GIN",
33             "dbi" => "DBI",
34             "jspon" => "JSPON",
35             "files" => "Files",
36             "couchdb" => "CouchDB",
37             "mongodb" => "MongoDB",
38             );
39              
40             sub _try_json {
41 0     0   0 my $json = shift;
42              
43 0         0 require JSON;
44 0         0 JSON->new->decode($json);
45             }
46              
47             sub dsn_to_backend {
48 52     52 1 186 my ( $dsn, @args ) = @_;
49              
50 52 50       456 if ( my ( $moniker, $rest ) = ( $dsn =~ /^([\w-]+)(?::(.*))?$/ ) ) {
    0          
51 52   33     275 $moniker = $monikers{$moniker} || $moniker;
52 52         156 my $class = "KiokuDB::Backend::$moniker";
53              
54 52         263 Class::MOP::load_class($class);
55 52         6792 return $class->new_from_dsn($rest, @args);
56             } elsif ( my $args = _try_json($dsn) ) {
57 0           my $dsn;
58              
59 0 0         if ( ref $args eq 'ARRAY' ) {
60 0           ( $dsn, $args ) = @$args;
61             }
62              
63 0 0         if ( ref $args eq 'HASH' ) {
64 0   0       $dsn ||= delete $args->{dsn};
65 0           return dsn_to_backend($dsn, %$args, @args);
66             }
67             }
68              
69 0           croak "Malformed DSN: $dsn";
70             }
71              
72             sub load_config {
73 0     0 0   my ( $base ) = @_;
74              
75 0           my $config_file;
76 0 0         if ( $base =~ /\.yml$/ ) {
77 0           $config_file = $base;
78             } else {
79 0           $config_file = dir($base)->file("kiokudb.yml");
80 0           $config_file->openr;
81             }
82              
83              
84 0           require MooseX::YAML;
85 0           MooseX::YAML::LoadFile($config_file);
86             }
87              
88             sub config_to_backend {
89 0     0 0   my ( $config, %args ) = @_;
90              
91 0           my $base = delete($args{base});
92              
93 0           my $backend = $config->{backend};
94              
95 0 0         return $backend if blessed($backend);
96              
97 0           my $backend_class = $backend->{class};
98 0           Class::MOP::load_class($backend_class);
99              
100 0 0         return $backend_class->new_from_dsn_params(
101             ( defined($base) ? ( dir => $base->subdir("data") ) : () ),
102             %$backend,
103             %args,
104             );
105             }
106              
107             sub import_yaml {
108 0     0 1   my ( $kiokudb, @src ) = @_;
109              
110 0           my @objects = load_yaml_files( find_yaml_files(@src) );
111              
112             $kiokudb->txn_do(sub {
113 0     0     my $scope = $kiokudb->new_scope;
114 0           $kiokudb->insert(@objects);
115 0           });
116             }
117              
118             sub find_yaml_files {
119 0     0 0   my ( @src ) = @_;
120              
121 0           my @files;
122              
123 0           foreach my $src ( @src ) {
124 0 0         if ( -d $src ) {
125             dir($src)->recurse( callback => sub {
126 0     0     my $file = shift;
127              
128 0 0 0       if ( -f $file && $file->basename =~ /\.yml$/ ) {
129 0           push @files, $file;
130             }
131 0           });
132             } else {
133 0           push @files, $src;
134             }
135             }
136              
137 0           return @files;
138             }
139              
140             sub load_yaml_files {
141 0     0 0   my ( @files ) = @_;
142              
143 0           my @objects;
144              
145 0           require MooseX::YAML;
146              
147 0           foreach my $file ( @files ) {
148 0           my @data = MooseX::YAML::LoadFile($file);
149              
150 0 0         if ( @data == 1 ) {
151 0 0         unless ( blessed $data[0] ) {
152 0 0         if ( ref $data[0] eq 'ARRAY' ) {
153 0           @data = @{ $data[0] };
  0            
154             } else {
155 0           @data = %{ $data[0] }; # with IDs
  0            
156             }
157             }
158             }
159              
160 0           push @objects, @data;
161             }
162              
163 0           return @objects;
164             }
165              
166             my %seen_deprecation;
167              
168 21     21   35275 use constant HARNESS_ACTIVE => not not $ENV{HARNESS_ACTIVE};
  21         44  
  21         5136  
169              
170             sub deprecate ($$) {
171 0     0 0   if ( HARNESS_ACTIVE ) {
172 0           my ( $version, $reason ) = @_;
173              
174             # parts stolen from Devel::Deprecate, but we're doing version based
175             # deprecation, not date based deprecation
176              
177 0           require KiokuDB;
178              
179 0 0         if ( $KiokuDB::VERSION >= $version ) {
180 0           my ( $package, $filename, $line ) = caller(1);
181 0           my ( undef, undef, undef, $subroutine ) = caller(2);
182              
183 0 0         return if $seen_deprecation{"${filename}:$line"}++; # no need to warn more than once
184              
185 0   0       $subroutine ||= 'n/a';
186 0           my $padding = ' ' x 18;
187 0           $reason =~ s/\n/\n#$padding/g;
188              
189 0           Carp::cluck(<<"END");
190             # DEPRECATION WARNING
191             #
192             # Package: $package
193             # File: $filename
194             # Line: $line
195             # Subroutine: $subroutine
196             #
197             # Reason: $reason
198             END
199             }
200             }
201             }
202              
203             __PACKAGE__
204              
205             __END__
206              
207             =pod
208              
209             =head1 NAME
210              
211             KiokuDB::Util - Utility functions for working with KiokuDB
212              
213             =head1 SYNOPSIS
214              
215             use KiokuDB::Util qw(set weak_set);
216              
217             my $set = set(@objects); # create a transient set
218              
219             my $weak = weak_set(@objects); # to avoid circular refs
220              
221             =head1 DESCRIPTION
222              
223             This module provides various helper functions for working with L<KiokuDB>.
224              
225             =head1 EXPORTS
226              
227             =over 4
228              
229             =item dsn_to_backend $dsn, %args
230              
231             Tries to parse C<$dsn>, load the backend and invoke C<new> on it.
232              
233             Used by L<KiokuDB/connect> and the various command line interfaces.
234              
235             =item set
236              
237             =item weak_set
238              
239             Instantiate a L<Set::Object> or L<Set::Object::Weak> from the arguments, and
240             then creates a L<KiokuDB::Set::Transient> with the result.
241              
242             =item import_yaml $kiokudb, @files_or_dirs
243              
244             Loads YAML files with L<MooseX::YAML> (if given a directory it will be searched
245             recursively for files with a C<.yml> extension are) into the specified KiokuDB
246             directory in a single transaction.
247              
248             The YAML files can contain multiple documents, with each document treated as an
249             object. If the YAML file contains a single non blessed array or hash then that
250             structure will be dereferenced as part of the arguments to C<insert>.
251              
252             Here is an example of an array of objects, and a custom tag alias to ease
253             authoring of the YAML file:
254              
255             %YAML 1.1
256             %TAG ! !MyFoo::
257             ---
258             - !User
259             id: foo
260             real_name: Foo Bar
261             email: foo@myfoo.com
262             password: '{cleartext}test123'
263              
264             You can use a hash to specify custom IDs:
265              
266             %YAML 1.1
267             ---
268             the_id: !Some::Class
269             attr: moose
270              
271             =back
272              
273             =cut
274              
275