graphiti 1.0.alpha.18 → 1.0.alpha.19
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/lib/generators/graphiti/templates/application_resource.rb.erb +1 -1
- data/lib/generators/graphiti/templates/create_request_spec.rb.erb +1 -1
- data/lib/generators/graphiti/templates/destroy_request_spec.rb.erb +1 -1
- data/lib/generators/graphiti/templates/index_request_spec.rb.erb +1 -1
- data/lib/generators/graphiti/templates/show_request_spec.rb.erb +1 -1
- data/lib/generators/graphiti/templates/update_request_spec.rb.erb +1 -1
- data/lib/graphiti/adapters/abstract.rb +1 -1
- data/lib/graphiti/adapters/active_record.rb +275 -6
- data/lib/graphiti/adapters/active_record/belongs_to_sideload.rb +7 -13
- data/lib/graphiti/adapters/active_record/has_many_sideload.rb +7 -13
- data/lib/graphiti/adapters/active_record/has_one_sideload.rb +7 -13
- data/lib/graphiti/adapters/active_record/inferrence.rb +10 -16
- data/lib/graphiti/adapters/active_record/many_to_many_sideload.rb +13 -19
- data/lib/graphiti/version.rb +1 -1
- metadata +1 -2
- data/lib/graphiti/adapters/active_record/base.rb +0 -271
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 87db44b8b56a2b6341dd62b0d1ef7bdf37703127
|
4
|
+
data.tar.gz: 934774ad413a6ac695b612253249620efc0f7c9b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 51ca1feec8cc701fd3786449d747f5ea44f72fd4e533fcb598793f74dc550e87aaa39a53eb4144e623653503a690a25d9ce2bf84b1bae253a66d92e5d84ab2fb
|
7
|
+
data.tar.gz: bf9acf3ecc4b5be6db1bc9d3e46c3591b59d48391bfa941fedf3c525418e8a8d393d91fee4ba9745e25a2fda1d92fb4499f500be323a55524a8c5cee2e72b9d8
|
@@ -9,6 +9,6 @@ class ApplicationResource < Graphiti::Resource
|
|
9
9
|
# Subclasses can still override this default.
|
10
10
|
<%- end -%>
|
11
11
|
self.abstract_class = true
|
12
|
-
self.adapter = Graphiti::Adapters::ActiveRecord
|
12
|
+
self.adapter = Graphiti::Adapters::ActiveRecord
|
13
13
|
self.endpoint_namespace = '<%= api_namespace %>'
|
14
14
|
end
|
@@ -2,7 +2,7 @@ require 'rails_helper'
|
|
2
2
|
|
3
3
|
RSpec.describe "<%= type %>#create", type: :request do
|
4
4
|
subject(:make_request) do
|
5
|
-
jsonapi_post "
|
5
|
+
jsonapi_post "<%= api_namespace %>/<%= type %>", payload
|
6
6
|
end
|
7
7
|
|
8
8
|
describe 'basic create' do
|
@@ -2,7 +2,7 @@ require 'rails_helper'
|
|
2
2
|
|
3
3
|
RSpec.describe "<%= type %>#destroy", type: :request do
|
4
4
|
subject(:make_request) do
|
5
|
-
jsonapi_delete "
|
5
|
+
jsonapi_delete "<%= api_namespace %>/<%= type %>/#{<%= var %>.id}"
|
6
6
|
end
|
7
7
|
|
8
8
|
describe 'basic destroy' do
|
@@ -4,7 +4,7 @@ RSpec.describe "<%= type %>#index", type: :request do
|
|
4
4
|
let(:params) { {} }
|
5
5
|
|
6
6
|
subject(:make_request) do
|
7
|
-
jsonapi_get "
|
7
|
+
jsonapi_get "<%= api_namespace %>/<%= type %>", params: params
|
8
8
|
end
|
9
9
|
|
10
10
|
describe 'basic fetch' do
|
@@ -4,7 +4,7 @@ RSpec.describe "<%= type %>#show", type: :request do
|
|
4
4
|
let(:params) { {} }
|
5
5
|
|
6
6
|
subject(:make_request) do
|
7
|
-
jsonapi_get "
|
7
|
+
jsonapi_get "<%= api_namespace %>/<%= type %>/#{<%= var %>.id}", params: params
|
8
8
|
end
|
9
9
|
|
10
10
|
describe 'basic fetch' do
|
@@ -2,7 +2,7 @@ require 'rails_helper'
|
|
2
2
|
|
3
3
|
RSpec.describe "<%= type %>#update", type: :request do
|
4
4
|
subject(:make_request) do
|
5
|
-
jsonapi_put "
|
5
|
+
jsonapi_put "<%= api_namespace %>/<%= type %>/#{<%= var %>.id}", payload
|
6
6
|
end
|
7
7
|
|
8
8
|
describe 'basic update' do
|
@@ -469,7 +469,7 @@ module Graphiti
|
|
469
469
|
|
470
470
|
def activerecord_adapter
|
471
471
|
@activerecord_adapter ||=
|
472
|
-
::Graphiti::Adapters::ActiveRecord
|
472
|
+
::Graphiti::Adapters::ActiveRecord.new(resource)
|
473
473
|
end
|
474
474
|
|
475
475
|
def activerecord_associate?(parent, child, association_name)
|
@@ -1,6 +1,275 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
require 'graphiti/adapters/active_record/
|
5
|
-
require 'graphiti/adapters/active_record/
|
6
|
-
require 'graphiti/adapters/active_record/
|
1
|
+
module Graphiti
|
2
|
+
module Adapters
|
3
|
+
class ActiveRecord < ::Graphiti::Adapters::Abstract
|
4
|
+
require 'graphiti/adapters/active_record/inferrence'
|
5
|
+
require 'graphiti/adapters/active_record/has_many_sideload'
|
6
|
+
require 'graphiti/adapters/active_record/belongs_to_sideload'
|
7
|
+
require 'graphiti/adapters/active_record/has_one_sideload'
|
8
|
+
require 'graphiti/adapters/active_record/many_to_many_sideload'
|
9
|
+
|
10
|
+
def self.sideloading_classes
|
11
|
+
{
|
12
|
+
has_many: Graphiti::Adapters::ActiveRecord::HasManySideload,
|
13
|
+
has_one: Graphiti::Adapters::ActiveRecord::HasOneSideload,
|
14
|
+
belongs_to: Graphiti::Adapters::ActiveRecord::BelongsToSideload,
|
15
|
+
many_to_many: Graphiti::Adapters::ActiveRecord::ManyToManySideload
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def filter_eq(scope, attribute, value)
|
20
|
+
scope.where(attribute => value)
|
21
|
+
end
|
22
|
+
alias :filter_integer_eq :filter_eq
|
23
|
+
alias :filter_float_eq :filter_eq
|
24
|
+
alias :filter_big_decimal_eq :filter_eq
|
25
|
+
alias :filter_date_eq :filter_eq
|
26
|
+
alias :filter_boolean_eq :filter_eq
|
27
|
+
|
28
|
+
def filter_not_eq(scope, attribute, value)
|
29
|
+
scope.where.not(attribute => value)
|
30
|
+
end
|
31
|
+
alias :filter_integer_not_eq :filter_not_eq
|
32
|
+
alias :filter_float_not_eq :filter_not_eq
|
33
|
+
alias :filter_big_decimal_not_eq :filter_not_eq
|
34
|
+
alias :filter_date_not_eq :filter_not_eq
|
35
|
+
alias :filter_boolean_not_eq :filter_not_eq
|
36
|
+
|
37
|
+
def filter_string_eq(scope, attribute, value, is_not: false)
|
38
|
+
column = scope.klass.arel_table[attribute]
|
39
|
+
clause = column.lower.eq_any(value.map(&:downcase))
|
40
|
+
is_not ? scope.where.not(clause) : scope.where(clause)
|
41
|
+
end
|
42
|
+
|
43
|
+
def filter_string_eql(scope, attribute, value, is_not: false)
|
44
|
+
clause = { attribute => value }
|
45
|
+
is_not ? scope.where.not(clause) : scope.where(clause)
|
46
|
+
end
|
47
|
+
|
48
|
+
def filter_string_not_eq(scope, attribute, value)
|
49
|
+
filter_string_eq(scope, attribute, value, is_not: true)
|
50
|
+
end
|
51
|
+
|
52
|
+
def filter_string_not_eql(scope, attribute, value)
|
53
|
+
filter_string_eql(scope, attribute, value, is_not: true)
|
54
|
+
end
|
55
|
+
|
56
|
+
def filter_string_prefix(scope, attribute, value, is_not: false)
|
57
|
+
column = scope.klass.arel_table[attribute]
|
58
|
+
map = value.map { |v| "#{v}%" }
|
59
|
+
clause = column.lower.matches_any(map)
|
60
|
+
is_not ? scope.where.not(clause) : scope.where(clause)
|
61
|
+
end
|
62
|
+
|
63
|
+
def filter_string_not_prefix(scope, attribute, value)
|
64
|
+
filter_string_prefix(scope, attribute, value, is_not: true)
|
65
|
+
end
|
66
|
+
|
67
|
+
def filter_string_suffix(scope, attribute, value, is_not: false)
|
68
|
+
column = scope.klass.arel_table[attribute]
|
69
|
+
map = value.map { |v| "%#{v}" }
|
70
|
+
clause = column.lower.matches_any(map)
|
71
|
+
is_not ? scope.where.not(clause) : scope.where(clause)
|
72
|
+
end
|
73
|
+
|
74
|
+
def filter_string_not_suffix(scope, attribute, value)
|
75
|
+
filter_string_suffix(scope, attribute, value, is_not: true)
|
76
|
+
end
|
77
|
+
|
78
|
+
def filter_string_match(scope, attribute, value, is_not: false)
|
79
|
+
column = scope.klass.arel_table[attribute]
|
80
|
+
map = value.map { |v| "%#{v.downcase}%" }
|
81
|
+
clause = column.lower.matches_any(map)
|
82
|
+
is_not ? scope.where.not(clause) : scope.where(clause)
|
83
|
+
end
|
84
|
+
|
85
|
+
def filter_string_not_match(scope, attribute, value)
|
86
|
+
filter_string_match(scope, attribute, value, is_not: true)
|
87
|
+
end
|
88
|
+
|
89
|
+
def filter_gt(scope, attribute, value)
|
90
|
+
column = scope.klass.arel_table[attribute]
|
91
|
+
scope.where(column.gt_any(value))
|
92
|
+
end
|
93
|
+
alias :filter_integer_gt :filter_gt
|
94
|
+
alias :filter_float_gt :filter_gt
|
95
|
+
alias :filter_big_decimal_gt :filter_gt
|
96
|
+
alias :filter_datetime_gt :filter_gt
|
97
|
+
alias :filter_date_gt :filter_gt
|
98
|
+
|
99
|
+
def filter_gte(scope, attribute, value)
|
100
|
+
column = scope.klass.arel_table[attribute]
|
101
|
+
scope.where(column.gteq_any(value))
|
102
|
+
end
|
103
|
+
alias :filter_integer_gte :filter_gte
|
104
|
+
alias :filter_float_gte :filter_gte
|
105
|
+
alias :filter_big_decimal_gte :filter_gte
|
106
|
+
alias :filter_datetime_gte :filter_gte
|
107
|
+
alias :filter_date_gte :filter_gte
|
108
|
+
|
109
|
+
def filter_lt(scope, attribute, value)
|
110
|
+
column = scope.klass.arel_table[attribute]
|
111
|
+
scope.where(column.lt_any(value))
|
112
|
+
end
|
113
|
+
alias :filter_integer_lt :filter_lt
|
114
|
+
alias :filter_float_lt :filter_lt
|
115
|
+
alias :filter_big_decimal_lt :filter_lt
|
116
|
+
alias :filter_datetime_lt :filter_lt
|
117
|
+
alias :filter_date_lt :filter_lt
|
118
|
+
|
119
|
+
def filter_lte(scope, attribute, value)
|
120
|
+
column = scope.klass.arel_table[attribute]
|
121
|
+
scope.where(column.lteq_any(value))
|
122
|
+
end
|
123
|
+
alias :filter_integer_lte :filter_lte
|
124
|
+
alias :filter_float_lte :filter_lte
|
125
|
+
alias :filter_big_decimal_lte :filter_lte
|
126
|
+
alias :filter_date_lte :filter_lte
|
127
|
+
|
128
|
+
# Ensure fractional seconds don't matter
|
129
|
+
def filter_datetime_eq(scope, attribute, value, is_not: false)
|
130
|
+
ranges = value.map { |v| (v..v+1.second-0.00000001) }
|
131
|
+
clause = { attribute => ranges }
|
132
|
+
is_not ? scope.where.not(clause) : scope.where(clause)
|
133
|
+
end
|
134
|
+
|
135
|
+
def filter_datetime_not_eq(scope, attribute, value)
|
136
|
+
filter_datetime_eq(scope, attribute, value, is_not: true)
|
137
|
+
end
|
138
|
+
|
139
|
+
def filter_datetime_lte(scope, attribute, value)
|
140
|
+
value = value.map { |v| v + 1.second-0.00000001 }
|
141
|
+
column = scope.klass.arel_table[attribute]
|
142
|
+
scope.where(column.lteq_any(value))
|
143
|
+
end
|
144
|
+
|
145
|
+
def base_scope(model)
|
146
|
+
model.all
|
147
|
+
end
|
148
|
+
|
149
|
+
# (see Adapters::Abstract#order)
|
150
|
+
def order(scope, attribute, direction)
|
151
|
+
scope.order(attribute => direction)
|
152
|
+
end
|
153
|
+
|
154
|
+
# (see Adapters::Abstract#paginate)
|
155
|
+
def paginate(scope, current_page, per_page)
|
156
|
+
scope.page(current_page).per(per_page)
|
157
|
+
end
|
158
|
+
|
159
|
+
# (see Adapters::Abstract#count)
|
160
|
+
def count(scope, attr)
|
161
|
+
if attr.to_sym == :total
|
162
|
+
scope.distinct.count
|
163
|
+
else
|
164
|
+
scope.distinct.count(attr)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
# (see Adapters::Abstract#average)
|
169
|
+
def average(scope, attr)
|
170
|
+
scope.average(attr).to_f
|
171
|
+
end
|
172
|
+
|
173
|
+
# (see Adapters::Abstract#sum)
|
174
|
+
def sum(scope, attr)
|
175
|
+
scope.sum(attr)
|
176
|
+
end
|
177
|
+
|
178
|
+
# (see Adapters::Abstract#maximum)
|
179
|
+
def maximum(scope, attr)
|
180
|
+
scope.maximum(attr)
|
181
|
+
end
|
182
|
+
|
183
|
+
# (see Adapters::Abstract#minimum)
|
184
|
+
def minimum(scope, attr)
|
185
|
+
scope.minimum(attr)
|
186
|
+
end
|
187
|
+
|
188
|
+
# (see Adapters::Abstract#resolve)
|
189
|
+
def resolve(scope)
|
190
|
+
scope.to_a
|
191
|
+
end
|
192
|
+
|
193
|
+
# Run this write request within an ActiveRecord transaction
|
194
|
+
# @param [Class] model_class The ActiveRecord class we are saving
|
195
|
+
# @return Result of yield
|
196
|
+
# @see Adapters::Abstract#transaction
|
197
|
+
def transaction(model_class)
|
198
|
+
model_class.transaction do
|
199
|
+
yield
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def belongs_to_many_filter(sideload, scope, value)
|
204
|
+
scope
|
205
|
+
.includes(sideload.through_relationship_name)
|
206
|
+
.where(sideload.through_table_name => {
|
207
|
+
sideload.true_foreign_key => value
|
208
|
+
})
|
209
|
+
end
|
210
|
+
|
211
|
+
def associate_all(parent, children, association_name, association_type)
|
212
|
+
if activerecord_associate?(parent, children[0], association_name)
|
213
|
+
association = parent.association(association_name)
|
214
|
+
association.loaded!
|
215
|
+
|
216
|
+
children.each do |child|
|
217
|
+
if association_type == :many_to_many &&
|
218
|
+
!parent.send(association_name).exists?(child.id) &&
|
219
|
+
[:create, :update].include?(Graphiti.context[:namespace])
|
220
|
+
parent.send(association_name) << child
|
221
|
+
else
|
222
|
+
target = association.instance_variable_get(:@target)
|
223
|
+
target |= [child]
|
224
|
+
association.instance_variable_set(:@target, target)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
else
|
228
|
+
super
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def associate(parent, child, association_name, association_type)
|
233
|
+
if activerecord_associate?(parent, child, association_name)
|
234
|
+
association = parent.association(association_name)
|
235
|
+
association.loaded!
|
236
|
+
association.instance_variable_set(:@target, child)
|
237
|
+
else
|
238
|
+
super
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
# When a has_and_belongs_to_many relationship, we don't have a foreign
|
243
|
+
# key that can be null'd. Instead, go through the ActiveRecord API.
|
244
|
+
# @see Adapters::Abstract#disassociate
|
245
|
+
def disassociate(parent, child, association_name, association_type)
|
246
|
+
if association_type == :many_to_many
|
247
|
+
parent.send(association_name).delete(child)
|
248
|
+
else
|
249
|
+
# Nothing to do here, happened when we merged foreign key
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
# (see Adapters::Abstract#create)
|
254
|
+
def create(model_class, create_params)
|
255
|
+
instance = model_class.new(create_params)
|
256
|
+
instance.save
|
257
|
+
instance
|
258
|
+
end
|
259
|
+
|
260
|
+
# (see Adapters::Abstract#update)
|
261
|
+
def update(model_class, update_params)
|
262
|
+
instance = model_class.find(update_params.delete(:id))
|
263
|
+
instance.update_attributes(update_params)
|
264
|
+
instance
|
265
|
+
end
|
266
|
+
|
267
|
+
# (see Adapters::Abstract#destroy)
|
268
|
+
def destroy(model_class, id)
|
269
|
+
instance = model_class.find(id)
|
270
|
+
instance.destroy
|
271
|
+
instance
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
@@ -1,17 +1,11 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
module ActiveRecord
|
4
|
-
class BelongsToSideload < Sideload::BelongsTo
|
5
|
-
include Inferrence
|
1
|
+
class Graphiti::Adapters::ActiveRecord::BelongsToSideload < Graphiti::Sideload::BelongsTo
|
2
|
+
include Graphiti::Adapters::ActiveRecord::Inferrence
|
6
3
|
|
7
|
-
|
8
|
-
|
9
|
-
|
4
|
+
def default_base_scope
|
5
|
+
resource_class.model.all
|
6
|
+
end
|
10
7
|
|
11
|
-
|
12
|
-
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
8
|
+
def scope(parent_ids)
|
9
|
+
base_scope.where(primary_key => parent_ids)
|
16
10
|
end
|
17
11
|
end
|
@@ -1,17 +1,11 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
module ActiveRecord # todo change
|
4
|
-
class HasManySideload < Sideload::HasMany
|
5
|
-
include Inferrence
|
1
|
+
class Graphiti::Adapters::ActiveRecord::HasManySideload < Graphiti::Sideload::HasMany
|
2
|
+
include Graphiti::Adapters::ActiveRecord::Inferrence
|
6
3
|
|
7
|
-
|
8
|
-
|
9
|
-
|
4
|
+
def default_base_scope
|
5
|
+
resource_class.model.all
|
6
|
+
end
|
10
7
|
|
11
|
-
|
12
|
-
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
8
|
+
def scope(parent_ids)
|
9
|
+
base_scope.where(foreign_key => parent_ids)
|
16
10
|
end
|
17
11
|
end
|
@@ -1,17 +1,11 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
module ActiveRecord
|
4
|
-
class HasOneSideload < Sideload::HasOne
|
5
|
-
include Inferrence
|
1
|
+
class Graphiti::Adapters::ActiveRecord::HasOneSideload < Graphiti::Sideload::HasOne
|
2
|
+
include Graphiti::Adapters::ActiveRecord::Inferrence
|
6
3
|
|
7
|
-
|
8
|
-
|
9
|
-
|
4
|
+
def default_base_scope
|
5
|
+
resource_class.model.all
|
6
|
+
end
|
10
7
|
|
11
|
-
|
12
|
-
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
8
|
+
def scope(parent_ids)
|
9
|
+
base_scope.where(foreign_key => parent_ids)
|
16
10
|
end
|
17
11
|
end
|
@@ -1,19 +1,13 @@
|
|
1
|
-
module Graphiti
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
reflection.foreign_key.to_sym
|
12
|
-
else
|
13
|
-
super
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
1
|
+
module Graphiti::Adapters::ActiveRecord::Inferrence
|
2
|
+
# If going AR to AR, use AR introspection
|
3
|
+
# If going AR to PORO, fall back to normal inferrence
|
4
|
+
def infer_foreign_key
|
5
|
+
parent_model = parent_resource_class.model
|
6
|
+
reflection = parent_model.reflections[association_name.to_s]
|
7
|
+
if reflection
|
8
|
+
reflection.foreign_key.to_sym
|
9
|
+
else
|
10
|
+
super
|
17
11
|
end
|
18
12
|
end
|
19
13
|
end
|
@@ -1,23 +1,17 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
@through_table_name ||= parent_resource_class.model
|
7
|
-
.reflections[through.to_s].klass.table_name
|
8
|
-
end
|
1
|
+
class Graphiti::Adapters::ActiveRecord::ManyToManySideload < Graphiti::Sideload::ManyToMany
|
2
|
+
def through_table_name
|
3
|
+
@through_table_name ||= parent_resource_class.model
|
4
|
+
.reflections[through.to_s].klass.table_name
|
5
|
+
end
|
9
6
|
|
10
|
-
|
11
|
-
|
12
|
-
|
7
|
+
def through_relationship_name
|
8
|
+
foreign_key.keys.first
|
9
|
+
end
|
13
10
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
11
|
+
def infer_foreign_key
|
12
|
+
parent_model = parent_resource_class.model
|
13
|
+
key = parent_model.reflections[name.to_s].options[:through]
|
14
|
+
value = parent_model.reflections[key.to_s].foreign_key.to_sym
|
15
|
+
{ key => value }
|
22
16
|
end
|
23
17
|
end
|
data/lib/graphiti/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphiti
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.alpha.
|
4
|
+
version: 1.0.alpha.19
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lee Richmond
|
@@ -236,7 +236,6 @@ files:
|
|
236
236
|
- lib/graphiti.rb
|
237
237
|
- lib/graphiti/adapters/abstract.rb
|
238
238
|
- lib/graphiti/adapters/active_record.rb
|
239
|
-
- lib/graphiti/adapters/active_record/base.rb
|
240
239
|
- lib/graphiti/adapters/active_record/belongs_to_sideload.rb
|
241
240
|
- lib/graphiti/adapters/active_record/has_many_sideload.rb
|
242
241
|
- lib/graphiti/adapters/active_record/has_one_sideload.rb
|
@@ -1,271 +0,0 @@
|
|
1
|
-
module Graphiti
|
2
|
-
module Adapters
|
3
|
-
module ActiveRecord
|
4
|
-
class Base < ::Graphiti::Adapters::Abstract
|
5
|
-
def filter_eq(scope, attribute, value)
|
6
|
-
scope.where(attribute => value)
|
7
|
-
end
|
8
|
-
alias :filter_integer_eq :filter_eq
|
9
|
-
alias :filter_float_eq :filter_eq
|
10
|
-
alias :filter_big_decimal_eq :filter_eq
|
11
|
-
alias :filter_date_eq :filter_eq
|
12
|
-
alias :filter_boolean_eq :filter_eq
|
13
|
-
|
14
|
-
def filter_not_eq(scope, attribute, value)
|
15
|
-
scope.where.not(attribute => value)
|
16
|
-
end
|
17
|
-
alias :filter_integer_not_eq :filter_not_eq
|
18
|
-
alias :filter_float_not_eq :filter_not_eq
|
19
|
-
alias :filter_big_decimal_not_eq :filter_not_eq
|
20
|
-
alias :filter_date_not_eq :filter_not_eq
|
21
|
-
alias :filter_boolean_not_eq :filter_not_eq
|
22
|
-
|
23
|
-
def filter_string_eq(scope, attribute, value, is_not: false)
|
24
|
-
column = scope.klass.arel_table[attribute]
|
25
|
-
clause = column.lower.eq_any(value.map(&:downcase))
|
26
|
-
is_not ? scope.where.not(clause) : scope.where(clause)
|
27
|
-
end
|
28
|
-
|
29
|
-
def filter_string_eql(scope, attribute, value, is_not: false)
|
30
|
-
clause = { attribute => value }
|
31
|
-
is_not ? scope.where.not(clause) : scope.where(clause)
|
32
|
-
end
|
33
|
-
|
34
|
-
def filter_string_not_eq(scope, attribute, value)
|
35
|
-
filter_string_eq(scope, attribute, value, is_not: true)
|
36
|
-
end
|
37
|
-
|
38
|
-
def filter_string_not_eql(scope, attribute, value)
|
39
|
-
filter_string_eql(scope, attribute, value, is_not: true)
|
40
|
-
end
|
41
|
-
|
42
|
-
def filter_string_prefix(scope, attribute, value, is_not: false)
|
43
|
-
column = scope.klass.arel_table[attribute]
|
44
|
-
map = value.map { |v| "#{v}%" }
|
45
|
-
clause = column.lower.matches_any(map)
|
46
|
-
is_not ? scope.where.not(clause) : scope.where(clause)
|
47
|
-
end
|
48
|
-
|
49
|
-
def filter_string_not_prefix(scope, attribute, value)
|
50
|
-
filter_string_prefix(scope, attribute, value, is_not: true)
|
51
|
-
end
|
52
|
-
|
53
|
-
def filter_string_suffix(scope, attribute, value, is_not: false)
|
54
|
-
column = scope.klass.arel_table[attribute]
|
55
|
-
map = value.map { |v| "%#{v}" }
|
56
|
-
clause = column.lower.matches_any(map)
|
57
|
-
is_not ? scope.where.not(clause) : scope.where(clause)
|
58
|
-
end
|
59
|
-
|
60
|
-
def filter_string_not_suffix(scope, attribute, value)
|
61
|
-
filter_string_suffix(scope, attribute, value, is_not: true)
|
62
|
-
end
|
63
|
-
|
64
|
-
def filter_string_match(scope, attribute, value, is_not: false)
|
65
|
-
column = scope.klass.arel_table[attribute]
|
66
|
-
map = value.map { |v| "%#{v.downcase}%" }
|
67
|
-
clause = column.lower.matches_any(map)
|
68
|
-
is_not ? scope.where.not(clause) : scope.where(clause)
|
69
|
-
end
|
70
|
-
|
71
|
-
def filter_string_not_match(scope, attribute, value)
|
72
|
-
filter_string_match(scope, attribute, value, is_not: true)
|
73
|
-
end
|
74
|
-
|
75
|
-
def filter_gt(scope, attribute, value)
|
76
|
-
column = scope.klass.arel_table[attribute]
|
77
|
-
scope.where(column.gt_any(value))
|
78
|
-
end
|
79
|
-
alias :filter_integer_gt :filter_gt
|
80
|
-
alias :filter_float_gt :filter_gt
|
81
|
-
alias :filter_big_decimal_gt :filter_gt
|
82
|
-
alias :filter_datetime_gt :filter_gt
|
83
|
-
alias :filter_date_gt :filter_gt
|
84
|
-
|
85
|
-
def filter_gte(scope, attribute, value)
|
86
|
-
column = scope.klass.arel_table[attribute]
|
87
|
-
scope.where(column.gteq_any(value))
|
88
|
-
end
|
89
|
-
alias :filter_integer_gte :filter_gte
|
90
|
-
alias :filter_float_gte :filter_gte
|
91
|
-
alias :filter_big_decimal_gte :filter_gte
|
92
|
-
alias :filter_datetime_gte :filter_gte
|
93
|
-
alias :filter_date_gte :filter_gte
|
94
|
-
|
95
|
-
def filter_lt(scope, attribute, value)
|
96
|
-
column = scope.klass.arel_table[attribute]
|
97
|
-
scope.where(column.lt_any(value))
|
98
|
-
end
|
99
|
-
alias :filter_integer_lt :filter_lt
|
100
|
-
alias :filter_float_lt :filter_lt
|
101
|
-
alias :filter_big_decimal_lt :filter_lt
|
102
|
-
alias :filter_datetime_lt :filter_lt
|
103
|
-
alias :filter_date_lt :filter_lt
|
104
|
-
|
105
|
-
def filter_lte(scope, attribute, value)
|
106
|
-
column = scope.klass.arel_table[attribute]
|
107
|
-
scope.where(column.lteq_any(value))
|
108
|
-
end
|
109
|
-
alias :filter_integer_lte :filter_lte
|
110
|
-
alias :filter_float_lte :filter_lte
|
111
|
-
alias :filter_big_decimal_lte :filter_lte
|
112
|
-
alias :filter_date_lte :filter_lte
|
113
|
-
|
114
|
-
# Ensure fractional seconds don't matter
|
115
|
-
def filter_datetime_eq(scope, attribute, value, is_not: false)
|
116
|
-
ranges = value.map { |v| (v..v+1.second-0.00000001) }
|
117
|
-
clause = { attribute => ranges }
|
118
|
-
is_not ? scope.where.not(clause) : scope.where(clause)
|
119
|
-
end
|
120
|
-
|
121
|
-
def filter_datetime_not_eq(scope, attribute, value)
|
122
|
-
filter_datetime_eq(scope, attribute, value, is_not: true)
|
123
|
-
end
|
124
|
-
|
125
|
-
def filter_datetime_lte(scope, attribute, value)
|
126
|
-
value = value.map { |v| v + 1.second-0.00000001 }
|
127
|
-
column = scope.klass.arel_table[attribute]
|
128
|
-
scope.where(column.lteq_any(value))
|
129
|
-
end
|
130
|
-
|
131
|
-
def base_scope(model)
|
132
|
-
model.all
|
133
|
-
end
|
134
|
-
|
135
|
-
# (see Adapters::Abstract#order)
|
136
|
-
def order(scope, attribute, direction)
|
137
|
-
scope.order(attribute => direction)
|
138
|
-
end
|
139
|
-
|
140
|
-
# (see Adapters::Abstract#paginate)
|
141
|
-
def paginate(scope, current_page, per_page)
|
142
|
-
scope.page(current_page).per(per_page)
|
143
|
-
end
|
144
|
-
|
145
|
-
# (see Adapters::Abstract#count)
|
146
|
-
def count(scope, attr)
|
147
|
-
if attr.to_sym == :total
|
148
|
-
scope.distinct.count
|
149
|
-
else
|
150
|
-
scope.distinct.count(attr)
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
# (see Adapters::Abstract#average)
|
155
|
-
def average(scope, attr)
|
156
|
-
scope.average(attr).to_f
|
157
|
-
end
|
158
|
-
|
159
|
-
# (see Adapters::Abstract#sum)
|
160
|
-
def sum(scope, attr)
|
161
|
-
scope.sum(attr)
|
162
|
-
end
|
163
|
-
|
164
|
-
# (see Adapters::Abstract#maximum)
|
165
|
-
def maximum(scope, attr)
|
166
|
-
scope.maximum(attr)
|
167
|
-
end
|
168
|
-
|
169
|
-
# (see Adapters::Abstract#minimum)
|
170
|
-
def minimum(scope, attr)
|
171
|
-
scope.minimum(attr)
|
172
|
-
end
|
173
|
-
|
174
|
-
# (see Adapters::Abstract#resolve)
|
175
|
-
def resolve(scope)
|
176
|
-
scope.to_a
|
177
|
-
end
|
178
|
-
|
179
|
-
# Run this write request within an ActiveRecord transaction
|
180
|
-
# @param [Class] model_class The ActiveRecord class we are saving
|
181
|
-
# @return Result of yield
|
182
|
-
# @see Adapters::Abstract#transaction
|
183
|
-
def transaction(model_class)
|
184
|
-
model_class.transaction do
|
185
|
-
yield
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
|
-
def self.sideloading_classes
|
190
|
-
{
|
191
|
-
has_many: HasManySideload,
|
192
|
-
has_one: HasOneSideload,
|
193
|
-
belongs_to: BelongsToSideload,
|
194
|
-
many_to_many: ManyToManySideload
|
195
|
-
}
|
196
|
-
end
|
197
|
-
|
198
|
-
def belongs_to_many_filter(sideload, scope, value)
|
199
|
-
scope
|
200
|
-
.includes(sideload.through_relationship_name)
|
201
|
-
.where(sideload.through_table_name => {
|
202
|
-
sideload.true_foreign_key => value
|
203
|
-
})
|
204
|
-
end
|
205
|
-
|
206
|
-
def associate_all(parent, children, association_name, association_type)
|
207
|
-
if activerecord_associate?(parent, children[0], association_name)
|
208
|
-
association = parent.association(association_name)
|
209
|
-
association.loaded!
|
210
|
-
|
211
|
-
children.each do |child|
|
212
|
-
if association_type == :many_to_many &&
|
213
|
-
!parent.send(association_name).exists?(child.id) &&
|
214
|
-
[:create, :update].include?(Graphiti.context[:namespace])
|
215
|
-
parent.send(association_name) << child
|
216
|
-
else
|
217
|
-
target = association.instance_variable_get(:@target)
|
218
|
-
target |= [child]
|
219
|
-
association.instance_variable_set(:@target, target)
|
220
|
-
end
|
221
|
-
end
|
222
|
-
else
|
223
|
-
super
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
def associate(parent, child, association_name, association_type)
|
228
|
-
if activerecord_associate?(parent, child, association_name)
|
229
|
-
association = parent.association(association_name)
|
230
|
-
association.loaded!
|
231
|
-
association.instance_variable_set(:@target, child)
|
232
|
-
else
|
233
|
-
super
|
234
|
-
end
|
235
|
-
end
|
236
|
-
|
237
|
-
# When a has_and_belongs_to_many relationship, we don't have a foreign
|
238
|
-
# key that can be null'd. Instead, go through the ActiveRecord API.
|
239
|
-
# @see Adapters::Abstract#disassociate
|
240
|
-
def disassociate(parent, child, association_name, association_type)
|
241
|
-
if association_type == :many_to_many
|
242
|
-
parent.send(association_name).delete(child)
|
243
|
-
else
|
244
|
-
# Nothing to do here, happened when we merged foreign key
|
245
|
-
end
|
246
|
-
end
|
247
|
-
|
248
|
-
# (see Adapters::Abstract#create)
|
249
|
-
def create(model_class, create_params)
|
250
|
-
instance = model_class.new(create_params)
|
251
|
-
instance.save
|
252
|
-
instance
|
253
|
-
end
|
254
|
-
|
255
|
-
# (see Adapters::Abstract#update)
|
256
|
-
def update(model_class, update_params)
|
257
|
-
instance = model_class.find(update_params.delete(:id))
|
258
|
-
instance.update_attributes(update_params)
|
259
|
-
instance
|
260
|
-
end
|
261
|
-
|
262
|
-
# (see Adapters::Abstract#destroy)
|
263
|
-
def destroy(model_class, id)
|
264
|
-
instance = model_class.find(id)
|
265
|
-
instance.destroy
|
266
|
-
instance
|
267
|
-
end
|
268
|
-
end
|
269
|
-
end
|
270
|
-
end
|
271
|
-
end
|