Create a #many_to_pg_array association, for the case where the associated table contains the array with foreign keys pointing to the current table. See associate for options.
# File lib/sequel/plugins/pg_array_associations.rb, line 182 def many_to_pg_array(name, opts=OPTS, &block) associate(:many_to_pg_array, name, opts, &block) end
Create a #pg_array_to_many association, for the case where the current table contains the array with foreign keys pointing to the associated table. See associate for options.
# File lib/sequel/plugins/pg_array_associations.rb, line 189 def pg_array_to_many(name, opts=OPTS, &block) associate(:pg_array_to_many, name, opts, &block) end
Setup the many_to_pg_array-specific datasets, eager loaders, and modification methods.
# File lib/sequel/plugins/pg_array_associations.rb, line 196 def def_many_to_pg_array(opts) name = opts[:name] model = self pk = opts[:eager_loader_key] = opts[:primary_key] ||= model.primary_key opts[:key] = opts.default_key unless opts.has_key?(:key) key = opts[:key] key_column = opts[:key_column] ||= opts[:key] opts[:after_load].unshift(:array_uniq!) if opts[:uniq] slice_range = opts.slice_range opts[:dataset] ||= lambda do opts.associated_dataset.where(Sequel.pg_array_op(opts.predicate_key).contains([send(pk)])) end opts[:eager_loader] ||= proc do |eo| id_map = eo[:id_map] rows = eo[:rows] rows.each do |object| object.associations[name] = [] end klass = opts.associated_class ds = model.eager_loading_dataset(opts, klass.where(Sequel.pg_array_op(opts.predicate_key).overlaps(id_map.keys)), nil, eo[:associations], eo) ds.all do |assoc_record| if pks ||= assoc_record.send(key) pks.each do |pkv| next unless objects = id_map[pkv] objects.each do |object| object.associations[name].push(assoc_record) end end end end if slice_range rows.each{|o| o.associations[name] = o.associations[name][slice_range] || []} end end join_type = opts[:graph_join_type] select = opts[:graph_select] opts[:cartesian_product_number] ||= 1 if opts.include?(:graph_only_conditions) conditions = opts[:graph_only_conditions] graph_block = opts[:graph_block] else conditions = opts[:graph_conditions] conditions = nil if conditions.empty? graph_block = proc do |j, lj, js| Sequel.pg_array_op(Sequel.deep_qualify(j, key_column)).contains([Sequel.deep_qualify(lj, opts.primary_key)]) end if orig_graph_block = opts[:graph_block] pg_array_graph_block = graph_block graph_block = proc do |j, lj, js| Sequel.&(orig_graph_block.call(j,lj,js), pg_array_graph_block.call(j, lj, js)) end end end opts[:eager_grapher] ||= proc do |eo| ds = eo[:self] ds = ds.graph(eager_graph_dataset(opts, eo), conditions, eo.merge(:select=>select, :join_type=>join_type, :qualify=>:deep, :from_self_alias=>ds.opts[:eager_graph][:master]), &graph_block) ds end def_association_dataset_methods(opts) unless opts[:read_only] validate = opts[:validate] array_type = opts[:array_type] ||= :integer adder = opts[:adder] || proc do |o| if array = o.send(key) array << send(pk) else o.send("#{key}=", Sequel.pg_array([send(pk)], array_type)) end o.save(:validate=>validate) || raise(Sequel::Error, "invalid associated object, cannot save") end association_module_private_def(opts._add_method, opts, &adder) remover = opts[:remover] || proc do |o| if (array = o.send(key)) && !array.empty? array.delete(send(pk)) o.save(:validate=>validate) || raise(Sequel::Error, "invalid associated object, cannot save") end end association_module_private_def(opts._remove_method, opts, &remover) clearer = opts[:clearer] || proc do opts.associated_dataset.where(Sequel.pg_array_op(key).contains([send(pk)])).update(key=>Sequel.function(:array_remove, key, send(pk))) end association_module_private_def(opts._remove_all_method, opts, &clearer) def_add_method(opts) def_remove_methods(opts) end end
Setup the pg_array_to_many-specific datasets, eager loaders, and modification methods.
# File lib/sequel/plugins/pg_array_associations.rb, line 295 def def_pg_array_to_many(opts) name = opts[:name] model = self opts[:key] = opts.default_key unless opts.has_key?(:key) key = opts[:key] key_column = opts[:key_column] ||= key opts[:eager_loader_key] = nil opts[:after_load].unshift(:array_uniq!) if opts[:uniq] slice_range = opts.slice_range opts[:dataset] ||= lambda do opts.associated_dataset.where(opts.predicate_key=>send(key).to_a) end opts[:eager_loader] ||= proc do |eo| rows = eo[:rows] id_map = {} pkm = opts.primary_key_method rows.each do |object| object.associations[name] = [] if associated_pks = object.send(key) associated_pks.each do |apk| (id_map[apk] ||= []) << object end end end klass = opts.associated_class ds = model.eager_loading_dataset(opts, klass.where(opts.predicate_key=>id_map.keys), nil, eo[:associations], eo) ds.all do |assoc_record| if objects = id_map[assoc_record.send(pkm)] objects.each do |object| object.associations[name].push(assoc_record) end end end if slice_range rows.each{|o| o.associations[name] = o.associations[name][slice_range] || []} end end join_type = opts[:graph_join_type] select = opts[:graph_select] opts[:cartesian_product_number] ||= 1 if opts.include?(:graph_only_conditions) conditions = opts[:graph_only_conditions] graph_block = opts[:graph_block] else conditions = opts[:graph_conditions] conditions = nil if conditions.empty? graph_block = proc do |j, lj, js| Sequel.pg_array_op(Sequel.deep_qualify(lj, key_column)).contains([Sequel.deep_qualify(j, opts.primary_key)]) end if orig_graph_block = opts[:graph_block] pg_array_graph_block = graph_block graph_block = proc do |j, lj, js| Sequel.&(orig_graph_block.call(j,lj,js), pg_array_graph_block.call(j, lj, js)) end end end opts[:eager_grapher] ||= proc do |eo| ds = eo[:self] ds = ds.graph(eager_graph_dataset(opts, eo), conditions, eo.merge(:select=>select, :join_type=>join_type, :qualify=>:deep, :from_self_alias=>ds.opts[:eager_graph][:master]), &graph_block) ds end def_association_dataset_methods(opts) unless opts[:read_only] validate = opts[:validate] array_type = opts[:array_type] ||= :integer if opts[:save_after_modify] save_after_modify = proc do |obj| obj.save(:validate=>validate) || raise(Sequel::Error, "invalid associated object, cannot save") end end adder = opts[:adder] || proc do |o| opk = o.send(opts.primary_key) if array = send(key) modified!(key) array << opk else send("#{key}=", Sequel.pg_array([opk], array_type)) end save_after_modify.call(self) if save_after_modify end association_module_private_def(opts._add_method, opts, &adder) remover = opts[:remover] || proc do |o| if (array = send(key)) && !array.empty? modified!(key) array.delete(o.send(opts.primary_key)) save_after_modify.call(self) if save_after_modify end end association_module_private_def(opts._remove_method, opts, &remover) clearer = opts[:clearer] || proc do if (array = send(key)) && !array.empty? modified!(key) array.clear save_after_modify.call(self) if save_after_modify end end association_module_private_def(opts._remove_all_method, opts, &clearer) def_add_method(opts) def_remove_methods(opts) end end