diff --git a/src/cached.cr b/src/cached.cr index b3a88e7..c4f436b 100644 --- a/src/cached.cr +++ b/src/cached.cr @@ -108,4 +108,22 @@ class DODB::CachedDataBase(V) < DODB::Storage(V) super @data = Hash(Int32, V).new end + + def new_index(name : String, &block : Proc(V, String)) + CachedIndex(V).new(self, @directory_name, name, block).tap do |indexer| + @indexers << indexer + end + end + + def new_partition(name : String, &block : Proc(V, String)) + CachedPartition(V).new(self, @directory_name, name, block).tap do |table| + @indexers << table + end + end + + def new_tags(name : String, &block : Proc(V, Array(String))) + CachedTags(V).new(self, @directory_name, name, block).tap do |tags| + @indexers << tags + end + end end diff --git a/src/dodb/index.cr b/src/dodb/index.cr index 5c0f31d..6326a57 100644 --- a/src/dodb/index.cr +++ b/src/dodb/index.cr @@ -142,3 +142,43 @@ class DODB::Index(V) < DODB::Indexer(V) end end +class DODB::CachedIndex(V) < DODB::Index(V) + # This hash contains the relation between the index key and the data key. + property data = Hash(String, Int32).new + + def check!(key, value, old_value) + index_key = key_proc.call value + + # FIXME: Check it’s not pointing to “old_value”, if any, before raising. + if data[index_key]? + if old_value + old_key = key_proc.call old_value + return if index_key == old_key + end + + raise IndexOverload.new "index '#{@name}' is overloaded for key '#{key}'" + end + end + + def index(key, value) + super(key, value) + + index_key = key_proc.call value + return if index_key.is_a? NoIndex + + @data[index_key] = key.to_i + end + + def deindex(key, value) + super(key, value) + + index_key = key_proc.call value + return if index_key.is_a? NoIndex + + @data.delete index_key + end + + def get(index : String) : V + @storage[@data[index]] + end +end diff --git a/src/dodb/partition.cr b/src/dodb/partition.cr index 0060932..6aa817c 100644 --- a/src/dodb/partition.cr +++ b/src/dodb/partition.cr @@ -93,3 +93,41 @@ class DODB::Partition(V) < DODB::Indexer(V) end end +class DODB::CachedPartition(V) < DODB::Partition(V) + # This hash contains the relation between the index key and the data keys. + property data = Hash(String, Array(Int32)).new + + def index(key, value) + super(key, value) + partition = key_proc.call value + + array = if v = @data[partition]? + v + else + Array(Int32).new + end + array << key.to_i + + @data[partition] = array + end + + def deindex(key, value) + super(key, value) + partition = key_proc.call value + + if v = @data[partition]? + v.delete key.to_i + @data[partition] = v + end + end + + def get(partition) + r_value = Array(V).new + + @data[partition].each do |data_key| + r_value << @storage[data_key] + end + + r_value + end +end diff --git a/src/dodb/tags.cr b/src/dodb/tags.cr index 1c53386..30f9c5b 100644 --- a/src/dodb/tags.cr +++ b/src/dodb/tags.cr @@ -107,3 +107,46 @@ class DODB::Tags(V) < DODB::Indexer(V) "../../../data/#{key}" end end + +class DODB::CachedTags(V) < DODB::Tags(V) + # This hash contains the relation between the index key and the data keys. + property data = Hash(String, Array(Int32)).new + + def index(key, value) + super(key, value) + indices = key_proc.call value + + indices.each do |tag| + array = if v = @data[tag]? + v + else + Array(Int32).new + end + array << key.to_i + + @data[tag] = array + end + end + + def deindex(key, value) + super(key, value) + indices = key_proc.call value + + indices.each do |tag| + if v = @data[tag]? + v.delete key.to_i + @data[tag] = v + end + end + end + + def get(tag : String) + r_value = Array(V).new + + @data[tag].each do |data_key| + r_value << @storage[data_key] + end + + r_value + end +end