File Coverage

blib/lib/Catmandu/Fix/lookup_in_store.pm
Criterion Covered Total %
statement 47 47 100.0
branch 11 12 91.6
condition 6 9 66.6
subroutine 13 13 100.0
pod n/a
total 77 81 95.0


line stmt bran cond sub pod time code
1             package Catmandu::Fix::lookup_in_store;
2              
3 1     1   112066 use Catmandu::Sane;
  1         4  
  1         8  
4              
5             our $VERSION = '1.2020';
6              
7 1     1   457 use Catmandu;
  1         3  
  1         5  
8 1     1   694 use Catmandu::Util::Path qw(as_path);
  1         3  
  1         61  
9 1     1   6 use Catmandu::Util qw(is_value);
  1         2  
  1         40  
10 1     1   6 use Moo;
  1         2  
  1         7  
11 1     1   370 use namespace::clean;
  1         2  
  1         14  
12 1     1   741 use Catmandu::Fix::Has;
  1         3  
  1         7  
13              
14             with 'Catmandu::Fix::Builder';
15              
16             has path => (fix_arg => 1);
17             has store_name => (fix_arg => 1);
18             has bag_name => (fix_opt => 1, init_arg => 'bag');
19             has default => (fix_opt => 1, predicate => 1);
20             has delete => (fix_opt => 1);
21             has store_args => (fix_opt => 'collect');
22             has store => (is => 'lazy', init_arg => undef);
23             has bag => (is => 'lazy', init_arg => undef);
24              
25             sub _build_store {
26 6     6   49 my ($self) = @_;
27 6         13 Catmandu->store($self->store_name, %{$self->store_args});
  6         41  
28             }
29              
30             sub _build_bag {
31 6     6   50 my ($self) = @_;
32 6 50       107 defined $self->bag_name
33             ? $self->store->bag($self->bag_name)
34             : $self->store->bag;
35             }
36              
37             sub _build_fixer {
38 6     6   55 my ($self) = @_;
39              
40 6         97 my $bag = $self->bag;
41 6         12 my $cb;
42              
43 6 100       47 if ($self->delete) {
    100          
44             $cb = sub {
45 3     3   7 my $val = $_[0];
46 3 100 66     63 if (is_value($val) && defined($val = $bag->get($val))) {
47 1         20 return $val;
48             }
49 2         57 return undef, 1, 1;
50 2         11 };
51             }
52             elsif ($self->has_default) {
53 2         6 my $default = $self->default;
54             $cb = sub {
55 3     3   7 my $val = $_[0];
56 3 100 66     62 if (is_value($val) && defined($val = $bag->get($val))) {
57 1         21 return $val;
58             }
59 2         54 $default;
60 2         10 };
61             }
62             else {
63             $cb = sub {
64 2     2   3 my $val = $_[0];
65 2 100 66     47 if (is_value($val) && defined($val = $bag->get($val))) {
66 1         22 return $val;
67             }
68 1         28 return undef, 1, 0;
69 2         13 };
70             }
71              
72 6         28 as_path($self->path)->updater($cb);
73             }
74              
75             1;
76              
77             __END__
78              
79             =pod
80              
81             =head1 NAME
82              
83             Catmandu::Fix::lookup_in_store - change the value of a HASH key or ARRAY index
84             by looking up its value in a store
85              
86             =head1 SYNOPSIS
87              
88             # Lookup in an SQLLite database
89             lookup_in_store(foo.bar, DBI, data_source: "dbi:SQLite:path/data.sqlite")
90              
91             # Lookup in a MongoDB database
92             lookup_in_store(foo.bar, MongoDB, database_name: lookups, bag: mydata)
93              
94             # Lookup in a MongoDB database, using the default bag and a default value when nothing found
95             lookup_in_store(foo.bar, MongoDB, database_name: lookups, default: 'default value')
96              
97             # Lookup in a MongoDB database, using the default bag and delete the foo.bar field when nothing found
98             lookup_in_store(foo.bar, MongoDB, database_name: lookups, delete: 1)
99              
100             # Or, a much faster option: use a named store in a catmandu.yml file
101             #
102             # store:
103             # mydbi:
104             # package: DBI
105             # options:
106             # data_source: "dbi:SQLite:path/data.sqlite"
107             # mymongo:
108             # package: MongoDB
109             # options:
110             # database_name: lookups
111             lookup_in_store(foo.bar, mydbi)
112             lookup_in_store(foo.bar, mymongo, bag: mydata)
113             lookup_in_store(foo.bar, mymongo, default: 'default value')
114             lookup_in_store(foo.bar, mymongo, delete: 1)
115              
116             =head1 DESCRIPTION
117              
118             =head2 lookup_in_store(PATH,STORE[,store_param: store_val, ...][,bag: bag_name][,delete:1][,default:value])
119              
120             Use the lookup_in_store fix to match a field in a record to the "_id" field in
121             a Catmandu::Store of choice. For instance, if a Catmandu::Store contains these
122             records:
123              
124             ---
125             _id: water
126             fr: l'eau
127             de: wasser
128             en: water
129             nl: water
130             ---
131             _id: tree
132             fr: arbre
133             de: baum
134             en: tree
135             nl: boom
136              
137             And you data contains these fields:
138              
139             ---
140             _id: 001
141             tag: tree
142             ---
143             _id: 002
144             tag: water
145              
146             Then, the fix below will lookup a tag in the Catmandu::Store and replace it
147             with the database value:
148              
149             lookup_in_store(tag, DBI, data_source: "dbi:SQLite:path/data.sqlite")
150              
151             The resulting data will contain:
152              
153             ---
154             _id: 001
155             tag:
156             _id: tree
157             fr: arbre
158             de: baum
159             en: tree
160             nl: boom
161             ---
162             _id: 002
163             tag:
164             _id: water
165             fr: l'eau
166             de: wasser
167             en: water
168             nl: water
169              
170             =head1 DATABASE CONNECTIONS
171              
172             For every call to a C<lookup_in_store> a new database connection is created. It
173             is much more effient to used named stores in a C<catmandu.yml> file. This file
174             needs to contain all the connection parameters to the database. E.g.
175              
176             store:
177             mystore:
178             package: MongoDB
179             options:
180             database_name: mydata
181              
182             The C<catmandu.yml> file should be available in the same directory as where the
183             C<catmandu> command is executed. Or, this directory can be set with the C<-L> option:
184              
185             $ catmandu -L /tmp/path convert ...
186              
187             =head1 SEE ALSO
188              
189             L<Catmandu::Fix>, L<Catmandu::Store> , L<Catmandu::Fix::add_to_store>
190              
191             =cut