Skip to content
Open
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
9 changes: 5 additions & 4 deletions lib/fbe/delete_one.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
# @param [Factbase] fb The factbase to use (defaults to Fbe.fb)
# @param [String] id The property name used as unique identifier (defaults to '_id')
# @return [nil] Nothing
# @raise [Fbe::Error] If fact is nil, has no ID, or shares its ID with another fact
def Fbe.delete_one(fact, prop, value, fb: Fbe.fb, id: '_id')
raise(Fbe::Error, 'The fact is nil') if fact.nil?
prop = prop.to_s
Expand All @@ -28,15 +29,15 @@ def Fbe.delete_one(fact, prop, value, fb: Fbe.fb, id: '_id')
fact.all_properties.each do |k|
before[k] = fact[k]
end
return unless before[prop]
nv = before[prop].dup
at = nv.index(value)
at = before.fetch(prop, []).index(value)
return if at.nil?
nv = before[prop].dup
nv.delete_at(at)
before[prop] = nv
before.delete(prop) if nv.empty?
fb.txn do |fbt|
fbt.query("(eq #{id} #{i})").delete!
deleted = fbt.query("(eq #{id} #{i})").delete!
raise(Fbe::Error, "#{deleted} facts share #{id} = #{i}, cannot delete one of them") if deleted > 1
c = fbt.insert
f = c
while f.instance_variable_defined?(:@fact) || f.instance_variable_defined?(:@origin)
Expand Down
35 changes: 35 additions & 0 deletions test/fbe/test_delete_one.rb
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,39 @@ def test_preserves_system_props_on_decorated_fb
assert_equal(snapshot[:job], after._job)
assert_equal([22], after['bar'])
end

def test_rejects_facts_sharing_the_id
seed = Random.new_seed
rnd = Random.new(seed)
fb = Factbase.new
id = rnd.rand(1..1000)
tags = Array.new(2) { |i| "t\u00e4g-#{i}-#{rnd.rand(1000)}" }
facts =
tags.map do |t|
f = fb.insert
f._id = id
f.tag = t
f
end
assert_raises(Fbe::Error, "delete_one destroyed every fact with _id #{id}, seed #{seed}") do
Fbe.delete_one(facts.first, 'tag', tags.first, fb:)
end
end

def test_rejects_facts_sharing_a_custom_id
seed = Random.new_seed
rnd = Random.new(seed)
fb = Factbase.new
key = rnd.rand(1..1000)
facts =
Array.new(rnd.rand(2..5)) do |i|
f = fb.insert
f.key = key
f.k = i
f
end
assert_raises(Fbe::Error, "delete_one destroyed #{facts.size} facts with key #{key}, seed #{seed}") do
Fbe.delete_one(facts.last, 'k', facts.size - 1, fb:, id: 'key')
end
end
end
Loading