activedocument 0.6.2 → 1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/ActiveDocument/active_document.rb +101 -29
- data/lib/ActiveDocument/corona_interface.rb +186 -0
- data/lib/ActiveDocument/database_configuration.rb +71 -0
- data/lib/ActiveDocument/facets.rb +12 -0
- data/lib/ActiveDocument/finder.rb +36 -36
- data/lib/ActiveDocument/mark_logic_http.rb +40 -17
- data/lib/ActiveDocument/search_match.rb +4 -4
- data/lib/ActiveDocument/search_result.rb +21 -20
- data/lib/ActiveDocument/search_results.rb +11 -36
- data/lib/active_document.rb +1 -1
- metadata +21 -9
- data/lib/ActiveDocument/mark_logic_query_builder.rb +0 -111
@@ -17,7 +17,7 @@ require 'rubygems'
|
|
17
17
|
require 'nokogiri'
|
18
18
|
require 'yaml'
|
19
19
|
require 'ActiveDocument/mark_logic_http'
|
20
|
-
require 'ActiveDocument/
|
20
|
+
require 'ActiveDocument/corona_interface'
|
21
21
|
require 'ActiveDocument/search_results'
|
22
22
|
require 'ActiveDocument/finder'
|
23
23
|
require "ActiveDocument/inheritable"
|
@@ -68,7 +68,7 @@ module ActiveDocument
|
|
68
68
|
inheritable_attributes_list :my_namespaces, :my_default_namespace, :root, :my_attribute_namespaces, :my_default_attribute_namespaces
|
69
69
|
@my_namespaces = Hash.new
|
70
70
|
@my_default_namespace = nil
|
71
|
-
attr_reader :document, :uri, :
|
71
|
+
attr_reader :document, :uri, :my_default_namespace, :my_namespaces, :root, :my_attribute_namespaces, :my_default_attribute_namespaces
|
72
72
|
|
73
73
|
|
74
74
|
# create a new instance with an optional xml string to use for constructing the model
|
@@ -76,14 +76,20 @@ module ActiveDocument
|
|
76
76
|
@document = Nokogiri::XML(xml_string) do |config|
|
77
77
|
config.noblanks
|
78
78
|
end
|
79
|
-
if !xml_string.empty? then
|
79
|
+
if !xml_string.empty? and self.class.my_root.nil? then
|
80
80
|
@root = @document.root.name
|
81
|
+
else
|
82
|
+
@root = self.class.my_root
|
81
83
|
end
|
82
84
|
@uri = uri
|
83
85
|
end
|
84
86
|
|
85
87
|
def to_s
|
86
|
-
@document
|
88
|
+
if @document
|
89
|
+
@document.to_xml(:save_with => Nokogiri::XML::Node::SaveOptions::NO_DECLARATION)
|
90
|
+
else
|
91
|
+
super.to_s
|
92
|
+
end
|
87
93
|
end
|
88
94
|
|
89
95
|
# saves this document to the repository. If _uri_ is provided then that will be the value used for the uri.
|
@@ -92,11 +98,12 @@ module ActiveDocument
|
|
92
98
|
def save(uri = nil)
|
93
99
|
doc_uri = (uri || @uri)
|
94
100
|
if doc_uri then
|
95
|
-
|
101
|
+
response_array = ActiveDocument::CoronaInterface.save(doc_uri)
|
102
|
+
uri_array = response_array[:uri]
|
103
|
+
@@ml_http.send_corona_request(uri_array[0], uri_array[1], self.document.to_s)
|
96
104
|
else
|
97
105
|
raise ArgumentError, "uri must not be nil", caller
|
98
106
|
end
|
99
|
-
|
100
107
|
end
|
101
108
|
|
102
109
|
# Returns the root element for this object
|
@@ -128,7 +135,7 @@ module ActiveDocument
|
|
128
135
|
end
|
129
136
|
access_element $1
|
130
137
|
elsif method =~ /^(\w*)=$/ && arguments.length == 1 # methods with no '.' in them and ending in '='
|
131
|
-
set_element($1, arguments)
|
138
|
+
set_element($1, arguments[0])
|
132
139
|
else
|
133
140
|
super
|
134
141
|
end
|
@@ -140,8 +147,8 @@ module ActiveDocument
|
|
140
147
|
|
141
148
|
def namespace_for_element(element)
|
142
149
|
namespace = nil
|
143
|
-
if !@my_namespaces.nil? && @my_namespaces[element]
|
144
|
-
namespace = @my_namespaces[element]
|
150
|
+
if !@my_namespaces.nil? && @my_namespaces[element.to_sym]
|
151
|
+
namespace = @my_namespaces[element.to_sym]
|
145
152
|
else
|
146
153
|
namespace = @my_default_namespace unless @my_default_namespace.nil?
|
147
154
|
end
|
@@ -150,52 +157,110 @@ module ActiveDocument
|
|
150
157
|
|
151
158
|
def namespace_for_attribute(attribute)
|
152
159
|
namespace = nil
|
153
|
-
if !@my_attribute_namespaces.nil? && @my_attribute_namespaces[attribute]
|
154
|
-
namespace = @my_attribute_namespaces[attribute]
|
160
|
+
if !@my_attribute_namespaces.nil? && @my_attribute_namespaces[attribute.to_sym]
|
161
|
+
namespace = @my_attribute_namespaces[attribute.to_sym]
|
155
162
|
else
|
156
163
|
namespace = @my_default_attribute_namespace unless @my_default_attribute_namespace.nil?
|
157
164
|
end
|
158
165
|
namespace
|
159
166
|
end
|
160
167
|
|
168
|
+
|
169
|
+
# Sets the hash of elements to namespace prefixes. All prefixes should have already been registered with
|
170
|
+
# the framework via the ActiveDocument::DataBaseConfiguration class. Otherwise, errors will likely occur at runtime
|
171
|
+
# @param namespace_hash [A hash where they keys are element names as strings and the values are namespace
|
172
|
+
# prefixes as strings]
|
173
|
+
# @return [the resultant hash]
|
161
174
|
def namespaces(namespace_hash)
|
162
175
|
@my_namespaces = namespace_hash
|
176
|
+
@my_namespaces
|
163
177
|
end
|
164
178
|
|
179
|
+
# Sets the hash of attributes to namespace prefixes. All prefixes should have already been registered with
|
180
|
+
# the framework via the ActiveDocument::DataBaseConfiguration class. Otherwise, errors will likely occur at runtime
|
181
|
+
# @param namespace_hash [A hash where they keys are element names as strings and the values are namespace
|
182
|
+
# prefixes as strings]
|
183
|
+
# @return [the resultant hash]
|
165
184
|
def attribute_namespaces(namespace_hash)
|
166
185
|
@my_attribute_namespaces = namespace_hash
|
186
|
+
@my_attribute_namespaces
|
167
187
|
end
|
168
188
|
|
169
|
-
|
170
|
-
|
189
|
+
# Adds an element / namespace prefix pair to the existing hash. All prefixes should have already been registered with
|
190
|
+
# the framework via the ActiveDocument::DataBaseConfiguration class. Otherwise, errors will likely occur at runtime
|
191
|
+
# @param element [The element]
|
192
|
+
# @param prefix [the namespace prefix to be associated with the element]
|
193
|
+
# @return [the resultant updated hash of elements to namespace prefixes]
|
194
|
+
def add_namespace(element, prefix)
|
195
|
+
@my_namespaces[element.to_s] = prefix
|
196
|
+
@my_namespaces
|
171
197
|
end
|
172
198
|
|
173
|
-
|
174
|
-
|
199
|
+
# Adds an attribute / namespace prefix pair to the existing hash. All prefixes should have already been registered with
|
200
|
+
# the framework via the ActiveDocument::DataBaseConfiguration class. Otherwise, errors will likely occur at runtime
|
201
|
+
# @param attribute [The attribute]
|
202
|
+
# @param prefix [the namespace prefix to be associated with the attribute]
|
203
|
+
# @return [the resultant updated hash of attributes to namespace prefixes]
|
204
|
+
def add_attribute_namespace(attribute, prefix)
|
205
|
+
@my_attribute_namespaces[attribute.to_s] = prefix
|
206
|
+
@my_attribute_namespaces
|
175
207
|
end
|
176
208
|
|
209
|
+
# Removes an element / namespace prefix pair from the existing hash. #todo what about the corona config?
|
210
|
+
# @param element [the element to be removed)]
|
211
|
+
# @return [the resultant updated hash of elements to namespace prefixes]
|
177
212
|
def remove_namespace(element)
|
178
|
-
@my_namespaces.delete element
|
213
|
+
@my_namespaces.delete element.to_s
|
214
|
+
@my_namespaces
|
179
215
|
end
|
180
216
|
|
217
|
+
# Removes an attribute / namespace prefix pair from the existing hash. #todo what about the corona config?
|
218
|
+
# @param attribute [the attribute to be removed)]
|
219
|
+
# @return [the resultant updated hash of attributes to namespace prefixes]
|
181
220
|
def remove_attribute_namespace(attribute)
|
182
|
-
@my_attribute_namespaces.delete attribute
|
221
|
+
@my_attribute_namespaces.delete attribute.to_s
|
222
|
+
@my_attribute_namespaces
|
223
|
+
end
|
224
|
+
|
225
|
+
# defines the default namespace prefix to be used for all otherwise unspecified elements. The prefix should have
|
226
|
+
# already been registered with the framework via the ActiveDocument::DataBaseConfiguration class. Otherwise,
|
227
|
+
# errors will likely occur at runtime
|
228
|
+
# @param prefix [the registered namespace prefix for all otherwise unspecified elements]
|
229
|
+
# @return [the default element namespace prefix]
|
230
|
+
def default_namespace(prefix)
|
231
|
+
@my_default_namespace = prefix
|
232
|
+
@my_default_namespace
|
183
233
|
end
|
184
234
|
|
185
|
-
|
186
|
-
|
235
|
+
# defines the default namespace prefix to be used for all otherwise unspecified attributes. The prefix should have
|
236
|
+
# already been registered with the framework via the ActiveDocument::DataBaseConfiguration class. Otherwise,
|
237
|
+
# errors will likely occur at runtime
|
238
|
+
# @param prefix [the registered namespace prefix for all otherwise unspecified attributes]
|
239
|
+
# @return [the default attribute namespace prefix]
|
240
|
+
def default_attribute_namespace(prefix)
|
241
|
+
@my_default_attribute_namespace = prefix
|
242
|
+
@my_default_attribute_namespace
|
187
243
|
end
|
188
244
|
|
245
|
+
# sets the root element of the document. If not set it will default to the classname
|
189
246
|
def root(root)
|
190
247
|
@root = root
|
191
248
|
end
|
192
249
|
|
193
|
-
def
|
194
|
-
@
|
250
|
+
def my_root
|
251
|
+
@root
|
195
252
|
end
|
196
253
|
|
254
|
+
|
197
255
|
def delete(uri)
|
198
|
-
|
256
|
+
doc_uri = (uri || @uri)
|
257
|
+
if doc_uri then
|
258
|
+
response_array = ActiveDocument::CoronaInterface.delete(doc_uri)
|
259
|
+
uri_array = response_array[:uri]
|
260
|
+
@@ml_http.send_corona_request(uri_array[0], uri_array[1])
|
261
|
+
else
|
262
|
+
raise ArgumentError, "uri must not be nil", caller
|
263
|
+
end
|
199
264
|
end
|
200
265
|
|
201
266
|
# enables the dynamic finders
|
@@ -235,7 +300,7 @@ module ActiveDocument
|
|
235
300
|
execute_attribute_finder(element, attribute, value, root, element_namespace, attribute_namespace, root_namespace, options)
|
236
301
|
elsif method =~ /find_by_(.*)$/ and arguments.length > 0 # identify element search methods
|
237
302
|
value = arguments[0]
|
238
|
-
element = $1.
|
303
|
+
element = $1 # todo: this used to be converted to a symbol. Make sure that keeping it as a string doesn't break something
|
239
304
|
if arguments[1]
|
240
305
|
root = arguments[1]
|
241
306
|
else
|
@@ -249,7 +314,7 @@ module ActiveDocument
|
|
249
314
|
if arguments[3]
|
250
315
|
root_namespace = arguments[3]
|
251
316
|
else
|
252
|
-
root_namespace = namespace_for_element(root)
|
317
|
+
root_namespace = namespace_for_element(root) unless root.nil?
|
253
318
|
end
|
254
319
|
if arguments[4]
|
255
320
|
options = arguments[4]
|
@@ -266,7 +331,13 @@ module ActiveDocument
|
|
266
331
|
# Returns an ActiveXML object representing the requested information. If no document exists at that uri then
|
267
332
|
# a LoadException is thrown
|
268
333
|
def load(uri)
|
269
|
-
|
334
|
+
response_array = ActiveDocument::CoronaInterface.load(uri)
|
335
|
+
uri_array = response_array[:uri]
|
336
|
+
begin
|
337
|
+
document = @@ml_http.send_corona_request(uri_array[0], uri_array[1])
|
338
|
+
rescue Net::HTTPServerException => exception
|
339
|
+
raise LoadException, "File #{uri} not found", caller
|
340
|
+
end
|
270
341
|
if document.empty?
|
271
342
|
raise LoadException, "File #{uri} not found", caller
|
272
343
|
end
|
@@ -275,9 +346,10 @@ module ActiveDocument
|
|
275
346
|
|
276
347
|
# Finds all documents of this type that contain the word anywhere in their structure
|
277
348
|
def find_by_word(word, root=@root, namespace=@my_default_namespace)
|
278
|
-
|
279
|
-
|
280
|
-
|
349
|
+
response_array = ActiveDocument::CoronaInterface.find_by_word(word, root, namespace)
|
350
|
+
uri_array = response_array[:uri]
|
351
|
+
@@log.info("ActiveDocument.execute_find_by_word at line #{__LINE__}: #{response_array}")
|
352
|
+
SearchResults.new(@@ml_http.send_corona_request(uri_array[0], uri_array[1], nil, response_array[:post_parameters]))
|
281
353
|
end
|
282
354
|
|
283
355
|
end # end inner class
|
@@ -394,7 +466,7 @@ module ActiveDocument
|
|
394
466
|
|
395
467
|
end
|
396
468
|
|
397
|
-
|
469
|
+
# end class
|
398
470
|
|
399
471
|
class ActiveDocumentException < Exception
|
400
472
|
|
@@ -0,0 +1,186 @@
|
|
1
|
+
# Copyright 2010 Mark Logic, Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
require 'ActiveDocument/mark_logic_search_options'
|
15
|
+
module ActiveDocument
|
16
|
+
|
17
|
+
#todo create a configuration class for logging info and such
|
18
|
+
|
19
|
+
# CoronaInterface methods always return a hash. This hash will always contain at least a uri key with associated
|
20
|
+
# value
|
21
|
+
class CoronaInterface
|
22
|
+
|
23
|
+
def self.load(uri)
|
24
|
+
{:uri => ["/store?uri=#{uri}", :get]}
|
25
|
+
end
|
26
|
+
|
27
|
+
# @param uri the uri of the record to be deleted
|
28
|
+
# @return A hash containing the necessary return values. This hash contains:
|
29
|
+
# uri: an array where the first element is the uri to be used for the REST call and the second element is the
|
30
|
+
# http verb
|
31
|
+
def self.delete(uri)
|
32
|
+
{:uri => ["/store?uri=#{uri}", :delete]}
|
33
|
+
end
|
34
|
+
|
35
|
+
# @param uri the uri of the record to be saved
|
36
|
+
# @return A hash containing the necessary return values. This hash contains:
|
37
|
+
# uri: an array where the first element is the uri to be used for the REST call and the second element is the
|
38
|
+
# http verb
|
39
|
+
def self.save(uri)
|
40
|
+
{:uri => ["/store?uri=#{uri}", :put]}
|
41
|
+
end
|
42
|
+
|
43
|
+
# This method does a full text search
|
44
|
+
# @return A hash containing the necessary return values. This hash contains:
|
45
|
+
# uri: an array where the first element is the uri to be used for the REST call and the second element is the
|
46
|
+
# http verb
|
47
|
+
# post_parameters: a hash of all post parameters to be submitted
|
48
|
+
def self.find_by_word(word, root, root_namespace, options = nil)
|
49
|
+
#todo deal with paging
|
50
|
+
response = Hash.new
|
51
|
+
post_parameters = Hash.new
|
52
|
+
options = self.setup_options(options, root, root_namespace)
|
53
|
+
unless root.nil?
|
54
|
+
if root_namespace.nil?
|
55
|
+
root_expression = root
|
56
|
+
else
|
57
|
+
root_expression = options.searchable_expression[root_namespace] + ":" + root unless root_namespace.nil?
|
58
|
+
end
|
59
|
+
end
|
60
|
+
structured_query = "{\"underElement\":\"#{root_expression}\",\"query\":{\"wordAnywhere\":\"#{word}\"}}"
|
61
|
+
response[:uri] = ["/search", :post]
|
62
|
+
post_parameters[:structuredQuery] = structured_query
|
63
|
+
post_parameters[:outputFormat] = "xml"
|
64
|
+
post_parameters[:include] = "snippet"
|
65
|
+
post_parameters[:include] = "confidence"
|
66
|
+
if options.directory_constraint
|
67
|
+
if options.directory_depth == 1
|
68
|
+
post_parameters[:inDirectory] = options.directory_constraint
|
69
|
+
else
|
70
|
+
post_parameters[:underDirectory] = options.directory_constraint
|
71
|
+
end
|
72
|
+
end
|
73
|
+
response[:post_parameters] = post_parameters
|
74
|
+
response
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.find_by_element(element, value, root, element_namespace, root_namespace, options = nil)
|
78
|
+
response = Hash.new
|
79
|
+
post_parameters = Hash.new
|
80
|
+
options = self.setup_options(options, root, root_namespace)
|
81
|
+
unless root.nil?
|
82
|
+
if root_namespace.nil?
|
83
|
+
root_expression = root
|
84
|
+
else
|
85
|
+
root_expression = options.searchable_expression[root_namespace] + ":" + root unless root_namespace.nil?
|
86
|
+
end
|
87
|
+
end
|
88
|
+
element_qname = element.to_s
|
89
|
+
element_qname.insert(0, element_namespace + ":") unless element_namespace.nil?
|
90
|
+
# todo this query is the more permissive contains. Deal with more restrictive equals as well
|
91
|
+
structured_query = "{\"element\":\"#{element_qname}\", \"contains\":\"#{value}\"}"
|
92
|
+
response[:uri] = ["/search", :post]
|
93
|
+
post_parameters[:structuredQuery] = structured_query
|
94
|
+
post_parameters[:outputFormat] = "xml"
|
95
|
+
post_parameters[:include] = "snippet"
|
96
|
+
post_parameters[:include] = "confidence"
|
97
|
+
if options.directory_constraint
|
98
|
+
if options.directory_depth == 1
|
99
|
+
post_parameters[:inDirectory] = options.directory_constraint
|
100
|
+
else
|
101
|
+
post_parameters[:underDirectory] = options.directory_constraint
|
102
|
+
end
|
103
|
+
end
|
104
|
+
response[:post_parameters] = post_parameters
|
105
|
+
response
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.find_by_attribute(element, attribute, value, root, element_namespace, attribute_namespace, root_namespace, options = nil)
|
109
|
+
response = Hash.new
|
110
|
+
post_parameters = Hash.new
|
111
|
+
options = self.setup_options(options, root, root_namespace)
|
112
|
+
unless root.nil?
|
113
|
+
if root_namespace.nil?
|
114
|
+
root_expression = root
|
115
|
+
else
|
116
|
+
root_expression = options.searchable_expression[root_namespace] + ":" + root unless root_namespace.nil?
|
117
|
+
end
|
118
|
+
end
|
119
|
+
element_qname = element
|
120
|
+
element_qname.insert(0, element_namespace + ":") unless element_namespace.nil?
|
121
|
+
attribute_qname = attribute.to_s
|
122
|
+
attribute_qname.insert(0, attribute_namespace + ":") unless attribute_namespace.nil?
|
123
|
+
# todo this query is the more permissive contains. Deal with more restrictive equals as well
|
124
|
+
structured_query = "{\"element\":\"#{element_qname}\",\"attribute\":\"#{attribute_qname}\", \"contains\":\"#{value}\"}"
|
125
|
+
response[:uri] = ["/search", :post]
|
126
|
+
post_parameters[:structuredQuery] = structured_query
|
127
|
+
post_parameters[:outputFormat] = "xml"
|
128
|
+
post_parameters[:include] = "snippet"
|
129
|
+
post_parameters[:include] = "confidence"
|
130
|
+
if options.directory_constraint
|
131
|
+
if options.directory_depth == 1
|
132
|
+
post_parameters[:inDirectory] = options.directory_constraint
|
133
|
+
else
|
134
|
+
post_parameters[:underDirectory] = options.directory_constraint
|
135
|
+
end
|
136
|
+
end
|
137
|
+
response[:post_parameters] = post_parameters
|
138
|
+
response
|
139
|
+
end
|
140
|
+
|
141
|
+
def self.search(search_text, start, page_length, options)
|
142
|
+
if options && options.directory_constraint
|
143
|
+
directory_string = nil
|
144
|
+
if options.directory_depth == 1
|
145
|
+
directory_string = "&inDirectory=" + options.directory_constraint
|
146
|
+
else
|
147
|
+
directory_string = "&underDirectory=" +options.directory_constraint
|
148
|
+
end
|
149
|
+
end
|
150
|
+
["/search?stringQuery=#{search_text}&start=#{start}&end=#{start + page_length -1}&outputFormat=xml&include=snippet&include=confidence#{directory_string}", :get]
|
151
|
+
end
|
152
|
+
|
153
|
+
def self.co_occurrence(element1, element1_namespace, element2, element2_namespace, query)
|
154
|
+
# Not supported by Corona at this time
|
155
|
+
end
|
156
|
+
|
157
|
+
def self.declare_namespace(prefix, uri)
|
158
|
+
["/manage/namespace/#{prefix}?uri=#{uri}", :post]
|
159
|
+
end
|
160
|
+
|
161
|
+
# @param uri [The uri for which the matching, if any, prefix should be found]
|
162
|
+
# @return [An array where the first item is the string uri for the request and the second item is the http verb]
|
163
|
+
def self.lookup_namespace(uri)
|
164
|
+
["/manage/namespace/#{uri}", :get]
|
165
|
+
end
|
166
|
+
|
167
|
+
def self.delete_all_namespaces
|
168
|
+
["/manage/namespaces/", :delete]
|
169
|
+
end
|
170
|
+
|
171
|
+
private
|
172
|
+
|
173
|
+
def self.setup_options(options, root, root_namespace)
|
174
|
+
if options then
|
175
|
+
search_options = options
|
176
|
+
else
|
177
|
+
search_options = ActiveDocument::MarkLogicSearchOptions.new
|
178
|
+
end
|
179
|
+
if (search_options.searchable_expression.empty?)
|
180
|
+
search_options.searchable_expression[root_namespace] = root unless root.nil?
|
181
|
+
end
|
182
|
+
return search_options
|
183
|
+
end
|
184
|
+
|
185
|
+
end # end class
|
186
|
+
end # end module
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# Copyright 2010 Mark Logic, Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
require "yaml"
|
15
|
+
require 'ActiveDocument/mark_logic_http'
|
16
|
+
require 'ActiveDocument/corona_interface'
|
17
|
+
require "ActiveDocument/finder"
|
18
|
+
module ActiveDocument
|
19
|
+
|
20
|
+
# This class is used to manage the configuration of MarkLogic. It can create, list and change / delete a variety of
|
21
|
+
# configuration options including indexes namespaces and fields
|
22
|
+
class DatabaseConfiguration
|
23
|
+
|
24
|
+
attr_reader :namespaces
|
25
|
+
|
26
|
+
# @param yaml_file [The yaml file containing the configuration information for the server connection]
|
27
|
+
def self.initialize(yaml_file)
|
28
|
+
config = YAML.load_file(yaml_file)
|
29
|
+
@@ml_http = ActiveDocument::MarkLogicHTTP.new(config['uri'], config['user_name'], config['password'])
|
30
|
+
@@namespaces = Hash.new
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
# @param namespaces [a Hash of namespaces prefixes to namespaces]
|
35
|
+
def self.define_namespaces(namespaces)
|
36
|
+
namespaces.keys.each do |key|
|
37
|
+
corona_array = ActiveDocument::CoronaInterface.declare_namespace(key, namespaces[key])
|
38
|
+
@@ml_http.send_corona_request(corona_array[0], corona_array[1])
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# @param prefix [The prefix for which you wish to find a matching namespace]
|
43
|
+
# @return The matching namespace as a string or nil if there is no matching namespace for the prefix
|
44
|
+
def self.lookup_namespace(prefix)
|
45
|
+
corona_array = ActiveDocument::CoronaInterface.lookup_namespace(prefix)
|
46
|
+
begin
|
47
|
+
@@ml_http.send_corona_request(corona_array[0], corona_array[1])
|
48
|
+
rescue Exception => exception
|
49
|
+
if exception.response.code == "404"
|
50
|
+
nil #return nil when no namespace is found
|
51
|
+
else
|
52
|
+
raise exception
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.delete_all_namespaces
|
58
|
+
corona_array = ActiveDocument::CoronaInterface.delete_all_namespaces
|
59
|
+
begin
|
60
|
+
@@ml_http.send_corona_request(corona_array[0], corona_array[1])
|
61
|
+
rescue Exception => exception
|
62
|
+
if exception.response && exception.response.code == "404"
|
63
|
+
nil
|
64
|
+
else
|
65
|
+
raise exception
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class Facets
|
2
|
+
|
3
|
+
@facets = Hash.new
|
4
|
+
@results_document.xpath("/search:response/search:facet").each do |facet|
|
5
|
+
name = facet.xpath("./@name").to_s
|
6
|
+
detail = Hash.new
|
7
|
+
@facets[name] = detail
|
8
|
+
facet.xpath("search:facet-value").each do |facet_value|
|
9
|
+
detail[facet_value.xpath("./@name").to_s] = facet_value.xpath("./@count").to_s
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -14,8 +14,8 @@
|
|
14
14
|
|
15
15
|
require 'rubygems'
|
16
16
|
require 'nokogiri'
|
17
|
-
require 'ActiveDocument/mark_logic_query_builder'
|
18
17
|
require 'ActiveDocument/mark_logic_http'
|
18
|
+
require 'ActiveDocument/corona_interface'
|
19
19
|
require 'ActiveDocument/search_results'
|
20
20
|
require 'logger'
|
21
21
|
|
@@ -24,8 +24,6 @@ module ActiveDocument
|
|
24
24
|
class Finder
|
25
25
|
|
26
26
|
|
27
|
-
@@xquery_builder = ActiveDocument::MarkLogicQueryBuilder.new
|
28
|
-
|
29
27
|
def self.config(yaml_file)
|
30
28
|
config = YAML.load_file(yaml_file)
|
31
29
|
@@ml_http = ActiveDocument::MarkLogicHTTP.new(config['uri'], config['user_name'], config['password'])
|
@@ -50,27 +48,29 @@ module ActiveDocument
|
|
50
48
|
end
|
51
49
|
|
52
50
|
def self.execute_finder(element, value, root = nil, element_namespace = nil, root_namespace = nil, options = nil)
|
53
|
-
|
54
|
-
|
55
|
-
|
51
|
+
response_array = ActiveDocument::CoronaInterface.find_by_element(element, value, root, element_namespace, root_namespace, options)
|
52
|
+
uri_array = response_array[:uri]
|
53
|
+
@@log.info("ActiveDocument.execute_element_finder at line #{__LINE__}: #{response_array}")
|
54
|
+
SearchResults.new(@@ml_http.send_corona_request(uri_array[0], uri_array[1], nil, response_array[:post_parameters]))
|
56
55
|
end
|
57
56
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
57
|
+
def self.execute_attribute_finder(element, attribute, value, root = nil, element_namespace = nil, attribute_namespace = nil, root_namespace = nil, options = nil)
|
58
|
+
response_array = ActiveDocument::CoronaInterface.find_by_attribute(element, attribute, value, root, element_namespace, attribute_namespace, root_namespace, options)
|
59
|
+
uri_array = response_array[:uri]
|
60
|
+
@@log.info("ActiveDocument.execute_attribute_find_by_word at line #{__LINE__}: #{response_array}")
|
61
|
+
SearchResults.new(@@ml_http.send_corona_request(uri_array[0], uri_array[1], nil, response_array[:post_parameters]))
|
62
62
|
end
|
63
63
|
|
64
64
|
def self.search(search_string, start = 1, page_length = 10, options = nil)
|
65
65
|
start ||= 1
|
66
66
|
page_length ||= 10
|
67
|
-
|
68
|
-
SearchResults.new(@@ml_http.
|
67
|
+
corona_array = ActiveDocument::CoronaInterface.search(search_string, start, page_length, options)
|
68
|
+
SearchResults.new(@@ml_http.send_corona_request(corona_array[0], corona_array[1]))
|
69
69
|
end
|
70
70
|
|
71
71
|
# returns a hash where the key is the terms of the co-occurrence separated by a | and the value is the frequency count
|
72
72
|
def self.co_occurrence(element1, element1_namespace, element2, element2_namespace, query)
|
73
|
-
pairs = @@ml_http.send_xquery(
|
73
|
+
pairs = @@ml_http.send_xquery(ActiveDocument::CoronaInterface.co_occurrence(element1, element1_namespace, element2, element2_namespace, query)).split("*")
|
74
74
|
pair_hash = Hash.new
|
75
75
|
pairs.each do |p|
|
76
76
|
temp = p.split("|")
|
@@ -85,30 +85,30 @@ module ActiveDocument
|
|
85
85
|
|
86
86
|
begin
|
87
87
|
log_location = if config['logger']['file']
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
88
|
+
config['logger']['file']
|
89
|
+
else
|
90
|
+
STDERR
|
91
|
+
end
|
92
92
|
log_level = case config['logger']['level']
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
rotation
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
93
|
+
when "debug" then
|
94
|
+
Logger::DEBUG
|
95
|
+
when "info" then
|
96
|
+
Logger::INFO
|
97
|
+
when "warn" then
|
98
|
+
Logger::WARN
|
99
|
+
when "error" then
|
100
|
+
Logger::ERROR
|
101
|
+
when "fatal" then
|
102
|
+
Logger::FATAL
|
103
|
+
else
|
104
|
+
Logger::WARN
|
105
|
+
end
|
106
|
+
|
107
|
+
rotation = if config['logger']['rotation']
|
108
|
+
config['logger']['rotation']
|
109
|
+
else
|
110
|
+
"daily"
|
111
|
+
end
|
112
112
|
file = open(log_location, File::WRONLY | File::APPEND | File::CREAT)
|
113
113
|
@@log = Logger.new(file, rotation)
|
114
114
|
@@log.level = log_level
|
@@ -68,30 +68,53 @@ module ActiveDocument
|
|
68
68
|
@password = password
|
69
69
|
end
|
70
70
|
|
71
|
-
|
72
|
-
|
73
|
-
|
71
|
+
# @param uri [the uri endpoint for the request]
|
72
|
+
# @param body [the optional body]
|
73
|
+
# @param verb [The HTTP verb to be used]
|
74
|
+
# @param post_fields [a hash of post fields. They key should be the field name and the value is the field value]
|
75
|
+
# @return [nil if there if no uri or it is an empty string. Otherwise, returns the http response]
|
76
|
+
def send_corona_request(uri, verb=:get, body="", post_fields=nil)
|
77
|
+
return nil if uri.nil? or uri.empty?
|
78
|
+
target_url = @url + URI.escape(uri)
|
79
|
+
http = Net::HTTP.new(target_url.host, target_url.port)
|
80
|
+
if target_url.query
|
81
|
+
endpoint = target_url.path + "?" + target_url.query
|
82
|
+
else
|
83
|
+
endpoint = target_url.path
|
74
84
|
end
|
75
|
-
|
76
|
-
|
77
|
-
|
85
|
+
case verb
|
86
|
+
when :post
|
87
|
+
req = Net::HTTP::Post.new(endpoint)
|
88
|
+
req.set_form_data(post_fields) unless post_fields.nil?
|
89
|
+
#puts URI.decode_www_form(req.body)
|
90
|
+
when :put
|
91
|
+
req = Net::HTTP::Put.new(endpoint)
|
92
|
+
when :get
|
93
|
+
req = Net::HTTP::Get.new(endpoint)
|
94
|
+
when :delete
|
95
|
+
req = Net::HTTP::Delete.new(endpoint)
|
96
|
+
else
|
97
|
+
req = Net::HTTP::Get.new(endpoint) # safe default
|
98
|
+
end
|
99
|
+
if ((! body.nil?) and (verb == :put or verb == :post) ) then
|
100
|
+
if (req.body.nil?) then req.body = body
|
101
|
+
else
|
102
|
+
req.body << body
|
103
|
+
end
|
104
|
+
end
|
105
|
+
res = http.head(target_url.request_uri)
|
106
|
+
#puts "body::::: #{req.body}" unless verb == :put
|
107
|
+
req.digest_auth(@user_name, @password, res)
|
108
|
+
res = http.request(req)
|
78
109
|
case res
|
79
110
|
when Net::HTTPSuccess, Net::HTTPRedirection
|
80
|
-
#
|
111
|
+
#puts res.body
|
81
112
|
res.body
|
82
113
|
else
|
83
|
-
|
114
|
+
#puts req.path
|
115
|
+
raise res.error!
|
84
116
|
end
|
85
117
|
end
|
86
118
|
|
87
|
-
private
|
88
|
-
def authenticate
|
89
|
-
req = Net::HTTP::Post.new(@url.path)
|
90
|
-
Net::HTTP.start(@url.host, @url.port) do |http|
|
91
|
-
res = http.head(@url.request_uri)
|
92
|
-
req.digest_auth(@user_name, @password, res)
|
93
|
-
end
|
94
|
-
return req
|
95
|
-
end
|
96
119
|
end
|
97
120
|
end
|
@@ -30,8 +30,8 @@ module ActiveDocument
|
|
30
30
|
def to_s
|
31
31
|
value = @node.xpath("./node()").to_s
|
32
32
|
begin
|
33
|
-
value[/<
|
34
|
-
value[/<\/
|
33
|
+
value[/<span class="hit">/] = ""
|
34
|
+
value[/<\/span>/] = ""
|
35
35
|
rescue IndexError
|
36
36
|
end
|
37
37
|
return value
|
@@ -41,8 +41,8 @@ module ActiveDocument
|
|
41
41
|
value = @node.xpath("./node()").to_s
|
42
42
|
unless highlight_tag.nil?
|
43
43
|
begin
|
44
|
-
value[/<
|
45
|
-
value[/<\/
|
44
|
+
value[/<span class="hit">/] = "<#{highlight_tag}>"
|
45
|
+
value[/<\/span>/] = "</#{highlight_tag}>"
|
46
46
|
rescue IndexError
|
47
47
|
value
|
48
48
|
end
|
@@ -24,52 +24,53 @@ module ActiveDocument
|
|
24
24
|
@node = node
|
25
25
|
end
|
26
26
|
|
27
|
-
def index
|
28
|
-
|
29
|
-
end
|
27
|
+
#def index
|
28
|
+
# Integer(@node.xpath("./@index").to_s)
|
29
|
+
#end
|
30
30
|
|
31
31
|
def uri
|
32
|
-
@node.xpath("
|
32
|
+
@node.xpath("./corona:result/corona:uri").text.to_s
|
33
33
|
end
|
34
34
|
|
35
|
-
def path
|
36
|
-
|
37
|
-
end
|
35
|
+
#def path
|
36
|
+
# @node.xpath("./@path").to_s
|
37
|
+
#end
|
38
38
|
|
39
|
-
def score
|
40
|
-
|
41
|
-
end
|
39
|
+
#def score
|
40
|
+
# Float(@node.xpath("./@score").to_s)
|
41
|
+
#end
|
42
42
|
|
43
43
|
def confidence
|
44
|
-
Float(@node.xpath("
|
44
|
+
Float(@node.xpath("./corona:result/corona:confidence").text.to_s)
|
45
45
|
end
|
46
46
|
|
47
|
-
def fitness
|
48
|
-
|
49
|
-
end
|
47
|
+
#def fitness
|
48
|
+
# Float(@node.xpath("./@fitness").to_s)
|
49
|
+
#end
|
50
50
|
|
51
51
|
def each(&block)
|
52
|
-
nodeset = @node.xpath("./
|
52
|
+
nodeset = @node.xpath("./corona:result/corona:snippet/span")
|
53
53
|
if nodeset.length == 1
|
54
54
|
yield SearchMatch.new(nodeset[0])
|
55
55
|
else
|
56
|
-
@node.xpath("./
|
56
|
+
@node.xpath("./corona:result/corona:snippet/span").each { |node| yield SearchMatch.new(node) }
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
60
|
def root_type
|
61
|
-
full_path = @node.xpath("./
|
62
|
-
root = full_path.match(
|
61
|
+
full_path = @node.xpath("./corona:result/corona:snippet/span").xpath("./@path").to_s
|
62
|
+
root = full_path.match(/^\/[[:alpha:]]*((:)[[:alpha:]]*)?/) # find the first :something/ which should indicate the root
|
63
63
|
root.to_s.delete(":/") # remove the : and / to get the root element name
|
64
64
|
end
|
65
65
|
|
66
66
|
def [](index)
|
67
|
-
SearchMatch.new(@node.xpath("./
|
67
|
+
SearchMatch.new(@node.xpath("./corona:result/corona:snippet/span")[index])
|
68
68
|
end
|
69
69
|
|
70
70
|
def length
|
71
|
-
@node.xpath("./
|
71
|
+
@node.xpath("./corona:result/corona:snippet/span").length
|
72
72
|
end
|
73
|
+
|
73
74
|
def realize(klass)
|
74
75
|
klass.load(uri)
|
75
76
|
end
|
@@ -23,64 +23,39 @@ module ActiveDocument
|
|
23
23
|
|
24
24
|
def initialize(results)
|
25
25
|
@results_document = Nokogiri::XML(results)
|
26
|
-
@facets = Hash.new
|
27
|
-
@results_document.xpath("/search:response/search:facet").each do |facet|
|
28
|
-
name = facet.xpath("./@name").to_s
|
29
|
-
detail = Hash.new
|
30
|
-
@facets[name] = detail
|
31
|
-
facet.xpath("search:facet-value").each do |facet_value|
|
32
|
-
detail[facet_value.xpath("./@name").to_s] = facet_value.xpath("./@count").to_s
|
33
|
-
end
|
34
|
-
end
|
35
26
|
end
|
36
27
|
|
37
28
|
def total
|
38
|
-
Integer(@results_document.xpath("/
|
39
|
-
end
|
40
|
-
|
41
|
-
def start
|
42
|
-
Integer(@results_document.xpath("/search:response/@start").to_s)
|
43
|
-
end
|
44
|
-
|
45
|
-
def page_length
|
46
|
-
Integer(@results_document.xpath("/search:response/@page-length").to_s)
|
29
|
+
Integer(@results_document.xpath("/corona:response/corona:meta/corona:total/text()").to_s)
|
47
30
|
end
|
48
31
|
|
49
|
-
def
|
50
|
-
@results_document.xpath("/
|
32
|
+
def execution_time
|
33
|
+
Integer(@results_document.xpath("/corona:response/corona:meta/corona:executionTime/text()").to_s)
|
51
34
|
end
|
52
35
|
|
53
|
-
def
|
54
|
-
@results_document.xpath("/
|
55
|
-
end
|
56
|
-
|
57
|
-
def snippet_resolution_time
|
58
|
-
@results_document.xpath("/search:response/search:metrics/search:snippet-resolution-time/text()").to_s
|
59
|
-
end
|
60
|
-
|
61
|
-
def facet_resolution_time
|
62
|
-
@results_document.xpath("/search:response/search:metrics/search:facet-resolution-time/text()").to_s
|
36
|
+
def start
|
37
|
+
Integer(@results_document.xpath("/corona:response/corona:meta/corona:start/text()").to_s)
|
63
38
|
end
|
64
39
|
|
65
|
-
def
|
66
|
-
|
40
|
+
def page_length
|
41
|
+
total - start + 1
|
67
42
|
end
|
68
43
|
|
69
44
|
def each(&block)
|
70
|
-
nodeset = @results_document.xpath("/
|
45
|
+
nodeset = @results_document.xpath("/corona:response/corona:results/corona:result")
|
71
46
|
if nodeset.length == 1
|
72
47
|
yield SearchResult.new(nodeset[0])
|
73
48
|
else
|
74
|
-
@results_document.xpath("/
|
49
|
+
@results_document.xpath("/corona:response/corona:results/corona:result").each {|node| yield SearchResult.new(node)}
|
75
50
|
end
|
76
51
|
end
|
77
52
|
|
78
53
|
def [](index)
|
79
|
-
SearchResult.new(@results_document.xpath("/
|
54
|
+
SearchResult.new(@results_document.xpath("/corona:response/corona:results/corona:result")[index])
|
80
55
|
end
|
81
56
|
|
82
57
|
def length
|
83
|
-
@results_document.xpath("/
|
58
|
+
@results_document.xpath("/corona:response/corona:results/corona:result").length
|
84
59
|
end
|
85
60
|
|
86
61
|
end
|
data/lib/active_document.rb
CHANGED
@@ -2,7 +2,7 @@ require 'ActiveDocument/active_document'
|
|
2
2
|
require 'ActiveDocument/finder'
|
3
3
|
require 'ActiveDocument/inheritable'
|
4
4
|
require 'ActiveDocument/mark_logic_http'
|
5
|
-
require 'ActiveDocument/
|
5
|
+
require 'ActiveDocument/corona_interface'
|
6
6
|
require 'ActiveDocument/search_match'
|
7
7
|
require 'ActiveDocument/mark_logic_search_options'
|
8
8
|
require 'ActiveDocument/search_result'
|
metadata
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activedocument
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
5
|
-
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 0
|
8
|
+
version: "1.0"
|
6
9
|
platform: ruby
|
7
10
|
authors:
|
8
11
|
- Clark D. Richey, Jr.
|
@@ -10,16 +13,20 @@ autorequire:
|
|
10
13
|
bindir: bin
|
11
14
|
cert_chain: []
|
12
15
|
|
13
|
-
date:
|
16
|
+
date: 2012-01-04 00:00:00 -05:00
|
17
|
+
default_executable:
|
14
18
|
dependencies:
|
15
19
|
- !ruby/object:Gem::Dependency
|
16
20
|
name: nokogiri
|
17
21
|
prerelease: false
|
18
22
|
requirement: &id001 !ruby/object:Gem::Requirement
|
19
|
-
none: false
|
20
23
|
requirements:
|
21
24
|
- - ">="
|
22
25
|
- !ruby/object:Gem::Version
|
26
|
+
segments:
|
27
|
+
- 1
|
28
|
+
- 4
|
29
|
+
- 1
|
23
30
|
version: 1.4.1
|
24
31
|
type: :runtime
|
25
32
|
version_requirements: *id001
|
@@ -32,17 +39,20 @@ extensions: []
|
|
32
39
|
extra_rdoc_files: []
|
33
40
|
|
34
41
|
files:
|
42
|
+
- lib/active_document.rb
|
35
43
|
- lib/ActiveDocument/active_document.rb
|
44
|
+
- lib/ActiveDocument/corona_interface.rb
|
45
|
+
- lib/ActiveDocument/database_configuration.rb
|
46
|
+
- lib/ActiveDocument/facets.rb
|
36
47
|
- lib/ActiveDocument/finder.rb
|
37
48
|
- lib/ActiveDocument/inheritable.rb
|
38
49
|
- lib/ActiveDocument/mark_logic_http.rb
|
39
|
-
- lib/ActiveDocument/mark_logic_query_builder.rb
|
40
50
|
- lib/ActiveDocument/mark_logic_search_options.rb
|
41
51
|
- lib/ActiveDocument/search_match.rb
|
42
52
|
- lib/ActiveDocument/search_result.rb
|
43
53
|
- lib/ActiveDocument/search_results.rb
|
44
|
-
- lib/active_document.rb
|
45
54
|
- lib/activedocument.rb
|
55
|
+
has_rdoc: true
|
46
56
|
homepage: http://github.com/crichey/ActiveDocument
|
47
57
|
licenses: []
|
48
58
|
|
@@ -52,21 +62,23 @@ rdoc_options: []
|
|
52
62
|
require_paths:
|
53
63
|
- lib
|
54
64
|
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
-
none: false
|
56
65
|
requirements:
|
57
66
|
- - ">="
|
58
67
|
- !ruby/object:Gem::Version
|
68
|
+
segments:
|
69
|
+
- 0
|
59
70
|
version: "0"
|
60
71
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
-
none: false
|
62
72
|
requirements:
|
63
73
|
- - ">="
|
64
74
|
- !ruby/object:Gem::Version
|
75
|
+
segments:
|
76
|
+
- 0
|
65
77
|
version: "0"
|
66
78
|
requirements: []
|
67
79
|
|
68
80
|
rubyforge_project:
|
69
|
-
rubygems_version: 1.
|
81
|
+
rubygems_version: 1.3.6
|
70
82
|
signing_key:
|
71
83
|
specification_version: 3
|
72
84
|
summary: Object Mapper for XML Database
|
@@ -1,111 +0,0 @@
|
|
1
|
-
# Copyright 2010 Mark Logic, Inc.
|
2
|
-
#
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
-
# you may not use this file except in compliance with the License.
|
5
|
-
# You may obtain a copy of the License at
|
6
|
-
#
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
-
#
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
-
# See the License for the specific language governing permissions and
|
13
|
-
# limitations under the License.
|
14
|
-
require 'ActiveDocument/mark_logic_search_options'
|
15
|
-
module ActiveDocument
|
16
|
-
# todo create new unit tests for this class - the old ones were no good
|
17
|
-
class MarkLogicQueryBuilder
|
18
|
-
|
19
|
-
def load(uri)
|
20
|
-
"fn:doc('#{uri}')"
|
21
|
-
end
|
22
|
-
|
23
|
-
def delete(uri)
|
24
|
-
"xdmp:document-delete('#{uri}')"
|
25
|
-
end
|
26
|
-
|
27
|
-
def save(document, uri)
|
28
|
-
xquery = <<-GENERATED
|
29
|
-
xdmp:document-insert(
|
30
|
-
"#{uri}",
|
31
|
-
#{document.to_s} ,
|
32
|
-
xdmp:default-permissions(),
|
33
|
-
xdmp:default-collections())
|
34
|
-
GENERATED
|
35
|
-
end
|
36
|
-
|
37
|
-
# This method does a full text search
|
38
|
-
def find_by_word(word, root, root_namespace, options = nil)
|
39
|
-
xquery = <<-GENERATED
|
40
|
-
import module namespace search = "http://marklogic.com/appservices/search" at "/MarkLogic/appservices/search/search.xqy";
|
41
|
-
search:search("#{word}",
|
42
|
-
GENERATED
|
43
|
-
search_options = setup_options(options, root, root_namespace)
|
44
|
-
xquery << search_options.to_s
|
45
|
-
xquery << ')'
|
46
|
-
end
|
47
|
-
|
48
|
-
def find_by_element(element, value, root, element_namespace, root_namespace, options = nil)
|
49
|
-
xquery = <<-GENERATED
|
50
|
-
import module namespace search = "http://marklogic.com/appservices/search"at "/MarkLogic/appservices/search/search.xqy";
|
51
|
-
search:search('find_by_element:\"#{value}\"',
|
52
|
-
GENERATED
|
53
|
-
search_options = setup_options(options, root, root_namespace)
|
54
|
-
search_options.word_constraints["find_by_element"] = {"namespace" => element_namespace, "element" => element}
|
55
|
-
xquery << search_options.to_s
|
56
|
-
xquery << ')'
|
57
|
-
end
|
58
|
-
|
59
|
-
|
60
|
-
def find_by_attribute(element, attribute, value, root, element_namespace, attribute_namespace, root_namespace, options = nil)
|
61
|
-
xquery = <<-GENERATED
|
62
|
-
import module namespace search = "http://marklogic.com/appservices/search" at "/MarkLogic/appservices/search/search.xqy";
|
63
|
-
search:search("attribute:#{value}",
|
64
|
-
GENERATED
|
65
|
-
search_options = setup_options(options, root, root_namespace)
|
66
|
-
attribute_constraint = ActiveDocument::MarkLogicSearchOptions::AttributeConstraint.new(attribute_namespace, attribute, element_namespace, element)
|
67
|
-
search_options.attribute_constraints["attribute"] = attribute_constraint
|
68
|
-
xquery << search_options.to_s
|
69
|
-
xquery << ')'
|
70
|
-
end
|
71
|
-
|
72
|
-
def search(search_text, start, page_length, options)
|
73
|
-
if options.nil?
|
74
|
-
option = '()'
|
75
|
-
else
|
76
|
-
option = options.to_s
|
77
|
-
end
|
78
|
-
<<-GENERATED
|
79
|
-
import module namespace search = "http://marklogic.com/appservices/search" at "/MarkLogic/appservices/search/search.xqy";
|
80
|
-
search:search('#{search_text}', #{option}, #{start}, #{page_length})
|
81
|
-
GENERATED
|
82
|
-
end
|
83
|
-
|
84
|
-
def co_occurrence(element1, element1_namespace, element2, element2_namespace, query)
|
85
|
-
<<-GENERATED
|
86
|
-
declare namespace one = "#{element1_namespace}";
|
87
|
-
declare namespace two = "#{element2_namespace}";
|
88
|
-
import module namespace search = "http://marklogic.com/appservices/search" at "/MarkLogic/appservices/search/search.xqy";
|
89
|
-
let $pairs := cts:element-value-co-occurrences(xs:QName('one:#{element1}'), xs:QName('two:#{element2}'), ('frequency-order', 'fragment-frequency','ordered'), cts:query(search:parse('#{query}')))
|
90
|
-
return
|
91
|
-
for $pair in $pairs
|
92
|
-
return
|
93
|
-
($pair/cts:value[1]/text(),"|",$pair/cts:value[2]/text(),"|",cts:frequency($pair),"*")
|
94
|
-
GENERATED
|
95
|
-
end
|
96
|
-
private
|
97
|
-
|
98
|
-
def setup_options(options, root, root_namespace)
|
99
|
-
if options then
|
100
|
-
search_options = options
|
101
|
-
else
|
102
|
-
search_options = ActiveDocument::MarkLogicSearchOptions.new
|
103
|
-
end
|
104
|
-
if (search_options.searchable_expression.empty?)
|
105
|
-
search_options.searchable_expression[root_namespace] = root unless root.nil?
|
106
|
-
end
|
107
|
-
return search_options
|
108
|
-
end
|
109
|
-
|
110
|
-
end # end class
|
111
|
-
end # end module
|