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