test: cover teardown and test_add_column_backfill_rebuilds_an_index_b...

This commit is contained in:
dualfroz committed 2026-09-12 16:16:07 +02:00
1 parent 5ce2152a70
commit 4ca517b1a7
1 file changed
+162
+162
View File
@@ -158,3 +158,165 @@ class OrmIndexColumnMigrationTest < Minitest::Test
@store.create_table(:posts, %w[id title])
end
def teardown
FileUtils.remove_entry(@dir)
end
def test_add_column_backfill_rebuilds_an_index_built_before_the_column_existed
id1 = @store.insert(:posts, title: 'first')
id2 = @store.insert(:posts, title: 'second')
@store.add_index(:posts, :status)
@store.add_column(:posts, :status, default: 'draft')
matches = @store.lookup_by_index(:posts, { 'status' => 'draft' })
refute_nil matches, 'the index should still cover the column after the backfill'
assert_equal [id1, id2].sort, matches.map { |row| row['id'] }.sort
end
def test_add_column_backfill_drops_the_stale_nil_key_from_the_index
@store.insert(:posts, title: 'first')
@store.add_index(:posts, :status)
@store.add_column(:posts, :status, default: 'draft')
assert_equal [], @store.lookup_by_index(:posts, { 'status' => nil }),
'no row should still be indexed under the pre-backfill nil value'
end
def test_add_column_backfill_keeps_a_range_capable_index_usable
id1 = @store.insert(:posts, title: 'first')
id2 = @store.insert(:posts, title: 'second')
@store.add_index(:posts, :priority)
@store.add_column(:posts, :priority, default: 5)
matches = @store.lookup_by_index_range(:posts, :priority, gte: 1)
refute_nil matches
assert_equal [id1, id2].sort, matches.map { |row| row['id'] }.sort
end
def test_remove_column_drops_a_single_column_index_covering_it
@store.add_index(:posts, :status, name: 'idx_status')
@store.remove_column(:posts, :status)
assert_equal [], @store.indexes(:posts)
assert_nil @store.lookup_by_index(:posts, { 'status' => 'draft' }),
'a dropped column must never be reported as indexed again'
end
def test_remove_column_drops_a_composite_index_covering_it
@store.add_column(:posts, :status, default: 'draft')
@store.add_index(:posts, %i[title status])
@store.remove_column(:posts, :title)
assert_equal [], @store.indexes(:posts),
'a composite index cannot survive with one of its columns gone'
end
def test_remove_column_leaves_indexes_on_other_columns_untouched
@store.add_column(:posts, :status, default: 'draft')
@store.add_index(:posts, :title)
@store.add_index(:posts, :status)
@store.remove_column(:posts, :status)
assert_equal ['index_posts_on_title'], @store.indexes(:posts).map { |index| index[:name] }
end
def test_remove_column_then_readding_it_starts_with_a_clean_index_free_slate
id = @store.insert(:posts, title: 'first')
@store.add_index(:posts, :status)
@store.add_column(:posts, :status, default: 'draft')
@store.remove_column(:posts, :status)
@store.add_column(:posts, :status, default: 'archived')
assert_equal [], @store.indexes(:posts),
'removing the column must have dropped the earlier index for good'
assert_equal 'archived', @store.find(:posts, id)['status']
end
end
class OrmIndexRangeStoreTest < Minitest::Test
def setup
@dir = Dir.mktmpdir('prism-index-range-store')
@store = Prism::Orm::Store.new(File.join(@dir, 'test.pstore'))
@store.create_table(:users, %w[id email age])
end
def teardown
FileUtils.remove_entry(@dir)
end
def test_single_column_index_is_range_capable_and_sorted
@store.insert(:users, email: 'c@x.com', age: 30)
@store.insert(:users, email: 'a@x.com', age: 10)
@store.insert(:users, email: 'b@x.com', age: 20)
@store.add_index(:users, :age)
matches = @store.lookup_by_index_range(:users, :age, gte: 20)
assert_equal [20, 30], matches.map { |row| row['age'] }.sort
end
def test_composite_index_is_never_range_capable
@store.add_index(:users, [:email, :age])
@store.insert(:users, email: 'a@x.com', age: 10)
assert_nil @store.lookup_by_index_range(:users, :age, gte: 0)
end
def test_lookup_by_index_range_returns_nil_without_a_covering_index
@store.insert(:users, email: 'a@x.com', age: 10)
assert_nil @store.lookup_by_index_range(:users, :age, gte: 0)
end
def test_gte_is_inclusive
@store.add_index(:users, :age)
@store.insert(:users, email: 'a@x.com', age: 20)
matches = @store.lookup_by_index_range(:users, :age, gte: 20)
assert_equal 1, matches.size
end
def test_gt_is_exclusive
@store.add_index(:users, :age)
@store.insert(:users, email: 'a@x.com', age: 20)
assert_equal [], @store.lookup_by_index_range(:users, :age, gt: 20)
end
def test_lte_is_inclusive
@store.add_index(:users, :age)
@store.insert(:users, email: 'a@x.com', age: 20)
matches = @store.lookup_by_index_range(:users, :age, lte: 20)
assert_equal 1, matches.size
end
def test_lt_is_exclusive
@store.add_index(:users, :age)
@store.insert(:users, email: 'a@x.com', age: 20)
assert_equal [], @store.lookup_by_index_range(:users, :age, lt: 20)
end
def test_combined_lower_and_upper_bound
@store.add_index(:users, :age)
[5, 15, 25, 35, 45].each { |age| @store.insert(:users, email: "#{age}@x.com", age: age) }
matches = @store.lookup_by_index_range(:users, :age, gte: 15, lte: 35)
assert_equal [15, 25, 35], matches.map { |row| row['age'] }.sort
end
def test_nil_valued_rows_are_never_returned_by_a_range_lookup
@store.add_index(:users, :age)
@store.insert(:users, email: 'a@x.com', age: nil)
@store.insert(:users, email: 'b@x.com', age: 10)
matches = @store.lookup_by_index_range(:users, :age, gte: 0)
assert_equal ['b@x.com'], matches.map { |row| row['email'] }
end
def test_index_backfilled_from_existing_rows_is_range_capable
@store.insert(:users, email: 'a@x.com', age: 10)
@store.insert(:users, email: 'b@x.com', age: 20)
@store.add_index(:users, :age)
matches = @store.lookup_by_index_range(:users, :age, gte: 15)
assert_equal ['b@x.com'], matches.map { |row| row['email'] }
end