lib/spiderfw/model/mappers/db_mapper.rb in spiderfw-0.5.10 vs lib/spiderfw/model/mappers/db_mapper.rb in spiderfw-0.5.11

- old
+ new

@@ -84,12 +84,14 @@ values = {} obj.no_autoload do @model.each_element do |element| next if !mapped?(element) || element.integrated? next if save_mode == :update && !obj.element_modified?(element) - if (save_mode == :insert && element.attributes[:autoincrement] && !schema.attributes(element.name)[:autoincrement]) - obj.set(element.name, @storage.sequence_next(schema.sequence(element.name))) + if (save_mode == :insert) + if element.attributes[:autoincrement] && !schema.attributes(element.name)[:autoincrement] + obj.set(element.name, @storage.sequence_next(schema.sequence(element.name))) + end end if (!element.multiple?) next if (save_mode == :update && element.primary_key?) next if (element.model? && !schema.has_foreign_fields?(element.name)) next if (element.model? && (!(element_val = obj.get(element)) || !obj.get(element).primary_keys_set?)) @@ -330,23 +332,23 @@ elements.each do |el| element = @model.elements[el.to_sym] next if !element || !element.type || element.integrated? if !element.model? field = schema.field(el) + primary_keys << field if model_pks.include?(el) unless seen_fields[field.name] keys << field - primary_keys << field if model_pks.include?(el) seen_fields[field.name] = true end elsif !element.attributes[:junction] if schema.has_foreign_fields?(el) element.model.primary_keys.each do |key| field = schema.foreign_key_field(el, key.name) raise "Can't find a foreign key field for key #{key.name} of element #{el} of model #{@model}" unless field + primary_keys << field if model_pks.include?(el) unless seen_fields[field.name] keys << field - primary_keys << field if model_pks.include?(el) seen_fields[field.name] = true end end end sub_request = query.request[element.name] @@ -407,11 +409,11 @@ joins = prepare_joins(joins) return nil if (keys.empty?) return { :query_type => :select, :keys => keys, - :primary_keys => primary_keys, + :primary_keys => primary_keys.uniq, :tables => tables, :condition => condition, :joins => joins, :order => order, :offset => query.offset, @@ -478,28 +480,44 @@ joins = options[:joins] || [] remaining_condition = Condition.new # TODO: implement cond[:conj] = condition.conjunction.to_s cond[:values] = [] - # find out which elements have non nil conditions to figure out joins - def get_not_nil(model, condition, not_nil) - condition.all_each_with_comparison do |k, v, comp| + + + def get_join_info(model, condition) + join_info = {} + condition.each_with_comparison do |k, v, comp| next unless k.respond_to?(:to_sym) element = model.elements[k.to_sym] next unless element next unless model.mapper.mapped?(element) next unless element.model? - not_nil[k] = {} if !v.nil? || comp != '=' - get_not_nil(element.model, v, not_nil[k]) if v.is_a?(Condition) + join_info[k.to_s] = true if !v.nil? || comp != '=' + if v.is_a?(Spider::Model::Condition) + el_join_info = get_join_info(element.model, v) + el_join_info.each do |jk, jv| + join_info["#{k}.#{jk}"] = jv + end + end end + condition.subconditions.each do |sub_cond| + sub_join_info = get_join_info(model, sub_cond) + if condition.conjunction == :or + join_info.each_key do |k| + join_info.delete(k) unless sub_join_info[k] + end + else + join_info.merge!(sub_join_info) + end + end + join_info end - not_nil = options[:not_nil] - unless not_nil - not_nil = {} - get_not_nil(@model, condition, not_nil) - end + join_info = options[:join_info] + join_info ||= get_join_info(@model, condition) + condition.each_with_comparison do |k, v, comp| if k.is_a?(QueryFuncs::Function) field = prepare_queryfunc(k) cond[:values] << [field, comp, v] @@ -507,10 +525,16 @@ next end element = model.elements[k.to_sym] next unless model.mapper.mapped?(element) if (element.model?) + el_join_info = {} + join_info.each do |jk, jv| + if jk.index(k.to_s+'.') == 0 + el_join_info[jk[k.to_s.length..-1]] = jv + end + end if (v && model.mapper.have_references?(element.name) && v.select{ |key, value| !element.model.elements[key] || !element.model.elements[key].primary_key? }.empty?) # 1/n <-> 1 with only primary keys element_cond = {:conj => 'AND', :values => []} v.each_with_comparison do |el_k, el_v, el_comp| @@ -521,11 +545,11 @@ element_cond[:values] << field_cond end cond[:values] << element_cond else if (element.storage == model.mapper.storage) - join_type = (v.nil? && comp == '=') ? :left : :inner + join_type = join_info[element.name.to_s] ? :inner : :left sub_join = model.mapper.get_join(element, join_type) # FIXME! cleanup, and apply the check to joins acquired in other places, too (maybe pass the current joins to get_join) existent = joins.select{ |j| j[:to] == sub_join[:to] } j_cnt = nil had_join = false @@ -540,29 +564,30 @@ end end sub_join[:as] = "#{sub_join[:to]}#{j_cnt}" if j_cnt joins << sub_join unless had_join - if v.nil? && comp == '=' && !not_nil[element.name] + if v.nil? && comp == '=' + el_model_schema = model_schema element_cond = {:conj => 'AND', :values => []} if model.mapper.have_references?(element.name) el_name = element.name el_model = element.model else el_model = element.type - model_schema = element.model.mapper.schema + el_model_schema = element.model.mapper.schema el_name = element.attributes[:junction_their_element] end el_model.primary_keys.each do |k| - field = model_schema.qualified_foreign_key_field(el_name, k.name) + field = el_model_schema.qualified_foreign_key_field(el_name, k.name) field_cond = [field, comp, map_condition_value(element.model.elements[k.name].type, nil)] element_cond[:values] << field_cond end cond[:values] << element_cond elsif v v = element.model.mapper.preprocess_condition(v) - sub_condition, sub_joins = element.mapper.prepare_condition(v, :table => sub_join[:as], :joins => joins, :not_nil => not_nil[element.name]) + sub_condition, sub_joins = element.mapper.prepare_condition(v, :table => sub_join[:as], :joins => joins, :join_info => el_join_info) sub_condition[:table] = sub_join[:as] if sub_join[:as] joins = sub_joins cond[:values] << sub_condition end @@ -585,10 +610,10 @@ end sub_sqls = [] sub_bind_values = [] condition.subconditions.each do |sub| - sub_res = self.prepare_condition(sub, :joins => joins, :not_nil => not_nil) + sub_res = self.prepare_condition(sub, :joins => joins, :join_info => join_info) cond[:values] << sub_res[0] joins = sub_res[1] remaining_condition += sub_res[2] end return [cond, joins, remaining_condition]