brainstem 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.
- checksums.yaml +15 -0
- data/CHANGELOG.md +7 -0
- data/Gemfile.lock +41 -32
- data/README.md +136 -73
- data/brainstem.gemspec +1 -1
- data/lib/brainstem.rb +0 -2
- data/lib/brainstem/association_field.rb +6 -0
- data/lib/brainstem/controller_methods.rb +1 -1
- data/lib/brainstem/presenter.rb +12 -4
- data/lib/brainstem/presenter_collection.rb +26 -5
- data/lib/brainstem/test_helpers.rb +81 -0
- data/lib/brainstem/version.rb +1 -1
- data/spec/brainstem/controller_methods_spec.rb +21 -16
- data/spec/brainstem/presenter_collection_spec.rb +205 -172
- data/spec/brainstem/presenter_spec.rb +70 -47
- data/spec/brainstem_spec.rb +5 -5
- data/spec/spec_helpers/db.rb +2 -1
- metadata +13 -38
- data/pkg/brainstem-0.0.2.gem +0 -0
- data/pkg/brainstem-0.2.1.gem +0 -0
- data/pkg/brainstem-0.2.2.gem +0 -0
- data/pkg/brainstem-0.2.gem +0 -0
@@ -108,6 +108,9 @@ module Brainstem
|
|
108
108
|
|
109
109
|
rewrite_keys_as_objects!(struct)
|
110
110
|
|
111
|
+
# Make struct pretty-print when rendered as json, if required.
|
112
|
+
make_pretty_printable!(struct) if options[:params][:pretty] == "true"
|
113
|
+
|
111
114
|
struct
|
112
115
|
end
|
113
116
|
|
@@ -215,9 +218,9 @@ module Brainstem
|
|
215
218
|
filter_lambda = options[:presenter].filters[filter_name][1]
|
216
219
|
|
217
220
|
if filter_lambda
|
218
|
-
scope = filter_lambda.call(scope,
|
221
|
+
scope = filter_lambda.call(scope, arg)
|
219
222
|
else
|
220
|
-
scope = scope.send(filter_name,
|
223
|
+
scope = scope.send(filter_name, arg)
|
221
224
|
end
|
222
225
|
end
|
223
226
|
|
@@ -230,7 +233,7 @@ module Brainstem
|
|
230
233
|
|
231
234
|
(options[:presenter].filters || {}).each do |filter_name, filter|
|
232
235
|
requested = options[:params][filter_name]
|
233
|
-
requested = requested.present? ? requested.to_s : nil
|
236
|
+
requested = requested.is_a?(Array) ? requested : (requested.present? ? requested.to_s : nil)
|
234
237
|
requested = requested == "true" ? true : (requested == "false" ? false : requested)
|
235
238
|
|
236
239
|
filter_options = filter[0]
|
@@ -326,11 +329,11 @@ module Brainstem
|
|
326
329
|
records.tap do |models|
|
327
330
|
association_names_to_preload = includes_hash.values.map {|i| i.method_name }
|
328
331
|
if models.first
|
329
|
-
reflections = models.first.reflections
|
332
|
+
reflections = models.first.class.reflections
|
330
333
|
association_names_to_preload.reject! { |association| !reflections.has_key?(association) }
|
331
334
|
end
|
332
335
|
if association_names_to_preload.any?
|
333
|
-
|
336
|
+
preload(models, association_names_to_preload)
|
334
337
|
Brainstem.logger.info "Eager loaded #{association_names_to_preload.join(", ")}."
|
335
338
|
end
|
336
339
|
end
|
@@ -371,5 +374,23 @@ module Brainstem
|
|
371
374
|
struct[key] = struct[key].inject({}) {|memo, obj| memo[obj[:id] || obj["id"] || "unknown_id"] = obj; memo }
|
372
375
|
end
|
373
376
|
end
|
377
|
+
|
378
|
+
def preload(models, association_names)
|
379
|
+
if Gem.loaded_specs['activerecord'].version >= Gem::Version.create('4.1')
|
380
|
+
ActiveRecord::Associations::Preloader.new.preload(models, association_names)
|
381
|
+
else
|
382
|
+
ActiveRecord::Associations::Preloader.new(models, association_names).run
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
# Modify a hash so that it is pretty-printed when rendered as JSON. Works
|
387
|
+
# by adding a `to_json` singleton method which is called during rendering.
|
388
|
+
# Uses a copy of the hash to avoid recursion issues.
|
389
|
+
def make_pretty_printable!(struct)
|
390
|
+
struct.define_singleton_method(:to_json) do |options = nil|
|
391
|
+
copy = self.deep_dup
|
392
|
+
JSON.pretty_generate(copy)
|
393
|
+
end
|
394
|
+
end
|
374
395
|
end
|
375
396
|
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Brainstem
|
2
|
+
# Helpers for easing the testing of brainstem responses in controller specs
|
3
|
+
#
|
4
|
+
# To use, add the following to you spec_helper file:
|
5
|
+
#
|
6
|
+
# require 'brainstem/test_helpers'
|
7
|
+
# Rspec.configure { |config| config.include Brainstem::TestHelpers, :type => :controller }
|
8
|
+
#
|
9
|
+
module TestHelpers
|
10
|
+
# Use brainstem_data in your controller specs to easily access
|
11
|
+
# Brainstem JSON data payloads and their attributes
|
12
|
+
#
|
13
|
+
# Examples:
|
14
|
+
#
|
15
|
+
# Assume user is the model and name is an attribute
|
16
|
+
#
|
17
|
+
# Selecting an item from a collection by it's id
|
18
|
+
# expect(brainstem_data.users.by_id(235).name).to eq('name')
|
19
|
+
#
|
20
|
+
# Getting an array of all ids of in a collection without map
|
21
|
+
# expect(brainstem_data.users.ids).to include(1)
|
22
|
+
#
|
23
|
+
# Accessing the keys of a collection
|
24
|
+
# expect(brainstem_data.users.first.keys).to =~ %w(id name email address)
|
25
|
+
#
|
26
|
+
# Using standard array methods on a collection
|
27
|
+
# expect(brainstem_data.users.first.name).to eq('name')
|
28
|
+
# expect(brainstem_data.users[2].name).to eq('name')
|
29
|
+
#
|
30
|
+
def brainstem_data
|
31
|
+
BrainstemDataHelper.new(response.body)
|
32
|
+
end
|
33
|
+
|
34
|
+
class BrainstemDataHelper
|
35
|
+
def initialize(response_body)
|
36
|
+
@json = JSON.parse(response_body)
|
37
|
+
end
|
38
|
+
|
39
|
+
def method_missing(name)
|
40
|
+
data = @json[name.to_s].try(:values)
|
41
|
+
BrainstemHelperCollection.new(data) unless data.nil?
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
class BrainstemHelperCollection < Array
|
47
|
+
def initialize(collection)
|
48
|
+
collection.each do |item|
|
49
|
+
self << BrainstemHelperItem.new(item)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def ids
|
54
|
+
map { |item| item.id.to_i }
|
55
|
+
end
|
56
|
+
|
57
|
+
def by_id(id)
|
58
|
+
detect { |item| item.id == id.to_s }
|
59
|
+
end
|
60
|
+
|
61
|
+
def method_missing(name)
|
62
|
+
map { |item| item.send(name.to_s.singularize) }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class BrainstemHelperItem
|
67
|
+
def initialize(data)
|
68
|
+
@data = data
|
69
|
+
end
|
70
|
+
|
71
|
+
def keys
|
72
|
+
@data.keys
|
73
|
+
end
|
74
|
+
|
75
|
+
def method_missing(name)
|
76
|
+
@data[name.to_s]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/lib/brainstem/version.rb
CHANGED
@@ -33,48 +33,53 @@ describe Brainstem::ControllerMethods do
|
|
33
33
|
|
34
34
|
it "works with arrays of ActiveRecord objects" do
|
35
35
|
@controller.present_object([Workspace.find(1), Workspace.find(3)])
|
36
|
-
@controller.call_results[:klass].
|
37
|
-
@controller.call_results[:options][:as].
|
38
|
-
@controller.call_results[:block_result].pluck(:id).
|
36
|
+
expect(@controller.call_results[:klass]).to eq(Workspace)
|
37
|
+
expect(@controller.call_results[:options][:as]).to eq("workspaces")
|
38
|
+
expect(@controller.call_results[:block_result].pluck(:id)).to eq([1, 3])
|
39
39
|
end
|
40
40
|
|
41
41
|
it "works with a Relation" do
|
42
42
|
@controller.present_object(Workspace.owned_by(1))
|
43
|
-
@controller.call_results[:klass].
|
44
|
-
@controller.call_results[:options][:as].
|
45
|
-
@controller.call_results[:block_result].pluck(:id).
|
43
|
+
expect(@controller.call_results[:klass]).to eq(Workspace)
|
44
|
+
expect(@controller.call_results[:options][:as]).to eq("workspaces")
|
45
|
+
expect(@controller.call_results[:block_result].pluck(:id)).to eq([1, 2, 3, 4])
|
46
46
|
end
|
47
47
|
|
48
48
|
it "works with singleton objects" do
|
49
49
|
@controller.present_object(Workspace.find(1))
|
50
|
-
@controller.call_results[:klass].
|
51
|
-
@controller.call_results[:options][:as].
|
52
|
-
@controller.call_results[:block_result].pluck(:id).
|
50
|
+
expect(@controller.call_results[:klass]).to eq(Workspace)
|
51
|
+
expect(@controller.call_results[:options][:as]).to eq("workspaces")
|
52
|
+
expect(@controller.call_results[:block_result].pluck(:id)).to eq([1])
|
53
53
|
end
|
54
54
|
|
55
55
|
it "accepts a key map" do
|
56
56
|
@controller.present_object(Workspace.find(1), :key_map => { "Workspace" => "your_workspaces" })
|
57
|
-
@controller.call_results[:klass].
|
58
|
-
@controller.call_results[:options][:as].
|
59
|
-
@controller.call_results[:block_result].pluck(:id).
|
57
|
+
expect(@controller.call_results[:klass]).to eq(Workspace)
|
58
|
+
expect(@controller.call_results[:options][:as]).to eq("your_workspaces")
|
59
|
+
expect(@controller.call_results[:block_result].pluck(:id)).to eq([1])
|
60
60
|
end
|
61
61
|
|
62
62
|
it "passes through the controller params" do
|
63
63
|
@controller.present_object(Workspace.find(1), :key_map => { "Workspace" => "your_workspaces" })
|
64
|
-
@controller.call_results[:options][:params].
|
64
|
+
expect(@controller.call_results[:options][:params]).to eq(@controller.params.merge(:only => '1'))
|
65
65
|
end
|
66
66
|
|
67
67
|
it "passes through supplied options" do
|
68
68
|
@controller.present_object(Workspace.find(1), :foo => :bar)
|
69
|
-
@controller.call_results[:options][:foo].
|
69
|
+
expect(@controller.call_results[:options][:foo]).to eq(:bar)
|
70
70
|
end
|
71
71
|
|
72
72
|
it "adds an only param if there is only one object to present" do
|
73
73
|
@controller.present_object(Workspace.find(1))
|
74
|
-
@controller.call_results[:options][:params][:only].
|
74
|
+
expect(@controller.call_results[:options][:params][:only]).to eq("1")
|
75
75
|
|
76
76
|
@controller.present_object(Workspace.all)
|
77
|
-
@controller.call_results[:options][:params][:only].
|
77
|
+
expect(@controller.call_results[:options][:params][:only]).to be_nil
|
78
|
+
end
|
79
|
+
|
80
|
+
it "passes :apply_default_filters => false to the PresenterCollection so that filters are not applied by default" do
|
81
|
+
@controller.present_object(Workspace.find(1))
|
82
|
+
expect(@controller.call_results[:options][:apply_default_filters]).to eq(false)
|
78
83
|
end
|
79
84
|
end
|
80
85
|
end
|
@@ -22,81 +22,81 @@ describe Brainstem::PresenterCollection do
|
|
22
22
|
end
|
23
23
|
|
24
24
|
it "has a global per_page default" do
|
25
|
-
@presenter_collection.presenting("workspaces") { Workspace.order('id desc') }[:workspaces].length.
|
25
|
+
expect(@presenter_collection.presenting("workspaces") { Workspace.order('id desc') }[:workspaces].length).to eq(2)
|
26
26
|
end
|
27
27
|
|
28
28
|
it "will not accept a per_page less than 1" do
|
29
|
-
@presenter_collection.presenting("workspaces", :params => { :per_page => 0 }) { Workspace.order('id desc') }[:workspaces].length.
|
30
|
-
@presenter_collection.presenting("workspaces", :per_page => 0) { Workspace.order('id desc') }[:workspaces].length.
|
29
|
+
expect(@presenter_collection.presenting("workspaces", :params => { :per_page => 0 }) { Workspace.order('id desc') }[:workspaces].length).to eq(2)
|
30
|
+
expect(@presenter_collection.presenting("workspaces", :per_page => 0) { Workspace.order('id desc') }[:workspaces].length).to eq(2)
|
31
31
|
end
|
32
32
|
|
33
33
|
it "will accept strings" do
|
34
34
|
struct = @presenter_collection.presenting("workspaces", :params => { :per_page => "1", :page => "2" }) { Workspace.order('id desc') }
|
35
|
-
struct[:results].first[:id].
|
35
|
+
expect(struct[:results].first[:id]).to eq(Workspace.order('id desc')[1].id.to_s)
|
36
36
|
end
|
37
37
|
|
38
38
|
it "has a global max_per_page default" do
|
39
|
-
@presenter_collection.presenting("workspaces", :params => { :per_page => 5 }) { Workspace.order('id desc') }[:workspaces].length.
|
39
|
+
expect(@presenter_collection.presenting("workspaces", :params => { :per_page => 5 }) { Workspace.order('id desc') }[:workspaces].length).to eq(3)
|
40
40
|
end
|
41
41
|
|
42
42
|
it "takes a configurable default page size and max page size" do
|
43
|
-
@presenter_collection.presenting("workspaces", :params => { :per_page => 5 }, :max_per_page => 4) { Workspace.order('id desc') }[:workspaces].length.
|
43
|
+
expect(@presenter_collection.presenting("workspaces", :params => { :per_page => 5 }, :max_per_page => 4) { Workspace.order('id desc') }[:workspaces].length).to eq(4)
|
44
44
|
end
|
45
45
|
|
46
46
|
describe "limits and offsets" do
|
47
47
|
context "when only per_page and page are present" do
|
48
48
|
it "honors the user's requested page size and page and returns counts" do
|
49
49
|
result = @presenter_collection.presenting("workspaces", :params => { :per_page => 1, :page => 2 }) { Workspace.order('id desc') }[:results]
|
50
|
-
result.length.
|
51
|
-
result.first[:id].
|
50
|
+
expect(result.length).to eq(1)
|
51
|
+
expect(result.first[:id]).to eq(Workspace.order('id desc')[1].id.to_s)
|
52
52
|
|
53
53
|
result = @presenter_collection.presenting("workspaces", :params => { :per_page => 2, :page => 2 }) { Workspace.order('id desc') }[:results]
|
54
|
-
result.length.
|
55
|
-
result.map { |m| m[:id] }.
|
54
|
+
expect(result.length).to eq(2)
|
55
|
+
expect(result.map { |m| m[:id] }).to eq(Workspace.order('id desc')[2..3].map(&:id).map(&:to_s))
|
56
56
|
end
|
57
57
|
|
58
58
|
it "defaults to 1 if the page number is less than 1" do
|
59
59
|
result = @presenter_collection.presenting("workspaces", :params => { :per_page => 1, :page => 0 }) { Workspace.order('id desc') }[:results]
|
60
|
-
result.length.
|
61
|
-
result.first[:id].
|
60
|
+
expect(result.length).to eq(1)
|
61
|
+
expect(result.first[:id]).to eq(Workspace.order('id desc')[0].id.to_s)
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
65
|
context "when only limit and offset are present" do
|
66
66
|
it "honors the user's requested limit and offset and returns counts" do
|
67
67
|
result = @presenter_collection.presenting("workspaces", :params => { :limit => 1, :offset => 2 }) { Workspace.order('id desc') }[:results]
|
68
|
-
result.length.
|
69
|
-
result.first[:id].
|
68
|
+
expect(result.length).to eq(1)
|
69
|
+
expect(result.first[:id]).to eq(Workspace.order('id desc')[2].id.to_s)
|
70
70
|
|
71
71
|
result = @presenter_collection.presenting("workspaces", :params => { :limit => 2, :offset => 2 }) { Workspace.order('id desc') }[:results]
|
72
|
-
result.length.
|
73
|
-
result.map { |m| m[:id] }.
|
72
|
+
expect(result.length).to eq(2)
|
73
|
+
expect(result.map { |m| m[:id] }).to eq(Workspace.order('id desc')[2..3].map(&:id).map(&:to_s))
|
74
74
|
end
|
75
75
|
|
76
76
|
it "defaults to offset 0 if the passed offset is less than 0 and limit to 1 if the passed limit is less than 1" do
|
77
77
|
stub.proxy(@presenter_collection).calculate_offset(anything).times(1)
|
78
78
|
stub.proxy(@presenter_collection).calculate_limit(anything).times(1)
|
79
79
|
result = @presenter_collection.presenting("workspaces", :params => { :limit => -1, :offset => -1 }) { Workspace.order('id desc') }[:results]
|
80
|
-
result.length.
|
81
|
-
result.first[:id].
|
80
|
+
expect(result.length).to eq(1)
|
81
|
+
expect(result.first[:id]).to eq(Workspace.order('id desc')[0].id.to_s)
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
85
85
|
context "when both sets of params are present" do
|
86
86
|
it "prefers limit and offset over per_page and page" do
|
87
87
|
result = @presenter_collection.presenting("workspaces", :params => { :limit => 1, :offset => 0, :per_page => 2, :page => 2 }) { Workspace.order('id desc') }[:results]
|
88
|
-
result.length.
|
89
|
-
result.first[:id].
|
88
|
+
expect(result.length).to eq(1)
|
89
|
+
expect(result.first[:id]).to eq(Workspace.order('id desc')[0].id.to_s)
|
90
90
|
end
|
91
91
|
|
92
92
|
it "uses per_page and page if limit and offset are not complete" do
|
93
93
|
result = @presenter_collection.presenting("workspaces", :params => { :limit => 5, :per_page => 1, :page => 0 }) { Workspace.order('id desc') }[:results]
|
94
|
-
result.length.
|
95
|
-
result.first[:id].
|
94
|
+
expect(result.length).to eq(1)
|
95
|
+
expect(result.first[:id]).to eq(Workspace.order('id desc')[0].id.to_s)
|
96
96
|
|
97
97
|
result = @presenter_collection.presenting("workspaces", :params => { :offset => 5, :per_page => 1, :page => 0 }) { Workspace.order('id desc') }[:results]
|
98
|
-
result.length.
|
99
|
-
result.first[:id].
|
98
|
+
expect(result.length).to eq(1)
|
99
|
+
expect(result.first[:id]).to eq(Workspace.order('id desc')[0].id.to_s)
|
100
100
|
end
|
101
101
|
end
|
102
102
|
end
|
@@ -107,34 +107,34 @@ describe Brainstem::PresenterCollection do
|
|
107
107
|
it "should raise the provided error class when the empty_error_class option is provided" do
|
108
108
|
class MyException < Exception; end
|
109
109
|
|
110
|
-
|
110
|
+
expect {
|
111
111
|
@presenter_collection.presenting("workspaces", :raise_on_empty => true, :empty_error_class => MyException) { Workspace.where(:id => nil) }
|
112
|
-
}.
|
112
|
+
}.to raise_error(MyException)
|
113
113
|
end
|
114
114
|
|
115
115
|
it "should raise ActiveRecord::RecordNotFound when the empty_error_class option is not provided" do
|
116
|
-
|
116
|
+
expect {
|
117
117
|
@presenter_collection.presenting("workspaces", :raise_on_empty => true) { Workspace.where(:id => nil) }
|
118
|
-
}.
|
118
|
+
}.to raise_error(ActiveRecord::RecordNotFound)
|
119
119
|
end
|
120
120
|
end
|
121
121
|
|
122
122
|
context "results are not empty" do
|
123
123
|
it "should not raise an exception" do
|
124
|
-
Workspace.count.
|
124
|
+
expect(Workspace.count).to be > 0
|
125
125
|
|
126
|
-
|
126
|
+
expect {
|
127
127
|
@presenter_collection.presenting("workspaces", :raise_on_empty => true) { Workspace.order('id desc') }
|
128
|
-
}.
|
128
|
+
}.not_to raise_error
|
129
129
|
end
|
130
130
|
end
|
131
131
|
end
|
132
132
|
|
133
133
|
context "raise_on_empty is false" do
|
134
134
|
it "should not raise an exception when the results are empty" do
|
135
|
-
|
135
|
+
expect {
|
136
136
|
@presenter_collection.presenting("workspaces") { Workspace.where(:id => nil) }
|
137
|
-
}.
|
137
|
+
}.not_to raise_error
|
138
138
|
end
|
139
139
|
end
|
140
140
|
end
|
@@ -147,7 +147,7 @@ describe Brainstem::PresenterCollection do
|
|
147
147
|
|
148
148
|
it "returns the unique count by model id" do
|
149
149
|
result = @presenter_collection.presenting("workspaces", :params => { :per_page => 2, :page => 1 }) { Workspace.order('id desc') }
|
150
|
-
result[:count].
|
150
|
+
expect(result[:count]).to eq(Workspace.count)
|
151
151
|
end
|
152
152
|
end
|
153
153
|
end
|
@@ -155,157 +155,157 @@ describe Brainstem::PresenterCollection do
|
|
155
155
|
describe "uses presenters" do
|
156
156
|
it "finds presenter by table name string" do
|
157
157
|
result = @presenter_collection.presenting("workspaces") { Workspace.order('id desc') }
|
158
|
-
result[:workspaces].length.
|
158
|
+
expect(result[:workspaces].length).to eq(Workspace.count)
|
159
159
|
end
|
160
160
|
|
161
161
|
it "finds presenter by model name string" do
|
162
162
|
result = @presenter_collection.presenting("Workspace") { order('id desc') }
|
163
|
-
result[:workspaces].length.
|
163
|
+
expect(result[:workspaces].length).to eq(Workspace.count)
|
164
164
|
end
|
165
165
|
|
166
166
|
it "finds presenter by model" do
|
167
167
|
result = @presenter_collection.presenting(Workspace) { order('id desc') }
|
168
|
-
result[:workspaces].length.
|
168
|
+
expect(result[:workspaces].length).to eq(Workspace.count)
|
169
169
|
end
|
170
170
|
|
171
171
|
it "infers the table name from the model" do
|
172
172
|
result = @presenter_collection.presenting("not_workspaces", :model => "Workspace", :params => { :per_page => 2, :page => 1 }) { Workspace.order('id desc') }
|
173
|
-
result[:not_workspaces].
|
174
|
-
result[:count].
|
173
|
+
expect(result[:not_workspaces]).not_to be_empty
|
174
|
+
expect(result[:count]).to eq(Workspace.count)
|
175
175
|
end
|
176
176
|
end
|
177
177
|
|
178
178
|
describe "the 'results' top level key" do
|
179
179
|
it "comes back with an explicit list of the matching results" do
|
180
180
|
structure = @presenter_collection.presenting("workspaces", :params => { :include => "tasks" }, :max_per_page => 2) { Workspace.where(:id => 1) }
|
181
|
-
structure.keys.
|
182
|
-
structure[:results].
|
183
|
-
structure[:workspaces].keys.
|
181
|
+
expect(structure.keys).to match_array([:workspaces, :tasks, :count, :results])
|
182
|
+
expect(structure[:results]).to eq(Workspace.where(:id => 1).limit(2).map {|w| { :key => "workspaces", :id => w.id.to_s } })
|
183
|
+
expect(structure[:workspaces].keys).to eq(%w[1])
|
184
184
|
end
|
185
185
|
end
|
186
186
|
|
187
187
|
describe "includes" do
|
188
188
|
it "reads allowed includes from the presenter" do
|
189
189
|
result = @presenter_collection.presenting("workspaces", :params => { :include => "drop table,tasks,users" }) { Workspace.order('id desc') }
|
190
|
-
result.keys.
|
190
|
+
expect(result.keys).to match_array([:count, :workspaces, :tasks, :results])
|
191
191
|
|
192
192
|
result = @presenter_collection.presenting("workspaces", :params => { :include => "foo,tasks,lead_user" }) { Workspace.order('id desc') }
|
193
|
-
result.keys.
|
193
|
+
expect(result.keys).to match_array([:count, :workspaces, :tasks, :users, :results])
|
194
194
|
end
|
195
195
|
|
196
196
|
it "allows the allowed includes list to have different json names and association names" do
|
197
197
|
result = @presenter_collection.presenting("tasks",
|
198
198
|
:params => { :include => "other_tasks" }) { Task.order('id desc') }
|
199
|
-
result[:tasks].
|
200
|
-
result[:other_tasks].
|
199
|
+
expect(result[:tasks]).to be_present
|
200
|
+
expect(result[:other_tasks]).to be_present
|
201
201
|
end
|
202
202
|
|
203
203
|
it "defaults to not include any allowed includes" do
|
204
204
|
tasked_workspace = Task.first
|
205
205
|
result = @presenter_collection.presenting("workspaces", :max_per_page => 2) { Workspace.where(:id => tasked_workspace.workspace_id) }
|
206
|
-
result[:workspaces].keys.
|
207
|
-
result[:tasks].
|
206
|
+
expect(result[:workspaces].keys).to eq([ tasked_workspace.workspace_id.to_s ])
|
207
|
+
expect(result[:tasks]).to be_nil
|
208
208
|
end
|
209
209
|
|
210
210
|
it "loads has_many associations and returns them when requested" do
|
211
211
|
result = @presenter_collection.presenting("workspaces", :params => { :include => "tasks" }, :max_per_page => 2) { Workspace.where(:id => 1) }
|
212
|
-
result[:tasks].keys.
|
213
|
-
result[:workspaces]["1"][:task_ids].
|
212
|
+
expect(result[:tasks].keys).to match_array(Workspace.first.tasks.map(&:id).map(&:to_s))
|
213
|
+
expect(result[:workspaces]["1"][:task_ids]).to match_array(Workspace.first.tasks.map(&:id).map(&:to_s))
|
214
214
|
end
|
215
215
|
|
216
216
|
it "returns appropriate fields" do
|
217
217
|
result = @presenter_collection.presenting("workspaces",
|
218
218
|
:params => { :include => "tasks" },
|
219
219
|
:max_per_page => 2) { Workspace.where(:id => 1) }
|
220
|
-
result[:workspaces].values.first.
|
221
|
-
result[:tasks].values.first.
|
220
|
+
expect(result[:workspaces].values.first).to have_key(:description)
|
221
|
+
expect(result[:tasks].values.first).to have_key(:name)
|
222
222
|
end
|
223
223
|
|
224
224
|
it "loads belongs_tos and returns them when requested" do
|
225
225
|
result = @presenter_collection.presenting("tasks", :params => { :include => "workspace" }, :max_per_page => 2) { Task.where(:id => 1) }
|
226
|
-
result[:workspaces].keys.
|
226
|
+
expect(result[:workspaces].keys).to eq(%w[1])
|
227
227
|
end
|
228
228
|
|
229
229
|
it "doesn't return nils when belong_tos are missing" do
|
230
230
|
t = Task.first
|
231
231
|
t.update_attribute :workspace, nil
|
232
|
-
t.reload.workspace.
|
232
|
+
expect(t.reload.workspace).to be_nil
|
233
233
|
result = @presenter_collection.presenting("tasks", :params => { :include => "workspace" }, :max_per_page => 2) { Task.where(:id => t.id) }
|
234
|
-
result[:tasks].keys.
|
235
|
-
result[:workspaces].
|
236
|
-
result.keys.
|
234
|
+
expect(result[:tasks].keys).to eq([ t.id.to_s ])
|
235
|
+
expect(result[:workspaces]).to eq({})
|
236
|
+
expect(result.keys).to match_array([:tasks, :workspaces, :count, :results])
|
237
237
|
end
|
238
238
|
|
239
239
|
it "returns sensible data when including something of the same type as the primary model" do
|
240
240
|
result = @presenter_collection.presenting("tasks", :params => { :include => "sub_tasks" }) { Task.where(:id => 2) }
|
241
241
|
sub_task_ids = Task.find(2).sub_tasks.map(&:id).map(&:to_s)
|
242
|
-
result[:tasks].keys.
|
243
|
-
result[:tasks]["2"][:sub_task_ids].
|
244
|
-
result[:tasks][sub_task_ids.first][:sub_task_ids].
|
242
|
+
expect(result[:tasks].keys).to match_array(sub_task_ids + ["2"])
|
243
|
+
expect(result[:tasks]["2"][:sub_task_ids]).to eq(sub_task_ids) # The primary should have a sub_story_ids array.
|
244
|
+
expect(result[:tasks][sub_task_ids.first][:sub_task_ids]).not_to be_present # Sub stories should not have a sub_story_ids array.
|
245
245
|
end
|
246
246
|
|
247
247
|
it "includes requested includes even when all records are filtered" do
|
248
248
|
result = @presenter_collection.presenting("workspaces", :params => { :only => "not an id", :include => "not an include,tasks" }) { Workspace.order("id desc") }
|
249
|
-
result[:workspaces].length.
|
250
|
-
result[:tasks].length.
|
249
|
+
expect(result[:workspaces].length).to eq(0)
|
250
|
+
expect(result[:tasks].length).to eq(0)
|
251
251
|
end
|
252
252
|
|
253
253
|
it "includes requested includes even when the scope has no records" do
|
254
|
-
Workspace.where(:id => 123456789).
|
254
|
+
expect(Workspace.where(:id => 123456789)).to be_empty
|
255
255
|
result = @presenter_collection.presenting("workspaces", :params => { :include => "not an include,tasks" }) { Workspace.where(:id => 123456789) }
|
256
|
-
result[:workspaces].length.
|
257
|
-
result[:tasks].length.
|
256
|
+
expect(result[:workspaces].length).to eq(0)
|
257
|
+
expect(result[:tasks].length).to eq(0)
|
258
258
|
end
|
259
259
|
|
260
260
|
it "preloads associations when they are full model-level associations" do
|
261
261
|
# Here, primary_maven is a method on Workspace, not a true association.
|
262
|
-
mock(
|
262
|
+
mock(@presenter_collection).preload(anything, [:tasks])
|
263
263
|
result = @presenter_collection.presenting("workspaces", :params => { :include => "tasks" }) { Workspace.order('id desc') }
|
264
|
-
result[:tasks].length.
|
264
|
+
expect(result[:tasks].length).to be > 0
|
265
265
|
end
|
266
266
|
|
267
267
|
it "works with model methods that load records (but without preloading)" do
|
268
268
|
result = @presenter_collection.presenting("workspaces", :params => { :include => "lead_user" }) { Workspace.order('id desc') }
|
269
|
-
result[:workspaces][Workspace.first.id.to_s].
|
270
|
-
result[:users][Workspace.first.lead_user.id.to_s].
|
269
|
+
expect(result[:workspaces][Workspace.first.id.to_s]).to be_present
|
270
|
+
expect(result[:users][Workspace.first.lead_user.id.to_s]).to be_present
|
271
271
|
end
|
272
272
|
|
273
273
|
it "can accept a lambda for the association and uses that when present" do
|
274
274
|
result = @presenter_collection.presenting("users", :params => { :include => "odd_workspaces" }) { User.where(:id => 1) }
|
275
|
-
result[:odd_workspaces][Workspace.first.id.to_s].
|
276
|
-
result[:users][Workspace.first.lead_user.id.to_s].
|
275
|
+
expect(result[:odd_workspaces][Workspace.first.id.to_s]).to be_present
|
276
|
+
expect(result[:users][Workspace.first.lead_user.id.to_s]).to be_present
|
277
277
|
end
|
278
278
|
|
279
279
|
describe "restricted associations" do
|
280
280
|
it "does apply includes that are restricted to only queries in an only query" do
|
281
281
|
t = Task.first
|
282
282
|
result = @presenter_collection.presenting("tasks", :params => { :include => "restricted", :only => t.id.to_s }, :max_per_page => 2) { Task.where(:id => t.id) }
|
283
|
-
result[:tasks][t.id.to_s].keys.
|
284
|
-
result.keys.
|
283
|
+
expect(result[:tasks][t.id.to_s].keys).to include(:restricted_id)
|
284
|
+
expect(result.keys).to include(:restricted_associations)
|
285
285
|
end
|
286
286
|
|
287
287
|
it "does not apply includes that are restricted to only queries in a non-only query" do
|
288
288
|
t = Task.first
|
289
289
|
result = @presenter_collection.presenting("tasks", :params => { :include => "restricted" }, :max_per_page => 2) { Task.where(:id => t.id) }
|
290
290
|
|
291
|
-
result[:tasks][t.id.to_s].keys.
|
292
|
-
result.keys.
|
291
|
+
expect(result[:tasks][t.id.to_s].keys).not_to include(:restricted_id)
|
292
|
+
expect(result.keys).not_to include(:restricted_associations)
|
293
293
|
end
|
294
294
|
end
|
295
295
|
|
296
296
|
describe "polymorphic associations" do
|
297
297
|
it "works with polymorphic associations" do
|
298
298
|
result = @presenter_collection.presenting("posts", :params => { :include => "subject" }) { Post.order('id desc') }
|
299
|
-
result[:posts][Post.first.id.to_s].
|
300
|
-
result[:workspaces][Workspace.first.id.to_s].
|
301
|
-
result[:tasks][Task.first.id.to_s].
|
299
|
+
expect(result[:posts][Post.first.id.to_s]).to be_present
|
300
|
+
expect(result[:workspaces][Workspace.first.id.to_s]).to be_present
|
301
|
+
expect(result[:tasks][Task.first.id.to_s]).to be_present
|
302
302
|
end
|
303
303
|
|
304
304
|
it "does not return an empty hash when none are found" do
|
305
305
|
result = @presenter_collection.presenting("posts", :params => { :include => "subject" }) { Post.where(:id => nil) }
|
306
|
-
result.
|
307
|
-
result.
|
308
|
-
result.
|
306
|
+
expect(result).to have_key(:posts)
|
307
|
+
expect(result).not_to have_key(:workspaces)
|
308
|
+
expect(result).not_to have_key(:tasks)
|
309
309
|
end
|
310
310
|
end
|
311
311
|
end
|
@@ -313,7 +313,7 @@ describe Brainstem::PresenterCollection do
|
|
313
313
|
describe "handling of only" do
|
314
314
|
it "accepts params[:only] as a list of ids to limit to" do
|
315
315
|
result = @presenter_collection.presenting("workspaces", :params => { :only => Workspace.limit(2).pluck(:id).join(",") }) { Workspace.order("id desc") }
|
316
|
-
result[:workspaces].keys.
|
316
|
+
expect(result[:workspaces].keys).to match_array(Workspace.limit(2).pluck(:id).map(&:to_s))
|
317
317
|
end
|
318
318
|
|
319
319
|
it "does not paginate only requests" do
|
@@ -323,15 +323,15 @@ describe Brainstem::PresenterCollection do
|
|
323
323
|
|
324
324
|
it "escapes ids" do
|
325
325
|
result = @presenter_collection.presenting("workspaces", :params => { :only => "#{Workspace.first.id}foo,;drop tables;,#{Workspace.first.id}" }) { Workspace.order("id desc") }
|
326
|
-
result[:workspaces].length.
|
326
|
+
expect(result[:workspaces].length).to eq(1)
|
327
327
|
end
|
328
328
|
|
329
329
|
it "only runs when it receives ids" do
|
330
330
|
result = @presenter_collection.presenting("workspaces", :params => { :only => "" }) { Workspace.order("id desc") }
|
331
|
-
result[:workspaces].length.
|
331
|
+
expect(result[:workspaces].length).to be > 1
|
332
332
|
|
333
333
|
result = @presenter_collection.presenting("workspaces", :params => { :only => "1" }) { Workspace.order("id desc") }
|
334
|
-
result[:workspaces].length.
|
334
|
+
expect(result[:workspaces].length).to be <= 1
|
335
335
|
end
|
336
336
|
end
|
337
337
|
|
@@ -343,50 +343,67 @@ describe Brainstem::PresenterCollection do
|
|
343
343
|
|
344
344
|
it "limits records to those matching given filters" do
|
345
345
|
result = @presenter_collection.presenting("workspaces", :params => { :owned_by => bob.id.to_s }) { Workspace.order("id desc") } # hit the API, filtering on owned_by:bob
|
346
|
-
result[:workspaces].
|
347
|
-
result[:workspaces].keys.all? {|id| bob_workspaces_ids.map(&:to_s).include?(id) }.
|
346
|
+
expect(result[:workspaces]).to be_present
|
347
|
+
expect(result[:workspaces].keys.all? {|id| bob_workspaces_ids.map(&:to_s).include?(id) }).to be_truthy # all of the returned workspaces should contain bob
|
348
348
|
end
|
349
349
|
|
350
350
|
it "returns all records if filters are not given" do
|
351
351
|
result = @presenter_collection.presenting("workspaces") { Workspace.order("id desc") } # hit the API again, this time not filtering on anything
|
352
|
-
result[:workspaces].keys.all? {|id| bob_workspaces_ids.map(&:to_s).include?(id) }.
|
352
|
+
expect(result[:workspaces].keys.all? {|id| bob_workspaces_ids.map(&:to_s).include?(id) }).to be_falsey # the returned workspaces no longer all contain bob
|
353
353
|
end
|
354
354
|
|
355
355
|
it "ignores unknown filters" do
|
356
356
|
result = @presenter_collection.presenting("workspaces", :params => { :wut => "is this?" }) { Workspace.order("id desc") }
|
357
|
-
result[:workspaces].keys.all? {|id| bob_workspaces_ids.map(&:to_s).include?(id) }.
|
357
|
+
expect(result[:workspaces].keys.all? {|id| bob_workspaces_ids.map(&:to_s).include?(id) }).to be_falsey
|
358
358
|
end
|
359
359
|
|
360
360
|
it "limits records to those matching all given filters" do
|
361
361
|
result = @presenter_collection.presenting("workspaces", :params => { :owned_by => bob.id.to_s, :title => "bob workspace 1" }) { Workspace.order("id desc") } # try two filters
|
362
|
-
result[:results].first[:id].
|
362
|
+
expect(result[:results].first[:id]).to eq(Workspace.where(:title => "bob workspace 1").first.id.to_s)
|
363
363
|
end
|
364
364
|
|
365
365
|
it "converts boolean parameters from strings to booleans" do
|
366
366
|
WorkspacePresenter.filter(:owned_by_bob) { |scope, boolean| boolean ? scope.where(:user_id => bob.id) : scope.where(:user_id => jane.id) }
|
367
367
|
result = @presenter_collection.presenting("workspaces", :params => { :owned_by_bob => "false" }) { Workspace.where(nil) }
|
368
|
-
result[:workspaces].values.find { |workspace| workspace[:title].include?("jane") }.
|
369
|
-
result[:workspaces].values.find { |workspace| workspace[:title].include?("bob") }.
|
368
|
+
expect(result[:workspaces].values.find { |workspace| workspace[:title].include?("jane") }).to be
|
369
|
+
expect(result[:workspaces].values.find { |workspace| workspace[:title].include?("bob") }).not_to be
|
370
370
|
end
|
371
371
|
|
372
|
-
it "ensures arguments are strings" do
|
373
|
-
|
374
|
-
|
372
|
+
it "ensures arguments are strings if they are not arrays" do
|
373
|
+
filter_was_run = false
|
374
|
+
WorkspacePresenter.filter(:owned_by_bob) do |scope, string|
|
375
|
+
filter_was_run = true
|
376
|
+
expect(string).to be_a(String)
|
377
|
+
scope
|
378
|
+
end
|
379
|
+
@presenter_collection.presenting("workspaces", :params => { :owned_by_bob => { :wut => "is this?" } }) { Workspace.where(nil) }
|
380
|
+
expect(filter_was_run).to be_truthy
|
381
|
+
end
|
382
|
+
|
383
|
+
it "preserves array arguments" do
|
384
|
+
filter_was_run = false
|
385
|
+
WorkspacePresenter.filter(:owned_by_bob) do |scope, array|
|
386
|
+
filter_was_run = true
|
387
|
+
expect(array).to be_a(Array)
|
388
|
+
scope
|
389
|
+
end
|
390
|
+
@presenter_collection.presenting("workspaces", :params => { :owned_by_bob => [1, 2] }) { Workspace.where(nil) }
|
391
|
+
expect(filter_was_run).to be_truthy
|
375
392
|
end
|
376
393
|
|
377
394
|
it "allows filters to be called with false as an argument" do
|
378
395
|
WorkspacePresenter.filter(:nothing) { |scope, bool| bool ? scope.where(:id => nil) : scope }
|
379
396
|
result = @presenter_collection.presenting("workspaces", :params => { :nothing => "true" }) { Workspace.where(nil) }
|
380
|
-
result[:workspaces].length.
|
397
|
+
expect(result[:workspaces].length).to eq(0)
|
381
398
|
result = @presenter_collection.presenting("workspaces", :params => { :nothing => "false" }) { Workspace.where(nil) }
|
382
|
-
result[:workspaces].length.
|
399
|
+
expect(result[:workspaces].length).not_to eq(0)
|
383
400
|
end
|
384
401
|
|
385
402
|
it "passes colon separated params through as a string" do
|
386
403
|
WorkspacePresenter.filter(:between) { |scope, a_and_b|
|
387
404
|
a, b = a_and_b.split(':')
|
388
|
-
a.
|
389
|
-
b.
|
405
|
+
expect(a).to eq("1")
|
406
|
+
expect(b).to eq("10")
|
390
407
|
scope
|
391
408
|
}
|
392
409
|
|
@@ -402,32 +419,32 @@ describe Brainstem::PresenterCollection do
|
|
402
419
|
|
403
420
|
it "applies the filter when it is not requested" do
|
404
421
|
result = @presenter_collection.presenting("workspaces") { Workspace.order('id desc') }
|
405
|
-
result[:workspaces].keys.
|
422
|
+
expect(result[:workspaces].keys).to match_array(bob.workspaces.map(&:id).map(&:to_s))
|
406
423
|
end
|
407
424
|
|
408
425
|
it "allows falsy defaults" do
|
409
426
|
WorkspacePresenter.filter(:include_early_workspaces, :default => false) { |scope, bool| bool ? scope : scope.where("id > 3") }
|
410
427
|
result = @presenter_collection.presenting("workspaces") { Workspace.unscoped }
|
411
|
-
result[:workspaces]["2"].
|
428
|
+
expect(result[:workspaces]["2"]).not_to be_present
|
412
429
|
result = @presenter_collection.presenting("workspaces", :params => { :include_early_workspaces => "true" }) { Workspace.unscoped }
|
413
|
-
result[:workspaces]["2"].
|
430
|
+
expect(result[:workspaces]["2"]).to be_present
|
414
431
|
end
|
415
432
|
|
416
433
|
it "allows defaults to be skipped if :apply_default_filters is false" do
|
417
434
|
WorkspacePresenter.filter(:include_early_workspaces, :default => false) { |scope, bool| bool ? scope : scope.where("id > 3") }
|
418
435
|
result = @presenter_collection.presenting("workspaces", :apply_default_filters => true) { Workspace.unscoped }
|
419
|
-
result[:workspaces]["2"].
|
436
|
+
expect(result[:workspaces]["2"]).not_to be_present
|
420
437
|
result = @presenter_collection.presenting("workspaces", :apply_default_filters => false) { Workspace.unscoped }
|
421
|
-
result[:workspaces]["2"].
|
438
|
+
expect(result[:workspaces]["2"]).to be_present
|
422
439
|
end
|
423
440
|
|
424
441
|
it "allows the default value to be overridden" do
|
425
442
|
result = @presenter_collection.presenting("workspaces", :params => { :owner => jane.id.to_s }) { Workspace.order('id desc') }
|
426
|
-
result[:workspaces].keys.
|
443
|
+
expect(result[:workspaces].keys).to match_array(jane.workspaces.map(&:id).map(&:to_s))
|
427
444
|
|
428
445
|
WorkspacePresenter.filter(:include_early_workspaces, :default => true) { |scope, bool| bool ? scope : scope.where("id > 3") }
|
429
446
|
result = @presenter_collection.presenting("workspaces", :params => { :include_early_workspaces => "false" }) { Workspace.unscoped }
|
430
|
-
result[:workspaces]["2"].
|
447
|
+
expect(result[:workspaces]["2"]).not_to be_present
|
431
448
|
end
|
432
449
|
end
|
433
450
|
|
@@ -442,27 +459,27 @@ describe Brainstem::PresenterCollection do
|
|
442
459
|
|
443
460
|
it "calls the named scope with default arguments" do
|
444
461
|
result = @presenter_collection.presenting("workspaces") { Workspace.where(nil) }
|
445
|
-
result[:workspaces].keys.
|
462
|
+
expect(result[:workspaces].keys).to eq(bob.workspaces.pluck(:id).map(&:to_s))
|
446
463
|
end
|
447
464
|
|
448
465
|
it "calls the named scope with given arguments" do
|
449
466
|
result = @presenter_collection.presenting("workspaces", :params => { :owned_by => jane.id.to_s }) { Workspace.where(nil) }
|
450
|
-
result[:workspaces].keys.
|
467
|
+
expect(result[:workspaces].keys).to eq(jane.workspaces.pluck(:id).map(&:to_s))
|
451
468
|
end
|
452
469
|
|
453
470
|
it "can use filters without lambdas in the presenter or model, but behaves strangely when false is given" do
|
454
471
|
WorkspacePresenter.filter(:numeric_description)
|
455
472
|
|
456
473
|
result = @presenter_collection.presenting("workspaces") { Workspace.where(nil) }
|
457
|
-
result[:workspaces].keys.
|
474
|
+
expect(result[:workspaces].keys).to eq(%w[1 2 3 4])
|
458
475
|
|
459
476
|
result = @presenter_collection.presenting("workspaces", :params => { :numeric_description => "true" }) { Workspace.where(nil) }
|
460
|
-
result[:workspaces].keys.
|
477
|
+
expect(result[:workspaces].keys).to eq(%w[2 4])
|
461
478
|
|
462
479
|
# This is probably not the behavior that the developer or user intends. You should always use a one-argument lambda in your
|
463
480
|
# model scope declaration!
|
464
481
|
result = @presenter_collection.presenting("workspaces", :params => { :numeric_description => "false" }) { Workspace.where(nil) }
|
465
|
-
result[:workspaces].keys.
|
482
|
+
expect(result[:workspaces].keys).to eq(%w[2 4])
|
466
483
|
end
|
467
484
|
end
|
468
485
|
end
|
@@ -478,8 +495,8 @@ describe Brainstem::PresenterCollection do
|
|
478
495
|
context "and a search request is made" do
|
479
496
|
it "calls the search method and maintains the resulting order" do
|
480
497
|
result = @presenter_collection.presenting("workspaces", :params => { :search => "blah" }) { Workspace.order("id asc") }
|
481
|
-
result[:workspaces].keys.
|
482
|
-
result[:count].
|
498
|
+
expect(result[:workspaces].keys).to eq(%w[5 3])
|
499
|
+
expect(result[:count]).to eq(2)
|
483
500
|
end
|
484
501
|
|
485
502
|
it "does not apply filters" do
|
@@ -512,22 +529,22 @@ describe Brainstem::PresenterCollection do
|
|
512
529
|
false
|
513
530
|
end
|
514
531
|
|
515
|
-
|
532
|
+
expect {
|
516
533
|
@presenter_collection.presenting("workspaces", :params => { :search => "blah" }) { Workspace.unscoped }
|
517
|
-
}.
|
534
|
+
}.to raise_error(Brainstem::SearchUnavailableError)
|
518
535
|
end
|
519
536
|
|
520
537
|
describe "passing options to the search block" do
|
521
538
|
it "passes the search method, the search string, includes, order, and paging options" do
|
522
539
|
WorkspacePresenter.filter(:owned_by) { |scope| scope }
|
523
540
|
WorkspacePresenter.search do |string, options|
|
524
|
-
string.
|
525
|
-
options[:include].
|
526
|
-
options[:owned_by].
|
527
|
-
options[:order][:sort_order].
|
528
|
-
options[:order][:direction].
|
529
|
-
options[:page].
|
530
|
-
options[:per_page].
|
541
|
+
expect(string).to eq("blah")
|
542
|
+
expect(options[:include]).to eq(["tasks", "lead_user"])
|
543
|
+
expect(options[:owned_by]).to eq(false)
|
544
|
+
expect(options[:order][:sort_order]).to eq("updated_at")
|
545
|
+
expect(options[:order][:direction]).to eq("desc")
|
546
|
+
expect(options[:page]).to eq(2)
|
547
|
+
expect(options[:per_page]).to eq(5)
|
531
548
|
[[1], 1] # returned ids, count - not testing this in this set of specs
|
532
549
|
end
|
533
550
|
|
@@ -537,7 +554,7 @@ describe Brainstem::PresenterCollection do
|
|
537
554
|
describe "includes" do
|
538
555
|
it "throws out requested inlcudes that the presenter does not have associations for" do
|
539
556
|
WorkspacePresenter.search do |string, options|
|
540
|
-
options[:include].
|
557
|
+
expect(options[:include]).to eq([])
|
541
558
|
[[1], 1]
|
542
559
|
end
|
543
560
|
|
@@ -549,7 +566,7 @@ describe Brainstem::PresenterCollection do
|
|
549
566
|
it "passes through the default filters if no filter is requested" do
|
550
567
|
WorkspacePresenter.filter(:owned_by, :default => true) { |scope| scope }
|
551
568
|
WorkspacePresenter.search do |string, options|
|
552
|
-
options[:owned_by].
|
569
|
+
expect(options[:owned_by]).to eq(true)
|
553
570
|
[[1], 1]
|
554
571
|
end
|
555
572
|
|
@@ -558,7 +575,7 @@ describe Brainstem::PresenterCollection do
|
|
558
575
|
|
559
576
|
it "throws out requested filters that the presenter does not have" do
|
560
577
|
WorkspacePresenter.search do |string, options|
|
561
|
-
options[:highest_rated].
|
578
|
+
expect(options[:highest_rated]).to be_nil
|
562
579
|
[[1], 1]
|
563
580
|
end
|
564
581
|
|
@@ -568,7 +585,7 @@ describe Brainstem::PresenterCollection do
|
|
568
585
|
it "does not pass through existing non-default filters that are not requested" do
|
569
586
|
WorkspacePresenter.filter(:owned_by) { |scope| scope }
|
570
587
|
WorkspacePresenter.search do |string, options|
|
571
|
-
options.has_key?(:owned_by).
|
588
|
+
expect(options.has_key?(:owned_by)).to eq(false)
|
572
589
|
[[1], 1]
|
573
590
|
end
|
574
591
|
|
@@ -580,8 +597,8 @@ describe Brainstem::PresenterCollection do
|
|
580
597
|
it "passes through the default sort order if no order is requested" do
|
581
598
|
WorkspacePresenter.default_sort_order("description:desc")
|
582
599
|
WorkspacePresenter.search do |string, options|
|
583
|
-
options[:order][:sort_order].
|
584
|
-
options[:order][:direction].
|
600
|
+
expect(options[:order][:sort_order]).to eq("description")
|
601
|
+
expect(options[:order][:direction]).to eq("desc")
|
585
602
|
[[1], 1]
|
586
603
|
end
|
587
604
|
|
@@ -590,8 +607,8 @@ describe Brainstem::PresenterCollection do
|
|
590
607
|
|
591
608
|
it "makes the sort order 'updated_at:desc' if the requested order doesn't match an existing sort order and there is no default" do
|
592
609
|
WorkspacePresenter.search do |string, options|
|
593
|
-
options[:order][:sort_order].
|
594
|
-
options[:order][:direction].
|
610
|
+
expect(options[:order][:sort_order]).to eq("updated_at")
|
611
|
+
expect(options[:order][:direction]).to eq("desc")
|
595
612
|
[[1], 1]
|
596
613
|
end
|
597
614
|
|
@@ -602,8 +619,8 @@ describe Brainstem::PresenterCollection do
|
|
602
619
|
describe "pagination" do
|
603
620
|
it "passes through limit and offset if they are requested" do
|
604
621
|
WorkspacePresenter.search do |string, options|
|
605
|
-
options[:limit].
|
606
|
-
options[:offset].
|
622
|
+
expect(options[:limit]).to eq(1)
|
623
|
+
expect(options[:offset]).to eq(2)
|
607
624
|
[[1], 1]
|
608
625
|
end
|
609
626
|
|
@@ -612,10 +629,10 @@ describe Brainstem::PresenterCollection do
|
|
612
629
|
|
613
630
|
it "passes through only limit and offset if all pagination options are requested" do
|
614
631
|
WorkspacePresenter.search do |string, options|
|
615
|
-
options[:limit].
|
616
|
-
options[:offset].
|
617
|
-
options[:per_page].
|
618
|
-
options[:page].
|
632
|
+
expect(options[:limit]).to eq(1)
|
633
|
+
expect(options[:offset]).to eq(2)
|
634
|
+
expect(options[:per_page]).to eq(nil)
|
635
|
+
expect(options[:page]).to eq(nil)
|
619
636
|
[[1], 1]
|
620
637
|
end
|
621
638
|
|
@@ -624,10 +641,10 @@ describe Brainstem::PresenterCollection do
|
|
624
641
|
|
625
642
|
it "passes through page and per_page when limit not present" do
|
626
643
|
WorkspacePresenter.search do |string, options|
|
627
|
-
options[:limit].
|
628
|
-
options[:offset].
|
629
|
-
options[:per_page].
|
630
|
-
options[:page].
|
644
|
+
expect(options[:limit]).to eq(nil)
|
645
|
+
expect(options[:offset]).to eq(nil)
|
646
|
+
expect(options[:per_page]).to eq(3)
|
647
|
+
expect(options[:page]).to eq(4)
|
631
648
|
[[1], 1]
|
632
649
|
end
|
633
650
|
|
@@ -636,10 +653,10 @@ describe Brainstem::PresenterCollection do
|
|
636
653
|
|
637
654
|
it "passes through page and per_page when offset not present" do
|
638
655
|
WorkspacePresenter.search do |string, options|
|
639
|
-
options[:limit].
|
640
|
-
options[:offset].
|
641
|
-
options[:per_page].
|
642
|
-
options[:page].
|
656
|
+
expect(options[:limit]).to eq(nil)
|
657
|
+
expect(options[:offset]).to eq(nil)
|
658
|
+
expect(options[:per_page]).to eq(3)
|
659
|
+
expect(options[:page]).to eq(4)
|
643
660
|
[[1], 1]
|
644
661
|
end
|
645
662
|
|
@@ -648,10 +665,10 @@ describe Brainstem::PresenterCollection do
|
|
648
665
|
|
649
666
|
it "passes through page and per_page by default" do
|
650
667
|
WorkspacePresenter.search do |string, options|
|
651
|
-
options[:limit].
|
652
|
-
options[:offset].
|
653
|
-
options[:per_page].
|
654
|
-
options[:page].
|
668
|
+
expect(options[:limit]).to eq(nil)
|
669
|
+
expect(options[:offset]).to eq(nil)
|
670
|
+
expect(options[:per_page]).to eq(20)
|
671
|
+
expect(options[:page]).to eq(1)
|
655
672
|
[[1], 1]
|
656
673
|
end
|
657
674
|
|
@@ -664,7 +681,7 @@ describe Brainstem::PresenterCollection do
|
|
664
681
|
context "and there is no search request" do
|
665
682
|
it "does not call the search method" do
|
666
683
|
result = @presenter_collection.presenting("workspaces") { Workspace.order("id asc") }
|
667
|
-
result[:workspaces].keys.
|
684
|
+
expect(result[:workspaces].keys).to eq(Workspace.pluck(:id).map(&:to_s))
|
668
685
|
end
|
669
686
|
end
|
670
687
|
end
|
@@ -673,7 +690,7 @@ describe Brainstem::PresenterCollection do
|
|
673
690
|
context "and a search request is made" do
|
674
691
|
it "returns as if there was no search" do
|
675
692
|
result = @presenter_collection.presenting("workspaces", :params => { :search => "blah" }) { Workspace.order("id asc") }
|
676
|
-
result[:workspaces].keys.
|
693
|
+
expect(result[:workspaces].keys).to eq(Workspace.pluck(:id).map(&:to_s))
|
677
694
|
end
|
678
695
|
end
|
679
696
|
end
|
@@ -683,12 +700,12 @@ describe Brainstem::PresenterCollection do
|
|
683
700
|
context "when there is no sort provided" do
|
684
701
|
it "returns an empty array when there are no objects" do
|
685
702
|
result = @presenter_collection.presenting("workspaces") { Workspace.where(:id => nil) }
|
686
|
-
result.
|
703
|
+
expect(result).to eq(:count => 0, :workspaces => {}, :results => [])
|
687
704
|
end
|
688
705
|
|
689
706
|
it "falls back to the object's sort order when nothing is provided" do
|
690
707
|
result = @presenter_collection.presenting("workspaces") { Workspace.where(:id => [1, 3]) }
|
691
|
-
result[:workspaces].keys.
|
708
|
+
expect(result[:workspaces].keys).to eq(%w[1 3])
|
692
709
|
end
|
693
710
|
end
|
694
711
|
|
@@ -696,28 +713,28 @@ describe Brainstem::PresenterCollection do
|
|
696
713
|
WorkspacePresenter.sort_order(:description, "workspaces.description")
|
697
714
|
WorkspacePresenter.default_sort_order("description:desc")
|
698
715
|
result = @presenter_collection.presenting("workspaces") { Workspace.where("id is not null") }
|
699
|
-
result[:results].map {|i| result[:workspaces][i[:id]][:description] }.
|
716
|
+
expect(result[:results].map {|i| result[:workspaces][i[:id]][:description] }).to eq(%w(c b a 3 2 1))
|
700
717
|
end
|
701
718
|
|
702
719
|
it "allows default ordering ascending" do
|
703
720
|
WorkspacePresenter.sort_order(:description, "workspaces.description")
|
704
721
|
WorkspacePresenter.default_sort_order("description:asc")
|
705
722
|
result = @presenter_collection.presenting("workspaces") { Workspace.where("id is not null") }
|
706
|
-
result[:results].map {|i| result[:workspaces][i[:id]][:description] }.
|
723
|
+
expect(result[:results].map {|i| result[:workspaces][i[:id]][:description] }).to eq(%w(1 2 3 a b c))
|
707
724
|
end
|
708
725
|
|
709
726
|
it "applies orders that match the default order" do
|
710
727
|
WorkspacePresenter.sort_order(:description, "workspaces.description")
|
711
728
|
WorkspacePresenter.default_sort_order("description:desc")
|
712
729
|
result = @presenter_collection.presenting("workspaces", :params => { :order => "description:desc"} ) { Workspace.where("id is not null") }
|
713
|
-
result[:results].map {|i| result[:workspaces][i[:id]][:description] }.
|
730
|
+
expect(result[:results].map {|i| result[:workspaces][i[:id]][:description] }).to eq(%w(c b a 3 2 1))
|
714
731
|
end
|
715
732
|
|
716
733
|
it "applies orders that conflict with the default order" do
|
717
734
|
WorkspacePresenter.sort_order(:description, "workspaces.description")
|
718
735
|
WorkspacePresenter.default_sort_order("description:desc")
|
719
736
|
result = @presenter_collection.presenting("workspaces", :params => { :order => "description:asc"} ) { Workspace.where("id is not null") }
|
720
|
-
result[:results].map {|i| result[:workspaces][i[:id]][:description] }.
|
737
|
+
expect(result[:results].map {|i| result[:workspaces][i[:id]][:description] }).to eq(%w(1 2 3 a b c))
|
721
738
|
end
|
722
739
|
|
723
740
|
it "cleans the params" do
|
@@ -725,11 +742,11 @@ describe Brainstem::PresenterCollection do
|
|
725
742
|
WorkspacePresenter.default_sort_order("description:desc")
|
726
743
|
|
727
744
|
result = @presenter_collection.presenting("workspaces", :params => { :order => "updated_at:drop table" }) { Workspace.where("id is not null") }
|
728
|
-
result.keys.
|
745
|
+
expect(result.keys).to match_array([:count, :workspaces, :results])
|
729
746
|
|
730
747
|
result = @presenter_collection.presenting("workspaces", :params => { :order => "drop table:desc" }) { Workspace.where("id is not null") }
|
731
|
-
result.keys.
|
732
|
-
result[:results].map {|i| result[:workspaces][i[:id]][:description] }.
|
748
|
+
expect(result.keys).to match_array([:count, :workspaces, :results])
|
749
|
+
expect(result[:results].map {|i| result[:workspaces][i[:id]][:description] }).to eq(%w(c b a 3 2 1))
|
733
750
|
end
|
734
751
|
|
735
752
|
it "can take a proc" do
|
@@ -738,22 +755,22 @@ describe Brainstem::PresenterCollection do
|
|
738
755
|
|
739
756
|
# Default
|
740
757
|
result = @presenter_collection.presenting("workspaces") { Workspace.where("id is not null") }
|
741
|
-
result[:results].map {|i| result[:workspaces][i[:id]][:description] }.
|
758
|
+
expect(result[:results].map {|i| result[:workspaces][i[:id]][:description] }).to eq(%w(a 1 b 2 c 3))
|
742
759
|
|
743
760
|
# Asc
|
744
761
|
result = @presenter_collection.presenting("workspaces", :params => { :order => "id:asc" }) { Workspace.where("id is not null") }
|
745
|
-
result[:results].map {|i| result[:workspaces][i[:id]][:description] }.
|
762
|
+
expect(result[:results].map {|i| result[:workspaces][i[:id]][:description] }).to eq(%w(a 1 b 2 c 3))
|
746
763
|
|
747
764
|
# Desc
|
748
765
|
result = @presenter_collection.presenting("workspaces", :params => { :order => "id:desc" }) { Workspace.where("id is not null") }
|
749
|
-
result[:results].map {|i| result[:workspaces][i[:id]][:description] }.
|
766
|
+
expect(result[:results].map {|i| result[:workspaces][i[:id]][:description] }).to eq(%w(3 c 2 b 1 a))
|
750
767
|
end
|
751
768
|
end
|
752
769
|
|
753
770
|
describe "the :as param" do
|
754
771
|
it "determines the chosen top-level key name" do
|
755
772
|
result = @presenter_collection.presenting("workspaces", :as => :my_workspaces) { Workspace.where(:id => 1) }
|
756
|
-
result.keys.
|
773
|
+
expect(result.keys).to eq([:count, :my_workspaces, :results])
|
757
774
|
end
|
758
775
|
end
|
759
776
|
|
@@ -762,16 +779,32 @@ describe Brainstem::PresenterCollection do
|
|
762
779
|
WorkspacePresenter.filter(:owned_by) { |scope, user_id| scope.owned_by(user_id.to_i) }
|
763
780
|
|
764
781
|
result = @presenter_collection.presenting("workspaces") { Workspace.where(:id => 1) }
|
765
|
-
result[:count].
|
782
|
+
expect(result[:count]).to eq(1)
|
766
783
|
|
767
784
|
result = @presenter_collection.presenting("workspaces") { Workspace.unscoped }
|
768
|
-
result[:count].
|
785
|
+
expect(result[:count]).to eq(Workspace.count)
|
769
786
|
|
770
787
|
result = @presenter_collection.presenting("workspaces", :params => { :owned_by => bob.to_param }) { Workspace.unscoped }
|
771
|
-
result[:count].
|
788
|
+
expect(result[:count]).to eq(Workspace.owned_by(bob.to_param).count)
|
772
789
|
|
773
790
|
result = @presenter_collection.presenting("workspaces", :params => { :owned_by => bob.to_param }) { Workspace.group(:id) }
|
774
|
-
result[:count].
|
791
|
+
expect(result[:count]).to eq(Workspace.owned_by(bob.to_param).count)
|
792
|
+
end
|
793
|
+
end
|
794
|
+
|
795
|
+
describe "pretty printing" do
|
796
|
+
before do
|
797
|
+
@user_result = { :count => 1, :users => { 1 => { :username => "bob", :id => "1" } }, :results => [{ :key => "users", :id => "1" }] }
|
798
|
+
end
|
799
|
+
|
800
|
+
it "should return normal json if the pretty parameter is not true" do
|
801
|
+
result = @presenter_collection.presenting("users") { User.where(:id => 1) }
|
802
|
+
expect(result.to_json).to eq(JSON.generate(@user_result))
|
803
|
+
end
|
804
|
+
|
805
|
+
it "should return pretty printed json if the pretty parameter is true" do
|
806
|
+
result = @presenter_collection.presenting("users", :params => { :pretty => "true" }) { User.where(:id => 1) }
|
807
|
+
expect(result.to_json).to eq(JSON.pretty_generate(@user_result))
|
775
808
|
end
|
776
809
|
end
|
777
810
|
end
|
@@ -788,25 +821,25 @@ describe Brainstem::PresenterCollection do
|
|
788
821
|
end
|
789
822
|
|
790
823
|
it "returns the presenter for a given class" do
|
791
|
-
Brainstem.presenter_collection("v1").for(Array).
|
824
|
+
expect(Brainstem.presenter_collection("v1").for(Array)).to be_a(V1::ArrayPresenter)
|
792
825
|
end
|
793
826
|
|
794
827
|
it "returns nil when given nil" do
|
795
|
-
Brainstem.presenter_collection("v1").for(nil).
|
828
|
+
expect(Brainstem.presenter_collection("v1").for(nil)).to be_nil
|
796
829
|
end
|
797
830
|
|
798
831
|
it "returns nil when a given class has no presenter" do
|
799
|
-
Brainstem.presenter_collection("v1").for(String).
|
832
|
+
expect(Brainstem.presenter_collection("v1").for(String)).to be_nil
|
800
833
|
end
|
801
834
|
|
802
835
|
it "uses the default namespace when the passed namespace is nil" do
|
803
|
-
Brainstem.presenter_collection.
|
836
|
+
expect(Brainstem.presenter_collection).to eq(Brainstem.presenter_collection(nil))
|
804
837
|
end
|
805
838
|
end
|
806
839
|
|
807
840
|
describe "for! method" do
|
808
841
|
it "raises if there is no presenter for the given class" do
|
809
|
-
|
842
|
+
expect{ Brainstem.presenter_collection("v1").for!(String) }.to raise_error(ArgumentError)
|
810
843
|
end
|
811
844
|
end
|
812
845
|
end
|