<commit_before>require "dm-core"
require 'slf4r/logger'
# require 'adapters/noop_transaction'

module Ldap

  # the class provides two ways of getting a LdapFacade. either
  # one which is put on the current Thread or a new one
  class LdapConnection

    include ::Slf4r::Logger

    def initialize(options)
      if options[:facade].nil?
        require 'ldap/net_ldap_facade'
        @facade = ::Ldap::NetLdapFacade
      else
        case options[:facade].to_sym
        when :ruby_ldap
          require 'ldap/ruby_ldap_facade'
          @facade = ::Ldap::RubyLdapFacade
        when :net_ldap
          require 'ldap/net_ldap_facade'
          @facade = ::Ldap::NetLdapFacade
        else
          "please add a :facade parameter to the adapter setup. possible values are :ruby_ldap or net_ldap"
        end
      end
      logger.info("using #{@facade}")
      @ldaps = { }
      auth =  {
        :method => :simple,
        :username => options[:bind_name],
        :password => options[:password]
      }
      @config = {
        :host => options[:host],
        :port => options[:port].to_i,
        :auth => auth,
        :base => options[:base]
      }
    end

    # puts a LdapFacade into the current thread and executes the
    # given block.
    def open
      begin
        @facade.open(@config) do |ldap|
          @ldaps[Thread.current] = @facade.new(ldap)
          yield
        end
      ensure
        @ldaps[Thread.current] = nil
      end
    end

    # @return [Ldap::LdapFacade]
    #  either the one from the current Thread or a new one
    def current
      ldap = @ldaps[Thread.current]
      if ldap
        ldap
      else
        @facade.new(@config)
      end
    end
  end
end

require "dm-core"
module DataMapper
  class Query

    class SortCaseInsensitive < Sort
      def initialize(value, ascending = true)
        if(value && value.is_a?(String))
          super(value.upcase, ascending)
        else
          super
        end
      end
    end

    def sort_records_case_insensitive(records)
      #Return unsorted records unless we have order defined
      return records unless order
      sort_order = order.map { |direction| [ direction.target, direction.operator == :asc ] }
      
      records.sort_by do |record|
        sort_order.map do |(property, ascending)|
          SortCaseInsensitive.new(record_value(record, property), ascending)
        end
      end
    end
  end
  module Adapters
    class LdapAdapter < AbstractAdapter

      # @return [Ldap::LdapFacade]
      #   ready to use LdapFacade
      def ldap
        @ldap_connection.current
      end

      def open_ldap_connection(&block)
        @ldap_connection.open(&block)
      end

      def key_properties(resource)
        resource.model.key.first
      end

      COMPARATORS = { "=" => :eql, ">=" => :gte, "<=" => :lte, "like" => :like }

      # helper to remove datamapper specific classes from the conditions
      # @param [Array] conditions
      #   array of tuples: (action, property, new value)
      # @return [Array]
      #   tuples: (action, attribute name, new value)
      def to_ldap_conditions(query)
        conditions = query.conditions
        ldap_conditions = []
        conditions.operands.each do |c|
          if c.is_a? Array
            props = {}
            query.fields.each{ |f| props[f.name] = f.field}
            or_conditions = []
            c[0].split('or').each do |e|
              e.strip!
              match = e.match("=|<=|>=|like")
              or_conditions << [COMPARATORS[match.values_at(0)[0]],
                                props[match.pre_match.strip.to_sym],
                                match.post_match.strip.gsub(/'/, '')]
            end
            ldap_conditions << [:or_operator, or_conditions, nil]
          else
            comparator = c.slug
            case comparator
            when :raw
            when :not
                # TODO proper recursion !!!
                ldap_conditions << [comparator, c.operands.first.subject.field, c.operands.first.send(:dumped_value)]
            when :in
              ldap_conditions << [:eql, c.subject.field, c.send(:dumped_value)]
            else
              if c.subject.is_a? Ldap::LdapArray
                # assume a single value here !!!
                val = c.send(:dumped_value)
                ldap_conditions << [comparator, c.subject.field, val[1, val.size - 2]]
              else
                ldap_conditions << [comparator, c.subject.field, c.send(:dumped_value)]
              end
            end
          end
        end
        ldap_conditions
      end

      include ::Slf4r::Logger

      # @see AbstractAdapter
#      def transaction_primitive
 #       NoopTransaction.new
  #    end

      public

      def initialize(name, options)
        super(name, options)
        @ldap_connection = ::Ldap::LdapConnection.new(@options)
      end


      def create(resources)
        resources.select do |resource|

          create_resource(resource)

        end.size # just return the number of create resources
      end

      def update(attributes, collection)
        collection.each do |resource|
#puts "update"
#p resource
          update_resource(resource, attributes)

        end.size
      end
      # @param [DataMapper::Resource] resource
      #   to be created
      # @see SimpleAdapter#create_resource
      # @return [Fixnum]
      #    value for the primary key or nil
      def create_resource(resource)
        logger.debug { resource.inspect }

        props = resource.model.ldap_properties(resource)
        key = nil
        resource.send(:properties).each do |prop|
          value = prop.get!(resource)
          if prop.class == ::Ldap::LdapArray
            props[prop.field.to_sym] = value unless value.nil? or value.size == 0
          else
            props[prop.field.to_sym] = value.to_s unless value.nil?
          end
          key = prop if prop.serial?
        end
        resource_dup = resource.dup
        id = ldap.retrieve_next_id(resource.model.treebase,
                                   key_properties(resource).field)
        resource_dup.send("#{key_properties(resource).name}=".to_sym, id)
        props[key_properties(resource).field.to_sym] = "#{id}"
        key_value = begin
                      ldap.create_object(resource.model.dn_prefix(resource_dup),
                                         resource.model.treebase,
                                         key_properties(resource).field,
                                         props, resource.model.multivalue_field)
                    rescue => e
                      raise e unless resource.model.multivalue_field
                      # TODO something with creating these multivalue objects
                    end
        logger.debug { "resource #{resource.inspect} key value: #{key_value.inspect}" + ", multivalue_field: " + resource.model.multivalue_field.to_s }
        if key_value and !key.nil?
          key.set!(resource, key_value.to_i)
          resource
        elsif resource.model.multivalue_field
          multivalue_prop = resource.send(:properties).detect do |prop|
            prop.field.to_sym == resource.model.multivalue_field
          end
          update_resource(resource,
                          { multivalue_prop =>
                            resource.send(multivalue_prop.name.to_sym)})
        else
          nil
        end
      end

      # @param [DataMapper::Resource] resource
      #   to be updated
      # @param [Hash] attributes
      #   new attributes for the resource
      # @see SimpleAdapter#update_resource
      def update_resource(resource, attributes)
        actions = []
        attributes.each do |property, value|
          field = property.field.to_sym #TODO sym needed or string ???
          if property.class == ::Ldap::LdapArray
            value = property.load(value)
            if resource.original_attributes[property].nil?
              value.each do |v|
                actions << [:add, field, v]
              end
            else
              array_actions = []
              resource.original_attributes[property].each do |ov|
                unless value.member? ov
                  actions << [:delete, field, ov.to_s]
                end
              end
              value.each do |v|
                unless resource.original_attributes[property].member? v
                  actions << [:add, field, v.to_s]
                end
              end
              array_actions
            end
          else
            if resource.model.multivalue_field == property.field.to_sym
              if value.nil?
                actions << [:delete, field, resource.attribute_get(property.name).to_s]
              else
                actions << [:add, field, value.to_s]
              end
            elsif value.nil?
              actions << [:delete, field, []]
            elsif resource.original_attributes[property].nil?
              actions << [:add, field, value.to_s]
            else
              actions << [:replace, field, value.to_s]
            end
          end
        end
#puts "actions"
#p actions
#puts
        ldap.update_object(resource.model.dn_prefix(resource),
                           resource.model.treebase,
                           actions)
      end

      # @see AbstractAdapter#delete
      def delete(collection)
        collection.each do |resource|
          if resource.model.multivalue_field
            multivalue_prop = resource.send(:properties).detect do |prop|
              prop.field.to_sym == resource.model.multivalue_field
            end
            update_resource(resource,
                            { multivalue_prop => nil })
          else
            ldap.delete_object(resource.model.dn_prefix(resource),
                               resource.model.treebase)
          end
        end
      end

      # @see AbstractAdapter#read
      def read(query)
        result = []
        #get data values out of the query
        resources = read_resources(query)
        resources.each do |resource|
          map = {}
          query.fields.each_with_index do |property, idx|
            map[property.field] = property.typecast(resource[idx])
          end
          result << map
        end

#puts "read_many"
#p result
        result = result.uniq if query.unique?
        result = query.match_records(result) if query.model.multivalue_field
        result = query.sort_records_case_insensitive(result)
        result = query.limit_records(result)
        result
      end

      def read_resources(query)
        query_order = query.order.first.target.field if query.order
        #Use empty string as default for order in query
        order_by = query_order || ''

        field_names = query.fields.collect {|f| f.field }
        result = ldap.read_objects(query.model.treebase,
                                   query.model.key.collect { |k| k.field },
                                   to_ldap_conditions(query),
                                   field_names, order_by)
        if query.model.multivalue_field
          props_result = []
          result.each do |props|
            # run over all values of the multivalue field
            (props[query.model.multivalue_field] || []).each do |value|
              values =  query.fields.collect do |f|
                if query.model.multivalue_field == f.field.to_sym
                  value
                else
                  prop = props[f.field.to_sym].first
                  f.primitive == Integer ? prop.to_i : prop.join
                end
              end
              props_result << values
            end
          end
          props_result
        else # no multivalue field
          result.collect do |props|
            query.fields.collect do |f|
              prop = props[f.field.to_sym]
              if f.class == Ldap::LdapArray
                prop if prop
              elsif prop
                f.primitive == Integer ? prop.first.to_i : prop.join
              end
            end
          end
        end
      end
    end
  end
end
<commit_msg>Updated some formating.<commit_after>require "dm-core"
require 'slf4r/logger'
# require 'adapters/noop_transaction'

module Ldap

  # the class provides two ways of getting a LdapFacade. either
  # one which is put on the current Thread or a new one
  class LdapConnection

    include ::Slf4r::Logger

    def initialize(options)
      if options[:facade].nil?
        require 'ldap/net_ldap_facade'
        @facade = ::Ldap::NetLdapFacade
      else
        case options[:facade].to_sym
        when :ruby_ldap
          require 'ldap/ruby_ldap_facade'
          @facade = ::Ldap::RubyLdapFacade
        when :net_ldap
          require 'ldap/net_ldap_facade'
          @facade = ::Ldap::NetLdapFacade
        else
          "please add a :facade parameter to the adapter setup. possible values are :ruby_ldap or net_ldap"
        end
      end
      logger.info("using #{@facade}")
      @ldaps = { }
      auth =  {
        :method => :simple,
        :username => options[:bind_name],
        :password => options[:password]
      }
      @config = {
        :host => options[:host],
        :port => options[:port].to_i,
        :auth => auth,
        :base => options[:base]
      }
    end

    # puts a LdapFacade into the current thread and executes the
    # given block.
    def open
      begin
        @facade.open(@config) do |ldap|
          @ldaps[Thread.current] = @facade.new(ldap)
          yield
        end
      ensure
        @ldaps[Thread.current] = nil
      end
    end

    # @return [Ldap::LdapFacade]
    #  either the one from the current Thread or a new one
    def current
      ldap = @ldaps[Thread.current]
      if ldap
        ldap
      else
        @facade.new(@config)
      end
    end
  end
end

require "dm-core"
module DataMapper
  class Query

    class SortCaseInsensitive < Sort
      def initialize(value, ascending = true)
        if(value && value.is_a?(String))
          super(value.upcase, ascending)
        else
          super
        end
      end
    end

    def sort_records_case_insensitive(records)
      #Return unsorted records unless we have order defined
      return records unless order
      sort_order = order.map { |direction| [ direction.target, direction.operator == :asc ] }
      
      records.sort_by do |record|
        sort_order.map do |(property, ascending)|
          SortCaseInsensitive.new(record_value(record, property), ascending)
        end
      end
    end
  end
  module Adapters
    class LdapAdapter < AbstractAdapter

      # @return [Ldap::LdapFacade]
      #   ready to use LdapFacade
      def ldap
        @ldap_connection.current
      end

      def open_ldap_connection(&block)
        @ldap_connection.open(&block)
      end

      def key_properties(resource)
        resource.model.key.first
      end

      COMPARATORS = { "=" => :eql, ">=" => :gte, "<=" => :lte, "like" => :like }

      # helper to remove datamapper specific classes from the conditions
      # @param [Array] conditions
      #   array of tuples: (action, property, new value)
      # @return [Array]
      #   tuples: (action, attribute name, new value)
      def to_ldap_conditions(query)
        conditions = query.conditions
        ldap_conditions = []
        conditions.operands.each do |c|
          if c.is_a? Array
            props = {}
            query.fields.each{ |f| props[f.name] = f.field}
            or_conditions = []
            c[0].split('or').each do |e|
              e.strip!
              match = e.match("=|<=|>=|like")
              or_conditions << [COMPARATORS[match.values_at(0)[0]],
                                props[match.pre_match.strip.to_sym],
                                match.post_match.strip.gsub(/'/, '')]
            end
            ldap_conditions << [:or_operator, or_conditions, nil]
          else
            comparator = c.slug
            case comparator
            when :raw
            when :not
                # TODO proper recursion !!!
                ldap_conditions << [comparator, c.operands.first.subject.field, c.operands.first.send(:dumped_value)]
            when :in
              ldap_conditions << [:eql, c.subject.field, c.send(:dumped_value)]
            else
              if c.subject.is_a? Ldap::LdapArray
                # assume a single value here !!!
                val = c.send(:dumped_value)
                ldap_conditions << [comparator, c.subject.field, val[1, val.size - 2]]
              else
                ldap_conditions << [comparator, c.subject.field, c.send(:dumped_value)]
              end
            end
          end
        end
        ldap_conditions
      end

      include ::Slf4r::Logger

      # @see AbstractAdapter
#      def transaction_primitive
 #       NoopTransaction.new
  #    end

      public

      def initialize(name, options)
        super(name, options)
        @ldap_connection = ::Ldap::LdapConnection.new(@options)
      end


      def create(resources)
        resources.select do |resource|
          create_resource(resource)
        end.size # just return the number of create resources
      end

      def update(attributes, collection)
        collection.each do |resource|
#puts "update"
#p resource
          update_resource(resource, attributes)

        end.size
      end
      # @param [DataMapper::Resource] resource
      #   to be created
      # @see SimpleAdapter#create_resource
      # @return [Fixnum]
      #    value for the primary key or nil
      def create_resource(resource)
        logger.debug { resource.inspect }

        props = resource.model.ldap_properties(resource)
        key = nil
        resource.send(:properties).each do |prop|
          value = prop.get!(resource)
          if prop.class == ::Ldap::LdapArray
            props[prop.field.to_sym] = value unless value.nil? or value.size == 0
          else
            props[prop.field.to_sym] = value.to_s unless value.nil?
          end
          key = prop if prop.serial?
        end
        resource_dup = resource.dup
        id = ldap.retrieve_next_id(resource.model.treebase,
                                   key_properties(resource).field)
        resource_dup.send("#{key_properties(resource).name}=".to_sym, id)
        props[key_properties(resource).field.to_sym] = "#{id}"
        key_value = begin
                      ldap.create_object(resource.model.dn_prefix(resource_dup),
                                         resource.model.treebase,
                                         key_properties(resource).field,
                                         props, resource.model.multivalue_field)
                    rescue => e
                      raise e unless resource.model.multivalue_field
                      # TODO something with creating these multivalue objects
                    end
        logger.debug { "resource #{resource.inspect} key value: #{key_value.inspect}" + ", multivalue_field: " + resource.model.multivalue_field.to_s }
        if key_value and !key.nil?
          key.set!(resource, key_value.to_i)
          resource
        elsif resource.model.multivalue_field
          multivalue_prop = resource.send(:properties).detect do |prop|
            prop.field.to_sym == resource.model.multivalue_field
          end
          update_resource(resource,
                          { multivalue_prop =>
                            resource.send(multivalue_prop.name.to_sym)})
        else
          nil
        end
      end

      # @param [DataMapper::Resource] resource
      #   to be updated
      # @param [Hash] attributes
      #   new attributes for the resource
      # @see SimpleAdapter#update_resource
      def update_resource(resource, attributes)
        actions = []
        attributes.each do |property, value|
          field = property.field.to_sym #TODO sym needed or string ???
          if property.class == ::Ldap::LdapArray
            value = property.load(value)
            if resource.original_attributes[property].nil?
              value.each do |v|
                actions << [:add, field, v]
              end
            else
              array_actions = []
              resource.original_attributes[property].each do |ov|
                unless value.member? ov
                  actions << [:delete, field, ov.to_s]
                end
              end
              value.each do |v|
                unless resource.original_attributes[property].member? v
                  actions << [:add, field, v.to_s]
                end
              end
              array_actions
            end
          else
            if resource.model.multivalue_field == property.field.to_sym
              if value.nil?
                actions << [:delete, field, resource.attribute_get(property.name).to_s]
              else
                actions << [:add, field, value.to_s]
              end
            elsif value.nil?
              actions << [:delete, field, []]
            elsif resource.original_attributes[property].nil?
              actions << [:add, field, value.to_s]
            else
              actions << [:replace, field, value.to_s]
            end
          end
        end
#puts "actions"
#p actions
#puts
        ldap.update_object(resource.model.dn_prefix(resource),
                           resource.model.treebase,
                           actions)
      end

      # @see AbstractAdapter#delete
      def delete(collection)
        collection.each do |resource|
          if resource.model.multivalue_field
            multivalue_prop = resource.send(:properties).detect do |prop|
              prop.field.to_sym == resource.model.multivalue_field
            end
            update_resource(resource,
                            { multivalue_prop => nil })
          else
            ldap.delete_object(resource.model.dn_prefix(resource),
                               resource.model.treebase)
          end
        end
      end

      # @see AbstractAdapter#read
      def read(query)
        result = []
        #get data values out of the query
        resources = read_resources(query)
        resources.each do |resource|
          map = {}
          query.fields.each_with_index do |property, idx|
            map[property.field] = property.typecast(resource[idx])
          end
          result << map
        end

#puts "read_many"
#p result
        result = result.uniq if query.unique?
        result = query.match_records(result) if query.model.multivalue_field
        result = query.sort_records_case_insensitive(result)
        result = query.limit_records(result)
        result
      end

      def read_resources(query)
        query_order = query.order.first.target.field if query.order
        #Use empty string as default for order in query
        order_by = query_order || ''

        field_names = query.fields.collect {|f| f.field }
        result = ldap.read_objects(query.model.treebase,
                                   query.model.key.collect { |k| k.field },
                                   to_ldap_conditions(query),
                                   field_names, order_by)
        if query.model.multivalue_field
          props_result = []
          result.each do |props|
            # run over all values of the multivalue field
            (props[query.model.multivalue_field] || []).each do |value|
              values =  query.fields.collect do |f|
                if query.model.multivalue_field == f.field.to_sym
                  value
                else
                  prop = props[f.field.to_sym].first
                  f.primitive == Integer ? prop.to_i : prop.join
                end
              end
              props_result << values
            end
          end
          props_result
        else # no multivalue field
          result.collect do |props|
            query.fields.collect do |f|
              prop = props[f.field.to_sym]
              if f.class == Ldap::LdapArray
                prop if prop
              elsif prop
                f.primitive == Integer ? prop.first.to_i : prop.join
              end
            end
          end
        end
      end
    end
  end
end

{'fraction_non_alphanumeric': 0.08931360460337033, 'fraction_numerical': 0.0007398273736128237, 'mean_word_length': 1.6201809175102304, 'pattern_counts': {'":': 0, '<': 75, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 20, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '788629', 'n_tokens_mistral': 6716, 'n_tokens_neox': 6617, 'n_words': 1582}