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