From 54f11be47bf656ff3cbe09374a7bd1db5a9792b9 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Mon, 6 Jul 2015 02:33:43 +0200 Subject: [PATCH] Improved model helpers. --- lib/models.rb | 136 ++++++++++++++++++++++++++++++++-------- test/unit/model_test.rb | 105 +++++++++++++++++++++++++++++-- 2 files changed, 211 insertions(+), 30 deletions(-) diff --git a/lib/models.rb b/lib/models.rb index f2fe53553..5d1708ce1 100644 --- a/lib/models.rb +++ b/lib/models.rb @@ -40,9 +40,9 @@ returns all[model_class] = {} all[model_class][:attributes] = model_class.attribute_names all[model_class][:reflections] = model_class.reflections + #puts model_class #puts "rrrr #{all[model_class][:attributes]}" - #puts model.class - #puts " #{model.attribute_names.inspect}" + #puts " #{model_class.attribute_names.inspect}" end all end @@ -57,38 +57,51 @@ returns { 'Some::Classname1' => { - attributes: ['id', 'name', '...'] - reflections: ...model.reflections... + attribute1: 12, + attribute2: 6, }, 'Some::Classname2' => { - attributes: ['id', 'name', '...'] - reflections: ...model.reflections... + updated_by_id: 12, + created_by_id: 6, }, } =end def self.references(object_name, object_id) + + # check if model exists object_model = load_adapter(object_name) object_model.find(object_id) + list = all - references = { - model: {}, - total: 0, - } + references = {} # find relations via attributes - list.each {|model_class, model_attributes| - references[:model][model_class.to_s] = 0 - next if !model_attributes[:attributes] - %w(created_by_id updated_by_id).each {|item| + ref_attributes = ["#{object_name.downcase}_id"] + # for users we do not define relations for created_by_id & + # updated_by_id - add it here directly + if object_name == 'User' + ref_attributes.push 'created_by_id' + ref_attributes.push 'updated_by_id' + end + list.each {|model_class, model_attributes| + if !references[model_class.to_s] + references[model_class.to_s] = {} + end + + next if !model_attributes[:attributes] + ref_attributes.each {|item| next if !model_attributes[:attributes].include?(item) count = model_class.where("#{item} = ?", object_id).count next if count == 0 + if !references[model_class.to_s][item] + references[model_class.to_s][item] = 0 + end Rails.logger.debug "FOUND (by id) #{model_class}->#{item} #{count}!" - references[:model][model_class.to_s] += count + references[model_class.to_s][item] += count } } @@ -98,30 +111,103 @@ returns model_attributes[:reflections].each {|_reflection_key, reflection_value| next if reflection_value.macro != :belongs_to + col_name = "#{reflection_value.name}_id" + next if ref_attributes.include?(col_name) if reflection_value.options[:class_name] == object_name - count = model_class.where("#{reflection_value.name}_id = ?", object_id).count + count = model_class.where("#{col_name} = ?", object_id).count next if count == 0 - Rails.logger.debug "FOUND (by ref without class) #{model_class}->#{reflection_value.name} #{count}!" - references[:model][model_class.to_s] += count + if !references[model_class.to_s][col_name] + references[model_class.to_s][col_name] = 0 + end + Rails.logger.debug "FOUND (by ref without class) #{model_class}->#{col_name} #{count}!" + references[model_class.to_s][col_name] += count end next if reflection_value.options[:class_name] next if reflection_value.name != object_name.downcase.to_sym - count = model_class.where("#{reflection_value.name}_id = ?", object_id).count + count = model_class.where("#{col_name} = ?", object_id).count next if count == 0 - - Rails.logger.debug "FOUND (by ref with class) #{model_class}->#{reflection_value.name} #{count}!" - references[:model][model_class.to_s] += count + if !references[model_class.to_s][col_name] + references[model_class.to_s][col_name] = 0 + end + Rails.logger.debug "FOUND (by ref with class) #{model_class}->#{col_name} #{count}!" + references[model_class.to_s][col_name] += count } } - references[:model].each {|_k, v| - next if v == 0 - references[:total] += v + # cleanup, remove models with empty references + references.each {|k, v| + next if !v.empty? + references.delete(k) } + references end +=begin + +get reference total of a models + + count = Models.references_total('User', 2) + +returns + + count # 1234 + +=end + + def self.references_total(object_name, object_id) + references = self.references(object_name, object_id) + total = 0 + references.each {|_model, model_references| + model_references.each {|_col, count| + total += count + } + } + total + end + +=begin + +merge model references to other model + + result = Models.merge('User', 2, 4711) + +returns + + true # false + +=end + + def self.merge(object_name, object_id_primary, object_id_to_merge, force = false) + + # if lower x references to update, do it right now + if force + total = Models.references_total(object_name, object_id_to_merge) + if total > 1000 + fail "Can't merge object because object has more then 1000 (#{total}) references, please contact your system administrator." + end + end + + references = Models.references(object_name, object_id_to_merge) + references.each {|model, attributes| + model_object = Object.const_get(model) + items_to_update = {} + attributes.each {|attribute, _count| + #puts "-> #{model}: #{attribute}->#{object_id_to_merge}->#{object_id_primary}" + model_object.where("#{attribute} = ?", object_id_to_merge).each {|item| + if !items_to_update[item.id] + items_to_update[item.id] = item + end + items_to_update[item.id][attribute.to_sym] = object_id_primary + } + } + items_to_update.each {|_id, item| + item.save + } + } + true + end end diff --git a/test/unit/model_test.rb b/test/unit/model_test.rb index 0aaf82dd8..0bdb6ea50 100644 --- a/test/unit/model_test.rb +++ b/test/unit/model_test.rb @@ -20,6 +20,19 @@ class ModelTest < ActiveSupport::TestCase updated_by_id: 1, created_by_id: 1, ) + agent2 = User.create_or_update( + login: 'model-agent2@example.com', + firstname: 'Model', + lastname: 'Agent2', + email: 'model-agent2@example.com', + password: 'agentpw', + active: true, + roles: roles, + groups: groups, + updated_at: '2015-02-05 17:37:00', + updated_by_id: agent1.id, + created_by_id: 1, + ) organization1 = Organization.create_if_not_exists( name: 'Model Org 1', updated_at: '2015-02-05 16:37:00', @@ -73,12 +86,94 @@ class ModelTest < ActiveSupport::TestCase created_by_id: agent1.id, ) - references = Models.references('User', agent1.id) + # user + + # verify agent1 + references1 = Models.references('User', agent1.id) + + assert_equal(references1['User']['updated_by_id'], 3) + assert_equal(references1['User']['created_by_id'], 1) + assert_equal(references1['Organization']['updated_by_id'], 1) + assert(!references1['Group']) + + references_total1 = Models.references_total('User', agent1.id) + assert_equal(references_total1, 7) + + # verify agent2 + references2 = Models.references('User', agent2.id) + + assert(!references2['User']) + assert(!references2['Organization']) + assert(!references2['Group']) + assert(references2.empty?) + + references_total2 = Models.references_total('User', agent2.id) + assert_equal(references_total2, 0) + + Models.merge('User', agent2.id, agent1.id) + + # verify agent1 + references1 = Models.references('User', agent1.id) + + assert(!references1['User']) + assert(!references1['Organization']) + assert(!references1['Group']) + assert(references1.empty?) + + references_total1 = Models.references_total('User', agent1.id) + assert_equal(references_total1, 0) + + # verify agent2 + references2 = Models.references('User', agent2.id) + + assert_equal(references2['User']['updated_by_id'], 3) + assert_equal(references2['User']['created_by_id'], 1) + assert_equal(references2['Organization']['updated_by_id'], 1) + assert(!references2['Group']) + + references_total2 = Models.references_total('User', agent2.id) + assert_equal(references_total2, 7) + + # org + + # verify agent1 + references1 = Models.references('Organization', organization1.id) + + assert_equal(references1['User']['organization_id'], 1) + assert(!references1['Organization']) + assert(!references1['Group']) + + references_total1 = Models.references_total('Organization', organization1.id) + assert_equal(references_total1, 1) + + # verify agent2 + references2 = Models.references('Organization', organization2.id) + + assert(references2.empty?) + + references_total2 = Models.references_total('Organization', organization2.id) + assert_equal(references_total2, 0) + + Models.merge('Organization', organization2.id, organization1.id) + + # verify agent1 + references1 = Models.references('Organization', organization1.id) + + assert(references1.empty?) + + references_total1 = Models.references_total('Organization', organization1.id) + assert_equal(references_total1, 0) + + # verify agent2 + references2 = Models.references('Organization', organization2.id) + + assert_equal(references2['User']['organization_id'], 1) + assert(!references2['Organization']) + assert(!references2['Group']) + + references_total2 = Models.references_total('Organization', organization2.id) + assert_equal(references_total2, 1) - assert_equal(references[:model]['User'], 3) - assert_equal(references[:model]['Organization'], 1) - assert_equal(references[:model]['Group'], 0) - assert_equal(references[:total], 6) end end