Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support composite keys #17

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions lib/positioning/mechanisms.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,19 @@ 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
base_class.connection.quote_table_name_for_assignment base_class.table_name, @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
Expand Down Expand Up @@ -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"
Expand All @@ -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

Expand All @@ -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?
Expand Down
5 changes: 5 additions & 0 deletions test/models/item_with_composite_primary_key.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class ItemWithCompositePrimaryKey < ActiveRecord::Base
belongs_to :list

positioned on: :list
end
1 change: 1 addition & 0 deletions test/models/list.rb
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions test/support/active_record.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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")
25 changes: 25 additions & 0 deletions test/test_positioning.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -175,6 +176,16 @@ def test_primary_key
assert_equal student.id, mechanisms.send(: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"

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"
Expand All @@ -195,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"
Expand Down