dodb.cr/src/dodb/index.cr

127 lines
2.5 KiB
Crystal
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

require "file_utils"
require "json"
require "./exceptions.cr"
require "./indexer.cr"
class DODB::Index(V) < DODB::Indexer(V)
property name : String
property key_proc : Proc(V, String)
getter storage_root : String
@storage : DODB::DataBase(V)
def initialize(@storage, @storage_root, @name, @key_proc)
Dir.mkdir_p indexing_directory
end
def check!(key, value, old_value)
index_key = key_proc.call value
symlink = file_path_index index_key.to_s
# FIXME: Check its not pointing to “old_value”, if any, before raising.
if ::File.exists? symlink
if old_value
old_key = key_proc.call old_value
return if symlink == file_path_index old_key.to_s
end
raise IndexOverload.new "index '#{@name}' is overloaded for key '#{key}'"
end
end
def index(key, value)
index_key = key_proc.call value
symlink = file_path_index index_key
Dir.mkdir_p ::File.dirname symlink
# FIXME: Now that this is done in check!, can we remove it?
if ::File.exists? symlink
raise Exception.new "symlink already exists: #{symlink}"
end
::File.symlink get_data_symlink_index(key), symlink
end
def deindex(key, value)
index_key = key_proc.call value
symlink = file_path_index index_key
::File.delete symlink
end
def get(index : String) : V
file_path = file_path_index index
raise MissingEntry.new(@name, index) unless ::File.exists? file_path
V.from_json ::File.read file_path
end
def get?(index : String) : V?
get index
rescue MissingEntry
nil
end
def get_key(index : String) : Int32
file_path = file_path_index index
raise MissingEntry.new(@name, index) unless ::File.exists? file_path
::File.readlink(file_path)
.sub(/\.json$/, "")
.sub(/^.*\//, "")
.to_i
end
def get_with_key(index : String) : Tuple(V, Int32)
key = get_key index
value = @storage[key]
{value, key}
end
# in case new_value hasn't change its index
def update(new_value : V)
index = key_proc.call new_value
update index, new_value
end
def update(index : String, new_value : V)
_, key = get_with_key index
@storage[key] = new_value
end
def update_or_create(index : String, new_value : V)
update index, new_value
rescue MissingEntry
@storage << new_value
end
def delete(index : String)
key = get_key index
@storage.delete key
end
def indexing_directory : String
"#{@storage_root}/indices/by_#{@name}"
end
private def file_path_index(index_key : String)
"#{indexing_directory}/#{index_key}.json"
end
private def get_data_symlink_index(key : String)
"../../data/#{key}.json"
end
end