Class: Praxis::Mapper::Model
- Inherits:
-
Object
- Object
- Praxis::Mapper::Model
- Extended by:
- Finalizable
- Defined in:
- lib/praxis-mapper/model.rb,
lib/praxis-mapper/support/factory_bot.rb
Constant Summary collapse
- InspectedFields =
[:@data, :@deserialized_data].freeze
Class Attribute Summary collapse
-
._identities ⇒ Object
Returns the value of attribute _identities.
-
.associations ⇒ Object
readonly
Returns the value of attribute associations.
-
.config ⇒ Object
readonly
Returns the value of attribute config.
-
.contexts ⇒ Object
readonly
Returns the value of attribute contexts.
-
.serialized_fields ⇒ Object
readonly
Returns the value of attribute serialized_fields.
Instance Attribute Summary collapse
-
#_query ⇒ Object
Returns the value of attribute _query.
-
#_resource ⇒ Object
Returns the value of attribute _resource.
-
#identity_map ⇒ Object
Returns the value of attribute identity_map.
-
#new_record ⇒ Object
Returns the value of attribute new_record.
Class Method Summary collapse
-
._finalize! ⇒ Object
Internal finalize! logic.
-
.all(condition = {}) ⇒ Array<Model>
Looks up in the identity map first.
-
.array_to_many(name, &block) ⇒ Object
Define array_to_many (aka: belongs_to where the key attribute is an array).
-
.belongs_to(name = nil, belongs_to_options = {}) ⇒ Array
Implements Praxis::Mapper DSL directive ‘belongs_to’.
- .context(name, &block) ⇒ Object
- .define_array_to_many(name, association) ⇒ Object
- .define_association(name, association) ⇒ Object
- .define_associations ⇒ Object
-
.define_belongs_to(name, opts) ⇒ Object
The belongs_to association creates a one-to-one match with another model.
- .define_data_accessor(name) ⇒ Object
- .define_data_accessors(*names) ⇒ Object
- .define_many_to_array(name, association) ⇒ Object
- .define_many_to_one(name, association) ⇒ Object
-
.define_one_to_many(name, association) ⇒ Object
has_many.
- .define_serialized_accessor(name, serializer, **opts) ⇒ Object
-
.excluded_scopes(*scopes) ⇒ Array
Implements Praxis::Mapper DSL directive ‘excluded_scopes’.
-
.get(condition) ⇒ Model
Looks up in the identity map first.
-
.identities(*names) ⇒ Array
Implements Praxis::Mapper DSL directive ‘identities’.
-
.identity(name) ⇒ Object
Adds given identity to the list of model identities.
- .inherited(klass) ⇒ Object
-
.json(name, opts = {}) ⇒ Object
Implements Praxis::Mapper DSL directive ‘json’.
-
.many_to_array(name, &block) ⇒ Object
Define many_to_array (aka: has_many where the key attribute is an array).
-
.many_to_one(name, &block) ⇒ Object
Define many_to_one (aka: belongs_to).
-
.one_to_many(name, &block) ⇒ Object
Define one_to_many (aka: has_many).
-
.repository_name(name = nil) ⇒ Symbol
Gets or sets the repository for this model.
-
.table_name(name = nil) ⇒ Symbol
Implements Praxis::Mapper DSL directive ‘table_name’.
-
.yaml(name, opts = {}) ⇒ Object
Implements Praxis::Mapper DSL directive ‘yaml’.
Instance Method Summary collapse
- #_data ⇒ Object
- #identities ⇒ Object
-
#initialize(data = {}) ⇒ Model
constructor
A new instance of Model.
- #inspect ⇒ Object
- #method_missing(name, *args) ⇒ Object
- #original_method_missing ⇒ Object
- #respond_to_missing?(name) ⇒ Boolean
- #save! ⇒ Object
- #set_association(name, value) ⇒ Object
- #set_serialized_field(name, value) ⇒ Object
Methods included from Finalizable
_finalize!, extended, finalizable, finalize!, finalized?, inherited
Constructor Details
#initialize(data = {}) ⇒ Model
Returns a new instance of Model.
384 385 386 387 388 |
# File 'lib/praxis-mapper/model.rb', line 384 def initialize(data) @data = data @deserialized_data = {} @query = nil end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(name, *args) ⇒ Object
404 405 406 407 408 409 410 411 |
# File 'lib/praxis-mapper/model.rb', line 404 def method_missing(name, *args) if @data.has_key? name self.class.define_data_accessor(name) self.send(name) else super end end |
Class Attribute Details
._identities ⇒ Object
Returns the value of attribute _identities.
12 13 14 |
# File 'lib/praxis-mapper/model.rb', line 12 def _identities @_identities end |
.associations ⇒ Object (readonly)
Returns the value of attribute associations.
13 14 15 |
# File 'lib/praxis-mapper/model.rb', line 13 def associations @associations end |
.config ⇒ Object (readonly)
Returns the value of attribute config.
13 14 15 |
# File 'lib/praxis-mapper/model.rb', line 13 def config @config end |
.contexts ⇒ Object (readonly)
Returns the value of attribute contexts.
13 14 15 |
# File 'lib/praxis-mapper/model.rb', line 13 def contexts @contexts end |
.serialized_fields ⇒ Object (readonly)
Returns the value of attribute serialized_fields.
13 14 15 |
# File 'lib/praxis-mapper/model.rb', line 13 def serialized_fields @serialized_fields end |
Instance Attribute Details
#_query ⇒ Object
Returns the value of attribute _query.
9 10 11 |
# File 'lib/praxis-mapper/model.rb', line 9 def _query @_query end |
#_resource ⇒ Object
Returns the value of attribute _resource.
9 10 11 |
# File 'lib/praxis-mapper/model.rb', line 9 def _resource @_resource end |
#identity_map ⇒ Object
Returns the value of attribute identity_map.
9 10 11 |
# File 'lib/praxis-mapper/model.rb', line 9 def identity_map @identity_map end |
#new_record ⇒ Object
Returns the value of attribute new_record.
75 76 77 |
# File 'lib/praxis-mapper/support/factory_bot.rb', line 75 def new_record @new_record end |
Class Method Details
._finalize! ⇒ Object
Internal finalize! logic
31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/praxis-mapper/model.rb', line 31 def self._finalize! self.define_data_accessors *self.identities.flatten self.associations.each do |name,config| self.associations[name] = config.to_hash end self.define_associations super end |
.all(condition = {}) ⇒ Array<Model>
Looks up in the identity map first.
379 380 381 |
# File 'lib/praxis-mapper/model.rb', line 379 def self.all(condition={}) IdentityMap.current.all(self, condition) end |
.array_to_many(name, &block) ⇒ Object
Define array_to_many (aka: belongs_to where the key attribute is an array)
139 140 141 |
# File 'lib/praxis-mapper/model.rb', line 139 def self.array_to_many(name, &block) self.associations[name] = ConfigHash.from(type: :array_to_many, &block) end |
.belongs_to(name = nil, belongs_to_options = {}) ⇒ Array
Implements Praxis::Mapper DSL directive ‘belongs_to’. If name and belongs_to_options are given, upserts the association. If only name is given, gets the named association. Else, returns all configured associations.
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/praxis-mapper/model.rb', line 102 def self.belongs_to(name=nil, ={}) if !.empty? warn "DEPRECATION: `#{self}.belongs_to` is deprecated. Use `many_to_one` or `array_to_many` instead." opts = {:fk => :id}.merge() opts[:key] = opts.delete(:source_key) opts[:primary_key] = opts.delete(:fk) if opts.has_key?(:fk) if (opts.delete(:type) == :array) opts[:type] = :array_to_many else opts[:type] = :many_to_one end self.associations[name] = opts define_belongs_to(name, opts) else raise "Calling Model.belongs to fetch association information is no longer supported. Use Model.associations instead." end end |
.context(name, &block) ⇒ Object
215 216 217 218 219 220 |
# File 'lib/praxis-mapper/model.rb', line 215 def self.context(name, &block) default = Hash.new do |hash, key| hash[key] = Array.new end @contexts[name] = ConfigHash.from(default, &block).to_hash end |
.define_array_to_many(name, association) ⇒ Object
299 300 301 302 303 304 305 306 307 308 309 310 311 |
# File 'lib/praxis-mapper/model.rb', line 299 def self.define_array_to_many(name, association) model = association[:model] primary_key = association.fetch(:primary_key, :id) key = association.fetch(:key) module_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{name} return nil if #{key}.nil? @__#{name} ||= self.identity_map.all(#{model.name},#{primary_key.inspect} => #{key}) end RUBY end |
.define_association(name, association) ⇒ Object
246 247 248 249 250 251 252 253 254 255 256 257 |
# File 'lib/praxis-mapper/model.rb', line 246 def self.define_association(name, association) case association[:type] when :many_to_one self.define_many_to_one(name, association) when :array_to_many self.define_array_to_many(name, association) when :one_to_many self.define_one_to_many(name, association) when :many_to_array self.define_many_to_array(name, association) end end |
.define_associations ⇒ Object
240 241 242 243 244 |
# File 'lib/praxis-mapper/model.rb', line 240 def self.define_associations self.associations.each do |name, association| self.define_association(name,association) end end |
.define_belongs_to(name, opts) ⇒ Object
The belongs_to association creates a one-to-one match with another model. In database terms, this association says that this class contains the foreign key.
353 354 355 356 357 358 359 360 361 362 363 |
# File 'lib/praxis-mapper/model.rb', line 353 def self.define_belongs_to(name, opts) model = opts.fetch(:model) type = opts.fetch(:type, :many_to_one) # :scalar has no meaning other than it's not an array case opts.fetch(:type, :many_to_one) when :many_to_one return self.define_many_to_one(name, opts) when :array_to_many return self.define_array_to_many(name, opts) end end |
.define_data_accessor(name) ⇒ Object
230 231 232 233 234 235 236 237 238 |
# File 'lib/praxis-mapper/model.rb', line 230 def self.define_data_accessor(name) module_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{name} @__#{name} ||= @data.fetch(#{name.inspect}) do raise "field #{name.inspect} not loaded for #{self.inspect}." end.freeze end RUBY end |
.define_data_accessors(*names) ⇒ Object
223 224 225 226 227 |
# File 'lib/praxis-mapper/model.rb', line 223 def self.define_data_accessors(*names) names.each do |name| self.define_data_accessor(name) end end |
.define_many_to_array(name, association) ⇒ Object
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
# File 'lib/praxis-mapper/model.rb', line 314 def self.define_many_to_array(name, association) model = association[:model] primary_key = association.fetch(:primary_key, :id) key_name = association.fetch(:key) if primary_key.kind_of?(Array) key = "[" key += primary_key.collect { |k| "self.#{k}" }.join(", ") key += "]" else key = "self.#{primary_key}" end module_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{name} key = #{key} return nil if key.nil? @__#{name} ||= self.identity_map.all(#{model.name}). select { |record| record.#{key_name}.include? key } end RUBY end |
.define_many_to_one(name, association) ⇒ Object
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 |
# File 'lib/praxis-mapper/model.rb', line 277 def self.define_many_to_one(name, association) model = association[:model] primary_key = association.fetch(:primary_key, :id) if association[:key].kind_of?(Array) key = "[" key += association[:key].collect { |k| "self.#{k}" }.join(", ") key += "]" else key = "self.#{association[:key]}" end module_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{name} return nil if #{key}.nil? @__#{name} ||= self.identity_map.get(#{model.name},#{primary_key.inspect} => #{key}) end RUBY end |
.define_one_to_many(name, association) ⇒ Object
has_many
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 |
# File 'lib/praxis-mapper/model.rb', line 260 def self.define_one_to_many(name, association) model = association[:model] primary_key = association.fetch(:primary_key, :id) if primary_key.kind_of?(Array) define_method(name) do pk = primary_key.collect { |k| self.send(k) } self.identity_map.all(model,association[:key] => [pk]) end else define_method(name) do pk = self.send(primary_key) self.identity_map.all(model,association[:key] => [pk]) end end end |
.define_serialized_accessor(name, serializer, **opts) ⇒ Object
201 202 203 204 205 206 207 208 209 210 211 212 213 |
# File 'lib/praxis-mapper/model.rb', line 201 def self.define_serialized_accessor(name, serializer, **opts) define_method(name) do @deserialized_data[name] ||= if (value = @data.fetch(name)) serializer.load(value) else opts[:default] end end define_method("_raw_#{name}".to_sym) do @data.fetch name end end |
.excluded_scopes(*scopes) ⇒ Array
Implements Praxis::Mapper DSL directive ‘excluded_scopes’. Gets or sets the excluded scopes for this model. Exclusion means that the named condition cannot be applied.
50 51 52 53 54 55 56 |
# File 'lib/praxis-mapper/model.rb', line 50 def self.excluded_scopes(*scopes) if scopes.any? self.config[:excluded_scopes] = scopes else self.config.fetch(:excluded_scopes) end end |
.get(condition) ⇒ Model
Looks up in the identity map first.
370 371 372 |
# File 'lib/praxis-mapper/model.rb', line 370 def self.get(condition) IdentityMap.current.get(self, condition) end |
.identities(*names) ⇒ Array
Implements Praxis::Mapper DSL directive ‘identities’. Gets or sets list of identity fields.
164 165 166 167 168 169 170 171 |
# File 'lib/praxis-mapper/model.rb', line 164 def self.identities(*names) if names.any? self.config[:identities] = names @_identities = names else self.config.fetch(:identities) end end |
.identity(name) ⇒ Object
Adds given identity to the list of model identities. May be an array for composite keys.
151 152 153 154 155 |
# File 'lib/praxis-mapper/model.rb', line 151 def self.identity(name) @_identities ||= Array.new @_identities << name self.config[:identities] << name end |
.inherited(klass) ⇒ Object
16 17 18 19 20 21 22 23 24 25 26 27 28 |
# File 'lib/praxis-mapper/model.rb', line 16 def self.inherited(klass) super klass.instance_eval do @config = { excluded_scopes: [], identities: [] } @associations = {} @serialized_fields = {} @contexts = Hash.new end end |
.json(name, opts = {}) ⇒ Object
Implements Praxis::Mapper DSL directive ‘json’. This will perform JSON.load on serialized data.
196 197 198 199 |
# File 'lib/praxis-mapper/model.rb', line 196 def self.json(name, opts={}) @serialized_fields[name] = :json define_serialized_accessor(name, JSON, opts) end |
.many_to_array(name, &block) ⇒ Object
Define many_to_array (aka: has_many where the key attribute is an array)
144 145 146 |
# File 'lib/praxis-mapper/model.rb', line 144 def self.many_to_array(name, &block) self.associations[name] = ConfigHash.from(type: :many_to_array, &block) end |
.many_to_one(name, &block) ⇒ Object
Define many_to_one (aka: belongs_to)
134 135 136 |
# File 'lib/praxis-mapper/model.rb', line 134 def self.many_to_one(name, &block) self.associations[name] = ConfigHash.from(type: :many_to_one, &block) end |
.one_to_many(name, &block) ⇒ Object
Define one_to_many (aka: has_many)
128 129 130 |
# File 'lib/praxis-mapper/model.rb', line 128 def self.one_to_many(name, &block) self.associations[name] = ConfigHash.from(type: :one_to_many, &block) end |
.repository_name(name = nil) ⇒ Symbol
Gets or sets the repository for this model.
62 63 64 65 66 67 68 |
# File 'lib/praxis-mapper/model.rb', line 62 def self.repository_name(name=nil) if name self.config[:repository_name] = name else self.config.fetch(:repository_name, :default) end end |
.table_name(name = nil) ⇒ Symbol
Implements Praxis::Mapper DSL directive ‘table_name’. Gets or sets the SQL-like table name. Can also be thought of as a namespace in the repository.
77 78 79 80 81 82 83 |
# File 'lib/praxis-mapper/model.rb', line 77 def self.table_name(name=nil) if name self.config[:table_name] = name else self.config.fetch(:table_name, nil) end end |
.yaml(name, opts = {}) ⇒ Object
Implements Praxis::Mapper DSL directive ‘yaml’. This will perform YAML.load on serialized data.
182 183 184 185 |
# File 'lib/praxis-mapper/model.rb', line 182 def self.yaml(name, opts={}) @serialized_fields[name] = :yaml define_serialized_accessor(name, YAML, opts) end |
Instance Method Details
#_data ⇒ Object
425 426 427 |
# File 'lib/praxis-mapper/model.rb', line 425 def _data @data end |
#identities ⇒ Object
414 415 416 417 418 419 420 421 422 423 |
# File 'lib/praxis-mapper/model.rb', line 414 def identities self.class._identities.each_with_object(Hash.new) do |identity, hash| case identity when Symbol hash[identity] = @data[identity].freeze else hash[identity] = @data.values_at(*identity).collect(&:freeze) end end end |
#inspect ⇒ Object
391 392 393 394 395 396 397 |
# File 'lib/praxis-mapper/model.rb', line 391 def inspect "#<#{self.class}:0x#{object_id.to_s(16)} #{ instance_variables.select{|v| InspectedFields.include? v}.map {|var| "#{var}: #{instance_variable_get(var).inspect}" }.join("#{' '}") }#{' '}>" end |
#original_method_missing ⇒ Object
14 15 16 17 18 19 20 21 |
# File 'lib/praxis-mapper/support/factory_bot.rb', line 14 def method_missing(name, *args) if @data.has_key? name self.class.define_data_accessor(name) self.send(name) else super end end |
#respond_to_missing?(name) ⇒ Boolean
399 400 401 |
# File 'lib/praxis-mapper/model.rb', line 399 def respond_to_missing?(name, *) @data.key?(name) || super end |
#save! ⇒ Object
7 8 9 10 11 12 |
# File 'lib/praxis-mapper/support/factory_bot.rb', line 7 def save! @new_record = true unless Praxis::Mapper::IdentityMap.current.add_records([self]).include? self raise "Conflict trying to save record with type: #{self.class} and data:\n#{@data.pretty_inspect}" end end |
#set_association(name, value) ⇒ Object
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/praxis-mapper/support/factory_bot.rb', line 50 def set_association(name, value) spec = self.class.associations.fetch(name) case spec[:type] when :one_to_many raise "can not set one_to_many associations to nil" if value.nil? primary_key = @data[spec[:primary_key]] setter_name = "#{spec[:key]}=" Array(value).each { |item| item.send(setter_name, primary_key) } when :many_to_one primary_key = value && value.send(spec[:primary_key]) @data[spec[:key]] = primary_key else raise "can not handle associations of type #{spec[:type]}" end end |
#set_serialized_field(name, value) ⇒ Object
37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/praxis-mapper/support/factory_bot.rb', line 37 def set_serialized_field(name,value) @deserialized_data[name] = value case self.class.serialized_fields[name] when :json @data[name] = JSON.dump(value) when :yaml @data[name] = YAML.dump(value) else @data[name] = value # dunno end end |