diff --git a/lib/sequel/plugins/list.rb b/lib/sequel/plugins/list.rb index 3e06d1bb3..bca2ef0f8 100644 --- a/lib/sequel/plugins/list.rb +++ b/lib/sequel/plugins/list.rb @@ -185,10 +185,13 @@ def prev(n = 1) end # Set the value of the position_field to the maximum value plus 1 unless the - # position field already has a value. + # position field already has a value. If the list is empty, the position will + # be set to the model's +top_of_list+ value. def before_validation unless get_column_value(position_field) - set_column_value("#{position_field}=", list_dataset.max(position_field).to_i+1) + current_max = list_dataset.max(position_field) + value = current_max.nil? ? model.top_of_list : current_max.to_i + 1 + set_column_value("#{position_field}=", value) end super end diff --git a/spec/extensions/list_spec.rb b/spec/extensions/list_spec.rb index 12e2792fa..f8c6b34cb 100644 --- a/spec/extensions/list_spec.rb +++ b/spec/extensions/list_spec.rb @@ -113,6 +113,18 @@ def klass(opts={}) "SELECT * FROM items WHERE (id = 3) ORDER BY scope_id, position LIMIT 1"] end + it "should have position field set to configured top value when creating first item in the list if not already set" do + @tc.dataset = @tc.dataset.with_autoid(1).with_fetch([[{:pos=>nil}], [{:id=>1, :position=>0}], [{:pos=>0}], [{:id=>2, :position=>1}]]) + @tc.create.values.must_equal(:id=>1, :position=>0) + @tc.create.values.must_equal(:id=>2, :position=>1) + @db.sqls.must_equal ["SELECT max(position) AS max FROM items LIMIT 1", + "INSERT INTO items (position) VALUES (0)", + "SELECT * FROM items WHERE (id = 1) ORDER BY position LIMIT 1", + "SELECT max(position) AS max FROM items LIMIT 1", + "INSERT INTO items (position) VALUES (1)", + "SELECT * FROM items WHERE (id = 2) ORDER BY position LIMIT 1"] + end + it "should update positions automatically on deletion" do @o.destroy @db.sqls.must_equal ["DELETE FROM items WHERE (id = 7)", "UPDATE items SET position = (position - 1) WHERE (position > 3)"]