shamu 0.0.13 → 0.0.14
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 +4 -4
- data/.rubocop.yml +55 -20
- data/Gemfile +3 -3
- data/Gemfile.lock +13 -11
- data/circle.yml +1 -1
- data/lib/shamu/attributes/assignment.rb +44 -5
- data/lib/shamu/attributes/camel_case.rb +21 -0
- data/lib/shamu/attributes/validation.rb +13 -1
- data/lib/shamu/attributes/validators/valid_validator.rb +14 -0
- data/lib/shamu/attributes/validators.rb +7 -0
- data/lib/shamu/attributes.rb +13 -8
- data/lib/shamu/auditing/auditing_service.rb +1 -5
- data/lib/shamu/auditing/support.rb +14 -2
- data/lib/shamu/entities/active_record.rb +16 -2
- data/lib/shamu/entities/active_record_soft_destroy.rb +7 -3
- data/lib/shamu/entities/entity.rb +1 -1
- data/lib/shamu/entities/entity_lookup_service.rb +137 -0
- data/lib/shamu/entities/entity_path.rb +6 -9
- data/lib/shamu/entities/list.rb +8 -2
- data/lib/shamu/entities/list_scope/paging.rb +3 -3
- data/lib/shamu/entities/list_scope/sorting.rb +21 -2
- data/lib/shamu/entities/list_scope/window_paging.rb +96 -0
- data/lib/shamu/entities/list_scope.rb +2 -2
- data/lib/shamu/entities/opaque_entity_lookup_service.rb +59 -0
- data/lib/shamu/entities/opaque_id.rb +54 -0
- data/lib/shamu/entities/paged_list.rb +137 -0
- data/lib/shamu/entities.rb +5 -1
- data/lib/shamu/events/active_record/service.rb +1 -2
- data/lib/shamu/events/in_memory/service.rb +1 -2
- data/lib/shamu/features/conditions/percentage.rb +3 -3
- data/lib/shamu/features/features_service.rb +2 -2
- data/lib/shamu/features/toggle.rb +2 -3
- data/lib/shamu/json_api/context.rb +0 -1
- data/lib/shamu/json_api/rails/controller.rb +0 -2
- data/lib/shamu/rails/controller.rb +0 -1
- data/lib/shamu/rails/entity.rb +1 -1
- data/lib/shamu/security/policy.rb +1 -2
- data/lib/shamu/services/active_record.rb +16 -0
- data/lib/shamu/services/active_record_crud.rb +32 -22
- data/lib/shamu/services/lazy_transform.rb +31 -0
- data/lib/shamu/services/request_support.rb +3 -2
- data/lib/shamu/services/service.rb +11 -3
- data/lib/shamu/to_model_id_extension.rb +2 -1
- data/lib/shamu/version.rb +2 -1
- data/shamu.gemspec +2 -1
- data/spec/lib/shamu/active_record_support.rb +6 -0
- data/spec/lib/shamu/attributes/assignment_spec.rb +69 -5
- data/spec/lib/shamu/attributes/camel_case_spec.rb +33 -0
- data/spec/lib/shamu/attributes/validation_spec.rb +9 -1
- data/spec/lib/shamu/attributes_spec.rb +4 -0
- data/spec/lib/shamu/entities/active_record_spec.rb +27 -0
- data/spec/lib/shamu/entities/entity_lookup_models.rb +11 -0
- data/spec/lib/shamu/entities/entity_lookup_service_spec.rb +77 -0
- data/spec/lib/shamu/entities/entity_path_spec.rb +3 -4
- data/spec/lib/shamu/entities/list_scope/paging_spec.rb +7 -3
- data/spec/lib/shamu/entities/list_scope/sorting_spec.rb +1 -7
- data/spec/lib/shamu/entities/opaque_entity_lookup_service_spec.rb +39 -0
- data/spec/lib/shamu/entities/opaque_id_spec.rb +30 -0
- data/spec/lib/shamu/entities/paged_list_spec.rb +170 -0
- data/spec/lib/shamu/services/active_record_crud_spec.rb +10 -1
- data/spec/lib/shamu/services/lazy_transform_spec.rb +14 -0
- data/spec/lib/shamu/to_model_id_extension_spec.rb +5 -1
- data/spec/support/active_record.rb +1 -1
- metadata +24 -4
@@ -158,11 +158,11 @@ module Shamu
|
|
158
158
|
|
159
159
|
# @param [String] path of the default config file.
|
160
160
|
# @return [String]
|
161
|
-
def default_config_path=( path )
|
161
|
+
def default_config_path=( path ) # rubocop:disable Style/TrivialAccessors
|
162
162
|
@default_config_path = path
|
163
163
|
end
|
164
164
|
end
|
165
165
|
|
166
166
|
end
|
167
167
|
end
|
168
|
-
end
|
168
|
+
end
|
@@ -76,7 +76,6 @@ module Shamu
|
|
76
76
|
!retire_at || context.time > retire_at
|
77
77
|
end
|
78
78
|
|
79
|
-
|
80
79
|
def initialize( attributes )
|
81
80
|
fail ArgumentError, "Must provide a retire_at attribute for '#{ attributes[ 'name' ] }' toggle." unless attributes["retire_at"] # rubocop:disable Metrics/LineLength
|
82
81
|
fail ArgumentError, "Type must be one of #{ TYPES } for '#{ attributes[ 'name' ] }' toggle." unless TYPES.include?( attributes["type"] ) # rubocop:disable Metrics/LineLength
|
@@ -107,7 +106,7 @@ module Shamu
|
|
107
106
|
def load_from_path( path, toggles, state )
|
108
107
|
path = File.expand_path( path, state.file_path )
|
109
108
|
File.open( path, "r" ) do |file|
|
110
|
-
yaml = YAML.load( file.read )
|
109
|
+
yaml = YAML.load( file.read ) # rubocop:disable Security/YAMLLoad
|
111
110
|
parse_node( yaml, toggles, ParsingState.new( state.name, File.dirname( path ) ) )
|
112
111
|
end
|
113
112
|
end
|
@@ -146,4 +145,4 @@ module Shamu
|
|
146
145
|
ParsingState = Struct.new( :name, :file_path )
|
147
146
|
end
|
148
147
|
end
|
149
|
-
end
|
148
|
+
end
|
@@ -234,7 +234,6 @@ module Shamu
|
|
234
234
|
presenters: presenters == :not_set ? json_context_presenters : presenters
|
235
235
|
end
|
236
236
|
|
237
|
-
|
238
237
|
# See (Shamu::Rails::Entity#request_params)
|
239
238
|
def request_params( param_key )
|
240
239
|
if relationships = json_request_payload[ :relationships ]
|
@@ -291,7 +290,6 @@ module Shamu
|
|
291
290
|
end
|
292
291
|
end
|
293
292
|
|
294
|
-
|
295
293
|
def json_context_fields
|
296
294
|
params[:fields]
|
297
295
|
end
|
data/lib/shamu/rails/entity.rb
CHANGED
@@ -21,7 +21,7 @@ module Shamu
|
|
21
21
|
return unless service.respond_to?( :request_for )
|
22
22
|
return unless request = service.request_for( action, entity )
|
23
23
|
|
24
|
-
param_key ||= entity.model_name.param_key
|
24
|
+
param_key ||= entity.model_name.param_key if entity
|
25
25
|
request.assign_attributes( request_params( param_key ) )
|
26
26
|
|
27
27
|
service.authorize!( action, entity, request ) if service.respond_to?( :authorize! )
|
@@ -55,7 +55,6 @@ module Shamu
|
|
55
55
|
@roles = roles || []
|
56
56
|
end
|
57
57
|
|
58
|
-
|
59
58
|
# Authorize the given `action` on the given resource. If it is not
|
60
59
|
# {#permit? permitted} then an exception is raised.
|
61
60
|
#
|
@@ -286,4 +285,4 @@ module Shamu
|
|
286
285
|
|
287
286
|
end
|
288
287
|
end
|
289
|
-
end
|
288
|
+
end
|
@@ -53,6 +53,22 @@ module Shamu
|
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
|
+
# @param [ActiveRecord::Relation, Enumerable] source
|
57
|
+
# @return [Boolean] true if the source supports paging and has paging
|
58
|
+
# constraints set.
|
59
|
+
def source_paged?( source )
|
60
|
+
source.respond_to?( :current_page ) && !!source.current_page
|
61
|
+
end
|
62
|
+
|
63
|
+
# (see Service#build_entity_list)
|
64
|
+
def build_entity_list( source )
|
65
|
+
if source_paged?( source )
|
66
|
+
Shamu::Entities::PagedList.new( source )
|
67
|
+
else
|
68
|
+
super
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
56
72
|
end
|
57
73
|
end
|
58
74
|
end
|
@@ -43,7 +43,7 @@ module Shamu
|
|
43
43
|
extend ActiveSupport::Concern
|
44
44
|
|
45
45
|
# Known DSL methods defined by {ActiveRecordCrud}.
|
46
|
-
DSL_METHODS = %i
|
46
|
+
DSL_METHODS = %i[ create update change destroy find list lookup finders ].freeze
|
47
47
|
|
48
48
|
included do |base|
|
49
49
|
base.include Shamu::Services::RequestSupport
|
@@ -173,15 +173,21 @@ module Shamu
|
|
173
173
|
# @yieldparam (see .apply_changes)
|
174
174
|
# @return [Result] the result of the request.
|
175
175
|
# @return [void]
|
176
|
-
def change( method = :update, &block )
|
176
|
+
def change( method = :update, &block ) # rubocop:disable Metrics/PerceivedComplexity, Metrics/AbcSize
|
177
177
|
define_method method do |id, params = nil|
|
178
178
|
klass = request_class( method )
|
179
179
|
|
180
|
-
|
180
|
+
params, id = id, id[ :id ] if !params && !id.respond_to?( :to_model_id )
|
181
181
|
|
182
|
-
|
183
|
-
record = model_class.find( id.to_model_id )
|
184
|
-
|
182
|
+
with_partial_request params, klass do |request|
|
183
|
+
record = model_class.find( id.to_model_id || request.id )
|
184
|
+
entity = build_entity( record )
|
185
|
+
|
186
|
+
backfill_attributes = entity.to_attributes( only: request.unassigned_attributes )
|
187
|
+
request.assign_attributes backfill_attributes
|
188
|
+
next unless request.valid?
|
189
|
+
|
190
|
+
authorize! method, entity, request
|
185
191
|
|
186
192
|
request.apply_to( record )
|
187
193
|
|
@@ -213,6 +219,26 @@ module Shamu
|
|
213
219
|
change :update, &block
|
214
220
|
end
|
215
221
|
|
222
|
+
# Define a `destroy( id )` method that takes an {Entities::Entity} {Entities::Entity#id}
|
223
|
+
# and destroys the resource.
|
224
|
+
#
|
225
|
+
# @param [ActiveRecord::Relation] default_scope to use when finding
|
226
|
+
# records.
|
227
|
+
# @return [void]
|
228
|
+
def destroy( default_scope = model_class.all )
|
229
|
+
define_method :destroy do |params|
|
230
|
+
klass = request_class( :destroy )
|
231
|
+
|
232
|
+
params = { id: params } if params.respond_to?( :to_model_id )
|
233
|
+
|
234
|
+
with_request params, klass do |request|
|
235
|
+
record = default_scope.find( request.id )
|
236
|
+
authorize! :destroy, build_entity( record )
|
237
|
+
next record unless record.destroy
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
216
242
|
# Define a private method `apply_changes` on the service used by the
|
217
243
|
# {.create} and {.change} defined methods to apply changes in a
|
218
244
|
# {Request} to the model.
|
@@ -311,22 +337,6 @@ module Shamu
|
|
311
337
|
end
|
312
338
|
end
|
313
339
|
|
314
|
-
# Define a `destroy( id )` method that takes an {Entities::Entity} {Entities::Entity#id}
|
315
|
-
# and destroys the resource.
|
316
|
-
#
|
317
|
-
# @param [ActiveRecord::Relation] default_scope to use when finding
|
318
|
-
# records.
|
319
|
-
# @return [void]
|
320
|
-
def destroy( default_scope = model_class.all )
|
321
|
-
define_method :destroy do |id|
|
322
|
-
wrap_not_found do
|
323
|
-
record = default_scope.find( id.to_model_id )
|
324
|
-
authorize! :destroy, build_entity( record )
|
325
|
-
record.destroy
|
326
|
-
end
|
327
|
-
end
|
328
|
-
end
|
329
|
-
|
330
340
|
# Define a private `build_entities( records )` method that
|
331
341
|
# constructs an {Entities::Entity} for each of the given `records`.
|
332
342
|
#
|
@@ -53,6 +53,22 @@ module Shamu
|
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
|
+
# Get the last transformed value without transforming the entire list.
|
57
|
+
# @overload last(n)
|
58
|
+
# @overload last
|
59
|
+
# @return [Object]
|
60
|
+
def last( *args )
|
61
|
+
if args.any?
|
62
|
+
transformed.last( *args )
|
63
|
+
else
|
64
|
+
return @last if defined? @last
|
65
|
+
@last = begin
|
66
|
+
value = source.last
|
67
|
+
raise_if_not_transformed( transformer.call( [ value ] ) ).last unless value.nil?
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
56
72
|
# @return [Boolean] true if there are no source values.
|
57
73
|
def empty?
|
58
74
|
source.empty?
|
@@ -80,6 +96,21 @@ module Shamu
|
|
80
96
|
end
|
81
97
|
end
|
82
98
|
|
99
|
+
# For all other methods, force a transform then delegate to the
|
100
|
+
# transformed list.
|
101
|
+
|
102
|
+
def method_missing( name, *args, &block )
|
103
|
+
if respond_to_missing?( name, false )
|
104
|
+
source.public_send( name, *args, &block )
|
105
|
+
else
|
106
|
+
super
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def respond_to_missing?( *args )
|
111
|
+
super || source.respond_to?( *args )
|
112
|
+
end
|
113
|
+
|
83
114
|
private
|
84
115
|
|
85
116
|
attr_reader :source
|
@@ -88,15 +88,16 @@ module Shamu
|
|
88
88
|
# @see #with_request
|
89
89
|
def with_partial_request( params, request_class, &block )
|
90
90
|
request = request_class.coerce( params )
|
91
|
+
sources = yield( request )
|
92
|
+
|
91
93
|
# Make sure the request captures errors even if the block doesn't
|
92
94
|
# check
|
93
95
|
request.valid?
|
94
|
-
sources = yield( request )
|
95
96
|
|
96
97
|
if sources.is_a?( Result )
|
97
98
|
sources
|
98
99
|
else
|
99
|
-
result
|
100
|
+
result( *Array.wrap( sources ), request: request )
|
100
101
|
end
|
101
102
|
end
|
102
103
|
|
@@ -101,7 +101,7 @@ module Shamu
|
|
101
101
|
#
|
102
102
|
# @param [Enumerable] records the raw list of records.
|
103
103
|
# @yield (record)
|
104
|
-
# @yieldparam [Object]
|
104
|
+
# @yieldparam [Enumerable<Object>] records the raw values from the `list` to
|
105
105
|
# transform to an {Entities::Entity}.
|
106
106
|
# @yieldreturn [Entities::Entity]
|
107
107
|
# @return [Entities::List]
|
@@ -112,9 +112,17 @@ module Shamu
|
|
112
112
|
transformer ||= method( :build_entities )
|
113
113
|
end
|
114
114
|
|
115
|
-
|
115
|
+
build_entity_list build_records_transform( records, &transformer )
|
116
116
|
end
|
117
117
|
|
118
|
+
def build_records_transform( records, &transformer )
|
119
|
+
LazyTransform.new( records, &transformer )
|
120
|
+
end
|
121
|
+
|
122
|
+
def build_entity_list( source )
|
123
|
+
Entities::List.new source
|
124
|
+
end
|
125
|
+
|
118
126
|
# @!visibility public
|
119
127
|
# Match a list of records with the ids used to look up those records.
|
120
128
|
# Uses a {Entities::NullEntity} if the id doesn't have a matching record.
|
@@ -219,7 +227,7 @@ module Shamu
|
|
219
227
|
# @!visibility public
|
220
228
|
#
|
221
229
|
# Find an associated entity from a dependent service. Attempts to
|
222
|
-
#
|
230
|
+
# efficiently handle multiple requests to lookup associations by caching
|
223
231
|
# all the associated entities when {#lookup_association} is used
|
224
232
|
# repeatedly when building an entity.
|
225
233
|
#
|
@@ -11,6 +11,7 @@ module Shamu
|
|
11
11
|
Integer.include Integers
|
12
12
|
String.include Strings
|
13
13
|
Array.include Enumerables
|
14
|
+
NilClass.include Integers
|
14
15
|
|
15
16
|
ActiveRecord::Base.include Models if defined? ActiveRecord::Base
|
16
17
|
end
|
@@ -47,4 +48,4 @@ module Shamu
|
|
47
48
|
end
|
48
49
|
end
|
49
50
|
|
50
|
-
Shamu::ToModelIdExtension.extend!
|
51
|
+
Shamu::ToModelIdExtension.extend!
|
data/lib/shamu/version.rb
CHANGED
data/shamu.gemspec
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# coding: utf-8
|
2
|
+
|
2
3
|
lib = File.expand_path( "../lib", __FILE__ )
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
5
|
require "shamu/version"
|
@@ -23,7 +24,7 @@ Gem::Specification.new do |spec|
|
|
23
24
|
spec.add_dependency "activemodel", ">= 5.0"
|
24
25
|
spec.add_dependency "activesupport", ">= 5.0"
|
25
26
|
spec.add_dependency "scorpion-ioc", "~> 0.6"
|
26
|
-
spec.add_dependency "multi_json", "~> 1.11
|
27
|
+
spec.add_dependency "multi_json", "~> 1.11"
|
27
28
|
spec.add_dependency "rack", ">= 1"
|
28
29
|
spec.add_dependency "listen", "~> 3"
|
29
30
|
spec.add_dependency "crc32", "~> 1"
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require "active_record"
|
2
2
|
require "shamu/entities/active_record"
|
3
|
+
require "shamu/entities/active_record_soft_destroy"
|
3
4
|
|
4
5
|
module ActiveRecordSpec
|
5
6
|
class Favorite < ::ActiveRecord::Base
|
@@ -29,4 +30,9 @@ module ActiveRecordSpec
|
|
29
30
|
class FavoriteScope < Shamu::Entities::ListScope
|
30
31
|
attribute :name
|
31
32
|
end
|
33
|
+
|
34
|
+
class FavoriteEntity < Shamu::Entities::Entity
|
35
|
+
model :record
|
36
|
+
attribute :name, on: :record
|
37
|
+
end
|
32
38
|
end
|
@@ -59,6 +59,49 @@ describe Shamu::Attributes::Assignment do
|
|
59
59
|
expect( instance.q ).to eq "ABC"
|
60
60
|
end
|
61
61
|
|
62
|
+
describe "#assigned_attributes" do
|
63
|
+
let( :klass ) do
|
64
|
+
Class.new do
|
65
|
+
include Shamu::Attributes
|
66
|
+
include Shamu::Attributes::Assignment
|
67
|
+
|
68
|
+
attribute :name
|
69
|
+
attribute :email
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
it "identifies attributes assigned in constructor" do
|
74
|
+
instance = klass.new name: "set"
|
75
|
+
|
76
|
+
expect( instance.assigned_attributes ).to include :name
|
77
|
+
expect( instance.assigned_attributes ).not_to include :email
|
78
|
+
expect( instance.unassigned_attributes ).to include :email
|
79
|
+
end
|
80
|
+
|
81
|
+
it "does not identity attributes memoized by reading" do
|
82
|
+
instance = klass.new name: "set"
|
83
|
+
|
84
|
+
expect( instance.email ).to be_nil
|
85
|
+
expect( instance.assigned_attributes ).to include :name
|
86
|
+
expect( instance.assigned_attributes ).not_to include :email
|
87
|
+
expect( instance.set?( :email ) ).to be_truthy
|
88
|
+
end
|
89
|
+
|
90
|
+
it "identifies attributes assigned explicitly" do
|
91
|
+
instance = klass.new
|
92
|
+
instance.name = "set"
|
93
|
+
|
94
|
+
expect( instance.assigned_attributes ).to include :name
|
95
|
+
expect( instance.assigned_attributes ).not_to include :email
|
96
|
+
end
|
97
|
+
|
98
|
+
it "identifies attribute_assigned?" do
|
99
|
+
instance = klass.new name: "set"
|
100
|
+
expect( instance.name_assigned? ).to be_truthy
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
|
62
105
|
describe "coercion" do
|
63
106
|
it "coerces using given method name" do
|
64
107
|
klass = Class.new( base_klass ) do
|
@@ -83,6 +126,19 @@ describe Shamu::Attributes::Assignment do
|
|
83
126
|
expect( instance.label ).to eq "coerced"
|
84
127
|
end
|
85
128
|
|
129
|
+
it "coerces using a class" do
|
130
|
+
coerce_class = Class.new do
|
131
|
+
def initialize( v ); end
|
132
|
+
end
|
133
|
+
|
134
|
+
klass = Class.new( base_klass ) do
|
135
|
+
attribute :label, coerce: coerce_class
|
136
|
+
end
|
137
|
+
|
138
|
+
instance = klass.new( label: "original" )
|
139
|
+
expect( instance.label ).to be_a coerce_class
|
140
|
+
end
|
141
|
+
|
86
142
|
describe "smart" do
|
87
143
|
let( :klass ) do
|
88
144
|
Class.new( base_klass ) do
|
@@ -91,6 +147,7 @@ describe Shamu::Attributes::Assignment do
|
|
91
147
|
|
92
148
|
attribute :user_id
|
93
149
|
attribute :tag_ids
|
150
|
+
attribute :id
|
94
151
|
end
|
95
152
|
end
|
96
153
|
let( :instance ) { klass.new }
|
@@ -109,16 +166,23 @@ describe Shamu::Attributes::Assignment do
|
|
109
166
|
instance.expire_on = value
|
110
167
|
end
|
111
168
|
|
112
|
-
it "coerces nnn_id to
|
169
|
+
it "coerces nnn_id to a model id" do
|
113
170
|
value = double
|
114
|
-
expect( value ).to receive( :
|
171
|
+
expect( value ).to receive( :to_model_id )
|
115
172
|
|
116
173
|
instance.user_id = value
|
117
174
|
end
|
118
175
|
|
119
|
-
it "coerces
|
176
|
+
it "coerces id to a model id" do
|
177
|
+
value = double
|
178
|
+
expect( value ).to receive( :to_model_id )
|
179
|
+
|
180
|
+
instance.id = value
|
181
|
+
end
|
182
|
+
|
183
|
+
it "coerces nnn_ids to an array o model ids" do
|
120
184
|
value = double
|
121
|
-
expect( value ).to receive( :
|
185
|
+
expect( value ).to receive( :to_model_id )
|
122
186
|
|
123
187
|
instance.tag_ids = value
|
124
188
|
end
|
@@ -126,4 +190,4 @@ describe Shamu::Attributes::Assignment do
|
|
126
190
|
end
|
127
191
|
end
|
128
192
|
|
129
|
-
end
|
193
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Shamu::Attributes::CamelCase do
|
4
|
+
let( :klass ) do
|
5
|
+
Class.new do
|
6
|
+
include Shamu::Attributes
|
7
|
+
include Shamu::Attributes::Assignment
|
8
|
+
include Shamu::Attributes::CamelCase
|
9
|
+
|
10
|
+
attribute :name
|
11
|
+
attribute :camel_case
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it "responds to camelcased version" do
|
16
|
+
expect( klass.new( camel_case: "Word" ).camelCase ).to eq "Word"
|
17
|
+
end
|
18
|
+
|
19
|
+
it "assigns camelized version from input args" do
|
20
|
+
expect( klass.new( camelCase: "Word" ).camel_case ).to eq "Word"
|
21
|
+
end
|
22
|
+
|
23
|
+
it "allows short non-camelized words" do
|
24
|
+
expect( klass.new( name: "Pete" ).name ).to eq "Pete"
|
25
|
+
end
|
26
|
+
|
27
|
+
it "assigns the original attribute" do
|
28
|
+
instance = klass.new
|
29
|
+
instance.camelCase = "Worked"
|
30
|
+
|
31
|
+
expect( instance.camel_case ).to eq "Worked"
|
32
|
+
end
|
33
|
+
end
|
@@ -50,4 +50,12 @@ describe Shamu::Attributes::Validation do
|
|
50
50
|
instance.valid?
|
51
51
|
instance.valid?
|
52
52
|
end
|
53
|
-
|
53
|
+
|
54
|
+
it "supports shamu validators with simple hash names" do
|
55
|
+
nested = Class.new( klass ) do
|
56
|
+
attribute :nested, valid: true
|
57
|
+
end
|
58
|
+
|
59
|
+
expect( nested.validators ).to include Shamu::Attributes::Validators::ValidValidator
|
60
|
+
end
|
61
|
+
end
|
@@ -56,6 +56,10 @@ describe Shamu::Attributes do
|
|
56
56
|
it "is false if the attribute has not been set" do
|
57
57
|
expect( klass.new ).not_to be_set :name
|
58
58
|
end
|
59
|
+
|
60
|
+
it "has per attribute set? method" do
|
61
|
+
expect( klass.new( name: "Set" ).name_set? ).to be_truthy
|
62
|
+
end
|
59
63
|
end
|
60
64
|
|
61
65
|
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
require "active_record"
|
3
3
|
require "shamu/entities/active_record"
|
4
|
+
require "shamu/entities/active_record_soft_destroy"
|
4
5
|
|
5
6
|
describe Shamu::Entities::ActiveRecord do
|
6
7
|
use_active_record
|
@@ -37,6 +38,32 @@ describe Shamu::Entities::ActiveRecord do
|
|
37
38
|
expect( relation.limit_value ).to eq 25
|
38
39
|
end
|
39
40
|
|
41
|
+
it "filters by window paging" do
|
42
|
+
klass = Class.new( ActiveRecordSpec::FavoriteScope ) do
|
43
|
+
include Shamu::Entities::ListScope::WindowPaging
|
44
|
+
end
|
45
|
+
|
46
|
+
scope = klass.new( first: 10, after: 30 )
|
47
|
+
relation = ActiveRecordSpec::Favorite.by_list_scope( scope )
|
48
|
+
|
49
|
+
expect( relation.offset_value ).to eq 30
|
50
|
+
expect( relation.limit_value ).to eq 10
|
51
|
+
end
|
52
|
+
|
53
|
+
it "filters by inverse window paging" do
|
54
|
+
klass = Class.new( ActiveRecordSpec::FavoriteScope ) do
|
55
|
+
include Shamu::Entities::ListScope::WindowPaging
|
56
|
+
end
|
57
|
+
|
58
|
+
scope = klass.new
|
59
|
+
expect( scope ).to receive( :reverse_sort! ).at_least( :once )
|
60
|
+
scope.assign_attributes( last: 10, before: 30 )
|
61
|
+
relation = ActiveRecordSpec::Favorite.by_list_scope( scope )
|
62
|
+
|
63
|
+
expect( relation.offset_value ).to eq 30
|
64
|
+
expect( relation.limit_value ).to eq 10
|
65
|
+
end
|
66
|
+
|
40
67
|
it "filters by dates" do
|
41
68
|
klass = Class.new( ActiveRecordSpec::FavoriteScope ) do
|
42
69
|
include Shamu::Entities::ListScope::Dates
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require_relative "entity_lookup_models"
|
3
|
+
|
4
|
+
|
5
|
+
describe Shamu::Entities::EntityLookupService do
|
6
|
+
|
7
|
+
let( :service ) do
|
8
|
+
scorpion.new( Shamu::Entities::EntityLookupService, { "Water" => EntityLookupServiceSpecs::CustomService }, {} )
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "#service_class_for" do
|
12
|
+
it "finds default service" do
|
13
|
+
expect( service.service_class_for( "EntityLookupServiceSpecs::Example" ) ).to be \
|
14
|
+
EntityLookupServiceSpecs::ExamplesService
|
15
|
+
end
|
16
|
+
|
17
|
+
it "uses custom service" do
|
18
|
+
expect( service.service_class_for( "Water" ) ).to be EntityLookupServiceSpecs::CustomService
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#ids" do
|
23
|
+
it "maps entities to their entity path" do
|
24
|
+
entity = EntityLookupServiceSpecs::ExampleEntity.new( id: 5 )
|
25
|
+
expect( service.ids( entity ) ).to eq( [ "EntityLookupServiceSpecs::Example[5]" ] )
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#record_ids" do
|
30
|
+
it "gets the original record id" do
|
31
|
+
entity = EntityLookupServiceSpecs::ExampleEntity.new( id: 5 )
|
32
|
+
id = service.ids( entity ).first
|
33
|
+
|
34
|
+
expect( service.record_ids( id ).first ).to eq( 5 )
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#lookup" do
|
39
|
+
let( :examples_service ) { double( EntityLookupServiceSpecs::ExamplesService ) }
|
40
|
+
let( :custom_service ) { double( EntityLookupServiceSpecs::CustomService ) }
|
41
|
+
|
42
|
+
before( :each ) do
|
43
|
+
allow( service.scorpion ).to receive( :fetch )
|
44
|
+
.with( EntityLookupServiceSpecs::ExamplesService )
|
45
|
+
.and_return( examples_service )
|
46
|
+
|
47
|
+
allow( service.scorpion ).to receive( :fetch )
|
48
|
+
.with( EntityLookupServiceSpecs::CustomService )
|
49
|
+
.and_return( custom_service )
|
50
|
+
end
|
51
|
+
|
52
|
+
it "finds an entity" do
|
53
|
+
expect( examples_service ).to receive( :lookup ).with( "4" ).and_return [ "Found" ]
|
54
|
+
|
55
|
+
expect( service.lookup( "EntityLookupServiceSpecs::Example[4]" ).to_a ).to eq [ "Found" ]
|
56
|
+
end
|
57
|
+
|
58
|
+
it "batches common entity types" do
|
59
|
+
expect( examples_service ).to receive( :lookup ).with( "4", "91" ).and_return( [ "One", "Two" ] )
|
60
|
+
|
61
|
+
returned = service.lookup( "EntityLookupServiceSpecs::Example[4]", "EntityLookupServiceSpecs::Example[91]" )
|
62
|
+
expect( returned.to_a ).to eq [ "One", "Two" ]
|
63
|
+
end
|
64
|
+
|
65
|
+
it "returns in same order" do
|
66
|
+
expect( examples_service ).to receive( :lookup ).with( "4", "91" ).and_return( [ "One", "Two" ] )
|
67
|
+
expect( custom_service ).to receive( :lookup ).with( "500" ).and_return( [ "Agua" ] )
|
68
|
+
|
69
|
+
returned = service.lookup( "EntityLookupServiceSpecs::Example[4]",
|
70
|
+
"Water[500]",
|
71
|
+
"EntityLookupServiceSpecs::Example[91]" )
|
72
|
+
|
73
|
+
expect( returned.to_a ).to eq [ "One", "Agua", "Two" ]
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|