Module: PactBroker::Matrix::MatrixRowDatasetModule

Defined in:
lib/pact_broker/matrix/matrix_row_dataset_module.rb

Constant Summary collapse

EAGER_LOADED_RELATIONSHIPS_FOR_VERSION =
{ current_deployed_versions: :environment, current_supported_released_versions: :environment, branch_versions: [:branch_head, :version, branch: :pacticipant] }
LAST_ACTION_DATE =
Sequel.lit("CASE WHEN (provider_version_created_at IS NOT NULL AND provider_version_created_at > consumer_version_created_at) THEN provider_version_created_at ELSE consumer_version_created_at END").as(:last_action_date)

Instance Method Summary collapse

Instance Method Details

#consumer_criteria_for_selectors(resolved_selectors) ⇒ Array<Hash>

Parameters:

Returns:

  • (Array<Hash>)


175
176
177
178
179
180
181
182
# File 'lib/pact_broker/matrix/matrix_row_dataset_module.rb', line 175

def consumer_criteria_for_selectors(resolved_selectors)
  name_only, with_versions = resolved_selectors.partition(&:only_pacticipant_name_specified?)

  criteria = []
  criteria << { Sequel[:p][:consumer_id] => name_only.collect(&:pacticipant_id).uniq } if name_only.any?
  criteria << { Sequel[:p][:consumer_version_id] => with_versions.collect(&:pacticipant_version_id).uniq } if with_versions.any?
  criteria
end

#default_scopeObject

Just for testing purposes



45
46
47
48
49
50
# File 'lib/pact_broker/matrix/matrix_row_dataset_module.rb', line 45

def default_scope
  select_pact_columns_with_aliases
    .from_self(alias: :p)
    .left_outer_join_verifications
    .select_all_columns_after_join
end

#eager_all_the_thingsObject

eager load tags?



30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/pact_broker/matrix/matrix_row_dataset_module.rb', line 30

def eager_all_the_things
  eager(
    :consumer,
    :provider,
    :verification,
    :pact_publication,
    :pact_version,
    consumer_version: EAGER_LOADED_RELATIONSHIPS_FOR_VERSION,
    provider_version: EAGER_LOADED_RELATIONSHIPS_FOR_VERSION,
    consumer_version_tags: [:head_tag, { version: :pacticipant }],
    provider_version_tags: [:head_tag, { version: :pacticipant }]
  )
end

#inner_join_verifications_dataset(verifications_dataset) ⇒ Object



194
195
196
# File 'lib/pact_broker/matrix/matrix_row_dataset_module.rb', line 194

def inner_join_verifications_dataset(verifications_dataset)
  join(verifications_dataset, { Sequel[:p][:pact_version_id] => Sequel[:v][:pact_version_id] }, { table_alias: :v } )
end

#left_outer_join_verificationsObject



185
186
187
# File 'lib/pact_broker/matrix/matrix_row_dataset_module.rb', line 185

def left_outer_join_verifications
  left_outer_join_verifications_dataset(verification_dataset.select_verification_columns_with_aliases)
end

#left_outer_join_verifications_dataset(verifications) ⇒ Object



189
190
191
# File 'lib/pact_broker/matrix/matrix_row_dataset_module.rb', line 189

def left_outer_join_verifications_dataset(verifications)
  left_outer_join(verifications, { Sequel[:p][:pact_version_id] => Sequel[:v][:pact_version_id] }, { table_alias: :v } )
end

#matching_one_selector_for_either_consumer_or_provider(resolved_selectors, limit:) ⇒ Object

Final matrix query with one selector (not the normal use case) When we have one selector, we need to join ALL the verifications to find out what integrations exist



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/pact_broker/matrix/matrix_row_dataset_module.rb', line 58

def matching_one_selector_for_either_consumer_or_provider(resolved_selectors, limit: )
  if resolved_selectors.size != 1
    raise ArgumentError.new("Expected one selector to be provided, but received #{resolved_selectors.size}:  #{resolved_selectors}")
  end

  # consumer
  pact_publication_matching_consumer = select_pact_columns_with_aliases
    .most_recent(limit)
    .from_self(alias: :p)
    .where_consumer_version_matches_selectors(resolved_selectors)
  rows_where_selector_matches_consumer = pact_publication_matching_consumer
    .left_outer_join_verifications
    .select_all_columns_after_join

  # provider
  verifications_matching_provider = verification_dataset.matching_selectors_as_provider_for_any_consumer(resolved_selectors)
  rows_where_selector_matches_provider = select_pact_columns_with_aliases.most_recent(limit).from_self(alias: :p).inner_join_verifications_dataset(verifications_matching_provider).select_all_columns_after_join

  # union
  rows_where_selector_matches_consumer.union(rows_where_selector_matches_provider)
end

#matching_only_selectors_as_consumer(resolved_selectors, limit:) ⇒ Sequel::Dataset<MatrixRow>

Return pact publications where the consumer/consumer version is described by any of the resolved_selectors, AND the provider is described by any of the resolved selectors.

Parameters:

Returns:



111
112
113
114
115
116
# File 'lib/pact_broker/matrix/matrix_row_dataset_module.rb', line 111

def matching_only_selectors_as_consumer(resolved_selectors, limit: )
  [
    matching_only_selectors_as_consumer_where_only_pacticipant_name_in_selector(resolved_selectors, limit: limit),
    matching_only_selectors_as_consumer_where_not_only_pacticipant_name_in_selector(resolved_selectors, limit: limit),
  ].compact.reduce(&:union)
end

#matching_only_selectors_as_consumer_where_not_only_pacticipant_name_in_selector(resolved_selectors, limit:) ⇒ Sequel::Dataset<MatrixRow>?

Return pact publications where the consumer version is described by any of the resolved_selectors that specify more than just the pacticipant name, AND the provider is described by any of the resolved selectors. If the selector uses any of the tag/branch/environment/latest attributes, we need to join to the versions table to identify the required pact_publications. Return nil if there are no resolved selectors where anything other than the pacticipant name is specified.

Parameters:

Returns:



145
146
147
148
149
150
151
152
153
154
155
# File 'lib/pact_broker/matrix/matrix_row_dataset_module.rb', line 145

def matching_only_selectors_as_consumer_where_not_only_pacticipant_name_in_selector(resolved_selectors, limit:)
  all_pacticipant_ids = resolved_selectors.collect(&:pacticipant_id).uniq
  resolved_selectors_with_versions_specified = resolved_selectors.reject(&:only_pacticipant_name_specified?)

  if resolved_selectors_with_versions_specified.any?
    select_pact_columns_with_aliases
      .where_consumer_version_matches_selectors(resolved_selectors_with_versions_specified)
      .where(provider_id: all_pacticipant_ids)
      .most_recent(limit)
  end
end

#matching_only_selectors_as_consumer_where_only_pacticipant_name_in_selector(resolved_selectors, limit:) ⇒ Sequel::Dataset<MatrixRow>?

Return pact publications where the consumer is described by any of the resolved_selectors that only specify the pacticipant NAME, AND the provider is described by any of the resolved selectors. If the original selector only specified the pacticipant name, we don't need to join to the versions table to identify the required pact_publications. Return nil if there are no resolved selectors where only the pacticipant name is specified.

Parameters:

Returns:



125
126
127
128
129
130
131
132
133
134
135
# File 'lib/pact_broker/matrix/matrix_row_dataset_module.rb', line 125

def matching_only_selectors_as_consumer_where_only_pacticipant_name_in_selector(resolved_selectors, limit:)
  all_pacticipant_ids = resolved_selectors.collect(&:pacticipant_id).uniq
  pacticipant_ids_for_pacticipant_only_selectors = resolved_selectors.select(&:only_pacticipant_name_specified?).collect(&:pacticipant_id).uniq

  if pacticipant_ids_for_pacticipant_only_selectors.any?
    select_pact_columns_with_aliases
      .where(consumer_id: pacticipant_ids_for_pacticipant_only_selectors)
      .where(provider_id: all_pacticipant_ids)
      .most_recent(limit)
  end
end

#matching_only_selectors_joining_verifications(resolved_selectors, limit:) ⇒ Sequel::Dataset<MatrixRow>

Find the matrix rows When the user has specified multiple selectors, we only want to join the verifications for the specified selectors. This is because of the behaviour of the left outer join. Imagine a pact has been verified by a provider version that was NOT specified in the selectors. If we join all the verifications and THEN filter the rows to only show the versions specified in the selectors, we won't get a row for that pact, and hence, we won't know that it hasn't been verified by the provider version we're interested in. Instead, we need to filter the verifications dataset down to only the ones specified in the selectors first, and THEN join them to the pacts, so that we get a row for the pact with null provider version and verification fields. IDEA FOR OPTIMISATION - would it work to limit the pact_publications query and the verifications query to the limit of the overall query?

Parameters:

Returns:



94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/pact_broker/matrix/matrix_row_dataset_module.rb', line 94

def matching_only_selectors_joining_verifications(resolved_selectors, limit: )
  pact_publications = matching_only_selectors_as_consumer(resolved_selectors, limit: limit)
  verifications = verification_dataset.matching_only_selectors_as_provider(resolved_selectors)

  specified_pacticipant_ids = resolved_selectors.select(&:specified?).collect(&:pacticipant_id).uniq

  pact_publications
    .from_self(alias: :p)
    .select_all_columns_after_join
    .left_outer_join_verifications_dataset(verifications)
    .where(consumer_id: specified_pacticipant_ids).or(provider_id: specified_pacticipant_ids)
end

#matching_selectors(resolved_selectors, limit:) ⇒ Object

The matrix query used to determine the final dataset

Parameters:



15
16
17
18
19
20
21
# File 'lib/pact_broker/matrix/matrix_row_dataset_module.rb', line 15

def matching_selectors(resolved_selectors, limit:)
  if resolved_selectors.size == 1
    matching_one_selector_for_either_consumer_or_provider(resolved_selectors, limit: limit)
  else
    matching_only_selectors_joining_verifications(resolved_selectors, limit: limit)
  end
end

#most_recent(limit) ⇒ Object



198
199
200
# File 'lib/pact_broker/matrix/matrix_row_dataset_module.rb', line 198

def most_recent(limit)
  order(Sequel.desc(:created_at)).limit(limit)
end

#order_by_last_action_dateObject



24
25
26
# File 'lib/pact_broker/matrix/matrix_row_dataset_module.rb', line 24

def order_by_last_action_date
  from_self(alias: :unordered_rows).select(LAST_ACTION_DATE, Sequel[:unordered_rows].* ).order(Sequel.desc(:last_action_date), Sequel.desc(:pact_order), Sequel.desc(:verification_id))
end

#where_consumer_version_matches_selectors(resolved_selectors) ⇒ Object

Name-only selectors carry no version ID — matching_one_selector_for_either_consumer_or_provider passes its selectors unfiltered — so they filter on the pacticipant instead. That identifies the same rows, because a pact publication's consumer_id is the pacticipant_id of its consumer_version.

Parameters:



163
164
165
166
167
168
169
170
# File 'lib/pact_broker/matrix/matrix_row_dataset_module.rb', line 163

def where_consumer_version_matches_selectors(resolved_selectors)
  if resolved_selectors.empty?
    raise ArgumentError.new("resolved_selectors must not be empty")
  end

  criteria = consumer_criteria_for_selectors(resolved_selectors)
  where(criteria.size > 1 ? Sequel.|(*criteria) : criteria.first)
end