lib/btrieve/btrieve_table.rb in beezwax-0.5.2 vs lib/btrieve/btrieve_table.rb in beezwax-0.6.0
- old
+ new
@@ -1,80 +1,54 @@
require 'digest/md5'
+# Represents a single btrieve table for a particular BTR database.
class BtrieveTable
include Btrieve
- attr_reader :tablename, :session, :pos_buffer, :schema
+ attr_reader :tablename, :pos_buffer, :schema
attr_accessor :primary_key
- def initialize(tablename, session, schema=nil)
+ # Initializes a btrieve table.
+ def initialize(tablename, schema=nil)
@tablename = tablename
- @session = session
@pos_buffer = Btrieve.create_string_buffer(POS_BLOCK_SIZE)
- @schema = schema ? schema : @session.btrieve_schema.load_schema(@tablename)
+ @schema = schema ? schema : session.btrieve_schema.get_table_schema(@tablename)
end
- def open(mode = NORMAL_MODE)
- btr_op(@session, OPEN, @pos_buffer, NULL_BUFFER, @schema[:filename], mode)
+ # Opens this btrieve table in preparation for some BTR operation(s).
+ # If a block is passed to the call, the table is closed automatically.
+ # If a block is NOT passed to the call, the client code has to make sure to close the file.
+ def open(mode=NORMAL_MODE, &block)
+ file_unc="//#{session.host}/#{session.data_share}/#{@schema[:filename]}"
+ btr_op(OPEN, @pos_buffer, NULL_BUFFER, file_unc, mode)
+ if block_given?
+ yield
+ close()
+ end
end
- def mappings()
- @session.mappings[@tablename] ||= {}
- end
-
- def add_mapping(attr_name, mapping_name, transform)
- mappings[mapping_name.to_sym]={:column=>attr_name.to_sym,:transform=>transform.to_sym}
- end
-
- def relations()
- @session.relations[@tablename] ||= {}
- end
-
- def add_relation(name, target_table, index, join)
- relations[name.to_sym]={:target=>target_table.to_sym,:index=>index,:join=>join}
- end
-
- def find(match, index_number)
- unique=schema[:index_flags].map{|f|f&1==1}[index_number]
- result=nil
- if(unique)
- result=find_in_unique_index(match, index_numer)
+ # Finds an array of records in this table, using the specified index number and match hash.
+ # If a block is passed in, the entries of this set are passed into this block one by one. Otherwise,
+ # the set is returned to the caller.
+ def find(match, index_number, &block)
+ allows_duplicates=schema[:index_flags].map{|f|f&1==1;}[index_number]
+ set=nil
+ if(allows_duplicates)
+ set=find_in_index(match, index_number)
else
- result=find_in_index(match, index_numer)
+ rec=find_in_unique_index(match, index_number)
+ set=rec.nil? ? [] : [rec]
end
- result
- end
-
- def find_in_unique_index(match, index_number=nil)
- finder(match, index_number) do |key_buffer, index|
- btr_record = BtrieveRecord.new(self)
- batch(){ btr_op(@session, GET_EQUAL, @pos_buffer, btr_record.data_buffer, key_buffer, index) }
- btr_record
+ if(block_given?)
+ set.each{|record| yield record}
+ else
+ set
end
end
- def find_in_index(match, index_number=nil)
- finder(match, index_number) do |key_buffer, index|
- absolute_match = match.keys.inject({}){|vals, key| vals[key] = match[key] if(match[key] != nil); vals}
- absolute_match_keys = absolute_match.keys
- result = []
- batch() do
- btr_record = BtrieveRecord.new(self)
- ops_result = btr_op(@session, GET_GREATER_THAN_OR_EQUAL, @pos_buffer, btr_record.data_buffer, key_buffer, index, [OK, EOF])
- if OK==ops_result
- result << btr_record
- while(true)
- btr_record = BtrieveRecord.new(self)
- op_result = btr_op(@session, GET_NEXT, @pos_buffer, btr_record.data_buffer, key_buffer, index_number, [OK, EOF, 21])
- break unless btr_record.get_attributes(absolute_match_keys)==absolute_match and op_result!=EOF and op_result!=21
- result << btr_record
- end
- end
- end
- result
- end
- end
-
+ # Finds an array of records in this table, using the specified index number, a key and a range of values.
+ # If a block is passed in, the entries of this set are passed into this block one by one. Otherwise,
+ # the set is returned to the caller.
def find_in_range(index_num, key, range, &block)
index = @schema[:indices][index_num]
columns = @schema[:columns]
index_values = index.inject([]){|vals,akey|vals << (akey == key ? range.first : nil); vals}
key_packer = index.inject("") do |packer, akey|
@@ -82,62 +56,61 @@
nil_packer = 'x'*columns[key][:size]
packer << (akey == key ? value_packer : nil_packer)
packer
end
key_buffer = index_values.pack(key_packer)
-
btr_record = BtrieveRecord.new(self)
+ records = []
batch do
- btr_op(@session, GET_GREATER_THAN_OR_EQUAL, @pos_buffer, btr_record.data_buffer, key_buffer, index_num, [OK, EOF])
- while(range.include?(btr_record[key]))
- yield btr_record
+ btr_op(GET_GREATER_THAN_OR_EQUAL, @pos_buffer, btr_record.data_buffer, key_buffer, index_num, [OK, EOF])
+ while(range.include?(btr_record[key]))
+ if(!block.nil?)
+ yield btr_record
+ else
+ records << btr_record
+ end
btr_record = BtrieveRecord.new(self)
- btr_op(@session, GET_NEXT, @pos_buffer, btr_record.data_buffer, key_buffer, index_num, [OK, EOF])
+ btr_op(GET_NEXT, @pos_buffer, btr_record.data_buffer, key_buffer, index_num, [OK, EOF])
end
end
+ if(block.nil?)
+ records
+ end
end
+ # Closes this btrieve table to conclude a sequence of BTR operation(s).
def close
- btr_op(@session, CLOSE, @pos_buffer, NULL_BUFFER, NULL_BUFFER, NULL_KEY)
+ btr_op(CLOSE, @pos_buffer, NULL_BUFFER, NULL_BUFFER, NULL_KEY)
end
- def each_record(mode = READ_ONLY_MODE, &block)
+ # Loops over the records of this BTR table and passes each record to the block passed in.
+ def each_record(mode=NORMAL_MODE, &block)
batch(mode) do
while(record = step_next) do
yield record
end
end
end
- def batch(mode = READ_ONLY_MODE, &block)
+ # Wraps a sequence of BTR operations between a pair of open and close statements for this table.
+ # DEPRECATED - Use the "open" method instead and pass a block to it.
+ def batch(mode=NORMAL_MODE, &block)
open(mode)
yield
close
end
+ # Returns this table's version as a MD5 Digest value.
def version()
Digest::MD5.hexdigest(BtrieveSchema.sort(schema[:columns]).inject([]){|array,column|array << BtrieveSchema.readable_type(column);array}.to_s)
end
-
- #def self.primary_key_match(pk)
- # vals=pk.split('.')
- # {PK_KEYS[0]=>vals[0].to_i,PK_KEYS[1]=>vals[1].to_i,PK_KEYS[2]=>vals[2],PK_KEYS[3]=>vals[3].to_i,PK_KEYS[4]=>vals[4].to_i}
- #end
-
- #def self.tablename_to_url(tablename)
- # tablename.gsub(' & ','.and.').gsub('a/c ', 'ac.').gsub('es - o','es.o').gsub(' ','.')
- #end
-
- #def self.url_to_tablename(url_tablename)
- # url_tablename.gsub('.and.', ' & ').gsub('ac.', 'a/c ').gsub('es.o','es - o').gsub('.',' ')
- #end
private
def step_next
btr_record = BtrieveRecord.new(self)
- result = btr_op(@session, STEP_NEXT, @pos_buffer, btr_record.data_buffer, NULL_BUFFER, NULL_KEY, [OK, EOF])
+ result = btr_op(STEP_NEXT, @pos_buffer, btr_record.data_buffer, NULL_BUFFER, NULL_KEY, [OK, EOF])
return false if(result == EOF)
btr_record
end
def find_matching_index(match)
@@ -156,10 +129,11 @@
key_components = index.inject([]) do |vals, key|
datatype = BtrieveSchema.lookup(columns[key][:datatype], columns[key][:size])[:name]
value = match[key]
value = value.to_f if FLOAT_TYPES.include?(datatype)
value = value.to_i if INTEGER_TYPES.include?(datatype)
+ value = value.ljust(columns[key][:size], ' ') if datatype=='CHAR'
vals << value
vals
end
key_packer = index.inject("") do |packer, key|
datatype = BtrieveSchema.lookup(columns[key][:datatype], columns[key][:size])
@@ -171,7 +145,43 @@
packer
end
key_buffer = key_components.pack(key_packer)
yield(key_buffer, index_number)
end
+
+ def find_in_unique_index(match, index_number=nil)
+ finder(match, index_number) do |key_buffer, index|
+ btr_record = BtrieveRecord.new(self)
+ batch(){ btr_op(GET_EQUAL, @pos_buffer, btr_record.data_buffer, key_buffer, index, [KEY_NOT_FOUND, OK, EOF]) }
+ btr_record.nil? ? nil : btr_record
+ end
+ end
+
+ def find_in_index(match, index_number=nil)
+ finder(match, index_number) do |org_key_buffer, index|
+ absolute_match = match.keys.inject({}){|vals, key| vals[key] = match[key] if(match[key] != nil); vals}
+ absolute_match_keys = absolute_match.keys
+ result = []
+ batch do
+ key_buffer="#{org_key_buffer}"
+ ops_result = btr_op(GET_EQUAL_KEY, @pos_buffer, NULL_BUFFER, key_buffer, index, [OK, EOF, KEY_NOT_FOUND])
+ ops=GET_EQUAL
+ while(ops_result == OK)
+ btr_record = BtrieveRecord.new(self)
+ ops_result = btr_op(ops, @pos_buffer, btr_record.data_buffer, key_buffer, index, [OK, EOF])
+ break if(key_buffer!=org_key_buffer)
+ ops=GET_NEXT
+ result << btr_record if(ops_result == OK)
+ end
+ end
+ result
+ end
+ end
+
+ def session
+ s=BtrieveSession.get_session
+ raise "Cannot manipulate a BtrieveTable when no BtrieveSession exists." if s.nil?
+ s
+ end
+
end