Class: InventoryRefresh::InventoryCollection

Inherits:
Object
  • Object
show all
Includes:
Helpers::AssociationsHelper, Helpers::InitializeHelper, Helpers::QuestionsHelper
Defined in:
lib/inventory_refresh/inventory_collection.rb,
lib/inventory_refresh/inventory_collection/graph.rb,
lib/inventory_refresh/inventory_collection/builder.rb,
lib/inventory_refresh/inventory_collection/helpers.rb,
lib/inventory_refresh/inventory_collection/scanner.rb,
lib/inventory_refresh/inventory_collection/reference.rb,
lib/inventory_refresh/inventory_collection/index/proxy.rb,
lib/inventory_refresh/inventory_collection/data_storage.rb,
lib/inventory_refresh/inventory_collection/serialization.rb,
lib/inventory_refresh/inventory_collection/index/type/base.rb,
lib/inventory_refresh/inventory_collection/index/type/data.rb,
lib/inventory_refresh/inventory_collection/unconnected_edge.rb,
lib/inventory_refresh/inventory_collection/references_storage.rb,
lib/inventory_refresh/inventory_collection/index/type/local_db.rb,
lib/inventory_refresh/inventory_collection/index/type/skeletal.rb,
lib/inventory_refresh/inventory_collection/helpers/questions_helper.rb,
lib/inventory_refresh/inventory_collection/helpers/initialize_helper.rb,
lib/inventory_refresh/inventory_collection/helpers/associations_helper.rb

Overview

For more usage examples please follow spec examples in

  • spec/models/inventory_refresh/save_inventory/single_inventory_collection_spec.rb

  • spec/models/inventory_refresh/save_inventory/acyclic_graph_of_inventory_collections_spec.rb

  • spec/models/inventory_refresh/save_inventory/graph_of_inventory_collections_spec.rb

  • spec/models/inventory_refresh/save_inventory/graph_of_inventory_collections_targeted_refresh_spec.rb

  • spec/models/inventory_refresh/save_inventory/strategies_and_references_spec.rb

Examples:

storing Vm model data into the DB


@ems = ManageIQ::Providers::BaseManager.first
puts @ems.vms.collect(&:ems_ref) # => []

# Init InventoryCollection
vms_inventory_collection = ::InventoryRefresh::InventoryCollection.new(
  :model_class => ManageIQ::Providers::CloudManager::Vm, :parent => @ems, :association => :vms
)

# Fill InventoryCollection with data
# Starting with no vms, lets add vm1 and vm2
vms_inventory_collection.build(:ems_ref => "vm1", :name => "vm1")
vms_inventory_collection.build(:ems_ref => "vm2", :name => "vm2")

# Save InventoryCollection to the db
InventoryRefresh::SaveInventory.save_inventory(@ems, [vms_inventory_collection])

# The result in the DB is that vm1 and vm2 were created
puts @ems.vms.collect(&:ems_ref) # => ["vm1", "vm2"]

In another refresh, vm1 does not exist anymore and vm3 was added

# Init InventoryCollection
vms_inventory_collection = ::InventoryRefresh::InventoryCollection.new(
  :model_class => ManageIQ::Providers::CloudManager::Vm, :parent => @ems, :association => :vms
)

# Fill InventoryCollection with data
vms_inventory_collection.build(:ems_ref => "vm2", :name => "vm2")
vms_inventory_collection.build(:ems_ref => "vm3", :name => "vm3")

# Save InventoryCollection to the db
InventoryRefresh::SaveInventory.save_inventory(@ems, [vms_inventory_collection])

# The result in the DB is that vm1 was deleted, vm2 was updated and vm3 was created
puts @ems.vms.collect(&:ems_ref) # => ["vm2", "vm3"]

Defined Under Namespace

Modules: Helpers, Index Classes: Builder, DataStorage, Graph, Reference, ReferencesStorage, Scanner, Serialization, UnconnectedEdge

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Helpers::QuestionsHelper

#check_changed?, #complete?, #create_allowed?, #create_only?, #data_collection_finalized?, #delete_allowed?, #noop?, #saveable?, #saved?, #supports_column?, #supports_sti?, #update_only?, #use_ar_object?

Methods included from Helpers::InitializeHelper

#init_arels, #init_basic_properties, #init_changed_records_stats, #init_custom_procs, #init_data, #init_flags, #init_ic_relations, #init_model_attributes, #init_references, #init_storages, #init_strategies, #process_retention_strategy, #process_strategy, #strategy=

Methods included from Helpers::AssociationsHelper

#association_to_base_class_mapping, #association_to_foreign_key_mapping, #association_to_foreign_type_mapping, #belongs_to_associations, #fixed_foreign_keys, #foreign_key_to_association_mapping, #foreign_keys, #foreign_type_to_association_mapping

Constructor Details

#initialize(properties = {}) ⇒ InventoryCollection

Returns a new instance of InventoryCollection.

Parameters:

  • properties (Hash) (defaults to: {})
    • see init methods for params description



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/inventory_refresh/inventory_collection.rb', line 126

def initialize(properties = {})
  init_basic_properties(properties[:association],
                        properties[:model_class],
                        properties[:name],
                        properties[:parent])

  init_flags(properties[:complete],
             properties[:create_only],
             properties[:check_changed],
             properties[:update_only],
             properties[:use_ar_object],
             properties[:assert_graph_integrity])

  init_strategies(properties[:strategy],
                  properties[:retention_strategy])

  init_references(properties[:manager_ref],
                  properties[:manager_ref_allowed_nil],
                  properties[:secondary_refs])

  init_ic_relations(properties[:dependency_attributes])

  init_arels(properties[:arel])

  init_custom_procs(properties[:custom_save_block],
                    properties[:custom_reconnect_block])

  init_model_attributes(properties[:attributes_blacklist],
                        properties[:attributes_whitelist],
                        properties[:inventory_object_attributes],
                        properties[:batch_extra_attributes])

  init_data(properties[:default_values])

  init_storages

  init_changed_records_stats
end

Instance Attribute Details

#arelObject (readonly)

Returns the value of attribute arel.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def arel
  @arel
end

#assert_graph_integrityObject (readonly)

Returns the value of attribute assert_graph_integrity.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def assert_graph_integrity
  @assert_graph_integrity
end

#associationObject (readonly)

Returns the value of attribute association.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def association
  @association
end

#attributes_blacklistObject

Returns the value of attribute attributes_blacklist.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def attributes_blacklist
  @attributes_blacklist
end

#attributes_whitelistObject

Returns the value of attribute attributes_whitelist.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def attributes_whitelist
  @attributes_whitelist
end

#batch_extra_attributesObject (readonly)

Returns the value of attribute batch_extra_attributes.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def batch_extra_attributes
  @batch_extra_attributes
end

#check_changedObject (readonly)

Returns the value of attribute check_changed.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def check_changed
  @check_changed
end

#completeObject (readonly)

Returns the value of attribute complete.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def complete
  @complete
end

#create_onlyObject (readonly)

Returns the value of attribute create_only.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def create_only
  @create_only
end

#created_recordsObject (readonly)

Returns the value of attribute created_records.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def created_records
  @created_records
end

#custom_reconnect_blockObject (readonly)

Returns the value of attribute custom_reconnect_block.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def custom_reconnect_block
  @custom_reconnect_block
end

#custom_save_blockObject (readonly)

Returns the value of attribute custom_save_block.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def custom_save_block
  @custom_save_block
end

#data_collection_finalizedBoolean

Returns A true value marks that we collected all the data of the InventoryCollection, meaning we also collected all the references.

Returns:

  • (Boolean)

    A true value marks that we collected all the data of the InventoryCollection, meaning we also collected all the references.



63
64
65
# File 'lib/inventory_refresh/inventory_collection.rb', line 63

def data_collection_finalized
  @data_collection_finalized
end

#data_storageInventoryRefresh::InventoryCollection::DataStorage

Returns An InventoryCollection encapsulating all data with indexes.

Returns:



67
68
69
# File 'lib/inventory_refresh/inventory_collection.rb', line 67

def data_storage
  @data_storage
end

#default_valuesObject (readonly)

Returns the value of attribute default_values.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def default_values
  @default_values
end

#deleted_recordsObject (readonly)

Returns the value of attribute deleted_records.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def deleted_records
  @deleted_records
end

#dependeesSet

Returns A set of InventoryCollection objects that depends on this InventoryCollection object.

Returns:

  • (Set)

    A set of InventoryCollection objects that depends on this InventoryCollection object.



75
76
77
# File 'lib/inventory_refresh/inventory_collection.rb', line 75

def dependees
  @dependees
end

#dependency_attributesObject (readonly)

Returns the value of attribute dependency_attributes.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def dependency_attributes
  @dependency_attributes
end

#internal_attributesObject (readonly)

Returns the value of attribute internal_attributes.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def internal_attributes
  @internal_attributes
end

#inventory_object_attributesObject (readonly)

Returns the value of attribute inventory_object_attributes.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def inventory_object_attributes
  @inventory_object_attributes
end

#manager_refObject (readonly)

Returns the value of attribute manager_ref.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def manager_ref
  @manager_ref
end

#manager_ref_allowed_nilObject (readonly)

Returns the value of attribute manager_ref_allowed_nil.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def manager_ref_allowed_nil
  @manager_ref_allowed_nil
end

#model_classObject (readonly)

Returns the value of attribute model_class.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def model_class
  @model_class
end

#nameObject (readonly)

Returns the value of attribute name.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def name
  @name
end

#parentObject (readonly)

Returns the value of attribute parent.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def parent
  @parent
end

#references_storageObject (readonly)

Returns the value of attribute references_storage.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def references_storage
  @references_storage
end

#retention_strategyObject (readonly)

Returns the value of attribute retention_strategy.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def retention_strategy
  @retention_strategy
end

#savedBoolean

Returns true if this collection is already saved into the DB. E.g. InventoryCollections with DB only strategy are marked as saved. This causes InventoryCollection not being a dependency for any other InventoryCollection, since it is already persisted into the DB.

Returns:

  • (Boolean)

    true if this collection is already saved into the DB. E.g. InventoryCollections with DB only strategy are marked as saved. This causes InventoryCollection not being a dependency for any other InventoryCollection, since it is already persisted into the DB.



72
73
74
# File 'lib/inventory_refresh/inventory_collection.rb', line 72

def saved
  @saved
end

#saver_strategyObject (readonly)

Returns the value of attribute saver_strategy.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def saver_strategy
  @saver_strategy
end

#secondary_refsObject (readonly)

Returns the value of attribute secondary_refs.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def secondary_refs
  @secondary_refs
end

#strategyObject (readonly)

Returns the value of attribute strategy.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def strategy
  @strategy
end

#transitive_dependency_attributesObject (readonly)

Returns the value of attribute transitive_dependency_attributes.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def transitive_dependency_attributes
  @transitive_dependency_attributes
end

#unconnected_edgesObject (readonly)

Returns the value of attribute unconnected_edges.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def unconnected_edges
  @unconnected_edges
end

#update_onlyObject (readonly)

Returns the value of attribute update_only.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def update_only
  @update_only
end

#updated_recordsObject (readonly)

Returns the value of attribute updated_records.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def updated_records
  @updated_records
end

#use_ar_objectObject (readonly)

Returns the value of attribute use_ar_object.



77
78
79
# File 'lib/inventory_refresh/inventory_collection.rb', line 77

def use_ar_object
  @use_ar_object
end

Instance Method Details

#all_column_namesArray<Symbol>

Returns Array of all column names on the InventoryCollection.

Returns:

  • (Array<Symbol>)

    Array of all column names on the InventoryCollection



286
287
288
# File 'lib/inventory_refresh/inventory_collection.rb', line 286

def all_column_names
  @all_column_names ||= model_class.columns.map { |x| x.name.to_sym }
end

#base_class_nameString

Returns Base class name of the model_class of this InventoryCollection.

Returns:

  • (String)

    Base class name of the model_class of this InventoryCollection



437
438
439
440
441
# File 'lib/inventory_refresh/inventory_collection.rb', line 437

def base_class_name
  return "" unless model_class

  @base_class_name ||= model_class.base_class.name
end

#base_columnsObject



281
282
283
# File 'lib/inventory_refresh/inventory_collection.rb', line 281

def base_columns
  @base_columns ||= (unique_index_columns + internal_columns + not_null_columns).uniq
end

#batch_sizeInteger

Returns default batch size for talking to the DB.

Returns:

  • (Integer)

    default batch size for talking to the DB



461
462
463
# File 'lib/inventory_refresh/inventory_collection.rb', line 461

def batch_size
  1000
end

#batch_size_pure_sqlInteger

Returns default batch size for talking to the DB if not using ApplicationRecord objects.

Returns:

  • (Integer)

    default batch size for talking to the DB if not using ApplicationRecord objects



466
467
468
# File 'lib/inventory_refresh/inventory_collection.rb', line 466

def batch_size_pure_sql
  10_000
end

#blacklist_attributes!(attributes) ⇒ Array<Symbol>

Add passed attributes to blacklist. The manager_ref attributes cannot be blacklisted, otherwise we will not be able to identify the inventory_object. We do not automatically remove attributes causing fixed dependencies, so beware that without them, you won’t be able to create the record.

Parameters:

  • attributes (Array<Symbol>)

    Attributes we want to blacklist

Returns:

  • (Array<Symbol>)

    All blacklisted attributes



402
403
404
# File 'lib/inventory_refresh/inventory_collection.rb', line 402

def blacklist_attributes!(attributes)
  self.attributes_blacklist += attributes - (fixed_attributes + internal_attributes)
end

#build_multi_selection_condition(hashes, keys = unique_index_keys) ⇒ String

Builds a multiselection conditions like (table1.a = a1 AND table2.b = b1) OR (table1.a = a2 AND table2.b = b2)

Parameters:

  • hashes (Array<Hash>)

    data we want to use for the query

  • keys (Array<Symbol>) (defaults to: unique_index_keys)

    keys of attributes involved

Returns:

  • (String)

    A condition usable in .where of an ActiveRecord relation



475
476
477
478
479
480
# File 'lib/inventory_refresh/inventory_collection.rb', line 475

def build_multi_selection_condition(hashes, keys = unique_index_keys)
  arel_table = model_class.arel_table
  # We do pure SQL OR, since Arel is nesting every .or into another parentheses, otherwise this would be just
  # inject(:or) instead of to_sql with .join(" OR ")
  hashes.map { |hash| "(#{keys.map { |key| arel_table[key].eq(hash[key]) }.inject(:and).to_sql})" }.join(" OR ")
end

#cloneInventoryCollection

Returns a shallow copy of InventoryCollection, the copy will share data_storage of the original collection, otherwise we would be copying a lot of records in memory.

Returns:

  • (InventoryCollection)

    a shallow copy of InventoryCollection, the copy will share data_storage of the original collection, otherwise we would be copying a lot of records in memory.



418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
# File 'lib/inventory_refresh/inventory_collection.rb', line 418

def clone
  cloned = self.class.new(:model_class           => model_class,
                          :manager_ref           => manager_ref,
                          :association           => association,
                          :parent                => parent,
                          :arel                  => arel,
                          :strategy              => strategy,
                          :custom_save_block     => custom_save_block,
                          # We want cloned IC to be update only, since this is used for cycle resolution
                          :update_only           => true,
                          # Dependency attributes need to be a hard copy, since those will differ for each
                          # InventoryCollection
                          :dependency_attributes => dependency_attributes.clone)

  cloned.data_storage = data_storage
  cloned
end

#db_collection_for_comparisonInventoryRefresh::ApplicationRecordIterator

Returns iterator for the passed references and a query

Returns:



485
486
487
# File 'lib/inventory_refresh/inventory_collection.rb', line 485

def db_collection_for_comparison
  InventoryRefresh::ApplicationRecordIterator.new(:inventory_collection => self)
end

#db_collection_for_comparison_for(references) ⇒ ActiveRecord::Relation

Builds an ActiveRecord::Relation that can fetch all the references from the DB

Parameters:

Returns:

  • (ActiveRecord::Relation)

    relation that can fetch all the references from the DB



515
516
517
518
519
520
521
522
# File 'lib/inventory_refresh/inventory_collection.rb', line 515

def db_collection_for_comparison_for(references)
  query = full_collection_for_comparison.where(targeted_selection_for(references))
  if pure_sql_record_fetching?
    return get_connection.query(query.select(*select_keys).to_sql)
  end

  query
end

#dependenciesArray<InventoryRefresh::InventoryCollection>

Returns all unique non saved dependencies.

Returns:



379
380
381
# File 'lib/inventory_refresh/inventory_collection.rb', line 379

def dependencies
  filtered_dependency_attributes.values.map(&:to_a).flatten.uniq.reject(&:saved?)
end

#dependency_attributes_for(inventory_collections) ⇒ Array<InventoryRefresh::InventoryCollection>

Returns what attributes are causing a dependencies to certain InventoryCollection objects.

Parameters:

Returns:



388
389
390
391
392
393
394
# File 'lib/inventory_refresh/inventory_collection.rb', line 388

def dependency_attributes_for(inventory_collections)
  attributes = Set.new
  inventory_collections.each do |inventory_collection|
    attributes += filtered_dependency_attributes.select { |_key, value| value.include?(inventory_collection) }.keys
  end
  attributes
end

#filtered_dependency_attributesHash{Symbol => Set}

List attributes causing a dependency and filters them by attributes_blacklist and attributes_whitelist

Returns:

  • (Hash{Symbol => Set})

    attributes causing a dependency and filtered by blacklist and whitelist



326
327
328
329
330
331
332
333
334
335
336
337
338
# File 'lib/inventory_refresh/inventory_collection.rb', line 326

def filtered_dependency_attributes
  filtered_attributes = dependency_attributes

  if attributes_blacklist.present?
    filtered_attributes = filtered_attributes.reject { |key, _value| attributes_blacklist.include?(key) }
  end

  if attributes_whitelist.present?
    filtered_attributes = filtered_attributes.select { |key, _value| attributes_whitelist.include?(key) }
  end

  filtered_attributes
end

#fixed_attributesArray<Symbol>

Attributes that are needed to be able to save the record, i.e. attributes that are part of the unique index and attributes with presence validation or NOT NULL constraint

Returns:

  • (Array<Symbol>)

    attributes that are needed for saving of the record



344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
# File 'lib/inventory_refresh/inventory_collection.rb', line 344

def fixed_attributes
  not_null_attributes = []

  if model_class
    # Attrs having presence validator
    presence_validators = model_class.validators.detect { |x| x.kind_of?(ActiveRecord::Validations::PresenceValidator) }
    not_null_attributes += presence_validators.attributes if presence_validators.present?

    # Column names having NOT NULL constraint
    non_null_constraints = model_class.columns_hash.values.reject(&:null).map(&:name) - [model_class.primary_key]
    not_null_attributes += non_null_constraints.map(&:to_sym)

    # Column names having NOT NULL constraint transformed to relation names
    not_null_attributes += non_null_constraints.map {|x| foreign_key_to_association_mapping[x]}.compact
  end
  # Attributes that has to be always on the entity, so attributes making unique index of the record + attributes
  # that have presence validation

  fixed_attributes = manager_ref
  fixed_attributes += not_null_attributes.uniq
  fixed_attributes
end

#fixed_dependenciesObject

Returns fixed dependencies, which are the ones we can’t move, because we wouldn’t be able to save the data



370
371
372
373
374
375
376
# File 'lib/inventory_refresh/inventory_collection.rb', line 370

def fixed_dependencies
  fixed_attrs = fixed_attributes

  filtered_dependency_attributes.each_with_object(Set.new) do |(key, value), fixed_deps|
    fixed_deps.merge(value) if fixed_attrs.include?(key)
  end.reject(&:saved?)
end

#full_collection_for_comparisonActiveRecord::Relation

Returns relation that can fetch all the references from the DB.

Returns:

  • (ActiveRecord::Relation)

    relation that can fetch all the references from the DB



525
526
527
528
529
# File 'lib/inventory_refresh/inventory_collection.rb', line 525

def full_collection_for_comparison
  return arel unless arel.nil?
  rel = parent.send(association)
  rel
end

#get_connectionActiveRecord::ConnectionAdapters::AbstractAdapter

Returns ActiveRecord connection.

Returns:

  • (ActiveRecord::ConnectionAdapters::AbstractAdapter)

    ActiveRecord connection



503
504
505
# File 'lib/inventory_refresh/inventory_collection.rb', line 503

def get_connection
  ActiveRecord::Base.connection
end

#inspectString

Returns a concise form of the InventoryCollection for easy logging.

Returns:

  • (String)

    a concise form of the InventoryCollection for easy logging



456
457
458
# File 'lib/inventory_refresh/inventory_collection.rb', line 456

def inspect
  to_s
end

#internal_columnsObject



252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
# File 'lib/inventory_refresh/inventory_collection.rb', line 252

def internal_columns
  return @internal_columns if @internal_columns

  @internal_columns = [] + internal_timestamp_columns
  @internal_columns << :type if supports_sti?
  @internal_columns += [resource_version_column,
                        :resource_timestamps_max,
                        :resource_timestamps,
                        :resource_timestamp,
                        :resource_counters_max,
                        :resource_counters,
                        :resource_counter].collect do |col|
    col if supports_column?(col)
  end.compact
end

#internal_timestamp_columnsObject



268
269
270
271
272
273
274
# File 'lib/inventory_refresh/inventory_collection.rb', line 268

def internal_timestamp_columns
  return @internal_timestamp_columns if @internal_timestamp_columns

  @internal_timestamp_columns = %i(created_at created_on updated_at updated_on).collect do |timestamp_col|
    timestamp_col if supports_column?(timestamp_col)
  end.compact
end

#inventory_object?(value) ⇒ Boolean

Returns true is value is kind of InventoryRefresh::InventoryObject.

Parameters:

  • value (Object)

    Object we want to test

Returns:

  • (Boolean)

    true is value is kind of InventoryRefresh::InventoryObject



292
293
294
# File 'lib/inventory_refresh/inventory_collection.rb', line 292

def inventory_object?(value)
  value.kind_of?(::InventoryRefresh::InventoryObject)
end

#inventory_object_lazy?(value) ⇒ Boolean

Returns true is value is kind of InventoryRefresh::InventoryObjectLazy.

Parameters:

  • value (Object)

    Object we want to test

Returns:

  • (Boolean)

    true is value is kind of InventoryRefresh::InventoryObjectLazy



298
299
300
# File 'lib/inventory_refresh/inventory_collection.rb', line 298

def inventory_object_lazy?(value)
  value.kind_of?(::InventoryRefresh::InventoryObjectLazy)
end

#manager_ref_to_colsArray<String>

Convert manager_ref list of attributes to list of DB columns

Returns:

  • (Array<String>)

    Converted manager_ref list of attributes to list of DB columns



315
316
317
318
319
320
321
# File 'lib/inventory_refresh/inventory_collection.rb', line 315

def manager_ref_to_cols
  # TODO(lsmola) this should contain the polymorphic _type, otherwise the IC with polymorphic unique key will get
  # conflicts
  manager_ref.map do |ref|
    association_to_foreign_key_mapping[ref] || ref
  end
end

#new_inventory_object(hash) ⇒ InventoryRefresh::InventoryObject

Creates InventoryRefresh::InventoryObject object from passed hash data

Parameters:

  • hash (Hash)

    Object data

Returns:



535
536
537
538
539
540
541
542
# File 'lib/inventory_refresh/inventory_collection.rb', line 535

def new_inventory_object(hash)
  manager_ref.each do |x|
    # TODO(lsmola) with some effort, we can do this, but it's complex
    raise "A lazy_find with a :key can't be a part of the manager_uuid" if inventory_object_lazy?(hash[x]) && hash[x].key
  end

  inventory_object_class.new(self, hash)
end

#not_null_columnsArray

Returns Array of column names that have not null constraint.

Returns:

  • (Array)

    Array of column names that have not null constraint



277
278
279
# File 'lib/inventory_refresh/inventory_collection.rb', line 277

def not_null_columns
  @not_null_constraint_columns ||= model_class.columns.reject(&:null).map { |x| x.name.to_sym } - [model_class.primary_key.to_sym]
end

#object_index_with_keys(keys, record) ⇒ String

Builds string uuid from passed Object and keys

Parameters:

  • keys (Array<Symbol>)

    Indexes into the Hash data

  • record (ApplicationRecord)

    ActiveRecord record

Returns:

  • (String)

    Concatenated values on keys from data



307
308
309
310
# File 'lib/inventory_refresh/inventory_collection.rb', line 307

def object_index_with_keys(keys, record)
  # TODO(lsmola) remove, last usage is in k8s reconnect logic
  build_stringified_reference_for_record(record, keys)
end

#pure_sql_record_fetching?Boolean

Returns:

  • (Boolean)


507
508
509
# File 'lib/inventory_refresh/inventory_collection.rb', line 507

def pure_sql_record_fetching?
  !use_ar_object?
end

#resource_version_columnObject



248
249
250
# File 'lib/inventory_refresh/inventory_collection.rb', line 248

def resource_version_column
  :resource_version
end

#select_keysObject



498
499
500
# File 'lib/inventory_refresh/inventory_collection.rb', line 498

def select_keys
  @select_keys ||= [@model_class.primary_key] + manager_ref_to_cols.map(&:to_s) + internal_columns.map(&:to_s)
end

#store_created_records(records) ⇒ Object

Caches what records were created, for later use, e.g. post provision behavior

Parameters:

  • records (Array<ApplicationRecord, Hash>)

    list of stored records



175
176
177
# File 'lib/inventory_refresh/inventory_collection.rb', line 175

def store_created_records(records)
  @created_records.concat(records_identities(records))
end

#store_deleted_records(records) ⇒ Object

Caches what records were deleted/soft-deleted, for later use, e.g. post provision behavior

Parameters:

  • records (Array<ApplicationRecord, Hash>)

    list of stored records



189
190
191
# File 'lib/inventory_refresh/inventory_collection.rb', line 189

def store_deleted_records(records)
  @deleted_records.concat(records_identities(records))
end

#store_unconnected_edges(inventory_object, inventory_object_key, inventory_object_lazy) ⇒ Object



165
166
167
168
169
170
# File 'lib/inventory_refresh/inventory_collection.rb', line 165

def store_unconnected_edges(inventory_object, inventory_object_key, inventory_object_lazy)
  (@unconnected_edges ||= []) <<
    InventoryRefresh::InventoryCollection::UnconnectedEdge.new(
      inventory_object, inventory_object_key, inventory_object_lazy
    )
end

#store_updated_records(records) ⇒ Object

Caches what records were updated, for later use, e.g. post provision behavior

Parameters:

  • records (Array<ApplicationRecord, Hash>)

    list of stored records



182
183
184
# File 'lib/inventory_refresh/inventory_collection.rb', line 182

def store_updated_records(records)
  @updated_records.concat(records_identities(records))
end

#targeted_selection_for(references) ⇒ String

Builds a multiselection conditions like (table1.a = a1 AND table2.b = b1) OR (table1.a = a2 AND table2.b = b2) for passed references

Parameters:

Returns:

  • (String)

    A condition usable in .where of an ActiveRecord relation



494
495
496
# File 'lib/inventory_refresh/inventory_collection.rb', line 494

def targeted_selection_for(references)
  build_multi_selection_condition(references.map(&:second))
end

#to_sString

Returns a concise form of the inventoryCollection for easy logging.

Returns:

  • (String)

    a concise form of the inventoryCollection for easy logging



444
445
446
447
448
449
450
451
452
453
# File 'lib/inventory_refresh/inventory_collection.rb', line 444

def to_s
  whitelist = ", whitelist: [#{attributes_whitelist.to_a.join(", ")}]" if attributes_whitelist.present?
  blacklist = ", blacklist: [#{attributes_blacklist.to_a.join(", ")}]" if attributes_blacklist.present?

  strategy_name = ", strategy: #{strategy}" if strategy

  name = model_class || association

  "InventoryCollection:<#{name}>#{whitelist}#{blacklist}#{strategy_name}"
end

#uniq_keys_candidates(keys) ⇒ Array<ActiveRecord::ConnectionAdapters::IndexDefinition>

Find candidates for unique key. Candidate must cover all columns we are passing as keys.

Parameters:

  • keys (Array<Symbol>)

Returns:

  • (Array<ActiveRecord::ConnectionAdapters::IndexDefinition>)

    Array of unique indexes fitting the keys

Raises:

  • (Exception)

    if the unique index for the columns was not found



236
237
238
239
240
241
242
243
244
245
246
# File 'lib/inventory_refresh/inventory_collection.rb', line 236

def uniq_keys_candidates(keys)
  # Find all uniq indexes that that are covering our keys
  uniq_key_candidates = unique_indexes.each_with_object([]) { |i, obj| obj << i if (keys - i.columns.map(&:to_sym)).empty? }

  if unique_indexes.blank? || uniq_key_candidates.blank?
    raise "#{self} and its table #{model_class.table_name} must have a unique index defined "\
            "covering columns #{keys} to be able to use saver_strategy :concurrent_safe_batch."
  end

  uniq_key_candidates
end

#unique_index_columnsArray<Symbol>

Returns all columns that are part of the best fit unique index.

Returns:

  • (Array<Symbol>)

    all columns that are part of the best fit unique index



194
195
196
197
198
# File 'lib/inventory_refresh/inventory_collection.rb', line 194

def unique_index_columns
  return @unique_index_columns if @unique_index_columns

  @unique_index_columns = unique_index_for(unique_index_keys).columns.map(&:to_sym)
end

#unique_index_for(keys) ⇒ ActiveRecord::ConnectionAdapters::IndexDefinition

Finds an index that fits the list of columns (keys) the best

Parameters:

  • keys (Array<Symbol>)

Returns:

  • (ActiveRecord::ConnectionAdapters::IndexDefinition)

    unique index fitting the keys

Raises:

  • (Exception)

    if the unique index for the columns was not found



223
224
225
226
227
228
229
# File 'lib/inventory_refresh/inventory_collection.rb', line 223

def unique_index_for(keys)
  @unique_index_for_keys_cache ||= {}
  @unique_index_for_keys_cache[keys] if @unique_index_for_keys_cache[keys]

  # Take the uniq key having the least number of columns
  @unique_index_for_keys_cache[keys] = uniq_keys_candidates(keys).min_by { |x| x.columns.count }
end

#unique_index_keysObject



200
201
202
# File 'lib/inventory_refresh/inventory_collection.rb', line 200

def unique_index_keys
  @unique_index_keys ||= manager_ref_to_cols.map(&:to_sym)
end

#unique_indexesArray<ActiveRecord::ConnectionAdapters::IndexDefinition>

Returns array of all unique indexes known to model.

Returns:

  • (Array<ActiveRecord::ConnectionAdapters::IndexDefinition>)

    array of all unique indexes known to model



205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/inventory_refresh/inventory_collection.rb', line 205

def unique_indexes
  @unique_indexes_cache if @unique_indexes_cache

  @unique_indexes_cache = model_class.connection.indexes(model_class.table_name).select(&:unique)

  if @unique_indexes_cache.blank?
    raise "#{self} and its table #{model_class.table_name} must have a unique index defined, to"\
            " be able to use saver_strategy :concurrent_safe_batch."
  end

  @unique_indexes_cache
end

#whitelist_attributes!(attributes) ⇒ Array<Symbol>

Add passed attributes to whitelist. The manager_ref attributes always needs to be in the white list, otherwise we will not be able to identify theinventory_object. We do not automatically add attributes causing fixed dependencies, so beware that without them, you won’t be able to create the record.

Parameters:

  • attributes (Array<Symbol>)

    Attributes we want to whitelist

Returns:

  • (Array<Symbol>)

    All whitelisted attributes



412
413
414
# File 'lib/inventory_refresh/inventory_collection.rb', line 412

def whitelist_attributes!(attributes)
  self.attributes_whitelist += attributes + (fixed_attributes + internal_attributes)
end