diff --git a/lib/pact_broker/domain/tag.rb b/lib/pact_broker/domain/tag.rb index e4d087566..f1283c7db 100644 --- a/lib/pact_broker/domain/tag.rb +++ b/lib/pact_broker/domain/tag.rb @@ -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 = { diff --git a/lib/pact_broker/domain/version.rb b/lib/pact_broker/domain/version.rb index 1d5235b31..d78661321 100644 --- a/lib/pact_broker/domain/version.rb +++ b/lib/pact_broker/domain/version.rb @@ -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] @@ -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 diff --git a/spec/lib/pact_broker/domain/tag_spec.rb b/spec/lib/pact_broker/domain/tag_spec.rb new file mode 100644 index 000000000..25cd5ecbe --- /dev/null +++ b/spec/lib/pact_broker/domain/tag_spec.rb @@ -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) diff --git a/spec/lib/pact_broker/domain/version_spec.rb b/spec/lib/pact_broker/domain/version_spec.rb index 0815eb8d0..9dab19b1f 100644 --- a/spec/lib/pact_broker/domain/version_spec.rb +++ b/spec/lib/pact_broker/domain/version_spec.rb @@ -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