Module: SmartEnum::ActiveRecordCompatibility::QueryMethods
- Defined in:
- lib/smart_enum/active_record_compatibility.rb
Overview
Simulate ActiveRecord Query API
Constant Summary collapse
- STRING =
[String].freeze
- SYMBOL =
[Symbol].freeze
- BOOLEAN =
[TrueClass, FalseClass].freeze
- INTEGER =
[Integer].freeze
- BIG_DECIMAL =
[BigDecimal].freeze
Instance Method Summary collapse
- #all ⇒ Object
-
#cast_primary_key(id_input) ⇒ Object
Given an “id-like” parameter (usually the first argument to find), cast it to the same type used to index the PK lookup hash.
-
#cast_query_attrs(raw_attrs) ⇒ Object
Ensure that the attrs we query by are compatible with the internal types, casting where possible.
- #find(id, raise_on_missing: true) ⇒ Object
- #find_by(uncast_attrs) ⇒ Object
- #find_by!(attrs) ⇒ Object
- #none ⇒ Object
- #where(uncast_attrs) ⇒ Object
Instance Method Details
#all ⇒ Object
104 105 106 |
# File 'lib/smart_enum/active_record_compatibility.rb', line 104 def all values end |
#cast_primary_key(id_input) ⇒ Object
Given an “id-like” parameter (usually the first argument to find), cast it to the same type used to index the PK lookup hash.
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/smart_enum/active_record_compatibility.rb', line 153 def cast_primary_key(id_input) return if id_input == nil id_attribute = attribute_set[:id] fail "no :id attribute defined on #{self}" if !id_attribute types = id_attribute.types # if the type is already compatible, return it. return id_input if types.any? { |t| id_input.instance_of?(t) } case types when INTEGER then Integer(id_input) when STRING then id_input.to_s when SYMBOL then id_input.to_s.to_sym else fail "incompatible type: got #{id_input.class}, need #{types.inspect} or something castable to that" end end |
#cast_query_attrs(raw_attrs) ⇒ Object
Ensure that the attrs we query by are compatible with the internal types, casting where possible. This allows us to e.g.
find_by(id: '1', key: :blah)
even when types differ like we can in ActiveRecord.
117 118 119 120 121 122 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 |
# File 'lib/smart_enum/active_record_compatibility.rb', line 117 def cast_query_attrs(raw_attrs) raw_attrs.symbolize_keys.each_with_object({}) do |(k, v), new_attrs| if v.instance_of?(Array) fail "SmartEnum can't query with array arguments yet. Got #{raw_attrs.inspect}" end if (attr_def = attribute_set[k]) if attr_def.types.any?{|type| v.instance_of?(type) } # No need to cast new_attrs[k] = v elsif (v.nil? && attr_def.types != BOOLEAN) # Querying by nil is a legit case, unless the type is boolean new_attrs[k] = v elsif attr_def.types == STRING new_attrs[k] = String(v) elsif attr_def.types == INTEGER if v.instance_of?(String) && v.empty? # support querying by (id: '') new_attrs[k] = nil else new_attrs[k] = Integer(v) end elsif attr_def.types == BOOLEAN # TODO should we treat "f", 0, etc as false? new_attrs[k] = !!v elsif attr_def.types == BIG_DECIMAL new_attrs[k] = BigDecimal(v) else fail "Passed illegal query arguments for #{k}: #{v} is a #{v.class}, need #{attr_def.types} or a cast rule (got #{raw_attrs.inspect})" end else fail "#{k} is not an attribute of #{self}! (got #{raw_attrs.inspect})" end end end |
#find(id, raise_on_missing: true) ⇒ Object
74 75 76 77 78 79 80 |
# File 'lib/smart_enum/active_record_compatibility.rb', line 74 def find(id, raise_on_missing: true) self[cast_primary_key(id)].tap do |result| if !result && raise_on_missing fail ActiveRecord::RecordNotFound.new("Couldn't find #{self} with 'id'=#{id}") end end end |
#find_by(uncast_attrs) ⇒ Object
82 83 84 85 86 87 88 89 90 |
# File 'lib/smart_enum/active_record_compatibility.rb', line 82 def find_by(uncast_attrs) attrs = cast_query_attrs(uncast_attrs) if attrs.size == 1 && attrs.has_key?(:id) return find(attrs[:id], raise_on_missing: false) end all.detect do |instance| instance.attributes.slice(*attrs.keys) == attrs end end |
#find_by!(attrs) ⇒ Object
92 93 94 95 96 97 98 |
# File 'lib/smart_enum/active_record_compatibility.rb', line 92 def find_by!(attrs) find_by(attrs).tap do |result| if !result fail ActiveRecord::RecordNotFound.new("Couldn't find #{self} with #{attrs.inspect}") end end end |
#none ⇒ Object
100 101 102 |
# File 'lib/smart_enum/active_record_compatibility.rb', line 100 def none [] end |
#where(uncast_attrs) ⇒ Object
67 68 69 70 71 72 |
# File 'lib/smart_enum/active_record_compatibility.rb', line 67 def where(uncast_attrs) attrs = cast_query_attrs(uncast_attrs) all.select do |instance| instance.attributes.slice(*attrs.keys) == attrs end.tap(&:freeze) end |