From ee4fef992ea266dcc0008aa4139f0ecd365fd72f Mon Sep 17 00:00:00 2001 From: Beth Skurrie Date: Sun, 5 Aug 2018 14:18:14 +1000 Subject: [PATCH] feat: replace latest_verifications view with latest_verifications_for_provider_versions --- db/ddl_statements.rb | 3 ++ db/ddl_statements/head_matrix_v001.rb | 31 ++++++++++++++++ db/ddl_statements/head_matrix_v002.rb | 31 ++++++++++++++++ ...fication_ids_for_provider_versions_v001.rb | 4 ++ .../20180311_optimise_head_matrix.rb | 35 +----------------- ...20180723_create_latest_verification_ids.rb | 3 +- db/migrations/20180726_recreate_views.rb | 7 ---- ...728_truncate_materialized_matrix_tables.rb | 20 ++++++++++ ..._verification_ids_for_provider_versions.rb | 8 ++++ ...est_verifications_for_provider_versions.rb | 29 +++++++++++++++ db/migrations/20180731_update_head_matrix.rb | 11 ++++++ db/pact_broker_database.sqlite3 | Bin 249856 -> 319488 bytes 12 files changed, 141 insertions(+), 41 deletions(-) create mode 100644 db/ddl_statements.rb create mode 100644 db/ddl_statements/head_matrix_v001.rb create mode 100644 db/ddl_statements/head_matrix_v002.rb create mode 100644 db/ddl_statements/latest_verification_ids_for_provider_versions_v001.rb create mode 100644 db/migrations/20180728_truncate_materialized_matrix_tables.rb create mode 100644 db/migrations/20180729_create_latest_verification_ids_for_provider_versions.rb create mode 100644 db/migrations/20180730_create_latest_verifications_for_provider_versions.rb create mode 100644 db/migrations/20180731_update_head_matrix.rb diff --git a/db/ddl_statements.rb b/db/ddl_statements.rb new file mode 100644 index 000000000..e9325dc9a --- /dev/null +++ b/db/ddl_statements.rb @@ -0,0 +1,3 @@ +Dir.glob(File.expand_path(File.join(__FILE__, "..", "ddl_statements", "*.rb"))).sort.each do | path | + require path +end diff --git a/db/ddl_statements/head_matrix_v001.rb b/db/ddl_statements/head_matrix_v001.rb new file mode 100644 index 000000000..4468ac8bc --- /dev/null +++ b/db/ddl_statements/head_matrix_v001.rb @@ -0,0 +1,31 @@ +HEAD_MATRIX_V1 = " +select + p.consumer_id, p.consumer_name, p.consumer_version_id, p.consumer_version_number, p.consumer_version_order, + p.id as pact_publication_id, p.pact_version_id, p.pact_version_sha, p.revision_number as pact_revision_number, + p.created_at as pact_created_at, + p.provider_id, p.provider_name, lv.provider_version_id, lv.provider_version_number, lv.provider_version_order, + lv.id as verification_id, lv.success, lv.number as verification_number, lv.execution_date as verification_executed_at, + lv.build_url as verification_build_url, + null as consumer_version_tag_name +from latest_pact_publications p +left outer join latest_verifications lv + on p.pact_version_id = lv.pact_version_id + +union all + +select + p.consumer_id, p.consumer_name, p.consumer_version_id, p.consumer_version_number, p.consumer_version_order, + p.id as pact_publication_id, p.pact_version_id, p.pact_version_sha, p.revision_number as pact_revision_number, + p.created_at as pact_created_at, + p.provider_id, p.provider_name, lv.provider_version_id, lv.provider_version_number, lv.provider_version_order, + lv.id as verification_id, lv.success, lv.number as verification_number, lv.execution_date as verification_executed_at, + lv.build_url as verification_build_url, + lt.tag_name as consumer_version_tag_name +from latest_tagged_pact_consumer_version_orders lt +inner join latest_pact_publications_by_consumer_versions p + on lt.consumer_id = p.consumer_id + and lt.provider_id = p.provider_id + and lt.latest_consumer_version_order = p.consumer_version_order +left outer join latest_verifications lv + on p.pact_version_id = lv.pact_version_id +" diff --git a/db/ddl_statements/head_matrix_v002.rb b/db/ddl_statements/head_matrix_v002.rb new file mode 100644 index 000000000..804dda13c --- /dev/null +++ b/db/ddl_statements/head_matrix_v002.rb @@ -0,0 +1,31 @@ +HEAD_MATRIX_V2 = " +select + p.consumer_id, p.consumer_name, p.consumer_version_id, p.consumer_version_number, p.consumer_version_order, + p.id as pact_publication_id, p.pact_version_id, p.pact_version_sha, p.revision_number as pact_revision_number, + p.created_at as pact_created_at, + p.provider_id, p.provider_name, lv.provider_version_id, lv.provider_version_number, lv.provider_version_order, + lv.id as verification_id, lv.success, lv.number as verification_number, lv.execution_date as verification_executed_at, + lv.build_url as verification_build_url, + null as consumer_version_tag_name +from latest_pact_publications p +left outer join latest_verifications_for_provider_versions lv + on p.pact_version_id = lv.pact_version_id + +union all + +select + p.consumer_id, p.consumer_name, p.consumer_version_id, p.consumer_version_number, p.consumer_version_order, + p.id as pact_publication_id, p.pact_version_id, p.pact_version_sha, p.revision_number as pact_revision_number, + p.created_at as pact_created_at, + p.provider_id, p.provider_name, lv.provider_version_id, lv.provider_version_number, lv.provider_version_order, + lv.id as verification_id, lv.success, lv.number as verification_number, lv.execution_date as verification_executed_at, + lv.build_url as verification_build_url, + lt.tag_name as consumer_version_tag_name +from latest_tagged_pact_consumer_version_orders lt +inner join latest_pact_publications_by_consumer_versions p + on lt.consumer_id = p.consumer_id + and lt.provider_id = p.provider_id + and lt.latest_consumer_version_order = p.consumer_version_order +left outer join latest_verifications_for_provider_versions lv + on p.pact_version_id = lv.pact_version_id +" diff --git a/db/ddl_statements/latest_verification_ids_for_provider_versions_v001.rb b/db/ddl_statements/latest_verification_ids_for_provider_versions_v001.rb new file mode 100644 index 000000000..78644bc8d --- /dev/null +++ b/db/ddl_statements/latest_verification_ids_for_provider_versions_v001.rb @@ -0,0 +1,4 @@ +LATEST_VERIFICATION_IDS_FOR_PROVIDER_VERSIONS_V1 = + "select pact_version_id, MAX(verification_id) latest_verification_id + FROM latest_verification_id_for_pact_version_and_provider_version + GROUP BY pact_version_id" diff --git a/db/migrations/20180311_optimise_head_matrix.rb b/db/migrations/20180311_optimise_head_matrix.rb index fc3db6d59..aafc3df30 100644 --- a/db/migrations/20180311_optimise_head_matrix.rb +++ b/db/migrations/20180311_optimise_head_matrix.rb @@ -1,4 +1,5 @@ require_relative 'migration_helper' +require_relative '../ddl_statements' Sequel.migration do up do @@ -46,38 +47,6 @@ ) - create_or_replace_view(:head_matrix, - " - select - p.consumer_id, p.consumer_name, p.consumer_version_id, p.consumer_version_number, p.consumer_version_order, - p.id as pact_publication_id, p.pact_version_id, p.pact_version_sha, p.revision_number as pact_revision_number, - p.created_at as pact_created_at, - p.provider_id, p.provider_name, lv.provider_version_id, lv.provider_version_number, lv.provider_version_order, - lv.id as verification_id, lv.success, lv.number as verification_number, lv.execution_date as verification_executed_at, - lv.build_url as verification_build_url, - null as consumer_version_tag_name - from latest_pact_publications p - left outer join latest_verifications lv - on p.pact_version_id = lv.pact_version_id - - union all - - select - p.consumer_id, p.consumer_name, p.consumer_version_id, p.consumer_version_number, p.consumer_version_order, - p.id as pact_publication_id, p.pact_version_id, p.pact_version_sha, p.revision_number as pact_revision_number, - p.created_at as pact_created_at, - p.provider_id, p.provider_name, lv.provider_version_id, lv.provider_version_number, lv.provider_version_order, - lv.id as verification_id, lv.success, lv.number as verification_number, lv.execution_date as verification_executed_at, - lv.build_url as verification_build_url, - lt.tag_name as consumer_version_tag_name - from latest_tagged_pact_consumer_version_orders lt - inner join latest_pact_publications_by_consumer_versions p - on lt.consumer_id = p.consumer_id - and lt.provider_id = p.provider_id - and lt.latest_consumer_version_order = p.consumer_version_order - left outer join latest_verifications lv - on p.pact_version_id = lv.pact_version_id - " - ) + create_or_replace_view(:head_matrix, HEAD_MATRIX_V1) end end diff --git a/db/migrations/20180723_create_latest_verification_ids.rb b/db/migrations/20180723_create_latest_verification_ids.rb index ba8289dda..1b3e78135 100644 --- a/db/migrations/20180723_create_latest_verification_ids.rb +++ b/db/migrations/20180723_create_latest_verification_ids.rb @@ -12,7 +12,8 @@ foreign_key :provider_version_id, :versions, null: false, on_delete: :cascade, foreign_key_constraint_name: 'latest_v_id_for_pv_and_pv_provider_version_id_fk' foreign_key :verification_id, :verifications, null: false, on_delete: :cascade, foreign_key_constraint_name: 'latest_v_id_for_pv_and_pv_verification_id_fk' index [:verification_id], unique: true, name: "latest_v_id_for_pv_and_pv_v_id_unq" - index [:pact_version_id, :provider_version_id], unique: true, name: "unq_latest_verifid_pvid_provid" + index [:pact_version_id, :provider_version_id], unique: true, name: "latest_v_id_for_pv_and_pv_pv_id_pv_id_unq" + index [:pact_version_id, :verification_id], name: "latest_v_id_for_pv_and_pv_pv_id_v_id" end end diff --git a/db/migrations/20180726_recreate_views.rb b/db/migrations/20180726_recreate_views.rb index 32266bf56..a754ad67f 100644 --- a/db/migrations/20180726_recreate_views.rb +++ b/db/migrations/20180726_recreate_views.rb @@ -11,13 +11,6 @@ left outer join latest_verification_id_for_pact_version_and_provider_version lv on lv.pact_version_id = pp.pact_version_id" ) - - # TODO - #drop_view(:latest_matrix) - #drop_view(:latest_verification_id_for_consumer_version_and_provider) - #drop_view(:latest_matrix_for_consumer_version_and_provider_version) - #drop_table(:materialized_matrix) - #drop_table(:materialized_head_matrix) end down do diff --git a/db/migrations/20180728_truncate_materialized_matrix_tables.rb b/db/migrations/20180728_truncate_materialized_matrix_tables.rb new file mode 100644 index 000000000..cb64349c1 --- /dev/null +++ b/db/migrations/20180728_truncate_materialized_matrix_tables.rb @@ -0,0 +1,20 @@ +Sequel.migration do + up do + from(:materialized_matrix).delete + from(:materialized_head_matrix).delete + + # TODO + # drop_view(:latest_matrix) + # drop_view(:latest_verification_id_for_consumer_version_and_provider) + # drop_view(:latest_matrix_for_consumer_version_and_provider_version) + # drop_table(:materialized_matrix) + # drop_table(:materialized_head_matrix) + end + + down do + from(:materialized_matrix).delete + from(:materialized_matrix).insert(from(:matrix).select_all) + from(:materialized_head_matrix).delete + from(:materialized_head_matrix).insert(from(:head_matrix).select_all) + end +end diff --git a/db/migrations/20180729_create_latest_verification_ids_for_provider_versions.rb b/db/migrations/20180729_create_latest_verification_ids_for_provider_versions.rb new file mode 100644 index 000000000..2a4c3ce3a --- /dev/null +++ b/db/migrations/20180729_create_latest_verification_ids_for_provider_versions.rb @@ -0,0 +1,8 @@ +require_relative '../ddl_statements' + +Sequel.migration do + change do + create_view(:latest_verification_ids_for_provider_versions, + LATEST_VERIFICATION_IDS_FOR_PROVIDER_VERSIONS_V1) + end +end diff --git a/db/migrations/20180730_create_latest_verifications_for_provider_versions.rb b/db/migrations/20180730_create_latest_verifications_for_provider_versions.rb new file mode 100644 index 000000000..3ea8a0aaa --- /dev/null +++ b/db/migrations/20180730_create_latest_verifications_for_provider_versions.rb @@ -0,0 +1,29 @@ +Sequel.migration do + change do + # The most recent verification for each pact_version + v = :verifications + create_view(:latest_verifications_for_provider_versions, + from(v) + .select( + Sequel[v][:id], + Sequel[v][:number], + Sequel[v][:success], + Sequel[v][:build_url], + Sequel[v][:pact_version_id], + Sequel[v][:execution_date], + Sequel[v][:created_at], + Sequel[v][:provider_version_id], + Sequel[:s][:number].as(:provider_version_number), + Sequel[:s][:order].as(:provider_version_order)) + .join(:latest_verification_ids_for_provider_versions, + { + Sequel[v][:pact_version_id] => Sequel[:lv][:pact_version_id], + Sequel[v][:id] => Sequel[:lv][:latest_verification_id] + }, { table_alias: :lv }) + .join(:versions, + { + Sequel[v][:provider_version_id] => Sequel[:s][:id] + }, { table_alias: :s }) + ) + end +end diff --git a/db/migrations/20180731_update_head_matrix.rb b/db/migrations/20180731_update_head_matrix.rb new file mode 100644 index 000000000..2aa15d5ea --- /dev/null +++ b/db/migrations/20180731_update_head_matrix.rb @@ -0,0 +1,11 @@ +Sequel.migration do + up do + create_or_replace_view(:head_matrix, HEAD_MATRIX_V2) + #TODO + #drop_view(:latest_verifications) + end + + down do + create_or_replace_view(:head_matrix, HEAD_MATRIX_V1) + end +end diff --git a/db/pact_broker_database.sqlite3 b/db/pact_broker_database.sqlite3 index 856f6f89fe3e9cf36d852040af70cdbd9bdbd24b..dd84baee9702e8f60fd3d38babc9d569769e5e27 100644 GIT binary patch delta 7789 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