graphiti-rb 1.0.alpha.1

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.
Files changed (95) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +3 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +20 -0
  6. data/.yardopts +2 -0
  7. data/Appraisals +11 -0
  8. data/CODE_OF_CONDUCT.md +49 -0
  9. data/Gemfile +12 -0
  10. data/Guardfile +32 -0
  11. data/LICENSE.txt +21 -0
  12. data/README.md +75 -0
  13. data/Rakefile +15 -0
  14. data/bin/appraisal +17 -0
  15. data/bin/console +14 -0
  16. data/bin/rspec +17 -0
  17. data/bin/setup +8 -0
  18. data/gemfiles/rails_4.gemfile +17 -0
  19. data/gemfiles/rails_5.gemfile +17 -0
  20. data/graphiti.gemspec +34 -0
  21. data/lib/generators/jsonapi/resource_generator.rb +169 -0
  22. data/lib/generators/jsonapi/templates/application_resource.rb.erb +15 -0
  23. data/lib/generators/jsonapi/templates/controller.rb.erb +61 -0
  24. data/lib/generators/jsonapi/templates/create_request_spec.rb.erb +30 -0
  25. data/lib/generators/jsonapi/templates/destroy_request_spec.rb.erb +20 -0
  26. data/lib/generators/jsonapi/templates/index_request_spec.rb.erb +22 -0
  27. data/lib/generators/jsonapi/templates/resource.rb.erb +11 -0
  28. data/lib/generators/jsonapi/templates/resource_reads_spec.rb.erb +62 -0
  29. data/lib/generators/jsonapi/templates/resource_writes_spec.rb.erb +63 -0
  30. data/lib/generators/jsonapi/templates/show_request_spec.rb.erb +21 -0
  31. data/lib/generators/jsonapi/templates/update_request_spec.rb.erb +34 -0
  32. data/lib/graphiti-rb.rb +1 -0
  33. data/lib/graphiti.rb +121 -0
  34. data/lib/graphiti/adapters/abstract.rb +516 -0
  35. data/lib/graphiti/adapters/active_record.rb +6 -0
  36. data/lib/graphiti/adapters/active_record/base.rb +249 -0
  37. data/lib/graphiti/adapters/active_record/belongs_to_sideload.rb +17 -0
  38. data/lib/graphiti/adapters/active_record/has_many_sideload.rb +17 -0
  39. data/lib/graphiti/adapters/active_record/has_one_sideload.rb +17 -0
  40. data/lib/graphiti/adapters/active_record/inferrence.rb +12 -0
  41. data/lib/graphiti/adapters/active_record/many_to_many_sideload.rb +30 -0
  42. data/lib/graphiti/adapters/null.rb +236 -0
  43. data/lib/graphiti/base.rb +70 -0
  44. data/lib/graphiti/configuration.rb +21 -0
  45. data/lib/graphiti/context.rb +16 -0
  46. data/lib/graphiti/deserializer.rb +208 -0
  47. data/lib/graphiti/errors.rb +309 -0
  48. data/lib/graphiti/extensions/boolean_attribute.rb +33 -0
  49. data/lib/graphiti/extensions/extra_attribute.rb +70 -0
  50. data/lib/graphiti/extensions/temp_id.rb +26 -0
  51. data/lib/graphiti/filter_operators.rb +25 -0
  52. data/lib/graphiti/hash_renderer.rb +57 -0
  53. data/lib/graphiti/jsonapi_serializable_ext.rb +50 -0
  54. data/lib/graphiti/query.rb +251 -0
  55. data/lib/graphiti/rails.rb +28 -0
  56. data/lib/graphiti/railtie.rb +74 -0
  57. data/lib/graphiti/renderer.rb +60 -0
  58. data/lib/graphiti/resource.rb +110 -0
  59. data/lib/graphiti/resource/configuration.rb +239 -0
  60. data/lib/graphiti/resource/dsl.rb +138 -0
  61. data/lib/graphiti/resource/interface.rb +32 -0
  62. data/lib/graphiti/resource/polymorphism.rb +68 -0
  63. data/lib/graphiti/resource/sideloading.rb +102 -0
  64. data/lib/graphiti/resource_proxy.rb +127 -0
  65. data/lib/graphiti/responders.rb +19 -0
  66. data/lib/graphiti/runner.rb +25 -0
  67. data/lib/graphiti/scope.rb +98 -0
  68. data/lib/graphiti/scoping/base.rb +99 -0
  69. data/lib/graphiti/scoping/default_filter.rb +58 -0
  70. data/lib/graphiti/scoping/extra_attributes.rb +29 -0
  71. data/lib/graphiti/scoping/filter.rb +93 -0
  72. data/lib/graphiti/scoping/filterable.rb +36 -0
  73. data/lib/graphiti/scoping/paginate.rb +87 -0
  74. data/lib/graphiti/scoping/sort.rb +64 -0
  75. data/lib/graphiti/sideload.rb +281 -0
  76. data/lib/graphiti/sideload/belongs_to.rb +34 -0
  77. data/lib/graphiti/sideload/has_many.rb +16 -0
  78. data/lib/graphiti/sideload/has_one.rb +9 -0
  79. data/lib/graphiti/sideload/many_to_many.rb +24 -0
  80. data/lib/graphiti/sideload/polymorphic_belongs_to.rb +108 -0
  81. data/lib/graphiti/stats/dsl.rb +89 -0
  82. data/lib/graphiti/stats/payload.rb +49 -0
  83. data/lib/graphiti/types.rb +172 -0
  84. data/lib/graphiti/util/attribute_check.rb +88 -0
  85. data/lib/graphiti/util/field_params.rb +16 -0
  86. data/lib/graphiti/util/hash.rb +51 -0
  87. data/lib/graphiti/util/hooks.rb +33 -0
  88. data/lib/graphiti/util/include_params.rb +39 -0
  89. data/lib/graphiti/util/persistence.rb +219 -0
  90. data/lib/graphiti/util/relationship_payload.rb +64 -0
  91. data/lib/graphiti/util/serializer_attributes.rb +97 -0
  92. data/lib/graphiti/util/sideload.rb +33 -0
  93. data/lib/graphiti/util/validation_response.rb +78 -0
  94. data/lib/graphiti/version.rb +3 -0
  95. metadata +317 -0
@@ -0,0 +1,6 @@
1
+ require 'graphiti/adapters/active_record/base'
2
+ require 'graphiti/adapters/active_record/inferrence'
3
+ require 'graphiti/adapters/active_record/has_many_sideload'
4
+ require 'graphiti/adapters/active_record/belongs_to_sideload'
5
+ require 'graphiti/adapters/active_record/has_one_sideload'
6
+ require 'graphiti/adapters/active_record/many_to_many_sideload'
@@ -0,0 +1,249 @@
1
+ module Graphiti
2
+ module Adapters
3
+ module ActiveRecord
4
+ class Base < ::Graphiti::Adapters::Abstract
5
+ def filter_string_eq(scope, attribute, value, is_not: false)
6
+ column = scope.klass.arel_table[attribute]
7
+ clause = column.lower.eq_any(value.map(&:downcase))
8
+ is_not ? scope.where.not(clause) : scope.where(clause)
9
+ end
10
+
11
+ def filter_string_eql(scope, attribute, value, is_not: false)
12
+ clause = { attribute => value }
13
+ is_not ? scope.where.not(clause) : scope.where(clause)
14
+ end
15
+
16
+ def filter_string_not_eq(scope, attribute, value)
17
+ filter_string_eq(scope, attribute, value, is_not: true)
18
+ end
19
+
20
+ def filter_string_not_eql(scope, attribute, value)
21
+ filter_string_eql(scope, attribute, value, is_not: true)
22
+ end
23
+
24
+ def filter_string_prefix(scope, attribute, value, is_not: false)
25
+ column = scope.klass.arel_table[attribute]
26
+ map = value.map { |v| "#{v}%" }
27
+ clause = column.lower.matches_any(map)
28
+ is_not ? scope.where.not(clause) : scope.where(clause)
29
+ end
30
+
31
+ def filter_string_not_prefix(scope, attribute, value)
32
+ filter_string_prefix(scope, attribute, value, is_not: true)
33
+ end
34
+
35
+ def filter_string_suffix(scope, attribute, value, is_not: false)
36
+ column = scope.klass.arel_table[attribute]
37
+ map = value.map { |v| "%#{v}" }
38
+ clause = column.lower.matches_any(map)
39
+ is_not ? scope.where.not(clause) : scope.where(clause)
40
+ end
41
+
42
+ def filter_string_not_suffix(scope, attribute, value)
43
+ filter_string_suffix(scope, attribute, value, is_not: true)
44
+ end
45
+
46
+ def filter_string_match(scope, attribute, value, is_not: false)
47
+ column = scope.klass.arel_table[attribute]
48
+ map = value.map { |v| "%#{v.downcase}%" }
49
+ clause = column.lower.matches_any(map)
50
+ is_not ? scope.where.not(clause) : scope.where(clause)
51
+ end
52
+
53
+ def filter_string_not_match(scope, attribute, value)
54
+ filter_string_match(scope, attribute, value, is_not: true)
55
+ end
56
+
57
+ def filter_integer_eq(scope, attribute, value, is_not: false)
58
+ clause = { attribute => value }
59
+ is_not ? scope.where.not(clause) : scope.where(clause)
60
+ end
61
+ alias :filter_float_eq :filter_integer_eq
62
+ alias :filter_big_decimal_eq :filter_integer_eq
63
+ alias :filter_date_eq :filter_integer_eq
64
+ alias :filter_boolean_eq :filter_integer_eq
65
+
66
+ def filter_integer_not_eq(scope, attribute, value)
67
+ filter_integer_eq(scope, attribute, value, is_not: true)
68
+ end
69
+ alias :filter_float_not_eq :filter_integer_not_eq
70
+ alias :filter_big_decimal_not_eq :filter_integer_not_eq
71
+ alias :filter_date_not_eq :filter_integer_not_eq
72
+
73
+ def filter_integer_gt(scope, attribute, value)
74
+ column = scope.klass.arel_table[attribute]
75
+ scope.where(column.gt_any(value))
76
+ end
77
+ alias :filter_float_gt :filter_integer_gt
78
+ alias :filter_big_decimal_gt :filter_integer_gt
79
+ alias :filter_datetime_gt :filter_integer_gt
80
+ alias :filter_date_gt :filter_integer_gt
81
+
82
+ def filter_integer_gte(scope, attribute, value)
83
+ column = scope.klass.arel_table[attribute]
84
+ scope.where(column.gteq_any(value))
85
+ end
86
+ alias :filter_float_gte :filter_integer_gte
87
+ alias :filter_big_decimal_gte :filter_integer_gte
88
+ alias :filter_datetime_gte :filter_integer_gte
89
+ alias :filter_date_gte :filter_integer_gte
90
+
91
+ def filter_integer_lt(scope, attribute, value)
92
+ column = scope.klass.arel_table[attribute]
93
+ scope.where(column.lt_any(value))
94
+ end
95
+ alias :filter_float_lt :filter_integer_lt
96
+ alias :filter_big_decimal_lt :filter_integer_lt
97
+ alias :filter_datetime_lt :filter_integer_lt
98
+ alias :filter_date_lt :filter_integer_lt
99
+
100
+ def filter_integer_lte(scope, attribute, value)
101
+ column = scope.klass.arel_table[attribute]
102
+ scope.where(column.lteq_any(value))
103
+ end
104
+ alias :filter_float_lte :filter_integer_lte
105
+ alias :filter_big_decimal_lte :filter_integer_lte
106
+ alias :filter_date_lte :filter_integer_lte
107
+
108
+ # Ensure fractional seconds don't matter
109
+ def filter_datetime_eq(scope, attribute, value, is_not: false)
110
+ ranges = value.map { |v| (v..v+1.second-0.00000001) }
111
+ clause = { attribute => ranges }
112
+ is_not ? scope.where.not(clause) : scope.where(clause)
113
+ end
114
+
115
+ def filter_datetime_not_eq(scope, attribute, value)
116
+ filter_datetime_eq(scope, attribute, value, is_not: true)
117
+ end
118
+
119
+ def filter_datetime_lte(scope, attribute, value)
120
+ value = value.map { |v| v + 1.second-0.00000001 }
121
+ column = scope.klass.arel_table[attribute]
122
+ scope.where(column.lteq_any(value))
123
+ end
124
+
125
+ def base_scope(model)
126
+ model.all
127
+ end
128
+
129
+ # (see Adapters::Abstract#order)
130
+ def order(scope, attribute, direction)
131
+ scope.order(attribute => direction)
132
+ end
133
+
134
+ # (see Adapters::Abstract#paginate)
135
+ def paginate(scope, current_page, per_page)
136
+ scope.page(current_page).per(per_page)
137
+ end
138
+
139
+ # (see Adapters::Abstract#count)
140
+ def count(scope, attr)
141
+ if attr.to_sym == :total
142
+ scope.distinct.count
143
+ else
144
+ scope.distinct.count(attr)
145
+ end
146
+ end
147
+
148
+ # (see Adapters::Abstract#average)
149
+ def average(scope, attr)
150
+ scope.average(attr).to_f
151
+ end
152
+
153
+ # (see Adapters::Abstract#sum)
154
+ def sum(scope, attr)
155
+ scope.sum(attr)
156
+ end
157
+
158
+ # (see Adapters::Abstract#maximum)
159
+ def maximum(scope, attr)
160
+ scope.maximum(attr)
161
+ end
162
+
163
+ # (see Adapters::Abstract#minimum)
164
+ def minimum(scope, attr)
165
+ scope.minimum(attr)
166
+ end
167
+
168
+ # (see Adapters::Abstract#resolve)
169
+ def resolve(scope)
170
+ scope.to_a
171
+ end
172
+
173
+ # Run this write request within an ActiveRecord transaction
174
+ # @param [Class] model_class The ActiveRecord class we are saving
175
+ # @return Result of yield
176
+ # @see Adapters::Abstract#transaction
177
+ def transaction(model_class)
178
+ model_class.transaction do
179
+ yield
180
+ end
181
+ end
182
+
183
+ def sideloading_classes
184
+ {
185
+ has_many: HasManySideload,
186
+ has_one: HasOneSideload,
187
+ belongs_to: BelongsToSideload,
188
+ many_to_many: ManyToManySideload
189
+ }
190
+ end
191
+
192
+ def associate_all(parent, children, association_name, association_type)
193
+ association = parent.association(association_name)
194
+ association.loaded!
195
+
196
+ children.each do |child|
197
+ if association_type == :many_to_many &&
198
+ !parent.send(association_name).exists?(child.id) &&
199
+ [:create, :update].include?(Graphiti.context[:namespace])
200
+ parent.send(association_name) << child
201
+ else
202
+ target = association.instance_variable_get(:@target)
203
+ target |= [child]
204
+ association.instance_variable_set(:@target, target)
205
+ end
206
+ end
207
+ end
208
+
209
+ def associate(parent, child, association_name, association_type)
210
+ association = parent.association(association_name)
211
+ association.loaded!
212
+ association.instance_variable_set(:@target, child)
213
+ end
214
+
215
+ # When a has_and_belongs_to_many relationship, we don't have a foreign
216
+ # key that can be null'd. Instead, go through the ActiveRecord API.
217
+ # @see Adapters::Abstract#disassociate
218
+ def disassociate(parent, child, association_name, association_type)
219
+ if association_type == :many_to_many
220
+ parent.send(association_name).delete(child)
221
+ else
222
+ # Nothing to do here, happened when we merged foreign key
223
+ end
224
+ end
225
+
226
+ # (see Adapters::Abstract#create)
227
+ def create(model_class, create_params)
228
+ instance = model_class.new(create_params)
229
+ instance.save
230
+ instance
231
+ end
232
+
233
+ # (see Adapters::Abstract#update)
234
+ def update(model_class, update_params)
235
+ instance = model_class.find(update_params.delete(:id))
236
+ instance.update_attributes(update_params)
237
+ instance
238
+ end
239
+
240
+ # (see Adapters::Abstract#destroy)
241
+ def destroy(model_class, id)
242
+ instance = model_class.find(id)
243
+ instance.destroy
244
+ instance
245
+ end
246
+ end
247
+ end
248
+ end
249
+ end
@@ -0,0 +1,17 @@
1
+ module Graphiti
2
+ module Adapters
3
+ module ActiveRecord
4
+ class BelongsToSideload < Sideload::BelongsTo
5
+ include Inferrence
6
+
7
+ def default_base_scope
8
+ resource_class.model.all
9
+ end
10
+
11
+ def scope(parent_ids)
12
+ base_scope.where(primary_key => parent_ids)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Graphiti
2
+ module Adapters
3
+ module ActiveRecord # todo change
4
+ class HasManySideload < Sideload::HasMany
5
+ include Inferrence
6
+
7
+ def default_base_scope
8
+ resource_class.model.all
9
+ end
10
+
11
+ def scope(parent_ids)
12
+ base_scope.where(foreign_key => parent_ids)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Graphiti
2
+ module Adapters
3
+ module ActiveRecord
4
+ class HasOneSideload < Sideload::HasOne
5
+ include Inferrence
6
+
7
+ def default_base_scope
8
+ resource_class.model.all
9
+ end
10
+
11
+ def scope(parent_ids)
12
+ base_scope.where(foreign_key => parent_ids)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,12 @@
1
+ module Graphiti
2
+ module Adapters
3
+ module ActiveRecord
4
+ module Inferrence
5
+ def infer_foreign_key
6
+ parent_model = parent_resource_class.model
7
+ parent_model.reflections[association_name.to_s].foreign_key.to_sym
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,30 @@
1
+ module Graphiti
2
+ module Adapters
3
+ module ActiveRecord
4
+ class ManyToManySideload < Sideload::ManyToMany
5
+ def default_base_scope
6
+ resource_class.model.all
7
+ end
8
+
9
+ def through_table_name
10
+ @through_table_name ||= parent_resource_class.model
11
+ .reflections[through.to_s].klass.table_name
12
+ end
13
+
14
+ def scope(parent_ids)
15
+ base_scope
16
+ .includes(through)
17
+ .where(through_table_name => { true_foreign_key => parent_ids })
18
+ .distinct
19
+ end
20
+
21
+ def infer_foreign_key
22
+ parent_model = parent_resource_class.model
23
+ key = parent_model.reflections[name.to_s].options[:through]
24
+ value = parent_model.reflections[key.to_s].foreign_key.to_sym
25
+ { key => value }
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,236 @@
1
+ module Graphiti
2
+ module Adapters
3
+ # The Null adapter is a 'pass-through' adapter. It won't modify the scope.
4
+ # Useful when your customization does not support all possible
5
+ # configuration (e.g. the service you hit does not support sorting)
6
+ class Null < Abstract
7
+ def filter_string_eq(scope, attribute, value)
8
+ scope
9
+ end
10
+
11
+ def filter_string_eql(scope, attribute, value)
12
+ scope
13
+ end
14
+
15
+ def filter_string_not_eq(scope, attribute, value)
16
+ scope
17
+ end
18
+
19
+ def filter_string_not_eql(scope, attribute, value)
20
+ scope
21
+ end
22
+
23
+ def filter_string_prefix_eq(scope, attribute, value)
24
+ scope
25
+ end
26
+
27
+ def filter_string_not_prefix_eq(scope, attribute, value)
28
+ scope
29
+ end
30
+
31
+ def filter_string_suffix_eq(scope, attribute, value)
32
+ scope
33
+ end
34
+
35
+ def filter_string_not_suffix_eq(scope, attribute, value)
36
+ scope
37
+ end
38
+
39
+ def filter_string_match_eq(scope, attribute, value)
40
+ scope
41
+ end
42
+
43
+ def filter_string_not_match_eq(scope, attribute, value)
44
+ scope
45
+ end
46
+
47
+ def filter_integer_eq(scope, attribute, value)
48
+ scope
49
+ end
50
+
51
+ def filter_integer_not_eq(scope, attribute, value)
52
+ scope
53
+ end
54
+
55
+ def filter_integer_gt(scope, attribute, value)
56
+ scope
57
+ end
58
+
59
+ def filter_integer_gte(scope, attribute, value)
60
+ scope
61
+ end
62
+
63
+ def filter_integer_lt(scope, attribute, value)
64
+ scope
65
+ end
66
+
67
+ def filter_integer_lte(scope, attribute, value)
68
+ scope
69
+ end
70
+
71
+ def filter_datetime_eq(scope, attribute, value)
72
+ scope
73
+ end
74
+
75
+ def filter_datetime_not_eq(scope, attribute, value)
76
+ scope
77
+ end
78
+
79
+ def filter_datetime_lte(scope, attribute, value)
80
+ scope
81
+ end
82
+
83
+ def filter_float_eq(scope, attribute, value)
84
+ scope
85
+ end
86
+
87
+ def filter_float_not_eq(scope, attribute, value)
88
+ scope
89
+ end
90
+
91
+ def filter_float_gt(scope, attribute, value)
92
+ scope
93
+ end
94
+
95
+ def filter_float_gte(scope, attribute, value)
96
+ scope
97
+ end
98
+
99
+ def filter_float_lt(scope, attribute, value)
100
+ scope
101
+ end
102
+
103
+ def filter_float_lte(scope, attribute, value)
104
+ scope
105
+ end
106
+
107
+ def filter_decimal_eq(scope, attribute, value)
108
+ scope
109
+ end
110
+
111
+ def filter_decimal_not_eq(scope, attribute, value)
112
+ scope
113
+ end
114
+
115
+ def filter_decimal_gt(scope, attribute, value)
116
+ scope
117
+ end
118
+
119
+ def filter_decimal_gte(scope, attribute, value)
120
+ scope
121
+ end
122
+
123
+ def filter_decimal_lt(scope, attribute, value)
124
+ scope
125
+ end
126
+
127
+ def filter_decimal_lte(scope, attribute, value)
128
+ scope
129
+ end
130
+
131
+ def filter_datetime_eq(scope, attribute, value)
132
+ scope
133
+ end
134
+
135
+ def filter_datetime_not_eq(scope, attribute, value)
136
+ scope
137
+ end
138
+
139
+ def filter_datetime_gt(scope, attribute, value)
140
+ scope
141
+ end
142
+
143
+ def filter_datetime_gte(scope, attribute, value)
144
+ scope
145
+ end
146
+
147
+ def filter_datetime_lt(scope, attribute, value)
148
+ scope
149
+ end
150
+
151
+ def filter_datetime_lte(scope, attribute, value)
152
+ scope
153
+ end
154
+
155
+ def filter_date_eq(scope, attribute, value)
156
+ scope
157
+ end
158
+
159
+ def filter_date_not_eq(scope, attribute, value)
160
+ scope
161
+ end
162
+
163
+ def filter_date_gt(scope, attribute, value)
164
+ scope
165
+ end
166
+
167
+ def filter_date_gte(scope, attribute, value)
168
+ scope
169
+ end
170
+
171
+ def filter_date_lt(scope, attribute, value)
172
+ scope
173
+ end
174
+
175
+ def filter_date_lte(scope, attribute, value)
176
+ scope
177
+ end
178
+
179
+ def filter_boolean_eq(scope, attribute, value)
180
+ scope
181
+ end
182
+
183
+ def base_scope(model)
184
+ raise 'Null adapter has no base scope!'
185
+ end
186
+
187
+ # (see Adapters::Abstract#order)
188
+ def order(scope, attribute, direction)
189
+ scope
190
+ end
191
+
192
+ # (see Adapters::Abstract#paginate)
193
+ def paginate(scope, current_page, per_page)
194
+ scope
195
+ end
196
+
197
+ # (see Adapters::Abstract#count)
198
+ def count(scope, attr)
199
+ scope
200
+ end
201
+
202
+ # (see Adapters::Abstract#average)
203
+ def average(scope, attr)
204
+ scope
205
+ end
206
+
207
+ # (see Adapters::Abstract#sum)
208
+ def sum(scope, attr)
209
+ scope
210
+ end
211
+
212
+ # (see Adapters::Abstract#sum)
213
+ def maximum(scope, attr)
214
+ scope
215
+ end
216
+
217
+ # (see Adapters::Abstract#minimum)
218
+ def minimum(scope, attr)
219
+ scope
220
+ end
221
+
222
+ # Since this is a null adapter, just yield
223
+ # @see Adapters::ActiveRecord#transaction
224
+ # @return Result of yield
225
+ # @param [Class] model_class The class we're operating on
226
+ def transaction(model_class)
227
+ yield
228
+ end
229
+
230
+ # (see Adapters::Abstract#resolve)
231
+ def resolve(scope)
232
+ scope
233
+ end
234
+ end
235
+ end
236
+ end