Class: Graphiti::Adapters::ActiveRecord

Inherits:
Abstract show all
Defined in:
lib/graphiti/adapters/active_record.rb

Defined Under Namespace

Modules: Inference Classes: BelongsToSideload, HasManySideload, HasOneSideload, ManyToManySideload, Sanitizer

Instance Attribute Summary

Attributes inherited from Abstract

#resource

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Abstract

#assign_attributes, #belongs_to_many_filter, #build, default_operators, #initialize, numerical_operators, #persistence_attributes

Methods included from Persistence::Associations

#process_belongs_to, #process_has_many, #update_foreign_key, #update_foreign_key_for_parents, #update_foreign_type

Constructor Details

This class inherits a constructor from Graphiti::Adapters::Abstract

Class Method Details

.sideloading_classesObject



10
11
12
13
14
15
16
17
# File 'lib/graphiti/adapters/active_record.rb', line 10

def self.sideloading_classes
  {
    has_many: Graphiti::Adapters::ActiveRecord::HasManySideload,
    has_one: Graphiti::Adapters::ActiveRecord::HasOneSideload,
    belongs_to: Graphiti::Adapters::ActiveRecord::BelongsToSideload,
    many_to_many: Graphiti::Adapters::ActiveRecord::ManyToManySideload
  }
end

Instance Method Details

#associate(parent, child, association_name, association_type) ⇒ Object



262
263
264
265
266
267
268
269
270
# File 'lib/graphiti/adapters/active_record.rb', line 262

def associate(parent, child, association_name, association_type)
  if activerecord_associate?(parent, child, association_name)
    association = parent.association(association_name)
    association.loaded!
    association.instance_variable_set(:@target, child)
  else
    super
  end
end

#associate_all(parent, children, association_name, association_type) ⇒ Object



240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
# File 'lib/graphiti/adapters/active_record.rb', line 240

def associate_all(parent, children, association_name, association_type)
  if activerecord_associate?(parent, children[0], association_name)
    association = parent.association(association_name)
    association.loaded!

    children.each do |child|
      if association_type == :many_to_many &&
          [:create, :update].include?(Graphiti.context[:namespace]) &&
          !parent.send(association_name).exists?(child.id) &&
          child.errors.blank?
        parent.send(association_name) << child
      else
        target = association.instance_variable_get(:@target)
        target |= [child]
        association.instance_variable_set(:@target, target)
      end
    end
  else
    super
  end
end

#average(scope, attr) ⇒ Float

Returns the average of the scope.

Examples:

ActiveRecord default

def average(scope, attr)
  scope.average(attr).to_f
end

Parameters:

  • scope

    the scope object we are chaining

  • attr (Symbol)

    corresponding stat attribute name

Returns:

  • (Float)

    the average of the scope



206
207
208
# File 'lib/graphiti/adapters/active_record.rb', line 206

def average(scope, attr)
  scope.average(attr).to_f
end

#base_scope(model) ⇒ Object



179
180
181
# File 'lib/graphiti/adapters/active_record.rb', line 179

def base_scope(model)
  model.all
end

#can_group?Boolean

Returns:

  • (Boolean)


314
315
316
# File 'lib/graphiti/adapters/active_record.rb', line 314

def can_group?
  true
end

#closeObject



306
307
308
309
310
311
312
# File 'lib/graphiti/adapters/active_record.rb', line 306

def close
  if ::ActiveRecord.version > Gem::Version.new("7.2")
    ::ActiveRecord::Base.connection_handler.clear_active_connections!
  else
    ::ActiveRecord::Base.clear_active_connections!
  end
end

#count(scope, attr) ⇒ Numeric

Returns the count of the scope.

Examples:

ActiveRecord default

def count(scope, attr)
  column = attr == :total ? :all : attr
  scope.uniq.count(column)
end

Parameters:

  • scope

    the scope object we are chaining

  • attr (Symbol)

    corresponding stat attribute name

Returns:

  • (Numeric)

    the count of the scope



197
198
199
200
201
202
203
# File 'lib/graphiti/adapters/active_record.rb', line 197

def count(scope, attr)
  if attr.to_sym == :total
    scope.distinct.count(:all)
  else
    scope.distinct.count(attr)
  end
end

#create(model_class, create_params) ⇒ Object



283
284
285
286
287
# File 'lib/graphiti/adapters/active_record.rb', line 283

def create(model_class, create_params)
  instance = model_class.new(create_params)
  instance.save
  instance
end

#destroy(model_instance) ⇒ Object



301
302
303
304
# File 'lib/graphiti/adapters/active_record.rb', line 301

def destroy(model_instance)
  model_instance.destroy
  model_instance
end

#disassociate(parent, child, association_name, association_type) ⇒ Object

When a has_and_belongs_to_many relationship, we don’t have a foreign key that can be null’d. Instead, go through the ActiveRecord API.



275
276
277
278
279
280
# File 'lib/graphiti/adapters/active_record.rb', line 275

def disassociate(parent, child, association_name, association_type)
  if association_type == :many_to_many
    parent.send(association_name).delete(child)
  end
  # Nothing to do in the else case, happened when we merged foreign key
end

#filter_datetime_eq(scope, attribute, value, is_not: false) ⇒ Object

Ensure fractional seconds don’t matter



163
164
165
166
167
# File 'lib/graphiti/adapters/active_record.rb', line 163

def filter_datetime_eq(scope, attribute, value, is_not: false)
  ranges = value.map { |v| (v..v + 1.second - 0.00000001) unless v.nil? }
  clause = {attribute => ranges}
  is_not ? scope.where.not(clause) : scope.where(clause)
end

#filter_datetime_lte(scope, attribute, value) ⇒ Object



173
174
175
176
177
# File 'lib/graphiti/adapters/active_record.rb', line 173

def filter_datetime_lte(scope, attribute, value)
  value = value.map { |v| v + 1.second - 0.00000001 }
  column = scope.klass.arel_table[attribute]
  scope.where(column.lteq_any(value))
end

#filter_datetime_not_eq(scope, attribute, value) ⇒ Object



169
170
171
# File 'lib/graphiti/adapters/active_record.rb', line 169

def filter_datetime_not_eq(scope, attribute, value)
  filter_datetime_eq(scope, attribute, value, is_not: true)
end

#filter_eq(scope, attribute, value) ⇒ Object Also known as: filter_integer_eq, filter_float_eq, filter_big_decimal_eq, filter_date_eq, filter_boolean_eq, filter_uuid_eq, filter_enum_eq, filter_enum_eql



19
20
21
# File 'lib/graphiti/adapters/active_record.rb', line 19

def filter_eq(scope, attribute, value)
  scope.where(attribute => value)
end

#filter_gt(scope, attribute, value) ⇒ Object Also known as: filter_integer_gt, filter_float_gt, filter_big_decimal_gt, filter_datetime_gt, filter_date_gt



123
124
125
126
# File 'lib/graphiti/adapters/active_record.rb', line 123

def filter_gt(scope, attribute, value)
  column = column_for(scope, attribute)
  scope.where(column.gt_any(value))
end

#filter_gte(scope, attribute, value) ⇒ Object Also known as: filter_integer_gte, filter_float_gte, filter_big_decimal_gte, filter_datetime_gte, filter_date_gte



133
134
135
136
# File 'lib/graphiti/adapters/active_record.rb', line 133

def filter_gte(scope, attribute, value)
  column = column_for(scope, attribute)
  scope.where(column.gteq_any(value))
end

#filter_lt(scope, attribute, value) ⇒ Object Also known as: filter_integer_lt, filter_float_lt, filter_big_decimal_lt, filter_datetime_lt, filter_date_lt



143
144
145
146
# File 'lib/graphiti/adapters/active_record.rb', line 143

def filter_lt(scope, attribute, value)
  column = column_for(scope, attribute)
  scope.where(column.lt_any(value))
end

#filter_lte(scope, attribute, value) ⇒ Object Also known as: filter_integer_lte, filter_float_lte, filter_big_decimal_lte, filter_date_lte



153
154
155
156
# File 'lib/graphiti/adapters/active_record.rb', line 153

def filter_lte(scope, attribute, value)
  column = column_for(scope, attribute)
  scope.where(column.lteq_any(value))
end

#filter_not_eq(scope, attribute, value) ⇒ Object Also known as: filter_integer_not_eq, filter_float_not_eq, filter_big_decimal_not_eq, filter_date_not_eq, filter_boolean_not_eq, filter_uuid_not_eq, filter_enum_not_eq, filter_enum_not_eql



31
32
33
# File 'lib/graphiti/adapters/active_record.rb', line 31

def filter_not_eq(scope, attribute, value)
  scope.where.not(attribute => value)
end

#filter_string_eq(scope, attribute, value, is_not: false) ⇒ Object



43
44
45
46
47
# File 'lib/graphiti/adapters/active_record.rb', line 43

def filter_string_eq(scope, attribute, value, is_not: false)
  column = column_for(scope, attribute)
  clause = column.lower.eq_any(value.map(&:downcase))
  is_not ? scope.where.not(clause) : scope.where(clause)
end

#filter_string_eql(scope, attribute, value, is_not: false) ⇒ Object



49
50
51
52
# File 'lib/graphiti/adapters/active_record.rb', line 49

def filter_string_eql(scope, attribute, value, is_not: false)
  clause = {attribute => value}
  is_not ? scope.where.not(clause) : scope.where(clause)
end

#filter_string_match(scope, attribute, value, is_not: false) ⇒ Object



66
67
68
69
70
71
# File 'lib/graphiti/adapters/active_record.rb', line 66

def filter_string_match(scope, attribute, value, is_not: false)
  clause = sanitized_like_for(scope, attribute, value) { |v|
    "%#{v}%"
  }
  is_not ? scope.where.not(clause) : scope.where(clause)
end

#filter_string_not_eq(scope, attribute, value) ⇒ Object



54
55
56
# File 'lib/graphiti/adapters/active_record.rb', line 54

def filter_string_not_eq(scope, attribute, value)
  filter_string_eq(scope, attribute, value, is_not: true)
end

#filter_string_not_eql(scope, attribute, value) ⇒ Object



58
59
60
# File 'lib/graphiti/adapters/active_record.rb', line 58

def filter_string_not_eql(scope, attribute, value)
  filter_string_eql(scope, attribute, value, is_not: true)
end

#filter_string_not_match(scope, attribute, value) ⇒ Object



119
120
121
# File 'lib/graphiti/adapters/active_record.rb', line 119

def filter_string_not_match(scope, attribute, value)
  filter_string_match(scope, attribute, value, is_not: true)
end

#filter_string_not_prefix(scope, attribute, value) ⇒ Object



111
112
113
# File 'lib/graphiti/adapters/active_record.rb', line 111

def filter_string_not_prefix(scope, attribute, value)
  filter_string_prefix(scope, attribute, value, is_not: true)
end

#filter_string_not_suffix(scope, attribute, value) ⇒ Object



115
116
117
# File 'lib/graphiti/adapters/active_record.rb', line 115

def filter_string_not_suffix(scope, attribute, value)
  filter_string_suffix(scope, attribute, value, is_not: true)
end

#filter_string_prefix(scope, attribute, value, is_not: false) ⇒ Object



73
74
75
76
77
78
# File 'lib/graphiti/adapters/active_record.rb', line 73

def filter_string_prefix(scope, attribute, value, is_not: false)
  clause = sanitized_like_for(scope, attribute, value) { |v|
    "#{v}%"
  }
  is_not ? scope.where.not(clause) : scope.where(clause)
end

#filter_string_suffix(scope, attribute, value, is_not: false) ⇒ Object



80
81
82
83
84
85
# File 'lib/graphiti/adapters/active_record.rb', line 80

def filter_string_suffix(scope, attribute, value, is_not: false)
  clause = sanitized_like_for(scope, attribute, value) { |v|
    "%#{v}"
  }
  is_not ? scope.where.not(clause) : scope.where(clause)
end

#group(scope, attribute) ⇒ Object



318
319
320
# File 'lib/graphiti/adapters/active_record.rb', line 318

def group(scope, attribute)
  scope.group(attribute)
end

#maximum(scope, attr) ⇒ Numeric

Returns the maximum value of the scope.

Examples:

ActiveRecord default

def maximum(scope, attr)
  scope.maximum(attr)
end

Parameters:

  • scope

    the scope object we are chaining

  • attr (Symbol)

    corresponding stat attribute name

Returns:

  • (Numeric)

    the maximum value of the scope



216
217
218
# File 'lib/graphiti/adapters/active_record.rb', line 216

def maximum(scope, attr)
  scope.maximum(attr)
end

#minimum(scope, attr) ⇒ Numeric

Returns the maximum value of the scope.

Examples:

ActiveRecord default

def maximum(scope, attr)
  scope.maximum(attr)
end

Parameters:

  • scope

    the scope object we are chaining

  • attr (Symbol)

    corresponding stat attribute name

Returns:

  • (Numeric)

    the maximum value of the scope



221
222
223
# File 'lib/graphiti/adapters/active_record.rb', line 221

def minimum(scope, attr)
  scope.minimum(attr)
end

#order(scope, attribute, direction) ⇒ Object

Returns the scope.

Examples:

ActiveRecord default

def order(scope, attribute, direction)
  scope.order(attribute => direction)
end

Parameters:

  • scope

    The scope object we are chaining

  • attribute (Symbol)

    The attribute name we are sorting

  • direction (Symbol)

    The direction we are sorting (asc/desc)

Returns:

  • the scope



184
185
186
# File 'lib/graphiti/adapters/active_record.rb', line 184

def order(scope, attribute, direction)
  scope.order(attribute => direction)
end

#paginate(scope, current_page, per_page, offset) ⇒ Object

Returns the scope.

Examples:

ActiveRecord default

# via kaminari gem
def paginate(scope, current_page, per_page, offset)
  scope.page(current_page).per(per_page)
end

Parameters:

  • scope

    The scope object we are chaining

  • current_page (Integer)

    The current page number

  • per_page (Integer)

    The number of results per page

  • offset (Integer)

    The offset to start from

Returns:

  • the scope



189
190
191
192
193
194
# File 'lib/graphiti/adapters/active_record.rb', line 189

def paginate(scope, current_page, per_page, offset)
  scope = scope.page(current_page) if current_page
  scope = scope.per(per_page) if per_page
  scope = scope.padding(offset) if offset
  scope
end

#resolve(scope) ⇒ Object

Resolve the scope. This is where you’d actually fire SQL, actually make an HTTP call, etc.

Examples:

ActiveRecordDefault

def resolve(scope)
  scope.to_a
end

Suggested Customization

# When making a service call, we suggest this abstraction
# 'scope' here is a hash
def resolve(scope)
  # The implementation of .where can be whatever you want
  SomeModelClass.where(scope)
end

Parameters:

  • scope

    The scope object to resolve

Returns:

  • an array of Model instances

See Also:



226
227
228
# File 'lib/graphiti/adapters/active_record.rb', line 226

def resolve(scope)
  scope.to_a
end

#save(model_instance) ⇒ Object



296
297
298
299
# File 'lib/graphiti/adapters/active_record.rb', line 296

def save(model_instance)
  model_instance.save
  model_instance
end

#sum(scope, attr) ⇒ Numeric

Returns the sum of the scope.

Examples:

ActiveRecord default

def sum(scope, attr)
  scope.sum(attr)
end

Parameters:

  • scope

    the scope object we are chaining

  • attr (Symbol)

    corresponding stat attribute name

Returns:

  • (Numeric)

    the sum of the scope



211
212
213
# File 'lib/graphiti/adapters/active_record.rb', line 211

def sum(scope, attr)
  scope.sum(attr)
end

#transaction(model_class) ⇒ Object

Run this write request within an ActiveRecord transaction

Parameters:

  • model_class (Class)

    The ActiveRecord class we are saving

Returns:

  • Result of yield

See Also:



234
235
236
237
238
# File 'lib/graphiti/adapters/active_record.rb', line 234

def transaction(model_class)
  model_class.transaction do
    yield
  end
end

#update(model_class, update_params) ⇒ Object



290
291
292
293
294
# File 'lib/graphiti/adapters/active_record.rb', line 290

def update(model_class, update_params)
  instance = model_class.find(update_params.only(:id))
  instance.update_attributes(update_params.except(:id))
  instance
end