Commit aabf8403 authored by Francis's avatar Francis
Browse files

Added suport for search endpoints

parent fc4c2c7b
Pipeline #154087350 passed with stage
in 5 minutes and 27 seconds
Please view this file on the master branch, otherwise it may be outdated
**Version 0.4.0**
Added support to searchable endpoints
https://develop.battle.net/documentation/world-of-warcraft/guides/search
**Version 0.3.11**
Fixed D3 item URL.
......
PATH
remote: .
specs:
blizzard_api (0.3.9)
blizzard_api (0.4.0)
redis (~> 4.1, >= 4.1.0)
GEM
remote: https://rubygems.org/
specs:
ast (2.4.0)
dotenv (2.7.5)
jaro_winkler (1.5.3)
minitest (5.11.3)
parallel (1.17.0)
......@@ -15,7 +16,7 @@ GEM
ast (~> 2.4.0)
rainbow (3.0.0)
rake (13.0.1)
redis (4.1.3)
redis (4.1.4)
rubocop (0.74.0)
jaro_winkler (~> 1.5.1)
parallel (~> 1.10)
......@@ -25,15 +26,18 @@ GEM
unicode-display_width (>= 1.4.0, < 1.7)
ruby-progressbar (1.10.1)
unicode-display_width (1.6.0)
yard (0.9.25)
PLATFORMS
ruby
DEPENDENCIES
blizzard_api!
dotenv
minitest (~> 5.0)
rake (~> 13.0)
rubocop (~> 0.61)
yard
BUNDLED WITH
2.1.2
2.1.4
......@@ -73,6 +73,46 @@ Most **data** endpoints will have always 3 methods available `index`, `get` and
* `get` is used to get all information about a entry of the index returned data. It receives an id or slug as the first parameter, that depends on the endpoint.
* `complete` is a complete information of all items listed in index. **This may perform various calls to the blizzard api** only use if you really need all information.
### 3.1 Searchable endpoints
Some endpoints support search filters. To perform a search you can use the following formats:
To use the **or** operator you may pass an array of values as argument to `where` or `where_not` methods.
```ruby
realm = BlizzardApi::Wow.realm
realm_data = realm.search(1, 100) do |options|
options.where 'name.en_US', %w[Azralon Nemesis]
end
```
To use the **and** operator you may call `where` or `where_not` multiple times methods.
```ruby
realm = BlizzardApi::Wow.realm
realm_data = realm.search(1, 100) do |options|
options.where 'name.en_US', 'Azralon'
options.where 'id', 3209
end
```
To use the **range** operator you may pass a hash to `where` or `where_not`.
```ruby
realm = BlizzardApi::Wow.realm
realm_data = realm.search(1, 100) do |options|
options.where 'id', min: 3209, max: 4000, mode: :exclusive
end
```
*Note*: If you don't pass the `mode` key as `:exclusive` it will be `:inclusive` by default.
To **sort** fields you may call the `order_by` method multiple times:
```ruby
realm = BlizzardApi::Wow.realm
realm_data = realm.search(1, 100) do |options|
options.where 'id', min: 3209, max: 4000, mode: :exclusive
options.order_by 'id', :desc
end
```
## 4. Available endpoints
**Hint**: All methods support an additional optional hash parameter that allows you to override the following configurations for a single call:
......
......@@ -34,7 +34,9 @@ Gem::Specification.new do |spec|
spec.add_runtime_dependency 'redis', '~> 4.1', '>= 4.1.0'
spec.add_development_dependency 'dotenv'
spec.add_development_dependency 'minitest', '~> 5.0'
spec.add_development_dependency 'rake', '~> 13.0'
spec.add_development_dependency 'rubocop', '~> 0.61'
spec.add_development_dependency 'yard'
end
......@@ -13,7 +13,7 @@ module BlizzardApi
##
# Return information about an item
#
# @param item_slug [String] Item slug
# @param item_slug_and_id [String] Item slug
# @!macro request_options
#
# @!macro response
......
......@@ -50,7 +50,8 @@ module BlizzardApi
community: 'https://%s.api.blizzard.com/%s',
profile: 'https://%s.api.blizzard.com/profile/%s',
media: 'https://%s.api.blizzard.com/data/%s/media',
user_profile: 'https://%s.api.blizzard.com/profile/user/%s'
user_profile: 'https://%s.api.blizzard.com/profile/user/%s',
search: 'https://%s.api.blizzard.com/data/%s/search'
}.freeze
##
......
......@@ -2,5 +2,5 @@
module BlizzardApi
# Gem version
VERSION = '0.3.11'
VERSION = '0.4.0'
end
......@@ -5,6 +5,8 @@ module BlizzardApi
module Wow
require_relative 'wow/request'
require_relative 'wow/game_data/generic_data_endpoint'
require_relative 'wow/search/search_composer'
require_relative 'wow/search/search_request'
# WoW data api
require_relative 'wow/game_data/achievement'
......
......@@ -10,6 +10,8 @@ module BlizzardApi
# You can get an instance of this class using the default region as follows:
# api_instance = BlizzardApi::Wow.connected_realm
class ConnectedRealm < Wow::GenericDataEndpoint
include BlizzardApi::Wow::Searchable
protected
def endpoint_setup
......
......@@ -48,9 +48,9 @@ module BlizzardApi
protected
def endpoint_uri(variant = nil)
def endpoint_uri(variant = nil, scope = :game_data)
endpoint = variant ? "#{@endpoint}-#{variant}" : @endpoint
"#{base_url(:game_data)}/#{endpoint}"
"#{base_url(scope)}/#{endpoint}"
end
def endpoint_setup
......
......@@ -10,6 +10,8 @@ module BlizzardApi
# You can get an instance of this class using the default region as follows:
# api_instance = BlizzardApi::Wow.realm
class Realm < Wow::GenericDataEndpoint
include BlizzardApi::Wow::Searchable
protected
def endpoint_setup
......
# frozen_string_literal: true
module BlizzardApi
module Wow
##
# Composer for search endpoint arguments
class SearchComposer
attr_accessor :fields, :order, :page, :page_size
def initialize(page, page_size)
self.page = page
self.page_size = page_size
self.fields = []
self.order = []
end
##
# Add a search field
#
# The second argument takes a simple value, an array of values or a hash for range searches.
#
# @param field [String] Field name
# @param value [String|Integer|Hash|Array<Integer|String>]
# @option value [Integer] :min Range start
# @option value [Integer] :max Range end
# @option value [Integer] :mode Range mode (:inclusive|:exclusive)
#
# @return {SearchComposer}
def where(field, value)
fields.push "#{field}=#{resolve_value(value)}"
self
end
##
# Add a search field
#
# The second argument takes a simple value, an array of values or a hash for range searches.
#
# @param field [String] Field name
# @param value [String|Integer|Hash|Array<Integer|String>]
# @option value [Integer] :min Range start
# @option value [Integer] :max Range end
# @option value [Integer] :mode Range mode (:inclusive|:exclusive)
#
# @return {SearchComposer}
def where_not(field, value)
fields.push "#{field}!=#{resolve_value(value)}"
self
end
##
# Add a sort field
#
# @param field [String] Field name
# @param mode [Symbol] :asc or :desc
#
# @return {SearchComposer}
def order_by(field, mode = :asc)
raise ArgumentError, 'Invalid order mode.' unless %i[asc desc].include? mode
order.push "#{field}:#{mode}"
self
end
##
# Returns a valid queryString based on the options
#
# @return {String}
def to_search_query
query_string = "_page=#{page}&_pageSize=#{page_size}"
query_string += '&' + fields.join('&') unless fields.size.zero?
query_string += "&orderby=#{order.join(',')}" unless order.size.zero?
query_string
end
protected
def resolve_value(value)
return value.join '||' if value.is_a? Array
return value.to_s unless value.is_a? Hash
resolve_hash value
end
def resolve_hash(value)
min = value.key?(:min) ? value[:min] : ''
max = value.key?(:max) ? value[:max] : ''
mode = value.key?(:mode) ? value[:mode] : :inclusive
return "[#{min},#{max}]" if mode.eql? :inclusive
"(#{min},#{max})"
end
end
end
end
# frozen_string_literal: true
module BlizzardApi
module Wow
##
# Added search support to an endpoint
module Searchable
##
# Fetch data base on search criteria
#
# @param page [Integer] Page o return
# @param page_size [Integer] Amount of items per page
#
# @!macro request_options
# @!macro response
def search(page = 1, page_size = 100, options = {})
search_options = SearchComposer.new(page, page_size)
yield search_options if block_given?
api_request "#{endpoint_uri(nil, :search)}?#{search_options.to_search_query}", default_options.merge(options)
end
end
end
end
......@@ -24,6 +24,32 @@ module BlizzardApi
realm_data = @connected_realm.complete
assert_equal 'kilrogg', realm_data[0][:realms][0][:slug]
end
def test_connected_realm_pagination
realm_data = @connected_realm.search(1, 10)
assert_equal 10, realm_data[:results].size
end
def test_connected_realm_search
realm_data = @connected_realm.search(1, 10) do |options|
options.where 'id', 60
end
assert_equal 60, realm_data[:results][0][:data][:id]
end
def test_connected_realm_search_or
realm_data = @connected_realm.search(1, 10) do |options|
options.where 'id', [60, 67]
end
assert_equal 2, realm_data[:results].size
end
def test_connected_realm_range_search
realm_data = @connected_realm.search(1, 100) do |options|
options.where 'id', min: 60, max: 100
end
assert_equal 26, realm_data[:results].size
end
end
end
end
......@@ -5,23 +5,31 @@ require 'test_helper'
module BlizzardApi
module Wow
class RealmTest < Minitest::Test
def setup
@realm = BlizzardApi::Wow.realm
end
def test_realm_index
realm = BlizzardApi::Wow.realm
realm_data = realm.index
realm_data = @realm.index
assert realm_data[:realms]
end
def test_realm_get
realm = BlizzardApi::Wow::Realm.new
realm_data = realm.get 'azralon'
realm_data = @realm.get 'azralon'
assert_equal 'azralon', realm_data[:slug]
end
def test_realm_complete
realm = BlizzardApi::Wow::Realm.new
realm_data = realm.complete
realm_data = @realm.complete
assert_equal 'lightbringer', realm_data[0][:slug]
end
def test_realm_search
realm_data = @realm.search do |options|
options.where 'name.en_US', %w[Azralon Nemesis]
end
assert_equal 2, realm_data[:results].size
end
end
end
end
......@@ -4,8 +4,11 @@ $LOAD_PATH.unshift File.expand_path('../lib', __dir__)
require 'minitest/autorun'
require 'blizzard_api'
require 'dotenv'
Dotenv.load
BlizzardApi.configure do |config|
puts ENV['BNET_APPLICATION_ID']
config.app_id = ENV['BNET_APPLICATION_ID']
config.app_secret = ENV['BNET_APPLICATION_SECRET']
config.region = 'us'
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment