Module: Inquery::Mixins::RelationValidation

Extended by:
ActiveSupport::Concern
Included in:
Query::Chainable
Defined in:
lib/inquery/mixins/relation_validation.rb

Defined Under Namespace

Modules: ClassMethods

Constant Summary collapse

OPTIONS_SCHEMA =
{
  hash: {
    class: { type: String, null: true, required: false },
    fields: { type: :integer, null: true, required: false },
    default_select: { type: :symbol, null: true, required: false },
    default: { type: [Proc, FalseClass], null: true, required: false }
  }
}
DEFAULT_OPTIONS =
{
  # Allows to restrict the class (attribute `klass`) of the relation. Use
  # `nil` to not perform any checks. The `class` attribute will also be
  # taken to infer a default if no relation is given and you didn't
  # specify any `default`.
  class: nil,

  # This allows to specify a default relation that will be taken if no
  # relation is given. This must be specified as a Proc returning the
  # relation. Set this to `false` for no default. If this is set to `nil`,
  # it will try to infer the default from the option `class` (if given).
  default: nil,

  # Allows to restrict the number of fields / values the relation must
  # select. This is particularly useful if you're using the query as a
  # subquery and need it to return exactly one field. Use `nil` to not
  # perform any checks.
  fields: nil,

  # If this is set to a symbol, the relation does not have any select
  # fields specified (`select_values` is empty) and `fields` is > 0, it
  # will automatically select the given field. Use `nil` to disable this
  # behavior.
  default_select: :id
}

Instance Method Summary collapse

Instance Method Details

#validate_relation!(relation) ⇒ Object

Validates (and possibly alters) the given relation according to the options specified at class level using the relation method.



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/inquery/mixins/relation_validation.rb', line 56

def validate_relation!(relation)
  options = DEFAULT_OPTIONS.dup
  options.merge!(self.class._relation_options.dup) if self.class._relation_options

  relation_class = options[:class].try(:constantize)

  # ---------------------------------------------------------------
  # Validate presence
  # ---------------------------------------------------------------
  if relation.nil?
    if options[:default]
      relation = options[:default].call
    elsif options[:default].nil? && relation_class
      relation = relation_class.all
    else
      fail Inquery::Exceptions::InvalidRelation, 'A relation must be given for this query.'
    end
  end

  # ---------------------------------------------------------------
  # Validate class
  # ---------------------------------------------------------------
  if relation_class && relation_class != relation.klass
    fail Inquery::Exceptions::InvalidRelation, "Unexpected relation class '#{relation.klass}' for this query, expected a '#{relation_class}'."
  end

  # ---------------------------------------------------------------
  # Validate selected fields
  # ---------------------------------------------------------------
  fields_count = relation.select_values.size

  if fields_count == 0 && options[:default_select] && options[:fields] && options[:fields] > 0
    relation = relation.select(options[:default_select])
    fields_count = 1
  end

  if !options[:fields].nil? && fields_count != options[:fields]
    fail Inquery::Exceptions::InvalidRelation, "Expected given relation to select #{options[:fields]} field(s) but got #{fields_count}."
  end

  return relation
end