<commit_before>module Netzke::Basepack::DataAdapters
  # Implementation of {Netzke::Basepack::DataAdapters::AbstractAdapter}
  class ActiveRecordAdapter < AbstractAdapter
    def self.for_class?(model_class)
      model_class && model_class <= ActiveRecord::Base
    end

    def new_record(params = {})
      @model_class.new(params)
    end

    def primary_key
      @model_class.primary_key.to_s
    end

    def model_attributes
      @_model_attributes ||= attribute_names.map do |column_name|
        # If it's named as foreign key of some association, then it's an association column
        assoc = @model_class.reflect_on_all_associations.detect { |a| a.foreign_key == column_name }

        if assoc && !assoc.options[:polymorphic]
          candidates = %w{name title label} << assoc.klass.primary_key
          assoc_method = candidates.detect{|m| (assoc.klass.instance_methods.map(&:to_s) + assoc.klass.column_names).include?(m) }
          :"#{assoc.name}__#{assoc_method}"
        else
          column_name.to_sym
        end
        # auto set up the default value from the column settings
        # c[:default_value] = @model_class.columns_hash[column_name].default if @model_class.columns_hash[column_name].default
      end
    end

    def attribute_names
      @model_class.column_names
    end

    def human_attribute_name(attr_name)
      @model_class.human_attribute_name(attr_name)
    end

    def attr_type(attr_name)
      association_attr?(attr_name) ? :integer : (@model_class.columns_hash[attr_name.to_s].try(:type) || :string)
    end

    def get_records(params, columns=[])
      @cls = columns
      # build initial relation based on passed params
      relation = get_relation(params)

      # addressing the n+1 query problem
      columns.each do |c|
        assoc, method = c[:name].split('__')
        relation = relation.includes(assoc.to_sym) if method
      end

      # apply sorting if needed
      if params[:sort] && sort_params = params[:sort].first
        dir = sort_params["direction"].downcase
        column = columns.detect { |c| c[:name] == sort_params["property"] }
        relation = apply_sorting(relation, column, dir)
      end

      #page = params[:limit] ? params[:start].to_i/params[:limit].to_i + 1 : 1
      if params[:limit]
        relation.offset(params[:start]).limit(params[:limit])
      else
        relation.all
      end
    end

    def apply_sorting(relation, column, dir)
      assoc, method = column[:name].split('__')

      # if a sorting scope is set, call the scope with the given direction
      if column.has_key?(:sorting_scope)
        relation = relation.send(column[:sorting_scope].to_sym, dir.to_sym)
      else
        relation = if method.nil?
          relation.order("#{@model_class.table_name}.#{assoc} #{dir}")
        else
          assoc = @model_class.reflect_on_association(assoc.to_sym)
          relation.joins(assoc.name).order("#{assoc.klass.table_name}.#{method} #{dir}")
        end
      end

      relation
    end
    protected :apply_sorting

    def count_records(params, columns=[])
      # build initial relation based on passed params
      relation = get_relation(params)

      # addressing the n+1 query problem
      columns.each do |c|
        assoc, method = c[:name].split('__')
        relation = relation.includes(assoc.to_sym) if method
      end

      relation.count
    end

    def get_assoc_property_type assoc_name, prop_name
      if prop_name && assoc=@model_class.reflect_on_association(assoc_name)
        assoc_column = assoc.klass.columns_hash[prop_name.to_s]
        assoc_column.try(:type)
      end
    end

    def virtual_attribute?(c)
      assoc_name, asso = c[:name].split('__')
      assoc, assoc_method = assoc_and_assoc_method_for_attr(c[:name])

      if assoc
        return !assoc.klass.column_names.include?(assoc_method)
      else
        return !@model_class.column_names.include?(c[:name])
      end
    end

    def combo_data(attr, query = "")
      assoc, assoc_method = assoc_and_assoc_method_for_attr(attr[:name])

      if assoc
        # Options for an asssociation attribute

        relation = assoc.klass.scoped
        relation = relation.extend_with(attr[:scope]) if attr[:scope]

        if assoc.klass.column_names.include?(assoc_method)
          # apply query
          relation = relation.where(["#{assoc_method} like ?", "%#{query}%"]) if query.present?
          relation.all.map{ |r| [r.id, r.send(assoc_method)] }
        else
          # an expensive search!
          relation.all.map{ |r| [r.id, r.send(assoc_method)] }.select{ |id,value| value =~ /^#{query}/ }
        end

      else<commit_msg>Implemented query for combo_data with arel<commit_after>module Netzke::Basepack::DataAdapters
  # Implementation of {Netzke::Basepack::DataAdapters::AbstractAdapter}
  class ActiveRecordAdapter < AbstractAdapter
    def self.for_class?(model_class)
      model_class && model_class <= ActiveRecord::Base
    end

    def new_record(params = {})
      @model_class.new(params)
    end

    def primary_key
      @model_class.primary_key.to_s
    end

    def model_attributes
      @_model_attributes ||= attribute_names.map do |column_name|
        # If it's named as foreign key of some association, then it's an association column
        assoc = @model_class.reflect_on_all_associations.detect { |a| a.foreign_key == column_name }

        if assoc && !assoc.options[:polymorphic]
          candidates = %w{name title label} << assoc.klass.primary_key
          assoc_method = candidates.detect{|m| (assoc.klass.instance_methods.map(&:to_s) + assoc.klass.column_names).include?(m) }
          :"#{assoc.name}__#{assoc_method}"
        else
          column_name.to_sym
        end
        # auto set up the default value from the column settings
        # c[:default_value] = @model_class.columns_hash[column_name].default if @model_class.columns_hash[column_name].default
      end
    end

    def attribute_names
      @model_class.column_names
    end

    def human_attribute_name(attr_name)
      @model_class.human_attribute_name(attr_name)
    end

    def attr_type(attr_name)
      association_attr?(attr_name) ? :integer : (@model_class.columns_hash[attr_name.to_s].try(:type) || :string)
    end

    def get_records(params, columns=[])
      @cls = columns
      # build initial relation based on passed params
      relation = get_relation(params)

      # addressing the n+1 query problem
      columns.each do |c|
        assoc, method = c[:name].split('__')
        relation = relation.includes(assoc.to_sym) if method
      end

      # apply sorting if needed
      if params[:sort] && sort_params = params[:sort].first
        dir = sort_params["direction"].downcase
        column = columns.detect { |c| c[:name] == sort_params["property"] }
        relation = apply_sorting(relation, column, dir)
      end

      #page = params[:limit] ? params[:start].to_i/params[:limit].to_i + 1 : 1
      if params[:limit]
        relation.offset(params[:start]).limit(params[:limit])
      else
        relation.all
      end
    end

    def apply_sorting(relation, column, dir)
      assoc, method = column[:name].split('__')

      # if a sorting scope is set, call the scope with the given direction
      if column.has_key?(:sorting_scope)
        relation = relation.send(column[:sorting_scope].to_sym, dir.to_sym)
      else
        relation = if method.nil?
          relation.order("#{@model_class.table_name}.#{assoc} #{dir}")
        else
          assoc = @model_class.reflect_on_association(assoc.to_sym)
          relation.joins(assoc.name).order("#{assoc.klass.table_name}.#{method} #{dir}")
        end
      end

      relation
    end
    protected :apply_sorting

    def count_records(params, columns=[])
      # build initial relation based on passed params
      relation = get_relation(params)

      # addressing the n+1 query problem
      columns.each do |c|
        assoc, method = c[:name].split('__')
        relation = relation.includes(assoc.to_sym) if method
      end

      relation.count
    end

    def get_assoc_property_type assoc_name, prop_name
      if prop_name && assoc=@model_class.reflect_on_association(assoc_name)
        assoc_column = assoc.klass.columns_hash[prop_name.to_s]
        assoc_column.try(:type)
      end
    end

    def virtual_attribute?(c)
      assoc_name, asso = c[:name].split('__')
      assoc, assoc_method = assoc_and_assoc_method_for_attr(c[:name])

      if assoc
        return !assoc.klass.column_names.include?(assoc_method)
      else
        return !@model_class.column_names.include?(c[:name])
      end
    end

    def combo_data(attr, query = "")
      assoc, assoc_method = assoc_and_assoc_method_for_attr(attr[:name])

      if assoc
        # Options for an asssociation attribute

        relation = assoc.klass.scoped
        relation = relation.extend_with(attr[:scope]) if attr[:scope]

        if assoc.klass.column_names.include?(assoc_method)
          # apply query
          assoc_arel_table = assoc.klass.arel_table

          relation = relation.where(assoc_arel_table[assoc_method].matches("%#{query}%"))  if query.present?
          relation.all.map{ |r| [r.id, r.send(assoc_method)] }
        else
          # an expensive search!
          relation.all.map{ |r| [r.id, r.send(assoc_method)] }.select{ |id,value| value =~ /^#{query}/ }
        end

      else
{'fraction_non_alphanumeric': 0.10991219718607849, 'fraction_numerical': 0.0008462921823759652, 'mean_word_length': 2.8477818477818477, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 3, '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': '3312650', 'n_tokens_mistral': 2963, 'n_tokens_neox': 2932, 'n_words': 612}