activedocument 0.5 → 0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -221,7 +221,12 @@ module ActiveDocument
221
221
  else
222
222
  root_namespace = namespace_for_element(root)
223
223
  end
224
- execute_attribute_finder(element, attribute, value, root, element_namespace, attribute_namespace, root_namespace)
224
+ if arguments[6]
225
+ options = arguments[6]
226
+ else
227
+ options = nil
228
+ end
229
+ execute_attribute_finder(element, attribute, value, root, element_namespace, attribute_namespace, root_namespace, options)
225
230
  elsif method =~ /find_by_(.*)$/ and arguments.length > 0 # identify element search methods
226
231
  value = arguments[0]
227
232
  element = $1.to_sym
@@ -240,7 +245,14 @@ module ActiveDocument
240
245
  else
241
246
  root_namespace = namespace_for_element(root)
242
247
  end
243
- execute_finder(element, value, root, element_namespace, root_namespace)
248
+ if arguments[4]
249
+ options = arguments[4]
250
+ else
251
+ options = nil
252
+ end
253
+ execute_finder(element, value, root, element_namespace, root_namespace, options)
254
+ else
255
+ super
244
256
  end
245
257
 
246
258
  end
@@ -49,14 +49,14 @@ module ActiveDocument
49
49
  end
50
50
  end
51
51
 
52
- def self.execute_finder(element, value, root = nil, element_namespace = nil, root_namespace = nil)
53
- xquery = @@xquery_builder.find_by_element(element, value, root, element_namespace, root_namespace)
52
+ def self.execute_finder(element, value, root = nil, element_namespace = nil, root_namespace = nil, options = nil)
53
+ xquery = @@xquery_builder.find_by_element(element, value, root, element_namespace, root_namespace, options)
54
54
  @@log.info("Finder.execute_finder at line #{__LINE__}: #{xquery}")
55
55
  SearchResults.new(@@ml_http.send_xquery(xquery))
56
56
  end
57
57
 
58
- def self.execute_attribute_finder(element, attribute, value, root = nil, element_namespace = nil, attribute_namespace = nil, root_namespace = nil)
59
- xquery = @@xquery_builder.find_by_attribute(element, attribute, value, root, element_namespace, attribute_namespace, root_namespace)
58
+ def self.execute_attribute_finder(element, attribute, value, root = nil, element_namespace = nil, attribute_namespace = nil, root_namespace = nil, options = nil)
59
+ xquery = @@xquery_builder.find_by_attribute(element, attribute, value, root, element_namespace, attribute_namespace, root_namespace, options)
60
60
  @@log.info("Finder.execute_attribute_finder at line #{__LINE__}: #{xquery}")
61
61
  SearchResults.new(@@ml_http.send_xquery(xquery))
62
62
  end
@@ -11,7 +11,7 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
-
14
+ require 'ActiveDocument/mark_logic_search_options'
15
15
  module ActiveDocument
16
16
  # todo create new unit tests for this class - the old ones were no good
17
17
  class MarkLogicQueryBuilder
@@ -26,77 +26,47 @@ module ActiveDocument
26
26
 
27
27
  def save(document, uri)
28
28
  xquery = <<-GENERATED
29
- xdmp:document-insert(
30
- "#{uri}",
31
- #{document.to_s},
32
- xdmp:default-permissions(),
33
- xdmp:default-collections())
34
- GENERATED
35
-
29
+ xdmp:document-insert(
30
+ "#{uri}",
31
+ #{document.to_s} ,
32
+ xdmp:default-permissions(),
33
+ xdmp:default-collections())
34
+ GENERATED
36
35
  end
37
36
 
38
37
  # This method does a full text search
39
- def find_by_word(word, root, namespace)
38
+ def find_by_word(word, root, root_namespace, options = nil)
40
39
  xquery = <<-GENERATED
41
- import module namespace search = "http://marklogic.com/appservices/search"at "/MarkLogic/appservices/search/search.xqy";
40
+ import module namespace search = "http://marklogic.com/appservices/search" at "/MarkLogic/appservices/search/search.xqy";
42
41
  search:search("#{word}",
43
- <options xmlns="http://marklogic.com/appservices/search">
44
- GENERATED
45
- unless root.nil?
46
- xquery << "<searchable-expression"
47
-
48
- xquery << " xmlns:a=\"#{namespace}\"" unless namespace.nil? or namespace.empty?
49
- xquery << '>/'
50
- xquery << "a:" unless namespace.nil? or namespace.empty?
51
- xquery << "#{root}</searchable-expression>"
52
- end
53
- xquery << "</options>)"
42
+ GENERATED
43
+ search_options = setup_options(options, root, root_namespace)
44
+ xquery << search_options.to_s
45
+ xquery << ')'
54
46
  end
55
47
 
56
- def find_by_element(element, value, root, element_namespace, root_namespace)
48
+ def find_by_element(element, value, root, element_namespace, root_namespace, options = nil)
57
49
  xquery = <<-GENERATED
58
50
  import module namespace search = "http://marklogic.com/appservices/search"at "/MarkLogic/appservices/search/search.xqy";
59
- search:search("word:#{value}",
60
- <options xmlns="http://marklogic.com/appservices/search">
51
+ search:search('find_by_element:\"#{value}\"',
61
52
  GENERATED
62
- unless root.nil?
63
- xquery << "<searchable-expression"
64
- xquery << " xmlns:a=\"#{root_namespace}\"" unless root_namespace.nil?
65
- xquery << '>/'
66
- xquery << "a:" unless root_namespace.nil?
67
- xquery << "#{root}</searchable-expression>"
68
- end
69
- xquery << <<-CONSTRAINT
70
- <constraint name="word">
71
- <word>
72
- <element ns="#{element_namespace unless element_namespace.nil?}" name="#{element}"/>
73
- </word>
74
- </constraint></options>)
75
- CONSTRAINT
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 << ')'
76
57
  end
77
58
 
78
- def find_by_attribute(element, attribute, value, root, element_namespace, attribute_namespace, root_namespace)
79
- # todo should the searchable expression portion be refactored?
59
+
60
+ def find_by_attribute(element, attribute, value, root, element_namespace, attribute_namespace, root_namespace, options = nil)
80
61
  xquery = <<-GENERATED
81
- import module namespace search = "http://marklogic.com/appservices/search"at "/MarkLogic/appservices/search/search.xqy";
82
- search:search("word:#{value}",
83
- <options xmlns="http://marklogic.com/appservices/search">
62
+ import module namespace search = "http://marklogic.com/appservices/search" at "/MarkLogic/appservices/search/search.xqy";
63
+ search:search("attribute:#{value}",
84
64
  GENERATED
85
- unless root.nil?
86
- xquery << "<searchable-expression"
87
- xquery << " xmlns:a=\"#{root_namespace}\"" unless root_namespace.nil?
88
- xquery << '>/'
89
- xquery << "a:" unless root_namespace.nil?
90
- xquery << "#{root}</searchable-expression>"
91
- end
92
- xquery << <<-CONSTRAINT
93
- <constraint name="word">
94
- <word>
95
- <attribute ns="#{attribute_namespace unless attribute_namespace.nil?}" name="#{attribute}"/>
96
- <element ns="#{element_namespace unless element_namespace.nil?}" name="#{element}"/>
97
- </word>
98
- </constraint></options>)
99
- CONSTRAINT
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 << ')'
100
70
  end
101
71
 
102
72
  def search(search_text, start, page_length, options)
@@ -106,23 +76,36 @@ GENERATED
106
76
  option = options.to_s
107
77
  end
108
78
  <<-GENERATED
109
- import module namespace search = "http://marklogic.com/appservices/search"at "/MarkLogic/appservices/search/search.xqy";
110
- search:search('#{search_text}',#{option},#{start}, #{page_length})
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})
111
81
  GENERATED
112
82
  end
113
83
 
114
84
  def co_occurrence(element1, element1_namespace, element2, element2_namespace, query)
115
85
  <<-GENERATED
116
- declare namespace one = "#{element1_namespace}";
117
- declare namespace two = "#{element2_namespace}";
118
- import module namespace search = "http://marklogic.com/appservices/search"at "/MarkLogic/appservices/search/search.xqy";
119
- 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}')))
120
- return
121
- for $pair in $pairs
122
- return
123
- ($pair/cts:value[1]/text(),"|",$pair/cts:value[2]/text(),"|",cts:frequency($pair),"*")
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),"*")
124
94
  GENERATED
125
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
126
109
 
127
110
  end # end class
128
111
  end # end module
@@ -13,26 +13,45 @@
13
13
  # limitations under the License.
14
14
 
15
15
 
16
- # MarkLogicSearchOptions allow you to control exactly how the ActiveDocument::Finder#search method behaves and what additional
17
- # information may be returned in the ActiveDocument::SearchResults object
18
- # == Attributes
19
- # * return_facets - if true then facet information is returned in the resultant ActiveDocument::SearchResults object. Default is true
20
- # * value_constraints - this is a #Hash of value constraint names to their options. e.g. search_options_object.value_constraints["Region"] = {"namespace" => "http://wits.nctc.gov", "element" => "Region"}
21
16
  module ActiveDocument
17
+ # MarkLogicSearchOptions allow you to control exactly how the ActiveDocument::Finder#search method behaves and what additional
18
+ # information may be returned in the ActiveDocument::SearchResults object
19
+ # == Attributes
20
+ # * return_facets - if true then facet information is returned in the resultant ActiveDocument::SearchResults object. Default is true
21
+ # * value_constraints - Used for creating searches on the value of an element
22
+ # this is a #Hash of value constraint names to their options.
23
+ # e.g. search_options_object.value_constraints["Region"] = {"namespace" => "http://wits.nctc.gov", "element" => "Region"}
24
+ # * word_constraints - Used for creating searches for a word within an element value. This is a #Hash of word constaint names to their options
25
+ # this is a #Hash of value constraint names to their options.
26
+ # e.g. search_options_object.word_constraints["Region"] = {"namespace" => "http://wits.nctc.gov", "element" => "Region"}
27
+ # * range_constraints - Used for searching for a range of values, also for creating facets or doing co-occurents.
28
+ # This is a #hash of range_constraint names to their options
29
+ # e.g. search_options_object.range_constraints["Facility Type"] = {"namespace" => "http://wits.nctc.gov", "element" => "FacilityType", "type" => "xs:string", "collation" => "http://marklogic.com/collation/"}
30
+ # * directory_constraint - Used for specifying that the search should only executed for this directory, to the depth
31
+ # specified in directory_depth
32
+ # * searchable_expression - An expression to be searched. Whatever expression is specified is returned from the search.
33
+ # This is provided as a hash where the key is the element name and the value is the element's namespace. If there is no
34
+ # namespace then nil or "" should be passed as the value. eg search_options_object.searchable_expression["element"] = "namespace" or
35
+ # search_options_object.searchable_expression["element"] = "" if there is no namespace for element
22
36
  class MarkLogicSearchOptions
23
- attr_accessor :return_facets, :value_constraints, :word_constraints, :range_constraints
37
+ attr_accessor :return_facets, :value_constraints, :word_constraints, :attribute_constraints, :range_constraints, :directory_constraint, :directory_depth, :searchable_expression
24
38
 
25
39
  def initialize
26
40
  @return_facets = true;
27
41
  @value_constraints = Hash.new
28
42
  @word_constraints = Hash.new
43
+ @attribute_constraints = Hash.new
29
44
  @range_constraints = Hash.new
45
+ @searchable_expression = Hash.new
46
+ @directory_depth = 1
30
47
  end
31
48
 
32
-
33
49
  # outputs the object in correctly formatted XML suitable for use in a search
34
50
  def to_s
35
51
  constraints = String.new
52
+ additional_query = String.new
53
+ searchable_path = String.new
54
+
36
55
  @value_constraints.each do |key, value|
37
56
  constraints << <<-XML
38
57
  <constraint name="#{key.gsub(/\s/, '_')}">
@@ -53,6 +72,17 @@ module ActiveDocument
53
72
  XML
54
73
  end
55
74
 
75
+ @attribute_constraints.each do |constraint_name, attribute_constraint|
76
+ constraints << <<-XML
77
+ <constraint name="#{constraint_name.gsub(/\s/, '_')}">
78
+ <word>
79
+ <attribute ns="#{attribute_constraint.attribute_namespace unless attribute_constraint.attribute_namespace.nil?}" name="#{attribute_constraint.attribute}"/>
80
+ <element ns="#{attribute_constraint.element_namespace unless attribute_constraint.element_namespace.nil?}" name="#{attribute_constraint.element}"/>
81
+ </word>
82
+ </constraint>
83
+ XML
84
+ end
85
+
56
86
  @range_constraints.each do |key, value|
57
87
  constraints << <<-XML
58
88
  <constraint name="#{key.gsub(/\s/, '_')}">
@@ -75,15 +105,35 @@ module ActiveDocument
75
105
  constraints << "</range></constraint>"
76
106
  end
77
107
 
78
- value = <<-XML
79
- <options xmlns="http://marklogic.com/appservices/search">
80
- <return-facets>#{@return_facets}</return-facets>
81
- XML
108
+ # serialize the additional query information
109
+ if @directory_constraint
110
+ additional_query = "<additional-query>{cts:directory-query(\"#{directory_constraint}\", \"#{directory_depth}\")}</additional-query>"
111
+ end
112
+
113
+ # serialize the searchable_expression
114
+ if @searchable_expression.size > 0
115
+ searchable_path << "<searchable-expression"
116
+ searchable_path << " xmlns:a=\"#{@searchable_expression.keys[0]}\"" unless @searchable_expression.keys[0].nil? or @searchable_expression.keys[0].empty?
117
+ searchable_path << '>/'
118
+ searchable_path << "a:" unless @searchable_expression.keys[0].nil? or @searchable_expression.keys[0].empty?
119
+ searchable_path << "#{@searchable_expression.values[0]}</searchable-expression>"
120
+ end
121
+
122
+ value = "<options xmlns=\"http://marklogic.com/appservices/search\">"
123
+ unless additional_query.empty?
124
+ value << additional_query
125
+ end
82
126
 
83
127
  # add in constraints
84
128
  unless constraints.empty?
85
129
  value << constraints
86
130
  end
131
+ value << "<return-facets>#{@return_facets}</return-facets>"
132
+
133
+ # output the searchable expression
134
+ unless searchable_path.empty?
135
+ value << searchable_path
136
+ end
87
137
  # close the options node
88
138
  value << "</options>"
89
139
 
@@ -108,6 +158,18 @@ module ActiveDocument
108
158
  XML
109
159
  end
110
160
  end
161
+
162
+ class AttributeConstraint
163
+ attr_reader :attribute_namespace, :attribute, :element_namespace, :element
164
+
165
+ def initialize (attribute_namespace, attribute, element_namespace, element)
166
+ @attribute_namespace = attribute_namespace
167
+ @attribute = attribute
168
+ @element_namespace = element_namespace
169
+ @element = element
170
+ end
171
+ end
172
+
111
173
  end
112
174
 
113
175
  end
metadata CHANGED
@@ -4,8 +4,8 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 5
8
- version: "0.5"
7
+ - 6
8
+ version: "0.6"
9
9
  platform: ruby
10
10
  authors:
11
11
  - Clark D. Richey, Jr.
@@ -13,7 +13,7 @@ autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
15
 
16
- date: 2010-09-22 00:00:00 -07:00
16
+ date: 2010-11-03 00:00:00 -04:00
17
17
  default_executable:
18
18
  dependencies:
19
19
  - !ruby/object:Gem::Dependency