Class: GraphqlDeclarative::FilterInput
- Inherits:
-
GraphQL::Schema::InputObject
- Object
- GraphQL::Schema::InputObject
- GraphqlDeclarative::FilterInput
- Defined in:
- lib/graphql_declarative/filter_input.rb
Overview
A GraphQL::Schema::InputObject built from filter declarations.
class Types::CourseFilter < GraphqlDeclarative::FilterInput
filter :title, :string, ops: [:eq, :contains, :starts_with]
filter :published, :boolean
filter :created_at, :datetime, ops: [:gte, :lte]
filter :author_name, :string, through: :author, column: :name
end
Each (name, op) pair generates one argument: :title_contains, :created_at_gte.
:eq generates the bare name (:title), not :title_eq.
The registry (definitions) is what Filter.apply reads back at request
time. It is the ONLY source of column and association identifiers — nothing
in the SQL layer is ever derived from user input. See SPEC.md section 7.
Defined Under Namespace
Classes: Definition
Constant Summary collapse
- DEFAULT_OPS =
{ string: %i[eq contains starts_with ends_with in], integer: %i[eq gt gte lt lte in], float: %i[eq gt gte lt lte], boolean: %i[eq], datetime: %i[eq gt gte lt lte] }.freeze
- GRAPHQL_TYPES =
The GraphQL scalar each declared type maps to.
:inwraps this in a list and the LIKE ops (contains/starts_with/ends_with) override it to String. { string: GraphQL::Types::String, integer: GraphQL::Types::Int, float: GraphQL::Types::Float, boolean: GraphQL::Types::Boolean, datetime: GraphQL::Types::ISO8601DateTime }.freeze
Class Method Summary collapse
-
.argument_name_for(name, op) ⇒ Object
The argument naming table from SPEC.md section 4.
-
.definitions ⇒ Object
=> Definition.
-
.filter(name, type, ops: nil, through: nil, column: nil) ⇒ Object
Declare one filterable attribute and generate one argument per op.
-
.own_definitions ⇒ Object
Declarations made directly on this class, excluding inherited ones.
Class Method Details
.argument_name_for(name, op) ⇒ Object
The argument naming table from SPEC.md section 4. :eq is the bare
name — title, never title_eq.
103 104 105 |
# File 'lib/graphql_declarative/filter_input.rb', line 103 def argument_name_for(name, op) (op.to_sym == :eq) ? name.to_sym : :"#{name}_#{op}" end |
.definitions ⇒ Object
=> Definition. Inheritance-safe: walking superclass on every
read means a subclass sees its parent's declarations without ever
holding (or mutating) the parent's hash. Adding a filter to the parent
after the subclass exists is picked up too.
88 89 90 91 92 93 94 |
# File 'lib/graphql_declarative/filter_input.rb', line 88 def definitions if superclass.respond_to?(:definitions) superclass.definitions.merge(own_definitions) else own_definitions.dup end end |
.filter(name, type, ops: nil, through: nil, column: nil) ⇒ Object
Declare one filterable attribute and generate one argument per op.
Everything here fails loudly at class-definition time (SPEC.md 6.1): an unknown type or an op that makes no sense for the type is a boot error, never a per-request surprise.
46 47 48 49 50 51 52 53 54 55 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 |
# File 'lib/graphql_declarative/filter_input.rb', line 46 def filter(name, type, ops: nil, through: nil, column: nil) name = name.to_sym type = type.to_sym valid_ops = DEFAULT_OPS[type] unless valid_ops raise Error, "unknown filter type #{type.inspect} for filter #{name.inspect}; " \ "expected one of #{DEFAULT_OPS.keys.inspect}" end ops = Array(ops || valid_ops).map(&:to_sym) raise Error, "filter #{name.inspect} declares an empty ops list" if ops.empty? invalid = ops - valid_ops unless invalid.empty? raise Error, "invalid op(s) #{invalid.inspect} for #{type} filter #{name.inspect}; " \ "valid ops for #{type} are #{valid_ops.inspect}" end definition = Definition.new( name: name, type: type, ops: ops.freeze, through: through&.to_sym, # `column:` defaults to the filter name; for a `through:` filter it is # the column on the ASSOCIATION's table, not on the base model. column: (column || name).to_sym ) own_definitions[name] = definition ops.each do |op| argument(argument_name_for(name, op), graphql_type_for(type, op), required: false) end definition end |
.own_definitions ⇒ Object
Declarations made directly on this class, excluding inherited ones.
97 98 99 |
# File 'lib/graphql_declarative/filter_input.rb', line 97 def own_definitions @own_definitions ||= {} end |