Removes a lot of duplicated code.
This commit is contained in:
parent
2b24fbc8a0
commit
7a342f8391
@ -96,28 +96,45 @@ class DODB::Partition(V) < DODB::Indexer(V)
|
|||||||
# WARNING: throws an exception if no value is found.
|
# WARNING: throws an exception if no value is found.
|
||||||
# NOTE: for a safe version, use `#get?`.
|
# NOTE: for a safe version, use `#get?`.
|
||||||
def get(partition : String) : Array(V)
|
def get(partition : String) : Array(V)
|
||||||
partition_directory = indexing_directory partition
|
get_with_keys(partition).map &.[0]
|
||||||
raise MissingEntry.new(@name, partition) unless Dir.exists? partition_directory
|
|
||||||
|
|
||||||
r_value = Array(V).new
|
|
||||||
|
|
||||||
Dir.each_child partition_directory do |child|
|
|
||||||
r_value << @storage[get_key child]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
r_value
|
# Safe version of `#get`, gets data and returns *an empty array* in case of
|
||||||
end
|
|
||||||
|
|
||||||
# Safe version of `#get`, gets data and returns a *nil* value in case of
|
|
||||||
# a missing entry instead of an exception.
|
# a missing entry instead of an exception.
|
||||||
#
|
#
|
||||||
# ```
|
# ```
|
||||||
# red_cars = cars_by_color.get? "red" # No red cars = nil.
|
# red_cars = cars_by_color.get? "red"
|
||||||
# ```
|
# ```
|
||||||
def get?(partition : String) : Array(V)?
|
def get?(partition : String) : Array(V)?
|
||||||
get partition
|
get partition
|
||||||
rescue MissingEntry
|
rescue MissingEntry
|
||||||
nil
|
Array(V).new
|
||||||
|
end
|
||||||
|
|
||||||
|
# Gets partition entries (and their keys) from the file-system representation.
|
||||||
|
#
|
||||||
|
# ```
|
||||||
|
# # Gets all red cars.
|
||||||
|
# cars_by_color.get "red"
|
||||||
|
# # Returns something like:
|
||||||
|
# # [ (@storage[42], 42)
|
||||||
|
# # , (@storage[91], 91)
|
||||||
|
# # ]
|
||||||
|
# # Each tuple is composed of a car and its key in the database.
|
||||||
|
# ```
|
||||||
|
# WARNING: throws a MissingEntry exception on non-existing partition.
|
||||||
|
def get_with_keys(partition : String) : Array(Tuple(V, Int32))
|
||||||
|
partition_directory = indexing_directory partition
|
||||||
|
raise MissingEntry.new(@name, partition) unless Dir.exists? partition_directory
|
||||||
|
|
||||||
|
r_value = Array(Tuple(V, Int32)).new
|
||||||
|
|
||||||
|
Dir.each_child partition_directory do |child|
|
||||||
|
key = get_key child
|
||||||
|
r_value << { @storage[key], key }
|
||||||
|
end
|
||||||
|
|
||||||
|
r_value
|
||||||
end
|
end
|
||||||
|
|
||||||
# Deletes all entries within the provided partition.
|
# Deletes all entries within the provided partition.
|
||||||
@ -125,6 +142,7 @@ class DODB::Partition(V) < DODB::Indexer(V)
|
|||||||
# ```
|
# ```
|
||||||
# cars_by_color.delete "red" # Deletes all red cars.
|
# cars_by_color.delete "red" # Deletes all red cars.
|
||||||
# ```
|
# ```
|
||||||
|
# WARNING: throws a MissingEntry exception on non-existing partition.
|
||||||
def delete(partition : String)
|
def delete(partition : String)
|
||||||
delete partition, do true end
|
delete partition, do true end
|
||||||
end
|
end
|
||||||
@ -137,17 +155,10 @@ class DODB::Partition(V) < DODB::Indexer(V)
|
|||||||
# car.name == "Corvet"
|
# car.name == "Corvet"
|
||||||
# end
|
# end
|
||||||
# ```
|
# ```
|
||||||
# TODO: in case the partition is left empty, should the partition's directory be removed?
|
# WARNING: throws a MissingEntry exception on non-existing partition.
|
||||||
def delete(partition, &matcher : Proc(V, Bool))
|
def delete(partition : String, &matcher : Proc(V, Bool))
|
||||||
partition_directory = indexing_directory partition
|
get_with_keys(partition).each do |entry, key|
|
||||||
|
if yield entry
|
||||||
return unless Dir.exists? partition_directory
|
|
||||||
|
|
||||||
Dir.each_child partition_directory do |child|
|
|
||||||
key = get_key child
|
|
||||||
item = @storage[key]
|
|
||||||
|
|
||||||
if yield item
|
|
||||||
@storage.delete key
|
@storage.delete key
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -213,12 +224,6 @@ class DODB::CachedPartition(V) < DODB::Partition(V)
|
|||||||
# WARNING: used for internal operations, do not change its content or access it directly.
|
# WARNING: used for internal operations, do not change its content or access it directly.
|
||||||
property data = Hash(String, Array(Int32)).new
|
property data = Hash(String, Array(Int32)).new
|
||||||
|
|
||||||
# Clears the cache and removes the `#indexing_directory`.
|
|
||||||
def nuke_index
|
|
||||||
super
|
|
||||||
data.clear
|
|
||||||
end
|
|
||||||
|
|
||||||
# Indexes the value on the file-system as `DODB::Partition#index` but also puts the index in a cache.
|
# Indexes the value on the file-system as `DODB::Partition#index` but also puts the index in a cache.
|
||||||
#
|
#
|
||||||
# NOTE: used for internal operations.
|
# NOTE: used for internal operations.
|
||||||
@ -253,6 +258,9 @@ class DODB::CachedPartition(V) < DODB::Partition(V)
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Gets partition entries and the database key for each entry.
|
# Gets partition entries and the database key for each entry.
|
||||||
|
# In `DODB::CachedPartition`, `#get_with_keys(partition : String)` is modified to retrieve data keys from
|
||||||
|
# the index cache.
|
||||||
|
# In case the data isn't already in the cache, it is retrieved from the file-system.
|
||||||
#
|
#
|
||||||
# ```
|
# ```
|
||||||
# # For example, get all red cars.
|
# # For example, get all red cars.
|
||||||
@ -263,6 +271,7 @@ class DODB::CachedPartition(V) < DODB::Partition(V)
|
|||||||
# # ]
|
# # ]
|
||||||
# # Each tuple is composed of a car and its key in the database.
|
# # Each tuple is composed of a car and its key in the database.
|
||||||
# ```
|
# ```
|
||||||
|
# WARNING: throws a MissingEntry exception on non-existing partition.
|
||||||
def get_with_keys(partition : String) : Array(Tuple(V, Int32))
|
def get_with_keys(partition : String) : Array(Tuple(V, Int32))
|
||||||
r_value = Array(Tuple(V, Int32)).new
|
r_value = Array(Tuple(V, Int32)).new
|
||||||
|
|
||||||
@ -272,73 +281,17 @@ class DODB::CachedPartition(V) < DODB::Partition(V)
|
|||||||
r_value << { @storage[data_key], data_key }
|
r_value << { @storage[data_key], data_key }
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
# Get the key from the database representation on the file-system.
|
# Gets data from the database representation on the file-system.
|
||||||
partition_directory = indexing_directory partition
|
r_value = super(partition)
|
||||||
raise MissingEntry.new(@name, partition) unless Dir.exists? partition_directory
|
|
||||||
|
|
||||||
Dir.each_child partition_directory do |child|
|
|
||||||
r_value << { @storage[get_key child], get_key child }
|
|
||||||
end
|
|
||||||
|
|
||||||
@data[partition] = r_value.map &.[1]
|
@data[partition] = r_value.map &.[1]
|
||||||
end
|
end
|
||||||
r_value
|
r_value
|
||||||
end
|
end
|
||||||
|
|
||||||
# Gets partition entries from the cache or the file-system representation.
|
# Clears the cache and removes the `#indexing_directory`.
|
||||||
#
|
def nuke_index
|
||||||
# ```
|
super
|
||||||
# # For example, get all red cars.
|
data.clear
|
||||||
# cars_by_color.get "red"
|
|
||||||
# ```
|
|
||||||
# NOTE: returns an empty list on empty or non-existing partition.
|
|
||||||
def get(partition : String) : Array(V)
|
|
||||||
r_value = Array(V).new
|
|
||||||
|
|
||||||
# In case the partition is cached.
|
|
||||||
if keys = @data[partition]?
|
|
||||||
keys.each do |data_key|
|
|
||||||
r_value << @storage[data_key]
|
|
||||||
end
|
|
||||||
else
|
|
||||||
# The keys to put in the partition.
|
|
||||||
p_value = Array(Int32).new
|
|
||||||
|
|
||||||
# Get the key from the database representation on the file-system.
|
|
||||||
partition_directory = indexing_directory partition
|
|
||||||
raise MissingEntry.new(@name, partition) unless Dir.exists? partition_directory
|
|
||||||
|
|
||||||
Dir.each_child partition_directory do |child|
|
|
||||||
key = get_key child
|
|
||||||
r_value << @storage[key]
|
|
||||||
p_value << key
|
|
||||||
end
|
|
||||||
|
|
||||||
@data[partition] = p_value
|
|
||||||
end
|
|
||||||
r_value
|
|
||||||
end
|
|
||||||
|
|
||||||
# Deletes entries within the provided partition and matching the provided block of code,
|
|
||||||
# both from the file-system representation and from the cache.
|
|
||||||
#
|
|
||||||
# ```
|
|
||||||
# # Deletes all red Corvets.
|
|
||||||
# cars_by_color.delete "red", do |car|
|
|
||||||
# car.name == "Corvet"
|
|
||||||
# end
|
|
||||||
# ```
|
|
||||||
# TODO: in case the partition is left empty, should the partition be removed from the cache?
|
|
||||||
def delete(partition : String, &matcher : Proc(V, Bool))
|
|
||||||
# Use `get_with_keys` to retrieve data on-disk, if necessary.
|
|
||||||
new_partition = get_with_keys(partition).map(&.[1]).select do |key|
|
|
||||||
item = @storage[key]
|
|
||||||
! yield item
|
|
||||||
end
|
|
||||||
|
|
||||||
@data[partition] = new_partition
|
|
||||||
|
|
||||||
super(partition, &matcher)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -393,52 +346,19 @@ class DODB::RAMOnlyPartition(V) < DODB::CachedPartition(V)
|
|||||||
# # ]
|
# # ]
|
||||||
# # Each tuple is composed of a car and its key in the database.
|
# # Each tuple is composed of a car and its key in the database.
|
||||||
# ```
|
# ```
|
||||||
|
# WARNING: FOR CONSISTENCY, throws a MissingEntry exception on non-existing partition.
|
||||||
def get_with_keys(partition : String) : Array(Tuple(V, Int32))
|
def get_with_keys(partition : String) : Array(Tuple(V, Int32))
|
||||||
r_value = Array(Tuple(V, Int32)).new
|
r_value = Array(Tuple(V, Int32)).new
|
||||||
if keys = @data[partition]?
|
if keys = @data[partition]?
|
||||||
keys.each do |data_key|
|
keys.each do |data_key|
|
||||||
r_value << { @storage[data_key], data_key }
|
r_value << { @storage[data_key], data_key }
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
raise MissingEntry.new(@name, partition)
|
||||||
end
|
end
|
||||||
r_value
|
r_value
|
||||||
end
|
end
|
||||||
|
|
||||||
# Gets partition entries from the in-memory partition cache.
|
|
||||||
#
|
|
||||||
# ```
|
|
||||||
# # Get all red cars.
|
|
||||||
# cars_by_color.get "red"
|
|
||||||
# ```
|
|
||||||
# NOTE: returns an empty list on empty or non-existing partition.
|
|
||||||
def get(partition : String) : Array(V)
|
|
||||||
r_value = Array(V).new
|
|
||||||
if keys = @data[partition]?
|
|
||||||
keys.each do |data_key|
|
|
||||||
r_value << @storage[data_key]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
r_value
|
|
||||||
end
|
|
||||||
|
|
||||||
# Deletes entries within the provided partition and matching the provided block of code.
|
|
||||||
#
|
|
||||||
# ```
|
|
||||||
# # Deletes all red Corvets.
|
|
||||||
# cars_by_color.delete "red", do |car|
|
|
||||||
# car.name == "Corvet"
|
|
||||||
# end
|
|
||||||
# ```
|
|
||||||
# TODO: in case the partition is left empty, should it be removed from the cache?
|
|
||||||
def delete(partition : String, &matcher : Proc(V, Bool))
|
|
||||||
if keys = @data[partition]?
|
|
||||||
new_partition = keys.select do |key|
|
|
||||||
item = @storage[key]
|
|
||||||
! yield item
|
|
||||||
end
|
|
||||||
@data[partition] = new_partition
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Clears the cache.
|
# Clears the cache.
|
||||||
def nuke_index
|
def nuke_index
|
||||||
data.clear
|
data.clear
|
||||||
|
@ -64,14 +64,12 @@ class DODB::Tags(V) < DODB::Indexer(V)
|
|||||||
end
|
end
|
||||||
|
|
||||||
def index(key : String, value : V)
|
def index(key : String, value : V)
|
||||||
indices = key_proc.call(value)
|
tags = key_proc.call(value)
|
||||||
return if indices.is_a? NoIndex
|
return if tags.is_a? NoIndex
|
||||||
|
|
||||||
indices.each do |i|
|
tags.each do |tag|
|
||||||
symlink = get_tagged_entry_path(i, key)
|
symlink = get_tagged_entry_path(tag, key)
|
||||||
Dir.mkdir_p ::File.dirname symlink
|
Dir.mkdir_p ::File.dirname symlink
|
||||||
# FIXME: Should not happen anymore. Should we remove this?
|
|
||||||
::File.delete symlink if ::File.exists? symlink
|
|
||||||
::File.symlink get_data_symlink(key), symlink
|
::File.symlink get_data_symlink(key), symlink
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -79,11 +77,11 @@ class DODB::Tags(V) < DODB::Indexer(V)
|
|||||||
# :inherit:
|
# :inherit:
|
||||||
# TODO: in case the tag is left empty, should the tag directory be removed?
|
# TODO: in case the tag is left empty, should the tag directory be removed?
|
||||||
def deindex(key : String, value : V)
|
def deindex(key : String, value : V)
|
||||||
indices = key_proc.call(value)
|
tags = key_proc.call(value)
|
||||||
return if indices.is_a? NoIndex
|
return if tags.is_a? NoIndex
|
||||||
|
|
||||||
indices.each do |i|
|
tags.each do |tag|
|
||||||
symlink = get_tagged_entry_path(i, key)
|
symlink = get_tagged_entry_path(tag, key)
|
||||||
|
|
||||||
begin
|
begin
|
||||||
::File.delete symlink
|
::File.delete symlink
|
||||||
@ -95,7 +93,7 @@ class DODB::Tags(V) < DODB::Indexer(V)
|
|||||||
# Gets tag entries (and their keys) from the file-system representation of the tag.
|
# Gets tag entries (and their keys) from the file-system representation of the tag.
|
||||||
#
|
#
|
||||||
# ```
|
# ```
|
||||||
# # Get all slow cars.
|
# # Gets all slow cars.
|
||||||
# cars_by_keywords.get "slow"
|
# cars_by_keywords.get "slow"
|
||||||
# # Returns something like:
|
# # Returns something like:
|
||||||
# # [ (@storage[42], 42)
|
# # [ (@storage[42], 42)
|
||||||
@ -273,11 +271,11 @@ class DODB::CachedTags(V) < DODB::Tags(V)
|
|||||||
property data = Hash(String, Array(Int32)).new
|
property data = Hash(String, Array(Int32)).new
|
||||||
|
|
||||||
def index(key : String, value : V)
|
def index(key : String, value : V)
|
||||||
indices = key_proc.call value
|
tags = key_proc.call value
|
||||||
return if indices.is_a? NoIndex
|
return if tags.is_a? NoIndex
|
||||||
super(key, value)
|
super(key, value)
|
||||||
|
|
||||||
indices.each do |tag|
|
tags.each do |tag|
|
||||||
array = if v = @data[tag]?
|
array = if v = @data[tag]?
|
||||||
v
|
v
|
||||||
else
|
else
|
||||||
@ -292,11 +290,11 @@ class DODB::CachedTags(V) < DODB::Tags(V)
|
|||||||
# :inherit:
|
# :inherit:
|
||||||
# TODO: in case the tag is left empty, should it be removed from the cache?
|
# TODO: in case the tag is left empty, should it be removed from the cache?
|
||||||
def deindex(key : String, value : V)
|
def deindex(key : String, value : V)
|
||||||
indices = key_proc.call value
|
tags = key_proc.call value
|
||||||
return if indices.is_a? NoIndex
|
return if tags.is_a? NoIndex
|
||||||
super(key, value)
|
super(key, value)
|
||||||
|
|
||||||
indices.each do |tag|
|
tags.each do |tag|
|
||||||
if v = @data[tag]?
|
if v = @data[tag]?
|
||||||
v.delete key.to_i
|
v.delete key.to_i
|
||||||
@data[tag] = v
|
@data[tag] = v
|
||||||
@ -320,22 +318,16 @@ class DODB::CachedTags(V) < DODB::Tags(V)
|
|||||||
def get_with_keys(tag : String) : Array(Tuple(V, Int32))
|
def get_with_keys(tag : String) : Array(Tuple(V, Int32))
|
||||||
r_value = Array(Tuple(V, Int32)).new
|
r_value = Array(Tuple(V, Int32)).new
|
||||||
|
|
||||||
|
# In case the tag is cached.
|
||||||
if keys = @data[tag]?
|
if keys = @data[tag]?
|
||||||
keys.each do |data_key|
|
keys.each do |data_key|
|
||||||
r_value << { @storage[data_key], data_key }
|
r_value << { @storage[data_key], data_key }
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
# Get the key from the database representation on the file-system.
|
# Gets data from the database representation on the file-system.
|
||||||
tag_directory = indexing_directory tag
|
r_value = super(tag)
|
||||||
raise MissingEntry.new(@name, tag) unless Dir.exists? tag_directory
|
|
||||||
|
|
||||||
Dir.each_child tag_directory do |child|
|
|
||||||
r_value << { @storage[get_key child], get_key child }
|
|
||||||
end
|
|
||||||
|
|
||||||
@data[tag] = r_value.map &.[1]
|
@data[tag] = r_value.map &.[1]
|
||||||
end
|
end
|
||||||
|
|
||||||
r_value
|
r_value
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -363,10 +355,10 @@ end
|
|||||||
# NOTE: for an fs representation but still fast for retrieval, see `CachedTags`.
|
# NOTE: for an fs representation but still fast for retrieval, see `CachedTags`.
|
||||||
class DODB::RAMOnlyTags(V) < DODB::CachedTags(V)
|
class DODB::RAMOnlyTags(V) < DODB::CachedTags(V)
|
||||||
def index(key : String, value : V)
|
def index(key : String, value : V)
|
||||||
indices = key_proc.call value
|
tags = key_proc.call value
|
||||||
return if indices.is_a? NoIndex
|
return if tags.is_a? NoIndex
|
||||||
|
|
||||||
indices.each do |tag|
|
tags.each do |tag|
|
||||||
array = if v = @data[tag]?
|
array = if v = @data[tag]?
|
||||||
v
|
v
|
||||||
else
|
else
|
||||||
@ -379,10 +371,10 @@ class DODB::RAMOnlyTags(V) < DODB::CachedTags(V)
|
|||||||
end
|
end
|
||||||
|
|
||||||
def deindex(key : String, value : V)
|
def deindex(key : String, value : V)
|
||||||
indices = key_proc.call value
|
tags = key_proc.call value
|
||||||
return if indices.is_a? NoIndex
|
return if tags.is_a? NoIndex
|
||||||
|
|
||||||
indices.each do |tag|
|
tags.each do |tag|
|
||||||
if v = @data[tag]?
|
if v = @data[tag]?
|
||||||
v.delete key.to_i
|
v.delete key.to_i
|
||||||
@data[tag] = v
|
@data[tag] = v
|
||||||
@ -414,23 +406,6 @@ class DODB::RAMOnlyTags(V) < DODB::CachedTags(V)
|
|||||||
r_value
|
r_value
|
||||||
end
|
end
|
||||||
|
|
||||||
# Gets tag entries from the in-memory tag cache.
|
|
||||||
#
|
|
||||||
# ```
|
|
||||||
# # Get all slow cars.
|
|
||||||
# cars_by_keywords.get "slow"
|
|
||||||
# ```
|
|
||||||
# NOTE: returns an empty list on empty or non-existing tag.
|
|
||||||
def get(tag : String) : Array(V)
|
|
||||||
r_value = Array(V).new
|
|
||||||
if keys = @data[tag]?
|
|
||||||
keys.each do |data_key|
|
|
||||||
r_value << @storage[data_key]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
r_value
|
|
||||||
end
|
|
||||||
|
|
||||||
# Clears the cache.
|
# Clears the cache.
|
||||||
def nuke_index
|
def nuke_index
|
||||||
data.clear
|
data.clear
|
||||||
|
Loading…
Reference in New Issue
Block a user