rufus-tokyo 0.1.7 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -28,178 +28,179 @@
28
28
  # jmettraux@gmail.com
29
29
  #
30
30
 
31
- module Rufus
32
- module Tokyo
31
+ module Rufus::Tokyo
33
32
 
34
- #
35
- # The libtokyocabinet.so methods get bound to this module
36
- #
37
- module CabinetLib #:nodoc#
38
- extend FFI::Library
33
+ #
34
+ # The libtokyocabinet.so methods get bound to this module
35
+ #
36
+ module CabinetLib #:nodoc#
37
+ extend FFI::Library
39
38
 
40
- #
41
- # find Tokyo Cabinet lib
39
+ #
40
+ # find Tokyo Cabinet lib
42
41
 
43
- paths = Array(ENV['TOKYO_CABINET_LIB'] || %w{
44
- /opt/local/lib/libtokyocabinet.dylib
45
- /usr/local/lib/libtokyocabinet.dylib
46
- /usr/local/lib/libtokyocabinet.so
47
- })
42
+ paths = Array(ENV['TOKYO_CABINET_LIB'] || %w{
43
+ /opt/local/lib/libtokyocabinet.dylib
44
+ /usr/local/lib/libtokyocabinet.dylib
45
+ /usr/local/lib/libtokyocabinet.so
46
+ })
48
47
 
49
- path = paths.find { |path| File.exist?(path) }
48
+ path = paths.find { |path| File.exist?(path) }
50
49
 
51
- raise(
52
- "didn't find Tokyo Cabinet libs on your system. " +
53
- "Please install Tokyo Cabinet (http://tokyocabinet.sf.net)"
54
- ) unless path
50
+ raise(
51
+ "didn't find Tokyo Cabinet libs on your system. " +
52
+ "Please install Tokyo Cabinet (http://tokyocabinet.sf.net)"
53
+ ) unless path
55
54
 
56
- ffi_lib(path)
55
+ ffi_lib(path)
57
56
 
58
- class << self
59
- alias :attfunc :attach_function
60
- end
57
+ class << self
58
+ alias :attfunc :attach_function
59
+ end
61
60
 
62
- #
63
- # maybe put that in a standalone c_lib.rb
61
+ #
62
+ # maybe put that in a standalone c_lib.rb
64
63
 
65
- # length of a string
66
- #
67
- attfunc :strlen, [ :string ], :int
64
+ # length of a string
65
+ #
66
+ attfunc :strlen, [ :string ], :int
68
67
 
69
- # frees a mem zone (TC style)
70
- #
71
- attfunc :tcfree, [ :pointer ], :void
68
+ # frees a mem zone (TC style)
69
+ #
70
+ attfunc :tcfree, [ :pointer ], :void
72
71
 
73
- #
74
- # tcadb functions
75
- #
76
- # http://tokyocabinet.sourceforge.net/spex-en.html#tcadbapi
72
+ #
73
+ # tcadb functions
74
+ #
75
+ # http://tokyocabinet.sourceforge.net/spex-en.html#tcadbapi
77
76
 
78
- attfunc :tcadbnew, [], :pointer
77
+ attfunc :tcadbnew, [], :pointer
79
78
 
80
- attfunc :tcadbopen, [ :pointer, :string ], :int
81
- attfunc :abs_close, :tcadbclose, [ :pointer ], :int
79
+ attfunc :tcadbopen, [ :pointer, :string ], :int
80
+ attfunc :abs_close, :tcadbclose, [ :pointer ], :int
82
81
 
83
- attfunc :abs_del, :tcadbdel, [ :pointer ], :void
82
+ attfunc :abs_del, :tcadbdel, [ :pointer ], :void
84
83
 
85
- attfunc :abs_rnum, :tcadbrnum, [ :pointer ], :uint64
86
- attfunc :abs_size, :tcadbsize, [ :pointer ], :uint64
84
+ attfunc :abs_rnum, :tcadbrnum, [ :pointer ], :uint64
85
+ attfunc :abs_size, :tcadbsize, [ :pointer ], :uint64
87
86
 
88
- attfunc :abs_put2, :tcadbput2, [ :pointer, :string, :string ], :int
89
- attfunc :abs_get2, :tcadbget2, [ :pointer, :string ], :string
90
- attfunc :abs_out2, :tcadbout2, [ :pointer, :string ], :int
87
+ attfunc :abs_put2, :tcadbput2, [ :pointer, :string, :string ], :int
88
+ attfunc :abs_get2, :tcadbget2, [ :pointer, :string ], :string
89
+ attfunc :abs_out2, :tcadbout2, [ :pointer, :string ], :int
91
90
 
92
- attfunc :abs_iterinit, :tcadbiterinit, [ :pointer ], :int
93
- attfunc :abs_iternext2, :tcadbiternext2, [ :pointer ], :string
91
+ attfunc :abs_iterinit, :tcadbiterinit, [ :pointer ], :int
92
+ attfunc :abs_iternext2, :tcadbiternext2, [ :pointer ], :string
94
93
 
95
- attfunc :abs_vanish, :tcadbvanish, [ :pointer ], :int
94
+ attfunc :abs_vanish, :tcadbvanish, [ :pointer ], :int
96
95
 
97
- attfunc :abs_sync, :tcadbsync, [ :pointer ], :int
98
- attfunc :abs_copy, :tcadbcopy, [ :pointer, :string ], :int
96
+ attfunc :abs_sync, :tcadbsync, [ :pointer ], :int
97
+ attfunc :abs_copy, :tcadbcopy, [ :pointer, :string ], :int
99
98
 
100
- attfunc :abs_fwmkeys2, :tcadbfwmkeys2, [ :pointer, :string, :int ], :pointer
99
+ attfunc :abs_fwmkeys2, :tcadbfwmkeys2, [ :pointer, :string, :int ], :pointer
101
100
 
102
- #
103
- # tctdb functions
104
- #
105
- # http://tokyocabinet.sourceforge.net/spex-en.html#tctdbapi
101
+ attfunc :tcadbmisc, [ :pointer, :string, :pointer ], :pointer
106
102
 
107
- attfunc :tctdbnew, [], :pointer
108
- attfunc :tctdbsetmutex, [ :pointer ], :int
109
- attfunc :tctdbtune, [ :pointer, :uint64, :uint8, :uint8, :uint8 ], :int
110
- attfunc :tctdbsetcache, [ :pointer, :uint32, :uint32, :uint32 ], :int
111
- attfunc :tctdbsetxmsiz, [ :pointer, :uint64 ], :int
103
+ #
104
+ # tctdb functions
105
+ #
106
+ # http://tokyocabinet.sourceforge.net/spex-en.html#tctdbapi
112
107
 
113
- attfunc :tctdbopen, [ :pointer, :string, :int ], :int
108
+ attfunc :tctdbnew, [], :pointer
109
+ attfunc :tctdbsetmutex, [ :pointer ], :int
110
+ attfunc :tctdbtune, [ :pointer, :uint64, :uint8, :uint8, :uint8 ], :int
111
+ attfunc :tctdbsetcache, [ :pointer, :uint32, :uint32, :uint32 ], :int
112
+ attfunc :tctdbsetxmsiz, [ :pointer, :uint64 ], :int
114
113
 
115
- attfunc :tab_close, :tctdbclose, [ :pointer ], :int
114
+ attfunc :tctdbopen, [ :pointer, :string, :int ], :int
116
115
 
117
- attfunc :tab_genuid, :tctdbgenuid, [ :pointer ], :int64
116
+ attfunc :tab_close, :tctdbclose, [ :pointer ], :int
118
117
 
119
- attfunc :tab_get, :tctdbget, [ :pointer, :string, :int ], :pointer
118
+ attfunc :tab_genuid, :tctdbgenuid, [ :pointer ], :int64
120
119
 
121
- attfunc :tab_iterinit, :tctdbiterinit, [ :pointer ], :int
122
- attfunc :tab_iternext2, :tctdbiternext2, [ :pointer ], :string
120
+ attfunc :tab_get, :tctdbget, [ :pointer, :string, :int ], :pointer
123
121
 
124
- attfunc :tab_put, :tctdbput, [ :pointer, :string, :int, :pointer ], :int
122
+ attfunc :tab_iterinit, :tctdbiterinit, [ :pointer ], :int
123
+ attfunc :tab_iternext2, :tctdbiternext2, [ :pointer ], :string
125
124
 
126
- #attfunc :tctdbput3, [ :pointer, :string, :string ], :int
127
- # not using it anymore, Ruby can turn an array into a hash so easily
125
+ attfunc :tab_put, :tctdbput, [ :pointer, :string, :int, :pointer ], :int
128
126
 
129
- attfunc :tab_out, :tctdbout, [ :pointer, :string, :int ], :int
127
+ #attfunc :tctdbput3, [ :pointer, :string, :string ], :int
128
+ # not using it anymore, Ruby can turn an array into a hash so easily
130
129
 
131
- attfunc :tab_ecode, :tctdbecode, [ :pointer ], :int
132
- attfunc :tab_errmsg, :tctdberrmsg, [ :int ], :string
130
+ attfunc :tab_out, :tctdbout, [ :pointer, :string, :int ], :int
133
131
 
134
- attfunc :tab_del, :tctdbdel, [ :pointer ], :void
132
+ attfunc :tab_ecode, :tctdbecode, [ :pointer ], :int
133
+ attfunc :tab_errmsg, :tctdberrmsg, [ :int ], :string
135
134
 
136
- attfunc :tab_rnum, :tctdbrnum, [ :pointer ], :uint64
135
+ attfunc :tab_del, :tctdbdel, [ :pointer ], :void
137
136
 
138
- attfunc :tab_vanish, :tctdbvanish, [ :pointer ], :int
137
+ attfunc :tab_rnum, :tctdbrnum, [ :pointer ], :uint64
139
138
 
140
- attfunc :tab_setindex, :tctdbsetindex, [ :pointer, :string, :int ], :int
139
+ attfunc :tab_vanish, :tctdbvanish, [ :pointer ], :int
141
140
 
142
- attfunc :tctdbtranbegin, [ :pointer ], :int
143
- attfunc :tctdbtrancommit, [ :pointer ], :int
144
- attfunc :tctdbtranabort, [ :pointer ], :int
141
+ attfunc :tab_setindex, :tctdbsetindex, [ :pointer, :string, :int ], :int
145
142
 
146
- attfunc :tab_fwmkeys2, :tctdbfwmkeys2, [ :pointer, :string, :int ], :pointer
143
+ attfunc :tctdbtranbegin, [ :pointer ], :int
144
+ attfunc :tctdbtrancommit, [ :pointer ], :int
145
+ attfunc :tctdbtranabort, [ :pointer ], :int
147
146
 
148
- #
149
- # tctdbqry functions
150
- #
151
- # http://tokyocabinet.sourceforge.net/spex-en.html#tctdbapi
147
+ attfunc :tab_fwmkeys2, :tctdbfwmkeys2, [ :pointer, :string, :int ], :pointer
152
148
 
153
- attfunc :qry_new, :tctdbqrynew, [ :pointer ], :pointer
154
- attfunc :qry_del, :tctdbqrydel, [ :pointer ], :void
149
+ #
150
+ # tctdbqry functions
151
+ #
152
+ # http://tokyocabinet.sourceforge.net/spex-en.html#tctdbapi
155
153
 
156
- attfunc :qry_addcond, :tctdbqryaddcond, [ :pointer, :string, :int, :string ], :void
157
- attfunc :qry_setorder, :tctdbqrysetorder, [ :pointer, :string, :int ], :void
158
- attfunc :qry_setmax, :tctdbqrysetmax, [ :pointer, :int ], :void
154
+ attfunc :qry_new, :tctdbqrynew, [ :pointer ], :pointer
155
+ attfunc :qry_del, :tctdbqrydel, [ :pointer ], :void
159
156
 
160
- attfunc :qry_search, :tctdbqrysearch, [ :pointer ], :pointer
157
+ attfunc :qry_addcond, :tctdbqryaddcond, [ :pointer, :string, :int, :string ], :void
158
+ attfunc :qry_setorder, :tctdbqrysetorder, [ :pointer, :string, :int ], :void
159
+ attfunc :qry_setmax, :tctdbqrysetmax, [ :pointer, :int ], :void
161
160
 
162
- #
163
- # tcmap functions
164
- #
165
- # http://tokyocabinet.sourceforge.net/spex-en.html#tcutilapi
161
+ attfunc :qry_search, :tctdbqrysearch, [ :pointer ], :pointer
166
162
 
167
- attfunc :tcmapnew, [], :pointer
163
+ #
164
+ # tcmap functions
165
+ #
166
+ # http://tokyocabinet.sourceforge.net/spex-en.html#tcutilapi
168
167
 
169
- attfunc :tcmapput2, [ :pointer, :string, :string ], :void
170
- attfunc :tcmapout2, [ :pointer, :string ], :int
171
- attfunc :tcmapclear, [ :pointer ], :void
168
+ attfunc :tcmapnew, [], :pointer
172
169
 
173
- attfunc :tcmapdel, [ :pointer ], :void
170
+ attfunc :tcmapput2, [ :pointer, :string, :string ], :void
171
+ attfunc :tcmapout2, [ :pointer, :string ], :int
172
+ attfunc :tcmapclear, [ :pointer ], :void
174
173
 
175
- attfunc :tcmapget2, [ :pointer, :string ], :string
174
+ attfunc :tcmapdel, [ :pointer ], :void
176
175
 
177
- attfunc :tcmapiterinit, [ :pointer ], :void
178
- attfunc :tcmapiternext2, [ :pointer ], :string
176
+ attfunc :tcmapget2, [ :pointer, :string ], :string
179
177
 
180
- attfunc :tcmaprnum, [ :pointer ], :uint64
178
+ attfunc :tcmapiterinit, [ :pointer ], :void
179
+ attfunc :tcmapiternext2, [ :pointer ], :string
181
180
 
182
- #
183
- # tclist functions
184
- #
185
- # http://tokyocabinet.sourceforge.net/spex-en.html#tcutilapi
181
+ attfunc :tcmaprnum, [ :pointer ], :uint64
186
182
 
187
- attfunc :tclistnew, [], :pointer
183
+ #
184
+ # tclist functions
185
+ #
186
+ # http://tokyocabinet.sourceforge.net/spex-en.html#tcutilapi
188
187
 
189
- attfunc :tclistnum, [ :pointer ], :int
190
- attfunc :tclistval2, [ :pointer, :int ], :string
188
+ attfunc :tclistnew, [], :pointer
191
189
 
192
- attfunc :tclistpush2, [ :pointer, :string ], :void
193
- attfunc :tclistpop2, [ :pointer ], :string
194
- attfunc :tclistshift2, [ :pointer ], :string
195
- attfunc :tclistunshift2, [ :pointer, :string ], :void
196
- attfunc :tclistover2, [ :pointer, :int, :string ], :void
190
+ attfunc :tclistnum, [ :pointer ], :int
191
+ attfunc :tclistval2, [ :pointer, :int ], :string
197
192
 
198
- attfunc :tclistremove2, [ :pointer, :int ], :string
199
- # beware, seems like have to free the return string self
193
+ attfunc :tclistpush2, [ :pointer, :string ], :void
194
+ attfunc :tclistpop2, [ :pointer ], :string
195
+ attfunc :tclistshift2, [ :pointer ], :string
196
+ attfunc :tclistunshift2, [ :pointer, :string ], :void
197
+ attfunc :tclistover2, [ :pointer, :int, :string ], :void
200
198
 
201
- attfunc :tclistdel, [ :pointer ], :void
202
- end
199
+ attfunc :tclistremove2, [ :pointer, :int ], :string
200
+ # beware, seems like have to free the return string self
203
201
 
202
+ attfunc :tclistdel, [ :pointer ], :void
204
203
  end
204
+
205
205
  end
206
+
@@ -28,768 +28,604 @@
28
28
  # jmettraux@gmail.com
29
29
  #
30
30
 
31
- module Rufus
32
- module Tokyo
31
+ require 'rufus/tokyo/query'
32
+ require 'rufus/tokyo/config'
33
+ require 'rufus/tokyo/transactions'
34
+
35
+
36
+ module Rufus::Tokyo
37
+
38
+ #
39
+ # A 'table' a table database.
40
+ #
41
+ # http://alpha.mixi.co.jp/blog/?p=290
42
+ # http://tokyocabinet.sourceforge.net/spex-en.html#tctdbapi
43
+ #
44
+ # A short example :
45
+ #
46
+ # require 'rubygems'
47
+ # require 'rufus/tokyo/cabinet/table'
48
+ #
49
+ # t = Rufus::Tokyo::Table.new('table.tdb', :create, :write)
50
+ # # '.tdb' suffix is a must
51
+ #
52
+ # t['pk0'] = { 'name' => 'alfred', 'age' => '22' }
53
+ # t['pk1'] = { 'name' => 'bob', 'age' => '18' }
54
+ # t['pk2'] = { 'name' => 'charly', 'age' => '45' }
55
+ # t['pk3'] = { 'name' => 'doug', 'age' => '77' }
56
+ # t['pk4'] = { 'name' => 'ephrem', 'age' => '32' }
57
+ #
58
+ # p t.query { |q|
59
+ # q.add_condition 'age', :numge, '32'
60
+ # q.order_by 'age'
61
+ # q.limit 2
62
+ # }
63
+ # # => [ {"name"=>"ephrem", :pk=>"pk4", "age"=>"32"},
64
+ # # {"name"=>"charly", :pk=>"pk2", "age"=>"45"} ]
65
+ #
66
+ # t.close
67
+ #
68
+ class Table
69
+
70
+ include HashMethods
71
+ include CabinetConfig
72
+
73
+ include Transactions
74
+ # this class has tranbegin/trancommit/tranabort so let's include the
75
+ # transaction mixin
33
76
 
34
77
  #
35
- # Methods for setting up / tuning a Cabinet.
78
+ # Creates a Table instance (creates or opens it depending on the args)
36
79
  #
37
- # Gets included into Table.
80
+ # For example,
38
81
  #
39
- module CabinetConfig
40
-
41
- protected
42
-
43
- #
44
- # Given a path, a hash of parameters and a suffix,
45
- #
46
- # a) makes sure that the path has the given suffix or raises an exception
47
- # b) gathers params found in the path (#) or in params
48
- # c) determines the config as set by the parameters
49
- #
50
- def determine_conf (path, params, suffix)
51
-
52
- if path.index('#')
53
-
54
- ss = path.split('#')
55
- path = ss.shift
56
-
57
- ss.each { |p| pp = p.split('='); params[pp[0]] = pp[1] }
58
- end
59
-
60
- raise "path '#{path}' must be suffixed with #{suffix}" \
61
- unless path[-suffix.length..-1] == suffix
62
-
63
- params = params.inject({}) { |h, (k, v)| h[k.to_sym] = v; h }
64
-
65
- conf = {
66
- :params => params,
67
- :path => path,
68
- :mode => determine_open_mode(params),
69
- :mutex => (params[:mutex].to_s == 'true'),
70
- #:indexes => params[:idx] || params[:indexes],
71
- :xmsiz => (params[:xmsiz] || 67108864).to_i
72
- }
73
- conf.merge!(determine_tuning_values(params))
74
- conf.merge(determine_cache_values(params))
75
- end
76
-
77
- def determine_open_mode (params) #:nodoc#
78
-
79
- mode = params[:mode].to_s
80
- mode = 'wc' if mode.size < 1
81
-
82
- {
83
- 'r' => (1 << 0), # open as a reader
84
- 'w' => (1 << 1), # open as a writer
85
- 'c' => (1 << 2), # writer creating
86
- 't' => (1 << 3), # writer truncating
87
- 'e' => (1 << 4), # open without locking
88
- 'f' => (1 << 5), # lock without blocking
89
- 's' => (1 << 6), # synchronize every transaction (tctdb.h)
90
-
91
- }.inject(0) { |r, (c, v)|
92
-
93
- r = r | v if mode.index(c); r
94
- }
95
- end
96
-
97
- def determine_tuning_values (params) #:nodoc#
98
-
99
- bnum = (params[:bnum] || 131071).to_i
100
- apow = (params[:apow] || 4).to_i
101
- fpow = (params[:fpow] || 10).to_i
102
-
103
- o = params[:opts] || ''
104
- o = {
105
- 'l' => 1 << 0, # large
106
- 'd' => 1 << 1, # deflate
107
- 'b' => 1 << 2, # bzip2
108
- 't' => 1 << 3, # tcbs
109
- 'x' => 1 << 4
110
- }.inject(0) { |i, (k, v)| i = i | v if o.index(k); i }
111
-
112
- { :bnum => bnum, :apow => apow, :fpow => fpow, :opts => o }
113
- end
114
-
115
- def determine_cache_values (params) #:nodoc#
116
-
117
- {
118
- :rcnum => params[:rcnum].to_i,
119
- :lcnum => (params[:lcnum] || 2048).to_i,
120
- :ncnum => (params[:ncnum] || 512).to_i
121
- }
122
- end
123
- end
124
-
82
+ # t = Rufus::Tokyo::Table.new('table.tdb')
83
+ # # '.tdb' suffix is a must
125
84
  #
126
- # A 'table' a table database.
85
+ # will create the table.tdb (or simply open it if already present)
86
+ # and make sure we have write access to it.
127
87
  #
128
- # http://alpha.mixi.co.jp/blog/?p=290
129
- # http://tokyocabinet.sourceforge.net/spex-en.html#tctdbapi
88
+ # == parameters
130
89
  #
131
- # A short example :
90
+ # Parameters can be set in the path or via the optional params hash (like
91
+ # in Rufus::Tokyo::Cabinet)
132
92
  #
133
- # require 'rubygems'
134
- # require 'rufus/tokyo/cabinet/table'
93
+ # * :mode a set of chars ('r'ead, 'w'rite, 'c'reate, 't'runcate,
94
+ # 'e' non locking, 'f' non blocking lock), default is 'wc'
95
+ # * :opts a set of chars ('l'arge, 'd'eflate, 'b'zip2, 't'cbs)
96
+ # (usually empty or something like 'ld' or 'lb')
135
97
  #
136
- # t = Rufus::Tokyo::Table.new('table.tdb', :create, :write)
137
- # # '.tdb' suffix is a must
98
+ # * :bnum number of elements of the bucket array
99
+ # * :apow size of record alignment by power of 2 (defaults to 4)
100
+ # * :fpow maximum number of elements of the free block pool by
101
+ # power of 2 (defaults to 10)
102
+ # * :mutex when set to true, makes sure only 1 thread at a time
103
+ # accesses the table (well, Ruby, global thread lock, ...)
138
104
  #
139
- # t['pk0'] = { 'name' => 'alfred', 'age' => '22' }
140
- # t['pk1'] = { 'name' => 'bob', 'age' => '18' }
141
- # t['pk2'] = { 'name' => 'charly', 'age' => '45' }
142
- # t['pk3'] = { 'name' => 'doug', 'age' => '77' }
143
- # t['pk4'] = { 'name' => 'ephrem', 'age' => '32' }
105
+ # * :rcnum specifies the maximum number of records to be cached.
106
+ # If it is not more than 0, the record cache is disabled.
107
+ # It is disabled by default.
108
+ # * :lcnum specifies the maximum number of leaf nodes to be cached.
109
+ # If it is not more than 0, the default value is specified.
110
+ # The default value is 2048.
111
+ # * :ncnum specifies the maximum number of non-leaf nodes to be
112
+ # cached. If it is not more than 0, the default value is
113
+ # specified. The default value is 512.
144
114
  #
145
- # p t.query { |q|
146
- # q.add_condition 'age', :numge, '32'
147
- # q.order_by 'age'
148
- # q.limit 2
149
- # }
150
- # # => [ {"name"=>"ephrem", :pk=>"pk4", "age"=>"32"},
151
- # # {"name"=>"charly", :pk=>"pk2", "age"=>"45"} ]
115
+ # * :xmsiz specifies the size of the extra mapped memory. If it is
116
+ # not more than 0, the extra mapped memory is disabled.
117
+ # The default size is 67108864.
152
118
  #
153
- # t.close
119
+ # Some examples :
154
120
  #
155
- class Table
156
-
157
- include HashMethods
158
- include CabinetConfig
159
-
160
- #
161
- # Creates a Table instance (creates or opens it depending on the args)
162
- #
163
- # For example,
164
- #
165
- # t = Rufus::Tokyo::Table.new('table.tdb')
166
- # # '.tdb' suffix is a must
167
- #
168
- # will create the table.tdb (or simply open it if already present)
169
- # and make sure we have write access to it.
170
- #
171
- # == parameters
172
- #
173
- # Parameters can be set in the path or via the optional params hash (like
174
- # in Rufus::Tokyo::Cabinet)
175
- #
176
- # * :mode a set of chars ('r'ead, 'w'rite, 'c'reate, 't'runcate,
177
- # 'e' non locking, 'f' non blocking lock), default is 'wc'
178
- # * :opts a set of chars ('l'arge, 'd'eflate, 'b'zip2, 't'cbs)
179
- # (usually empty or something like 'ld' or 'lb')
180
- #
181
- # * :bnum number of elements of the bucket array
182
- # * :apow size of record alignment by power of 2 (defaults to 4)
183
- # * :fpow maximum number of elements of the free block pool by
184
- # power of 2 (defaults to 10)
185
- # * :mutex when set to true, makes sure only 1 thread at a time
186
- # accesses the table (well, Ruby, global thread lock, ...)
187
- #
188
- # * :rcnum specifies the maximum number of records to be cached.
189
- # If it is not more than 0, the record cache is disabled.
190
- # It is disabled by default.
191
- # * :lcnum specifies the maximum number of leaf nodes to be cached.
192
- # If it is not more than 0, the default value is specified.
193
- # The default value is 2048.
194
- # * :ncnum specifies the maximum number of non-leaf nodes to be
195
- # cached. If it is not more than 0, the default value is
196
- # specified. The default value is 512.
197
- #
198
- # * :xmsiz specifies the size of the extra mapped memory. If it is
199
- # not more than 0, the extra mapped memory is disabled.
200
- # The default size is 67108864.
201
- #
202
- # Some examples :
203
- #
204
- # t = Rufus::Tokyo::Table.new('table.tdb')
205
- # t = Rufus::Tokyo::Table.new('table.tdb#mode=r')
206
- # t = Rufus::Tokyo::Table.new('table.tdb', :mode => 'r')
207
- # t = Rufus::Tokyo::Table.new('table.tdb#opts=ld#mode=r')
208
- # t = Rufus::Tokyo::Table.new('table.tdb', :opts => 'ld', :mode => 'r')
209
- #
210
- def initialize (path, params={})
211
-
212
- conf = determine_conf(path, params, '.tdb')
213
-
214
- @db = lib.tctdbnew
215
-
216
- #
217
- # tune table
218
-
219
- libcall(:tctdbsetmutex) if conf[:mutex]
220
-
221
- libcall(:tctdbtune, conf[:bnum], conf[:apow], conf[:fpow], conf[:opts])
222
-
223
- # TODO : set indexes here... well, there is already #set_index
224
- #conf[:indexes]...
225
-
226
- libcall(:tctdbsetcache, conf[:rcnum], conf[:lcnum], conf[:ncnum])
227
-
228
- libcall(:tctdbsetxmsiz, conf[:xmsiz])
121
+ # t = Rufus::Tokyo::Table.new('table.tdb')
122
+ # t = Rufus::Tokyo::Table.new('table.tdb#mode=r')
123
+ # t = Rufus::Tokyo::Table.new('table.tdb', :mode => 'r')
124
+ # t = Rufus::Tokyo::Table.new('table.tdb#opts=ld#mode=r')
125
+ # t = Rufus::Tokyo::Table.new('table.tdb', :opts => 'ld', :mode => 'r')
126
+ #
127
+ def initialize (path, params={})
229
128
 
230
- #
231
- # open table
129
+ conf = determine_conf(path, params, :table)
232
130
 
233
- libcall(:tctdbopen, conf[:path], conf[:mode])
234
- end
131
+ @db = lib.tctdbnew
235
132
 
236
133
  #
237
- # using the cabinet lib
238
- #
239
- def lib
240
- CabinetLib
241
- end
134
+ # tune table
242
135
 
243
- #
244
- # Closes the table (and frees the datastructure allocated for it),
245
- # returns true in case of success.
246
- #
247
- def close
248
- result = lib.tab_close(@db)
249
- lib.tab_del(@db)
250
- (result == 1)
251
- end
136
+ libcall(:tctdbsetmutex) if conf[:mutex]
252
137
 
253
- #
254
- # Generates a unique id (in the context of this Table instance)
255
- #
256
- def generate_unique_id
257
- lib.tab_genuid(@db)
258
- end
259
- alias :genuid :generate_unique_id
260
-
261
- INDEX_TYPES = {
262
- :lexical => 0,
263
- :decimal => 1,
264
- :void => 9999,
265
- :remove => 9999,
266
- :keep => 1 << 24
267
- }
268
-
269
- #
270
- # Sets an index on a column of the table.
271
- #
272
- # Types maybe be :lexical or :decimal, use :keep to "add" and
273
- # :remove (or :void) to "remove" an index.
274
- #
275
- # If column_name is :pk or "", the index will be set on the primary key.
276
- #
277
- # Returns true in case of success.
278
- #
279
- def set_index (column_name, *types)
138
+ libcall(:tctdbtune, conf[:bnum], conf[:apow], conf[:fpow], conf[:opts])
280
139
 
281
- column_name = '' if column_name == :pk
140
+ # TODO : set indexes here... well, there is already #set_index
141
+ #conf[:indexes]...
282
142
 
283
- i = types.inject(0) { |i, t| i = i & INDEX_TYPES[t]; i }
143
+ libcall(:tctdbsetcache, conf[:rcnum], conf[:lcnum], conf[:ncnum])
284
144
 
285
- (lib.tab_setindex(@db, column_name, i) == 1)
286
- end
145
+ libcall(:tctdbsetxmsiz, conf[:xmsiz])
287
146
 
288
147
  #
289
- # Inserts a record in the table db
290
- #
291
- # table['pk0'] = [ 'name', 'fred', 'age', '45' ]
292
- # table['pk1'] = { 'name' => 'jeff', 'age' => '46' }
293
- #
294
- # Accepts both a hash or an array (expects the array to be of the
295
- # form [ key, value, key, value, ... ] else it will raise
296
- # an ArgumentError)
297
- #
298
- def []= (pk, h_or_a)
299
-
300
- m = Rufus::Tokyo::Map[h_or_a]
148
+ # open table
301
149
 
302
- r = lib.tab_put(@db, pk, CabinetLib.strlen(pk), m.pointer)
303
-
304
- m.free
150
+ libcall(:tctdbopen, conf[:path], conf[:mode])
151
+ end
305
152
 
306
- (r == 1) || raise_error
153
+ #
154
+ # using the cabinet lib
155
+ #
156
+ def lib
157
+ CabinetLib
158
+ end
307
159
 
308
- h_or_a
309
- end
160
+ #
161
+ # Closes the table (and frees the datastructure allocated for it),
162
+ # returns true in case of success.
163
+ #
164
+ def close
165
+ result = lib.tab_close(@db)
166
+ lib.tab_del(@db)
167
+ (result == 1)
168
+ end
310
169
 
311
- #
312
- # Removes an entry in the table
313
- #
314
- # (might raise an error if the delete itself failed, but returns nil
315
- # if there was no entry for the given key)
316
- #
317
- def delete (k)
318
- v = self[k]
319
- return nil unless v
320
- libcall(:tab_out, k, CabinetLib.strlen(k))
321
- v
322
- end
170
+ #
171
+ # Generates a unique id (in the context of this Table instance)
172
+ #
173
+ def generate_unique_id
174
+ lib.tab_genuid(@db)
175
+ end
176
+ alias :genuid :generate_unique_id
323
177
 
324
- #
325
- # Removes all records in this table database
326
- #
327
- def clear
328
- libcall(:tab_vanish)
329
- end
178
+ INDEX_TYPES = {
179
+ :lexical => 0,
180
+ :decimal => 1,
181
+ :void => 9999,
182
+ :remove => 9999,
183
+ :keep => 1 << 24
184
+ }
330
185
 
331
- #
332
- # Returns an array of all the primary keys in the table
333
- #
334
- # With no options given, this method will return all the keys (strings)
335
- # in a Ruby array.
336
- #
337
- # :prefix --> returns only the keys who match a given string prefix
338
- #
339
- # :limit --> returns a limited number of keys
340
- #
341
- # :native --> returns an instance of Rufus::Tokyo::List instead of
342
- # a Ruby Hash, you have to call #free on that List when done with it !
343
- # Else you're exposing yourself to a memory leak.
344
- #
345
- def keys (options={})
186
+ #
187
+ # Sets an index on a column of the table.
188
+ #
189
+ # Types maybe be :lexical or :decimal, use :keep to "add" and
190
+ # :remove (or :void) to "remove" an index.
191
+ #
192
+ # If column_name is :pk or "", the index will be set on the primary key.
193
+ #
194
+ # Returns true in case of success.
195
+ #
196
+ def set_index (column_name, *types)
346
197
 
347
- if pref = options[:prefix]
198
+ column_name = '' if column_name == :pk
348
199
 
349
- l = lib.tab_fwmkeys2(@db, pref, options[:limit] || -1)
350
- l = Rufus::Tokyo::List.new(l)
351
- options[:native] ? l : l.release
200
+ i = types.inject(0) { |i, t| i = i | INDEX_TYPES[t]; i }
352
201
 
353
- else
202
+ (lib.tab_setindex(@db, column_name, i) == 1)
203
+ end
354
204
 
355
- limit = options[:limit] || -1
356
- limit = nil if limit < 1
205
+ #
206
+ # Inserts a record in the table db
207
+ #
208
+ # table['pk0'] = [ 'name', 'fred', 'age', '45' ]
209
+ # table['pk1'] = { 'name' => 'jeff', 'age' => '46' }
210
+ #
211
+ # Accepts both a hash or an array (expects the array to be of the
212
+ # form [ key, value, key, value, ... ] else it will raise
213
+ # an ArgumentError)
214
+ #
215
+ # Raises an error in case of failure.
216
+ #
217
+ def []= (pk, h_or_a)
357
218
 
358
- l = options[:native] ? Rufus::Tokyo::List.new : []
219
+ m = Rufus::Tokyo::Map[h_or_a]
359
220
 
360
- lib.tab_iterinit(@db)
221
+ r = lib.tab_put(@db, pk, CabinetLib.strlen(pk), m.pointer)
361
222
 
362
- while (k = (lib.tab_iternext2(@db) rescue nil))
363
- break if limit and l.size >= limit
364
- l << k
365
- end
223
+ m.free
366
224
 
367
- l
368
- end
369
- end
225
+ (r == 1) || raise_error # raising potential error after freeing map
370
226
 
371
- #
372
- # Returns the number of records in this table db
373
- #
374
- def size
375
- lib.tab_rnum(@db)
376
- end
227
+ h_or_a
228
+ end
377
229
 
378
- #
379
- # Prepares a query instance (block is optional)
380
- #
381
- def prepare_query (&block)
382
- q = TableQuery.new(self)
383
- block.call(q) if block
384
- q
385
- end
230
+ #
231
+ # Removes an entry in the table
232
+ #
233
+ # (might raise an error if the delete itself failed, but returns nil
234
+ # if there was no entry for the given key)
235
+ #
236
+ def delete (k)
237
+ v = self[k]
238
+ return nil unless v
239
+ libcall(:tab_out, k, CabinetLib.strlen(k))
240
+ v
241
+ end
386
242
 
387
- #
388
- # Prepares and runs a query, returns a ResultSet instance
389
- # (takes care of freeing the query structure)
390
- #
391
- def do_query (&block)
392
- q = prepare_query(&block)
393
- rs = q.run
394
- q.free
395
- rs
396
- end
243
+ #
244
+ # Removes all records in this table database
245
+ #
246
+ def clear
247
+ libcall(:tab_vanish)
248
+ end
397
249
 
398
- #
399
- # Prepares and runs a query, returns an array of hashes (all Ruby)
400
- # (takes care of freeing the query and the result set structures)
401
- #
402
- def query (&block)
403
- rs = do_query(&block)
404
- a = rs.to_a
405
- rs.free
406
- a
407
- end
250
+ #
251
+ # Returns an array of all the primary keys in the table
252
+ #
253
+ # With no options given, this method will return all the keys (strings)
254
+ # in a Ruby array.
255
+ #
256
+ # :prefix --> returns only the keys who match a given string prefix
257
+ #
258
+ # :limit --> returns a limited number of keys
259
+ #
260
+ # :native --> returns an instance of Rufus::Tokyo::List instead of
261
+ # a Ruby Hash, you have to call #free on that List when done with it !
262
+ # Else you're exposing yourself to a memory leak.
263
+ #
264
+ def keys (options={})
408
265
 
409
- #
410
- # Transaction in a block.
411
- #
412
- # table.transaction do
413
- # table['pk0'] => { 'name' => 'Fred', 'age' => '40' }
414
- # table['pk1'] => { 'name' => 'Brooke', 'age' => '76' }
415
- # table.abort if weather.bad?
416
- # end
417
- #
418
- # If an error or an abort is trigger withing the transaction, it's rolled
419
- # back. If the block executes successfully, it gets commited.
420
- #
421
- def transaction
266
+ if pref = options[:prefix]
422
267
 
423
- return unless block_given?
268
+ l = lib.tab_fwmkeys2(@db, pref, options[:limit] || -1)
269
+ l = Rufus::Tokyo::List.new(l)
270
+ options[:native] ? l : l.release
424
271
 
425
- begin
426
- tranbegin
427
- yield
428
- trancommit
429
- rescue Exception => e
430
- tranabort
431
- end
432
- end
272
+ else
433
273
 
434
- #
435
- # Aborts the enclosing transaction
436
- #
437
- # See #transaction
438
- #
439
- def abort
440
- raise "abort transaction !"
441
- end
274
+ limit = options[:limit] || -1
275
+ limit = nil if limit < 1
442
276
 
443
- #
444
- # Warning : this method is low-level, you probably only need
445
- # to use #transaction and a block.
446
- #
447
- # Direct call for 'transaction begin'.
448
- #
449
- def tranbegin
450
- libcall(:tctdbtranbegin)
451
- end
277
+ l = options[:native] ? Rufus::Tokyo::List.new : []
452
278
 
453
- #
454
- # Warning : this method is low-level, you probably only need
455
- # to use #transaction and a block.
456
- #
457
- # Direct call for 'transaction commit'.
458
- #
459
- def trancommit
460
- libcall(:tctdbtrancommit)
461
- end
279
+ lib.tab_iterinit(@db)
462
280
 
463
- #
464
- # Warning : this method is low-level, you probably only need
465
- # to use #transaction and a block.
466
- #
467
- # Direct call for 'transaction abort'.
468
- #
469
- def tranabort
470
- libcall(:tctdbtranabort)
471
- end
281
+ while (k = (lib.tab_iternext2(@db) rescue nil))
282
+ break if limit and l.size >= limit
283
+ l << k
284
+ end
472
285
 
473
- #
474
- # Returns the actual pointer to the Tokyo Cabinet table
475
- #
476
- def pointer
477
- @db
286
+ l
478
287
  end
288
+ end
479
289
 
480
- protected
290
+ #
291
+ # Deletes all the entries whose key begin with the given prefix.
292
+ #
293
+ def delete_keys_with_prefix (prefix)
481
294
 
482
- #
483
- # Returns the value (as a Ruby Hash) else nil
484
- #
485
- # (the actual #[] method is provided by HashMethods)
486
- #
487
- def get (k)
488
- m = lib.tab_get(@db, k, CabinetLib.strlen(k))
489
- return nil if m.address == 0 # :( too bad, but it works
490
- Map.to_h(m) # which frees the map
295
+ ks = lib.tab_fwmkeys2(@db, prefix, -1) # -1 for no limit
296
+ #Rufus::Tokyo::List.new(ks).release.each { |k| self.delete(k) }
297
+ begin
298
+ ks = Rufus::Tokyo::List.new(ks)
299
+ ks.each { |k| self.delete(k) }
300
+ ensure
301
+ ks.free
491
302
  end
303
+ end
492
304
 
493
- def libcall (lib_method, *args)
494
-
495
- #(lib.send(lib_method, @db, *args) == 1) or raise_error
496
- # stack level too deep with JRuby 1.1.6 :(
305
+ #
306
+ # Returns the number of records in this table db
307
+ #
308
+ def size
309
+ lib.tab_rnum(@db)
310
+ end
497
311
 
498
- (eval(%{ lib.#{lib_method}(@db, *args) }) == 1) or raise_error
499
- # works with JRuby 1.1.6
500
- end
312
+ #
313
+ # Prepares a query instance (block is optional)
314
+ #
315
+ def prepare_query (&block)
316
+ q = TableQuery.new(self)
317
+ block.call(q) if block
318
+ q
319
+ end
501
320
 
502
- #
503
- # Obviously something got wrong, let's ask the db about it and raise
504
- # a TokyoError
505
- #
506
- def raise_error
321
+ #
322
+ # Prepares and runs a query, returns a ResultSet instance
323
+ # (takes care of freeing the query structure)
324
+ #
325
+ def do_query (&block)
326
+ q = prepare_query(&block)
327
+ rs = q.run
328
+ q.free
329
+ rs
330
+ end
507
331
 
508
- err_code = lib.tab_ecode(@db)
509
- err_msg = lib.tab_errmsg(err_code)
332
+ #
333
+ # Prepares and runs a query, returns an array of hashes (all Ruby)
334
+ # (takes care of freeing the query and the result set structures)
335
+ #
336
+ def query (&block)
337
+ rs = do_query(&block)
338
+ a = rs.to_a
339
+ rs.free
340
+ a
341
+ end
510
342
 
511
- raise TokyoError, "(err #{err_code}) #{err_msg}"
512
- end
343
+ #
344
+ # Warning : this method is low-level, you probably only need
345
+ # to use #transaction and a block.
346
+ #
347
+ # Direct call for 'transaction begin'.
348
+ #
349
+ def tranbegin
350
+ libcall(:tctdbtranbegin)
513
351
  end
514
352
 
515
353
  #
516
- # A query on a Tokyo Cabinet table db
354
+ # Warning : this method is low-level, you probably only need
355
+ # to use #transaction and a block.
356
+ #
357
+ # Direct call for 'transaction commit'.
517
358
  #
518
- class TableQuery
359
+ def trancommit
360
+ libcall(:tctdbtrancommit)
361
+ end
519
362
 
520
- OPERATORS = {
363
+ #
364
+ # Warning : this method is low-level, you probably only need
365
+ # to use #transaction and a block.
366
+ #
367
+ # Direct call for 'transaction abort'.
368
+ #
369
+ def tranabort
370
+ libcall(:tctdbtranabort)
371
+ end
521
372
 
522
- # strings...
373
+ #
374
+ # Returns the actual pointer to the Tokyo Cabinet table
375
+ #
376
+ def pointer
377
+ @db
378
+ end
523
379
 
524
- :streq => 0, # string equality
525
- :eq => 0,
526
- :eql => 0,
527
- :equals => 0,
380
+ protected
528
381
 
529
- :strinc => 1, # string include
530
- :inc => 1, # string include
531
- :includes => 1, # string include
382
+ #
383
+ # Returns the value (as a Ruby Hash) else nil
384
+ #
385
+ # (the actual #[] method is provided by HashMethods)
386
+ #
387
+ def get (k)
388
+ m = lib.tab_get(@db, k, CabinetLib.strlen(k))
389
+ return nil if m.address == 0 # :( too bad, but it works
390
+ Map.to_h(m) # which frees the map
391
+ end
532
392
 
533
- :strbw => 2, # string begins with
534
- :bw => 2,
535
- :starts_with => 2,
536
- :strew => 3, # string ends with
537
- :ew => 3,
538
- :ends_with => 3,
393
+ def libcall (lib_method, *args)
539
394
 
540
- :strand => 4, # string which include all the tokens in the given exp
541
- :and => 4,
395
+ #(lib.send(lib_method, @db, *args) == 1) or raise_error
396
+ # stack level too deep with JRuby 1.1.6 :(
542
397
 
543
- :stror => 5, # string which include at least one of the tokens
544
- :or => 5,
398
+ (eval(%{ lib.#{lib_method}(@db, *args) }) == 1) or raise_error
399
+ # works with JRuby 1.1.6
400
+ end
545
401
 
546
- :stroreq => 6, # string which is equal to at least one token
402
+ #
403
+ # Obviously something got wrong, let's ask the db about it and raise
404
+ # a TokyoError
405
+ #
406
+ def raise_error
547
407
 
548
- :strorrx => 7, # string which matches the given regex
549
- :regex => 7,
550
- :matches => 7,
408
+ err_code = lib.tab_ecode(@db)
409
+ err_msg = lib.tab_errmsg(err_code)
551
410
 
552
- # numbers...
411
+ raise TokyoError, "(err #{err_code}) #{err_msg}"
412
+ end
413
+ end
553
414
 
554
- :numeq => 8, # equal
555
- :numequals => 8,
556
- :numgt => 9, # greater than
557
- :gt => 9,
558
- :numge => 10, # greater or equal
559
- :ge => 10,
560
- :gte => 10,
561
- :numlt => 11, # greater or equal
562
- :lt => 11,
563
- :numle => 12, # greater or equal
564
- :le => 12,
565
- :lte => 12,
566
- :numbt => 13, # a number between two tokens in the given exp
567
- :bt => 13,
568
- :between => 13,
415
+ #
416
+ # A query on a Tokyo Cabinet table db
417
+ #
418
+ class TableQuery
569
419
 
570
- :numoreq => 14 # number which is equal to at least one token
571
- }
420
+ include QueryConstants
572
421
 
573
- TDBQCNEGATE = 1 << 24
574
- TDBQCNOIDX = 1 << 25
422
+ #
423
+ # Creates a query for a given Rufus::Tokyo::Table
424
+ #
425
+ # Queries are usually created via the #query (#prepare_query #do_query)
426
+ # of the Table instance.
427
+ #
428
+ # Methods of interest here are :
429
+ #
430
+ # * #add (or #add_condition)
431
+ # * #order_by
432
+ # * #limit
433
+ #
434
+ # also
435
+ #
436
+ # * #pk_only
437
+ # * #no_pk
438
+ #
439
+ def initialize (table)
440
+ @table = table
441
+ @query = @table.lib.qry_new(@table.pointer)
442
+ @opts = {}
443
+ end
575
444
 
576
- DIRECTIONS = {
577
- :strasc => 0,
578
- :strdesc => 1,
579
- :asc => 0,
580
- :desc => 1,
581
- :numasc => 2,
582
- :numdesc => 3
583
- }
445
+ def lib
446
+ @table.lib
447
+ end
584
448
 
585
- #
586
- # Creates a query for a given Rufus::Tokyo::Table
587
- #
588
- # Queries are usually created via the #query (#prepare_query #do_query)
589
- # of the Table instance.
590
- #
591
- # Methods of interest here are :
592
- #
593
- # * #add (or #add_condition)
594
- # * #order_by
595
- # * #limit
596
- #
597
- # also
598
- #
599
- # * #pk_only
600
- # * #no_pk
601
- #
602
- def initialize (table)
603
- @table = table
604
- @query = @table.lib.qry_new(@table.pointer)
605
- @opts = {}
606
- end
449
+ #
450
+ # Adds a condition
451
+ #
452
+ # table.query { |q|
453
+ # q.add 'name', :equals, 'Oppenheimer'
454
+ # q.add 'age', :numgt, 35
455
+ # }
456
+ #
457
+ # Understood 'operators' :
458
+ #
459
+ # :streq # string equality
460
+ # :eq
461
+ # :eql
462
+ # :equals
463
+ #
464
+ # :strinc # string include
465
+ # :inc # string include
466
+ # :includes # string include
467
+ #
468
+ # :strbw # string begins with
469
+ # :bw
470
+ # :starts_with
471
+ # :strew # string ends with
472
+ # :ew
473
+ # :ends_with
474
+ #
475
+ # :strand # string which include all the tokens in the given exp
476
+ # :and
477
+ #
478
+ # :stror # string which include at least one of the tokens
479
+ # :or
480
+ #
481
+ # :stroreq # string which is equal to at least one token
482
+ #
483
+ # :strorrx # string which matches the given regex
484
+ # :regex
485
+ # :matches
486
+ #
487
+ # # numbers...
488
+ #
489
+ # :numeq # equal
490
+ # :numequals
491
+ # :numgt # greater than
492
+ # :gt
493
+ # :numge # greater or equal
494
+ # :ge
495
+ # :gte
496
+ # :numlt # greater or equal
497
+ # :lt
498
+ # :numle # greater or equal
499
+ # :le
500
+ # :lte
501
+ # :numbt # a number between two tokens in the given exp
502
+ # :bt
503
+ # :between
504
+ #
505
+ # :numoreq # number which is equal to at least one token
506
+ #
507
+ def add (colname, operator, val, affirmative=true, no_index=true)
508
+ op = operator.is_a?(Fixnum) ? operator : OPERATORS[operator]
509
+ op = op | TDBQCNEGATE unless affirmative
510
+ op = op | TDBQCNOIDX if no_index
511
+ lib.qry_addcond(@query, colname, op, val)
512
+ end
513
+ alias :add_condition :add
607
514
 
608
- def lib
609
- @table.lib
610
- end
515
+ #
516
+ # Sets the max number of records to return for this query.
517
+ #
518
+ # (sorry no 'offset' as of now)
519
+ #
520
+ def limit (i)
521
+ lib.qry_setmax(@query, i)
522
+ end
611
523
 
612
- #
613
- # Adds a condition
614
- #
615
- # table.query { |q|
616
- # q.add 'name', :equals, 'Oppenheimer'
617
- # q.add 'age', :numgt, 35
618
- # }
619
- #
620
- # Understood 'operators' :
621
- #
622
- # :streq # string equality
623
- # :eq
624
- # :eql
625
- # :equals
626
- #
627
- # :strinc # string include
628
- # :inc # string include
629
- # :includes # string include
630
- #
631
- # :strbw # string begins with
632
- # :bw
633
- # :starts_with
634
- # :strew # string ends with
635
- # :ew
636
- # :ends_with
637
- #
638
- # :strand # string which include all the tokens in the given exp
639
- # :and
640
- #
641
- # :stror # string which include at least one of the tokens
642
- # :or
643
- #
644
- # :stroreq # string which is equal to at least one token
645
- #
646
- # :strorrx # string which matches the given regex
647
- # :regex
648
- # :matches
649
- #
650
- # # numbers...
651
- #
652
- # :numeq # equal
653
- # :numequals
654
- # :numgt # greater than
655
- # :gt
656
- # :numge # greater or equal
657
- # :ge
658
- # :gte
659
- # :numlt # greater or equal
660
- # :lt
661
- # :numle # greater or equal
662
- # :le
663
- # :lte
664
- # :numbt # a number between two tokens in the given exp
665
- # :bt
666
- # :between
667
- #
668
- # :numoreq # number which is equal to at least one token
669
- #
670
- def add (colname, operator, val, affirmative=true, no_index=true)
671
- op = operator.is_a?(Fixnum) ? operator : OPERATORS[operator]
672
- op = op | TDBQCNEGATE unless affirmative
673
- op = op | TDBQCNOIDX if no_index
674
- lib.qry_addcond(@query, colname, op, val)
675
- end
676
- alias :add_condition :add
524
+ #
525
+ # Sets the sort order for the result of the query
526
+ #
527
+ # The 'direction' may be :
528
+ #
529
+ # :strasc # string ascending
530
+ # :strdesc
531
+ # :asc # string ascending
532
+ # :desc
533
+ # :numasc # number ascending
534
+ # :numdesc
535
+ #
536
+ def order_by (colname, direction=:strasc)
537
+ lib.qry_setorder(@query, colname, DIRECTIONS[direction])
538
+ end
677
539
 
678
- #
679
- # Sets the max number of records to return for this query.
680
- #
681
- # (sorry no 'offset' as of now)
682
- #
683
- def limit (i)
684
- lib.qry_setmax(@query, i)
685
- end
540
+ #
541
+ # When set to true, only the primary keys of the matching records will
542
+ # be returned.
543
+ #
544
+ def pk_only (on=true)
545
+ @opts[:pk_only] = on
546
+ end
686
547
 
687
- #
688
- # Sets the sort order for the result of the query
689
- #
690
- # The 'direction' may be :
691
- #
692
- # :strasc # string ascending
693
- # :strdesc
694
- # :asc # string ascending
695
- # :desc
696
- # :numasc # number ascending
697
- # :numdesc
698
- #
699
- def order_by (colname, direction=:strasc)
700
- lib.qry_setorder(@query, colname, DIRECTIONS[direction])
701
- end
548
+ #
549
+ # When set to true, the :pk (primary key) is not inserted in the record
550
+ # (hashes) returned
551
+ #
552
+ def no_pk (on=true)
553
+ @opts[:no_pk] = on
554
+ end
702
555
 
703
- #
704
- # When set to true, only the primary keys of the matching records will
705
- # be returned.
706
- #
707
- def pk_only (on=true)
708
- @opts[:pk_only] = on
709
- end
556
+ #
557
+ # Runs this query (returns a TableResultSet instance)
558
+ #
559
+ def run
560
+ TableResultSet.new(@table, lib.qry_search(@query), @opts)
561
+ end
710
562
 
711
- #
712
- # When set to true, the :pk (primary key) is not inserted in the record
713
- # (hashes) returned
714
- #
715
- def no_pk (on=true)
716
- @opts[:no_pk] = on
717
- end
563
+ #
564
+ # Frees this data structure
565
+ #
566
+ def free
567
+ lib.qry_del(@query)
568
+ @query = nil
569
+ end
718
570
 
719
- #
720
- # Runs this query (returns a TableResultSet instance)
721
- #
722
- def run
723
- TableResultSet.new(@table, lib.qry_search(@query), @opts)
724
- end
571
+ alias :close :free
572
+ alias :destroy :free
573
+ end
725
574
 
726
- #
727
- # Frees this data structure
728
- #
729
- def free
730
- lib.qry_del(@query)
731
- @query = nil
732
- end
575
+ #
576
+ # The thing queries return
577
+ #
578
+ class TableResultSet
579
+ include Enumerable
733
580
 
734
- alias :close :free
735
- alias :destroy :free
581
+ def initialize (table, list_pointer, query_opts)
582
+ @table = table
583
+ @list = list_pointer
584
+ @opts = query_opts
736
585
  end
737
586
 
738
587
  #
739
- # The thing queries return
588
+ # Returns the count of element in this result set
740
589
  #
741
- class TableResultSet
742
- include Enumerable
743
-
744
- def initialize (table, list_pointer, query_opts)
745
- @table = table
746
- @list = list_pointer
747
- @opts = query_opts
748
- end
749
-
750
- #
751
- # Returns the count of element in this result set
752
- #
753
- def size
754
- CabinetLib.tclistnum(@list)
755
- end
590
+ def size
591
+ CabinetLib.tclistnum(@list)
592
+ end
756
593
 
757
- alias :length :size
594
+ alias :length :size
758
595
 
759
- #
760
- # The classical each
761
- #
762
- def each
763
- (0..size-1).each do |i|
764
- pk = CabinetLib.tclistval2(@list, i)
765
- if @opts[:pk_only]
766
- yield(pk)
767
- else
768
- val = @table[pk]
769
- val[:pk] = pk unless @opts[:no_pk]
770
- yield(val)
771
- end
596
+ #
597
+ # The classical each
598
+ #
599
+ def each
600
+ (0..size-1).each do |i|
601
+ pk = CabinetLib.tclistval2(@list, i)
602
+ if @opts[:pk_only]
603
+ yield(pk)
604
+ else
605
+ val = @table[pk]
606
+ val[:pk] = pk unless @opts[:no_pk]
607
+ yield(val)
772
608
  end
773
609
  end
610
+ end
774
611
 
775
- #
776
- # Returns an array of hashes
777
- #
778
- def to_a
779
- collect { |m| m }
780
- end
781
-
782
- #
783
- # Frees this query (the underlying Tokyo Cabinet list structure)
784
- #
785
- def free
786
- CabinetLib.tclistdel(@list)
787
- @list = nil
788
- end
612
+ #
613
+ # Returns an array of hashes
614
+ #
615
+ def to_a
616
+ collect { |m| m }
617
+ end
789
618
 
790
- alias :close :free
791
- alias :destroy :free
619
+ #
620
+ # Frees this query (the underlying Tokyo Cabinet list structure)
621
+ #
622
+ def free
623
+ CabinetLib.tclistdel(@list)
624
+ @list = nil
792
625
  end
793
626
 
627
+ alias :close :free
628
+ alias :destroy :free
794
629
  end
795
630
  end
631
+