About

Its ruby client for Tarantool Key-Value Storage.

Install

gem install tarantool

Usage

require 'tarantool'

To be able to send requests to the server, you must initialize Tarantool and Tarantool space:

DB = Tarantool.new host: 'locahost', port: 33013
space = DB.space 0

The driver internals can work in two modes: block via TCPSocket and non block via EventMachine and fibers. By default it uses block mode.

space.insert 'prepor', 'Andrew', '[email protected]'
res = space.select 'prepor'
puts "Name: #{res.tuple[1].to_s}; Email: #{res.tuple[2].to_s}"
space.delete 'prepor'

Notice Tarantool instances (connections actually) are not threadsafe. So, you should create Tarantool instance per thread.

To use EventMachine pass type: em in options:

require 'em-synchrony'
DB = Tarantool.new host: 'locahost', port: 33013
space = DB.space 0
EM.synchrony do
  Fiber.new do
    space.insert 'prepor', 'Andrew', '[email protected]'
    res = space.select 'prepor'
    puts "Name: #{res.tuple[1].to_s}; Email: #{res.tuple[2].to_s}"
    space.delete 'prepor'
  end.resume
end

The driver itself provides ActiveModel API: Callbacks, Validations, Serialization, Dirty. Type casting is automatic, based on the index type chosen to process the query. For example:

require 'tarantool/record'
require 'tarantool/serializers/bson'
class User < Tarantool::Record
  field :login, :string
  field :name, :string
  field :email, :string      
  field :apples_count, :integer, default: 0
  field :info, :bson
  index :name, :email

  validates_length_of(:login, minimum: 3)

  after_create do
    # after work!
  end
end

# Now attribute positions are not important.
User.create login: 'prepor', email: '[email protected]', name: 'Andrew'
User.create login: 'ruden', name: 'Andrew', email: '[email protected]'

# find by primary key login
User.find 'prepor' 
# first 2 users with name Andrew
User.where(name: 'Andrew').limit(2).all 
# second user with name Andrew
User.where(name: 'Andrew').offset(1).limit(1).all 
# user with name Andrew and email [email protected]
User.where(name: 'Andrew', email: '[email protected]').first
# raise exception, becouse we can't select query started from not first part of index
begin
    User.where(email: '[email protected]') 
rescue Tarantool::ArgumentError => e
end
# increment field apples_count by one. Its atomic operation via native Tarantool interface
User.find('prepor').increment :apples_count

# update only dirty attributes
user = User.find('prepor')
user.name = "Petr"
user.save

# field serialization to bson
user.info = { 'bio' => "hi!", 'age' => 23, 'hobbies' => ['mufa', 'tuka'] }
user.save
User.find('prepor').info['bio'] # => 'hi!'
# delete record
user.destroy

When definining a record, field order is important: this is the order of fields in the tuple stored by Tarantool. By default, the primary key is field 0.

index method just mapping to your Tarantool schema, client doesn't modify schema for you.

TODO

  • #first, #all without keys, batches requests via box.select_range
  • #where chains
  • admin-socket protocol
  • safe to add fields to exist model
  • Hash, Array and lambdas as default values
  • timers to response, reconnect strategies