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 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