Module: Sequel::Packer::EagerHash
- Defined in:
- lib/sequel/packer/eager_hash.rb
Defined Under Namespace
Classes: MixedProcHashError, MultipleProcKeysError, NestedEagerProcsError
Class Method Summary collapse
-
.deep_dup(hash) ⇒ Object
Creates a deep copy of an eager hash.
- .is_proc_hash?(hash) ⇒ Boolean
-
.merge(hash1, hash2) ⇒ Object
Merges two eager hashes together, without modifying either one.
-
.merge!(hash1, hash2) ⇒ Object
Merges two eager hashes together, modifying the first hash, while leaving the second unmodified.
-
.normalize_eager_args(*associations) ⇒ Object
Sequel’s eager function can accept arguments in a number of different formats: .eager(:assoc) .eager([:assoc1, :assoc2]) .eager(assoc: :nested_assoc) .eager( :assoc1, assoc2: {|ds| …) => [:nested_assoc1, :nested_assoc2]}, ).
Class Method Details
.deep_dup(hash) ⇒ Object
Creates a deep copy of an eager hash.
165 166 167 168 |
# File 'lib/sequel/packer/eager_hash.rb', line 165 def self.deep_dup(hash) return nil if !hash hash.transform_values {|val| deep_dup(val)} end |
.is_proc_hash?(hash) ⇒ Boolean
107 108 109 110 111 |
# File 'lib/sequel/packer/eager_hash.rb', line 107 def self.is_proc_hash?(hash) return false if !hash.is_a?(Hash) return false if hash.size != 1 hash.keys[0].is_a?(Proc) end |
.merge(hash1, hash2) ⇒ Object
Merges two eager hashes together, without modifying either one.
114 115 116 117 |
# File 'lib/sequel/packer/eager_hash.rb', line 114 def self.merge(hash1, hash2) return deep_dup(hash2) if !hash1 merge!(deep_dup(hash1), hash2) end |
.merge!(hash1, hash2) ⇒ Object
Merges two eager hashes together, modifying the first hash, while leaving the second unmodified. Since the first argument may be nil, callers should still use the return value, rather than the first argument.
123 124 125 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 |
# File 'lib/sequel/packer/eager_hash.rb', line 123 def self.merge!(hash1, hash2) return hash1 if !hash2 return deep_dup(hash2) if !hash1 hash2.each do |key, val2| if !hash1.key?(key) hash1[key] = deep_dup(val2) next end val1 = hash1[key] h1_is_proc_hash = is_proc_hash?(val1) h2_is_proc_hash = is_proc_hash?(val2) case [h1_is_proc_hash, h2_is_proc_hash] when [false, false] hash1[key] = merge!(val1, val2) when [true, false] # We want to actually merge the hash the proc points to. eager_proc, nested_hash = val1.entries[0] hash1[key] = {eager_proc => merge!(nested_hash, val2)} when [false, true] # Same as above, but flipped. Notice the order of the arguments to # merge! to ensure hash2 is not modified! eager_proc, nested_hash = val2.entries[0] hash1[key] = {eager_proc => merge!(val1, nested_hash)} when [true, true] # Create a new proc that applies both procs, then merge their # respective hashes. proc1, nested_hash1 = val1.entries[0] proc2, nested_hash2 = val2.entries[0] new_proc = (proc {|ds| proc2.call(proc1.call(ds))}) hash1[key] = {new_proc => merge!(nested_hash1, nested_hash2)} end end hash1 end |
.normalize_eager_args(*associations) ⇒ Object
Sequel’s eager function can accept arguments in a number of different formats:
.eager(:assoc)
.eager([:assoc1, :assoc2])
.eager(assoc: :nested_assoc)
.eager(
:assoc1,
assoc2: {(proc {|ds| ...}) => [:nested_assoc1, :nested_assoc2]},
)
This method normalizes these arguments such that:
-
A Hash is returned
-
The keys of that hash are the names of associations
-
The values of that hash are either:
-
nil, representing no nested associations
-
a nested normalized hash, meeting these definitions
-
a “Proc hash”, which is a hash with a single key, which is a proc, and whose value is either nil or a nested normalized hash.
-
Notice that a normalized has the property that every value in the hash is either nil, or itself a normalized hash.
Note that this method cannot return a “Proc hash” as the top level normalized hash; Proc hashes can only be nested under other associations.
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 |
# File 'lib/sequel/packer/eager_hash.rb', line 40 def self.normalize_eager_args(*associations) # Implementation largely borrowed from Sequel's # eager_options_for_associations: # # https://github.com/jeremyevans/sequel/blob/5.32.0/lib/sequel/model/associations.rb#L3228-L3245 normalized_hash = {} associations.flatten.each do |association| case association when Symbol normalized_hash[association] = nil when Hash num_proc_keys = 0 num_symbol_keys = 0 association.each do |key, val| case key when Symbol num_symbol_keys += 1 when Proc num_proc_keys += 1 if val.is_a?(Proc) || is_proc_hash?(val) raise( NestedEagerProcsError, "eager hash has nested Procs: #{associations.inspect}", ) end end if val.nil? # Already normalized normalized_hash[key] = nil elsif val.is_a?(Proc) # Convert Proc value to a Proc hash. normalized_hash[key] = {val => nil} else # Otherwise recurse. normalized_hash[key] = normalize_eager_args(val) end end if num_proc_keys > 1 raise( MultipleProcKeysError, "eager hash has multiple Proc keys: #{associations.inspect}", ) end if num_proc_keys > 0 && num_symbol_keys > 0 raise( MixedProcHashError, 'eager hash has both symbol keys and Proc keys: ' + associations.inspect, ) end else raise( Sequel::Error, 'Associations must be in the form of a symbol or hash', ) end end normalized_hash end |