Class: DatasetRecord
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- DatasetRecord
- Includes:
- Housekeeping, Shared::IsData
- Defined in:
- app/models/dataset_record.rb
Overview
A DatasetRecord is the unit of data (typically a table row) from an ImportDataset
Direct Known Subclasses
Defined Under Namespace
Classes: DarwinCore
Instance Attribute Summary collapse
-
#metadata ⇒ Hash
Data about the record.
-
#status ⇒ String
Current import status (e.g. Pending, Imported, Deleted, etc.).
Instance Method Summary collapse
- #create_fields ⇒ Object private
- #data_field_changed(index, value) ⇒ Object private
- #data_fields ⇒ Object
-
#dataset_record_fields ⇒ Object
has_many has serious performance consequences when deleting an import dataset, so using class method instead.
- #destroy_fields ⇒ Object private
- #field_db_attributes(position, value) ⇒ Object private
- #fields_db_attributes ⇒ Object private
- #frozen_fields? ⇒ Boolean
- #get_data_field(index) ⇒ Object
- #ignored_fields ⇒ Object
-
#initialize_data_fields(field_data) ⇒ Object
Sets up internal representation of data fields with field data, skipping those fields that are blank for performance and space-efficiency reasons.
- #set_data_field(index, value) ⇒ Object
- #update_fields ⇒ Object private
Methods included from Shared::IsData
#errors_excepting, #full_error_messages_excepting, #identical, #is_community?, #is_in_use?, #similar
Methods included from Housekeeping
#has_polymorphic_relationship?
Methods inherited from ApplicationRecord
Instance Attribute Details
#metadata ⇒ Hash
Returns data about the record. No particular structure is enforced, any subclass may store metadata (typically to aid the import process).
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'app/models/dataset_record.rb', line 11 class DatasetRecord < ApplicationRecord include Housekeeping include Shared::IsData belongs_to :import_dataset validates :type, presence: true validates :status, presence: true after_create :create_fields after_update :update_fields before_destroy :destroy_fields # has_many has serious performance consequences when deleting an import dataset, so using class method instead def dataset_record_fields DatasetRecordField.where(dataset_record: self) end # Sets up internal representation of data fields with field data, skipping those fields that are blank for performance and space-efficiency reasons. # @param field_data [Array] ordered list of values, each value representing a cell/field of the record. def initialize_data_fields(field_data) @data_fields = [] field_data.each_with_index do |value, index| @data_fields[index] = (value.blank? ? nil : value) end @data_field_changed = Array.new(@data_fields.size) end def data_fields unless @data_fields @data_fields = self.dataset_record_fields .pluck(:position, :value) .inject([]) { |a, f| a[f[0]] = f[1]; a } @data_field_changed = Array.new(@data_fields.size) end @data_fields end def ignored_fields # Subclasses may re-implement to inform which fields are ignored by this particular record end def get_data_field(index) self.data_fields[index] end def set_data_field(index, value) unless frozen_fields? old = self.data_fields[index] self.data_fields[index] = value begin data_field_changed(index, value) @data_field_changed[index] = true rescue self.data_fields[index] = old raise end end end def frozen_fields? self.status == 'Imported' end private def data_field_changed(index, value) # Subclasses may re-implement to perform actions when field change end def field_db_attributes(position, value) { position: position, value: value, dataset_record_id: id, project_id: project_id, import_dataset_id: import_dataset_id, encoded_dataset_record_type: DatasetRecordField.encode_record_type(self.class) } if value end def fields_db_attributes data_fields.filter_map.with_index { |v, p| field_db_attributes(p, v) } end def create_fields attributes = fields_db_attributes DatasetRecordField.insert_all(attributes) if attributes.any? end def update_fields upsert_fields = @data_field_changed &.filter_map&.with_index { |c, i| field_db_attributes(i, data_fields[i]) if c } || [] delete_fields = @data_field_changed &.filter_map&.with_index { |c, i| i if c && data_fields[i].blank? } || [] DatasetRecordField.upsert_all(upsert_fields, unique_by: [:dataset_record_id, :position]) if upsert_fields.any? dataset_record_fields.where(position: delete_fields).delete_all if delete_fields.any? end def destroy_fields dataset_record_fields.delete_all end end |
#status ⇒ String
Returns current import status (e.g. Pending, Imported, Deleted, etc.).
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'app/models/dataset_record.rb', line 11 class DatasetRecord < ApplicationRecord include Housekeeping include Shared::IsData belongs_to :import_dataset validates :type, presence: true validates :status, presence: true after_create :create_fields after_update :update_fields before_destroy :destroy_fields # has_many has serious performance consequences when deleting an import dataset, so using class method instead def dataset_record_fields DatasetRecordField.where(dataset_record: self) end # Sets up internal representation of data fields with field data, skipping those fields that are blank for performance and space-efficiency reasons. # @param field_data [Array] ordered list of values, each value representing a cell/field of the record. def initialize_data_fields(field_data) @data_fields = [] field_data.each_with_index do |value, index| @data_fields[index] = (value.blank? ? nil : value) end @data_field_changed = Array.new(@data_fields.size) end def data_fields unless @data_fields @data_fields = self.dataset_record_fields .pluck(:position, :value) .inject([]) { |a, f| a[f[0]] = f[1]; a } @data_field_changed = Array.new(@data_fields.size) end @data_fields end def ignored_fields # Subclasses may re-implement to inform which fields are ignored by this particular record end def get_data_field(index) self.data_fields[index] end def set_data_field(index, value) unless frozen_fields? old = self.data_fields[index] self.data_fields[index] = value begin data_field_changed(index, value) @data_field_changed[index] = true rescue self.data_fields[index] = old raise end end end def frozen_fields? self.status == 'Imported' end private def data_field_changed(index, value) # Subclasses may re-implement to perform actions when field change end def field_db_attributes(position, value) { position: position, value: value, dataset_record_id: id, project_id: project_id, import_dataset_id: import_dataset_id, encoded_dataset_record_type: DatasetRecordField.encode_record_type(self.class) } if value end def fields_db_attributes data_fields.filter_map.with_index { |v, p| field_db_attributes(p, v) } end def create_fields attributes = fields_db_attributes DatasetRecordField.insert_all(attributes) if attributes.any? end def update_fields upsert_fields = @data_field_changed &.filter_map&.with_index { |c, i| field_db_attributes(i, data_fields[i]) if c } || [] delete_fields = @data_field_changed &.filter_map&.with_index { |c, i| i if c && data_fields[i].blank? } || [] DatasetRecordField.upsert_all(upsert_fields, unique_by: [:dataset_record_id, :position]) if upsert_fields.any? dataset_record_fields.where(position: delete_fields).delete_all if delete_fields.any? end def destroy_fields dataset_record_fields.delete_all end end |
Instance Method Details
#create_fields ⇒ Object (private)
98 99 100 101 |
# File 'app/models/dataset_record.rb', line 98 def create_fields attributes = fields_db_attributes DatasetRecordField.insert_all(attributes) if attributes.any? end |
#data_field_changed(index, value) ⇒ Object (private)
79 80 81 |
# File 'app/models/dataset_record.rb', line 79 def data_field_changed(index, value) # Subclasses may re-implement to perform actions when field change end |
#data_fields ⇒ Object
39 40 41 42 43 44 45 46 47 48 |
# File 'app/models/dataset_record.rb', line 39 def data_fields unless @data_fields @data_fields = self.dataset_record_fields .pluck(:position, :value) .inject([]) { |a, f| a[f[0]] = f[1]; a } @data_field_changed = Array.new(@data_fields.size) end @data_fields end |
#dataset_record_fields ⇒ Object
has_many has serious performance consequences when deleting an import dataset, so using class method instead
25 26 27 |
# File 'app/models/dataset_record.rb', line 25 def dataset_record_fields DatasetRecordField.where(dataset_record: self) end |
#destroy_fields ⇒ Object (private)
113 114 115 |
# File 'app/models/dataset_record.rb', line 113 def destroy_fields dataset_record_fields.delete_all end |
#field_db_attributes(position, value) ⇒ Object (private)
83 84 85 86 87 88 89 90 91 92 |
# File 'app/models/dataset_record.rb', line 83 def field_db_attributes(position, value) { position: position, value: value, dataset_record_id: id, project_id: project_id, import_dataset_id: import_dataset_id, encoded_dataset_record_type: DatasetRecordField.encode_record_type(self.class) } if value end |
#fields_db_attributes ⇒ Object (private)
94 95 96 |
# File 'app/models/dataset_record.rb', line 94 def fields_db_attributes data_fields.filter_map.with_index { |v, p| field_db_attributes(p, v) } end |
#frozen_fields? ⇒ Boolean
73 74 75 |
# File 'app/models/dataset_record.rb', line 73 def frozen_fields? self.status == 'Imported' end |
#get_data_field(index) ⇒ Object
54 55 56 |
# File 'app/models/dataset_record.rb', line 54 def get_data_field(index) self.data_fields[index] end |
#ignored_fields ⇒ Object
50 51 52 |
# File 'app/models/dataset_record.rb', line 50 def ignored_fields # Subclasses may re-implement to inform which fields are ignored by this particular record end |
#initialize_data_fields(field_data) ⇒ Object
Sets up internal representation of data fields with field data, skipping those fields that are blank for performance and space-efficiency reasons.
31 32 33 34 35 36 37 |
# File 'app/models/dataset_record.rb', line 31 def initialize_data_fields(field_data) @data_fields = [] field_data.each_with_index do |value, index| @data_fields[index] = (value.blank? ? nil : value) end @data_field_changed = Array.new(@data_fields.size) end |
#set_data_field(index, value) ⇒ Object
58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'app/models/dataset_record.rb', line 58 def set_data_field(index, value) unless frozen_fields? old = self.data_fields[index] self.data_fields[index] = value begin data_field_changed(index, value) @data_field_changed[index] = true rescue self.data_fields[index] = old raise end end end |
#update_fields ⇒ Object (private)
103 104 105 106 107 108 109 110 111 |
# File 'app/models/dataset_record.rb', line 103 def update_fields upsert_fields = @data_field_changed &.filter_map&.with_index { |c, i| field_db_attributes(i, data_fields[i]) if c } || [] delete_fields = @data_field_changed &.filter_map&.with_index { |c, i| i if c && data_fields[i].blank? } || [] DatasetRecordField.upsert_all(upsert_fields, unique_by: [:dataset_record_id, :position]) if upsert_fields.any? dataset_record_fields.where(position: delete_fields).delete_all if delete_fields.any? end |