From c575d132a8dd9548827f67053c52f8265db61679 Mon Sep 17 00:00:00 2001 From: Beth Skurrie Date: Tue, 30 Nov 2021 16:55:39 +1100 Subject: [PATCH] fix: fix performance issue loading latest version for pacticipant --- lib/pact_broker/domain/pacticipant.rb | 38 ++++++++++++++++++- lib/pact_broker/versions/latest_version.rb | 21 ---------- .../pact_broker/domain/pacticipant_spec.rb | 32 ++++++++++++++++ 3 files changed, 68 insertions(+), 23 deletions(-) delete mode 100644 lib/pact_broker/versions/latest_version.rb create mode 100644 spec/lib/pact_broker/domain/pacticipant_spec.rb diff --git a/lib/pact_broker/domain/pacticipant.rb b/lib/pact_broker/domain/pacticipant.rb index ff1157103..108c55b3f 100644 --- a/lib/pact_broker/domain/pacticipant.rb +++ b/lib/pact_broker/domain/pacticipant.rb @@ -1,14 +1,44 @@ require "pact_broker/db" require "pact_broker/messages" require "pact_broker/repositories/helpers" -require "pact_broker/versions/latest_version" require "pact_broker/domain/label" require "pact_broker/string_refinements" require "pact_broker/pacticipants/generate_display_name" module PactBroker module Domain + class LatestVersionForPacticipantEagerLoader + def self.call(eo, **_other) + populate_associations(eo[:rows]) + end + + def self.populate_associations(pacticipants) + pacticipants.each { | pacticipant | pacticipant.associations[:latest_version] = nil } + pacticipant_ids = pacticipants.collect(&:id) + + max_orders = PactBroker::Domain::Version + .where(pacticipant_id: pacticipant_ids) + .select_group(:pacticipant_id) + .select_append { max(order).as(latest_order) } + + max_orders_join = { + Sequel[:max_orders][:latest_order] => Sequel[:versions][:order], + Sequel[:max_orders][:pacticipant_id] => Sequel[:versions][:pacticipant_id] + } + + latest_versions = PactBroker::Domain::Version + .select_all_qualified + .join(max_orders, max_orders_join, { table_alias: :max_orders}) + + latest_versions.each do | version | + pacticipant = pacticipants.find{ | pacticipant | pacticipant.id == version.pacticipant_id } + pacticipant.associations[:latest_version] = version + end + end + end + class Pacticipant < Sequel::Model + include Messages include PactBroker::Pacticipants::GenerateDisplayName using PactBroker::StringRefinements @@ -21,7 +51,11 @@ class Pacticipant < Sequel::Model one_to_many :versions, :order => :order, :reciprocal => :pacticipant one_to_many :labels, :order => :name, :reciprocal => :pacticipant one_to_many :pacts - one_to_one :latest_version, :class => "PactBroker::Versions::LatestVersion", primary_key: :id, key: :pacticipant_id + one_to_one :latest_version, :class => "PactBroker::Domain::Version", + primary_key: :id, key: :pacticipant_id, + dataset: lambda { PactBroker::Domain::Version.where(pacticipant_id: id).order(Sequel.desc(:order)).limit(1) }, + eager_loader: LatestVersionForPacticipantEagerLoader + one_to_many :branch_heads, class: "PactBroker::Versions::BranchHead", primary_key: :id, key: :pacticipant_id one_to_many :branches, class: "PactBroker::Versions::Branch", primary_key: :id, key: :pacticipant_id diff --git a/lib/pact_broker/versions/latest_version.rb b/lib/pact_broker/versions/latest_version.rb deleted file mode 100644 index 38998c9f6..000000000 --- a/lib/pact_broker/versions/latest_version.rb +++ /dev/null @@ -1,21 +0,0 @@ -require "pact_broker/domain/version" - -module PactBroker - module Versions - include PactBroker::Repositories::Helpers - - class LatestVersion < PactBroker::Domain::Version - set_dataset(:latest_versions) - end - end -end - -# Table: latest_versions -# Columns: -# id | integer | -# number | text | -# repository_ref | text | -# pacticipant_id | integer | -# order | integer | -# created_at | timestamp without time zone | -# updated_at | timestamp without time zone | diff --git a/spec/lib/pact_broker/domain/pacticipant_spec.rb b/spec/lib/pact_broker/domain/pacticipant_spec.rb new file mode 100644 index 000000000..86a6731f4 --- /dev/null +++ b/spec/lib/pact_broker/domain/pacticipant_spec.rb @@ -0,0 +1,32 @@ +require "pact_broker/domain/pacticipant" + +module PactBroker + module Domain + describe Pacticipant do + describe "#latest_version" do + before do + td.create_consumer("Foo") + .create_consumer_version("1") + .create_consumer_version("2") + .create_consumer_version("3") + .create_consumer("Bar") + .create_consumer_version("10") + .create_consumer_version("11") + .create_consumer_version("12") + end + + it "lazy loads" do + pacticipants = Pacticipant.order(:id).all + expect(pacticipants.first.latest_version.number).to eq "3" + expect(pacticipants.last.latest_version.number).to eq "12" + end + + it "eager_loads" do + pacticipants = Pacticipant.order(:id).eager(:latest_version).all + expect(pacticipants.first.associations[:latest_version].number).to eq "3" + expect(pacticipants.last.associations[:latest_version].number).to eq "12" + end + end + end + end +end