<commit_before># This provides a cache for several distance measures between members
class MemberDistance < ActiveRecord::Base
  self.table_name = "pw_cache_realreal_distance"
  belongs_to :member1, foreign_key: :mp_id1, class_name: "Member"
  belongs_to :member2, foreign_key: :mp_id2, class_name: "Member"

  before_save :update_cache_values!

  def agreement_percentage
    (1 - distance_a) * 100
  end

  def agreement_percentage_without_abstentions
    (1 - distance_b) * 100
  end

  def self.update_all!
    MemberDistance.delete_all
    Member.all.find_each do |member1|
      puts "Updating distances for #{member1.name}..."
      # Find all members who overlap with this member
      members = Member.where(house: member1.house).where("left_house >= ?", member1.entered_house).
        where("entered_house <= ?", member1.left_house)
      # We're only populating half of the matrix
      members.where("mp_id >= ?", member1.mp_id).each do |member2|
        MemberDistance.create(member1: member1, member2: member2)
      end
    end
  end

  def update_cache_values!
    self.nvotessame = MemberDistance.calculate_nvotessame(member1, member2)
    self.nvotesdiffer = MemberDistance.calculate_nvotesdiffer(member1, member2)
    self.nvotesabsent = MemberDistance.calculate_nvotesabsent(member1, member2)
    self.distance_a = Distance.distance_a(nvotessame, nvotesdiffer, nvotesabsent)
    self.distance_b = Distance.distance_b(nvotessame, nvotesdiffer)
  end

  def self.calculate_nvotessame(member1, member2)
    # TODO Move knowledge of tells out of here. Shouldn't have to know about this to do this
    # kind of query
    Division
      .joins("LEFT JOIN pw_vote AS pw_vote1 on pw_vote1.division_id = pw_division.division_id")
      .joins("LEFT JOIN pw_vote AS pw_vote2 on pw_vote2.division_id = pw_division.division_id")
      .where("pw_vote1.mp_id = ?", member1.id)
      .where("pw_vote2.mp_id = ?", member2.id)
      .where("((pw_vote1.vote = 'aye' OR pw_vote1.vote = 'tellaye') AND (pw_vote2.vote = 'aye' OR pw_vote2.vote = 'tellaye')) OR ((pw_vote1.vote = 'no' OR pw_vote1.vote = 'tellno') AND (pw_vote2.vote = 'no' OR pw_vote2.vote = 'tellno'))")
      .count
  end

  def self.calculate_nvotesdiffer(member1, member2)
    Division
      .joins("LEFT JOIN pw_vote AS pw_vote1 on pw_vote1.division_id = pw_division.division_id")
      .joins("LEFT JOIN pw_vote AS pw_vote2 on pw_vote2.division_id = pw_division.division_id")<commit_msg>Keep MemberDistance cache data filled as it is regenerated<commit_after># This provides a cache for several distance measures between members
class MemberDistance < ActiveRecord::Base
  self.table_name = "pw_cache_realreal_distance"
  belongs_to :member1, foreign_key: :mp_id1, class_name: "Member"
  belongs_to :member2, foreign_key: :mp_id2, class_name: "Member"

  before_save :update_cache_values!

  def agreement_percentage
    (1 - distance_a) * 100
  end

  def agreement_percentage_without_abstentions
    (1 - distance_b) * 100
  end

  def self.update_all!
    Member.all.find_each do |member1|
      puts "Updating distances for #{member1.name}..."
      # Find all members who overlap with this member
      members = Member.where(house: member1.house).where("left_house >= ?", member1.entered_house).
        where("entered_house <= ?", member1.left_house)
      # We're only populating half of the matrix
      members.where("mp_id >= ?", member1.mp_id).each do |member2|
        MemberDistance.where(member1: member1, member2: member2).delete_all
        MemberDistance.create(member1: member1, member2: member2)
      end
    end
  end

  def update_cache_values!
    self.nvotessame = MemberDistance.calculate_nvotessame(member1, member2)
    self.nvotesdiffer = MemberDistance.calculate_nvotesdiffer(member1, member2)
    self.nvotesabsent = MemberDistance.calculate_nvotesabsent(member1, member2)
    self.distance_a = Distance.distance_a(nvotessame, nvotesdiffer, nvotesabsent)
    self.distance_b = Distance.distance_b(nvotessame, nvotesdiffer)
  end

  def self.calculate_nvotessame(member1, member2)
    # TODO Move knowledge of tells out of here. Shouldn't have to know about this to do this
    # kind of query
    Division
      .joins("LEFT JOIN pw_vote AS pw_vote1 on pw_vote1.division_id = pw_division.division_id")
      .joins("LEFT JOIN pw_vote AS pw_vote2 on pw_vote2.division_id = pw_division.division_id")
      .where("pw_vote1.mp_id = ?", member1.id)
      .where("pw_vote2.mp_id = ?", member2.id)
      .where("((pw_vote1.vote = 'aye' OR pw_vote1.vote = 'tellaye') AND (pw_vote2.vote = 'aye' OR pw_vote2.vote = 'tellaye')) OR ((pw_vote1.vote = 'no' OR pw_vote1.vote = 'tellno') AND (pw_vote2.vote = 'no' OR pw_vote2.vote = 'tellno'))")
      .count
  end

  def self.calculate_nvotesdiffer(member1, member2)
    Division
      .joins("LEFT JOIN pw_vote AS pw_vote1 on pw_vote1.division_id = pw_division.division_id")
      .joins("LEFT JOIN pw_vote AS pw_vote2 on pw_vote2.division_id = pw_division.division_id")
{'fraction_non_alphanumeric': 0.09978048293753741, 'fraction_numerical': 0.02195170624625823, 'mean_word_length': 4.078014184397163, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6485178', 'n_tokens_mistral': 1803, 'n_tokens_neox': 1734, 'n_words': 396}