ork 0.1.1 → 0.1.2

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.
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