Permalink
Browse files

update readme

  • Loading branch information...
1 parent 60dcfb4 commit 0bd5de261443739dd2caffbacde6d4a7b476b070 @funny-falcon funny-falcon committed Jul 18, 2012
Showing with 90 additions and 30 deletions.
  1. +90 −30 README.md
View
120 README.md
@@ -14,12 +14,36 @@ gem install tarantool
require 'tarantool'
```
-To be able to send requests to the server, you must
-initialize Tarantool and Tarantool space:
+To be able to send requests to the server, you must initialize Tarantool
+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
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:
@@ -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
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
-space.insert 'prepor', 'Andrew', 'ceo@prepor.ru'
-res = space.select 'prepor'
-puts "Name: #{res.tuple[1].to_s}; Email: #{res.tuple[2].to_s}"
-space.delete 'prepor'
+ space = (DB_SYNC || DB_FIBER).space 0, [:str, :str, :str], keys: 0
+ # EM.synchrony do
+ space.insert ['prepor', 'Andrew', 'ceo@prepor.ru']
+ 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.
-
-To use EventMachine pass type: em in options:
+Callback interface is a bit different:
```ruby
-require 'em-synchrony'
-DB = Tarantool.new host: 'locahost', port: 33013, type: :em
-EM.synchrony do
- space = DB.space 0
- space.insert 'prepor', 'Andrew', 'ceo@prepor.ru'
- res = space.select 'prepor'
- puts "Name: #{res.tuple[1].to_s}; Email: #{res.tuple[2].to_s}"
- space.delete 'prepor'
- EM.stop
+space = DB_CALLBACK.space 0, [:str, :str, :str], keys: 0
+EM.schedule do
+ space.insert ['prepor', 'Andrew', 'ceo@prepor.ru'] do |res|
+ if Exception === res
+ catch_error
+ else
+ space.by_pk 'prepor' do |res|
+ if Exception === res
+ 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
```
-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:
+**Notice** Blocking `Tarantool` connections are not threadsafe. So, you should create `Tarantool` instance per thread.
+
+## 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
-require 'tarantool/record'
+require 'tarantool/light_record'
require 'tarantool/serializers/bson'
class User < Tarantool::Record
field :login, :string
@@ -70,10 +116,14 @@ class User < Tarantool::Record
field :info, :bson
index :name, :email
- validates_length_of(:login, minimum: 3)
+ def after_init
+ super
+ # some work
+ end
- after_create do
- # after work!
+ def before_create
+ # validation could occure here
+ super # call super if all is allright, return false otherwise
end
end
@@ -82,11 +132,19 @@ User.create login: 'prepor', email: 'ceo@prepor.ru', name: 'Andrew'
User.create login: 'ruden', name: 'Andrew', email: 'rudenkoco@gmail.com'
# find by primary key login
+User.by_pk 'prepor'
+User.first 'prepor'
+User.first login: 'prepor'
User.find 'prepor'
# 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
# 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.where(name: 'Andrew', email: 'ceo@prepor.ru').first
# raise exception, becouse we can't select query started from not first part of index
@@ -97,10 +155,12 @@ end
# increment field apples_count by one. Its atomic operation via native Tarantool interface
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.name = "Petr"
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
user.info = { 'bio' => "hi!", 'age' => 23, 'hobbies' => ['mufa', 'tuka'] }
@@ -123,4 +183,4 @@ in the tuple stored by Tarantool. By default, the primary key is field 0.
* admin-socket protocol
* safe to add fields to exist model
* 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.