activetokyocabinet 0.1.7 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
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: tokyocabinet
28
- database: path_of_database_directory
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
- hellos: { host: localhost, port: 1978 }
35
- tests: { host: localhost, port: 1979 }
36
+ emps: { host: localhost, port: 1978 }
37
+ depts: { host: localhost, port: 1979 }
36
38
 
37
39
  === Model
38
40
 
39
- class Hello < ActiveRecord::Base
41
+ class Emp < ActiveRecord::Base
40
42
  include ActiveTokyoCabinet::TDB
41
43
 
42
44
  # define schema information.
43
45
  # (string, int, float)
44
- string :name
46
+ string :ename
45
47
  int :age
48
+ string :job
49
+ float :sal
50
+ string :hiredate
46
51
  end
47
52
 
48
- === Example Controller
53
+ === ActiveRecord API
49
54
 
50
- class HelloController < ApplicationController
51
- def index
52
- hello_id = nil
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
- (20..35).each do |i|
55
- hello = Hello.new
56
- hello.name = 'yamada'
57
- hello.age = i
58
- hello.save!
59
- hello_id = hello.id
60
- end
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
- p Hello.find(:all,
63
- :conditions => ["name = ? and age > ?", "yamada", 25],
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
- hello = Hello.find(hello_id)
67
- hello.name = 'yamashita'
68
- hello.save!
90
+ # query condition: string ends with
91
+ emp = Emp.find(:all, :conditions => ['ename ew ?', 'ES'])
69
92
 
70
- p Hello.find(:first, :conditions => ["name = ?", "yamashita"])
93
+ # query condition: string is included in
94
+ emp = Emp.find(:all, :conditions => ['ename inc ?', 'LA'])
71
95
 
72
- hello = Hello.find(hello_id)
73
- hello.destroy
96
+ # query condition: string includes all tokens i
97
+ emp = Emp.find(:all, :conditions => ['job incall (?)', ['ANALYST', 'MANAGER']])
74
98
 
75
- p Hello.find(:first, :conditions => ["name = ?", "yamashita"])
99
+ # query condition: string includes at least one token in
100
+ emp = Emp.find(:all, :conditions => ['job incany (?)', ['ANALYST', 'MANAGER']])
76
101
 
77
- p Hello.find(:all)
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
- Hello.delete_all(["name = ? and age <= ?", "yamada", 30])
106
+ # query condition: string matches regular expressions of
107
+ emp = Emp.find(:all, :conditions => ['ename regexp ?', '^J[AO].+$'])
80
108
 
81
- p Hello.find(:all)
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
- render :text => 'hello'
84
- end
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(parsed_sql)
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 parsed_sql[:command] == :select
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(parsed_sql)
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
- rows.each {|i| i['id'] = i[""].to_i }
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.7
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 00:00:00 +09:00
12
+ date: 2010-01-17 00:00:00 +09:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency