]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/Application/Storage/CDBI.pm
added super-fast fieldmap builder and magical (though slightly untested) nodeset...
[working/Evergreen.git] / Open-ILS / src / perlmods / OpenILS / Application / Storage / CDBI.pm
1 package OpenILS::Application::Storage::CDBI;
2 use vars qw/@ISA/;
3 use Class::DBI;
4 use base qw/Class::DBI/;
5
6 use OpenILS::Utils::Fieldmapper;
7
8 our $VERSION = 1;
9
10
11 use OpenILS::Application::Storage::CDBI::actor;
12 use OpenILS::Application::Storage::CDBI::asset;
13 use OpenILS::Application::Storage::CDBI::biblio;
14 use OpenILS::Application::Storage::CDBI::metabib;
15
16 sub child_init {
17         my $self = shift;
18
19         __PACKAGE__->set_sql( 'OILSFastSearch', <<"     SQL", 'Main');
20                 SELECT  %s
21                   FROM  %s
22                   WHERE %s = ?
23         SQL
24
25         __PACKAGE__->set_sql( 'OILSFastOrderedSearch', <<"      SQL", 'Main');
26                 SELECT  %s
27                   FROM  %s
28                   WHERE %s = ?
29                   ORDER BY %s
30         SQL
31
32         $self->SUPER::child_init(@_);
33
34 }
35
36 sub fast_flesh_sth {
37         my $class = shift;
38         $class = ref($class) || $class;
39
40         my $field = shift;
41         my $value = shift;
42         my $order = shift;
43
44         if (!(defined($order) and ref($order) and ref($order) eq 'HASH')) {
45                 if (defined($value) and ref($order) and ref($order) eq 'HASH') {
46                         $order = $value;
47                         $value = $field;
48                         $field = $class->primary_column;
49                 } else {
50                         $order = { order_by => 'id' }
51                 }
52         }
53
54         unless (defined $value) {
55                 $value = $field;
56                 $field = $class->primary_column;
57         }
58
59         my $fm_class = 'Fieldmapper::'.$class;
60         my $field_list = join ',', $class->columns('All');
61         
62         warn " !!-> field list for OILSFastOrderedSearch is '$field_list'";
63
64         my $sth = $class->sql_OILSFastOrderedSearch( $field_list, $class->table, $field, $order->{order_by});
65         $sth->execute($value);
66         return $sth;
67 }
68
69 sub fast_flesh {
70         my $self = shift;
71         return map $class->construct($_), $self->fast_flesh_sth(@_)->fetchall_hash;
72 }
73
74 sub fast_fieldmapper {
75         my $self = shift;
76         my $class = ref($self) || $self;
77         my $fm_class = 'Fieldmapper::'.$class;
78         my @fms;
79         for my $hash ($self->fast_flesh_sth(@_)->fetchall_hash) {
80                 my $fm = $fm_class->new;
81                 for my $field ( keys %$hash ) {
82                         $fm->$field( $$hash{$field} );
83                 }
84                 push @fms, $fm;
85         }
86         return @fms;
87 }
88
89 sub retrieve {
90         my $self = shift;
91         my $arg = shift;
92         if (ref($arg) and UNIVERSAL::isa($arg => 'Fieldmapper')) {
93                 $arg = $arg->id;
94         }
95         return $self->SUPER::retrieve("$arg");
96 }
97
98 sub to_fieldmapper {
99         my $obj = shift;
100         my $class = ref($obj) || $obj;
101
102         my $fm_class = 'Fieldmapper::'.$class;
103         my $fm = $fm_class->new;
104
105         if (ref($obj)) {
106                 for my $field ( $fm->real_fields ) {
107                         $fm->$field( $obj->$field );
108                 }
109         }
110
111         return $fm;
112 }
113
114 sub create {
115         my $self = shift;
116         my $arg = shift;
117
118         if (ref($arg) and UNIVERSAL::isa($arg => 'Fieldmapper')) {
119                 return $self->create_from_fieldmapper($arg,@_);
120         }
121
122         return $self->SUPER::create($arg,@_);
123 }
124
125 sub create_from_fieldmapper {
126         my $obj = shift;
127         my $fm = shift;
128         my @params = @_;
129
130         my $class = ref($obj) || $obj;
131
132         if (ref $fm) {
133                 my %hash = map { defined $fm->$_ ?
134                                         ($_ => $fm->$_) :
135                                         ()
136                                 } $fm->real_fields;
137                 return $class->create( \%hash, @params );
138         } else {
139                 return undef;
140         }
141 }
142
143 sub update {
144         my $self = shift;
145         my $arg = shift;
146
147         if (ref($arg) and UNIVERSAL::isa($arg => 'Fieldmapper')) {
148                 $self = $self->modify_from_fieldmapper($arg);
149         }
150
151         $self->SUPER::update;
152         return $self;
153 }
154
155 sub delete {
156         my $self = shift;
157         my $arg = shift;
158
159         if (ref($arg) and UNIVERSAL::isa($arg => 'Fieldmapper')) {
160                 $self = $self->retrieve($arg);
161         }
162
163         $self->SUPER::delete;
164         return $arg;
165 }
166
167 sub modify_from_fieldmapper {
168         my $obj = shift;
169         my $fm = shift;
170
171         my $class = ref($obj) || $obj;
172
173         if (!ref($obj)) {
174                 $obj = $class->retieve($fm);
175                 return undef unless ($obj);
176         }
177
178         my %hash = map { defined $fm->$_ ?
179                                 ($_ => $fm->$_) :
180                                 ()
181                         } $fm->real_fields;
182
183         my $au = $obj->autoupdate;
184         $obj->autoupdate(0);
185         
186         for my $field ( keys %hash ) {
187                 $obj->$field( $hash{$field} );
188         }
189
190         $obj->autoupdate($au);
191
192         return $obj;
193 }
194
195
196
197 #-------------------------------------------------------------------------------
198 asset::copy->has_a( call_number => 'asset::call_number' );
199 asset::copy->might_have( metadata => 'asset::copy_metadata' );
200 #-------------------------------------------------------------------------------
201 asset::copy_metadata->might_have( copy => 'asset::copy' );
202 #asset::copy_metadata->has_a( ciruclating_location => 'actor::org_unit');
203 #asset::copy_metadata->has_a( hold_radius => 'actor::org_unit_type');
204 #-------------------------------------------------------------------------------
205 asset::call_number->has_a( record => 'biblio::record_entry' );
206 asset::call_number->has_many( copies => 'asset::copy' );
207 #-------------------------------------------------------------------------------
208
209
210 #-------------------------------------------------------------------------------
211 biblio::record_note->has_a( record => 'biblio::record_entry' );
212 #-------------------------------------------------------------------------------
213 biblio::record_entry->has_many( notes => 'biblio::record_note' );
214 biblio::record_entry->has_many( nodes => 'biblio::record_node', { order_by => 'intra_doc_id' } );
215 biblio::record_entry->has_many( call_numbers => 'asset::call_number' );
216
217 # should we have just one field entry per class for each record???? (xslt vs xpath)
218 #biblio::record_entry->has_a( title_field_entries => 'metabib::title_field_entry' );
219 #biblio::record_entry->has_a( author_field_entries => 'metabib::author_field_entry' );
220 #biblio::record_entry->has_a( subject_field_entries => 'metabib::subject_field_entry' );
221 #biblio::record_entry->has_a( keyword_field_entries => 'metabib::keyword_field_entry' );
222 #-------------------------------------------------------------------------------
223 biblio::record_node->has_a( owner_doc => 'biblio::record_entry' );
224 #biblio::record_node->has_a(
225 #       parent_node     => 'biblio::record_node::subnode',
226 #       inflate         => sub { return biblio::record_node::subnode::_load(@_) }
227 #);
228 #-------------------------------------------------------------------------------
229
230 #-------------------------------------------------------------------------------
231 #metabib::metarecord->has_a( master_record => 'biblio::record_entry' );
232 #-------------------------------------------------------------------------------
233 #metabib::title_field_entry->has_a( field => 'config::metabib_field_map' );
234 #-------------------------------------------------------------------------------
235 #metabib::author_field_entry->has_a( field => 'config::metabib_field_map' );
236 #-------------------------------------------------------------------------------
237 #metabib::subject_field_entry->has_a( field => 'config::metabib_field_map' );
238 #-------------------------------------------------------------------------------
239 #metabib::keyword_field_entry->has_a( field => 'config::metabib_field_map' );
240 #-------------------------------------------------------------------------------
241
242
243 # should we have just one field entry per class for each record???? (xslt vs xpath)
244 #metabib::title_field_entry_source_map->has_a( field_entry => 'metabib::title_field_entry' );
245 #metabib::title_field_entry_source_map->has_a( source_record => 'biblio::record_entry' );
246 #-------------------------------------------------------------------------------
247 #metabib::subject_field_entry_source_map->has_a( field_entry => 'metabib::subject_field_entry' );
248 #metabib::subject_field_entry_source_map->has_a( source_record => 'biblio::record_entry' );
249 #-------------------------------------------------------------------------------
250 #metabib::author_field_entry_source_map->has_a( field_entry => 'metabib::author_field_entry' );
251 #metabib::author_field_entry_source_map->has_a( source_record => 'biblio::record_entry' );
252 #-------------------------------------------------------------------------------
253 #metabib::keyword_field_entry_source_map->has_a( field_entry => 'metabib::keyword_field_entry' );
254 #metabib::keyword_field_entry_source_map->has_a( source_record => 'biblio::record_entry' );
255 #-------------------------------------------------------------------------------
256
257
258 1;