<commit_before>module DataMapper
  module Associations
    include Extlib::Assertions
    extend Chainable

    class UnsavedParentError < RuntimeError; end

    # Initializes relationships hash for extended model
    # class.
    #
    # When model calls has n, has 1 or belongs_to, relationships
    # are stored in that hash: keys are repository names and
    # values are relationship sets.
    #
    # @api private
    def self.extended(model)
      model.instance_variable_set(:@relationships, {})
    end

    chainable do
      # When DataMapper model is inherited, relationships
      # of parent are duplicated and copied to subclass model
      #
      # @api private
      def inherited(target)
        # TODO: Create a RelationshipSet class, and then add a method that allows copying the relationships to the supplied repository and model
        duped_relationships = {}
        @relationships.each do |repository_name, relationships|
          duped_relationship = duped_relationships[repository_name] ||= Mash.new

          relationships.each do |name, relationship|
            dup = relationship.dup

            [ :@child_model, :@parent_mode ].each do |ivar|
              if dup.instance_variable_defined?(ivar) && dup.instance_variable_get(ivar) == self
                dup.instance_variable_set(ivar, target)
              end
            end

            duped_relationship[name] = dup
          end
        end

        target.instance_variable_set(:@relationships, duped_relationships)

        super
      end
    end

    ##
    # Returns all relationships that are many-to-one for this model.
    #
    # Used to find the relationships that require properties in any Repository.
    #
    #  class Plur
    #    include DataMapper::Resource
    #
    #    def self.default_repository_name
    #      :plur_db
    #    end
    #
    #    repository(:plupp_db) do
    #      has 1, :plupp
    #    end
    #  end
    #
    # This resource has a many-to-one to the Plupp resource residing in the :plupp_db repository,
    # but the Plur resource needs the plupp_id property no matter what repository itself lives in,
    # ie we need to create that property when we migrate etc.
    #
    # Used in Model.properties_with_subclasses
    #
    # @api private
    def many_to_one_relationships
      @relationships.values.collect { |r| r.values }.flatten.select { |r| r.child_model == self }
    end

    # Returns copy of relationships set in given repository.
    #
    # @param [Symbol] repository_name
    #   Name of the repository for which relationships set is returned
    # @return [Mash]  relationships set for given repository
    #
    # @api semipublic
    def relationships(repository_name = default_repository_name)
      assert_kind_of 'repository_name', repository_name, Symbol

      # TODO: create RelationshipSet#copy that will copy the relationships, but assign the
      # new Relationship objects to a supplied repository and model.  dup does not really
      # do what is needed

      @relationships[repository_name] ||= if repository_name == default_repository_name
        Mash.new
      else
        relationships(default_repository_name).dup
      end
    end

    # Used to express unlimited cardinality of association,
    # see +has+
    def n
      1.0/0
    end

    ##
    # A shorthand, clear syntax for defining one-to-one, one-to-many and
    # many-to-many resource relationships.
    #
    #  * has 1,    :friend    # one friend
    #  * has n,    :friends   # many friends
    #  * has 1..3, :friends   # many friends (at least 1, at most 3)
    #  * has 3,    :friends   # many friends (exactly 3)
    #  * has 1,    :friend,  :model   => 'User'       # one friend with the class User
    #  * has 3,    :friends, :through => :friendships # many friends through the friendships relationship
    #
    # @param cardinality [Integer, Range, Infinity]
    #   cardinality that defines the association type and constraints
    # @param name <Symbol>  the name that the association will be referenced by
    # @param opts <Hash>    an options hash
    #
    # @option :through[Symbol]  A association that this join should go through to form
    #       a many-to-many association
    # @option :model[Model,String] The name of the class to associate with, if omitted
    #       then the association name is assumed to match the class name
    #
    # @return [Association::Relationship] the relationship that was
    #   created to reflect either a one-to-one, one-to-many or many-to-many
    #   relationship
    # @raise [ArgumentError] if the cardinality was not understood. Should be a
    #   Integer, Range or Infinity(n)
    #
    # @api public
    def has(cardinality, name, options = {})
      assert_kind_of 'cardinality', cardinality, Integer, Range, n.class
      assert_kind_of 'name',        name,        Symbol
      assert_kind_of 'options',     options,     Hash

      min, max = extract_min_max(cardinality)
      options = options.merge(:min => min, :max => max)

      assert_valid_options(options)

      parent_repository_name = repository.name

      options[:child_repository_name]  = options.delete(:repository)
      options[:parent_repository_name] = parent_repository_name

      klass = if options.key?(:through)<commit_msg>Document :repository option of DataMapper::Associations#has<commit_after>module DataMapper
  module Associations
    include Extlib::Assertions
    extend Chainable

    class UnsavedParentError < RuntimeError; end

    # Initializes relationships hash for extended model
    # class.
    #
    # When model calls has n, has 1 or belongs_to, relationships
    # are stored in that hash: keys are repository names and
    # values are relationship sets.
    #
    # @api private
    def self.extended(model)
      model.instance_variable_set(:@relationships, {})
    end

    chainable do
      # When DataMapper model is inherited, relationships
      # of parent are duplicated and copied to subclass model
      #
      # @api private
      def inherited(target)
        # TODO: Create a RelationshipSet class, and then add a method that allows copying the relationships to the supplied repository and model
        duped_relationships = {}
        @relationships.each do |repository_name, relationships|
          duped_relationship = duped_relationships[repository_name] ||= Mash.new

          relationships.each do |name, relationship|
            dup = relationship.dup

            [ :@child_model, :@parent_mode ].each do |ivar|
              if dup.instance_variable_defined?(ivar) && dup.instance_variable_get(ivar) == self
                dup.instance_variable_set(ivar, target)
              end
            end

            duped_relationship[name] = dup
          end
        end

        target.instance_variable_set(:@relationships, duped_relationships)

        super
      end
    end

    ##
    # Returns all relationships that are many-to-one for this model.
    #
    # Used to find the relationships that require properties in any Repository.
    #
    #  class Plur
    #    include DataMapper::Resource
    #
    #    def self.default_repository_name
    #      :plur_db
    #    end
    #
    #    repository(:plupp_db) do
    #      has 1, :plupp
    #    end
    #  end
    #
    # This resource has a many-to-one to the Plupp resource residing in the :plupp_db repository,
    # but the Plur resource needs the plupp_id property no matter what repository itself lives in,
    # ie we need to create that property when we migrate etc.
    #
    # Used in Model.properties_with_subclasses
    #
    # @api private
    def many_to_one_relationships
      @relationships.values.collect { |r| r.values }.flatten.select { |r| r.child_model == self }
    end

    # Returns copy of relationships set in given repository.
    #
    # @param [Symbol] repository_name
    #   Name of the repository for which relationships set is returned
    # @return [Mash]  relationships set for given repository
    #
    # @api semipublic
    def relationships(repository_name = default_repository_name)
      assert_kind_of 'repository_name', repository_name, Symbol

      # TODO: create RelationshipSet#copy that will copy the relationships, but assign the
      # new Relationship objects to a supplied repository and model.  dup does not really
      # do what is needed

      @relationships[repository_name] ||= if repository_name == default_repository_name
        Mash.new
      else
        relationships(default_repository_name).dup
      end
    end

    # Used to express unlimited cardinality of association,
    # see +has+
    def n
      1.0/0
    end

    ##
    # A shorthand, clear syntax for defining one-to-one, one-to-many and
    # many-to-many resource relationships.
    #
    #  * has 1,    :friend    # one friend
    #  * has n,    :friends   # many friends
    #  * has 1..3, :friends   # many friends (at least 1, at most 3)
    #  * has 3,    :friends   # many friends (exactly 3)
    #  * has 1,    :friend,  :model   => 'User'       # one friend with the class User
    #  * has 3,    :friends, :through => :friendships # many friends through the friendships relationship
    #
    # @param cardinality [Integer, Range, Infinity]
    #   cardinality that defines the association type and constraints
    # @param name <Symbol>  the name that the association will be referenced by
    # @param opts <Hash>    an options hash
    #
    # @option :through[Symbol]  A association that this join should go through to form
    #       a many-to-many association
    # @option :model[Model,String] The name of the class to associate with, if omitted
    #       then the association name is assumed to match the class name
    # @option :repository[Symbol]
    #       name of child model repository
    #
    # @return [Association::Relationship] the relationship that was
    #   created to reflect either a one-to-one, one-to-many or many-to-many
    #   relationship
    # @raise [ArgumentError] if the cardinality was not understood. Should be a
    #   Integer, Range or Infinity(n)
    #
    # @api public
    def has(cardinality, name, options = {})
      assert_kind_of 'cardinality', cardinality, Integer, Range, n.class
      assert_kind_of 'name',        name,        Symbol
      assert_kind_of 'options',     options,     Hash

      min, max = extract_min_max(cardinality)
      options = options.merge(:min => min, :max => max)

      assert_valid_options(options)

      parent_repository_name = repository.name

      options[:child_repository_name]  = options.delete(:repository)
      options[:parent_repository_name] = parent_repository_name

      klass = if options.key?(:through)
{'fraction_non_alphanumeric': 0.07364016736401674, 'fraction_numerical': 0.002603440260344026, 'mean_word_length': 2.5710491367861885, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2983445', 'n_tokens_mistral': 3029, 'n_tokens_neox': 2905, 'n_words': 1018}