azure_search 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/azure_search.rb +7 -0
- data/lib/azure_search/errors.rb +26 -0
- data/lib/azure_search/index_batch_operation.rb +59 -0
- data/lib/azure_search/index_field.rb +104 -0
- data/lib/azure_search/index_search_options.rb +177 -0
- data/lib/azure_search/search_index_client.rb +169 -0
- data/lib/azure_search/utils.rb +41 -0
- data/lib/azure_search/version.rb +3 -0
- metadata +123 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: bc148b6807b2928ac0842c5f0839cad1375fa433
|
4
|
+
data.tar.gz: b696a4ceb1c8a277e5bd9639b8fc326ffbfd32cf
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7f8441c96cae85be15a736906bb1a31c489e201fb20318bdb09107369494ef9bf55d9f23fc657ee97e083b79f5cd921cf5a049fa92c5dbdb4656d2d8b8623a52
|
7
|
+
data.tar.gz: 03f9bfa8c10d7c189620dc21928c995613426f89f6d126d757e27d94c61b7efdeb77b4502e4e13d58786b6be94ca9b5361414bc4d452a0ffbe6535eb845a8942
|
data/lib/azure_search.rb
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
require 'azure_search/utils'
|
2
|
+
require 'azure_search/errors'
|
3
|
+
require 'azure_search/version'
|
4
|
+
require 'azure_search/index_field'
|
5
|
+
require 'azure_search/search_index_client'
|
6
|
+
require 'azure_search/index_search_options'
|
7
|
+
require 'azure_search/index_batch_operation'
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module AzureSearch
|
2
|
+
|
3
|
+
# Defines errors that are raised by AzureSearch client.
|
4
|
+
#
|
5
|
+
# @since 0.1.0
|
6
|
+
module Errors
|
7
|
+
|
8
|
+
# Raised to indicate that a HTTP request needs to be retried.
|
9
|
+
class RetriableHttpError < StandardError
|
10
|
+
# @return [Symbol] The response status code.
|
11
|
+
attr_accessor :code
|
12
|
+
# @return [Symbol] The error message.
|
13
|
+
attr_accessor :message
|
14
|
+
|
15
|
+
def initialize(code, message)
|
16
|
+
self.code = code
|
17
|
+
self.message = message
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
"RetriableHttpError <#{self.code}>: #{self.message}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module AzureSearch
|
4
|
+
|
5
|
+
# Represents a batch operation in an indexing request.
|
6
|
+
class IndexBatchOperation
|
7
|
+
# Encapsulates the supplied document in an IndexUploadOperation.
|
8
|
+
#
|
9
|
+
# @param [Hash] document The document.
|
10
|
+
# @return [Hash] The upload operation as a Hash.
|
11
|
+
def self.upload(document)
|
12
|
+
IndexUploadOperation.new(document).to_hash
|
13
|
+
end
|
14
|
+
|
15
|
+
# Encapsulates a delete request in an IndexDeleteOperation.
|
16
|
+
#
|
17
|
+
# @param [String] key_name The key name.
|
18
|
+
# @param [String] key_value The key value.
|
19
|
+
def self.delete(key_name, key_value)
|
20
|
+
IndexDeleteOperation.new(key_name, key_value).to_hash
|
21
|
+
end
|
22
|
+
|
23
|
+
# @todo Add support for merge & merge_or_upload
|
24
|
+
end
|
25
|
+
|
26
|
+
# Represents an upload operation of a document.
|
27
|
+
class IndexUploadOperation < IndexBatchOperation
|
28
|
+
def initialize(document)
|
29
|
+
@document = document
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns the upload operation as a Hash.
|
33
|
+
#
|
34
|
+
# @return [Hash] The upload operation.
|
35
|
+
def to_hash
|
36
|
+
@document["@search.action"] = "upload"
|
37
|
+
@document
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Represents a document deletion request.
|
42
|
+
class IndexDeleteOperation < IndexBatchOperation
|
43
|
+
def initialize(key_name, key_value)
|
44
|
+
@key_name = key_name
|
45
|
+
@key_value = key_value
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns the delete operation as a Hash.
|
49
|
+
#
|
50
|
+
# @return [Hash] The delete operation.
|
51
|
+
def to_hash
|
52
|
+
{
|
53
|
+
@key_name => @key_value,
|
54
|
+
"@search_action" => "delete"
|
55
|
+
}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module AzureSearch
|
2
|
+
|
3
|
+
# Represents an Index field definition.
|
4
|
+
class IndexField
|
5
|
+
# Valid EDM (Entity Data Model) data types.
|
6
|
+
VALID_EDM_TYPES = [
|
7
|
+
"Edm.String",
|
8
|
+
"Collection(Edm.String)",
|
9
|
+
"Edm.Boolean",
|
10
|
+
"Edm.Int32",
|
11
|
+
"Edm.Int64",
|
12
|
+
"Edm.Double",
|
13
|
+
"Edm.DateTimeOffset",
|
14
|
+
"Edm.GeographyPoint"
|
15
|
+
].freeze
|
16
|
+
|
17
|
+
def initialize(name, type)
|
18
|
+
raise "Field name is required." unless !name.empty?
|
19
|
+
@name = name
|
20
|
+
raise "Invalid field type." unless VALID_EDM_TYPES.include? type
|
21
|
+
@type = type
|
22
|
+
end
|
23
|
+
|
24
|
+
# Sets the analyzer name used for search and indexing.
|
25
|
+
#
|
26
|
+
# @param [String] analyzer The analyzer name.
|
27
|
+
# @return [self] The current instance.
|
28
|
+
def analyzer(analyzer)
|
29
|
+
@analyzer = analyzer
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
# Sets the field to be searchable.
|
34
|
+
#
|
35
|
+
# @param [TrueClass,FalseClass] searchable true or false.
|
36
|
+
# @return [self] The current instance.
|
37
|
+
def searchable(searchable)
|
38
|
+
raise "searchable must be a boolean." unless is_bool? searchable
|
39
|
+
@searchable = searchable
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
# Sets the field to be filterable.
|
44
|
+
#
|
45
|
+
# @param [TrueClass,FalseClass] filterable true or false.
|
46
|
+
# @return [self] The current instance.
|
47
|
+
def filterable(filterable)
|
48
|
+
raise "filterable must be a boolean." unless is_bool? filterable
|
49
|
+
@filterable = filterable
|
50
|
+
self
|
51
|
+
end
|
52
|
+
|
53
|
+
# Sets the field to be retrievable.
|
54
|
+
#
|
55
|
+
# @param [TrueClass,FalseClass] retrievable true or false.
|
56
|
+
# @return [self] The current instance.
|
57
|
+
def retrievable(retrievable)
|
58
|
+
raise "retrievable must be a boolean." unless is_bool? retrievable
|
59
|
+
@retrievable = retrievable
|
60
|
+
self
|
61
|
+
end
|
62
|
+
|
63
|
+
# Sets the field to be sortable.
|
64
|
+
#
|
65
|
+
# @param [TrueClass,FalseClass] sortable true or false.
|
66
|
+
# @return [self] The current instance.
|
67
|
+
def sortable(sortable)
|
68
|
+
raise "sortable must be a boolean." unless is_bool? sortable
|
69
|
+
@sortable = sortable
|
70
|
+
self
|
71
|
+
end
|
72
|
+
|
73
|
+
# Sets the field to be facetable.
|
74
|
+
#
|
75
|
+
# @param [TrueClass,FalseClass] facetable true or false.
|
76
|
+
# @return [self] The current instance.
|
77
|
+
def facetable(facetable)
|
78
|
+
raise "facetable must be a boolean." unless is_bool? facetable
|
79
|
+
@facetable = facetable
|
80
|
+
self
|
81
|
+
end
|
82
|
+
|
83
|
+
# Sets the field to be the key (Only Edm.String fields can be keys).
|
84
|
+
#
|
85
|
+
# @param [TrueClass,FalseClass] key true or false.
|
86
|
+
# @return [self] The current instance.
|
87
|
+
def key(key)
|
88
|
+
raise "key must be a boolean." unless is_bool? key
|
89
|
+
raise "Only Edm.String fields can be keys." unless @type == "Edm.String"
|
90
|
+
@key = key
|
91
|
+
self
|
92
|
+
end
|
93
|
+
|
94
|
+
# Converts this IndexField to a Hash.
|
95
|
+
#
|
96
|
+
# @return [Hash] Hash representation of IndexField.
|
97
|
+
def to_hash
|
98
|
+
hash = {}
|
99
|
+
instance_variables.each {|var| hash[var.to_s.delete("@")] = instance_variable_get(var) }
|
100
|
+
hash
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
require 'azure_search/utils'
|
2
|
+
|
3
|
+
module AzureSearch
|
4
|
+
|
5
|
+
# Represents search options that will be sent along with a search request.
|
6
|
+
class IndexSearchOptions
|
7
|
+
SPECIAL_PARAMS = %w(count filter orderby select top skip).freeze
|
8
|
+
|
9
|
+
# Specifies whether to fetch the total count of results.
|
10
|
+
#
|
11
|
+
# @param [TrueClass,FalseClass] val true or false.
|
12
|
+
# @return [self] the current instance.
|
13
|
+
def include_count(val)
|
14
|
+
raise "include_count requires a boolean value." unless is_bool?(val)
|
15
|
+
@count = val
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
# Sets the structured search expression in standard OData syntax.
|
20
|
+
#
|
21
|
+
# @param [String] val The filter expression.
|
22
|
+
# @return [self] The current instance.
|
23
|
+
def filter(val)
|
24
|
+
raise "filter requires a String." unless val.is_a? String
|
25
|
+
@filter = val
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
# Sets the list of comma-separated expressions to sort the results by.
|
30
|
+
#
|
31
|
+
# @param [String] val Comma-separated expressions.
|
32
|
+
# @return [self] The current instance.
|
33
|
+
def order_by(val)
|
34
|
+
raise "order_by requires a String." unless val.is_a? String
|
35
|
+
@orderby = val
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
# Sets the list of comma-separated fields to retrieve.
|
40
|
+
#
|
41
|
+
# @param [String] val Comma-separated fields.
|
42
|
+
# @return [self] The current instance.
|
43
|
+
def select(val)
|
44
|
+
raise "select requires a String." unless val.is_a? String
|
45
|
+
@select = val
|
46
|
+
self
|
47
|
+
end
|
48
|
+
|
49
|
+
# Sets the list of comma-separated field names to search for the specified text.
|
50
|
+
#
|
51
|
+
# @param [String] val Comma-separated field names.
|
52
|
+
# @return [self] The current instance.
|
53
|
+
def search_fields(val)
|
54
|
+
raise "search_fields requires a String." unless val.is_a? String
|
55
|
+
@searchFields = val
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
59
|
+
# Sets the list of fields to facet by.
|
60
|
+
#
|
61
|
+
# @param [Array] fs The list of fields.
|
62
|
+
# @return [self] The current instance.
|
63
|
+
def facets(fs)
|
64
|
+
raise "facts requires an Array of Strings." unless fs.is_a? Array
|
65
|
+
@facet = fs
|
66
|
+
self
|
67
|
+
end
|
68
|
+
|
69
|
+
# Sets the set of comma-separated field names used for hit highlights.
|
70
|
+
#
|
71
|
+
# @param [String] hl Comma-separated field names.
|
72
|
+
# @return [self] The current instance.
|
73
|
+
def highlight(hl)
|
74
|
+
raise "highlight requires a String." unless hl.is_a? String
|
75
|
+
@highlight = hl
|
76
|
+
self
|
77
|
+
end
|
78
|
+
|
79
|
+
# Sets the string tag that appends to hit highlights (defaults to <em>).
|
80
|
+
#
|
81
|
+
# @param [String] hpt The string tag.
|
82
|
+
# @return [self] The current instance.
|
83
|
+
def highlight_pre_tag(hpt)
|
84
|
+
raise "highlight_pre_tag requires an HTML string." unless has_html?(hpt)
|
85
|
+
@highlightPreTag = hpt
|
86
|
+
self
|
87
|
+
end
|
88
|
+
|
89
|
+
# Sets the string tag that appends to hit highlights (defaults to </em>).
|
90
|
+
#
|
91
|
+
# @param [String] hpt The string tag.
|
92
|
+
# @return [self] The current instance.
|
93
|
+
def highlight_post_tag(hpt)
|
94
|
+
raise "highlight_post_tag requires an HTML string." unless has_html?(hpt)
|
95
|
+
@highlightPostTag = hpt
|
96
|
+
self
|
97
|
+
end
|
98
|
+
|
99
|
+
# Sets the name of a scoring profile to evaluate match scores for matching documents.
|
100
|
+
#
|
101
|
+
# @param [String] sp The scoring profile name.
|
102
|
+
# @return [self] The current instance.
|
103
|
+
def scoring_profile(sp)
|
104
|
+
raise "scoring_profile requires a String." unless sp.is_a? String
|
105
|
+
@scoringProfile = sp
|
106
|
+
self
|
107
|
+
end
|
108
|
+
|
109
|
+
# Sets the values for each parameter defined in a scoring function.
|
110
|
+
#
|
111
|
+
# @param [Array] params The parameters values.
|
112
|
+
# @return [self] The current instance.
|
113
|
+
def scoring_parameters(params)
|
114
|
+
raise "scoring_parameters requires an Array of Strings." unless params.is_a? Array
|
115
|
+
@scoringParameter = params
|
116
|
+
self
|
117
|
+
end
|
118
|
+
|
119
|
+
# Sets the number of search results to retrieve (defaults to 50).
|
120
|
+
#
|
121
|
+
# @param [Integer] val The number of search results.
|
122
|
+
# @return [self] The current instance.
|
123
|
+
def top(val)
|
124
|
+
raise "top requires an Integer." unless val.is_a? Integer
|
125
|
+
@top = val
|
126
|
+
self
|
127
|
+
end
|
128
|
+
|
129
|
+
# Sets the number of search results to skip.
|
130
|
+
#
|
131
|
+
# @param [Integer] val The number to skip (cannot be greater than 100,000).
|
132
|
+
# @return [self] The current instance.
|
133
|
+
def skip(val)
|
134
|
+
raise "skip requires an Integer." unless val.is_a? Integer
|
135
|
+
@skip = val
|
136
|
+
self
|
137
|
+
end
|
138
|
+
|
139
|
+
# Specifies whether any or all of the search terms must be matched.
|
140
|
+
#
|
141
|
+
# @param [String] mode The search mode.
|
142
|
+
# @return [self] The current instance.
|
143
|
+
def search_mode(mode)
|
144
|
+
raise "invalid search mode." unless ["any", "all"].include? mode
|
145
|
+
@searchMode = mode
|
146
|
+
self
|
147
|
+
end
|
148
|
+
|
149
|
+
# Sets the percentage of the index that must be covered by a search query.
|
150
|
+
#
|
151
|
+
# @param [Float] val The percentage (must be between 0 and 100).
|
152
|
+
# @return [self] The current instance.
|
153
|
+
def minimum_coverage(val)
|
154
|
+
raise "minimum_coverage requires a Float." unless val.is_a? Float
|
155
|
+
raise "minimum_coverage must be between 0 and 100" unless val.between?(0, 100)
|
156
|
+
@minimumCoverage = val
|
157
|
+
self
|
158
|
+
end
|
159
|
+
|
160
|
+
# Returns the search options as a Hash.
|
161
|
+
#
|
162
|
+
# @return [Hash] The search options as a Hash.
|
163
|
+
def to_hash
|
164
|
+
hash = {}
|
165
|
+
instance_variables.each {|var|
|
166
|
+
varname = var.to_s.delete("@")
|
167
|
+
if SPECIAL_PARAMS.include? varname
|
168
|
+
hash["$"+varname] = instance_variable_get(var)
|
169
|
+
else
|
170
|
+
hash[varname] = instance_variable_get(var)
|
171
|
+
end
|
172
|
+
}
|
173
|
+
hash
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
require 'azure_search/index_search_options'
|
2
|
+
require 'azure_search/errors'
|
3
|
+
require 'azure_search/utils'
|
4
|
+
require 'http'
|
5
|
+
|
6
|
+
# Core module common across the entire API.
|
7
|
+
#
|
8
|
+
# @author Faissal Elamraoui
|
9
|
+
# @since 0.1.0
|
10
|
+
module AzureSearch
|
11
|
+
API_VERSION = "2016-09-01".freeze
|
12
|
+
|
13
|
+
# Client to perform requests to an Azure Search service.
|
14
|
+
class SearchIndexClient
|
15
|
+
include AzureSearch::Errors
|
16
|
+
|
17
|
+
# @return [Symbol] The search service name.
|
18
|
+
attr_accessor :service_name
|
19
|
+
# @return [Symbol] The index name.
|
20
|
+
attr_accessor :index_name
|
21
|
+
# @return [Symbol] The API key generated for the provisioned Search service.
|
22
|
+
attr_accessor :api_key
|
23
|
+
|
24
|
+
def initialize(service_name, index_name, api_key)
|
25
|
+
if service_name.empty? || index_name.empty? || api_key.empty?
|
26
|
+
raise StandardError, "Must provide service_name, index_name and api_key when creating client."
|
27
|
+
end
|
28
|
+
|
29
|
+
self.service_name = service_name
|
30
|
+
self.index_name = index_name
|
31
|
+
self.api_key = api_key
|
32
|
+
end
|
33
|
+
|
34
|
+
# Checks if the specified index exists.
|
35
|
+
#
|
36
|
+
# @return [TrueClass,FalseClass] true if the index exists, false otherwise.
|
37
|
+
def exists
|
38
|
+
resp = create_request().get(build_index_definition_url())
|
39
|
+
if resp.code == 404
|
40
|
+
return false
|
41
|
+
end
|
42
|
+
raise_on_http_error(resp)
|
43
|
+
return true
|
44
|
+
end
|
45
|
+
|
46
|
+
# Creates the index based on the provided index definition.
|
47
|
+
#
|
48
|
+
# @param [Hash] definition The index definition.
|
49
|
+
# @option definition [String] :name The index name.
|
50
|
+
# @option definition [Array<IndexField>] :fields Array of fields.
|
51
|
+
# @option definition [Array] :suggesters Array of suggesters.
|
52
|
+
def create(definition)
|
53
|
+
raise "Index definition must be a Hash." unless definition.is_a? Hash
|
54
|
+
definition[:name] = self.index_name unless !definition[:name]
|
55
|
+
resp = create_request().post(build_index_list_url(), :json => definition)
|
56
|
+
raise_on_http_error(resp)
|
57
|
+
return JSON.parse(resp.to_s)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Creates or updates the index based on the provided index definition.
|
61
|
+
#
|
62
|
+
# @param [Hash] definition The index definition.
|
63
|
+
# @option definition [String] :name The index name.
|
64
|
+
# @option definition [Array<IndexField>] :fields Array of fields.
|
65
|
+
# @option definition [Array] :suggesters Array of suggesters.
|
66
|
+
def create_or_update(definition)
|
67
|
+
raise "Index definition must be a Hash." unless definition.is_a? Hash
|
68
|
+
definition[:name] = self.index_name unless definition[:name]
|
69
|
+
resp = create_request().put(build_index_definition_url(), :json => definition)
|
70
|
+
raise_on_http_error(resp)
|
71
|
+
return resp.to_s.empty? ? nil : JSON.parse(resp.to_s)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Deletes the specified index.
|
75
|
+
#
|
76
|
+
# @return [TrueClass,FalseClass] true if the index is deleted, false otherwise.
|
77
|
+
def delete
|
78
|
+
resp = create_request().delete(build_index_definition_url())
|
79
|
+
if resp.code == 404
|
80
|
+
return false
|
81
|
+
end
|
82
|
+
raise_on_http_error(resp)
|
83
|
+
return true
|
84
|
+
end
|
85
|
+
|
86
|
+
# Inserts documents in batch.
|
87
|
+
#
|
88
|
+
# @param [Array<IndexBatchOperation>] operations Array of upload operations.
|
89
|
+
# @param [Integer] chunk_size The batch size. Must not exceed 1000 documents.
|
90
|
+
def batch_insert(operations, chunk_size=1000)
|
91
|
+
raise "Batch request must not exceed 1000 documents." unless chunk_size <= 1000
|
92
|
+
operations.each_slice(chunk_size)
|
93
|
+
.to_a
|
94
|
+
.each{|op|
|
95
|
+
resp = create_request().post(build_indexing_url(), :json => {:value => op})
|
96
|
+
raise_on_http_error(resp)
|
97
|
+
resp.to_s
|
98
|
+
}
|
99
|
+
end
|
100
|
+
|
101
|
+
# Search the index for the supplied text.
|
102
|
+
#
|
103
|
+
# @param [String] text The text to search for.
|
104
|
+
# @param [IndexSearchOptions] options Options to configure the search request.
|
105
|
+
#
|
106
|
+
# @return [Hash] Parsed JSON response.
|
107
|
+
def search(text, options)
|
108
|
+
resp = create_request().get(build_index_search_url(text, options))
|
109
|
+
raise_on_http_error(resp)
|
110
|
+
return JSON.parse(resp.to_s)
|
111
|
+
end
|
112
|
+
|
113
|
+
# Lookup an indexed document by key.
|
114
|
+
#
|
115
|
+
# @param [String] key The key.
|
116
|
+
# @return [Hash] The document identified by the supplied key.
|
117
|
+
def lookup(key)
|
118
|
+
resp = create_request().get(build_index_lookup_url(key))
|
119
|
+
raise_on_http_error(resp)
|
120
|
+
doc = JSON.parse(resp.to_s)
|
121
|
+
doc.delete("@odata.context")
|
122
|
+
return doc
|
123
|
+
end
|
124
|
+
|
125
|
+
private
|
126
|
+
def build_index_definition_url
|
127
|
+
"https://#{self.service_name}.search.windows.net/indexes/#{self.index_name}?api-version=#{API_VERSION}"
|
128
|
+
end
|
129
|
+
|
130
|
+
def build_index_list_url
|
131
|
+
"https://#{self.service_name}.search.windows.net/indexes?api-version=#{API_VERSION}"
|
132
|
+
end
|
133
|
+
|
134
|
+
def build_indexing_url
|
135
|
+
"https://#{self.service_name}.search.windows.net/indexes/#{self.index_name}/docs/index?api-version=#{API_VERSION}"
|
136
|
+
end
|
137
|
+
|
138
|
+
def build_index_search_url(text, options)
|
139
|
+
query = {"search" => URI.encode_www_form_component(text)}.merge(options.to_hash)
|
140
|
+
"https://#{self.service_name}.search.windows.net/indexes/#{self.index_name}/docs?api-version=#{API_VERSION}&" << to_query_string(query)
|
141
|
+
end
|
142
|
+
|
143
|
+
def build_index_lookup_url(key)
|
144
|
+
"https://#{self.service_name}.search.windows.net/indexes/#{self.index_name}/docs('#{key}')?api-version=#{API_VERSION}"
|
145
|
+
end
|
146
|
+
|
147
|
+
def create_request
|
148
|
+
HTTP.headers({
|
149
|
+
"Content-Type" => "application/json",
|
150
|
+
"api-key" => self.api_key
|
151
|
+
})
|
152
|
+
end
|
153
|
+
|
154
|
+
def raise_on_http_error(response)
|
155
|
+
status_code = response.code
|
156
|
+
if status_code > 399
|
157
|
+
# 503 means the server is asking for backoff + retry
|
158
|
+
if status_code == 503
|
159
|
+
raise RetriableHttpError.new(status_code, response.to_s)
|
160
|
+
else
|
161
|
+
raise StandardError, "#{response.to_s}"
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def validate_search_option(options)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
module AzureSearch
|
4
|
+
|
5
|
+
# Checks if the supplied value is a Boolean.
|
6
|
+
#
|
7
|
+
# @param [Object] value The value to check.
|
8
|
+
# @return [TrueClass,FalseClass] true or false.
|
9
|
+
def is_bool?(value); [true, false].include? value end
|
10
|
+
|
11
|
+
# Checks if the supplied text contains valid HTML.
|
12
|
+
#
|
13
|
+
# @param [String] text The text to check.
|
14
|
+
# @return [TrueClass,FalseClass] true or false.
|
15
|
+
def has_html?(text); Nokogiri::XML(text).errors.empty? end
|
16
|
+
|
17
|
+
# Converts a Hash into query parameters string.
|
18
|
+
#
|
19
|
+
# @param [Hash] params The hash to convert.
|
20
|
+
# @return [String] query string.
|
21
|
+
def to_query_string(params)
|
22
|
+
params.map{|k,v|
|
23
|
+
if v.nil?
|
24
|
+
k.to_s
|
25
|
+
elsif v.respond_to?(:to_ary)
|
26
|
+
v.to_ary.map{|w|
|
27
|
+
str = k.to_s.dup
|
28
|
+
unless w.nil?
|
29
|
+
str << '='
|
30
|
+
str << w.to_s
|
31
|
+
end
|
32
|
+
}.join('&')
|
33
|
+
else
|
34
|
+
str = k.to_s.dup
|
35
|
+
str << '='
|
36
|
+
str << v.to_s
|
37
|
+
end
|
38
|
+
}.join('&')
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
metadata
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: azure_search
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Faissal Elamraoui
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-05-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: http
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: nokogiri
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.7'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.7'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.15'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.15'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '12.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '12.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.6'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.6'
|
83
|
+
description: This library allows you to interact with Microsoft Azure Search using
|
84
|
+
Ruby.
|
85
|
+
email:
|
86
|
+
- amr.faissal@gmail.com
|
87
|
+
executables: []
|
88
|
+
extensions: []
|
89
|
+
extra_rdoc_files: []
|
90
|
+
files:
|
91
|
+
- lib/azure_search.rb
|
92
|
+
- lib/azure_search/errors.rb
|
93
|
+
- lib/azure_search/index_batch_operation.rb
|
94
|
+
- lib/azure_search/index_field.rb
|
95
|
+
- lib/azure_search/index_search_options.rb
|
96
|
+
- lib/azure_search/search_index_client.rb
|
97
|
+
- lib/azure_search/utils.rb
|
98
|
+
- lib/azure_search/version.rb
|
99
|
+
homepage: https://github.com/amrfaissal/azuresearch-ruby-client.git
|
100
|
+
licenses:
|
101
|
+
- MIT
|
102
|
+
metadata: {}
|
103
|
+
post_install_message:
|
104
|
+
rdoc_options: []
|
105
|
+
require_paths:
|
106
|
+
- lib
|
107
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
requirements: []
|
118
|
+
rubyforge_project:
|
119
|
+
rubygems_version: 2.6.11
|
120
|
+
signing_key:
|
121
|
+
specification_version: 4
|
122
|
+
summary: Microsoft Azure Search Client Library for Ruby.
|
123
|
+
test_files: []
|