From da497a764921c8a333bb6c8b95e5f3d11e6e5830 Mon Sep 17 00:00:00 2001 From: Beth Skurrie Date: Fri, 23 Oct 2020 19:20:25 +1100 Subject: [PATCH] feat: use a sequence for the version order on postgres --- ...023_create_verification_number_sequence.rb | 2 +- .../20201024_create_version_order_sequence.rb | 20 ++++++++++ lib/pact_broker/versions/sequence.rb | 38 ++++++++++--------- tasks/database.rb | 1 + 4 files changed, 43 insertions(+), 18 deletions(-) create mode 100644 db/migrations/20201024_create_version_order_sequence.rb diff --git a/db/migrations/20201023_create_verification_number_sequence.rb b/db/migrations/20201023_create_verification_number_sequence.rb index 299b4a36c..23a0d5200 100644 --- a/db/migrations/20201023_create_verification_number_sequence.rb +++ b/db/migrations/20201023_create_verification_number_sequence.rb @@ -4,7 +4,7 @@ up do if PactBroker::MigrationHelper.postgres? row = from(:verification_sequence_number).select(:value).limit(1).first - start = row ? row[:value] + 1 : 1 + start = row ? row[:value] + 100 : 1 run("CREATE SEQUENCE verification_number_sequence START WITH #{start}") end end diff --git a/db/migrations/20201024_create_version_order_sequence.rb b/db/migrations/20201024_create_version_order_sequence.rb new file mode 100644 index 000000000..f36ec2f68 --- /dev/null +++ b/db/migrations/20201024_create_version_order_sequence.rb @@ -0,0 +1,20 @@ +require_relative 'migration_helper' + +Sequel.migration do + up do + if PactBroker::MigrationHelper.postgres? + row = from(:version_sequence_number).select(:value).limit(1).first + start = row ? row[:value] + 100 : 1 + run("CREATE SEQUENCE version_order_sequence START WITH #{start}") + end + end + + down do + if PactBroker::MigrationHelper.postgres? + nextval = execute("SELECT nextval('version_order_sequence') as val") { |v| v.first["val"].to_i } + # Add a safety margin! + from(:version_sequence_number).update(value: nextval + 100) + run("DROP SEQUENCE version_order_sequence") + end + end +end diff --git a/lib/pact_broker/versions/sequence.rb b/lib/pact_broker/versions/sequence.rb index e6a65e816..d45b492a1 100644 --- a/lib/pact_broker/versions/sequence.rb +++ b/lib/pact_broker/versions/sequence.rb @@ -8,23 +8,27 @@ class Sequence < Sequel::Model(:version_sequence_number) # The easiest way to implement a cross database compatible sequence. # Sad, I know. def next_val - db.transaction do - for_update.first - select_all.update(value: Sequel[:value]+1) - row = first - if row - row.value - else - # The first row should have been created in the migration, so this code - # should only ever be executed in a test context, after we've truncated all the - # tables after a test. - # There would be a risk of a race condition creating two rows if this - # code executed in prod, as I don't think you can lock an empty table - # to prevent another record being inserted. - max_version_order = PactBroker::Domain::Version.max(:order) - value = max_version_order ? max_version_order + 100 : 1 - insert(value: value) - value + if PactBroker::Repositories::Helpers.postgres? + db.execute("SELECT nextval('version_order_sequence') as val") { |v| v.first["val"].to_i } + else + db.transaction do + for_update.first + select_all.update(value: Sequel[:value]+1) + row = first + if row + row.value + else + # The first row should have been created in the migration, so this code + # should only ever be executed in a test context, after we've truncated all the + # tables after a test. + # There would be a risk of a race condition creating two rows if this + # code executed in prod, as I don't think you can lock an empty table + # to prevent another record being inserted. + max_version_order = PactBroker::Domain::Version.max(:order) + value = max_version_order ? max_version_order + 100 : 1 + insert(value: value) + value + end end end end diff --git a/tasks/database.rb b/tasks/database.rb index f714bfdad..b961cd928 100644 --- a/tasks/database.rb +++ b/tasks/database.rb @@ -60,6 +60,7 @@ def drop_views def drop_sequences if psql? database.run('DROP SEQUENCE verification_number_sequence') + database.run('DROP SEQUENCE version_order_sequence') end end