From f855c0159c00942ecaac14da6eca97e74a4c851e Mon Sep 17 00:00:00 2001 From: Jacko Zuidema Date: Thu, 11 Jul 2024 10:54:55 +0200 Subject: [PATCH 1/2] Support composite keys --- lib/positioning/mechanisms.rb | 20 +++++++++++-------- .../models/item_with_composite_primary_key.rb | 5 +++++ test/models/list.rb | 1 + test/support/active_record.rb | 10 ++++++++++ test/test_positioning.rb | 9 +++++++++ 5 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 test/models/item_with_composite_primary_key.rb diff --git a/lib/positioning/mechanisms.rb b/lib/positioning/mechanisms.rb index 2fae8c2..14122b3 100644 --- a/lib/positioning/mechanisms.rb +++ b/lib/positioning/mechanisms.rb @@ -56,7 +56,11 @@ def primary_key_column end def primary_key - @positioned.send primary_key_column + if primary_key_column.is_a? Array + primary_key_column.map { |column| @positioned.send column } + else + @positioned.send primary_key_column + end end def quoted_column @@ -64,7 +68,7 @@ def quoted_column end def record_scope - base_class.where("#{primary_key_column}": primary_key) + base_class.where(Array(primary_key_column).zip(Array(primary_key)).to_h) end def position @@ -133,12 +137,12 @@ def solidify_position end relative_primary_key = if relative_record_or_primary_key.is_a? base_class - relative_record_or_primary_key.send(primary_key_column) + Array(primary_key_column).map { |column| relative_record_or_primary_key.send(column) } else - relative_record_or_primary_key + Array(relative_record_or_primary_key) end - relative_record_scope = positioning_scope.where("#{primary_key_column}": relative_primary_key) + relative_record_scope = positioning_scope.where(Array(primary_key_column).zip(relative_primary_key).to_h) unless relative_record_scope.exists? raise Error.new, "relative `#{@column}` record must be in the same scope" @@ -154,8 +158,8 @@ def solidify_position unless position.is_a? Integer raise Error.new, %(`#{@column}` must be an Integer, :first, :last, ) + - %{before: (#{base_class.name}, #{primary_key_column}, nil, or ""), } + - %{after: (#{base_class.name}, #{primary_key_column}, nil or ""), nil or ""} + %{before: (#{base_class.name}, #{Array(primary_key_column).join(", ")}, nil, or ""), } + + %{after: (#{base_class.name}, #{Array(primary_key_column).join(", ")}, nil or ""), nil or ""} end end @@ -176,7 +180,7 @@ def positioning_scope_was end def in_positioning_scope? - @positioned.persisted? && positioning_scope.where("#{primary_key_column}": primary_key).exists? + @positioned.persisted? && positioning_scope.where(Array(primary_key_column).zip(Array(primary_key)).to_h).exists? end def positioning_scope_changed? diff --git a/test/models/item_with_composite_primary_key.rb b/test/models/item_with_composite_primary_key.rb new file mode 100644 index 0000000..d51547b --- /dev/null +++ b/test/models/item_with_composite_primary_key.rb @@ -0,0 +1,5 @@ +class ItemWithCompositePrimaryKey < ActiveRecord::Base + belongs_to :list + + positioned on: :list +end diff --git a/test/models/list.rb b/test/models/list.rb index 118efda..c5c6083 100644 --- a/test/models/list.rb +++ b/test/models/list.rb @@ -1,5 +1,6 @@ class List < ActiveRecord::Base has_many :items, -> { order(:position) }, dependent: :destroy has_many :item_without_advisory_locks, -> { order(:position) }, dependent: :destroy + has_many :item_with_composite_primary_keys, -> { order(:position) }, dependent: :destroy has_many :authors, -> { order(:position) }, dependent: :destroy end diff --git a/test/support/active_record.rb b/test/support/active_record.rb index 6648e10..f9d0bfc 100644 --- a/test/support/active_record.rb +++ b/test/support/active_record.rb @@ -29,6 +29,16 @@ add_index :item_without_advisory_locks, [:list_id, :position], unique: true + create_table :item_with_composite_primary_keys, primary_key: [:item_id, :account_id], force: true do |t| + t.integer :item_id, null: false + t.integer :account_id, null: false + t.string :name + t.integer :position, null: false + t.references :list, null: false + end + + add_index :item_with_composite_primary_keys, [:list_id, :position], unique: true + create_table :categories, force: true do |t| t.string :name t.integer :position, null: false diff --git a/test/test_positioning.rb b/test/test_positioning.rb index 9ae097c..3c7f146 100644 --- a/test/test_positioning.rb +++ b/test/test_positioning.rb @@ -3,6 +3,7 @@ require_relative "models/list" require_relative "models/item" require_relative "models/item_without_advisory_lock" +require_relative "models/item_with_composite_primary_key" require_relative "models/category" require_relative "models/categorised_item" require_relative "models/author" @@ -175,6 +176,14 @@ def test_primary_key assert_equal student.id, mechanisms.send(:primary_key) end + def test_composite_primary_key + list = List.create name: "List" + item = list.item_with_composite_primary_keys.create item_id: "1", account_id: "1" + + mechanisms = Positioning::Mechanisms.new(item, :position) + assert_equal item.id, mechanisms.send(:primary_key) + end + def test_record_scope list = List.create name: "List" student = list.authors.create name: "Student", type: "Author::Student" From 61c3a52ad9a3f8e34e68d00786045a72f9118aaa Mon Sep 17 00:00:00 2001 From: Jacko Zuidema Date: Sat, 13 Jul 2024 12:24:56 +0200 Subject: [PATCH 2/2] Skip CPK tests before Rails 7.1 --- test/test_helper.rb | 2 ++ test/test_positioning.rb | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/test/test_helper.rb b/test/test_helper.rb index 86cc539..4847c24 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -5,3 +5,5 @@ require "minitest/hooks/test" require "minitest/autorun" require "mocha/minitest" + +RAILS_VERSION_WITTH_COMPOSITE_PRIMARY_KEYS = Gem::Version.new("7.1.0") diff --git a/test/test_positioning.rb b/test/test_positioning.rb index 3c7f146..4257735 100644 --- a/test/test_positioning.rb +++ b/test/test_positioning.rb @@ -177,6 +177,8 @@ def test_primary_key end def test_composite_primary_key + skip "Compsite primary keys are not yet supported in this Rails version." if ActiveRecord.version < RAILS_VERSION_WITTH_COMPOSITE_PRIMARY_KEYS + list = List.create name: "List" item = list.item_with_composite_primary_keys.create item_id: "1", account_id: "1" @@ -204,6 +206,20 @@ def test_position assert_equal 2, mechanisms.send(:position) end + def test_cpk_position + skip "Compsite primary keys are not yet supported in this Rails version." if ActiveRecord.version < RAILS_VERSION_WITTH_COMPOSITE_PRIMARY_KEYS + + list = List.create name: "List" + item1 = list.item_with_composite_primary_keys.create item_id: "1", account_id: "1" + item2 = list.item_with_composite_primary_keys.create item_id: "2", account_id: "1" + + mechanisms = Positioning::Mechanisms.new(item1, :position) + assert_equal 1, mechanisms.send(:position) + + mechanisms = Positioning::Mechanisms.new(item2, :position) + assert_equal 2, mechanisms.send(:position) + end + def test_position= list = List.create name: "List" student = list.authors.create name: "Student", type: "Author::Student"