File: lookup_in_store.pm

package info (click to toggle)
libcatmandu-perl 1.2024-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 3,552 kB
  • sloc: perl: 17,037; makefile: 24; sh: 1
file content (191 lines) | stat: -rw-r--r-- 4,619 bytes parent folder | download
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