activetokyocabinet 0.1.7 → 0.1.8
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/README +93 -33
- data/lib/active_record/connection_adapters/abstract_tokyocabinet_adapter.rb +51 -4
- data/lib/active_record/connection_adapters/tokyocabinet_adapter.rb +2 -4
- data/lib/active_record/connection_adapters/tokyotyrant_adapter.rb +9 -5
- data/lib/active_tokyocabinet/tdb.rb +12 -0
- metadata +2 -2
data/README
CHANGED
|
@@ -22,67 +22,127 @@ see http://gemcutter.org/gems/activetokyocabinet
|
|
|
22
22
|
|
|
23
23
|
== Example
|
|
24
24
|
=== database.yml
|
|
25
|
+
|
|
25
26
|
# TokyoCabinet
|
|
26
27
|
development:
|
|
27
|
-
adapter:
|
|
28
|
-
database:
|
|
29
|
-
|
|
28
|
+
adapter: tokyocabinet
|
|
29
|
+
database: db/casket/
|
|
30
|
+
# save to `$RAILS_ROOT/db/casket/*.tct'.
|
|
31
|
+
|
|
30
32
|
# TokyoTyrant
|
|
31
33
|
development:
|
|
32
34
|
adapter: tokyotyrant
|
|
33
35
|
database:
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
emps: { host: localhost, port: 1978 }
|
|
37
|
+
depts: { host: localhost, port: 1979 }
|
|
36
38
|
|
|
37
39
|
=== Model
|
|
38
40
|
|
|
39
|
-
class
|
|
41
|
+
class Emp < ActiveRecord::Base
|
|
40
42
|
include ActiveTokyoCabinet::TDB
|
|
41
43
|
|
|
42
44
|
# define schema information.
|
|
43
45
|
# (string, int, float)
|
|
44
|
-
string :
|
|
46
|
+
string :ename
|
|
45
47
|
int :age
|
|
48
|
+
string :job
|
|
49
|
+
float :sal
|
|
50
|
+
string :hiredate
|
|
46
51
|
end
|
|
47
52
|
|
|
48
|
-
===
|
|
53
|
+
=== ActiveRecord API
|
|
49
54
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
55
|
+
# see http://api.rubyonrails.org/classes/ActiveRecord/Base.html
|
|
56
|
+
|
|
57
|
+
emp = Emp.find(:first,
|
|
58
|
+
:conditions => ["ename = ? and age > ?", "yamada", 25],
|
|
59
|
+
:order => 'age desc', :limit => 5, :offset => 3)
|
|
60
|
+
|
|
61
|
+
emp.ename = 'yamamoto'
|
|
62
|
+
emp.age = 30
|
|
63
|
+
emp.save
|
|
64
|
+
|
|
65
|
+
emp_list = Emp.find(101, 102, 103)
|
|
53
66
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
67
|
+
emp_list.each do |i|
|
|
68
|
+
i.destroy if i.age > 20
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
new_emp = Emp.new
|
|
72
|
+
new_emp.ename = 'suzuki'
|
|
73
|
+
new_emp.age = 27
|
|
74
|
+
new_emp.save!
|
|
75
|
+
|
|
76
|
+
# not available:
|
|
77
|
+
# - :include, :group
|
|
78
|
+
# - `OR'
|
|
79
|
+
# - Subquery
|
|
80
|
+
# - Include `ID' in search condition
|
|
81
|
+
# see http://activetokyocabi.rubyforge.org/svn/trunk/lib/active_tokyocabinet/sqlparser.y
|
|
82
|
+
|
|
83
|
+
== Expanded operator
|
|
84
|
+
|
|
85
|
+
# see http://1978th.net/tokyotyrant/rubydoc/classes/TokyoTyrant/RDBQRY.html
|
|
61
86
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
:order => 'age desc', :limit => 5, :offset => 3)
|
|
87
|
+
# query condition: string begins with
|
|
88
|
+
emp = Emp.find(:all, :conditions => ['ename bw ?', 'J'])
|
|
65
89
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
hello.save!
|
|
90
|
+
# query condition: string ends with
|
|
91
|
+
emp = Emp.find(:all, :conditions => ['ename ew ?', 'ES'])
|
|
69
92
|
|
|
70
|
-
|
|
93
|
+
# query condition: string is included in
|
|
94
|
+
emp = Emp.find(:all, :conditions => ['ename inc ?', 'LA'])
|
|
71
95
|
|
|
72
|
-
|
|
73
|
-
|
|
96
|
+
# query condition: string includes all tokens i
|
|
97
|
+
emp = Emp.find(:all, :conditions => ['job incall (?)', ['ANALYST', 'MANAGER']])
|
|
74
98
|
|
|
75
|
-
|
|
99
|
+
# query condition: string includes at least one token in
|
|
100
|
+
emp = Emp.find(:all, :conditions => ['job incany (?)', ['ANALYST', 'MANAGER']])
|
|
76
101
|
|
|
77
|
-
|
|
102
|
+
# query condition: string is equal to at least one token in
|
|
103
|
+
emp = Emp.find(:all, :conditions => ['job in (?)', ['ANALYST', 'MANAGER']])
|
|
104
|
+
emp = Emp.find(:all, :conditions => ['job anyone (?)', ['ANALYST', 'MANAGER']])
|
|
78
105
|
|
|
79
|
-
|
|
106
|
+
# query condition: string matches regular expressions of
|
|
107
|
+
emp = Emp.find(:all, :conditions => ['ename regexp ?', '^J[AO].+$'])
|
|
80
108
|
|
|
81
|
-
|
|
109
|
+
# query condition: number is between two tokens of
|
|
110
|
+
emp = Emp.find(:all, :conditions => ['age between ? and ?', 20, 30])
|
|
111
|
+
emp = Emp.find(:all, :conditions => ['age bt (?)', [20, 30]])
|
|
112
|
+
|
|
113
|
+
# query condition: full-text search with the phrase of
|
|
114
|
+
emp = Emp.find(:all, :conditions => ['ename fts ?', 'MI'])
|
|
115
|
+
|
|
116
|
+
# query condition: full-text search with all tokens in
|
|
117
|
+
emp = Emp.find(:all, :conditions => ['ename ftsand ?', 'HATSUNE MIKU'])
|
|
118
|
+
emp = Emp.find(:all, :conditions => ['ename ftsand (?)', ['HATSUNE', 'MIKU']])
|
|
119
|
+
|
|
120
|
+
# query condition: full-text search with at least one token in
|
|
121
|
+
emp = Emp.find(:all, :conditions => ['hiredate ftsor ?', '1983 DEC'])
|
|
122
|
+
emp = Emp.find(:all, :conditions => ['hiredate ftsor (?)', ['1983', 'DEC']])
|
|
123
|
+
|
|
124
|
+
# query condition: full-text search with the compound expression of
|
|
125
|
+
emp = Emp.find(:all, :conditions => ['ename ftsex ?', 'MIKU || RIN'])
|
|
126
|
+
emp = Emp.find(:all, :conditions => ['ename ftsex ?', 'HATSUNE && MIKU'])
|
|
127
|
+
|
|
128
|
+
== Low layer API
|
|
82
129
|
|
|
83
|
-
|
|
84
|
-
|
|
130
|
+
Emp.tdbopen do |tdb|
|
|
131
|
+
pkey = tdb.genuid
|
|
132
|
+
cols = {"ename" => "tanaka", "age" => "30"}
|
|
133
|
+
tdb.put(pkey, cols)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
Emp.proc(:all, :conditions => ['name = ?', 'sugawara'], :limit => 10) do |tdb, pkey, cols|
|
|
137
|
+
puts "#{pkey}: #{cols.inspect}
|
|
85
138
|
end
|
|
139
|
+
# proc method return empty array.
|
|
140
|
+
|
|
141
|
+
== Set index
|
|
142
|
+
|
|
143
|
+
# see http://1978th.net/tokyotyrant/rubydoc/classes/TokyoTyrant/RDBTBL.html#M000007
|
|
144
|
+
|
|
145
|
+
Emp.setindex(:age, :decimal)
|
|
86
146
|
|
|
87
147
|
== Related article
|
|
88
148
|
* http://d.hatena.ne.jp/winebarrel/20100106/p1
|
|
@@ -1,7 +1,44 @@
|
|
|
1
|
+
require 'active_record/base'
|
|
1
2
|
require 'active_record/connection_adapters/abstract_adapter'
|
|
2
3
|
require 'active_tokyocabinet/tdb'
|
|
3
4
|
require 'active_tokyocabinet/sqlparser.tab'
|
|
4
5
|
|
|
6
|
+
module ActiveRecord
|
|
7
|
+
class Base
|
|
8
|
+
class << self
|
|
9
|
+
def find_by_sql_with_activetokyocabinet(args)
|
|
10
|
+
retval = nil
|
|
11
|
+
|
|
12
|
+
if self.include?(ActiveTokyoCabinet::TDB) and args.kind_of?(Array)
|
|
13
|
+
sql, proc = args
|
|
14
|
+
connection.select(sanitize_sql(sql), "#{name} Load", &proc)
|
|
15
|
+
retval = []
|
|
16
|
+
else
|
|
17
|
+
retval = find_by_sql_without_activetokyocabinet(args)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
return retval
|
|
21
|
+
end
|
|
22
|
+
alias_method_chain :find_by_sql, :activetokyocabinet
|
|
23
|
+
|
|
24
|
+
def construct_finder_sql_with_activetokyocabinet(options)
|
|
25
|
+
sql = construct_finder_sql_without_activetokyocabinet(options)
|
|
26
|
+
|
|
27
|
+
if self.include?(ActiveTokyoCabinet::TDB) and (proc = options[:activetokyocabinet_proc])
|
|
28
|
+
sql = [sql, proc]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
return sql
|
|
32
|
+
end
|
|
33
|
+
alias_method_chain :construct_finder_sql, :activetokyocabinet
|
|
34
|
+
|
|
35
|
+
unless VALID_FIND_OPTIONS.include?(:activetokyocabinet_proc)
|
|
36
|
+
VALID_FIND_OPTIONS << :activetokyocabinet_proc
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
5
42
|
module ActiveRecord
|
|
6
43
|
module ConnectionAdapters
|
|
7
44
|
class AbstractTokyoCabinetAdapter < AbstractAdapter
|
|
@@ -20,9 +57,13 @@ module ActiveRecord
|
|
|
20
57
|
log(sql, name) do
|
|
21
58
|
parsed_sql = ActiveTokyoCabinet::SQLParser.new(sql).parse
|
|
22
59
|
|
|
23
|
-
tdbopen(parsed_sql) do |tdb|
|
|
60
|
+
tdbopen(parsed_sql[:table], true) do |tdb|
|
|
24
61
|
if (count = parsed_sql[:count])
|
|
25
62
|
rows = [{count => rnum(tdb, parsed_sql)}]
|
|
63
|
+
elsif block_given?
|
|
64
|
+
rows = search(tdb, parsed_sql) do |_tdb, rkey, rcols|
|
|
65
|
+
yield([_tdb, rkey, rcols])
|
|
66
|
+
end
|
|
26
67
|
else
|
|
27
68
|
rows = search(tdb, parsed_sql)
|
|
28
69
|
end
|
|
@@ -38,7 +79,7 @@ module ActiveRecord
|
|
|
38
79
|
log(sql, name) do
|
|
39
80
|
parsed_sql = ActiveTokyoCabinet::SQLParser.new(sql).parse
|
|
40
81
|
|
|
41
|
-
tdbopen(parsed_sql) do |tdb|
|
|
82
|
+
tdbopen(parsed_sql[:table]) do |tdb|
|
|
42
83
|
pkey = tdb.genuid
|
|
43
84
|
keys = parsed_sql[:column_list]
|
|
44
85
|
vals = parsed_sql[:value_list]
|
|
@@ -64,7 +105,7 @@ module ActiveRecord
|
|
|
64
105
|
log(sql, name) do
|
|
65
106
|
parsed_sql = ActiveTokyoCabinet::SQLParser.new(sql).parse
|
|
66
107
|
|
|
67
|
-
tdbopen(parsed_sql) do |tdb|
|
|
108
|
+
tdbopen(parsed_sql[:table]) do |tdb|
|
|
68
109
|
set_clause_list = parsed_sql[:set_clause_list]
|
|
69
110
|
|
|
70
111
|
rkeys(tdb, parsed_sql).each do |rkey|
|
|
@@ -92,7 +133,7 @@ module ActiveRecord
|
|
|
92
133
|
log(sql, name) do
|
|
93
134
|
parsed_sql = ActiveTokyoCabinet::SQLParser.new(sql).parse
|
|
94
135
|
|
|
95
|
-
tdbopen(parsed_sql) do |tdb|
|
|
136
|
+
tdbopen(parsed_sql[:table]) do |tdb|
|
|
96
137
|
unless query(tdb, parsed_sql).searchout
|
|
97
138
|
ecode = tdb.ecode
|
|
98
139
|
raise '%s: %s' % [tdb.errmsg(ecode), sql]
|
|
@@ -110,6 +151,12 @@ module ActiveRecord
|
|
|
110
151
|
|
|
111
152
|
rkeys(tdb, parsed_sql).each do |rkey|
|
|
112
153
|
rcols = tdb.get(rkey)
|
|
154
|
+
|
|
155
|
+
if block_given?
|
|
156
|
+
yield(tdb, rkey.to_i, rcols)
|
|
157
|
+
next
|
|
158
|
+
end
|
|
159
|
+
|
|
113
160
|
next if rcols.nil?
|
|
114
161
|
|
|
115
162
|
unless select_list.nil? or select_list.empty?
|
|
@@ -28,11 +28,10 @@ module ActiveRecord
|
|
|
28
28
|
File.exist?(path)
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
def tdbopen(
|
|
32
|
-
table_name = parsed_sql[:table]
|
|
31
|
+
def tdbopen(table_name, readonly = false)
|
|
33
32
|
path = tdbpath(table_name)
|
|
34
33
|
|
|
35
|
-
if File.exist?(path) and
|
|
34
|
+
if File.exist?(path) and readonly
|
|
36
35
|
omode = TokyoCabinet::TDB::OREADER
|
|
37
36
|
else
|
|
38
37
|
omode = TokyoCabinet::TDB::OWRITER | TokyoCabinet::TDB::OCREAT
|
|
@@ -54,7 +53,6 @@ module ActiveRecord
|
|
|
54
53
|
end
|
|
55
54
|
end
|
|
56
55
|
end
|
|
57
|
-
private :tdbopen
|
|
58
56
|
|
|
59
57
|
def tdbpath(table_name)
|
|
60
58
|
File.join(@config[:database], table_name + ".tct")
|
|
@@ -45,9 +45,7 @@ module ActiveRecord
|
|
|
45
45
|
end
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
-
def tdbopen(
|
|
49
|
-
table_name = parsed_sql[:table]
|
|
50
|
-
|
|
48
|
+
def tdbopen(table_name, readonly = false)
|
|
51
49
|
unless table_exists?(table_name)
|
|
52
50
|
raise "Table does not exist: #{table_name}"
|
|
53
51
|
end
|
|
@@ -65,7 +63,6 @@ module ActiveRecord
|
|
|
65
63
|
yield(tdb)
|
|
66
64
|
@connection[table_name] = tdb
|
|
67
65
|
end
|
|
68
|
-
private :tdbopen
|
|
69
66
|
|
|
70
67
|
def search(tdb, parsed_sql)
|
|
71
68
|
condition = parsed_sql[:condition] || []
|
|
@@ -82,7 +79,14 @@ module ActiveRecord
|
|
|
82
79
|
end
|
|
83
80
|
|
|
84
81
|
rows = query(tdb, parsed_sql).searchget
|
|
85
|
-
|
|
82
|
+
|
|
83
|
+
if block_given?
|
|
84
|
+
rows.each do |i|
|
|
85
|
+
yield(tdb, i[""].to_i, i)
|
|
86
|
+
end
|
|
87
|
+
else
|
|
88
|
+
rows.each {|i| i['id'] = i[""].to_i }
|
|
89
|
+
end
|
|
86
90
|
|
|
87
91
|
return rows
|
|
88
92
|
end
|
|
@@ -14,9 +14,21 @@ module ActiveTokyoCabinet
|
|
|
14
14
|
class_eval "def \#{name}; v = self[:\#{name}]; (v.nil? || v.empty?) ? nil : v.#{conv}; end"
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
+
def tdbopen(readonly = false)
|
|
18
|
+
self.connection.tdbopen(self.table_name, readonly) {|tdb| yield(tdb) }
|
|
19
|
+
end
|
|
20
|
+
|
|
17
21
|
def setindex(name, type)
|
|
18
22
|
self.connection.setindex(self.table_name, name, type)
|
|
19
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
|
|
20
32
|
}
|
|
21
33
|
end
|
|
22
34
|
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.1.
|
|
4
|
+
version: 0.1.8
|
|
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-01-
|
|
12
|
+
date: 2010-01-17 00:00:00 +09:00
|
|
13
13
|
default_executable:
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|