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 =
Schemacop::Schema.new do
  opt :class, :string
  opt :fields, :integer
  opt :default_select, :symbol
  opt :default, :object, classes: [Proc, FalseClass]
end
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
}.freeze

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.



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
98
99
100
101
102
103
104
# File 'lib/inquery/mixins/relation_validation.rb', line 63

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.zero? && options[:default_select] && options[:fields]&.positive?
    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