add missing files
This commit is contained in:
parent
5667b6bfff
commit
cc91cdcd14
60
lib/bdb/base.rb
Normal file
60
lib/bdb/base.rb
Normal file
|
@ -0,0 +1,60 @@
|
|||
require 'bdb'
|
||||
require 'tuple'
|
||||
require 'bdb/environment'
|
||||
require 'bdb/result_set'
|
||||
|
||||
class Bdb::Base
|
||||
def initialize(opts)
|
||||
@config = Bdb::Environment.config.merge(opts)
|
||||
@indexes = {}
|
||||
end
|
||||
attr_reader :indexes
|
||||
|
||||
def config(config = {})
|
||||
@config.merge!(config)
|
||||
end
|
||||
|
||||
def index_by(field, opts = {})
|
||||
raise "index on #{field} already exists" if indexes[field]
|
||||
indexes[field] = opts
|
||||
end
|
||||
|
||||
def environment
|
||||
@environment ||= Bdb::Environment.new(config[:path], self)
|
||||
end
|
||||
|
||||
def transaction(nested = true, &block)
|
||||
environment.transaction(nested, &block)
|
||||
end
|
||||
|
||||
def synchronize(&block)
|
||||
environment.synchronize(&block)
|
||||
end
|
||||
|
||||
def checkpoint(opts = {})
|
||||
environment.synchronize(opts)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def get_field(field, value)
|
||||
value.kind_of?(Hash) ? value[field] : value.send(field)
|
||||
end
|
||||
end
|
||||
|
||||
class Object
|
||||
attr_accessor :bdb_locator_key
|
||||
end
|
||||
|
||||
# Array comparison should try Tuple comparison first.
|
||||
class Array
|
||||
cmp = instance_method(:<=>)
|
||||
|
||||
define_method(:<=>) do |other|
|
||||
begin
|
||||
Tuple.dump(self) <=> Tuple.dump(other)
|
||||
rescue TypeError => e
|
||||
cmp.bind(self).call(other)
|
||||
end
|
||||
end
|
||||
end
|
74
lib/bdb/partitioned_database.rb
Normal file
74
lib/bdb/partitioned_database.rb
Normal file
|
@ -0,0 +1,74 @@
|
|||
require 'bdb/base'
|
||||
|
||||
class Bdb::PartitionedDatabase < Bdb::Base
|
||||
SEPARATOR = '__'
|
||||
PARTITION_PATTERN = /^[-\w]*$/
|
||||
|
||||
def initialize(base_name, opts = {})
|
||||
@base_name = base_name
|
||||
@partition_by = opts.delete(:partition_by)
|
||||
super(opts)
|
||||
end
|
||||
attr_reader :base_name, :partition_by, :partition
|
||||
|
||||
def databases
|
||||
@databases ||= {}
|
||||
end
|
||||
|
||||
def database(partition = nil)
|
||||
partition ||= self.partition
|
||||
raise 'partition value required' if partition.nil?
|
||||
partition = partition.to_s
|
||||
raise "invalid partition value: #{partition}" unless partition =~ PARTITION_PATTERN
|
||||
|
||||
databases[partition] ||= begin
|
||||
name = [partition, base_name].join(SEPARATOR)
|
||||
database = Bdb::Database.new(name, config)
|
||||
indexes.each do |field, opts|
|
||||
database.index_by(field, opts)
|
||||
end
|
||||
database
|
||||
end
|
||||
end
|
||||
|
||||
def partitions
|
||||
Dir[environment.path + "/*#{SEPARATOR}#{base_name}"].collect do |file|
|
||||
File.basename(file).split(SEPARATOR).first
|
||||
end
|
||||
end
|
||||
|
||||
def with_partition(partition)
|
||||
@partition, old_partition = partition, @partition
|
||||
yield
|
||||
ensure
|
||||
@partition = old_partition
|
||||
end
|
||||
|
||||
def close
|
||||
databases.each do |partition, database|
|
||||
database.close
|
||||
end
|
||||
@databases.clear
|
||||
end
|
||||
|
||||
def get(*keys, &block)
|
||||
opts = keys.last.kind_of?(Hash) ? keys.last : {}
|
||||
database(opts[partition_by]).get(*keys, &block)
|
||||
end
|
||||
|
||||
def set(key, value, opts = {})
|
||||
partition = get_field(partition_by, value)
|
||||
database(partition).set(key, value, opts)
|
||||
end
|
||||
|
||||
def delete(key, opts = {})
|
||||
database(opts[partition_by]).delete(key)
|
||||
end
|
||||
|
||||
# Deletes all records in the database. Beware!
|
||||
def truncate!
|
||||
partitions.each do |partition|
|
||||
database(partition).truncate!
|
||||
end
|
||||
end
|
||||
end
|
41
lib/bdb/result_set.rb
Normal file
41
lib/bdb/result_set.rb
Normal file
|
@ -0,0 +1,41 @@
|
|||
class Bdb::ResultSet
|
||||
class LimitReached < Exception; end
|
||||
|
||||
def initialize(opts, &block)
|
||||
@block = block
|
||||
@count = 0
|
||||
@limit = opts[:limit] || opts[:per_page]
|
||||
@limit = @limit.to_i if @limit
|
||||
@offset = opts[:offset] || (opts[:page] ? @limit * (opts[:page] - 1) : 0)
|
||||
@offset = @offset.to_i if @offset
|
||||
|
||||
if @group = opts[:group]
|
||||
raise 'block not supported with group' if @block
|
||||
@results = hash_class.new
|
||||
else
|
||||
@results = []
|
||||
end
|
||||
end
|
||||
attr_reader :count, :group, :limit, :offset, :results
|
||||
|
||||
def hash_class
|
||||
@hash_class ||= defined?(ActiveSupport::OrderedHash) ? ActiveSupport::OrderedHash : Hash
|
||||
end
|
||||
|
||||
def <<(item)
|
||||
@count += 1
|
||||
return if count <= offset
|
||||
|
||||
raise LimitReached if limit and count > limit + offset
|
||||
|
||||
if group
|
||||
key = item.bdb_locator_key
|
||||
group_key = group.is_a?(Fixnum) ? key[0,group] : key
|
||||
(results[group_key] ||= []) << item
|
||||
elsif @block
|
||||
@block.call(item)
|
||||
else
|
||||
results << item
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue