class Clearly::Query::Definition

Validates and represents a model query specification definition.

Attributes

all_fields[R]

@return [Array<Symbol>] available model fields

associations[R]

@return [Array<Hash>] model associations hierarchy

associations_flat[R]

@return [Array<Hash>] model associations flat array

defaults[R]

@return [Hash] defaults

field_mappings[R]

@return [Array<Hash>] mapped model fields

joins[R]

@return [Array<Array<Hash>>] associations organised to calculate joins

model[R]

@return [ActiveRecord::Base] active record model for this definition

table[R]

@return [Arel::Table] arel table for this definition

text_fields[R]

@return [Array<Symbol>] available text model fields

Public Class Methods

new(opts) click to toggle source

Create a Definition @param [Hash] opts the options to create a message with. @option opts [ActiveRecord::Base] :model (nil) the ActiveRecord model @option opts [Hash] :hash (nil) the model definition hash @option opts [Arel::Table] :table (nil) the arel table @return [Clearly::Query::Definition]

# File lib/clearly/query/definition.rb, line 46
def initialize(opts)
  opts = {model: nil, hash: nil, table: nil}.merge(opts)

  # two ways to go: model and hash, or table and joins
  result = nil
  result = create_from_model(opts[:model], opts[:hash]) unless opts[:model].nil?
  result = create_from_table(opts[:table]) if result.nil? && !opts[:table].nil?

  fail Clearly::Query::QueryArgumentError.new('could not build definition from options') if result.nil?
  result
end

Public Instance Methods

get_field_mapping(column_name) click to toggle source

Build custom field from model mappings @param [Symbol] column_name @return [Arel::Nodes::Node, Arel::Attributes::Attribute, String]

# File lib/clearly/query/definition.rb, line 61
def get_field_mapping(column_name)
  value = @field_mappings[column_name]
  if @field_mappings.keys.include?(column_name) && !value.blank?
    value
  else
    nil
  end
end

Private Instance Methods

build_associations_flat(associations) click to toggle source

Create a flat array of joins. @param [Array<Hash>] associations @return [Array<Hash>] associations

# File lib/clearly/query/definition.rb, line 144
def build_associations_flat(associations)
  joins = []

  if associations.is_a?(Array)
    more_associations = associations.map { |i| build_associations_flat(i) }
    joins.push(*more_associations.flatten.compact) if more_associations.size > 0

  elsif associations.is_a?(Hash)
    joins.push(associations.except(:associations))

    if associations[:associations] && associations[:associations].size > 0
      more_associations = build_associations_flat(associations[:associations])
      joins.push(*more_associations.compact) if more_associations.size > 0
    end
  end

  joins.uniq
end
create_from_model(model, hash) click to toggle source

Create a Definition from an ActiveRecord model. @param [ActiveRecord::Base] model the ActiveRecord model @param [Hash] hash the model definition hash @return [Clearly::Query::Definition]

# File lib/clearly/query/definition.rb, line 76
def create_from_model(model, hash)
  validate_model(model)
  validate_definition(hash)

  @model = model
  @table = relation_table(model)

  @all_fields = hash[:fields][:valid]
  @text_fields = hash[:fields][:text]

  mappings = {}
  hash[:fields][:mappings].each { |m| mappings[m[:name]] = m[:value] }
  @field_mappings = mappings

  @associations = hash[:associations]
  @associations_flat = build_associations_flat(@associations)

  if @associations.size > 0
    node = {join: model, on: nil, associations: hash[:associations]}
    graph = Clearly::Query::Graph.new(node, :associations)
    @joins = graph.branches
  else
    @joins = []
  end

  @defaults = hash[:defaults]

  self
end
create_from_table(table) click to toggle source

Create a Definition for a has and belongs to many table. @param [Arel::Table] table the arel table @return [Clearly::Query::Definition]

# File lib/clearly/query/definition.rb, line 109
def create_from_table(table)
  validate_table(table)

  @model = nil
  @table = table
  @all_fields = []
  @text_fields = []
  @field_mappings = []
  @associations = []
  @associations_flat = []
  @joins = []
  @defaults = {}

  table_name = table.name
  associated_table_names = table_name.split('_')

  # assumes associated tables primary key is 'id'
  # assumes associated table names are the plural version of HABTM _id columns
  associated_table_names.each do |t|
    arel_table = Arel::Table.new(t.to_sym)
    id_column = "#{t.singularize}_id"
    join = {join: arel_table, on: arel_table[:id].eq(table[id_column]), available: true}

    @all_fields.push(id_column)
    @associations.push(join)
    @associations_flat.push(join)
    @joins.push([join])
  end

  self
end