activetokyocabinet 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +31 -3
- data/lib/active_tokyocabinet/sqlparser.tab.rb +2 -2
- data/lib/active_tokyocabinet/sqlparser.y +2 -2
- data/lib/active_tokyocabinet/tdb.rb +80 -16
- data/spec/models/book.rb +4 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/tokyocabinet_spec.rb +69 -0
- data/spec/tokyotyrant_spec.rb +69 -0
- metadata +3 -2
data/README
CHANGED
@@ -80,7 +80,7 @@ see http://gemcutter.org/gems/activetokyocabinet
|
|
80
80
|
# - Include `ID' in search condition
|
81
81
|
# see http://activetokyocabi.rubyforge.org/svn/trunk/lib/active_tokyocabinet/sqlparser.y
|
82
82
|
|
83
|
-
|
83
|
+
=== Expanded operator
|
84
84
|
|
85
85
|
# see http://1978th.net/tokyotyrant/rubydoc/classes/TokyoTyrant/RDBQRY.html
|
86
86
|
|
@@ -125,7 +125,7 @@ see http://gemcutter.org/gems/activetokyocabinet
|
|
125
125
|
emp = Emp.find(:all, :conditions => ['ename ftsex ?', 'MIKU || RIN'])
|
126
126
|
emp = Emp.find(:all, :conditions => ['ename ftsex ?', 'HATSUNE && MIKU'])
|
127
127
|
|
128
|
-
|
128
|
+
=== Low layer API
|
129
129
|
|
130
130
|
Emp.tdbopen do |tdb|
|
131
131
|
pkey = tdb.genuid
|
@@ -138,11 +138,39 @@ see http://gemcutter.org/gems/activetokyocabinet
|
|
138
138
|
end
|
139
139
|
# proc method return empty array.
|
140
140
|
|
141
|
-
|
141
|
+
=== Set index
|
142
142
|
|
143
143
|
# see http://1978th.net/tokyotyrant/rubydoc/classes/TokyoTyrant/RDBTBL.html#M000007
|
144
144
|
|
145
145
|
Emp.setindex(:age, :decimal)
|
146
146
|
|
147
|
+
== Example
|
148
|
+
=== database.yml
|
149
|
+
|
150
|
+
# TokyoCabinet
|
151
|
+
development:
|
152
|
+
adapter: tokyocabinet
|
153
|
+
database: db/casket/
|
154
|
+
# save to `$RAILS_ROOT/db/casket/*.tct'.
|
155
|
+
|
156
|
+
# TokyoTyrant
|
157
|
+
development:
|
158
|
+
adapter: tokyotyrant
|
159
|
+
database:
|
160
|
+
emps: { host: localhost, port: 1978 }
|
161
|
+
depts: { host: localhost, port: 1979 }
|
162
|
+
|
163
|
+
== Schema free
|
164
|
+
|
165
|
+
class Book < ActiveRecord::Base
|
166
|
+
include ActiveTokyoCabinet::TDB
|
167
|
+
schema_free :timestamp => true
|
168
|
+
end
|
169
|
+
|
170
|
+
Book.create(:title => 'photo book', :author => 'Tanaka Takeshi', :price => 200)
|
171
|
+
Book.create(:title => 'note book', :price => 50)
|
172
|
+
|
173
|
+
books = Book.find(:all, :conditions => ['author = ?', 'Tanaka Takeshi'])
|
174
|
+
|
147
175
|
== Related article
|
148
176
|
* http://d.hatena.ne.jp/winebarrel/20100106/p1
|
@@ -44,9 +44,9 @@ def scan
|
|
44
44
|
yield :NUMBER, tok.to_i
|
45
45
|
elsif (tok = @ss.scan /[,\(\)\*]/)
|
46
46
|
yield tok, tok
|
47
|
-
elsif (tok = @ss.scan /(?:[a-z_]
|
47
|
+
elsif (tok = @ss.scan /(?:[a-z_]\w+\.|[a-z]\.)*ID\b/i)
|
48
48
|
yield :ID, tok
|
49
|
-
elsif (tok = @ss.scan /(?:[a-z_]
|
49
|
+
elsif (tok = @ss.scan /(?:[a-z_]\w+\.|[a-z]\.)*(?:[a-z_]\w+|[a-z])/i)
|
50
50
|
yield :IDENTIFIER, tok
|
51
51
|
else
|
52
52
|
raise Racc::ParseError, ('parse error on value "%s"' % @ss.rest.inspect)
|
@@ -232,9 +232,9 @@ def scan
|
|
232
232
|
yield :NUMBER, tok.to_i
|
233
233
|
elsif (tok = @ss.scan /[,\(\)\*]/)
|
234
234
|
yield tok, tok
|
235
|
-
elsif (tok = @ss.scan /(?:[a-z_]
|
235
|
+
elsif (tok = @ss.scan /(?:[a-z_]\w+\.|[a-z]\.)*ID\b/i)
|
236
236
|
yield :ID, tok
|
237
|
-
elsif (tok = @ss.scan /(?:[a-z_]
|
237
|
+
elsif (tok = @ss.scan /(?:[a-z_]\w+\.|[a-z]\.)*(?:[a-z_]\w+|[a-z])/i)
|
238
238
|
yield :IDENTIFIER, tok
|
239
239
|
else
|
240
240
|
raise Racc::ParseError, ('parse error on value "%s"' % @ss.rest.inspect)
|
@@ -1,9 +1,89 @@
|
|
1
1
|
module ActiveTokyoCabinet
|
2
2
|
module TDB
|
3
3
|
def self.included(mod)
|
4
|
+
mod.instance_eval %{
|
5
|
+
def schema_free(options = {})
|
6
|
+
raise 'invalid definition: schema is already defined' if @__schema_defined
|
7
|
+
@__schema_free_defined = true
|
8
|
+
|
9
|
+
primary_key = ActiveRecord::ConnectionAdapters::Column.new('id', nil)
|
10
|
+
primary_key.primary = true
|
11
|
+
@columns = [primary_key]
|
12
|
+
|
13
|
+
class_eval <<-EOS
|
14
|
+
@@__with_timestamp = \#{options[:timestamp].inspect}
|
15
|
+
|
16
|
+
alias :__respond_to? :respond_to?
|
17
|
+
|
18
|
+
def attributes_with_quotes(include_primary_key = true, include_readonly_attributes = true, attribute_names = @attributes.keys)
|
19
|
+
quoted = {}
|
20
|
+
connection = self.class.connection
|
21
|
+
|
22
|
+
__attributes = (attributes || {}).merge(@__attributes || {})
|
23
|
+
__attributes.delete('id')
|
24
|
+
|
25
|
+
if @@__with_timestamp == :on
|
26
|
+
%w(created_at updated_at).each {|i| __attributes.delete(i) }
|
27
|
+
elsif @@__with_timestamp
|
28
|
+
%w(created_on updated_on).each {|i| __attributes.delete(i) }
|
29
|
+
else
|
30
|
+
%w(created_on updated_on created_at updated_at).each do |i|
|
31
|
+
__attributes.delete(i)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
__attributes.each do |name, value|
|
36
|
+
quoted[name] = connection.quote(value)
|
37
|
+
end
|
38
|
+
|
39
|
+
quoted
|
40
|
+
end
|
41
|
+
|
42
|
+
def respond_to?(name, priv = false); true; end
|
43
|
+
|
44
|
+
def method_missing(name, *args, &block)
|
45
|
+
@__attributes ||= {}
|
46
|
+
name = name.to_s
|
47
|
+
|
48
|
+
if __respond_to?(name)
|
49
|
+
super
|
50
|
+
elsif name =~ /\\\\A(.+)=\\\\Z/ and args.length == 1
|
51
|
+
@__attributes[$1] = args[0]
|
52
|
+
elsif name =~ /[^=]\\\\Z/ and args.length == 0
|
53
|
+
@__attributes[$1]
|
54
|
+
else
|
55
|
+
raise NoMethodError, "undefined method `\\\#{name}' for \#{name}"
|
56
|
+
super
|
57
|
+
end
|
58
|
+
end
|
59
|
+
EOS
|
60
|
+
end
|
61
|
+
}
|
62
|
+
|
63
|
+
mod.instance_eval %{
|
64
|
+
def tdbopen(readonly = false)
|
65
|
+
self.connection.tdbopen(self.table_name, readonly) {|tdb| yield(tdb) }
|
66
|
+
end
|
67
|
+
|
68
|
+
def setindex(name, type)
|
69
|
+
self.connection.setindex(self.table_name, name, type)
|
70
|
+
end
|
71
|
+
|
72
|
+
def proc(*args, &block)
|
73
|
+
if block and (options = args.last) and options.kind_of?(Hash)
|
74
|
+
options[:activetokyocabinet_proc] = block
|
75
|
+
end
|
76
|
+
|
77
|
+
self.find(*args)
|
78
|
+
end
|
79
|
+
}
|
80
|
+
|
4
81
|
{:string => :to_s, :int => :to_i, :float => :to_f}.each do |type, conv|
|
5
82
|
mod.instance_eval %{
|
6
83
|
def #{type}(name)
|
84
|
+
raise 'invalid definition: schema_free is already defined' if @__schema_free_defined
|
85
|
+
@__schema_defined = true
|
86
|
+
|
7
87
|
unless @columns
|
8
88
|
primary_key = ActiveRecord::ConnectionAdapters::Column.new('id', nil)
|
9
89
|
primary_key.primary = true
|
@@ -13,22 +93,6 @@ module ActiveTokyoCabinet
|
|
13
93
|
@columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, nil)
|
14
94
|
class_eval "def \#{name}; v = self[:\#{name}]; (v.nil? || v.empty?) ? nil : v.#{conv}; end"
|
15
95
|
end
|
16
|
-
|
17
|
-
def tdbopen(readonly = false)
|
18
|
-
self.connection.tdbopen(self.table_name, readonly) {|tdb| yield(tdb) }
|
19
|
-
end
|
20
|
-
|
21
|
-
def setindex(name, type)
|
22
|
-
self.connection.setindex(self.table_name, name, type)
|
23
|
-
end
|
24
|
-
|
25
|
-
def proc(*args, &block)
|
26
|
-
if block and (options = args.last) and options.kind_of?(Hash)
|
27
|
-
options[:activetokyocabinet_proc] = block
|
28
|
-
end
|
29
|
-
|
30
|
-
self.find(*args)
|
31
|
-
end
|
32
96
|
}
|
33
97
|
end
|
34
98
|
end
|
data/spec/models/book.rb
ADDED
data/spec/spec_helper.rb
CHANGED
@@ -8,6 +8,7 @@ require 'active_record'
|
|
8
8
|
require 'active_tokyocabinet/tdb'
|
9
9
|
require "#{$wd}/models/employee"
|
10
10
|
require "#{$wd}/models/department"
|
11
|
+
require "#{$wd}/models/book"
|
11
12
|
|
12
13
|
ActiveRecord::Base.logger = Logger.new($stderr)
|
13
14
|
ActiveRecord::Base.logger.level = Logger::INFO
|
@@ -188,6 +189,7 @@ module ActiveTokyoCabinetSpec
|
|
188
189
|
def clean
|
189
190
|
FileUtils.rm_f "#{$wd}/employees.tct"
|
190
191
|
FileUtils.rm_f "#{$wd}/departments.tct"
|
192
|
+
FileUtils.rm_f "#{$wd}/books.tct"
|
191
193
|
end
|
192
194
|
end # class << self
|
193
195
|
end # module TokyoCabinetSpec
|
@@ -202,6 +204,7 @@ module ActiveTokyoCabinetSpec
|
|
202
204
|
:database => {
|
203
205
|
:employees => {:host => 'localhost', :port => 1978},
|
204
206
|
:departments => {:host => 'localhost', :port => 1979},
|
207
|
+
:books => {:host => 'localhost', :port => 1980},
|
205
208
|
}
|
206
209
|
)
|
207
210
|
end
|
@@ -213,6 +216,7 @@ module ActiveTokyoCabinetSpec
|
|
213
216
|
|
214
217
|
`ttserver -port 1978 -dmn -pid "#{$wd}/employees.pid" "#{$wd}/employees.tct"`
|
215
218
|
`ttserver -port 1979 -dmn -pid "#{$wd}/departments.pid" "#{$wd}/departments.tct"`
|
219
|
+
`ttserver -port 1980 -dmn -pid "#{$wd}/books.pid" "#{$wd}/books.tct"`
|
216
220
|
sleep 3
|
217
221
|
end
|
218
222
|
|
data/spec/tokyocabinet_spec.rb
CHANGED
@@ -507,6 +507,75 @@ describe 'tokyocabinet:' do
|
|
507
507
|
Department.count.should == 0
|
508
508
|
end
|
509
509
|
|
510
|
+
it "schema free" do
|
511
|
+
Book.create(:foo => 'bar', :zoo => 'baz', :n => 100)
|
512
|
+
Book.create!(:hoge => 'fuga', :n => 200)
|
513
|
+
|
514
|
+
book = Book.new
|
515
|
+
book.xxx = 'XXX'
|
516
|
+
book.yyy = 'YYY'
|
517
|
+
book.zzz = 'ZZZ'
|
518
|
+
book.n = 300
|
519
|
+
book.save!
|
520
|
+
|
521
|
+
Book.count.should == 3
|
522
|
+
|
523
|
+
book = Book.find(2)
|
524
|
+
book.foo.should be_nil
|
525
|
+
book.hoge.should == 'fuga'
|
526
|
+
book.n.should == '200'
|
527
|
+
|
528
|
+
book.n = 250
|
529
|
+
book.save
|
530
|
+
|
531
|
+
books = Book.find(:all, :conditions => ['hoge = ?', 'fuga'])
|
532
|
+
books.length.should == 1
|
533
|
+
books[0].xxx.should be_nil
|
534
|
+
books[0].hoge.should == 'fuga'
|
535
|
+
books[0].n.should == '250'
|
536
|
+
|
537
|
+
books = Book.find(:all, :conditions => ['n >= ?', 200])
|
538
|
+
books.length.should == 2
|
539
|
+
books = books.sort_by {|i| i.id }
|
540
|
+
|
541
|
+
books[0].id.should == 2
|
542
|
+
books[0].hoge.should == 'fuga'
|
543
|
+
books[0].n.should == '250'
|
544
|
+
|
545
|
+
books[1].id.should == 3
|
546
|
+
books[1].xxx.should == 'XXX'
|
547
|
+
books[1].yyy.should == 'YYY'
|
548
|
+
books[1].zzz.should == 'ZZZ'
|
549
|
+
books[1].n.should == '300'
|
550
|
+
|
551
|
+
Book.update_all("xxx = 'xxx'", ['n > ?', 100])
|
552
|
+
|
553
|
+
books = Book.find(:all)
|
554
|
+
books.length.should == 3
|
555
|
+
books = books.sort_by {|i| i.id }
|
556
|
+
|
557
|
+
books[0].id.should == 1
|
558
|
+
books[0].xxx.should be_nil
|
559
|
+
|
560
|
+
books[1].id.should == 2
|
561
|
+
books[1].xxx.should == 'xxx'
|
562
|
+
|
563
|
+
books[2].id.should == 3
|
564
|
+
books[2].xxx.should == 'xxx'
|
565
|
+
|
566
|
+
Book.find(2).destroy
|
567
|
+
|
568
|
+
books = Book.find(:all)
|
569
|
+
books.length.should == 2
|
570
|
+
books = books.sort_by {|i| i.id }
|
571
|
+
|
572
|
+
books[0].id.should == 1
|
573
|
+
books[1].id.should == 3
|
574
|
+
|
575
|
+
Book.delete_all
|
576
|
+
Book.count.should == 0
|
577
|
+
end
|
578
|
+
|
510
579
|
after do
|
511
580
|
TokyoCabinetSpec.clean
|
512
581
|
end
|
data/spec/tokyotyrant_spec.rb
CHANGED
@@ -507,6 +507,75 @@ describe 'tokyotyrant:' do
|
|
507
507
|
Department.count.should == 0
|
508
508
|
end
|
509
509
|
|
510
|
+
it "schema free" do
|
511
|
+
Book.create(:foo => 'bar', :zoo => 'baz', :n => 100)
|
512
|
+
Book.create!(:hoge => 'fuga', :n => 200)
|
513
|
+
|
514
|
+
book = Book.new
|
515
|
+
book.xxx = 'XXX'
|
516
|
+
book.yyy = 'YYY'
|
517
|
+
book.zzz = 'ZZZ'
|
518
|
+
book.n = 300
|
519
|
+
book.save!
|
520
|
+
|
521
|
+
Book.count.should == 3
|
522
|
+
|
523
|
+
book = Book.find(2)
|
524
|
+
book.foo.should be_nil
|
525
|
+
book.hoge.should == 'fuga'
|
526
|
+
book.n.should == '200'
|
527
|
+
|
528
|
+
book.n = 250
|
529
|
+
book.save
|
530
|
+
|
531
|
+
books = Book.find(:all, :conditions => ['hoge = ?', 'fuga'])
|
532
|
+
books.length.should == 1
|
533
|
+
books[0].xxx.should be_nil
|
534
|
+
books[0].hoge.should == 'fuga'
|
535
|
+
books[0].n.should == '250'
|
536
|
+
|
537
|
+
books = Book.find(:all, :conditions => ['n >= ?', 200])
|
538
|
+
books.length.should == 2
|
539
|
+
books = books.sort_by {|i| i.id }
|
540
|
+
|
541
|
+
books[0].id.should == 2
|
542
|
+
books[0].hoge.should == 'fuga'
|
543
|
+
books[0].n.should == '250'
|
544
|
+
|
545
|
+
books[1].id.should == 3
|
546
|
+
books[1].xxx.should == 'XXX'
|
547
|
+
books[1].yyy.should == 'YYY'
|
548
|
+
books[1].zzz.should == 'ZZZ'
|
549
|
+
books[1].n.should == '300'
|
550
|
+
|
551
|
+
Book.update_all("xxx = 'xxx'", ['n > ?', 100])
|
552
|
+
|
553
|
+
books = Book.find(:all)
|
554
|
+
books.length.should == 3
|
555
|
+
books = books.sort_by {|i| i.id }
|
556
|
+
|
557
|
+
books[0].id.should == 1
|
558
|
+
books[0].xxx.should be_nil
|
559
|
+
|
560
|
+
books[1].id.should == 2
|
561
|
+
books[1].xxx.should == 'xxx'
|
562
|
+
|
563
|
+
books[2].id.should == 3
|
564
|
+
books[2].xxx.should == 'xxx'
|
565
|
+
|
566
|
+
Book.find(2).destroy
|
567
|
+
|
568
|
+
books = Book.find(:all)
|
569
|
+
books.length.should == 2
|
570
|
+
books = books.sort_by {|i| i.id }
|
571
|
+
|
572
|
+
books[0].id.should == 1
|
573
|
+
books[1].id.should == 3
|
574
|
+
|
575
|
+
Book.delete_all
|
576
|
+
Book.count.should == 0
|
577
|
+
end
|
578
|
+
|
510
579
|
after do
|
511
580
|
TokyoTyrantSpec.clean
|
512
581
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activetokyocabinet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- winebarrel
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-
|
12
|
+
date: 2010-03-28 00:00:00 +09:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -40,6 +40,7 @@ files:
|
|
40
40
|
- spec/tokyotyrant_spec.rb
|
41
41
|
- spec/models/department.rb
|
42
42
|
- spec/models/employee.rb
|
43
|
+
- spec/models/book.rb
|
43
44
|
- spec/spec_helper.rb
|
44
45
|
- spec/tokyocabinet_spec.rb
|
45
46
|
- spec/tcspec2ttspec.sh
|