Skip to content

Commit

Permalink
update readme
Browse files Browse the repository at this point in the history
  • Loading branch information
funny-falcon committed Jul 18, 2012
1 parent 60dcfb4 commit 0bd5de2
Showing 1 changed file with 90 additions and 30 deletions.
120 changes: 90 additions & 30 deletions README.md
Expand Up @@ -14,12 +14,36 @@ gem install tarantool
require 'tarantool' require 'tarantool'
``` ```


To be able to send requests to the server, you must To be able to send requests to the server, you must initialize Tarantool
initialize Tarantool and Tarantool space: and Tarantool space. Space could be initialized with definition of fields
types (and names) or without (which is not recommended).

Available field types:
- `:int`, `:integer` - nonnegative 32 bit integer
- `:int64`, `:integer64` - nonnegative 64 bit integer
- `:varint` - 32bit or 64bit integer, depending on value
- `:str`, `:string` - UTF-8 string (attention: empty string is stored as "\x00", which converted back to "" on load)
- `:bytes` - ASCII8-bit
- `:auto` - do not use it (used for space without definition)
- any object with #encode and #decode methods

Declaration of indexes is optional for array spaces and required for hash spaces.
When there is no indexes defined for space array, their behaviour is not fixes, so that
is up to you to specify right amount of values for that indexes.


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

space_array = DB.space 1, [:int, :str, :int], keys: [0, [1,2]]

# last integer specifies tuples tail pattern
# note, that two indexes are defined here
space_array_with_tail = DB.space 2, [:int, :str, :str, :int, 2], keys: [0, 1]

# space, which returns hashes
space_hash = DB.space 1, {id: int, name: :str, score: :int}, keys: [:id, [:name, :score]]
space_hash_with_tail = DB.space 2, {id: int, name: :str, _tail: [:str, :int]}, keys: [:id, :name]
``` ```


The driver internals can work in three modes: The driver internals can work in three modes:
Expand All @@ -28,39 +52,61 @@ The driver internals can work in three modes:
- EM::Synchrony like via EventMachine and fibers, so that control flow is visually - EM::Synchrony like via EventMachine and fibers, so that control flow is visually
blocked, but eventloop is not (see EM::Synchrony) blocked, but eventloop is not (see EM::Synchrony)


By default it uses block mode. ```ruby
DB_SYNC = Tarantool.new host: 'localhost', port: 33013, type: :block
DB_CALLBACK = Tarantool.new host: 'localhost', port: 33013, type: :em_callback || :em_cb
DB_FIBER = Tarantool.new host: 'localhost', port: 33013, type: :em_fiber || :em
```


Blocking and Fibered interfaces look similar:


```ruby ```ruby
space.insert 'prepor', 'Andrew', 'ceo@prepor.ru' space = (DB_SYNC || DB_FIBER).space 0, [:str, :str, :str], keys: 0
res = space.select 'prepor' # EM.synchrony do
puts "Name: #{res.tuple[1].to_s}; Email: #{res.tuple[2].to_s}" space.insert ['prepor', 'Andrew', 'ceo@prepor.ru']
space.delete 'prepor' res = space.by_pk 'prepor' # || ['prepor']
res = space.first_by_key 0, 'prepor' # || ['prepor']
res = space.select 0, ['prepor']
puts "Name: #{res[1]}; Email: #{res[2]}"
space.delete 'prepor'
# EM.stop
# end
``` ```


**Notice** `Tarantool` instances (connections actually) are not threadsafe. So, you should create `Tarantool` instance per thread. Callback interface is a bit different:

To use EventMachine pass type: em in options:


```ruby ```ruby
require 'em-synchrony' space = DB_CALLBACK.space 0, [:str, :str, :str], keys: 0
DB = Tarantool.new host: 'locahost', port: 33013, type: :em EM.schedule do
EM.synchrony do space.insert ['prepor', 'Andrew', 'ceo@prepor.ru'] do |res|
space = DB.space 0 if Exception === res
space.insert 'prepor', 'Andrew', 'ceo@prepor.ru' catch_error
res = space.select 'prepor' else
puts "Name: #{res.tuple[1].to_s}; Email: #{res.tuple[2].to_s}" space.by_pk 'prepor' do |res|
space.delete 'prepor' if Exception === res
EM.stop catch_error
else
puts "Name: #{res[1]}; Email: #{res[2]}"
space.delete 'prepor' do |res|
catch_error if Exception === res
EM.stop
end
end
end
end
end
end end
``` ```


The driver itself provides ActiveModel API: Callbacks, Validations, Serialization, Dirty. **Notice** Blocking `Tarantool` connections are not threadsafe. So, you should create `Tarantool` instance per thread.
Type casting is automatic, based on the index type chosen to process the query.
For example: ## LightRecord

`LightRecord` is a light model with callbacks ala Sequel. It is not aware about ActiveModel goodness.
For ActiveModel avare record look for `tarantool-record` gem


```ruby ```ruby
require 'tarantool/record' require 'tarantool/light_record'
require 'tarantool/serializers/bson' require 'tarantool/serializers/bson'
class User < Tarantool::Record class User < Tarantool::Record
field :login, :string field :login, :string
Expand All @@ -70,10 +116,14 @@ class User < Tarantool::Record
field :info, :bson field :info, :bson
index :name, :email index :name, :email


validates_length_of(:login, minimum: 3) def after_init
super
# some work
end


after_create do def before_create
# after work! # validation could occure here
super # call super if all is allright, return false otherwise
end end
end end


Expand All @@ -82,11 +132,19 @@ User.create login: 'prepor', email: 'ceo@prepor.ru', name: 'Andrew'
User.create login: 'ruden', name: 'Andrew', email: 'rudenkoco@gmail.com' User.create login: 'ruden', name: 'Andrew', email: 'rudenkoco@gmail.com'


# find by primary key login # find by primary key login
User.by_pk 'prepor'
User.first 'prepor'
User.first login: 'prepor'
User.find 'prepor' User.find 'prepor'
# first 2 users with name Andrew # first 2 users with name Andrew
User.all({name: 'Andrew'}, limit: 2)
User.select({name: 'Andrew'}, limit: 2)
User.where(name: 'Andrew').limit(2).all User.where(name: 'Andrew').limit(2).all
# second user with name Andrew # second user with name Andrew
User.where(name: 'Andrew').offset(1).limit(1).all User.all({name: 'Andrew'}, offset: 1, limit: 1)[0]
User.select({name: 'Andrew'}, offset: 1, limit: 1)[0]
User.where(name: 'Andrew').offset(1).limit(1).all[0]
User.where(name: 'Andrew').offset(1).first
# user with name Andrew and email ceo@prepor.ru # user with name Andrew and email ceo@prepor.ru
User.where(name: 'Andrew', email: 'ceo@prepor.ru').first User.where(name: 'Andrew', email: 'ceo@prepor.ru').first
# raise exception, becouse we can't select query started from not first part of index # raise exception, becouse we can't select query started from not first part of index
Expand All @@ -97,10 +155,12 @@ end
# increment field apples_count by one. Its atomic operation via native Tarantool interface # increment field apples_count by one. Its atomic operation via native Tarantool interface
User.find('prepor').increment :apples_count User.find('prepor').increment :apples_count


# update only dirty attributes # update all attributes (see tarantool-record gem for record, which updates only dirty attributes)
user = User.find('prepor') user = User.find('prepor')
user.name = "Petr" user.name = "Petr"
user.save user.save
user.update_attributes email: "petr@inter.com" # calls callbacks as well as `save`
user.update email: "petr@inter.com" # do not calls callbacks, and reloads all fields


# field serialization to bson # field serialization to bson
user.info = { 'bio' => "hi!", 'age' => 23, 'hobbies' => ['mufa', 'tuka'] } user.info = { 'bio' => "hi!", 'age' => 23, 'hobbies' => ['mufa', 'tuka'] }
Expand All @@ -123,4 +183,4 @@ in the tuple stored by Tarantool. By default, the primary key is field 0.
* admin-socket protocol * admin-socket protocol
* safe to add fields to exist model * safe to add fields to exist model
* Hash, Array and lambdas as default values * Hash, Array and lambdas as default values
* timers to response, reconnect strategies * timers to response

0 comments on commit 0bd5de2

Please sign in to comment.