# encoding: utf-8 module Mongoid class Criteria module Modifiable # Build a document given the selector and return it. # Complex criteria, such as $in and $or operations will get ignored. # # @example build the document. # Person.where(:title => "Sir").build # # @example Build with selectors getting ignored. # Person.where(:age.gt => 5).build # # @return [ Document ] A non-persisted document. # # @since 2.0.0 def build(attrs = {}, &block) create_document(:new, attrs, &block) end alias :new :build # Create a document in the database given the selector and return it. # Complex criteria, such as $in and $or operations will get ignored. # # @example Create the document. # Person.where(:title => "Sir").create # # @example Create with selectors getting ignored. # Person.where(:age.gt => 5).create # # @return [ Document ] A newly created document. # # @since 2.0.0.rc.1 def create(attrs = {}, &block) create_document(:create, attrs, &block) end # Create a document in the database given the selector and return it. # Complex criteria, such as $in and $or operations will get ignored. # If validation fails, an error will be raised. # # @example Create the document. # Person.where(:title => "Sir").create # # @example Create with selectors getting ignored. # Person.where(:age.gt => 5).create # # @raise [ Errors::Validations ] on a validation error. # # @return [ Document ] A newly created document. # # @since 3.0.0 def create!(attrs = {}, &block) create_document(:create!, attrs, &block) end # Find the first +Document+ given the conditions, or creates a new document # with the conditions that were supplied. # # @example Find or create the document. # Person.find_or_create_by(:attribute => "value") # # @param [ Hash ] attrs The attributes to check. # # @return [ Document ] A matching or newly created document. def find_or_create_by(attrs = {}, &block) find_or(:create, attrs, &block) end # Find the first +Document+ given the conditions, or creates a new document # with the conditions that were supplied. If validation fails an # exception will be raised. # # @example Find or create the document. # Person.find_or_create_by!(:attribute => "value") # # @param [ Hash ] attrs The attributes to check. # # @raise [ Errors::Validations ] on validation error. # # @return [ Document ] A matching or newly created document. def find_or_create_by!(attrs = {}, &block) find_or(:create!, attrs, &block) end # Find the first +Document+ given the conditions, or initializes a new document # with the conditions that were supplied. # # @example Find or initialize the document. # Person.find_or_initialize_by(:attribute => "value") # # @param [ Hash ] attrs The attributes to check. # # @return [ Document ] A matching or newly initialized document. def find_or_initialize_by(attrs = {}, &block) find_or(:new, attrs, &block) end # Find the first +Document+, or creates a new document # with the conditions that were supplied plus attributes. # # @example First or create the document. # Person.where(name: "Jon").first_or_create(attribute: "value") # # @param [ Hash ] attrs The additional attributes to add. # # @return [ Document ] A matching or newly created document. # # @since 3.1.0 def first_or_create(attrs = nil, &block) first_or(:create, attrs, &block) end # Find the first +Document+, or creates a new document # with the conditions that were supplied plus attributes and will # raise an error if validation fails. # # @example First or create the document. # Person.where(name: "Jon").first_or_create!(attribute: "value") # # @param [ Hash ] attrs The additional attributes to add. # # @return [ Document ] A matching or newly created document. # # @since 3.1.0 def first_or_create!(attrs = nil, &block) first_or(:create!, attrs, &block) end # Find the first +Document+, or initializes a new document # with the conditions that were supplied plus attributes. # # @example First or initialize the document. # Person.where(name: "Jon").first_or_initialize(attribute: "value") # # @param [ Hash ] attrs The additional attributes to add. # # @return [ Document ] A matching or newly initialized document. # # @since 3.1.0 def first_or_initialize(attrs = nil, &block) first_or(:new, attrs, &block) end private # Create a document given the provided method and attributes from the # existing selector. # # @api private # # @example Create a new document. # criteria.create_document(:new, {}) # # @param [ Symbol ] method Either :new or :create. # @param [ Hash ] attrs Additional attributes to use. # # @return [ Document ] The new or saved document. # # @since 3.0.0 def create_document(method, attrs = nil, &block) attributes = selector.reduce(attrs || {}) do |hash, (key, value)| unless key.to_s =~ /\$/ || value.is_a?(Hash) hash[key] = value end hash end if embedded? attributes[:_parent] = parent_document attributes[:__metadata] = metadata end klass.__send__(method, attributes, &block) end # Find the first object or create/initialize it. # # @api private # # @example Find or perform an action. # Person.find_or(:create, :name => "Dev") # # @param [ Symbol ] method The method to invoke. # @param [ Hash ] attrs The attributes to query or set. # # @return [ Document ] The first or new document. def find_or(method, attrs = {}, &block) where(attrs).first || send(method, attrs, &block) end # Find the first document or create/initialize it. # # @api private # # @example First or perform an action. # Person.first_or(:create, :name => "Dev") # # @param [ Symbol ] method The method to invoke. # @param [ Hash ] attrs The attributes to query or set. # # @return [ Document ] The first or new document. # # @since 3.1.0 def first_or(method, attrs = {}, &block) first || create_document(method, attrs, &block) end end end end