pact_broker 2.42.0 → 2.43.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1beb82704006c0aa9708a9b4e9af93075bfc3bf9
4
- data.tar.gz: 8cb7b7148ce8a3152d6ccbe35e49f3e646f5e628
3
+ metadata.gz: 452acf4f3b4042c53c9e91a793f558f39ad6677e
4
+ data.tar.gz: ffcc62ddc9991aed25c87cbdea9925e9471bc4f8
5
5
  SHA512:
6
- metadata.gz: b289766c4bc421c975fefc7a109f97eb6bc5f31eac99d1dd6e7754d7f2c7cf7f7dca21652d55d28a1e64d5eacd5f26e16f30ac1af3e2111eefc9a38bb42128f4
7
- data.tar.gz: d6ce416cd0133c2d8278e1addc4f99814a118d9a800a74d1937168ac132e9f7ff27c3a48d63866ffaac0ec0424bd433f468812695e133edbf7a6698edbc9ba09
6
+ metadata.gz: e843bb458d91149a64f50092fcc1d17e63ed8b57468c7c2293033947648233cc015a010d421f7386531e89e90eb7d9499bc8da177da81c5518ea1bb937305ef8
7
+ data.tar.gz: c4df7ee48ef81fdb78beb668267ad13fcf848916b047c6f848a65bcc4979e7fac851617e93fba857b2a63bd77545d08a614e46257ede2e39e821d937ac3e79ef
@@ -1,3 +1,24 @@
1
+ <a name="v2.43.0"></a>
2
+ ### v2.43.0 (2020-01-06)
3
+
4
+
5
+ #### Features
6
+
7
+ * support DELETE /integrations for deleting all integration related data at once (pacticipants, pacts, verifications and webhooks) ([d7e2ef27](/../../commit/d7e2ef27))
8
+ * optimise query to automatically determine integrations ([147cbfb6](/../../commit/147cbfb6))
9
+ * change badge timeout message from error to warning ([e34f5676](/../../commit/e34f5676))
10
+
11
+ * **matrix**
12
+ * optimise the query that determines the integrations ([704944b6](/../../commit/704944b6))
13
+ * attempt to optimise the query that determines the integrations ([afde01e1](/../../commit/afde01e1))
14
+
15
+
16
+ #### Bug Fixes
17
+
18
+ * update rack for https://github.com/advisories/GHSA-hrqr-hxpp-chr3 ([c9352fde](/../../commit/c9352fde))
19
+ * correctly identify missing verification for bi-directional pacts ([3577968a](/../../commit/3577968a))
20
+
21
+
1
22
  <a name="v2.42.0"></a>
2
23
  ### v2.42.0 (2019-12-05)
3
24
 
@@ -30,7 +30,7 @@ module PactBroker
30
30
  end
31
31
 
32
32
  def delete_resource
33
- integration_service.delete(consumer_name, provider_name)
33
+ integration_service.delete_all
34
34
  true
35
35
  end
36
36
  end
@@ -84,8 +84,11 @@ module PactBroker
84
84
  begin
85
85
  response = do_request(uri)
86
86
  response.code == '200' ? response.body : nil
87
+ rescue Net::OpenTimeout => e
88
+ logger.warn "Timeout retrieving badge from #{uri} #{e.class} - #{e.message}"
89
+ nil
87
90
  rescue StandardError => e
88
- logger.error "Error retrieving badge from #{uri} due to #{e.class} - #{e.message}"
91
+ log_error e, "Error retrieving badge from #{uri}"
89
92
  nil
90
93
  end
91
94
  end
@@ -0,0 +1,37 @@
1
+ require 'pact_broker/webhooks/execution'
2
+ require 'pact_broker/webhooks/triggered_webhook'
3
+ require 'pact_broker/webhooks/webhook'
4
+ require 'pact_broker/pacts/latest_pact_publication_id_by_consumer_version'
5
+ require 'pact_broker/verifications/latest_verification_id_for_pact_version_and_provider_version'
6
+ require 'pact_broker/pacts/pact_publication'
7
+ require 'pact_broker/pacts/pact_version'
8
+ require 'pact_broker/domain/verification'
9
+ require 'pact_broker/domain/tag'
10
+ require 'pact_broker/domain/version'
11
+ require 'pact_broker/domain/label'
12
+ require 'pact_broker/domain/pacticipant'
13
+
14
+ module PactBroker
15
+ INTEGRATIONS_TABLES = [
16
+ PactBroker::Webhooks::Execution,
17
+ PactBroker::Webhooks::TriggeredWebhook,
18
+ PactBroker::Webhooks::Webhook,
19
+ PactBroker::Pacts::LatestPactPublicationIdForConsumerVersion,
20
+ PactBroker::Verifications::LatestVerificationIdForPactVersionAndProviderVersion,
21
+ PactBroker::Domain::Verification,
22
+ PactBroker::Pacts::PactPublication,
23
+ PactBroker::Pacts::PactVersion,
24
+ PactBroker::Domain::Tag,
25
+ PactBroker::Domain::Version,
26
+ PactBroker::Domain::Label,
27
+ PactBroker::Domain::Pacticipant
28
+ ]
29
+
30
+ module DB
31
+ def self.each_integration_model
32
+ INTEGRATIONS_TABLES.each do | model |
33
+ yield model
34
+ end
35
+ end
36
+ end
37
+ end
@@ -2,6 +2,8 @@ require 'pact_broker/services'
2
2
  require 'pact_broker/repositories'
3
3
  require 'pact_broker/logging'
4
4
  require 'pact_broker/integrations/integration'
5
+ require 'pact_broker/db/models'
6
+ require 'pact_broker/repositories/helpers'
5
7
 
6
8
  module PactBroker
7
9
  module Integrations
@@ -41,6 +43,22 @@ module PactBroker
41
43
  pacticipant_service.delete_if_orphan(consumer)
42
44
  pacticipant_service.delete_if_orphan(provider) unless consumer == provider
43
45
  end
46
+
47
+ def self.delete_all
48
+ # TODO move all these into their own repositories
49
+ PactBroker::DB.each_integration_model do | model |
50
+ if PactBroker::Repositories::Helpers.postgres?
51
+ logger.info("Truncating ", model.table_name)
52
+ model.truncate(cascade: true)
53
+ else
54
+ logger.info("Deleting all from ", model.table_name)
55
+ # Mysql adapter needs to support cascade truncate
56
+ # https://travis-ci.org/pact-foundation/pact_broker/jobs/633050220#L841
57
+ # https://travis-ci.org/pact-foundation/pact_broker/jobs/633053228#L849
58
+ model.dataset.delete
59
+ end
60
+ end
61
+ end
44
62
  end
45
63
  end
46
64
  end
@@ -0,0 +1,78 @@
1
+ module PactBroker
2
+ module Matrix
3
+ class QueryBuilder
4
+ def self.provider_or_provider_version_matches(query_ids, qualifier = nil)
5
+ Sequel.|(*provider_or_provider_version_criteria(query_ids, qualifier))
6
+ end
7
+
8
+ def self.provider_or_provider_version_matches_or_pact_unverified(query_ids, qualifier = nil)
9
+ ors = provider_or_provider_version_criteria(query_ids, qualifier)
10
+
11
+ ors << {
12
+ qualify(:lp, :provider_id) => query_ids.all_pacticipant_ids,
13
+ qualify(qualifier, :provider_version_id) => nil
14
+ }
15
+ Sequel.|(*ors)
16
+ end
17
+
18
+ def self.provider_or_provider_version_criteria(query_ids, qualifier = nil)
19
+ ors = []
20
+ ors << { qualify(qualifier, :provider_version_id) => query_ids.pacticipant_version_ids } if query_ids.pacticipant_version_ids.any?
21
+ ors << { qualify(qualifier, :provider_id) => query_ids.pacticipant_ids } if query_ids.pacticipant_ids.any?
22
+ ors
23
+ end
24
+
25
+ def self.consumer_in_pacticipant_ids(query_ids)
26
+ { consumer_id: query_ids.all_pacticipant_ids }
27
+ end
28
+
29
+ def self.consumer_or_consumer_version_matches(query_ids, qualifier)
30
+ ors = []
31
+ ors << { qualify(qualifier, :consumer_version_id) => query_ids.pacticipant_version_ids } if query_ids.pacticipant_version_ids.any?
32
+ ors << { qualify(qualifier, :consumer_id) => query_ids.pacticipant_ids } if query_ids.pacticipant_ids.any?
33
+
34
+ Sequel.|(*ors)
35
+ end
36
+
37
+ # Some selecters are specified in the query, others are implied (when only one pacticipant is specified,
38
+ # the integrations are automatically worked out, and the selectors for these are of type :implied )
39
+ # When there are 3 pacticipants that each have dependencies on each other (A->B, A->C, B->C), the query
40
+ # to deploy C (implied A, implied B, specified C) was returning the A->B row because it matched the
41
+ # implied selectors as well.
42
+ # This extra filter makes sure that every row that is returned actually matches one of the specified
43
+ # selectors.
44
+ def self.either_consumer_or_provider_was_specified_in_query(query_ids, qualifier = nil)
45
+ Sequel.|({
46
+ qualify(qualifier, :consumer_id) => query_ids.specified_pacticipant_ids
47
+ } , {
48
+ qualify(qualifier, :provider_id) => query_ids.specified_pacticipant_ids
49
+ })
50
+ end
51
+
52
+ # QueryIds is built from a single selector, so there is only one pacticipant_id or pacticipant_version_id
53
+ def self.consumer_or_consumer_version_or_provider_or_provider_or_provider_version_match(query_ids)
54
+ ors = if query_ids.pacticipant_version_id
55
+ [
56
+ { Sequel[:lp][:consumer_version_id] => query_ids.pacticipant_version_id },
57
+ { Sequel[:lv][:provider_version_id] => query_ids.pacticipant_version_id }
58
+ ]
59
+ else
60
+ [
61
+ { Sequel[:lp][:consumer_id] => query_ids.pacticipant_id },
62
+ { Sequel[:lp][:provider_id] => query_ids.pacticipant_id }
63
+ ]
64
+ end
65
+
66
+ Sequel.|(*ors)
67
+ end
68
+
69
+ def self.qualify(qualifier, column)
70
+ if qualifier
71
+ Sequel[qualifier][column]
72
+ else
73
+ column
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,40 @@
1
+ module PactBroker
2
+ module Matrix
3
+ class QueryIds
4
+ attr_reader :all_pacticipant_ids, :specified_pacticipant_ids, :pacticipant_ids, :pacticipant_version_ids
5
+
6
+ # pacticipant_version_ids - the pacticipant version ids from the selectors where the pacticipant version id is the most specific criterion
7
+ # pacticipant_ids - the pacticipant ids from the selectors where the pacticipant id is the most specific criterion
8
+ # all_pacticipant_ids - the pacticipant ids from all the selectors, regardless of whether or not a pacticipant version has also been specified
9
+ # specified_pacticipant_ids the IDs of the pacticipants that were specified in the can-i-deploy query
10
+ def initialize(all_pacticipant_ids, specified_pacticipant_ids, pacticipant_ids, pacticipant_version_ids)
11
+ @all_pacticipant_ids = all_pacticipant_ids
12
+ @specified_pacticipant_ids = specified_pacticipant_ids
13
+ @pacticipant_ids = pacticipant_ids
14
+ @pacticipant_version_ids = pacticipant_version_ids
15
+ @all_pacticipant_ids = all_pacticipant_ids
16
+ end
17
+
18
+ def self.from_selectors(selectors)
19
+ most_specific_criteria = selectors.collect(&:most_specific_criterion)
20
+ all_pacticipant_ids = selectors.collect(&:pacticipant_id)
21
+ specified_pacticipant_ids = selectors.select(&:specified?).collect(&:pacticipant_id)
22
+ pacticipant_version_ids = collect_ids(most_specific_criteria, :pacticipant_version_id)
23
+ pacticipant_ids = collect_ids(most_specific_criteria, :pacticipant_id)
24
+ QueryIds.new(all_pacticipant_ids, specified_pacticipant_ids, pacticipant_ids, pacticipant_version_ids)
25
+ end
26
+
27
+ def self.collect_ids(hashes, key)
28
+ hashes.collect{ |s| s[key] }.flatten.compact
29
+ end
30
+
31
+ def pacticipant_id
32
+ pacticipant_ids.first
33
+ end
34
+
35
+ def pacticipant_version_id
36
+ pacticipant_version_ids.first
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,11 +1,6 @@
1
- =begin
2
- The Matrix::Row is based on the matrix view which does a join of every pact/verification
3
- and then selects the relevant ones.
4
-
5
- The Matrix::QuickRow starts with the relevant rows, and builds the matrix query from that,
6
- making it much quicker.
7
-
8
- =end
1
+ require 'pact_broker/pacts/all_pact_publications'
2
+ require 'pact_broker/repositories/helpers'
3
+ require 'pact_broker/matrix/query_builder'
9
4
  require 'sequel'
10
5
  require 'pact_broker/repositories/helpers'
11
6
  require 'pact_broker/logging'
@@ -15,41 +10,64 @@ require 'pact_broker/domain/version'
15
10
  require 'pact_broker/domain/verification'
16
11
  require 'pact_broker/pacts/pact_publication'
17
12
  require 'pact_broker/tags/tag_with_latest_flag'
13
+ require 'pact_broker/matrix/query_ids'
14
+
15
+ # The difference between `join_verifications_for` and `join_verifications` is that
16
+ # the left outer join is done on a pre-filtered dataset in `join_verifications_for`,
17
+ # so that we get a row with null verification fields for a pact that has been verified
18
+ # by a *different* version of the provider we're interested in,
19
+ # rather than being excluded from the dataset altogether.
18
20
 
19
21
  module PactBroker
20
22
  module Matrix
21
- LV = :latest_verification_id_for_pact_version_and_provider_version
22
- LP = :latest_pact_publication_ids_for_consumer_versions
23
-
24
- CONSUMER_COLUMNS = [Sequel[:lp][:consumer_id], Sequel[:consumers][:name].as(:consumer_name), Sequel[:lp][:pact_publication_id], Sequel[:lp][:pact_version_id]]
25
- PROVIDER_COLUMNS = [Sequel[:lp][:provider_id], Sequel[:providers][:name].as(:provider_name), Sequel[:lv][:verification_id]]
26
- CONSUMER_VERSION_COLUMNS = [Sequel[:lp][:consumer_version_id], Sequel[:cv][:number].as(:consumer_version_number), Sequel[:cv][:order].as(:consumer_version_order)]
27
- PROVIDER_VERSION_COLUMNS = [Sequel[:lv][:provider_version_id], Sequel[:pv][:number].as(:provider_version_number), Sequel[:pv][:order].as(:provider_version_order)]
28
- ALL_COLUMNS = CONSUMER_COLUMNS + CONSUMER_VERSION_COLUMNS + PROVIDER_COLUMNS + PROVIDER_VERSION_COLUMNS
29
-
30
- LP_LV_JOIN = { Sequel[:lp][:pact_version_id] => Sequel[:lv][:pact_version_id] }
31
- CONSUMER_JOIN = { Sequel[:lp][:consumer_id] => Sequel[:consumers][:id] }
32
- PROVIDER_JOIN = { Sequel[:lp][:provider_id] => Sequel[:providers][:id] }
33
- CONSUMER_VERSION_JOIN = { Sequel[:lp][:consumer_version_id] => Sequel[:cv][:id] }
34
- PROVIDER_VERSION_JOIN = { Sequel[:lv][:provider_version_id] => Sequel[:pv][:id] }
35
-
36
- RAW_QUERY = Sequel::Model.db[Sequel.as(LP, :lp)]
37
- .select(*ALL_COLUMNS)
38
- .left_outer_join(LV, LP_LV_JOIN, { table_alias: :lv } )
39
- .join(:pacticipants, CONSUMER_JOIN, { table_alias: :consumers })
40
- .join(:pacticipants, PROVIDER_JOIN, { table_alias: :providers })
41
- .join(:versions, CONSUMER_VERSION_JOIN, { table_alias: :cv })
42
- .left_outer_join(:versions, PROVIDER_VERSION_JOIN, { table_alias: :pv } )
43
-
44
- ALIASED_QUERY = Sequel.as(RAW_QUERY, :quick_rows)
45
-
46
- class QuickRow < Sequel::Model(ALIASED_QUERY)
47
- CONSUMER_ID = Sequel[:quick_rows][:consumer_id]
48
- PROVIDER_ID = Sequel[:quick_rows][:provider_id]
49
- CONSUMER_VERSION_ID = Sequel[:quick_rows][:consumer_version_id]
50
- PROVIDER_VERSION_ID = Sequel[:quick_rows][:provider_version_id]
51
- PACT_PUBLICATION_ID = Sequel[:quick_rows][:pact_publication_id]
52
- VERIFICATION_ID = Sequel[:quick_rows][:verification_id]
23
+ class QuickRow < Sequel::Model(Sequel.as(:latest_pact_publication_ids_for_consumer_versions, :lp))
24
+
25
+ # Tables
26
+ LV = :latest_verification_id_for_pact_version_and_provider_version
27
+ LP = :latest_pact_publication_ids_for_consumer_versions
28
+
29
+ # Joins
30
+ LP_LV_JOIN = { Sequel[:lp][:pact_version_id] => Sequel[:lv][:pact_version_id] }
31
+ CONSUMER_JOIN = { Sequel[:lp][:consumer_id] => Sequel[:consumers][:id] }
32
+ PROVIDER_JOIN = { Sequel[:lp][:provider_id] => Sequel[:providers][:id] }
33
+ CONSUMER_VERSION_JOIN = { Sequel[:lp][:consumer_version_id] => Sequel[:cv][:id] }
34
+ PROVIDER_VERSION_JOIN = { Sequel[:lv][:provider_version_id] => Sequel[:pv][:id] }
35
+
36
+ # Not sure why we're eager loading some things and including others in the base query :shrug:
37
+
38
+ # Columns
39
+ CONSUMER_COLUMNS = [
40
+ Sequel[:lp][:consumer_id],
41
+ Sequel[:consumers][:name].as(:consumer_name)
42
+ ]
43
+ PROVIDER_COLUMNS = [
44
+ Sequel[:lp][:provider_id],
45
+ Sequel[:providers][:name].as(:provider_name)
46
+ ]
47
+ CONSUMER_VERSION_COLUMNS = [
48
+ Sequel[:lp][:consumer_version_id],
49
+ Sequel[:cv][:number].as(:consumer_version_number),
50
+ Sequel[:cv][:order].as(:consumer_version_order)
51
+ ]
52
+ PROVIDER_VERSION_COLUMNS = [
53
+ Sequel[:lv][:provider_version_id],
54
+ Sequel[:pv][:number].as(:provider_version_number),
55
+ Sequel[:pv][:order].as(:provider_version_order)
56
+ ]
57
+ PACT_COLUMNS = [
58
+ Sequel[:lp][:pact_publication_id],
59
+ Sequel[:lp][:pact_version_id]
60
+ ]
61
+ VERIFICATION_COLUMNS = [
62
+ Sequel[:lv][:verification_id]
63
+ ]
64
+ ALL_COLUMNS = CONSUMER_COLUMNS + CONSUMER_VERSION_COLUMNS + PACT_COLUMNS +
65
+ PROVIDER_COLUMNS + PROVIDER_VERSION_COLUMNS + VERIFICATION_COLUMNS
66
+ PACTICIPANT_NAMES_AND_IDS = CONSUMER_COLUMNS + PROVIDER_COLUMNS
67
+
68
+ # cachable select arguments
69
+ SELECT_ALL_COLUMN_ARGS = [:select_all_columns] + ALL_COLUMNS
70
+ SELECT_PACTICIPANT_NAMES_AND_IDS_ARGS = [:select_pacticipant_names_and_ids] + PACTICIPANT_NAMES_AND_IDS
53
71
 
54
72
  associate(:many_to_one, :pact_publication, :class => "PactBroker::Pacts::PactPublication", :key => :pact_publication_id, :primary_key => :id)
55
73
  associate(:many_to_one, :provider, :class => "PactBroker::Domain::Pacticipant", :key => :provider_id, :primary_key => :id)
@@ -63,102 +81,26 @@ module PactBroker
63
81
 
64
82
  dataset_module do
65
83
  include PactBroker::Repositories::Helpers
66
- include PactBroker::Logging
67
84
 
68
- def consumer_id consumer_id
69
- where(CONSUMER_ID => consumer_id)
85
+ select *SELECT_ALL_COLUMN_ARGS
86
+ select *SELECT_PACTICIPANT_NAMES_AND_IDS_ARGS
87
+
88
+ def distinct_integrations selectors
89
+ select_pacticipant_names_and_ids
90
+ .distinct
91
+ .matching_selectors(selectors)
70
92
  end
71
93
 
72
94
  def matching_selectors selectors
73
95
  if selectors.size == 1
74
- where_consumer_or_provider_is(selectors.first)
96
+ matching_one_selector(selectors)
75
97
  else
76
- where_consumer_and_provider_in(selectors)
77
- end
78
- end
79
-
80
- # find rows where (the consumer (and optional version) matches any of the selectors)
81
- # AND
82
- # the (provider (and optional version) matches any of the selectors OR the provider matches
83
- # and the verification is missing (and hence the provider version is null))
84
- def where_consumer_and_provider_in selectors
85
- where{
86
- Sequel.&(
87
- Sequel.|(
88
- *QueryHelper.consumer_and_maybe_consumer_version_match_any_selector(selectors)
89
- ),
90
- Sequel.|(
91
- *QueryHelper.provider_and_maybe_provider_version_match_any_selector_or_verification_is_missing(selectors)
92
- ),
93
- QueryHelper.either_consumer_or_provider_was_specified_in_query(selectors)
94
- )
95
- }
96
- end
97
-
98
- # Can't access other dataset_module methods from inside the Sequel `where{ ... }` block, so make a private class
99
- # with some helper methods
100
- class QueryHelper
101
- def self.consumer_and_maybe_consumer_version_match_any_selector(selectors)
102
- selectors.collect { |s| consumer_and_maybe_consumer_version_match_selector(s) }
103
- end
104
-
105
- def self.consumer_and_maybe_consumer_version_match_selector(s)
106
- if s[:pact_publication_ids]
107
- Sequel.&(PACT_PUBLICATION_ID => s[:pact_publication_ids])
108
- elsif s[:pacticipant_version_id]
109
- Sequel.&(CONSUMER_ID => s[:pacticipant_id], CONSUMER_VERSION_ID => s[:pacticipant_version_id])
110
- else
111
- Sequel.&(CONSUMER_ID => s[:pacticipant_id])
112
- end
113
- end
114
-
115
- def self.provider_and_maybe_provider_version_match_selector(s)
116
- if s[:verification_ids]
117
- Sequel.&(VERIFICATION_ID => s[:verification_ids])
118
- elsif s[:pacticipant_version_id]
119
- Sequel.&(PROVIDER_ID => s[:pacticipant_id], PROVIDER_VERSION_ID => s[:pacticipant_version_id])
120
- else
121
- Sequel.&(PROVIDER_ID => s[:pacticipant_id])
122
- end
123
- end
124
-
125
- # if the pact for a consumer version has never been verified, it exists in the matrix as a row
126
- # with a blank provider version id
127
- def self.provider_verification_is_missing_for_matching_selector(s)
128
- Sequel.&(PROVIDER_ID => s[:pacticipant_id], PROVIDER_VERSION_ID => nil)
129
- end
130
-
131
- def self.provider_and_maybe_provider_version_match_any_selector_or_verification_is_missing(selectors)
132
- selectors.collect { |s|
133
- provider_and_maybe_provider_version_match_selector(s)
134
- } + selectors.collect { |s|
135
- provider_verification_is_missing_for_matching_selector(s)
136
- }
137
- end
138
-
139
- # Some selecters are specified in the query, others are implied (when only one pacticipant is specified,
140
- # the integrations are automatically worked out, and the selectors for these are of type :implied )
141
- # When there are 3 pacticipants that each have dependencies on each other (A->B, A->C, B->C), the query
142
- # to deploy C (implied A, implied B, specified C) was returning the A->B row because it matched the
143
- # implied selectors as well.
144
- # This extra filter makes sure that every row that is returned actually matches one of the specified
145
- # selectors.
146
- def self.either_consumer_or_provider_was_specified_in_query(selectors)
147
- specified_pacticipant_ids = selectors.select{ |s| s[:type] == :specified }.collect{ |s| s[:pacticipant_id] }
148
- Sequel.|({ CONSUMER_ID => specified_pacticipant_ids } , { PROVIDER_ID => specified_pacticipant_ids })
98
+ matching_multiple_selectors(selectors)
149
99
  end
150
100
  end
151
101
 
152
- def where_consumer_or_provider_is s
153
- where{
154
- Sequel.|(
155
- s[:pacticipant_version_id] ? Sequel.&(CONSUMER_ID => s[:pacticipant_id], CONSUMER_VERSION_ID => s[:pacticipant_version_id]) : Sequel.&(CONSUMER_ID => s[:pacticipant_id]),
156
- s[:pacticipant_version_id] ? Sequel.&(PROVIDER_ID => s[:pacticipant_id], PROVIDER_VERSION_ID => s[:pacticipant_version_id]) : Sequel.&(PROVIDER_ID => s[:pacticipant_id])
157
- )
158
- }
159
- end
160
-
161
102
  def order_by_names_ascending_most_recent_first
103
+ from_self.
162
104
  order(
163
105
  Sequel.asc(:consumer_name),
164
106
  Sequel.desc(:consumer_version_order),
@@ -177,7 +119,86 @@ module PactBroker
177
119
  .eager(:pact_version)
178
120
  end
179
121
 
180
- end
122
+ def default_scope
123
+ select_all_columns.join_verifications.join_pacticipants_and_pacticipant_versions.from_self
124
+ end
125
+
126
+ # PRIVATE METHODS
127
+
128
+ # When we have one selector, we need to join ALL the verifications to find out
129
+ # what integrations exist
130
+ def matching_one_selector(selectors)
131
+ join_verifications
132
+ .join_pacticipants_and_pacticipant_versions
133
+ .where {
134
+ QueryBuilder.consumer_or_consumer_version_or_provider_or_provider_or_provider_version_match(QueryIds.from_selectors(selectors))
135
+ }
136
+ end
137
+
138
+ # When the user has specified multiple selectors, we only want to join the verifications for
139
+ # the specified selectors. This is because of the behaviour of the left outer join.
140
+ # Imagine a pact has been verified by a provider version that was NOT specified in the selectors.
141
+ # If we join all the verifications and THEN filter the rows to only show the versions specified
142
+ # in the selectors, we won't get a row for that pact, and hence, we won't
143
+ # know that it hasn't been verified by the provider version we're interested in.
144
+ # Instead, we need to filter the verifications dataset down to only the ones specified in the selectors first,
145
+ # and THEN join them to the pacts, so that we get a row for the pact with null provider version
146
+ # and verification fields.
147
+ def matching_multiple_selectors(selectors)
148
+ query_ids = QueryIds.from_selectors(selectors)
149
+ join_verifications_for(query_ids)
150
+ .join_pacticipants_and_pacticipant_versions
151
+ .where {
152
+ Sequel.&(
153
+ QueryBuilder.consumer_or_consumer_version_matches(query_ids, :lp),
154
+ QueryBuilder.provider_or_provider_version_matches_or_pact_unverified(query_ids, :lv),
155
+ QueryBuilder.either_consumer_or_provider_was_specified_in_query(query_ids, :lp)
156
+ )
157
+ }
158
+ end
159
+
160
+ def join_verifications_for(query_ids)
161
+ left_outer_join(verifications_for(query_ids), LP_LV_JOIN, { table_alias: :lv } )
162
+ end
163
+
164
+ def verifications_for(query_ids)
165
+ db[LV]
166
+ .select(:verification_id, :provider_version_id, :pact_version_id, :provider_id)
167
+ .where {
168
+ Sequel.&(
169
+ QueryBuilder.consumer_in_pacticipant_ids(query_ids),
170
+ QueryBuilder.provider_or_provider_version_matches(query_ids)
171
+ )
172
+ }
173
+ end
174
+
175
+ def join_pacticipants_and_pacticipant_versions
176
+ join_consumers
177
+ .join_providers
178
+ .join_consumer_versions
179
+ .join_provider_versions
180
+ end
181
+
182
+ def join_consumers
183
+ join(:pacticipants, CONSUMER_JOIN, { table_alias: :consumers })
184
+ end
185
+
186
+ def join_providers
187
+ join(:pacticipants, PROVIDER_JOIN, { table_alias: :providers })
188
+ end
189
+
190
+ def join_consumer_versions
191
+ join(:versions, CONSUMER_VERSION_JOIN, { table_alias: :cv })
192
+ end
193
+
194
+ def join_provider_versions
195
+ left_outer_join(:versions, PROVIDER_VERSION_JOIN, { table_alias: :pv } )
196
+ end
197
+
198
+ def join_verifications
199
+ left_outer_join(LV, LP_LV_JOIN, { table_alias: :lv } )
200
+ end
201
+ end # end dataset_module
181
202
 
182
203
  def success
183
204
  verification&.success
@@ -250,6 +271,50 @@ module PactBroker
250
271
  def involves_pacticipant_with_name?(pacticipant_name)
251
272
  pacticipant_name.include?(pacticipant_name)
252
273
  end
274
+
275
+ def provider_version_id
276
+ # null when not verified
277
+ values[:provider_version_id]
278
+ end
279
+
280
+ def verification_id
281
+ # null when not verified
282
+ return_or_raise_if_not_set(:verification_id)
283
+ end
284
+
285
+ def consumer_name
286
+ return_or_raise_if_not_set(:consumer_name)
287
+ end
288
+
289
+ def consumer_version_number
290
+ return_or_raise_if_not_set(:consumer_version_number)
291
+ end
292
+
293
+ def consumer_version_order
294
+ return_or_raise_if_not_set(:consumer_version_order)
295
+ end
296
+
297
+ def provider_name
298
+ return_or_raise_if_not_set(:provider_name)
299
+ end
300
+
301
+ def provider_version_number
302
+ return_or_raise_if_not_set(:provider_version_number)
303
+ end
304
+
305
+ def provider_version_order
306
+ return_or_raise_if_not_set(:provider_version_order)
307
+ end
308
+
309
+ # This model needs the verifications and pacticipants joined to it
310
+ # before it can be used, as it's not a "real" model.
311
+ def return_or_raise_if_not_set(key)
312
+ if values.key?(key)
313
+ values[key]
314
+ else
315
+ raise "Required table not joined"
316
+ end
317
+ end
253
318
  end
254
319
  end
255
320
  end