ork 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 47e2643acef3adcb2aeac374845b5361247ba439
4
- data.tar.gz: 28fe5d544ea0c7fbb31d8630429a207d73cae3be
3
+ metadata.gz: 057b1b4f7eb4e0328a9998738e477947bacdacc3
4
+ data.tar.gz: d6522930cdaf1e25e16b19988be2901db7968e9b
5
5
  SHA512:
6
- metadata.gz: f25201cb3a85190b9f9b1fdcb07ea09b0c7aec3c820304547b90c3e66129e2fa6c15900d531493f817ad53c2f28af4b06630c9cb91b9102ba53c61dc7ccb2a1c
7
- data.tar.gz: 3beec74ee51de51612f07191eb1421dd5c558404048ad18e6d8e3d15a4560387efcc1dfc30f0bbd2240abcfa72d319a41a24c5d20f71060536af61ff0be2496d
6
+ metadata.gz: cbbc733bd2cc6dc9954827ed1d170fe2a27f95847e114bbaa000666a823be271e6a9ef018da6afb7d2e8c3f093364ad039d3f81ede44d3755adde4b1ab58adb2
7
+ data.tar.gz: e4ac8f95ace5511046f100a33f7005a56eb17cdeb3589d2d11174848067dfd23d697ae36671c13f3d0545f7f929ca90df99864c4c9671cfc45b2c0eed96e10ae
data/README.md CHANGED
@@ -172,11 +172,61 @@ Provides an accessor to the object that `embeds` the current model.
172
172
  embedded :post, :Post
173
173
  ```
174
174
 
175
+ ## Pagination
176
+
177
+ Pagination is a key feature introduced in _Riak 1.4_ and it is supported as well!
178
+
179
+ `Ork` will return the _enumerable_ `Ork::ResultSet` object which stores the keys and also the resulting objects.
180
+ The __keys__ are immediately loaded, but the __objects__ will be lazy loaded.
181
+
182
+ Given it uses the same API than `riak_client` let's jump into the examples.
183
+
184
+ ```ruby
185
+
186
+ resultset = Post.find(:age, 19, max_results: 3)
187
+ # => #<Ork::ResultSet:{:max_results=>3} ['object_key_1', 'object_key_2', 'object_key_3']>
188
+
189
+ resultset.keys
190
+ # => ['object_key_1', 'object_key_2', 'object_key_3']
191
+
192
+ resultset.all
193
+ # => [#<Post:1 ...>, #<Post:2 ...>, #<Post:3 ...>]
194
+
195
+ ##
196
+ # Advance to next page
197
+ ##
198
+
199
+ resultset.has_next_page?
200
+ # => true
201
+
202
+ next_resultset = resultset.next_page
203
+ # => #<Ork::ResultSet:{:max_results=>3, :continuation=>'a_continuation_string'}
204
+ # ['object_key_4', 'object_key_5']>
205
+
206
+ next_resultset.has_next_page?
207
+ # => false
208
+
209
+ next_resultset.next_page
210
+ # => raises Ork::NoNextPage: There is no next page
211
+
212
+ ##
213
+ # Skip pages and start from a continuation
214
+ ##
215
+
216
+ resultset2 = Post.find(:age, 19, max_results: 3, continuation: 'a_continuation_string')
217
+ # => #<Ork::ResultSet:{:max_results=>3, :continuation=>'a_continuation_string'}
218
+ # ['object_key_4', 'object_key_5']>
219
+
220
+ resultset2 == resultset.next_page
221
+ # => true
222
+
223
+ ```
224
+
175
225
  ## Validations
176
226
 
177
227
  As you can see, there is no reference to validations in this document and I'm aware of that!
178
228
  The validation logic for _nested embedded objects_ makes the code more complex than I want.
179
- Given that I want to keep this gem as simple as I can, I decided to avoid _object validation_ logic here and promote the use of other gems.
229
+ Given that I want to keep this gem as simple as I can, I decided to avoid _object validation_ logic here and promote the use of other gems.
180
230
 
181
231
  There are good implementations for object validation like [hatch](https://github.com/tonchis/hatch) or [scrivener](https://github.com/soveran/scrivener) which they do a great job!
182
232
  If you don't know them, you should take a look, but remember that you are free to use your prefered _gem_ or even your own method!
data/lib/ork/errors.rb CHANGED
@@ -5,4 +5,6 @@ module Ork
5
5
 
6
6
  class NotAnEmbeddableObject < RuntimeError; end
7
7
  class ParentMissing < RuntimeError; end
8
+
9
+ class NoNextPage < Error; end
8
10
  end
@@ -42,6 +42,13 @@ module Ork::Model
42
42
  # When the parameter is nil, it will return the content_type.
43
43
  # It also sets as default the standard content_type.
44
44
  #
45
+ # Example:
46
+ # class User
47
+ # include Ork:Document
48
+ #
49
+ # content_type 'text/plain'
50
+ # end
51
+ #
45
52
  def content_type(type = nil)
46
53
  @content_type = type unless type.nil?
47
54
  @content_type ||= 'application/json'
@@ -1,4 +1,4 @@
1
- require_relative 'model'
1
+ require_relative '../model'
2
2
 
3
3
  module Ork
4
4
  module Embeddable
@@ -1,3 +1,5 @@
1
+ require_relative '../result_set'
2
+
1
3
  module Ork::Model
2
4
  module Finders
3
5
 
@@ -20,17 +22,22 @@ module Ork::Model
20
22
  alias :exists? :exist?
21
23
 
22
24
  # Find all documents in the Document's bucket and return them.
23
- # @return [Array<Document>] all found documents in the bucket
25
+ # @return Ork::ResultSet<Document> all found documents in the bucket
24
26
  #
25
27
  # @Note: This operation is incredibly expensive and should not
26
28
  # be used in production applications.
27
29
  #
28
30
  def all
29
- load_robjects bucket.get_many(bucket.keys)
31
+ Ork::ResultSet.all(self)
30
32
  end
31
33
  alias :list :all
32
34
 
33
35
  # Find values in indexed fields.
36
+ # @return Ork::ResultSet<Document> found documents in the bucket
37
+ #
38
+ # options - Hash configs for pagination.
39
+ # :max_results - Number
40
+ # :continuation - String
34
41
  #
35
42
  # Example:
36
43
  #
@@ -42,20 +49,20 @@ module Ork::Model
42
49
  # end
43
50
  #
44
51
  # u = User.create(name: 'John')
45
- # User.find(name: 'John').include?(u)
52
+ # User.find(:name, 'John', max_results: 5).include?(u)
46
53
  # # => true
47
54
  #
48
- # User.find(name: 'Mike').include?(u)
55
+ # User.find(:name, 'Mike').include?(u)
49
56
  # # => false
50
57
  #
51
58
  # Note: If the key was not defined, an
52
59
  # `Ork::IndexNotFound` exception is raised.
53
60
  #
54
- def find(by_index, value)
61
+ def find(by_index, value, options = {})
55
62
  raise Ork::IndexNotFound unless indices.has_key? by_index
56
63
 
57
64
  index = indices[by_index]
58
- load_robjects bucket.get_many(bucket.get_index(index.riak_name, value))
65
+ Ork::ResultSet.new(self, index, value, options)
59
66
  end
60
67
 
61
68
  private
@@ -66,11 +73,5 @@ module Ork::Model
66
73
  raise e unless e.not_found?
67
74
  end
68
75
 
69
- def load_robjects(robjects)
70
- robjects.map do |id, robject|
71
- new.send(:__load_robject!, id, robject)
72
- end
73
- end
74
-
75
76
  end
76
77
  end
@@ -0,0 +1,79 @@
1
+ require 'forwardable'
2
+
3
+ module Ork
4
+ class ResultSet
5
+ extend Forwardable
6
+ include Enumerable
7
+
8
+ def_delegators :keys, :size, :count, :length, :empty?
9
+ def_delegators :all, :each, :first, :last
10
+
11
+ def initialize(model, index, query, options={})
12
+ @model, @index, @query, @options = model, index, query, options
13
+ @bucket = @model.bucket
14
+ end
15
+
16
+ # Find all documents in the Document's bucket and return them.
17
+ # @return Ork::ResultSet<Document> all the documents in the bucket
18
+ #
19
+ # @Note: This operation is incredibly expensive and should not
20
+ # be used in production applications.
21
+ #
22
+ def self.all(model)
23
+ new(model, nil, nil).tap do |r|
24
+ r.instance_variable_set(:@keys, model.bucket.keys)
25
+ end
26
+ end
27
+
28
+ # Pretty print for the ResultSet
29
+ # It uses keys when the objects are not present.
30
+ #
31
+ def inspect
32
+ string = "#<#{self.class}:#{@options} %s>"
33
+
34
+ string % (@all || self.keys).inspect
35
+ end
36
+
37
+ # Get the array of matched keys
38
+ #
39
+ def keys(&block)
40
+ @keys ||=
41
+ @bucket.client.backend do |b|
42
+ b.get_index @bucket, @index.riak_name, @query, @options, &block
43
+ end
44
+ end
45
+
46
+ # Get the array of objects
47
+ #
48
+ def all
49
+ return if self.keys.nil?
50
+ @all ||= load_robjects @bucket.get_many(@keys)
51
+ end
52
+
53
+ # Get a new ResultSet fetch for the next page
54
+ #
55
+ def next_page
56
+ raise Ork::NoNextPage.new 'There is no next page' unless has_next_page?
57
+
58
+ self.class.new(@model,
59
+ @index,
60
+ @query,
61
+ @options.merge(continuation: keys.continuation))
62
+ end
63
+
64
+ # Determine whether a SecondaryIndex fetch has a next page available
65
+ #
66
+ def has_next_page?
67
+ keys.respond_to?(:continuation) && !!keys.continuation
68
+ end
69
+
70
+ private
71
+
72
+ def load_robjects(robjects)
73
+ robjects.map do |id, robject|
74
+ @model.new.send(:__load_robject!, id, robject)
75
+ end
76
+ end
77
+
78
+ end
79
+ end
data/lib/ork.rb CHANGED
@@ -1,12 +1,13 @@
1
1
  require 'ork/connection'
2
2
  require 'ork/model'
3
3
  require 'ork/model/document'
4
- require 'ork/embedded'
4
+ require 'ork/model/embedded'
5
5
  require 'ork/utils'
6
6
  require 'ork/errors'
7
7
  require "riak"
8
8
 
9
9
  module Ork
10
+ VERSION = "0.1.2"
10
11
 
11
12
  def self.conn
12
13
  @conn ||= Ork::Connection.new
data/ork.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'ork'
3
- s.version = '0.1.1'
3
+ s.version = '0.1.2'
4
4
  s.date = Time.now.strftime('%Y-%m-%d')
5
5
  s.summary = 'Ruby modeling layer for Riak.'
6
6
  s.description = 'Ork is a small Ruby modeling layer for Riak, inspired by Ohm.'
@@ -19,6 +19,6 @@ Gem::Specification.new do |s|
19
19
 
20
20
  s.add_dependency 'riak-client'
21
21
  s.add_development_dependency 'protest'
22
- s.add_development_dependency 'toml-rb'
22
+ s.add_development_dependency 'mocha'
23
23
  end
24
24
 
@@ -0,0 +1,171 @@
1
+ require_relative 'helper'
2
+
3
+ Protest.describe 'ResultSet' do
4
+ class Post
5
+ include Ork::Document
6
+ attribute :name
7
+
8
+ index :name
9
+ end
10
+
11
+ setup do
12
+ randomize_bucket_name Post
13
+ @post1 = Post.create name: 'Post 1'
14
+ @post2 = Post.create name: 'Post 2'
15
+ end
16
+
17
+ context '*all*' do
18
+ setup do
19
+ @all = Ork::ResultSet.all(Post)
20
+ end
21
+
22
+ test 'index and query are nil' do
23
+ assert_equal nil, @all.instance_variable_get(:@index)
24
+ assert_equal nil, @all.instance_variable_get(:@query)
25
+ end
26
+
27
+ test 'model, bucket are not nil' do
28
+ assert_equal Post, @all.instance_variable_get(:@model)
29
+ assert_equal Post.bucket, @all.instance_variable_get(:@bucket)
30
+ end
31
+
32
+ test 'it has the keys set but not the loaded objects' do
33
+ key1, key2 = Post.bucket.keys
34
+ assert @all.instance_variable_get(:@keys).include? key1
35
+ assert @all.instance_variable_get(:@keys).include? key2
36
+ assert_equal nil, @all.instance_variable_get(:@all)
37
+ end
38
+
39
+ test 'it is not paginated' do
40
+ deny @all.has_next_page?
41
+ end
42
+
43
+ test 'it returns all the objects' do
44
+ assert_equal 2, @all.size
45
+ assert @all.include? @post1
46
+ assert @all.include? @post2
47
+ end
48
+ end
49
+
50
+ test 'it raises an exception when call next_page if does not have next page' do
51
+ resultset = Ork::ResultSet.all(Post)
52
+
53
+ deny resultset.has_next_page?
54
+ assert_raise Ork::NoNextPage do
55
+ resultset.next_page
56
+ end
57
+ end
58
+
59
+ context '*new*' do
60
+ setup do
61
+ @post3 = Post.create name: 'Post 1'
62
+
63
+ @index = Post.indices[:name]
64
+ @resultset = Ork::ResultSet.new(Post, @index, 'Post 1')
65
+ end
66
+
67
+ test 'the keys are not loaded' do
68
+ assert_equal nil, @resultset.instance_variable_get(:@keys)
69
+ assert_equal nil, @resultset.instance_variable_get(:@all)
70
+ end
71
+
72
+ test ':size, :count :length will not load the robjects' do
73
+ assert_equal 2, @resultset.size
74
+ assert_equal 2, @resultset.length
75
+ assert_equal 2, @resultset.count
76
+
77
+ assert @resultset.instance_variable_get(:@keys).include? @post1.id
78
+ assert @resultset.instance_variable_get(:@keys).include? @post3.id
79
+ assert_equal nil, @resultset.instance_variable_get(:@all)
80
+ end
81
+
82
+ test 'can be iterable and iterates over the objects' do
83
+ assert @resultset.respond_to?(:each)
84
+
85
+ @resultset.each{|post| assert_equal Post, post.class}
86
+ end
87
+
88
+ test 'it acts like an array' do
89
+ deny @resultset.empty?
90
+ assert_equal Post, @resultset.first.class
91
+ assert_equal Post, @resultset.last.class
92
+ assert @resultset.include? @post1
93
+ assert @resultset.include? @post3
94
+ end
95
+
96
+ test 'it shows the options and keys when objects are not loaded' do
97
+ @resultset = Ork::ResultSet.new(Post, @index, 'Post 2', max_results: 5)
98
+ expected = "#<Ork::ResultSet:{:max_results=>5} [\"#{@post2.id}\"]>"
99
+
100
+ assert_equal expected, @resultset.inspect
101
+ end
102
+
103
+ test 'it shows the options and objects when are loaded' do
104
+ @resultset = Ork::ResultSet.new(Post, @index, 'Post 2', max_results: 5)
105
+ expected = "#<Ork::ResultSet:{:max_results=>5} [#{@post2.inspect}]>"
106
+ @resultset.all
107
+
108
+ assert_equal expected, @resultset.inspect
109
+ end
110
+ end
111
+
112
+ context "*options*" do
113
+ setup do
114
+ @post3 = Post.create name: 'Post 1'
115
+ @index = Post.indices[:name]
116
+ end
117
+
118
+ context ':max_results' do
119
+ test 'it behaves like nil when its invalid' do
120
+ resultset = Ork::ResultSet.new(Post, @index, 'Post 1', max_results: -5)
121
+
122
+ assert_equal nil, resultset.keys
123
+ assert_equal nil, resultset.all
124
+ end
125
+
126
+ test 'it returns an empty array when did not find any object' do
127
+ resultset = Ork::ResultSet.new(Post, @index, 'Post 9', max_results: 5)
128
+
129
+ assert_equal [], resultset.keys
130
+ assert_equal [], resultset.all
131
+ end
132
+
133
+ test 'return no more than specified objects' do
134
+ resultset = Ork::ResultSet.new(Post, @index, 'Post 1', max_results: 1)
135
+
136
+ assert_equal 3, Post.all.size
137
+ assert_equal 1, resultset.size
138
+ assert resultset.has_next_page?
139
+ end
140
+
141
+ test 'fetch the next page and return a new resultset' do
142
+ post4 = Post.create name: 'Post 1'
143
+ resultset = Ork::ResultSet.new(Post, @index, 'Post 1', max_results: 2)
144
+ next_page = resultset.next_page
145
+
146
+ assert_equal 2, resultset.size
147
+ assert_equal 1, next_page.size
148
+ deny next_page.has_next_page?
149
+ end
150
+ end
151
+
152
+ context ':continuation' do
153
+ test 'it behaves like nil when its invalid' do
154
+ resultset = Ork::ResultSet.new(Post, @index, 'Post 1', continuation: 'not_a_continuation')
155
+
156
+ assert_equal nil, resultset.keys
157
+ assert_equal nil, resultset.all
158
+ end
159
+
160
+ test 'get a specific page' do
161
+ post4 = Post.create name: 'Post 1'
162
+ resultset = Ork::ResultSet.new(Post, @index, 'Post 1', max_results: 2)
163
+ continuation = resultset.keys.continuation
164
+
165
+ last_page = Ork::ResultSet.new(Post, @index, 'Post 1', continuation: continuation)
166
+
167
+ assert_equal resultset.next_page.keys, last_page.keys
168
+ end
169
+ end
170
+ end
171
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ork
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Emiliano Mancuso
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-11-09 00:00:00.000000000 Z
11
+ date: 2013-11-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: riak-client
@@ -39,7 +39,7 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: toml-rb
42
+ name: mocha
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - '>='
@@ -62,19 +62,20 @@ files:
62
62
  - README.md
63
63
  - rakefile
64
64
  - lib/ork/connection.rb
65
- - lib/ork/embedded.rb
66
65
  - lib/ork/errors.rb
67
66
  - lib/ork/model/associations.rb
68
67
  - lib/ork/model/class_methods.rb
69
68
  - lib/ork/model/document.rb
69
+ - lib/ork/model/embedded.rb
70
70
  - lib/ork/model/finders.rb
71
71
  - lib/ork/model/index.rb
72
72
  - lib/ork/model.rb
73
+ - lib/ork/result_set.rb
73
74
  - lib/ork/utils.rb
74
- - lib/ork/version.rb
75
75
  - lib/ork.rb
76
76
  - ork.gemspec
77
77
  - test/helper.rb
78
+ - test/result_set_test.rb
78
79
  homepage: http://github.com/emancu/ork
79
80
  licenses:
80
81
  - MIT
@@ -95,9 +96,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
95
96
  version: '0'
96
97
  requirements: []
97
98
  rubyforge_project:
98
- rubygems_version: 2.1.9
99
+ rubygems_version: 2.1.11
99
100
  signing_key:
100
101
  specification_version: 4
101
102
  summary: Ruby modeling layer for Riak.
102
103
  test_files:
103
104
  - test/helper.rb
105
+ - test/result_set_test.rb
data/lib/ork/version.rb DELETED
@@ -1,3 +0,0 @@
1
- class Ork
2
- VERSION = "0.0.1"
3
- end