ActiveTokyoCabinet

Copyright © 2010 SUGAWARA Genki <[email protected]>

Description

ActiveTokyoCabinet is a library for using Tokyo(Cabinet|Tyrant) under ActiveRecord.

ActiveTokyoCabinet depend on Tokyo(Cabinet|Tyrant).

see 1978th.net/tokyocabinet/ , 1978th.net/tokyotyrant/

Project Page

rubyforge.org/projects/activetokyocabi

Install

gem install activetokyocabinet

see gemcutter.org/gems/activetokyocabinet

Example

database.yml

# TokyoCabinet
development:
  adapter:  tokyocabinet
  database: db/casket/
            # save to `$RAILS_ROOT/db/casket/*.tct'.

# TokyoTyrant
development:
  adapter: tokyotyrant
  database:
    emps:  { host: localhost, port: 1978 }
    depts: { host: localhost, port: 1979 }

Model

class Emp < ActiveRecord::Base
  include ActiveTokyoCabinet::TDB

  # define schema information.
  # (string, int, float)
  string :ename
  int    :age
  string :job
  float  :sal
  string :hiredate
end

ActiveRecord API

# see http://api.rubyonrails.org/classes/ActiveRecord/Base.html

emp = Emp.find(:first, 
        :conditions => ["ename = ? and age > ?", "yamada", 25],
        :order => 'age desc', :limit => 5, :offset => 3)

emp.ename = 'yamamoto'
emp.age   = 30
emp.save

emp_list = Emp.find(101, 102, 103)

emp_list.each do |i|
  i.destroy if i.age > 20
end

new_emp = Emp.new
new_emp.ename = 'suzuki'
new_emp.age   = 27
new_emp.save!

# not available:
# - :include, :group
# - `OR'
# - Subquery
# - Include `ID' in search condition
# see http://activetokyocabi.rubyforge.org/svn/trunk/lib/active_tokyocabinet/sqlparser.y

Expanded operator

# see http://1978th.net/tokyotyrant/rubydoc/classes/TokyoTyrant/RDBQRY.html

# query condition: string begins with
emp = Emp.find(:all, :conditions => ['ename bw ?', 'J'])

# query condition: string ends with
emp = Emp.find(:all, :conditions => ['ename ew ?', 'ES'])

# query condition: string is included in
emp = Emp.find(:all, :conditions => ['ename inc ?', 'LA'])

# query condition: string includes all tokens i 
emp = Emp.find(:all, :conditions => ['job incall (?)', ['ANALYST', 'MANAGER']])

# query condition: string includes at least one token in
emp = Emp.find(:all, :conditions => ['job incany (?)', ['ANALYST', 'MANAGER']])

# query condition: string is equal to at least one token in
emp = Emp.find(:all, :conditions => ['job in (?)', ['ANALYST', 'MANAGER']])
emp = Emp.find(:all, :conditions => ['job anyone (?)', ['ANALYST', 'MANAGER']])

# query condition: string matches regular expressions of
emp = Emp.find(:all, :conditions => ['ename regexp ?', '^J[AO].+$'])

# query condition: number is between two tokens of
emp = Emp.find(:all, :conditions => ['age between ? and ?', 20, 30])
emp = Emp.find(:all, :conditions => ['age bt (?)', [20, 30]])

# query condition: full-text search with the phrase of
emp = Emp.find(:all, :conditions => ['ename fts ?', 'MI'])

# query condition: full-text search with all tokens in
emp = Emp.find(:all, :conditions => ['ename ftsand ?', 'HATSUNE MIKU'])
emp = Emp.find(:all, :conditions => ['ename ftsand (?)', ['HATSUNE', 'MIKU']])

# query condition: full-text search with at least one token in
emp = Emp.find(:all, :conditions => ['hiredate ftsor ?', '1983 DEC'])
emp = Emp.find(:all, :conditions => ['hiredate ftsor (?)', ['1983', 'DEC']])

# query condition: full-text search with the compound expression of
emp = Emp.find(:all, :conditions => ['ename ftsex ?', 'MIKU || RIN'])
emp = Emp.find(:all, :conditions => ['ename ftsex ?', 'HATSUNE && MIKU'])

Low layer API

Emp.tdbopen do |tdb|
  pkey = tdb.genuid
  cols = {"ename" => "tanaka", "age" => "30"}
  tdb.put(pkey, cols)
}

Emp.proc(:all, :conditions => ['name = ?', 'sugawara'], :limit => 10) do |tdb, pkey, cols|
  puts "#{pkey}: #{cols.inspect}
end
# proc method return empty array.

Set index

# see http://1978th.net/tokyotyrant/rubydoc/classes/TokyoTyrant/RDBTBL.html#M000007

Emp.setindex(:age, :decimal)

Example

database.yml

# TokyoCabinet
development:
  adapter:  tokyocabinet
  database: db/casket/
            # save to `$RAILS_ROOT/db/casket/*.tct'.

# TokyoTyrant
development:
  adapter: tokyotyrant
  database:
    emps:  { host: localhost, port: 1978 }
    depts: { host: localhost, port: 1979 }

Schema free

class Book < ActiveRecord::Base
  include ActiveTokyoCabinet::TDB
  schema_free :timestamp => true
end

Book.create(:title => 'photo book', :author => 'Tanaka Takeshi', :price => 200)
Book.create(:title => 'note book', :price => 50)

books = Book.find(:all, :conditions => ['author = ?', 'Tanaka Takeshi'])

Related article