Skip to content
This repository has been archived by the owner on Sep 24, 2019. It is now read-only.

Commit

Permalink
Merged next into master for 0.6.0 release.
Browse files Browse the repository at this point in the history
Fixed:

- Facets are not created for evidence uploaded through a dataset.
- Facets are empty while uploading a dataset.
- Dataset evidence collection is missing annotation/namespace URIs (#95).

Changed:

- Mongo schema redesign for evidence.facets and evidence facet cache.
- Bumped MongoDB requirement to 3.2.0. We now use the $slice operator
  for facet aggregation operations.

Added:

- Export evidence using BEL translator plugins (#44).
- Export dataset evidence using BEL translator plugins (#99).
- Mongo migration scripts for existing installations of openbel-api.
- Upgrading guide.
- 0.6.0 changelog notes.

Squashed commit of the following:

commit be2e6e1
Author: Anthony Bargnesi <[email protected]>
Date:   Tue Mar 15 15:07:24 2016 -0400

    replace method for BEL.keys_to_symbols

    additional style alignment

commit fbf5368
Author: Anthony Bargnesi <[email protected]>
Date:   Tue Mar 15 09:25:06 2016 -0400

    return 404 when translating empty evidence results

    refs #44

commit ac61baf
Author: Anthony Bargnesi <[email protected]>
Date:   Tue Mar 15 08:32:37 2016 -0400

    added storage.engine note for UPGRADING to 0.6.0

commit 3f4f700
Author: Anthony Bargnesi <[email protected]>
Date:   Tue Mar 15 08:27:14 2016 -0400

    added UPGRADING guide

commit 29f86e8
Author: Anthony Bargnesi <[email protected]>
Date:   Tue Mar 15 08:05:01 2016 -0400

    added document for 0.6.0 mongodb migration

commit 0e22354
Author: Anthony Bargnesi <[email protected]>
Date:   Tue Mar 15 06:30:26 2016 -0400

    add configuration check for MongoDB 3.2

    Check will fail to start OpenBEL API is MongoDB is < 3.2

commit 45e5e39
Author: Anthony Bargnesi <[email protected]>
Date:   Tue Mar 15 06:17:57 2016 -0400

    added missing arg to render evidence collection

commit 1edb037
Author: Anthony Bargnesi <[email protected]>
Date:   Mon Mar 14 14:45:43 2016 -0400

    set mongo operation timeouts to unbounded

    The operation timeout is the number of seconds that can pass before
    subsequent reads from a mongo operation. This change makes this read
    timeout unbounded in order to satisfy long evidence and facet creation
    queries.

commit 39524ca
Author: Anthony Bargnesi <[email protected]>
Date:   Mon Mar 14 13:46:25 2016 -0400

    remove cache facets during dataset load

    Cached facets were removed at the end of a dataset load. Now they are
    additionally removed at the start of the load as well as every increment
    of 10k nanopubs loaded.

commit 68c2107
Merge: de9a500 61a291d
Author: Anthony Bargnesi <[email protected]>
Date:   Mon Mar 14 12:50:35 2016 -0400

    Merge branch 'next' into rewrite_references

commit 61a291d
Merge: 1b4dbb7 1bdf14e
Author: Tony Bargnesi <[email protected]>
Date:   Mon Mar 14 12:20:40 2016 -0400

    Merge pull request #101 from nbargnesi/issue100

    Issue100

commit 1bdf14e
Author: Nick Bargnesi <[email protected]>
Date:   Mon Mar 14 12:05:43 2016 -0400

    document auth.enabled, auth.secret

commit 0e900f6
Author: Nick Bargnesi <[email protected]>
Date:   Tue Feb 2 13:56:15 2016 -0500

    include only auth enabled/secret in default config

    for #100

commit fbb8b06
Author: Nick Bargnesi <[email protected]>
Date:   Tue Feb 2 13:55:54 2016 -0500

    simplify authenticate route to enabled/disabled

commit fe724ff
Author: Nick Bargnesi <[email protected]>
Date:   Tue Feb 2 13:54:30 2016 -0500

    remove rest-client dependency

commit de9a500
Author: Anthony Bargnesi <[email protected]>
Date:   Thu Mar 10 14:29:16 2016 -0500

    set mongo connection pool size to 30

    This number was chosen in order to have at most 30 long-running queries
    simulaneously executing. This would then fail the 31st query unless a
    connection could be obtained with a timeout of 5 seconds.

commit 8d46fc1
Author: Anthony Bargnesi <[email protected]>
Date:   Wed Mar 9 14:54:15 2016 -0500

    do not index value of experiment_context/metadata

    annotation values can be large amount of text that will not fit into an
    index key of 1024, if it's attempted you may see an error:

      WiredTigerIndex::insert: key too large to index...

commit 4426582
Author: Anthony Bargnesi <[email protected]>
Date:   Tue Mar 8 23:01:46 2016 -0500

    flatten translator arrays so we return one, if any

commit 4d42c35
Author: Anthony Bargnesi <[email protected]>
Date:   Tue Mar 8 20:38:41 2016 -0500

    bump puma to 3.1.0

commit 5081567
Author: Anthony Bargnesi <[email protected]>
Date:   Tue Mar 8 20:36:41 2016 -0500

    remove unnecessary local variables

commit 32c5e56
Author: Tony Bargnesi <[email protected]>
Date:   Tue Mar 8 16:59:38 2016 -0500

    Update README.md

commit 53ea95f
Author: Tony Bargnesi <[email protected]>
Date:   Tue Mar 8 16:51:59 2016 -0500

    Update README.md

commit 53653c0
Author: Anthony Bargnesi <[email protected]>
Date:   Mon Mar 7 23:06:27 2016 -0500

    correct references when serialization evidence

    using rewrite references work in bel.rb

commit 1b4dbb7
Author: Anthony Bargnesi <[email protected]>
Date:   Tue Feb 2 16:11:02 2016 -0500

    convert /api/evidence to BEL using translators

    factored out rendering of evidence_resource_collection to evidence
    helper

    refs #44

commit 3500811
Author: Anthony Bargnesi <[email protected]>
Date:   Tue Feb 2 15:20:01 2016 -0500

    factored out filters validation into helper

    functional decomposition of filter validation for better
    understanding and maintenance; now reporting multiple JSON errors when
    responding with 400.

commit 83935aa
Author: Anthony Bargnesi <[email protected]>
Date:   Tue Feb 2 15:18:27 2016 -0500

    added doc for opening ::Sinatra::Helpers::Stream

    It is important to convey why methods were added to this class. The
    methods are a convenience so RDF.rb's writers can expect to call them.

commit c984f8a
Author: Anthony Bargnesi <[email protected]>
Date:   Tue Feb 2 15:08:44 2016 -0500

    bump version dependencies for bel-rdf-jena / rdf

    rdf bumped to 1.99.1

    bel-rdf-jena bumped to 0.4.2

commit e4eb5dd
Author: Anthony Bargnesi <[email protected]>
Date:   Mon Feb 1 14:50:34 2016 -0500

    dataset serialization to all bel.rb translators

    updated dependencies to support all bel.rb translators

    refs #99

commit b1243d8
Author: Anthony Bargnesi <[email protected]>
Date:   Tue Jan 26 15:57:16 2016 -0500

    aggregate on full-text search; avoids Mongo limits

    A full-text search filter to /api/evidence with a sort on bel_statement
    only used the text index. This means that the bel_statement sort had to
    be done in memory.

    This reaches the 32 MB sort limit with only several tens of thousands of
    documents.

    The solution employed here was to use cursored aggregation allowing disk
    use for sort stages.

    The solution was introduced as an alternative code path if a FTS filter
    was included in the HTTP request. Although this did minimize the risk of
    regression there is a fair bit of to clean up in the mongo
    access layer.

    closes #96

commit 5d44fd0
Author: Anthony Bargnesi <[email protected]>
Date:   Mon Jan 25 21:48:12 2016 -0500

    return annotation/namespace defs in BEL Script

    removed normalization of experiment_context annotation keywords. The
    normalized names were in inconsistent with references.annotations
    definitions.

    integrate next version of bel.rb (0.4.3) to get fixes for
    annotation/namespace formats.

    refs #95

commit 92f7e7e
Author: Anthony Bargnesi <[email protected]>
Date:   Mon Jan 25 15:51:14 2016 -0500

    require MongoDB 3.2; closes #98

commit 0507714
Author: Anthony Bargnesi <[email protected]>
Date:   Mon Jan 25 14:57:28 2016 -0500

    added 0.6.0 mongo migration helper, details follow

    The clear_evidence_facets_cache.rb mongo migration will clear out new
    evidence facet cache storage in case searches were built before
    migrating all documents in the "evidence" collection.

commit 7707a92
Author: Anthony Bargnesi <[email protected]>
Date:   Thu Jan 14 14:16:24 2016 -0500

    fix /api/datasets/{id}/evidence for facet changes

    Now facets correctly in light of evidence facet changes and respects
    "max_values_per_facet".

commit 19eedef
Author: Anthony Bargnesi <[email protected]>
Date:   Thu Jan 14 13:10:57 2016 -0500

    add scripts for Mongo data migrations in 0.6.0

    - Drops evidence_facets since it has been replaced by
      evidence_facet_cache plus individual "evidence_facet_cache_{UUID}"
      collections.
    - Updates each evidence document to have "facets" field contain JSON
      objects instead of JSON strings.

commit 21a7bc4
Author: Anthony Bargnesi <[email protected]>
Date:   Thu Jan 14 13:08:32 2016 -0500

    bumped next version to 0.6.0

    Minor release looking to include:
    - New evidence facet storage in mongo.
    - Improve dataset import for large documents (occasional OOM).
    - Evidence streaming.
    - Evidence export to multiple formats.

commit bb2ac16
Author: Anthony Bargnesi <[email protected]>
Date:   Wed Jan 13 16:44:47 2016 -0500

    facet cache collection creation and removal

    This design builds individual facet_cache collections based on the
    filters applied to the evidence collection. Each filtered evidence
    collection will get it's own "evidence_facet_cache_{UUID}" mongo
    collection. The facets values are grouped by category, name so it's
    trivial to cursor out the facets (still need to set the filter string
    though).

    This alleviates the max document size issue for large evidence
    collections. A max of 1000 facet values can be added to each category,
    name pair in order to stay within the size limit.

    Facet cache eviction isn't great here:

    - Individual evidence changes require removal of facet caches for the
      empty filter search as well as any overlapping filter/facet.
    - Creation or removal of a dataset will remove all facet caches. The
      thought is that for large dataset imports it is more effective to
      regenerate than cache vs. trying to synchronize it with new data.

    This includes a breaking change to evidence document schema. The
    evidence "facets" array stores the full category, name, value json
    objects instead of flat strings. This is done to make it possible to
    separate values into category, name groupings. We should include an
    upgrade note for this and possibly a script.

commit f5a08a3
Merge: f038be2 a515587
Author: Anthony Bargnesi <[email protected]>
Date:   Wed Jan 13 16:42:24 2016 -0500

    Merge branch 'master' into next

commit f038be2
Author: Anthony Bargnesi <[email protected]>
Date:   Mon Jan 11 22:58:47 2016 -0500

    batch evidence to an array, avoid JRuby enumerator

    The JRuby enumerator uses a thread per next object in an enumerator
    which proves costly. Hundreds of threads are created (tested with
    yourkit) when batch-creating evidence due to the "each_slice(500)" of
    the enumerator.

    This issue is logged in JRuby:
    jruby/jruby#2577

    The solution employed was to yield each evidence directly to the block
    and batch 500 into an array at a time. This should avoid the OOM
    exception received:

    ava.lang.OutOfMemoryError: unable to create new native thread

    Indeed the thread count was observed to be lower in yourkit.
  • Loading branch information
Anthony Bargnesi committed Mar 16, 2016
1 parent a515587 commit 55c531e
Show file tree
Hide file tree
Showing 29 changed files with 1,332 additions and 695 deletions.
18 changes: 13 additions & 5 deletions .gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,25 @@ Gem::Specification.new do |spec|
# Dependencies

## bel.rb
spec.add_runtime_dependency 'bel', '0.4.1'
spec.add_runtime_dependency 'bel', '0.6.0'

## bel.rb translator dependencies
spec.add_runtime_dependency 'json-ld', '1.99.0'
spec.add_runtime_dependency 'rdf-json', '1.99.0'
spec.add_runtime_dependency 'rdf-rdfa', '1.99.0'
spec.add_runtime_dependency 'rdf-rdfxml', '1.99.0'
spec.add_runtime_dependency 'rdf-trig', '1.99.0.1'
spec.add_runtime_dependency 'rdf-trix', '1.99.0'
spec.add_runtime_dependency 'rdf-turtle', '1.99.0'

## bel.rb plugin - annotation/namespace search
spec.add_runtime_dependency 'bel-search-sqlite', '0.4.2'

## bel.rb plugin - RDF repository using Apache Jena
spec.add_runtime_dependency 'bel-rdf-jena', '0.4.1'
spec.add_runtime_dependency 'bel-rdf-jena', '0.4.2'

## RDF - RDF abstraction
spec.add_runtime_dependency 'rdf', '1.99.0'
spec.add_runtime_dependency 'rdf', '1.99.1'

## Mongo - Faceted search of evidence.
spec.add_runtime_dependency 'mongo', '1.12.5'
Expand All @@ -55,14 +64,13 @@ Gem::Specification.new do |spec|
spec.add_runtime_dependency 'json_schema', '0.10.0'
spec.add_runtime_dependency 'multi_json', '1.11.2'
spec.add_runtime_dependency 'oat', '0.4.6'
spec.add_runtime_dependency 'puma', '2.15.3'
spec.add_runtime_dependency 'puma', '3.1.0'
spec.add_runtime_dependency 'rack', '1.6.4'
spec.add_runtime_dependency 'rack-cors', '0.4.0'
spec.add_runtime_dependency 'rack-handlers', '0.7.0'
spec.add_runtime_dependency 'sinatra', '1.4.6'
spec.add_runtime_dependency 'sinatra-contrib', '1.4.6'
spec.add_runtime_dependency 'jwt', '1.5.2'
spec.add_runtime_dependency 'rest-client', '1.8.0'
end
# vim: ts=2 sw=2:
# encoding: utf-8
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,25 @@ All notable changes to openbel-api will be documented in this file. The curated

This project adheres to [Semantic Versioning][Semantic Versioning].

## [0.6.0][0.6.0] - 2016-02-03
### Added
- Retrieve evidence in a format supported by BEL translator plugins ([Issue 44][44]).
- Retrieve dataset evidence in a format supported by BEL translator plugins ([Issue 99][99]).
### Fixed
- Dataset evidence collection is missing annotation/namespace URIs ([Issue 95][95]).
- Facets are not created for evidence uploaded through a dataset.
### Changed
- MongoDB version 3.2.0 is now required due to use of `$slice` operator in Aggregation queries.

-----

## [0.5.1][0.5.1] - 2015-12-18
### Fixed
- Authentication error for MongoDB user when faceting on `GET /api/evidence` ([Issue #93][93]).

### Changed
- MongoDB version 3.2.0 is now required due to use of `$slice` operator in Aggregation queries ([Issue ?][]).

-----

## [0.5.0][0.5.0] - 2015-12-17
Expand Down Expand Up @@ -44,6 +59,9 @@ This project adheres to [Semantic Versioning][Semantic Versioning].
[0.5.0]: https://github.com/OpenBEL/openbel-api/compare/0.4.0...0.5.0
[Semantic Versioning]: http://semver.org
[MongoDB User Authentication]: https://github.com/OpenBEL/openbel-api/wiki/Configuring-the-Evidence-Store#mongodb-user-authentication
[44]: https://github.com/OpenBEL/openbel-api/issues/44
[91]: https://github.com/OpenBEL/openbel-api/issues/91
[92]: https://github.com/OpenBEL/openbel-api/issues/92
[93]: https://github.com/OpenBEL/openbel-api/issues/93
[95]: https://github.com/OpenBEL/openbel-api/issues/95
[99]: https://github.com/OpenBEL/openbel-api/issues/99
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ The OpenBEL API is built to run with [JRuby][JRuby] and [Java 8][Java 8].
- [JRuby][JRuby], 9.x series (9.0.x.0 is recommended)
- The 9.x series is required due to a Ruby language 2.0 requirement.
- See "Installation" below for configuring JRuby and isolating the openbel-api application.
- [MongoDB][MongoDB], version 3.0 or greater
- [MongoDB][MongoDB], version 3.2 or greater
- Follow [MongoDB download][MongoDB download] page for download and installation instructions.
- [SQLite][SQLite], version 3.8.0 or greater
- Follow [SQLite download][SQLite download] page for download and installation instructions.
Expand Down Expand Up @@ -236,7 +236,7 @@ API documentation with *Try it* functionality is available [here][OpenBEL API do

-----

Built with collaboration and :heart: by the [OpenBEL][OpenBEL] community.
Built with collaboration and a lot of :heart: by the [OpenBEL][OpenBEL] community.

[OpenBEL]: http://www.openbel.org
[OpenBEL Platform]: https://github.com/OpenBEL/openbel-platform
Expand Down
75 changes: 75 additions & 0 deletions UPGRADING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Upgrading openbel-api

This files contains documentation for upgrading to specific versions of OpenBEL API.

## 0.6.0 Upgrade (2016-03-15)

### MongoDB 3.2

This release requires MongoDB >= 3.2. The latest MongoDB release is version [3.2.3](https://www.mongodb.com/mongodb-3.2) as of March 15th, 2016. OpenBEL API will fail to start (with message) if for MongoDB's version is less than 3.2.

Note: MongoDB 3.2 uses the *wiredTiger* storage engine by default. If you previously used the *mmapv1* storage engine for OpenBEL API then do not set *storage.engine* in your MongoDB configuration. MongoDB will determine the *storage.engine* by the data in your *dbPath*. See this [MongoDB article](https://docs.mongodb.org/manual/core/wiredtiger/) for details.

-----

### MongoDB Migration

The 0.6.0 version of OpenBEL API introduces a change to how evidence facets are stored in MongoDB.

#### Change Detail

##### 0.5.1

Collections:

- `evidence`
- Stores evidence.facets as strings.
- `evidence_facets`
- Stores evidence facet objects for all searches.

##### 0.6.0

Collections:

- `evidence`
- Stores evidence.facets as JSON objects for use in Mongo aggregation operations.
- `evidence_facet_cache`
- Stores the facet collection name for each unique evidence search.
- `evidence_facet_cache_{UUID}`
- Stores evidence facet objects for a specific evidence search.

#### Migration Procedure

Migrations are JRuby scripts that can be run directly as scripts (i.e. includes `#!/usr/bin/env jruby` shebang). You will need the OpenBEL API repository on GitHub as well as your OpenBEL API configuration file.

It is recommended to stop OpenBEL API and MongoDB before migrating.

1. Stop OpenBEL API.
2. Stop MongoDB daemon.
3. Clone OpenBEL API repository.
- `git clone https://github.com/OpenBEL/openbel-api.git`
4. Change directory to the 0.6.0 migrations directory.
- `cd openbel-api/tools/migrations/0.6.0`
5. Run *migrate_evidence_facets.rb* to update evidence.facets to JSON objects.
- `./migrate_evidence_facets.rb YOUR_CONFIG.yml` or `jruby migrate_evidence_facets.rb YOUR_CONFIG.yml`
6. Run *drop_unused_collection.rb* to remove the old *evidence_facets* collection.
- `./drop_unused_collection.rb YOUR_CONFIG.yml` or `jruby drop_unused_collection.rb YOUR_CONFIG.yml`
7. Start MongoDB daemon.
8. Start OpenBEL API.

-----

### Conflicting gem versions.

The *bel*, *puma*, and *rdf* gem dependencies have been upgraded. This may cause conflicting gem versions to exist in the same *GEM_HOME* location.

If you wish to install into an existing *GEM_HOME* (versus an isolated *GEM_HOME*) then please uninstall these gems:

- `gem uninstall bel puma rdf`
- Say yes to remove existing command scripts as well.

-----

### Installation

Install OpenBEL API 0.6.0 with `gem install openbel-api --version 0.6.0`.
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.5.1
0.6.0
12 changes: 12 additions & 0 deletions app/openbel/api/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,18 @@ def self.validate_evidence_store(evidence_store)
]
end

# Check Mongo server version >= 3.2.
# The aggregation framework's $slice operator is used which requires 3.2.
if mongo_client.server_version.to_s !~ /^3.2/
return [
true, <<-ERR
MongoDB version 3.2 or greater is required.
MongoDB version: #{mongo_client.server_version}
ERR
]
end

# Attempt access of database.
db = mongo_client.db(mongo[:database])

Expand Down
17 changes: 17 additions & 0 deletions app/openbel/api/helpers/base.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module OpenBEL
module Helpers

DEFAULT_CONTENT_TYPE = 'application/hal+json'
DEFAULT_CONTENT_TYPE_ID = :hal

def wants_default?
if params[:format]
return params[:format] == DEFAULT_CONTENT_TYPE
end

request.accept.any? { |accept_entry|
accept_entry.to_s == DEFAULT_CONTENT_TYPE
}
end
end
end
74 changes: 74 additions & 0 deletions app/openbel/api/helpers/evidence.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
require 'bel/util'
require_relative 'base'
require_relative 'translators'

module OpenBEL
module Helpers

def render_evidence_collection(
name, page_results, start, size, filters,
filtered_total, collection_total, evidence_api
)
# see if the user requested a BEL translator (Accept header or ?format)
translator = Translators.requested_translator(request, params)
translator_plugin = Translators.requested_translator_plugin(request, params)

halt 404 unless page_results[:cursor].has_next?

# Serialize to HAL if they [Accept]ed it, specified it as ?format, or
# no translator was found to match request.
if wants_default? || !translator
facets = page_results[:facets]
pager = Pager.new(start, size, filtered_total)
evidence = page_results[:cursor].map { |item|
item.delete('facets')
item
}.to_a

options = {
:facets => facets,
:start => start,
:size => size,
:filters => filters,
:metadata => {
:collection_paging => {
:total => collection_total,
:total_filtered => pager.total_size,
:total_pages => pager.total_pages,
:current_page => pager.current_page,
:current_page_size => evidence.size,
}
}
}

# pager links
options[:previous_page] = pager.previous_page
options[:next_page] = pager.next_page

render_collection(evidence, :evidence, options)
else
extension = translator_plugin.file_extensions.first

response.headers['Content-Type'] = translator_plugin.media_types.first
status 200
attachment "#{name}.#{extension}"
stream :keep_open do |response|
cursor = page_results[:cursor]
dataset_evidence = cursor.lazy.map { |evidence|
evidence.delete('facets')
evidence.delete('_id')
evidence = BEL::Model::Evidence.create(BEL.keys_to_symbols(evidence))
evidence.bel_statement = BEL::Model::Evidence.parse_statement(evidence)
evidence
}

translator.write(
dataset_evidence, response,
:annotation_reference_map => evidence_api.find_all_annotation_references,
:namespace_reference_map => evidence_api.find_all_namespace_references
)
end
end
end
end
end
94 changes: 94 additions & 0 deletions app/openbel/api/helpers/filters.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
module OpenBEL
module Helpers

# Parse filter query parameters and partition into an {Array}. The first
# index will contain the valid filters and the second index will contain
# the invalid filters.
#
# @param [Array<String>] filter_query_params an array of filter strings
# encoded in JSON
# @return [Array<Array<Hash>, Array<String>] the first index holds the
# valid, filter {Hash hashes}; the second index holds the invalid,
# filter {String strings}
def parse_filters(filter_query_params)
filter_query_params.map { |filter_string|
begin
MultiJson.load filter_string
rescue MultiJson::ParseError => ex
"#{ex} (filter: #{filter_string})"
end
}.partition { |filter|
filter.is_a?(Hash)
}
end

# Retrieve the filters that do not provide category, name, and value keys.
#
# The parsed, incomplete filters will contain an +:error+ key that provides
# an error message intended for the user.
#
# @param [Array<Hash>] filters an array of filter {Hash hashes}
# @return [Array<Hash>] an array of incomplete filter {Hash hashes} that
# contain a human-readable error at the +:error+ key
def incomplete_filters(filters)
filters.select { |filter|
['category', 'name', 'value'].any? { |f| !filter.include? f }
}.map { |incomplete_filter|
category, name, value = incomplete_filter.values_at('category', 'name', 'value')
error = <<-MSG.gsub(/^\s+/, '').strip
Incomplete filter, category:"#{category}", name:"#{name}", and value:"#{value}".
MSG
incomplete_filter.merge(:error => error)
}
end

# Retrieve the filters that represent invalid full-text search values.
#
# The parsed, invalid full-text search filters will contain an +:error+ key
# that provides an error message intended for the user.
#
# @param [Array<Hash>] filters an array of filter {Hash hashes}
# @return [Array<Hash>] an array of invalid full-text search filter
# {Hash hashes} that contain a human-readable error at the
# +:error+ key
def invalid_fts_filters(filters)
filters.select { |filter|
category, name, value = filter.values_at('category', 'name', 'value')
category == 'fts' && name == 'search' && value.to_s.length <= 1
}.map { |invalid_fts_filter|
error = <<-MSG.gsub(/^\s+/, '').strip
Full-text search filter values must be larger than one.
MSG
invalid_fts_filter.merge(:error => error)
}
end

# Validate the requested filter query strings. If all filters are valid
# then return them as {Hash hashes}, otherwise halt 400 Bad Request and
# return JSON error response.
def validate_filters!
filter_query_params = CGI::parse(env["QUERY_STRING"])['filter']
valid_filters, invalid_filters = parse_filters(filter_query_params)

invalid_filters |= incomplete_filters(valid_filters)
invalid_filters |= invalid_fts_filters(valid_filters)

return valid_filters if invalid_filters.empty?

halt(400, { 'Content-Type' => 'application/json' }, render_json({
:status => 400,
:msg => "Bad Request",
:detail =>
invalid_filters.
map { |invalid_filter|
if invalid_filter.is_a?(Hash) && invalid_filter[:error]
invalid_filter[:error]
else
invalid_filter
end
}.
map(&:to_s)
}))
end
end
end
Loading

0 comments on commit 55c531e

Please sign in to comment.