Skip to content

Commit

Permalink
feat: optimise the query to load the tags with latest flags
Browse files Browse the repository at this point in the history
  • Loading branch information
bethesque committed Nov 27, 2020
1 parent 67309e3 commit bc47613
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 1 deletion.
29 changes: 29 additions & 0 deletions lib/pact_broker/domain/tag.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,35 @@ class Tag < Sequel::Model
dataset_module do
include PactBroker::Repositories::Helpers

# Does NOT care about whether or not there is a pact publication
# for the version
def latest_tags_for_pacticipant_ids(pacticipant_ids)
tags_versions_join = {
Sequel[:tags][:version_id] => Sequel[:versions][:id],
Sequel[:versions][:pacticipant_id] => pacticipant_ids
}

latest_tags_versions_join = {
Sequel[:latest_tags][:name] => Sequel[:tags][:name],
Sequel[:latest_tags][:latest_order] => Sequel[:versions][:order],
Sequel[:latest_tags][:pacticipant_id] => Sequel[:versions][:pacticipant_id],
Sequel[:versions][:pacticipant_id] => pacticipant_ids
}

latest_tags = PactBroker::Domain::Tag
.select_group(Sequel[:tags][:name], Sequel[:versions][:pacticipant_id])
.select_append{ max(order).as(latest_order) }
.join(:versions, tags_versions_join)

PactBroker::Domain::Tag
.select_all_qualified
.join(:versions,
{ Sequel[:tags][:version_id] => Sequel[:versions][:id],
Sequel[:versions][:pacticipant_id] => pacticipant_ids
})
.join(latest_tags, latest_tags_versions_join, { table_alias: :latest_tags })
end

def head_tags_for_consumer_id(consumer_id)
lp = :latest_pact_publication_ids_for_consumer_versions
tags_versions_join = {
Expand Down
31 changes: 30 additions & 1 deletion lib/pact_broker/domain/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,21 @@

module PactBroker
module Domain

# Same attributes as PactBroker::Tags::TagWithLatestFlag
class EagerTagWithLatestFlag < SimpleDelegator
attr_reader :latest

def initialize(tag, latest)
super(tag)
@latest = latest
end

def latest?
latest
end
end

class Version < Sequel::Model
plugin :timestamps, update_on_create: true
plugin :insert_ignore, identifying_columns: [:pacticipant_id, :number]
Expand All @@ -13,7 +28,21 @@ class Version < Sequel::Model
one_to_many :pact_publications, order: :revision_number, class: "PactBroker::Pacts::PactPublication", key: :consumer_version_id
associate(:many_to_one, :pacticipant, :class => "PactBroker::Domain::Pacticipant", :key => :pacticipant_id, :primary_key => :id)
one_to_many :tags, :reciprocal => :version, order: :created_at
one_to_many :tags_with_latest_flag, class: "PactBroker::Tags::TagWithLatestFlag", key: :version_id, primary_key: :id

one_to_many :tags_with_latest_flag, :class => "PactBroker::Tags::TagWithLatestFlag", primary_keys: [:id], key: [:version_id], :eager_loader=>(proc do |eo_opts|
tags_for_versions = PactBroker::Domain::Tag.where(version_id: eo_opts[:key_hash][:id].keys)
latest_tag_for_pacticipants = PactBroker::Domain::Tag.latest_tags_for_pacticipant_ids(eo_opts[:rows].collect(&:pacticipant_id)).all

eo_opts[:rows].each{|row| row.associations[:tags_with_latest_flag] = [] }

tags_for_versions.each do | tag |
latest = latest_tag_for_pacticipants.any? { |latest_tag| latest_tag.name == tag.name && latest_tag.version_id == tag.version_id }
eo_opts[:id_map][tag.version_id].each do | version |
version.associations[:tags_with_latest_flag] << EagerTagWithLatestFlag.new(tag, latest)
end
end
end)


dataset_module do
include PactBroker::Repositories::Helpers
Expand Down
46 changes: 46 additions & 0 deletions spec/lib/pact_broker/domain/tag_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
require 'pact_broker/domain/tag'

module PactBroker
module Domain
describe Tag do
before do
td.create_consumer("foo")
.create_consumer_version("1")
.create_consumer_version_tag("dev")
.create_consumer_version_tag("prod")
.create_consumer_version("2")
.create_consumer_version_tag("dev")
.create_consumer_version_tag("bloop")
.create_consumer_version("3")
.create_consumer_version_tag("dev")
.create_consumer("bar")
.create_consumer_version("1")
.create_consumer_version_tag("test")
end

it "returns the latest tags for the given pacticipant ids" do
pacticipant = PactBroker::Domain::Pacticipant.order(:id).first
tags = Tag.latest_tags_for_pacticipant_ids([pacticipant.id]).all
expect(tags.collect(&:name).sort).to eq %w{bloop dev prod}
expect(tags.find{ |t| t.name == "dev" }.version.number).to eq "3"
expect(tags.find{ |t| t.name == "prod" }.version.number).to eq "1"
expect(tags.find{ |t| t.name == "bloop" }.version.number).to eq "2"
expect(tags.collect(&:version_id).compact.size).to eq 3
expect(tags.collect(&:created_at).compact.size).to eq 3
end
end
end
end

# Table: tags
# Primary Key: (name, version_id)
# Columns:
# name | text |
# version_id | integer |
# created_at | timestamp without time zone | NOT NULL
# updated_at | timestamp without time zone | NOT NULL
# Indexes:
# tags_pk | PRIMARY KEY btree (version_id, name)
# ndx_tag_name | btree (name)
# Foreign key constraints:
# tags_version_id_fkey | (version_id) REFERENCES versions(id)
23 changes: 23 additions & 0 deletions spec/lib/pact_broker/domain/version_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,29 @@ def version_numbers
.to raise_error(Sequel::UniqueConstraintViolation)
end
end

describe "tags_with_latest_flag" do
before do
td.create_consumer("foo")
.create_consumer_version("1")
.create_consumer_version_tag("dev")
.create_consumer_version_tag("prod")
.create_consumer_version("2")
.create_consumer_version_tag("dev")
end

it "uneager loads" do
version = Version.first(number: "1")
expect(version.tags.collect(&:name).sort).to eq %w{dev prod}
expect(version.tags_with_latest_flag.select(&:latest).collect(&:name)).to eq %w{prod}
end

it "eager loads" do
version = Version.eager(:tags, :tags_with_latest_flag).where(number: "1").all.first
expect(version.tags.collect(&:name).sort).to eq %w{dev prod}
expect(version.tags_with_latest_flag.select(&:latest).collect(&:name)).to eq %w{prod}
end
end
end
end
end

0 comments on commit bc47613

Please sign in to comment.