tarantool 0.2.4 → 0.2.5

Sign up to get free protection for your applications and to get access to all the features.
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