Rewrite of the tag mechanism. Tests are needed.

This commit is contained in:
Karchnu 2024-04-26 19:35:00 +02:00
parent 35f5c52cbc
commit 7584c3acc0
2 changed files with 61 additions and 57 deletions

View File

@ -277,7 +277,7 @@ describe "DODB::DataBase" do
end end
# Removing the “flagship” tag, brace for impact. # Removing the “flagship” tag, brace for impact.
flagship, index = db_ships_by_tags.get_with_indices("flagship")[0] flagship, index = db_ships_by_tags.get_with_indice("flagship")[0]
flagship.tags = [] of String flagship.tags = [] of String
db[index] = flagship db[index] = flagship

View File

@ -10,48 +10,27 @@ class DODB::Tags(V) < DODB::Indexer(V)
::Dir.mkdir_p indexing_directory ::Dir.mkdir_p indexing_directory
end end
# FIXME: The slow is damn too high. def check!(key, value, old_value)
def tag_combinations(tags) return true # Tags dont have collisions or overloads.
combinations = [] of Array(String)
tags.size.times do |i|
combinations.concat tags.permutations (i+1)
end
return combinations
end end
def index(key, value) def index(key, value)
indices = key_proc.call(value).sort indices = key_proc.call(value)
tag_combinations(indices).each do |previous_indices|
# FIXME: Not on `index`, but on the list of all previous indices.
symdir = symlinks_directory previous_indices
otdir = other_tags_directory previous_indices
::Dir.mkdir_p symdir
::Dir.mkdir_p otdir
symlink = get_tagged_entry_path(key, previous_indices)
indices.each do |i|
symlink = get_tagged_entry_path(i, key)
Dir.mkdir_p ::File.dirname symlink
# FIXME: Should not happen anymore. Should we remove this?
::File.delete symlink if ::File.exists? symlink ::File.delete symlink if ::File.exists? symlink
::File.symlink get_data_symlink(key), symlink
::File.symlink get_data_symlink(key, previous_indices), symlink
end end
end end
def deindex(key, value) def deindex(key, value)
indices = key_proc.call(value).sort indices = key_proc.call(value)
tag_combinations(indices).each do |previous_indices| indices.each do |i|
# FIXME: Not on `index`, but on the list of all previous indices. symlink = get_tagged_entry_path(i, key)
symdir = symlinks_directory previous_indices
otdir = other_tags_directory previous_indices
::Dir.mkdir_p symdir
::Dir.mkdir_p otdir
symlink = get_tagged_entry_path(key, previous_indices)
::File.delete symlink if ::File.exists? symlink ::File.delete symlink if ::File.exists? symlink
@ -59,24 +38,16 @@ class DODB::Tags(V) < DODB::Indexer(V)
end end
end end
def check!(key, value, old_value) def get_with_indice(tag : String) : Array(Tuple(V, Int32))
return true # Tags dont have collisions or overloads.
end
def get_with_indices(key : String) : Array(Tuple(V, Int32))
get_with_indices [key]
end
def get_with_indices(keys : Array(String)) : Array(Tuple(V, Int32))
r_value = Array(Tuple(V, Int32)).new r_value = Array(Tuple(V, Int32)).new
partition_directory = symlinks_directory keys tag_directory = indexing_directory tag
return r_value unless Dir.exists? partition_directory return r_value unless Dir.exists? tag_directory
Dir.each_child partition_directory do |child| Dir.each_child tag_directory do |child|
r_value << { r_value << {
V.from_json(::File.read("#{partition_directory}/#{child}")), V.from_json(::File.read("#{tag_directory}/#{child}")),
File.basename(child).gsub(/\.json$/, "").to_i File.basename(child).gsub(/\.json$/, "").to_i
} }
end end
@ -84,30 +55,63 @@ class DODB::Tags(V) < DODB::Indexer(V)
r_value r_value
end end
def get(key : String) : Array(V) def get_with_indices(keys : Array(String)) : Array(Tuple(V, Int32))
get_with_indices(key).map &.[0] r_value = Array(Tuple(V, Int32)).new
keys.each do |tag|
r_value.concat get_with_indice tag
end
r_value
end
def get(tag : String) : Array(V)
get_with_indice(tag).map &.[0]
end end
def get(keys : Array(String)) : Array(V) def get(keys : Array(String)) : Array(V)
get_with_indices(keys.sort).map &.[0] get_with_indices(keys.sort).map &.[0]
end end
def delete(tag)
delete tag, do true end
end
def delete(tag, &matcher)
tag_directory = indexing_directory tag
return unless Dir.exists? tag_directory
Dir.each_child tag_directory do |child|
path = "#{tag_directory}/#{child}"
item = V.from_json ::File.read path
if yield item
key = get_key path
@storage.delete key
end
end
end
private def get_key(path : String) : Int32
::File.readlink(path)
.sub(/\.json$/, "")
.sub(/^.*\//, "")
.to_i
end
def indexing_directory : String def indexing_directory : String
"#{@storage_root}/tags/by_#{@name}" "#{@storage_root}/tags/by_#{@name}"
end end
private def symlinks_directory(previous_indices : Array(String)) private def indexing_directory(tag)
"#{indexing_directory}#{previous_indices.map { |i| "/other-tags/#{i}" }.join}/data" "#{indexing_directory}/#{tag}"
end
private def other_tags_directory(previous_indices : Array(String))
"#{indexing_directory}#{previous_indices.map { |i| "/other-tags/#{i}" }.join}/other-tags"
end end
private def get_tagged_entry_path(key : String, indices : Array(String)) private def get_tagged_entry_path(tag : String, key : String)
"#{indexing_directory}#{indices.map { |i| "/other-tags/#{i}" }.join}/data/#{key}.json" "#{indexing_directory}/#{tag}/#{key}.json"
end end
private def get_data_symlink(key : String, indices : Array(String))
"../../../#{indices.map { "../../" }.join}/data/#{key}.json" private def get_data_symlink(key : String)
"../../../data/#{key}.json"
end end
end end