tarantool 0.2.4 → 0.2.5

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/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- tarantool (0.2.3)
4
+ tarantool (0.2.4)
5
5
  activemodel (>= 3.1, < 4.0)
6
6
  iproto (>= 0.2)
7
7
 
data/README.md CHANGED
@@ -111,7 +111,7 @@ in the tuple stored by Tarantool. By default, the primary key is field 0.
111
111
 
112
112
  # TODO
113
113
 
114
- # .to_config
114
+ * .to_config
115
115
  * `#first`, `#all` without keys, batches requests via box.select_range
116
116
  * `#where` chains
117
117
  * admin-socket protocol
@@ -77,20 +77,14 @@ class Tarantool
77
77
  end
78
78
 
79
79
  def detect_index_no(keys)
80
- index_no = nil
81
- record.indexes.each_with_index do |v, i|
80
+ record.indexes.each.with_index do |v, i|
82
81
  keys_inst = keys.dup
83
82
  v.each do |index_part|
84
- unless keys_inst.delete(index_part)
85
- break
86
- end
87
- if keys_inst.size == 0
88
- index_no = i
89
- end
83
+ break unless keys_inst.delete(index_part)
84
+ return i if keys_inst.empty?
90
85
  end
91
- break if index_no
92
86
  end
93
- index_no
87
+ nil
94
88
  end
95
89
 
96
90
  def to_records(tuples)
@@ -111,6 +105,7 @@ class Tarantool
111
105
  include ActiveModel::Serializers::Xml
112
106
 
113
107
  define_model_callbacks :save, :create, :update, :destroy
108
+ define_model_callbacks :initialize, :only => :after
114
109
 
115
110
  class_attribute :fields
116
111
  self.fields = {}
@@ -153,7 +148,14 @@ class Tarantool
153
148
  end
154
149
 
155
150
  def index(*fields)
156
- self.indexes = (indexes.dup << fields).sort_by { |v| v.size }
151
+ options = {}
152
+ options = fields.pop if Hash === fields.last
153
+ if options[:primary]
154
+ self.indexes[0] = fields
155
+ self.primary_index = fields
156
+ else
157
+ self.indexes = (indexes.dup << fields)
158
+ end
157
159
  end
158
160
 
159
161
  def find(*keys)
@@ -184,7 +186,7 @@ class Tarantool
184
186
  end
185
187
 
186
188
  def from_server(tuple)
187
- new(tuple_to_hash(tuple)).tap { |v| v.old_record! }
189
+ new(tuple_to_hash(tuple).merge __new_record: false)
188
190
  end
189
191
 
190
192
  def space
@@ -233,16 +235,29 @@ class Tarantool
233
235
  end
234
236
  end
235
237
 
236
- attr_accessor :new_record
238
+ attr_accessor :__new_record
237
239
  def initialize(attributes = {})
240
+ run_callbacks(:initialize) do
241
+ init attributes
242
+ end
243
+ end
244
+
245
+ def init(attributes)
246
+ @__new_record = attributes.delete(:__new_record)
247
+ @__new_record = true if @__new_record.nil?
238
248
  attributes.each do |k, v|
239
249
  send("#{k}=", v)
240
- end
241
- @new_record = true
250
+ end
242
251
  end
243
252
 
244
253
  def id
245
- attributes[self.class.primary_index]
254
+ primary = self.class.primary_index
255
+ case primary
256
+ when Array
257
+ primary.map{ |p| attributes[p] }
258
+ else
259
+ attributes[primary]
260
+ end
246
261
  end
247
262
 
248
263
  def space
@@ -250,7 +265,7 @@ class Tarantool
250
265
  end
251
266
 
252
267
  def new_record?
253
- @new_record
268
+ @__new_record
254
269
  end
255
270
 
256
271
  def attributes
@@ -258,11 +273,11 @@ class Tarantool
258
273
  end
259
274
 
260
275
  def new_record!
261
- @new_record = true
276
+ @__new_record = true
262
277
  end
263
278
 
264
279
  def old_record!
265
- @new_record = false
280
+ @__new_record = false
266
281
  end
267
282
 
268
283
  def save
@@ -274,6 +289,7 @@ class Tarantool
274
289
  if new_record?
275
290
  space.insert(*to_tuple)
276
291
  else
292
+ return true if changed.size == 0
277
293
  ops = changed.inject([]) do |memo, k|
278
294
  k = k.to_sym
279
295
  memo << [field_no(k), :set, self.class._cast(k, attributes[k])] if attributes[k]
@@ -322,9 +338,15 @@ class Tarantool
322
338
  self.class.fields[name][:field_no]
323
339
  end
324
340
 
325
- # return new object, not reloading itself as AR-model
326
341
  def reload
327
- self.class.find(id)
342
+ tuple = space.select(id).tuple
343
+ return false unless tuple
344
+ init self.class.tuple_to_hash(tuple).merge __new_record: false
345
+ self
346
+ end
347
+
348
+ def ==(other)
349
+ self.id == other.id
328
350
  end
329
351
 
330
352
  end
@@ -11,7 +11,7 @@ class Tarantool
11
11
 
12
12
  def make_body
13
13
  [space_no, flags].pack('LL') +
14
- self.class.pack_tuple(key)
14
+ self.class.pack_tuple(*key)
15
15
  end
16
16
  end
17
17
  end
@@ -26,7 +26,7 @@ class Tarantool
26
26
 
27
27
  def make_body
28
28
  [space_no, flags].pack('LL') +
29
- self.class.pack_tuple(key) +
29
+ self.class.pack_tuple(*key) +
30
30
  [ops.size].pack('L') +
31
31
  self.class.pack_ops(ops)
32
32
  end
data/lib/tarantool.rb CHANGED
@@ -2,7 +2,7 @@
2
2
  require 'iproto'
3
3
 
4
4
  class Tarantool
5
- VERSION = '0.2.4'
5
+ VERSION = '0.2.5'
6
6
 
7
7
  require 'tarantool/space'
8
8
  require 'tarantool/requests'
@@ -1,9 +1,9 @@
1
1
  module Helpers
2
2
  module Truncate
3
- def teardown
3
+ def teardown
4
4
  while (res = space.call('box.select_range', space.space_no, 0, 100, return_tuple: true)) && res.tuples.size > 0
5
- res.tuples.each do |k, *_|
6
- space.delete key: k
5
+ res.tuples.each do |keys|
6
+ space.delete key: keys.take(@primary_key_size || 1)
7
7
  end
8
8
  end
9
9
  super
data/spec/spec_helper.rb CHANGED
@@ -11,7 +11,7 @@ require 'rr'
11
11
 
12
12
  require 'tarantool'
13
13
 
14
- TARANTOOL_CONFIG = { host: 'localhost', port: 33013, type: :block }
14
+ TARANTOOL_CONFIG = { host: 'localhost', port: 33113, type: :block }
15
15
 
16
16
  DB = Tarantool.new TARANTOOL_CONFIG
17
17
 
@@ -0,0 +1,79 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'spec_helper'
3
+ require 'tarantool/record'
4
+ require 'yajl'
5
+ require 'tarantool/serializers/bson'
6
+ describe Tarantool::Record do
7
+ include Helpers::Truncate
8
+
9
+ describe "primary key" do
10
+ def space
11
+ @space ||= DB.space 2
12
+ end
13
+
14
+ before do
15
+ @primary_key_size = 2
16
+ end
17
+
18
+ let(:address_class) do
19
+ Class.new(Tarantool::Record) do
20
+ set_tarantool DB
21
+ set_space_no 2
22
+
23
+ def self.name # For naming
24
+ "Adress"
25
+ end
26
+
27
+ field :city, :string
28
+ field :street, :string
29
+ field :index, :integer
30
+ field :name, :string
31
+ field :citizens, :integer, default: 1
32
+ index :city, :street, primary: true
33
+ index :index
34
+ end
35
+ end
36
+
37
+ describe "composite primary key" do
38
+
39
+ before do
40
+ address_class.create city: "Moscow", street: "Leningradskii", index: 123, name: "Pedro"
41
+ address_class.create city: "Moscow", street: "Mohovaya", index: 123, name: "Pedro"
42
+ end
43
+
44
+ it "should return objects by second index" do
45
+ a1 = address_class.where(index: 123)
46
+ a1.all.size.must_equal 2
47
+ end
48
+
49
+ it "should work with increment" do
50
+ a1 = address_class.where(city: "Moscow", street: "Leningradskii").first
51
+ citizens = a1.citizens
52
+ a1.increment :citizens
53
+ a1.reload.citizens.must_equal(citizens+1)
54
+ end
55
+
56
+ it "should return all objects" do
57
+ a1 = address_class.where city: "Moscow"
58
+ a1.all.size.must_equal 2
59
+ a1.all.map(&:street).must_equal ["Leningradskii", "Mohovaya"]
60
+ end
61
+
62
+ it "should return right object" do
63
+ a1 = address_class.where city: "Moscow", street: "Leningradskii"
64
+ a1.first.street.must_equal "Leningradskii"
65
+ end
66
+
67
+ it "should destroy object" do
68
+ a1 = address_class.where city: "Moscow", street: "Leningradskii"
69
+ a1.first.destroy
70
+ end
71
+
72
+ it "should return id" do
73
+ a1 = address_class.where city: "Moscow", street: "Leningradskii"
74
+ a1.first.id.must_equal ["Moscow", "Leningradskii"]
75
+ end
76
+
77
+ end
78
+ end
79
+ end
@@ -110,13 +110,13 @@ describe Tarantool::Record do
110
110
  u = user_class.create login: 'prepor', name: 'Andrew', email: 'ceo@prepor.ru', apples_count: nil
111
111
  u.info.must_be_nil
112
112
  u.apples_count.must_be_nil
113
- u = u.reload
113
+ u.reload
114
114
  u.info.must_be_nil
115
115
  u.apples_count.must_be_nil
116
116
  u.info = {'bio' => 'hi!'}
117
117
  u.apples_count = 1
118
118
  u.save
119
- u = u.reload
119
+ u.reload
120
120
  u.info.must_equal({ 'bio' => 'hi!' })
121
121
  u.apples_count.must_equal 1
122
122
  end
@@ -132,6 +132,7 @@ describe Tarantool::Record do
132
132
  end
133
133
 
134
134
  describe "increment" do
135
+ before { @truncate_fields = 2 }
135
136
  let(:user) { user_class.create login: 'prepor', name: 'Andrew', email: 'ceo@prepor.ru' }
136
137
  it "should increment apples count by 1" do
137
138
  user.increment :apples_count
@@ -148,7 +149,7 @@ describe Tarantool::Record do
148
149
  it "should destroy record" do
149
150
  u = user_class.create login: 'prepor', name: 'Andrew', email: 'ceo@prepor.ru'
150
151
  u.destroy
151
- u.reload.must_be_nil
152
+ u.reload.must_equal false
152
153
  end
153
154
  end
154
155
 
@@ -171,15 +172,42 @@ describe Tarantool::Record do
171
172
  end
172
173
 
173
174
  describe "callbacks" do
175
+ let(:u) { user_class.new login: 'prepor', name: 'Andrew', email: 'ceo@prepor.ru '}
174
176
  it "should run before / after create callbackss in right places" do
175
177
  user_class.before_create :action_before_create
176
- user_class.after_create :action_after_create
177
-
178
- u = user_class.new login: 'prepor', name: 'Andrew', email: 'ceo@prepor.ru'
178
+ user_class.after_create :action_after_create
179
179
  mock(u).action_before_create { u.new_record?.must_equal true }
180
180
  mock(u).action_after_create { u.new_record?.must_equal false }
181
181
  u.save
182
182
  end
183
+
184
+ describe "initialize" do
185
+ it "should run after_initialize after any initialization" do
186
+ user_class.after_initialize :action_after_initialize
187
+ any_instance_of(user_class) do |u|
188
+ mock(u).action_after_initialize.twice
189
+ end
190
+ u.save
191
+ user_class.find u.login
192
+ end
193
+
194
+ it "should not run after_initialize after reload" do
195
+ user_class.after_initialize :action_after_initialize
196
+ any_instance_of(user_class) do |u|
197
+ mock(u).action_after_initialize.once
198
+ end
199
+ u.save
200
+ u.reload
201
+ end
202
+
203
+ it "should properly save record inside after_initialize" do
204
+ user_class.after_initialize do |u|
205
+ u.save
206
+ end
207
+ u
208
+ user_class.find u.login
209
+ end
210
+ end
183
211
  end
184
212
 
185
213
  describe "serialization" do
@@ -198,7 +226,9 @@ describe Tarantool::Record do
198
226
  info = { 'bio' => "hi!", 'age' => 23, 'hobbies' => ['mufa', 'tuka'] }
199
227
  u = user_class.create login: 'prepor', name: 'Andrew', email: 'ceo@prepor.ru', info: info
200
228
  u.info['hobbies'].must_equal ['mufa', 'tuka']
201
- u = u.reload
229
+ u.reload
230
+ u.info['hobbies'].must_equal ['mufa', 'tuka']
231
+ u = user_class.find u.login
202
232
  u.info['hobbies'].must_equal ['mufa', 'tuka']
203
233
  end
204
234
  end
@@ -247,6 +277,27 @@ describe Tarantool::Record do
247
277
  end
248
278
  end
249
279
 
280
+ describe "==" do
281
+
282
+ before do
283
+ user_class.create login: 'prepor', name: 'Andrew', email: 'ceo@prepor.ru'
284
+ user_class.create login: 'petro', name: 'Petr', email: 'petro@gmail.com'
285
+ end
286
+
287
+ it "should return equality as true" do
288
+ u1 = user_class.where(login: "prepor").first
289
+ u2 = user_class.where(login: "prepor").first
290
+ (u1 == u2).must_equal true
291
+ end
292
+
293
+ it "should not return equality as true" do
294
+ u1 = user_class.where(login: "prepor")
295
+ u2 = user_class.where(login: "petro")
296
+ (u1 == u2).must_equal false
297
+ end
298
+ end
299
+
300
+
250
301
  describe "call" do
251
302
  let(:res) { user.class.select.call('box.select_range', 0, 0, 2)}
252
303
  before do
@@ -5,6 +5,7 @@ describe Tarantool::Request do
5
5
  def space
6
6
  @space ||= DB.space 1
7
7
  end
8
+
8
9
  describe "pack method" do
9
10
  describe "for field" do
10
11
  it "should pack integer as 32 bit integer" do
data/spec/tarantool.cfg CHANGED
@@ -11,13 +11,13 @@ rows_per_wal = 50
11
11
 
12
12
  space[0].enabled = 1
13
13
 
14
- space[0].index[0].type = "HASH"
14
+ space[0].index[0].type = "TREE"
15
15
  space[0].index[0].unique = 1
16
16
  space[0].index[0].key_field[0].fieldno = 0
17
17
  space[0].index[0].key_field[0].type = "STR"
18
18
 
19
19
  space[0].index[1].type = "TREE"
20
- space[0].index[1].unique = 1
20
+ space[0].index[1].unique = 0
21
21
  space[0].index[1].key_field[0].fieldno = 1
22
22
  space[0].index[1].key_field[0].type = "STR"
23
23
  space[0].index[1].key_field[1].fieldno = 2
@@ -29,4 +29,19 @@ space[1].enabled = 1
29
29
  space[1].index[0].type = "HASH"
30
30
  space[1].index[0].unique = 1
31
31
  space[1].index[0].key_field[0].fieldno = 0
32
- space[1].index[0].key_field[0].type = "NUM"
32
+ space[1].index[0].key_field[0].type = "NUM"
33
+
34
+
35
+ space[2].enabled = 1
36
+
37
+ space[2].index[0].type = "TREE"
38
+ space[2].index[0].unique = 1
39
+ space[2].index[0].key_field[0].fieldno = 0
40
+ space[2].index[0].key_field[0].type = "STR"
41
+ space[2].index[0].key_field[1].fieldno = 1
42
+ space[2].index[0].key_field[1].type = "STR"
43
+
44
+ space[2].index[1].type = "TREE"
45
+ space[2].index[1].unique = 0
46
+ space[2].index[1].key_field[0].fieldno = 2
47
+ space[2].index[1].key_field[0].type = "NUM"
data/tarantool.gemspec CHANGED
@@ -4,8 +4,8 @@ Gem::Specification.new do |s|
4
4
  s.rubygems_version = '1.3.5'
5
5
 
6
6
  s.name = 'tarantool'
7
- s.version = '0.2.4'
8
- s.date = '2012-05-06'
7
+ s.version = '0.2.5'
8
+ s.date = '2012-06-02'
9
9
  s.rubyforge_project = 'tarantool'
10
10
 
11
11
  s.summary = "Tarantool KV-storage client."
@@ -55,6 +55,7 @@ Gem::Specification.new do |s|
55
55
  spec/helpers/truncate.rb
56
56
  spec/spec_helper.rb
57
57
  spec/tarantool.cfg
58
+ spec/tarantool/composite_primary_key_spec.rb
58
59
  spec/tarantool/em_spec.rb
59
60
  spec/tarantool/record_spec.rb
60
61
  spec/tarantool/request_spec.rb
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tarantool
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.2.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-06 00:00:00.000000000Z
12
+ date: 2012-06-02 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: iproto
16
- requirement: &70109143146600 !ruby/object:Gem::Requirement
16
+ requirement: &70121541108760 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0.2'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70109143146600
24
+ version_requirements: *70121541108760
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: activemodel
27
- requirement: &70109143145940 !ruby/object:Gem::Requirement
27
+ requirement: &70121541107900 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -35,7 +35,7 @@ dependencies:
35
35
  version: '4.0'
36
36
  type: :runtime
37
37
  prerelease: false
38
- version_requirements: *70109143145940
38
+ version_requirements: *70121541107900
39
39
  description: Tarantool KV-storage client.
40
40
  email: ceo@prepor.ru
41
41
  executables: []
@@ -73,6 +73,7 @@ files:
73
73
  - spec/helpers/truncate.rb
74
74
  - spec/spec_helper.rb
75
75
  - spec/tarantool.cfg
76
+ - spec/tarantool/composite_primary_key_spec.rb
76
77
  - spec/tarantool/em_spec.rb
77
78
  - spec/tarantool/record_spec.rb
78
79
  - spec/tarantool/request_spec.rb
@@ -103,6 +104,7 @@ signing_key:
103
104
  specification_version: 2
104
105
  summary: Tarantool KV-storage client.
105
106
  test_files:
107
+ - spec/tarantool/composite_primary_key_spec.rb
106
108
  - spec/tarantool/em_spec.rb
107
109
  - spec/tarantool/record_spec.rb
108
110
  - spec/tarantool/request_spec.rb