Class: SimpleMaster::Storage::Table
- Inherits:
-
Object
- Object
- SimpleMaster::Storage::Table
- Defined in:
- lib/simple_master/storage/table.rb
Direct Known Subclasses
Defined Under Namespace
Classes: AssignmentError, ColumnNotExist
Constant Summary collapse
- METADATA_PREFIX =
"__"
Instance Attribute Summary collapse
-
#all ⇒ Object
Returns the value of attribute all.
-
#applied_diff ⇒ Object
Returns the value of attribute applied_diff.
-
#class_method_cache ⇒ Object
Returns the value of attribute class_method_cache.
-
#dataset ⇒ Object
Returns the value of attribute dataset.
-
#digest ⇒ Object
Returns the value of attribute digest.
-
#grouped_hash ⇒ Object
Returns the value of attribute grouped_hash.
-
#id_hash ⇒ Object
Returns the value of attribute id_hash.
-
#klass ⇒ Object
Returns the value of attribute klass.
-
#loader ⇒ Object
Returns the value of attribute loader.
-
#method_cache ⇒ Object
Returns the value of attribute method_cache.
-
#sub_tables ⇒ Object
Returns the value of attribute sub_tables.
Instance Method Summary collapse
- #apply_diff ⇒ Object
- #apply_diff_to_id_hash ⇒ Object
- #diff ⇒ Object
- #duplicate_for(dataset, table_klass = self.class) ⇒ Object
- #freeze_all ⇒ Object
-
#initialize(klass, dataset, loader) ⇒ Table
constructor
A new instance of Table.
- #load_records ⇒ Object
- #run_on_sub_tables(method) ⇒ Object
- #sub_table(klass) ⇒ Object
- #tap_instance_methods ⇒ Object
- #update_class_method_cache ⇒ Object
- #update_grouped_hash ⇒ Object
- #update_id_hash ⇒ Object
- #update_sub_tables ⇒ Object
Constructor Details
#initialize(klass, dataset, loader) ⇒ Table
Returns a new instance of Table.
8 9 10 11 12 13 14 15 |
# File 'lib/simple_master/storage/table.rb', line 8 def initialize(klass, dataset, loader) @klass = klass @dataset = dataset @loader = loader @method_cache = Hash.new { |k, v| k[v] = {}.compare_by_identity }.compare_by_identity @sub_tables = nil end |
Instance Attribute Details
#all ⇒ Object
Returns the value of attribute all.
50 51 52 |
# File 'lib/simple_master/storage/table.rb', line 50 def all @all end |
#applied_diff ⇒ Object
Returns the value of attribute applied_diff.
55 56 57 |
# File 'lib/simple_master/storage/table.rb', line 55 def applied_diff @applied_diff end |
#class_method_cache ⇒ Object
Returns the value of attribute class_method_cache.
53 54 55 |
# File 'lib/simple_master/storage/table.rb', line 53 def class_method_cache @class_method_cache end |
#dataset ⇒ Object
Returns the value of attribute dataset.
47 48 49 |
# File 'lib/simple_master/storage/table.rb', line 47 def dataset @dataset end |
#digest ⇒ Object
Returns the value of attribute digest.
56 57 58 |
# File 'lib/simple_master/storage/table.rb', line 56 def digest @digest end |
#grouped_hash ⇒ Object
Returns the value of attribute grouped_hash.
52 53 54 |
# File 'lib/simple_master/storage/table.rb', line 52 def grouped_hash @grouped_hash end |
#id_hash ⇒ Object
Returns the value of attribute id_hash.
51 52 53 |
# File 'lib/simple_master/storage/table.rb', line 51 def id_hash @id_hash end |
#klass ⇒ Object
Returns the value of attribute klass.
46 47 48 |
# File 'lib/simple_master/storage/table.rb', line 46 def klass @klass end |
#loader ⇒ Object
Returns the value of attribute loader.
48 49 50 |
# File 'lib/simple_master/storage/table.rb', line 48 def loader @loader end |
#method_cache ⇒ Object
Returns the value of attribute method_cache.
54 55 56 |
# File 'lib/simple_master/storage/table.rb', line 54 def method_cache @method_cache end |
#sub_tables ⇒ Object
Returns the value of attribute sub_tables.
49 50 51 |
# File 'lib/simple_master/storage/table.rb', line 49 def sub_tables @sub_tables end |
Instance Method Details
#apply_diff ⇒ Object
130 131 132 133 134 135 136 137 138 139 |
# File 'lib/simple_master/storage/table.rb', line 130 def apply_diff update_id_hash if diff.present? apply_diff_to_id_hash self.all = id_hash.values.freeze end update_grouped_hash self end |
#apply_diff_to_id_hash ⇒ Object
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
# File 'lib/simple_master/storage/table.rb', line 141 def apply_diff_to_id_hash id_hash = self.id_hash.dup diff&.each do |key, record_diff| next if (key) id = key.to_i if record_diff.nil? id_hash.delete(id) next end original_record = id_hash[id] record = if original_record.nil? new_klass = klass.sti_column && record_diff[klass.sti_column.to_s]&.constantize || klass new_klass.new(id: id) elsif klass.sti_column && record_diff[klass.sti_column.to_s] record_diff[klass.sti_column.to_s].constantize.new(original_record.attributes) else original_record.create_copy end record_diff.each do |k, v| next if (k) # Handle expanded JSON columns by converting keys back to JSON strings before assignment if v.is_a?(Hash) || v.is_a?(Array) v = v.to_json end record.send(:"#{k}=", v) rescue NoMethodError => _e raise ColumnNotExist, "Column #{k} does not exist on #{klass}." rescue => e raise AssignmentError, "Failed to assign data: #{klass}.#{k} = #{v.inspect}. Message: #{e.}." end id_hash[id] = record end self.applied_diff = diff self.id_hash = id_hash.freeze end |
#diff ⇒ Object
126 127 128 |
# File 'lib/simple_master/storage/table.rb', line 126 def diff dataset.diff[klass.table_name] end |
#duplicate_for(dataset, table_klass = self.class) ⇒ Object
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/simple_master/storage/table.rb', line 21 def duplicate_for(dataset, table_klass = self.class) table = table_klass.new(klass, dataset, loader) if table.diff == applied_diff table.all = all table.applied_diff = applied_diff table.digest = digest # If already loaded, copy existing id_hash and grouped_hash table.id_hash = id_hash if @id_hash table.grouped_hash = grouped_hash if @grouped_hash table.sub_tables = sub_tables&.transform_values { |sub_table| sub_table.duplicate_for(dataset) } end table end |
#freeze_all ⇒ Object
58 59 60 |
# File 'lib/simple_master/storage/table.rb', line 58 def freeze_all all.each(&:freeze).tap { run_on_sub_tables(:freeze_all) } end |
#load_records ⇒ Object
40 41 42 43 44 |
# File 'lib/simple_master/storage/table.rb', line 40 def load_records @method_cache.clear loader.load_records(self) end |
#run_on_sub_tables(method) ⇒ Object
122 123 124 |
# File 'lib/simple_master/storage/table.rb', line 122 def run_on_sub_tables(method) sub_tables&.each_value(&method) end |
#sub_table(klass) ⇒ Object
17 18 19 |
# File 'lib/simple_master/storage/table.rb', line 17 def sub_table(klass) @sub_tables[klass] end |
#tap_instance_methods ⇒ Object
95 96 97 98 99 100 |
# File 'lib/simple_master/storage/table.rb', line 95 def tap_instance_methods klass.instance_methods_need_tap&.each do |method_name| all.each(&method_name) end run_on_sub_tables(:tap_instance_methods) end |
#update_class_method_cache ⇒ Object
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/simple_master/storage/table.rb', line 77 def update_class_method_cache self.class_method_cache = class_method_cache = {}.compare_by_identity # Use instance_eval so a block runs in the declaring class context klass.all_class_method_cache_info.each do |args, initializer| result = klass.instance_eval(&initializer) if args.length == 1 result = [result] end args.zip(result).each do |arg, value| class_method_cache[arg] = value end end class_method_cache.freeze.tap { run_on_sub_tables(:update_class_method_cache) } end |
#update_grouped_hash ⇒ Object
66 67 68 69 70 71 72 73 74 75 |
# File 'lib/simple_master/storage/table.rb', line 66 def update_grouped_hash grouped_hash = {}.compare_by_identity klass.group_keys.each do |group_key| grouped_hash[group_key] = all.group_by(&group_key).freeze.each_value(&:freeze) end grouped_hash.freeze self.grouped_hash = grouped_hash end |
#update_id_hash ⇒ Object
62 63 64 |
# File 'lib/simple_master/storage/table.rb', line 62 def update_id_hash self.id_hash = all.index_by(&:id).freeze end |
#update_sub_tables ⇒ Object
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/simple_master/storage/table.rb', line 102 def update_sub_tables sub_klasses = klass.descendants.reject(&:abstract_class) return if sub_klasses.empty? @sub_tables = sub_klasses.index_with { |sub_klass| self.class.new(sub_klass, dataset, loader) } grouped = all.group_by(&:class) sub_klasses.each do |sub_klass| sub_sub_klasses = [sub_klass, *sub_klass.descendants].reject(&:abstract_class) sub_table = self.sub_table(sub_klass) sub_table.all = sub_sub_klasses.flat_map { grouped[_1] || EMPTY_ARRAY }.freeze sub_table.digest = digest sub_table.applied_diff = applied_diff sub_table.update_id_hash sub_table.update_grouped_hash end end |