Module: DataMapper::Model
- Extended by:
- Chainable
- Defined in:
- lib/dm-core/model.rb,
lib/dm-core/model/is.rb,
lib/dm-core/model/hook.rb,
lib/dm-core/model/scope.rb,
lib/dm-core/model/property.rb,
lib/dm-core/model/relationship.rb,
lib/dm-core/model/descendant_set.rb
Defined Under Namespace
Modules: Hook, Is, Property, Relationship, Scope Classes: DescendantSet
Instance Attribute Summary collapse
-
#base_model ⇒ Object
readonly
TODO: document.
-
#descendants ⇒ Set
readonly
private
Return all models that inherit from a Model.
Class Method Summary collapse
-
.append_extensions(*extensions) ⇒ Boolean
Extends the model with this module after Resource has been included.
-
.append_inclusions(*inclusions) ⇒ Boolean
Appends a module for inclusion into the model class after Resource.
-
.descendants ⇒ DescendantSet
private
Return all models that extend the Model module.
-
.extended(model) ⇒ Object
private
TODO: document.
-
.extra_extensions ⇒ Set
private
The current registered extra extensions.
-
.extra_inclusions ⇒ Set
private
The current registered extra inclusions.
-
.new(storage_name = nil, &block) ⇒ Model
Creates a new Model class with default_storage_name
storage_name
.
Instance Method Summary collapse
- #[](*args) ⇒ Object (also: #slice)
-
#all(query = nil) ⇒ Collection
Find a set of records matching an optional set of conditions.
- #at(*args) ⇒ Object
-
#copy(source, destination, query = {}) ⇒ Collection
Copy a set of records from one repository to another.
-
#create(attributes = {}) ⇒ Resource
Create a Resource.
-
#create!(attributes = {}) ⇒ Resource
Create a Resource, bypassing hooks.
-
#default_order(repository_name = default_repository_name) ⇒ Object
TODO: document.
-
#default_repository_name ⇒ Object
TODO: document.
-
#entries ⇒ Object
(also: #to_a)
TODO: spec this.
-
#first(*args) ⇒ Resource, Collection
Return the first Resource or the first N Resources for the Model with an optional query.
-
#first_or_create(conditions = {}, attributes = {}) ⇒ Resource
Finds the first Resource by conditions, or creates a new Resource with the attributes if none found.
-
#first_or_new(conditions = {}, attributes = {}) ⇒ Resource
Finds the first Resource by conditions, or initializes a new Resource with the attributes if none found.
-
#get(*key) ⇒ Resource, NilClass
Grab a single record by its key.
-
#get!(*key) ⇒ Resource
Grab a single record just like #get, but raise an ObjectNotFoundError if the record doesn’t exist.
-
#last(*args) ⇒ Resource, Collection
Return the last Resource or the last N Resources for the Model with an optional query.
-
#load(records, query) ⇒ Resource
Loads an instance of this Model, taking into account IdentityMap lookup, inheritance columns(s) and Property typecasting.
-
#model_method_defined?(method) ⇒ Boolean
private
TODO: document.
-
#repositories ⇒ Set
private
Gets the current Set of repositories for which this Model has been defined (beyond default).
-
#repository(name = nil) ⇒ Object, Respository
private
Get the repository with a given name, or the default one for the current context, or the default one for this class.
-
#repository_name ⇒ String
private
Get the current
repository_name
for this Model. -
#resource_method_defined?(method) ⇒ Boolean
private
TODO: document.
- #reverse ⇒ Object
-
#storage_name(repository_name = default_repository_name) ⇒ String
Gets the name of the storage receptacle for this resource in the given Repository (ie., table name, for database stores).
-
#storage_names ⇒ Hash(Symbol => String)
the names of the storage receptacles for this resource across all repositories.
Methods included from Chainable
Methods included from Scope
#current_scope, #default_scope, #query
Methods included from Is
Instance Attribute Details
#base_model ⇒ Object (readonly)
TODO: document
533 534 535 |
# File 'lib/dm-core/model.rb', line 533 def base_model @base_model end |
#descendants ⇒ Set (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Return all models that inherit from a Model
class Foo
include DataMapper::Resource
end
class Bar < Foo
end
Foo.descendants.first #=> Bar
73 74 75 |
# File 'lib/dm-core/model.rb', line 73 def descendants @descendants end |
Class Method Details
.append_extensions(*extensions) ⇒ Boolean
Extends the model with this module after Resource has been included.
This is a useful way to extend Model while still retaining a self.extended method.
112 113 114 115 |
# File 'lib/dm-core/model.rb', line 112 def self.append_extensions(*extensions) extra_extensions.concat extensions true end |
.append_inclusions(*inclusions) ⇒ Boolean
Appends a module for inclusion into the model class after Resource.
This is a useful way to extend Resource while still retaining a self.included method.
87 88 89 90 |
# File 'lib/dm-core/model.rb', line 87 def self.append_inclusions(*inclusions) extra_inclusions.concat inclusions true end |
.descendants ⇒ DescendantSet
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Return all models that extend the Model module
class Foo
include DataMapper::Resource
end
DataMapper::Model.descendants.first #=> Foo
54 55 56 |
# File 'lib/dm-core/model.rb', line 54 def self.descendants @descendants ||= DescendantSet.new end |
.extended(model) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
TODO: document
128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/dm-core/model.rb', line 128 def self.extended(model) descendants << model model.instance_variable_set(:@valid, false) model.instance_variable_set(:@base_model, model) model.instance_variable_set(:@storage_names, {}) model.instance_variable_set(:@default_order, {}) model.instance_variable_set(:@descendants, descendants.class.new(model, descendants)) extra_extensions.each { |mod| model.extend(mod) } extra_inclusions.each { |mod| model.send(:include, mod) } end |
.extra_extensions ⇒ Set
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
The current registered extra extensions
122 123 124 |
# File 'lib/dm-core/model.rb', line 122 def self.extra_extensions @extra_extensions ||= [] end |
.extra_inclusions ⇒ Set
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
The current registered extra inclusions
97 98 99 |
# File 'lib/dm-core/model.rb', line 97 def self.extra_inclusions @extra_inclusions ||= [] end |
.new(storage_name = nil, &block) ⇒ Model
Creates a new Model class with default_storage_name storage_name
If a block is passed, it will be eval’d in the context of the new Model
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/dm-core/model.rb', line 18 def self.new(storage_name = nil, &block) model = Class.new model.class_eval <<-RUBY, __FILE__, __LINE__ + 1 include DataMapper::Resource def self.name to_s end RUBY if storage_name warn "Passing in +storage_name+ to #{name}.new is deprecated (#{caller[0]})" model.class_eval <<-RUBY, __FILE__, __LINE__ + 1 def self.default_storage_name #{Extlib::Inflection.classify(storage_name).inspect}.freeze end RUBY end model.instance_eval(&block) if block model end |
Instance Method Details
#[](*args) ⇒ Object Also known as: slice
222 223 224 |
# File 'lib/dm-core/model.rb', line 222 def [](*args) all[*args] end |
#all(query = nil) ⇒ Collection
Find a set of records matching an optional set of conditions. Additionally, specify the order that the records are return.
Zoo.all # all zoos
Zoo.all(:open => true) # all zoos that are open
Zoo.all(:opened_on => start..end) # all zoos that opened on a date in the date-range
Zoo.all(:order => [ :tiger_count.desc ]) # Ordered by tiger_count
258 259 260 261 262 263 264 265 |
# File 'lib/dm-core/model.rb', line 258 def all(query = nil) if query.nil? || (query.kind_of?(Hash) && query.empty?) # TODO: after adding Enumerable methods to Model, try to return self here new_collection(self.query.dup) else new_collection(scoped_query(query)) end end |
#at(*args) ⇒ Object
228 229 230 |
# File 'lib/dm-core/model.rb', line 228 def at(*args) all.at(*args) end |
#copy(source, destination, query = {}) ⇒ Collection
Copy a set of records from one repository to another.
433 434 435 436 437 438 439 440 441 442 443 444 |
# File 'lib/dm-core/model.rb', line 433 def copy(source, destination, query = {}) # get the list of properties that exist in the source and destination destination_properties = properties(destination) fields = query[:fields] ||= properties(source).select { |property| destination_properties.include?(property) } repository(destination) do all(query.merge(:repository => source)).map do |resource| create(fields.map { |property| [ property.name, property.get(resource) ] }.to_hash) end end end |
#create(attributes = {}) ⇒ Resource
Create a Resource
402 403 404 |
# File 'lib/dm-core/model.rb', line 402 def create(attributes = {}) _create(true, attributes) end |
#create!(attributes = {}) ⇒ Resource
Create a Resource, bypassing hooks
415 416 417 |
# File 'lib/dm-core/model.rb', line 415 def create!(attributes = {}) _create(false, attributes) end |
#default_order(repository_name = default_repository_name) ⇒ Object
TODO: document
543 544 545 |
# File 'lib/dm-core/model.rb', line 543 def default_order(repository_name = default_repository_name) @default_order[repository_name] ||= key(repository_name).map { |property| Query::Direction.new(property) }.freeze end |
#default_repository_name ⇒ Object
TODO: document
537 538 539 |
# File 'lib/dm-core/model.rb', line 537 def default_repository_name Repository.default_name end |
#entries ⇒ Object Also known as: to_a
TODO: spec this
237 238 239 |
# File 'lib/dm-core/model.rb', line 237 def entries all.entries end |
#first(*args) ⇒ Resource, Collection
Return the first Resource or the first N Resources for the Model with an optional query
When there are no arguments, return the first Resource in the Model. When the first argument is an Integer, return a Collection containing the first N Resources. When the last (optional) argument is a Hash scope the results to the query.
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 |
# File 'lib/dm-core/model.rb', line 284 def first(*args) last_arg = args.last limit = args.first if args.first.kind_of?(Integer) with_query = last_arg.respond_to?(:merge) && !last_arg.blank? query = with_query ? last_arg : {} query = if query.kind_of?(Query) query.slice(0, limit || 1) else offset = query.fetch(:offset, 0) query = query.except(:offset) scoped_query(query).slice(offset, limit || 1) end if limit all(query) else query.repository.read(query).first end end |
#first_or_create(conditions = {}, attributes = {}) ⇒ Resource
Finds the first Resource by conditions, or creates a new Resource with the attributes if none found
373 374 375 |
# File 'lib/dm-core/model.rb', line 373 def first_or_create(conditions = {}, attributes = {}) first(conditions) || create(conditions.merge(attributes)) end |
#first_or_new(conditions = {}, attributes = {}) ⇒ Resource
Finds the first Resource by conditions, or initializes a new Resource with the attributes if none found
358 359 360 |
# File 'lib/dm-core/model.rb', line 358 def first_or_new(conditions = {}, attributes = {}) first(conditions) || new(conditions.merge(attributes)) end |
#get(*key) ⇒ Resource, NilClass
Grab a single record by its key. Supports natural and composite key lookups as well.
Zoo.get(1) # get the zoo with primary key of 1.
Zoo.get!(1) # Or get! if you want an ObjectNotFoundError on failure
Zoo.get('DFW') # wow, support for natural primary keys
Zoo.get('Metro', 'DFW') # more wow, composite key look-up
200 201 202 203 204 205 |
# File 'lib/dm-core/model.rb', line 200 def get(*key) repository = self.repository key = self.key(repository.name).typecast(key) repository.identity_map(self)[key] || first(key_conditions(repository, key)) end |
#get!(*key) ⇒ Resource
Grab a single record just like #get, but raise an ObjectNotFoundError if the record doesn’t exist.
218 219 220 |
# File 'lib/dm-core/model.rb', line 218 def get!(*key) get(*key) || raise(ObjectNotFoundError, "Could not find #{self.name} with key #{key.inspect}") end |
#last(*args) ⇒ Resource, Collection
Return the last Resource or the last N Resources for the Model with an optional query
When there are no arguments, return the last Resource for the Model. When the first argument is an Integer, return a Collection containing the last N Resources. When the last (optional) argument is a Hash scope the results to the query.
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 |
# File 'lib/dm-core/model.rb', line 324 def last(*args) last_arg = args.last limit = args.first if args.first.kind_of?(Integer) with_query = last_arg.respond_to?(:merge) && !last_arg.blank? query = with_query ? last_arg : {} query = if query.kind_of?(Query) query.slice(0, limit || 1).reverse! else offset = query.fetch(:offset, 0) query = query.except(:offset) scoped_query(query).slice(offset, limit || 1).reverse! end if limit all(query) else query.repository.read(query).last end end |
#load(records, query) ⇒ Resource
Loads an instance of this Model, taking into account IdentityMap lookup, inheritance columns(s) and Property typecasting.
456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 |
# File 'lib/dm-core/model.rb', line 456 def load(records, query) repository = query.repository repository_name = repository.name fields = query.fields discriminator = properties(repository_name).discriminator no_reload = !query.reload? field_map = fields.map { |property| [ property, property.field ] }.to_hash records.map do |record| identity_map = nil key_values = nil resource = nil case record when Hash # remap fields to use the Property object record = record.dup field_map.each { |property, field| record[property] = record.delete(field) if record.key?(field) } model = discriminator && record[discriminator] || self resource = if (key_values = record.values_at(*model.key(repository_name))).all? identity_map = repository.identity_map(model) identity_map[key_values] end resource ||= model.allocate fields.each do |property| next if no_reload && property.loaded?(resource) value = record[property] # TODO: typecasting should happen inside the Adapter # and all values should come back as expected objects if property.custom? value = property.type.load(value, property) end property.set!(resource, value) end when Resource model = record.model resource = if (key_values = record.key).all? identity_map = repository.identity_map(model) identity_map[key_values] end resource ||= model.allocate fields.each do |property| next if no_reload && property.loaded?(resource) property.set!(resource, property.get!(record)) end end resource.instance_variable_set(:@repository, repository) resource.instance_variable_set(:@saved, true) if identity_map # defer setting the IdentityMap so second level caches can # record the state of the resource after loaded identity_map[key_values] = resource else resource.freeze end resource end end |
#model_method_defined?(method) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
TODO: document
600 601 602 |
# File 'lib/dm-core/model.rb', line 600 def model_method_defined?(method) model_methods.include?(method.to_s) end |
#repositories ⇒ Set
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Gets the current Set of repositories for which this Model has been defined (beyond default)
594 595 596 |
# File 'lib/dm-core/model.rb', line 594 def repositories [ repository ].to_set + @properties.keys.map { |repository_name| DataMapper.repository(repository_name) } end |
#repository(name = nil) ⇒ Object, Respository
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Get the repository with a given name, or the default one for the current context, or the default one for this class.
560 561 562 563 564 565 566 567 568 569 570 571 |
# File 'lib/dm-core/model.rb', line 560 def repository(name = nil) # # There has been a couple of different strategies here, but me (zond) and dkubb are at least # united in the concept of explicitness over implicitness. That is - the explicit wish of the # caller (+name+) should be given more priority than the implicit wish of the caller (Repository.context.last). # if block_given? DataMapper.repository(name || repository_name) { |*block_args| yield(*block_args) } else DataMapper.repository(name || repository_name) end end |
#repository_name ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Get the current repository_name
for this Model.
If there are any Repository contexts, the name of the last one will be returned, else the default_repository_name
of this model will be
582 583 584 |
# File 'lib/dm-core/model.rb', line 582 def repository_name Repository.context.any? ? Repository.context.last.name : default_repository_name end |
#resource_method_defined?(method) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
TODO: document
606 607 608 |
# File 'lib/dm-core/model.rb', line 606 def resource_method_defined?(method) resource_methods.include?(method.to_s) end |
#reverse ⇒ Object
232 233 234 |
# File 'lib/dm-core/model.rb', line 232 def reverse all.reverse end |
#storage_name(repository_name = default_repository_name) ⇒ String
Gets the name of the storage receptacle for this resource in the given Repository (ie., table name, for database stores).
170 171 172 |
# File 'lib/dm-core/model.rb', line 170 def storage_name(repository_name = default_repository_name) storage_names[repository_name] ||= repository(repository_name).adapter.resource_naming_convention.call(default_storage_name).freeze end |
#storage_names ⇒ Hash(Symbol => String)
the names of the storage receptacles for this resource across all repositories
180 181 182 |
# File 'lib/dm-core/model.rb', line 180 def storage_names @storage_names end |