Class: ForestAdminAgent::Utils::QueryStringParser
- Inherits:
-
Object
- Object
- ForestAdminAgent::Utils::QueryStringParser
- Includes:
- Http::Exceptions, ForestAdminDatasourceToolkit::Components, ForestAdminDatasourceToolkit::Components::Query, ForestAdminDatasourceToolkit::Exceptions, ForestAdminDatasourceToolkit::Validations
- Defined in:
- lib/forest_admin_agent/utils/query_string_parser.rb
Constant Summary collapse
- DEFAULT_ITEMS_PER_PAGE =
'15'.freeze
- DEFAULT_PAGE_TO_SKIP =
'1'.freeze
- POLYMORPHIC_TARGET_WILDCARD =
'*'.freeze
- FALSY_SEARCH_EXTENDED =
[nil, false, 0, '0', 'false', ''].freeze
Class Method Summary collapse
- .parse_caller(args) ⇒ Object
- .parse_chart_parameters(args) ⇒ Object
- .parse_condition_tree(collection, args) ⇒ Object
- .parse_export_pagination(limit) ⇒ Object
- .parse_pagination(args) ⇒ Object
- .parse_projection(collection, args) ⇒ Object
- .parse_projection_from_header(collection, args) ⇒ Object
- .parse_projection_from_request(collection, args) ⇒ Object
- .parse_projection_with_pks(collection, args) ⇒ Object
-
.parse_requested_projection(collection, args) ⇒ Object
Both halves read the same
fieldsparam the same way on purpose: an emptyfields[<collection>]=means "every column", so it is not named and must take the redaction path rather than a 403. - .parse_search(collection, args) ⇒ Object
- .parse_search_extended(args) ⇒ Object
- .parse_segment(collection, args) ⇒ Object
- .parse_sort(collection, args) ⇒ Object
-
.subset_or_query(args, key) ⇒ Object
Presence, not truth: with
||afalsein the select-all body would silently lose to the query string.
Class Method Details
.parse_caller(args) ⇒ Object
32 33 34 |
# File 'lib/forest_admin_agent/utils/query_string_parser.rb', line 32 def self.parse_caller(args) CallerParser.new(args).parse end |
.parse_chart_parameters(args) ⇒ Object
309 310 311 312 313 314 315 316 317 318 |
# File 'lib/forest_admin_agent/utils/query_string_parser.rb', line 309 def self.parse_chart_parameters(args) params = args[:params] || {} params.each_with_object({}) do |(key, value), result| key_s = key.to_s next if value.nil? || value.is_a?(Hash) || value.is_a?(Array) result[key_s] = value.to_s end end |
.parse_condition_tree(collection, args) ⇒ Object
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/forest_admin_agent/utils/query_string_parser.rb', line 15 def self.parse_condition_tree(collection, args) filters = begin args.dig(:params, :data, :attributes, :all_records_subset_query, :filters) || args.dig(:params, :filters) || args.dig(:params, :filter) rescue StandardError nil end return if filters.nil? filters = JSON.parse(filters, symbolize_names: true) if filters.is_a? String condition_tree = ConditionTreeParser.from_plain_object(collection, filters) ConditionTreeValidator.validate(condition_tree, collection) condition_tree end |
.parse_export_pagination(limit) ⇒ Object
245 246 247 |
# File 'lib/forest_admin_agent/utils/query_string_parser.rb', line 245 def self.parse_export_pagination(limit) Page.new(offset: 0, limit: limit&.to_i) end |
.parse_pagination(args) ⇒ Object
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 |
# File 'lib/forest_admin_agent/utils/query_string_parser.rb', line 225 def self.parse_pagination(args) items_per_pages = args.dig(:params, :data, :attributes, :all_records_subset_query, :size) || args.dig(:params, :page, :size) || DEFAULT_ITEMS_PER_PAGE page = args.dig(:params, :data, :attributes, :all_records_subset_query, :number) || args.dig(:params, :page, :number) || DEFAULT_PAGE_TO_SKIP # Validate both parameters page_valid = !page.to_s.match(/\A[+]?\d+\z/).nil? && page.to_i.positive? limit_valid = !items_per_pages.to_s.match(/\A[+]?\d+\z/).nil? && items_per_pages.to_i.positive? unless page_valid && limit_valid raise BadRequestError, "Invalid pagination [limit: #{items_per_pages}, skip: #{page}]" end offset = (page.to_i - 1) * items_per_pages.to_i Page.new(offset: offset, limit: items_per_pages.to_i) end |
.parse_projection(collection, args) ⇒ Object
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/forest_admin_agent/utils/query_string_parser.rb', line 36 def self.parse_projection(collection, args) fields = args.dig(:params, :fields, collection.name) || '' return ProjectionFactory.all(collection) unless fields != '' && !fields.nil? requested_field_names = fields.split(',').map(&:strip) add_polymorphic_type_fields(collection, requested_field_names) projection_fields = build_projection_fields(collection, requested_field_names, args) ForestAdminDatasourceToolkit::Validations::ProjectionValidator.validate?(collection, projection_fields) Projection.new(projection_fields) rescue ForestAdminDatasourceToolkit::Exceptions::ForestException => e raise BadRequestError, "Invalid projection: #{e.}" end |
.parse_projection_from_header(collection, args) ⇒ Object
52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/forest_admin_agent/utils/query_string_parser.rb', line 52 def self.parse_projection_from_header(collection, args) header = decode_header_value(args.dig(:headers, 'HTTP_FOREST_PROJECTION'))&.strip return if header.nil? || header.empty? projection_fields = build_header_projection_fields(collection, header.split(',', -1).map(&:strip)) ForestAdminDatasourceToolkit::Validations::ProjectionValidator.validate?(collection, projection_fields) Projection.new(projection_fields) rescue ForestAdminDatasourceToolkit::Exceptions::ForestException => e raise BadRequestError, "Invalid Forest-Projection header: #{e.}" end |
.parse_projection_from_request(collection, args) ⇒ Object
66 67 68 |
# File 'lib/forest_admin_agent/utils/query_string_parser.rb', line 66 def self.parse_projection_from_request(collection, args) parse_projection_from_header(collection, args) || parse_projection(collection, args) end |
.parse_projection_with_pks(collection, args) ⇒ Object
221 222 223 |
# File 'lib/forest_admin_agent/utils/query_string_parser.rb', line 221 def self.parse_projection_with_pks(collection, args) parse_projection_from_request(collection, args).with_pks(collection) end |
.parse_requested_projection(collection, args) ⇒ Object
Both halves read the same fields param the same way on purpose: an empty
fields[<collection>]= means "every column", so it is not named and must take the redaction
path rather than a 403.
73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/forest_admin_agent/utils/query_string_parser.rb', line 73 def self.parse_requested_projection(collection, args) from_header = parse_projection_from_header(collection, args) return { projection: from_header, named_by_caller: true } if from_header fields = args.dig(:params, :fields, collection.name) { projection: parse_projection(collection, args), named_by_caller: !(fields.nil? || fields == '') } end |
.parse_search(collection, args) ⇒ Object
268 269 270 271 272 273 274 275 276 277 278 279 280 |
# File 'lib/forest_admin_agent/utils/query_string_parser.rb', line 268 def self.parse_search(collection, args) search = subset_or_query(args, :search) return nil if search.nil? raise BadRequestError, 'Collection is not searchable' unless collection.is_searchable? unless search.is_a?(String) || search.is_a?(Numeric) raise BadRequestError, 'Search must be a string or a number' end search.to_s end |
.parse_search_extended(args) ⇒ Object
282 283 284 285 286 |
# File 'lib/forest_admin_agent/utils/query_string_parser.rb', line 282 def self.parse_search_extended(args) extended = subset_or_query(args, :searchExtended) !FALSY_SEARCH_EXTENDED.include?(extended.is_a?(String) ? extended.downcase : extended) end |
.parse_segment(collection, args) ⇒ Object
320 321 322 323 324 325 326 327 328 329 |
# File 'lib/forest_admin_agent/utils/query_string_parser.rb', line 320 def self.parse_segment(collection, args) segment = args.dig(:params, :data, :attributes, :all_records_subset_query, :segment) || args.dig(:params, :segment) return unless segment raise BadRequestError, "Invalid segment: #{segment}" unless collection.schema[:segments].include?(segment) segment end |
.parse_sort(collection, args) ⇒ Object
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 |
# File 'lib/forest_admin_agent/utils/query_string_parser.rb', line 288 def self.parse_sort(collection, args) raw_sort_string = args.dig(:params, :sort) return SortUtils::SortFactory.by_primary_keys(collection) unless raw_sort_string sort_list = [] raw_sort_string.split(',').map do |sort_string| field = sort_string.tr('.', ':') ascending = !sort_string.start_with?('-') field = field[1..] unless ascending sort_list.push({ field: field, ascending: ascending }) end sort = Sort.new(sort_list) ForestAdminDatasourceToolkit::Validations::SortValidator.validate(collection, sort) sort end |
.subset_or_query(args, key) ⇒ Object
Presence, not truth: with || a false in the select-all body would silently lose to the
query string. An explicit null or '' there is read as absent rather than as "no search",
so neither can widen a result set by discarding the term the URL carried.
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
# File 'lib/forest_admin_agent/utils/query_string_parser.rb', line 252 def self.subset_or_query(args, key) subset = begin args.dig(:params, :data, :attributes, :all_records_subset_query) rescue StandardError nil end return subset[key] if subset.is_a?(Hash) && !subset[key].nil? && subset[key] != '' begin args.dig(:params, key) rescue StandardError nil end end |