asset setup
[Evergreen.git] / Open-ILS / src / perlmods / OpenILS / Application / Storage / CDBI.pm
1 package OpenILS::Application::Storage::CDBI;
2 use base qw/Class::DBI/;
3 use Class::DBI;
4
5 use OpenILS::Application::Storage::CDBI::config;
6 use OpenILS::Application::Storage::CDBI::actor;
7 use OpenILS::Application::Storage::CDBI::asset;
8 use OpenILS::Application::Storage::CDBI::biblio;
9 use OpenILS::Application::Storage::CDBI::metabib;
10
11 use OpenILS::Utils::Fieldmapper;
12 use OpenSRF::Utils::Logger;
13
14 our $VERSION;
15 my $log = 'OpenSRF::Utils::Logger';
16
17 sub child_init {
18         my $self = shift;
19
20         $log->debug("Creating ImaDBI Querys", DEBUG);
21         __PACKAGE__->set_sql( 'OILSFastSearch', <<"     SQL", 'Main');
22                 SELECT  %s
23                   FROM  %s
24                   WHERE %s = ?
25         SQL
26
27         __PACKAGE__->set_sql( 'OILSFastOrderedSearchLike', <<"  SQL", 'Main');
28                 SELECT  %s
29                   FROM  %s
30                   WHERE %s ~ ?
31                   ORDER BY %s
32         SQL
33
34         __PACKAGE__->set_sql( 'OILSFastOrderedSearch', <<"      SQL", 'Main');
35                 SELECT  %s
36                   FROM  %s
37                   WHERE %s = ?
38                   ORDER BY %s
39         SQL
40
41         $log->debug("Calling Driver child_init", DEBUG);
42         $self->SUPER::child_init(@_);
43
44 }
45
46 sub fast_flesh_sth {
47         my $class = shift;
48         $class = ref($class) || $class;
49
50         my $field = shift;
51         my $value = shift;
52         my $order = shift;
53         my $like = shift;
54
55
56         if (!(defined($order) and ref($order) and ref($order) eq 'HASH')) {
57                 if (defined($value) and ref($value) and ref($value) eq 'HASH') {
58                         $order = $value;
59                         $value = undef;
60                 } else {
61                         $order = { order_by => $class->columns('Primary') }
62                 }
63         }
64
65         unless (defined $value) {
66                 $value = $field;
67                 $field = $class->primary_column;
68         }
69
70         unless (defined $field) {
71                 $field = $class->primary_column;
72         }
73
74         unless ($order->{order_by}) {
75                 $order = { order_by => $class->columns('Primary') }
76         }
77
78         my $fm_class = 'Fieldmapper::'.$class;
79         my $field_list = join ',', $class->columns('All');
80         
81         my $sth;
82         if (!$like) {
83                 $sth = $class->sql_OILSFastOrderedSearch( $field_list, $class->table, $field, $order->{order_by});
84         } else {
85                 $sth = $class->sql_OILSFastOrderedSearchLike( $field_list, $class->table, $field, $order->{order_by});
86         }
87         $sth->execute($value);
88         return $sth;
89 }
90
91 sub fast_flesh {
92         my $self = shift;
93         return map $class->construct($_), $self->fast_flesh_sth(@_)->fetchall_hash;
94 }
95
96 sub fast_fieldmapper {
97         my $self = shift;
98         my $id = shift;
99         my $col = shift;
100         my $like = shift;
101         my $class = ref($self) || $self;
102         my $fm_class = 'Fieldmapper::'.$class;
103         my @fms;
104         $log->debug("fast_fieldmapper() ==> Retrieving $fm_class", INTERNAL);
105         for my $hash ($self->fast_flesh_sth( $col, "$id", { order_by => $col }, $like )->fetchall_hash) {
106                 my $fm = $fm_class->new;
107                 for my $field ( $fm_class->real_fields ) {
108                         $fm->$field( $$hash{$field} );
109                 }
110                 push @fms, $fm;
111         }
112         return @fms;
113 }
114
115 sub retrieve {
116         my $self = shift;
117         my $arg = shift;
118         if (ref($arg) and UNIVERSAL::isa($arg => 'Fieldmapper')) {
119                 $arg = $arg->id;
120         }
121         $log->debug("Retrieving $self with $arg", INTERNAL);
122         my $rec =  $self->SUPER::retrieve("$arg");
123         unless ($rec) {
124                 $log->debug("Could not retrieve $self with $arg!", DEBUG);
125                 return undef;
126         }
127         return $rec;
128 }
129
130 sub to_fieldmapper {
131         my $obj = shift;
132         my $class = ref($obj) || $obj;
133
134         my $fm_class = 'Fieldmapper::'.$class;
135         my $fm = $fm_class->new;
136
137         if (ref($obj)) {
138                 for my $field ( $fm->real_fields ) {
139                         $fm->$field( $obj->$field );
140                 }
141         }
142
143         return $fm;
144 }
145
146 sub create {
147         my $self = shift;
148         my $arg = shift;
149
150         $log->debug("\$arg is $arg (".ref($arg).")",DEBUG);
151
152         if (ref($arg) and UNIVERSAL::isa($arg => 'Fieldmapper')) {
153                 return $self->create_from_fieldmapper($arg,@_);
154         }
155
156         return $self->SUPER::create($arg,@_);
157 }
158
159 sub create_from_fieldmapper {
160         my $obj = shift;
161         my $fm = shift;
162         my @params = @_;
163
164         $log->debug("Creating node of type ".ref($fm), DEBUG);
165
166         my $class = ref($obj) || $obj;
167
168         if (ref $fm) {
169                 my %hash = map { defined $fm->$_ ?
170                                         ($_ => $fm->$_) :
171                                         ()
172                                 } $fm->real_fields;
173
174                 if ($class->find_column( 'last_xact_id' )) {
175                         my $xact_id = $class->current_xact_id;
176                         throw Error unless ($xact_id);
177                         $hash{last_xact_id} = $xact_id;
178                 }
179
180                 return $class->create( \%hash, @params );
181         } else {
182                 return undef;
183         }
184 }
185
186 sub delete {
187         my $self = shift;
188         my $arg = shift;
189
190         my $class = ref($self) || $self;
191
192         if (ref($arg) and UNIVERSAL::isa($arg => 'Fieldmapper')) {
193                 $self = $self->retrieve($arg);
194                 unless (defined $self) {
195                         $log->debug("ARG! Couldn't retrieve record ".$arg->id, DEBUG);
196                         throw OpenSRF::EX::WARN ("ARG! Couldn't retrieve record ");
197                 }
198         }
199
200         if ($class->find_column( 'last_xact_id' )) {
201                 my $xact_id = $self->current_xact_id;
202                 throw Error unless ($xact_id);
203                 $self->last_xact_id( $class->current_xact_id );
204                 $self->SUPER::update;
205         }
206
207         $self->SUPER::delete;
208         return 1;
209 }
210
211 sub update {
212         my $self = shift;
213         my $arg = shift;
214
215         $log->debug("Attempting to update using $arg", DEBUG) if ($arg);
216
217         if (ref($arg) and UNIVERSAL::isa($arg => 'Fieldmapper')) {
218                 $self = $self->modify_from_fieldmapper($arg);
219                 $log->debug("Modification of $self seems to have failed....", DEBUG);
220                 return undef unless (defined $self);
221         }
222
223         $log->debug("Calling Class::DBI->update on modified object $self", DEBUG);
224         return $self->SUPER::update if ($self->is_changed);
225         return 0;
226 }
227
228 sub modify_from_fieldmapper {
229         my $obj = shift;
230         my $fm = shift;
231
232         $log->debug("Modifying object using fieldmapper", DEBUG);
233
234         my $class = ref($obj) || $obj;
235
236         if (!ref($obj)) {
237                 $obj = $class->retrieve($fm);
238                 unless ($obj) {
239                         $log->debug("Rretrieve using $fm (".$fm->id.") failed!", ERROR);
240                         throw OpenSRF::EX::WARN ("No $class with id of ".$fm->id."!!");
241                 }
242
243         }
244
245         my %hash = map { defined $fm->$_ ?
246                                 ($_ => $fm->$_) :
247                                 ()
248                         } $fm->real_fields;
249
250         my $au = $obj->autoupdate;
251         $obj->autoupdate(0);
252         
253         for my $field ( keys %hash ) {
254                 $obj->$field( $hash{$field} ) if ($obj->$field ne $hash{$field});
255                 $log->debug("Setting field $field on $obj to $hash{$field}",INTERNAL);
256         }
257
258         if ($class->find_column( 'last_xact_id' ) and $obj->is_changed) {
259                 my $xact_id = $obj->current_xact_id;
260                 throw Error unless ($xact_id);
261                 $obj->last_xact_id( $xact_id );
262         } else {
263                 $obj->autoupdate($au)
264         }
265
266         return $obj;
267 }
268
269
270
271 sub import {
272         return if ($VERSION);
273         #-------------------------------------------------------------------------------
274         actor::user->has_a( home_ou => 'actor::org_unit' );
275         #actor::org_unit->has_a( address => 'actor::address' );
276         #-------------------------------------------------------------------------------
277         actor::org_unit->has_many( users => 'actor::user' );
278         actor::org_unit->has_a( parent_ou => 'actor::org_unit' );
279         actor::org_unit->has_a( ou_type => 'actor::org_unit_type' );
280         #actor::org_unit->has_a( address => 'actor::address' );
281         #-------------------------------------------------------------------------------
282
283         #-------------------------------------------------------------------------------
284         asset::copy_note->has_a( owning_copy => 'asset::copy' );
285         #-------------------------------------------------------------------------------
286         asset::copy->has_a( call_number => 'asset::call_number' );
287         asset::copy->has_many( notes => 'asset::copy_note' );
288         asset::copy->has_a( creator => 'actor::user' );
289         asset::copy->has_a( editor => 'actor::user' );
290         #asset::copy->might_have( metadata => 'asset::copy_metadata' );
291         #-------------------------------------------------------------------------------
292         asset::call_number_note->has_a( owning_call_number => 'asset::call_number' );
293         #-------------------------------------------------------------------------------
294         asset::call_number->has_a( record => 'biblio::record_entry' );
295         asset::call_number->has_many( copies => 'asset::copy' );
296         asset::call_number->has_many( notes => 'asset::call_number_note' );
297         asset::call_number->has_a( creator => 'actor::user' );
298         asset::call_number->has_a( editor => 'actor::user' );
299         #-------------------------------------------------------------------------------
300         
301
302         #-------------------------------------------------------------------------------
303         biblio::record_note->has_a( record => 'biblio::record_entry' );
304         #-------------------------------------------------------------------------------
305         biblio::record_mods->is_a( id => 'biblio::record_entry' );
306         #-------------------------------------------------------------------------------
307         biblio::record_marc->is_a( id => 'biblio::record_entry' );
308         #-------------------------------------------------------------------------------
309         biblio::record_entry->has_a( creator => 'actor::user' );
310         biblio::record_entry->has_a( editor => 'actor::user' );
311         biblio::record_entry->might_have( mods_entry => 'biblio::record_mods' => qw/mods/ );
312         biblio::record_entry->might_have( marc_entry => 'biblio::record_marc' => qw/marc/ );
313         biblio::record_entry->has_many( notes => 'biblio::record_note' );
314         biblio::record_entry->has_many( nodes => 'biblio::record_node', { order_by => 'intra_doc_id' } );
315         biblio::record_entry->has_many( call_numbers => 'asset::call_number' );
316         
317         # should we have just one field entry per class for each record???? (xslt vs xpath)
318         #biblio::record_entry->has_a( title_field_entries => 'metabib::title_field_entry' );
319         #biblio::record_entry->has_a( author_field_entries => 'metabib::author_field_entry' );
320         #biblio::record_entry->has_a( subject_field_entries => 'metabib::subject_field_entry' );
321         #biblio::record_entry->has_a( keyword_field_entries => 'metabib::keyword_field_entry' );
322         #-------------------------------------------------------------------------------
323         biblio::record_node->has_a( owner_doc => 'biblio::record_entry' );
324         #biblio::record_node->has_a(
325         #       parent_node     => 'biblio::record_node::subnode',
326         #       inflate         => sub { return biblio::record_node::subnode::_load(@_) }
327         #);
328         #-------------------------------------------------------------------------------
329         
330         #-------------------------------------------------------------------------------
331         metabib::full_rec->has_a( record => 'biblio::record_entry' );
332         #-------------------------------------------------------------------------------
333         metabib::metarecord->has_a( master_record => 'biblio::record_entry' );
334         metabib::metarecord->has_many( source_records => [ 'metabib::metarecord_source_map' => 'source_record'] );
335         #-------------------------------------------------------------------------------
336         metabib::title_field_entry->has_many( source_records => [ 'metabib::title_field_entry_source_map' => 'source_record'] );
337         metabib::title_field_entry->has_a( field => 'config::metabib_field' );
338         #-------------------------------------------------------------------------------
339         metabib::author_field_entry->has_many( source_records => [ 'metabib::author_field_entry_source_map' => 'source_record'] );
340         metabib::author_field_entry->has_a( field => 'config::metabib_field' );
341         #-------------------------------------------------------------------------------
342         metabib::subject_field_entry->has_many( source_records => [ 'metabib::title_field_entry_source_map' => 'source_record'] );
343         metabib::subject_field_entry->has_a( field => 'config::metabib_field' );
344         #-------------------------------------------------------------------------------
345         metabib::keyword_field_entry->has_many( source_records => [ 'metabib::keyword_field_entry_source_map' => 'source_record'] );
346         metabib::keyword_field_entry->has_a( field => 'config::metabib_field' );
347         #-------------------------------------------------------------------------------
348         metabib::metarecord_source_map->has_a( metarecord => 'metabib::metarecord' );
349         metabib::metarecord_source_map->has_a( source_record => 'biblio::record_entry' );
350         #-------------------------------------------------------------------------------
351
352
353         # should we have just one field entry per class for each record???? (xslt vs xpath)
354         metabib::title_field_entry_source_map->has_a( field_entry => 'metabib::title_field_entry' );
355         metabib::title_field_entry_source_map->has_a( source_record => 'biblio::record_entry' );
356         metabib::title_field_entry_source_map->has_a( metarecord => 'metabib::metarecord' );
357         #-------------------------------------------------------------------------------
358         metabib::subject_field_entry_source_map->has_a( field_entry => 'metabib::subject_field_entry' );
359         metabib::subject_field_entry_source_map->has_a( source_record => 'biblio::record_entry' );
360         metabib::subject_field_entry_source_map->has_a( metarecord => 'metabib::metarecord' );
361         #-------------------------------------------------------------------------------
362         metabib::author_field_entry_source_map->has_a( field_entry => 'metabib::author_field_entry' );
363         metabib::author_field_entry_source_map->has_a( source_record => 'biblio::record_entry' );
364         metabib::author_field_entry_source_map->has_a( metarecord => 'metabib::metarecord' );
365         #-------------------------------------------------------------------------------
366         metabib::keyword_field_entry_source_map->has_a( field_entry => 'metabib::keyword_field_entry' );
367         metabib::keyword_field_entry_source_map->has_a( source_record => 'biblio::record_entry' );
368         metabib::keyword_field_entry_source_map->has_a( metarecord => 'metabib::metarecord' );
369         #-------------------------------------------------------------------------------
370         $VERSION = 1;
371 }
372
373
374 1;