Class: Praxis::Extensions::Pagination::OrderingParams

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
Attributor::Dumpable, Attributor::Type
Defined in:
lib/praxis/extensions/pagination/ordering_params.rb

Defined Under Namespace

Classes: DSLCompiler

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(parsed) ⇒ OrderingParams

Returns a new instance of OrderingParams.



195
196
197
# File 'lib/praxis/extensions/pagination/ordering_params.rb', line 195

def initialize(parsed)
  @items = parsed
end

Class Attribute Details

.enforce_allObject

True when we need to enforce the allowed fields at all ordering positions



84
85
86
# File 'lib/praxis/extensions/pagination/ordering_params.rb', line 84

def enforce_all
  @enforce_all
end

.fields_allowedObject

True when we need to enforce the allowed fields at all ordering positions



84
85
86
# File 'lib/praxis/extensions/pagination/ordering_params.rb', line 84

def fields_allowed
  @fields_allowed
end

.media_typeObject (readonly)

Returns the value of attribute media_type.



83
84
85
# File 'lib/praxis/extensions/pagination/ordering_params.rb', line 83

def media_type
  @media_type
end

Instance Attribute Details

#itemsObject (readonly)

Returns the value of attribute items.



100
101
102
# File 'lib/praxis/extensions/pagination/ordering_params.rb', line 100

def items
  @items
end

Class Method Details

.construct(pagination_definition, **options) ⇒ Object



126
127
128
129
130
131
# File 'lib/praxis/extensions/pagination/ordering_params.rb', line 126

def self.construct(pagination_definition, **options)
  return self if pagination_definition.nil?

  DSLCompiler.new(self, **options).parse(*pagination_definition)
  self
end

.constructable?Boolean

Returns:

  • (Boolean)


122
123
124
# File 'lib/praxis/extensions/pagination/ordering_params.rb', line 122

def self.constructable?
  true
end

.describe(_root = false, example: nil) ⇒ Object



184
185
186
187
188
189
190
191
192
193
# File 'lib/praxis/extensions/pagination/ordering_params.rb', line 184

def self.describe(_root = false, example: nil)
  hash = super

  if fields_allowed
    hash[:fields_allowed] = fields_allowed
    hash[:enforced_for] = enforce_all ? :all : :first
  end

  hash
end

.display_nameObject



114
115
116
# File 'lib/praxis/extensions/pagination/ordering_params.rb', line 114

def self.display_name
  'Ordering'
end

.dump(value, **_opts) ⇒ Object



180
181
182
# File 'lib/praxis/extensions/pagination/ordering_params.rb', line 180

def self.dump(value, **_opts)
  load(value).dump
end

.enforce_all_fields(newval = nil) ⇒ Object



66
67
68
# File 'lib/praxis/extensions/pagination/ordering_params.rb', line 66

def self.enforce_all_fields(newval = nil)
  newval ? @enforce_all_fields = newval : @enforce_all_fields
end

.example(_context = Attributor::DEFAULT_ROOT_CONTEXT, **_options) ⇒ Object



133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/praxis/extensions/pagination/ordering_params.rb', line 133

def self.example(_context = Attributor::DEFAULT_ROOT_CONTEXT, **_options)
  fields = if media_type
             chosen_set = if enforce_all
                            fields_allowed.sample(2)
                          else
                            starting_set = fields_allowed.sample(1)
                            simple_attrs = media_type.attributes.select do |_k, attr|
                              attr.type == Attributor::String || attr.type < Attributor::Numeric || attr.type < Attributor::Temporal
                            end.keys
                            starting_set + simple_attrs.reject { |attr| attr == starting_set.first }.sample(1)
                          end
             chosen_set.each_with_object([]) do |chosen, arr|
               sign = rand(10) < 5 ? '-' : ''
               arr << "#{sign}#{chosen}"
             end.join(',')
           else
             'name,last_name,-birth_date'
           end
  load(fields)
end

.familyObject



118
119
120
# File 'lib/praxis/extensions/pagination/ordering_params.rb', line 118

def self.family
  'string'
end

.for(media_type, **_opts) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/praxis/extensions/pagination/ordering_params.rb', line 86

def for(media_type, **_opts)
  unless media_type < Praxis::MediaType
    raise ArgumentError, "Invalid type: #{media_type.name} for Ordering. " \
      'Must be a subclass of MediaType'
  end

  ::Class.new(self) do
    @media_type = media_type
    # Default is to only enforce the allowed fields in the first ordering position (the one typicall uses an index if there)
    @enforce_all = OrderingParams.enforce_all_fields
  end
end

.json_schema_typeObject



102
103
104
# File 'lib/praxis/extensions/pagination/ordering_params.rb', line 102

def self.json_schema_type
  :string
end

.load(order, _context = Attributor::DEFAULT_ROOT_CONTEXT, **_options) ⇒ Object



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/praxis/extensions/pagination/ordering_params.rb', line 159

def self.load(order, _context = Attributor::DEFAULT_ROOT_CONTEXT, **_options)
  return order if order.is_a?(native_type)

  parsed_order = {}
  unless order.nil?
    parsed_order = order.split(',').each_with_object([]) do |order_string, arr|
      item = case order_string[0]
             when '-'
               { desc: order_string[1..].to_s }
             when '+'
               { asc: order_string[1..].to_s }
             else
               { asc: order_string.to_s }
             end
      arr.push item
    end
  end

  new(parsed_order)
end

.nameObject



110
111
112
# File 'lib/praxis/extensions/pagination/ordering_params.rb', line 110

def self.name
  'Praxis::Types::OrderingParams'
end

.native_typeObject



106
107
108
# File 'lib/praxis/extensions/pagination/ordering_params.rb', line 106

def self.native_type
  self
end

.validate(value, context = Attributor::DEFAULT_ROOT_CONTEXT, _attribute = nil) ⇒ Object



154
155
156
157
# File 'lib/praxis/extensions/pagination/ordering_params.rb', line 154

def self.validate(value, context = Attributor::DEFAULT_ROOT_CONTEXT, _attribute = nil)
  instance = load(value, context)
  instance.validate(context)
end

Instance Method Details

#dumpObject



226
227
228
229
230
231
232
233
234
235
# File 'lib/praxis/extensions/pagination/ordering_params.rb', line 226

def dump
  items.each_with_object([]) do |spec, arr|
    dir, field = spec.first
    arr << if dir == :desc
             "-#{field}"
           else
             field
           end
  end.join(',')
end

#each(&block) ⇒ Object



237
238
239
# File 'lib/praxis/extensions/pagination/ordering_params.rb', line 237

def each(&block)
  items.each(&block)
end

#valid_attribute_path?(media_type, path) ⇒ Boolean

Looks up if the given path (with symbol attribute names at each component) is actually a valid path from the given mediatype

Returns:

  • (Boolean)


243
244
245
246
247
248
249
250
251
252
# File 'lib/praxis/extensions/pagination/ordering_params.rb', line 243

def valid_attribute_path?(media_type, path)
  first, *rest = path
  # Get the member type if this is a collection
  media_type = media_type.member_type if media_type.respond_to?(:member_attribute)
  if (attribute = media_type.attributes[first])
    rest.empty? ? true : valid_attribute_path?(attribute.type, rest)
  else
    false
  end
end

#validate(_context = Attributor::DEFAULT_ROOT_CONTEXT) ⇒ Object



199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/praxis/extensions/pagination/ordering_params.rb', line 199

def validate(_context = Attributor::DEFAULT_ROOT_CONTEXT)
  return [] if items.blank?

  errors = []
  if self.class.fields_allowed
    # Validate against the enforced components (either all, or just the first one)
    enforceable_items = self.class.enforce_all ? items : [items.first]

    enforceable_items.each do |spec|
      _dir, field = spec.first
      field = field.to_sym
      next if self.class.fields_allowed.include?(field)

      field_path = field.to_s.split('.').map(&:to_sym)
      errors << if valid_attribute_path?(self.class.media_type, field_path)
                  "Ordering by field \'#{field}\' in media type #{self.class.media_type.name} is disallowed. Ordering is only allowed using the following fields: " +
                  self.class.fields_allowed.map { |f| "\'#{f}\'" }.join(', ').to_s
                else
                  "Ordering by field \'#{field}\' is not possible as this field is not reachable from " \
                  "media type #{self.class.media_type.name}"
                end
    end
  end

  errors
end