# File lib/flexirecord.rb, line 181
181:     def initialize(source_class, destination_class, column_info, src_to_dst_attr, dst_to_src_attr=nil)
182:       unless source_class.kind_of? Class and destination_class.kind_of? Class
183:         raise TypeError, "Class expected"
184:       end
185:       @source_class      = source_class
186:       @destination_class = destination_class
187:       if column_info.respond_to? :to_ary
188:         column_info = column_info.to_ary.flatten
189:         unless column_info.length % 2 == 0
190:           raise ArgumentError, "Flattened 'column_info' array contains odd number of elements."
191:         end
192:         @source_columns = column_info[0, column_info.length / 2].collect { |column| column.to_s.dup.freeze }
193:         @destination_columns = column_info[column_info.length / 2, column_info.length / 2].collect { |column| column.to_s.dup.freeze }
194:       elsif column_info.respond_to? :to_str
195:         column_info = column_info.to_str
196:         @source_columns = []
197:         @destination_columns = []
198:         destination_class.primary_columns.each do |column|
199:           @source_columns << "#{column_info}#{column}".freeze
200:           @destination_columns << column
201:         end
202:       else
203:         raise ArgumentError, "Array or String expected"
204:       end
205:       @source_columns.freeze
206:       @destination_columns.freeze
207:       @src_to_dst_attr = src_to_dst_attr ? src_to_dst_attr.to_s.dup.freeze : nil
208:       @dst_to_src_attr = dst_to_src_attr ? dst_to_src_attr.to_s.dup.freeze : nil
209:       # Work at the source_class:
210:       if @src_to_dst_attr
211:         @source_class.set_loader(@src_to_dst_attr) do |source_records, arguments|
212:           unless arguments.empty?
213:             raise ArgumentError, "No extra arguments may be specified for outgoing reference columns."
214:           end
215:           destination_records = @destination_class.select_by_value_set(
216:             @destination_columns,
217:             source_records.collect { |source_record|
218:               @source_columns.collect { |column| source_record[column] }
219:             },
220:             *arguments
221:           )
222:           destination_record_hash = {}
223:           destination_records.each do |destination_record|
224:             destination_record_hash[@destination_columns.collect { |column| destination_record[column] }] = destination_record
225:             if self.one_to_one? and @dst_to_src_attr
226:               destination_record[@dst_to_src_attr] = nil
227:             end
228:           end
229:           source_records.each do |source_record|
230:             destination_record = 
231:               destination_record_hash[@source_columns.collect { |column| source_record[column] }]
232:             source_record[@src_to_dst_attr, *arguments] = destination_record
233:             if destination_record and self.one_to_one? and @dst_to_src_attr
234:               destination_record[@dst_to_src_attr] = source_record
235:             end
236:           end
237:           next destination_records
238:         end
239:         @source_columns.each_index do |column_index|
240:           source_column = @source_columns[column_index]
241:           destination_column = @destination_columns[column_index]
242:           @source_class.set_reader(source_column) do |source_record, arguments|
243:             destination_record = source_record[@src_to_dst_attr]
244:             next destination_record ? destination_record[destination_column] : source_record[source_column]
245:           end
246:           @source_class.set_setter(source_column) do |source_record, value|
247:             source_record.delete_from_cache(@src_to_dst_attr)
248:             source_record[source_column] = value
249:           end
250:         end
251:         if self.one_to_one? and @dst_to_src_attr
252:           @source_class.set_setter(@src_to_dst_attr) do |source_record, value|
253:             old_destination_record = source_record[@src_to_dst_attr]
254:             if old_destination_record
255:               old_destination_record[@dst_to_src_attr] = nil
256:             end
257:             source_record[@src_to_dst_attr] = value
258:             if value
259:               value[@dst_to_src_attr] = source_record
260:             end
261:           end
262:         end
263:       end
264:       # Work at the destination_class:
265:       if @dst_to_src_attr
266:         @destination_class.set_loader(@dst_to_src_attr) do |destination_records, arguments|
267:           unless arguments.empty?
268:             unless arguments[0].respond_to? :to_str
269:               raise "First argument of reader method is not a SQL snippet string."
270:             end
271:             arguments[0] = arguments[0].to_str
272:           end
273:           source_records = @source_class.select_by_value_set(
274:             @source_columns,
275:             destination_records.collect { |destination_record|
276:               @destination_columns.collect { |column| destination_record[column] }
277:             },
278:             *arguments
279:           )
280:           destination_record_hash = {}
281:           destination_records.each do |destination_record|
282:             destination_record_hash[@destination_columns.collect { |column| destination_record[column] }] = destination_record
283:             destination_record[@dst_to_src_attr, *arguments] =
284:               if self.many_to_one?
285:                 FlexiRecord::RecordArray.new(@source_class)
286:               else
287:                 nil
288:               end
289:           end
290:           source_records.each do |source_record|
291:             destination_record = destination_record_hash[@source_columns.collect { |column| source_record[column] }]
292:             if @src_to_dst_attr
293:               source_record[@src_to_dst_attr] = destination_record
294:             end
295:             if destination_record
296:               if self.many_to_one?
297:                 destination_record[@dst_to_src_attr, *arguments] << source_record
298:               else
299:                 destination_record[@dst_to_src_attr, *arguments] = source_record
300:               end
301:             end
302:           end
303:           if self.many_to_one?
304:             destination_records.each do |destination_record|
305:               destination_record[@dst_to_src_attr, *arguments].freeze
306:             end
307:           end
308:           next source_records
309:         end
310:         if self.one_to_one? and @src_to_dst_attr
311:           @destination_class.set_setter(@dst_to_src_attr) do |destination_record, value|
312:             old_source_record = destination_record[@dst_to_src_attr]
313:             if old_source_record
314:               old_source_record[@src_to_dst_attr] = nil
315:             end
316:             destination_record[@dst_to_src_attr] = value
317:             if value
318:               value[@src_to_dst_attr] = destination_record
319:             end
320:           end
321:         end
322:       end
323:       return self
324:     end