beezwax 0.6.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/VERSION +1 -1
- data/beezwax.gemspec +5 -2
- data/lib/btrieve/btrieve_const.rb +2 -0
- data/lib/btrieve/btrieve_core.rb +1 -0
- data/lib/btrieve/btrieve_extended.rb +70 -0
- data/lib/btrieve/btrieve_record.rb +7 -19
- data/lib/btrieve/btrieve_schema.rb +7 -7
- data/lib/btrieve/btrieve_table.rb +65 -2
- data/test/btrieve/test_extended_beezwax.rb +41 -0
- metadata +7 -4
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.7.0
|
data/beezwax.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{beezwax}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.7.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Patrick Lardin"]
|
12
|
-
s.date = %q{2010-12-
|
12
|
+
s.date = %q{2010-12-22}
|
13
13
|
s.description = %q{Access Btrieve database files through a ruby API.}
|
14
14
|
s.email = %q{plardin@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -27,11 +27,13 @@ Gem::Specification.new do |s|
|
|
27
27
|
"lib/beezwax.rb",
|
28
28
|
"lib/btrieve/btrieve_const.rb",
|
29
29
|
"lib/btrieve/btrieve_core.rb",
|
30
|
+
"lib/btrieve/btrieve_extended.rb",
|
30
31
|
"lib/btrieve/btrieve_record.rb",
|
31
32
|
"lib/btrieve/btrieve_schema.rb",
|
32
33
|
"lib/btrieve/btrieve_session.rb",
|
33
34
|
"lib/btrieve/btrieve_table.rb",
|
34
35
|
"test/btrieve/test_beezwax.rb",
|
36
|
+
"test/btrieve/test_extended_beezwax.rb",
|
35
37
|
"test/helper.rb"
|
36
38
|
]
|
37
39
|
s.homepage = %q{http://github.com/plardin/beezwax}
|
@@ -40,6 +42,7 @@ Gem::Specification.new do |s|
|
|
40
42
|
s.summary = %q{Btrieve API wrapper.}
|
41
43
|
s.test_files = [
|
42
44
|
"test/btrieve/test_beezwax.rb",
|
45
|
+
"test/btrieve/test_extended_beezwax.rb",
|
43
46
|
"test/helper.rb"
|
44
47
|
]
|
45
48
|
|
data/lib/btrieve/btrieve_core.rb
CHANGED
@@ -0,0 +1,70 @@
|
|
1
|
+
class BtrieveSearchBuffer
|
2
|
+
include Btrieve
|
3
|
+
COMPARISON = {:equal=>1,:greater_than=>2,:less_than=>3, :not_equal=>4, :greater_than_or_equal=>5, :less_than_or_equal=>6}
|
4
|
+
BOOLEAN = {:and=>1, :or=>2}
|
5
|
+
|
6
|
+
def initialize(table, filter, fields_to_return, records_to_fetch=10, start_point=:next_record, max_reject_count=0)
|
7
|
+
@table=table
|
8
|
+
@filter=filter
|
9
|
+
@records_to_fetch=records_to_fetch
|
10
|
+
@fields_to_return=fields_to_return
|
11
|
+
@start_point = start_point == :current_record ? 'UC' : 'EG'
|
12
|
+
@max_reject_count=max_reject_count
|
13
|
+
end
|
14
|
+
|
15
|
+
def get_encoded_buffer
|
16
|
+
filter_buff = []
|
17
|
+
@filter.each_with_index() do |token, i|
|
18
|
+
is_expr = (i%2 == 0)
|
19
|
+
if(is_expr)
|
20
|
+
column = @table.schema[:columns][token[0]]
|
21
|
+
comparison = COMPARISON[token[1]]
|
22
|
+
right_operand = nil
|
23
|
+
if(is_symbol?(token[2]))
|
24
|
+
# We're comparing against a value stored in another field in this record
|
25
|
+
comparison += 64
|
26
|
+
right_operand=[@table.schema[:columns][token[2]][:offset]].pack('S')
|
27
|
+
else
|
28
|
+
# We're comparing against a constant in the exact same format as the column itself
|
29
|
+
right_operand=@table.pack_value(column, token[2])
|
30
|
+
right_operand=right_operand.gsub("\x00",' ') if [0,11,12,21].include?(column[:datatype])
|
31
|
+
end
|
32
|
+
#filter_buff << "DATATYPE=#{column[:datatype]} SIZE=#{column[:size]} OFFSET=#{column[:offset]} COMPARISON=#{comparison} OPERAND=#{right_operand}"
|
33
|
+
filter_item = [column[:datatype], column[:size], column[:offset], comparison, 0].pack('CSSCC')
|
34
|
+
filter_item << right_operand
|
35
|
+
#p filter_item
|
36
|
+
filter_buff << filter_item
|
37
|
+
else
|
38
|
+
boolean = BOOLEAN[token]
|
39
|
+
filter_buff.last[6..6]=[boolean].pack('C')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
num_logical_expressions = filter_buff.size
|
43
|
+
#p "num_logical_expressions = #{num_logical_expressions}"
|
44
|
+
#p filter_buff
|
45
|
+
result_descriptor=[@records_to_fetch, @fields_to_return.size].pack('SS')
|
46
|
+
#p "result_descriptor before = #{result_descriptor}"
|
47
|
+
@fields_to_return.inject(result_descriptor) do |desc, field|
|
48
|
+
column = @table.schema[:columns][field]
|
49
|
+
#p "#{field} => column[:size], column[:offset] = #{column[:size]}, #{column[:offset]}"
|
50
|
+
desc << [column[:size], column[:offset]].pack('SS')
|
51
|
+
desc
|
52
|
+
end
|
53
|
+
#p "result_descriptor after = #{result_descriptor}"
|
54
|
+
buffer_size=8+result_descriptor.size+filter_buff.join('').size
|
55
|
+
#p "buffer_size=#{buffer_size}"
|
56
|
+
search_buffer=[buffer_size, @start_point, @max_reject_count, num_logical_expressions].pack('Sa2SS')
|
57
|
+
#p "search_buffer.size=#{search_buffer.size}"
|
58
|
+
search_buffer << filter_buff.join('') << result_descriptor
|
59
|
+
#p "search_buffer.size=#{search_buffer.size}"
|
60
|
+
#p "buffer_size - search_buffer.size=#{buffer_size - search_buffer.size}"
|
61
|
+
search_buffer
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def is_symbol?(arg)
|
67
|
+
arg.object_id == arg.to_sym.object_id rescue false
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
@@ -57,27 +57,20 @@ class BtrieveRecord
|
|
57
57
|
|
58
58
|
# Returns this record's value of the column passed in.
|
59
59
|
def [](key_name)
|
60
|
-
|
61
|
-
return nil if(
|
62
|
-
val = @data_buffer.unpack(
|
60
|
+
column = @btrieve_table.schema[:columns][key_name]
|
61
|
+
return nil if(column.nil?)
|
62
|
+
val = @data_buffer.unpack(column[:unpacker])[0]
|
63
63
|
val = val.strip if val.respond_to?('strip')
|
64
64
|
val
|
65
65
|
end
|
66
66
|
|
67
67
|
# Sets this record's value for a particular column.
|
68
68
|
def []=(key_name, value)
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
offset = match[1].to_i
|
73
|
-
datatype = match[2]
|
74
|
-
thesizeof = BtrieveSchema::SIZEOF[datatype]
|
75
|
-
thesizeof *= match[3].empty? ? 1 : match[3].to_i
|
76
|
-
packer = "#{datatype}#{thesizeof}"
|
77
|
-
array = [value]
|
78
|
-
packed_value = array.pack(packer)
|
69
|
+
column = @btrieve_table.schema[:columns][key_name]
|
70
|
+
packed_value = @btrieve_table.pack_value(column, value)
|
71
|
+
offset = column[:offset]
|
79
72
|
range = (offset..offset+packed_value.size-1)
|
80
|
-
data_buffer[range] = packed_value
|
73
|
+
@data_buffer[range] = packed_value
|
81
74
|
end
|
82
75
|
|
83
76
|
# Determines if a record is nil.
|
@@ -107,9 +100,4 @@ class BtrieveRecord
|
|
107
100
|
@position = Btrieve.create_string_buffer(RECORD_POSITION_SIZE)
|
108
101
|
end
|
109
102
|
|
110
|
-
private
|
111
|
-
|
112
|
-
def get_column_info(column_name)
|
113
|
-
@btrieve_table.schema[:columns][column_name]
|
114
|
-
end
|
115
103
|
end
|
@@ -72,7 +72,13 @@ class BtrieveSchema
|
|
72
72
|
raise Exception.new("Unknown table '#{tablename}'.") if schema.nil?
|
73
73
|
schema
|
74
74
|
end
|
75
|
-
|
75
|
+
|
76
|
+
def self.readable_type(column)
|
77
|
+
c=column.to_a[0]
|
78
|
+
btrtype = lookup(c[1][:datatype],c[1][:size])
|
79
|
+
[:name=>c[0], :datatype=>btrtype[:name], :size=>c[1][:size]]
|
80
|
+
end
|
81
|
+
|
76
82
|
private
|
77
83
|
|
78
84
|
SYS_DDF = {
|
@@ -88,12 +94,6 @@ class BtrieveSchema
|
|
88
94
|
"#{offsetter}#{btrtype[:unpacker]}#{multiplier}"
|
89
95
|
end
|
90
96
|
|
91
|
-
def self.readable_type(column)
|
92
|
-
c=column.to_a[0]
|
93
|
-
btrtype = lookup(c[1][:datatype],c[1][:size])
|
94
|
-
[:name=>c[0], :datatype=>btrtype[:name], :size=>c[1][:size]]
|
95
|
-
end
|
96
|
-
|
97
97
|
def self.sort(schema)
|
98
98
|
schema.inject([]){|array,column|array[column[1][:offset]]={column[0]=>column[1]};array}.compact
|
99
99
|
end
|
@@ -47,8 +47,8 @@ class BtrieveTable
|
|
47
47
|
# Finds an array of records in this table, using the specified index number, a key and a range of values.
|
48
48
|
# If a block is passed in, the entries of this set are passed into this block one by one. Otherwise,
|
49
49
|
# the set is returned to the caller.
|
50
|
-
# WARNING - NO UNIT TEST EXIST!
|
51
|
-
#
|
50
|
+
# WARNING - NO UNIT TEST EXIST YET!
|
51
|
+
# CONSIDER - Deprecation coming soon... Should use the 'find_extended' method instead.
|
52
52
|
def find_in_range(index_num, key, range, &block)
|
53
53
|
index = @schema[:indices][index_num]
|
54
54
|
columns = @schema[:columns]
|
@@ -107,6 +107,69 @@ class BtrieveTable
|
|
107
107
|
Digest::MD5.hexdigest(BtrieveSchema.sort(schema[:columns]).inject([]){|array,column|array << BtrieveSchema.readable_type(column);array}.to_s)
|
108
108
|
end
|
109
109
|
|
110
|
+
# Packs a value according to the metadata of a particular column.
|
111
|
+
def pack_value(column, value)
|
112
|
+
packer_string = column[:unpacker]
|
113
|
+
match = packer_string.match(/@(\d+)([a-zA-Z]+)(\d*)/)
|
114
|
+
datatype = match[2]
|
115
|
+
size = match[3].empty? ? BtrieveSchema::SIZEOF[datatype] : BtrieveSchema::SIZEOF[datatype]*match[3].to_i
|
116
|
+
packer = "#{datatype}#{size}"
|
117
|
+
array = [value]
|
118
|
+
array.pack(packer)
|
119
|
+
end
|
120
|
+
|
121
|
+
# Returns an array of hashes that match the criteria defined by the filter parameter.
|
122
|
+
# An example of the filter parameter is given below -
|
123
|
+
#
|
124
|
+
# filter = [[:dept_name, :equal, 'Philosophy'], :and, [:name, :not_equal, 'PHI 101'], :and, [:name, :not_equal, :dept_name]]
|
125
|
+
#
|
126
|
+
# The following COMPARISON operators are supported in the logical comparison clauses -
|
127
|
+
# :equal
|
128
|
+
# :greater_than
|
129
|
+
# :less_than
|
130
|
+
# :not_equal
|
131
|
+
# :greater_than_or_equal
|
132
|
+
# :less_than_or_equal
|
133
|
+
#
|
134
|
+
# Logical comparison clauses can chained together using the following boolean operators -
|
135
|
+
# :and
|
136
|
+
# :or
|
137
|
+
#
|
138
|
+
# NOTE - The logical comparisons can compare a columns to a constant OR to another column in the same record.
|
139
|
+
def find_extended(index, filter, fields_to_return, records_to_fetch)
|
140
|
+
record_size = @schema[:record_size]
|
141
|
+
records_buffer = record_size*records_to_fetch
|
142
|
+
max_reject_count = 65535
|
143
|
+
start_point = :next_record
|
144
|
+
searcher = BtrieveSearchBuffer.new(self, filter, fields_to_return, records_to_fetch, max_reject_count, max_reject_count)
|
145
|
+
search_buffer = searcher.get_encoded_buffer
|
146
|
+
buff_diff = records_buffer - search_buffer.size
|
147
|
+
search_buffer << Btrieve.create_string_buffer(buff_diff) if(buff_diff > 0)
|
148
|
+
tmp_buff = Btrieve.create_string_buffer(record_size)
|
149
|
+
key_buff = Btrieve.create_string_buffer(record_size)
|
150
|
+
btr_op(GET_FIRST, @pos_buffer, tmp_buff, key_buff, index, [OK])
|
151
|
+
ops_result = btr_op(GET_NEXT_EXTENDED, @pos_buffer, search_buffer, key_buff, index, [OK, EOF])
|
152
|
+
num_records = search_buffer.unpack('S')[0]
|
153
|
+
record_byte_pointer=2
|
154
|
+
records = []
|
155
|
+
(0...num_records).each do |index|
|
156
|
+
record_length = search_buffer.unpack("@#{record_byte_pointer}S")[0]
|
157
|
+
record_position = search_buffer.unpack("@#{2+record_byte_pointer}i")[0]
|
158
|
+
record=search_buffer.unpack("@#{6+record_byte_pointer}a#{record_length}")[0]
|
159
|
+
record_byte_pointer += 6+record_length
|
160
|
+
unpacker = fields_to_return.inject(["", 0]) do |arr, c|
|
161
|
+
column = @schema[:columns][c]
|
162
|
+
str = BtrieveSchema.unpacker(arr[1], column[:datatype], column[:size])
|
163
|
+
arr[0] << str
|
164
|
+
arr[1] += column[:size]
|
165
|
+
arr
|
166
|
+
end
|
167
|
+
fields = record.unpack(unpacker[0])
|
168
|
+
records << {:position=>record_position, :values=>Hash[*fields_to_return.zip(fields).flatten]}
|
169
|
+
end
|
170
|
+
records
|
171
|
+
end
|
172
|
+
|
110
173
|
private
|
111
174
|
|
112
175
|
def step_next
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestExtendedBeezwax < Test::Unit::TestCase
|
4
|
+
context "when a BtrieveSession is initialized" do
|
5
|
+
setup do
|
6
|
+
BtrieveSession.create_session(PSQL_DB)
|
7
|
+
end
|
8
|
+
|
9
|
+
teardown do
|
10
|
+
BtrieveSession.destroy_session
|
11
|
+
end
|
12
|
+
|
13
|
+
should "support the creation of an extended query search buffer" do
|
14
|
+
table=BtrieveTable.new(:course)
|
15
|
+
filter = [[:name, :not_equal, 'PHI 101'], :and, [:dept_name, :equal, 'Philosophy'], :and, [:name, :not_equal, :dept_name]]
|
16
|
+
fields_to_return = table.schema[:columns].keys
|
17
|
+
encoded_buffer = nil
|
18
|
+
assert_nothing_raised do
|
19
|
+
search_buffer = BtrieveSearchBuffer.new(table, filter, fields_to_return)
|
20
|
+
encoded_buffer = search_buffer.get_encoded_buffer
|
21
|
+
end
|
22
|
+
assert_not_nil encoded_buffer
|
23
|
+
end
|
24
|
+
|
25
|
+
should "support calls to BtrieveTable.find_extended()" do
|
26
|
+
table = BtrieveTable.new(:course)
|
27
|
+
table.open do
|
28
|
+
index = 0
|
29
|
+
filter = [[:dept_name, :equal, 'Philosophy'], :and, [:name, :not_equal, 'PHI 101'], :and, [:name, :not_equal, :dept_name]]
|
30
|
+
fields_to_return = table.schema[:columns].keys
|
31
|
+
records_to_fetch = 10
|
32
|
+
records = nil
|
33
|
+
assert_nothing_raised do
|
34
|
+
records = table.find_extended(index, filter, fields_to_return, records_to_fetch)
|
35
|
+
end
|
36
|
+
assert_not_nil records
|
37
|
+
assert_equal 6, records.size
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 7
|
8
|
+
- 0
|
9
|
+
version: 0.7.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Patrick Lardin
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-12-
|
17
|
+
date: 2010-12-22 00:00:00 -08:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -52,11 +52,13 @@ files:
|
|
52
52
|
- lib/beezwax.rb
|
53
53
|
- lib/btrieve/btrieve_const.rb
|
54
54
|
- lib/btrieve/btrieve_core.rb
|
55
|
+
- lib/btrieve/btrieve_extended.rb
|
55
56
|
- lib/btrieve/btrieve_record.rb
|
56
57
|
- lib/btrieve/btrieve_schema.rb
|
57
58
|
- lib/btrieve/btrieve_session.rb
|
58
59
|
- lib/btrieve/btrieve_table.rb
|
59
60
|
- test/btrieve/test_beezwax.rb
|
61
|
+
- test/btrieve/test_extended_beezwax.rb
|
60
62
|
- test/helper.rb
|
61
63
|
has_rdoc: true
|
62
64
|
homepage: http://github.com/plardin/beezwax
|
@@ -92,4 +94,5 @@ specification_version: 3
|
|
92
94
|
summary: Btrieve API wrapper.
|
93
95
|
test_files:
|
94
96
|
- test/btrieve/test_beezwax.rb
|
97
|
+
- test/btrieve/test_extended_beezwax.rb
|
95
98
|
- test/helper.rb
|