Proper replacement of values.
It’s no longer needed to `hash.delete old_data`, `hash[id] = new_data`. Previously existing data are properly de-indexed, then replaced by the new data, which are then properly re-indexed. As you’d expect from a database thingy.remotes/1708105384931250775/master
parent
7a46fa3872
commit
2f00b56f0c
56
src/fs.cr
56
src/fs.cr
|
@ -104,14 +104,22 @@ class FS::Hash(K, V)
|
|||
end
|
||||
|
||||
def []=(key : K, value : V)
|
||||
# FIXME: Update partitions pointing to previous value (if any)
|
||||
# Removes any old indices or partitions pointing to a value about
|
||||
# to be replaced.
|
||||
self.[key]?.try do |old_value|
|
||||
remove_partitions key, old_value
|
||||
end
|
||||
|
||||
# avoid corruption in case of crash during file writing
|
||||
# Avoids corruption in case the application crashes while writing.
|
||||
file_path(key).tap do |path|
|
||||
::File.write "#{path}.new", value.to_json
|
||||
::FileUtils.mv "#{path}.new", path
|
||||
end
|
||||
|
||||
write_partitions key, value
|
||||
end
|
||||
|
||||
def write_partitions(key : K, value : V)
|
||||
@partitions.each do |index|
|
||||
index_key = index.key_proc.call value
|
||||
|
||||
|
@ -156,40 +164,44 @@ class FS::Hash(K, V)
|
|||
def delete(key : K)
|
||||
value = self[key]?
|
||||
|
||||
return if value.nil?
|
||||
|
||||
begin
|
||||
::File.delete file_path key
|
||||
rescue
|
||||
# FIXME: Only intercept “no such file" errors
|
||||
end
|
||||
|
||||
unless value.nil?
|
||||
@partitions.each do |index|
|
||||
index_key = index.key_proc.call value
|
||||
remove_partitions key, value
|
||||
|
||||
case index
|
||||
when IndexData
|
||||
symlink = file_path_indexes(key.to_s, index.name)
|
||||
value
|
||||
end
|
||||
|
||||
::File.delete symlink
|
||||
when PartitionData
|
||||
symlink = file_path_partition(key, index.name, index_key)
|
||||
def remove_partitions(key : K, value : V)
|
||||
@partitions.each do |index|
|
||||
index_key = index.key_proc.call value
|
||||
|
||||
::File.delete symlink
|
||||
end
|
||||
end
|
||||
case index
|
||||
when IndexData
|
||||
symlink = file_path_indexes(key.to_s, index.name)
|
||||
|
||||
@nn_partitions.each do |nn|
|
||||
indices = nn.key_proc.call value
|
||||
::File.delete symlink
|
||||
when PartitionData
|
||||
symlink = file_path_partition(key, index.name, index_key)
|
||||
|
||||
indices.each do |index_key|
|
||||
symlink = file_path_nn(key.to_s, nn.name, index_key)
|
||||
|
||||
::File.delete symlink
|
||||
end
|
||||
::File.delete symlink
|
||||
end
|
||||
end
|
||||
|
||||
value
|
||||
@nn_partitions.each do |nn|
|
||||
indices = nn.key_proc.call value
|
||||
|
||||
indices.each do |index_key|
|
||||
symlink = file_path_nn(key.to_s, nn.name, index_key)
|
||||
|
||||
::File.delete symlink
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
require "json"
|
||||
require "./src/fs.cr"
|
||||
require "uuid"
|
||||
|
||||
# This test basically works if no data is obtained when fetching "broken"
|
||||
# partitions/indices/tags.
|
||||
|
||||
class Ship
|
||||
JSON.mapping({
|
||||
id: String,
|
||||
class: String,
|
||||
name: String,
|
||||
tags: Array(String)
|
||||
})
|
||||
|
||||
def initialize(@name, @class = @name, @tags = [] of String)
|
||||
@id = UUID.random.to_s
|
||||
end
|
||||
|
||||
getter name
|
||||
getter id
|
||||
end
|
||||
|
||||
ships = FS::Hash(String, Ship).new "test-edit"
|
||||
by_name = ships.new_index "name", &.name
|
||||
by_class = ships.new_partition "class", &.class
|
||||
by_id = ships.new_index "id", &.id
|
||||
by_tags = ships.new_nn_partition "tags", &.tags
|
||||
|
||||
ship = Ship.new "Satsuki", "Mutsuki", tags: ["kuchikukan"]
|
||||
ships[ship.id] = ship
|
||||
|
||||
ship = Ship.new "Mutsuki", "Mutsuki", tags: ["kuchikukan"]
|
||||
ships[ship.id] = ship
|
||||
|
||||
ship = Ship.new "Kisaragi", "broken", tags: ["broken"]
|
||||
kisaragi = ship
|
||||
ships[ship.id] = ship
|
||||
|
||||
ship = Ship.new "Kisaragi", "Mutsuki", tags: ["kuchikukan"]
|
||||
ship.id = kisaragi.id # Overwriting the “broken” Kisaragi entry.
|
||||
ships[ship.id] = ship
|
||||
|
||||
puts "Database entries"
|
||||
ships.each do |id, ship|
|
||||
p "#{ship.name} (#{ship.class}) [#{ship.tags.join ", "}]"
|
||||
end
|
||||
|
||||
no_broken = Array(Array(Ship)).new
|
||||
puts
|
||||
puts "Partitions/indices"
|
||||
pp! ships.get_partition("class", "Mutsuki").map &.name
|
||||
pp! ships.get_nn_partition("tags", "kuchikukan").map &.name
|
||||
|
||||
pp! no_broken << ships.get_partition("class", "broken")
|
||||
pp! no_broken << ships.get_nn_partition("tags", "broken")
|
||||
|
||||
if no_broken.flatten.size > 0
|
||||
puts "ERROR: the test failed"
|
||||
end
|
||||
|
Loading…
Reference in New Issue