datamapper 0.3.2 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (180) hide show
  1. data/History.txt +0 -0
  2. data/Manifest.txt +5 -0
  3. data/README.txt +11 -0
  4. data/Rakefile +70 -0
  5. data/lib/datamapper.rb +8 -0
  6. metadata +152 -319
  7. data/CHANGELOG +0 -145
  8. data/FAQ +0 -96
  9. data/MIT-LICENSE +0 -22
  10. data/QUICKLINKS +0 -12
  11. data/README +0 -105
  12. data/environment.rb +0 -62
  13. data/example.rb +0 -156
  14. data/lib/data_mapper.rb +0 -88
  15. data/lib/data_mapper/adapters/abstract_adapter.rb +0 -43
  16. data/lib/data_mapper/adapters/data_object_adapter.rb +0 -480
  17. data/lib/data_mapper/adapters/mysql_adapter.rb +0 -72
  18. data/lib/data_mapper/adapters/postgresql_adapter.rb +0 -258
  19. data/lib/data_mapper/adapters/sql/coersion.rb +0 -134
  20. data/lib/data_mapper/adapters/sql/commands/load_command.rb +0 -545
  21. data/lib/data_mapper/adapters/sql/mappings/associations_set.rb +0 -34
  22. data/lib/data_mapper/adapters/sql/mappings/column.rb +0 -279
  23. data/lib/data_mapper/adapters/sql/mappings/conditions.rb +0 -172
  24. data/lib/data_mapper/adapters/sql/mappings/schema.rb +0 -60
  25. data/lib/data_mapper/adapters/sql/mappings/table.rb +0 -459
  26. data/lib/data_mapper/adapters/sql/quoting.rb +0 -24
  27. data/lib/data_mapper/adapters/sqlite3_adapter.rb +0 -159
  28. data/lib/data_mapper/associations.rb +0 -106
  29. data/lib/data_mapper/associations/belongs_to_association.rb +0 -160
  30. data/lib/data_mapper/associations/has_and_belongs_to_many_association.rb +0 -437
  31. data/lib/data_mapper/associations/has_many_association.rb +0 -283
  32. data/lib/data_mapper/associations/has_n_association.rb +0 -143
  33. data/lib/data_mapper/associations/reference.rb +0 -47
  34. data/lib/data_mapper/attributes.rb +0 -73
  35. data/lib/data_mapper/auto_migrations.rb +0 -36
  36. data/lib/data_mapper/base.rb +0 -17
  37. data/lib/data_mapper/callbacks.rb +0 -107
  38. data/lib/data_mapper/context.rb +0 -112
  39. data/lib/data_mapper/database.rb +0 -234
  40. data/lib/data_mapper/dependency_queue.rb +0 -28
  41. data/lib/data_mapper/embedded_value.rb +0 -145
  42. data/lib/data_mapper/identity_map.rb +0 -47
  43. data/lib/data_mapper/is/tree.rb +0 -121
  44. data/lib/data_mapper/migration.rb +0 -155
  45. data/lib/data_mapper/persistence.rb +0 -852
  46. data/lib/data_mapper/property.rb +0 -310
  47. data/lib/data_mapper/query.rb +0 -164
  48. data/lib/data_mapper/support/blank.rb +0 -35
  49. data/lib/data_mapper/support/connection_pool.rb +0 -117
  50. data/lib/data_mapper/support/enumerable.rb +0 -35
  51. data/lib/data_mapper/support/errors.rb +0 -16
  52. data/lib/data_mapper/support/inflector.rb +0 -265
  53. data/lib/data_mapper/support/object.rb +0 -54
  54. data/lib/data_mapper/support/serialization.rb +0 -96
  55. data/lib/data_mapper/support/silence.rb +0 -10
  56. data/lib/data_mapper/support/string.rb +0 -72
  57. data/lib/data_mapper/support/struct.rb +0 -7
  58. data/lib/data_mapper/support/symbol.rb +0 -82
  59. data/lib/data_mapper/support/typed_set.rb +0 -65
  60. data/lib/data_mapper/types/base.rb +0 -44
  61. data/lib/data_mapper/types/string.rb +0 -34
  62. data/lib/data_mapper/validatable_extensions/errors.rb +0 -12
  63. data/lib/data_mapper/validatable_extensions/macros.rb +0 -7
  64. data/lib/data_mapper/validatable_extensions/validatable_instance_methods.rb +0 -62
  65. data/lib/data_mapper/validatable_extensions/validation_base.rb +0 -18
  66. data/lib/data_mapper/validatable_extensions/validations/formats/email.rb +0 -43
  67. data/lib/data_mapper/validatable_extensions/validations/validates_acceptance_of.rb +0 -7
  68. data/lib/data_mapper/validatable_extensions/validations/validates_confirmation_of.rb +0 -7
  69. data/lib/data_mapper/validatable_extensions/validations/validates_each.rb +0 -7
  70. data/lib/data_mapper/validatable_extensions/validations/validates_format_of.rb +0 -28
  71. data/lib/data_mapper/validatable_extensions/validations/validates_length_of.rb +0 -15
  72. data/lib/data_mapper/validatable_extensions/validations/validates_numericality_of.rb +0 -7
  73. data/lib/data_mapper/validatable_extensions/validations/validates_presence_of.rb +0 -7
  74. data/lib/data_mapper/validatable_extensions/validations/validates_true_for.rb +0 -7
  75. data/lib/data_mapper/validatable_extensions/validations/validates_uniqueness_of.rb +0 -40
  76. data/lib/data_mapper/validations.rb +0 -20
  77. data/lib/data_mapper/validations/number_validator.rb +0 -40
  78. data/lib/data_mapper/validations/string_validator.rb +0 -20
  79. data/lib/data_mapper/validations/validator.rb +0 -13
  80. data/performance.rb +0 -307
  81. data/plugins/can_has_sphinx/LICENSE +0 -23
  82. data/plugins/can_has_sphinx/README +0 -4
  83. data/plugins/can_has_sphinx/REVISION +0 -1
  84. data/plugins/can_has_sphinx/Rakefile +0 -22
  85. data/plugins/can_has_sphinx/init.rb +0 -1
  86. data/plugins/can_has_sphinx/install.rb +0 -1
  87. data/plugins/can_has_sphinx/lib/acts_as_sphinx.rb +0 -123
  88. data/plugins/can_has_sphinx/lib/sphinx.rb +0 -460
  89. data/plugins/can_has_sphinx/scripts/sphinx.sh +0 -47
  90. data/plugins/can_has_sphinx/tasks/acts_as_sphinx_tasks.rake +0 -41
  91. data/profile_data_mapper.rb +0 -40
  92. data/rakefile.rb +0 -159
  93. data/spec/acts_as_tree_spec.rb +0 -67
  94. data/spec/adapters/data_object_adapter_spec.rb +0 -31
  95. data/spec/associations/belongs_to_association_spec.rb +0 -98
  96. data/spec/associations/has_and_belongs_to_many_association_spec.rb +0 -377
  97. data/spec/associations/has_many_association_spec.rb +0 -337
  98. data/spec/attributes_spec.rb +0 -52
  99. data/spec/auto_migrations_spec.rb +0 -101
  100. data/spec/callbacks_spec.rb +0 -186
  101. data/spec/can_has_sphinx.rb +0 -5
  102. data/spec/coersion_spec.rb +0 -41
  103. data/spec/column_spec.rb +0 -114
  104. data/spec/count_command_spec.rb +0 -45
  105. data/spec/database_spec.rb +0 -18
  106. data/spec/dataobjects_spec.rb +0 -27
  107. data/spec/delete_command_spec.rb +0 -11
  108. data/spec/dependency_spec.rb +0 -29
  109. data/spec/embedded_value_spec.rb +0 -161
  110. data/spec/fixtures/animals.yaml +0 -33
  111. data/spec/fixtures/animals_exhibits.yaml +0 -2
  112. data/spec/fixtures/careers.yaml +0 -5
  113. data/spec/fixtures/comments.yaml +0 -1
  114. data/spec/fixtures/exhibits.yaml +0 -90
  115. data/spec/fixtures/fruit.yaml +0 -6
  116. data/spec/fixtures/people.yaml +0 -37
  117. data/spec/fixtures/posts.yaml +0 -3
  118. data/spec/fixtures/projects.yaml +0 -13
  119. data/spec/fixtures/sections.yaml +0 -5
  120. data/spec/fixtures/serializers.yaml +0 -6
  121. data/spec/fixtures/tasks.yaml +0 -6
  122. data/spec/fixtures/tasks_tasks.yaml +0 -2
  123. data/spec/fixtures/tomatoes.yaml +0 -1
  124. data/spec/fixtures/users.yaml +0 -1
  125. data/spec/fixtures/zoos.yaml +0 -24
  126. data/spec/is_a_tree_spec.rb +0 -149
  127. data/spec/legacy_spec.rb +0 -16
  128. data/spec/load_command_spec.rb +0 -322
  129. data/spec/magic_columns_spec.rb +0 -26
  130. data/spec/migration_spec.rb +0 -267
  131. data/spec/mock_adapter.rb +0 -20
  132. data/spec/models/animal.rb +0 -12
  133. data/spec/models/candidate.rb +0 -8
  134. data/spec/models/career.rb +0 -7
  135. data/spec/models/chain.rb +0 -8
  136. data/spec/models/comment.rb +0 -6
  137. data/spec/models/exhibit.rb +0 -14
  138. data/spec/models/fence.rb +0 -7
  139. data/spec/models/fruit.rb +0 -8
  140. data/spec/models/job.rb +0 -8
  141. data/spec/models/person.rb +0 -30
  142. data/spec/models/post.rb +0 -14
  143. data/spec/models/project.rb +0 -41
  144. data/spec/models/sales_person.rb +0 -5
  145. data/spec/models/section.rb +0 -8
  146. data/spec/models/serializer.rb +0 -5
  147. data/spec/models/task.rb +0 -9
  148. data/spec/models/tomato.rb +0 -27
  149. data/spec/models/user.rb +0 -12
  150. data/spec/models/zoo.rb +0 -13
  151. data/spec/natural_key_spec.rb +0 -36
  152. data/spec/paranoia_spec.rb +0 -38
  153. data/spec/persistence_spec.rb +0 -479
  154. data/spec/postgres_spec.rb +0 -96
  155. data/spec/property_spec.rb +0 -151
  156. data/spec/query_spec.rb +0 -77
  157. data/spec/save_command_spec.rb +0 -94
  158. data/spec/schema_spec.rb +0 -8
  159. data/spec/serialize_spec.rb +0 -19
  160. data/spec/single_table_inheritance_spec.rb +0 -43
  161. data/spec/spec_helper.rb +0 -45
  162. data/spec/support/blank_spec.rb +0 -8
  163. data/spec/support/inflector_spec.rb +0 -41
  164. data/spec/support/object_spec.rb +0 -9
  165. data/spec/support/serialization_spec.rb +0 -61
  166. data/spec/support/silence_spec.rb +0 -15
  167. data/spec/support/string_spec.rb +0 -7
  168. data/spec/support/struct_spec.rb +0 -12
  169. data/spec/support/typed_set_spec.rb +0 -66
  170. data/spec/symbolic_operators_spec.rb +0 -27
  171. data/spec/table_spec.rb +0 -79
  172. data/spec/types/string.rb +0 -81
  173. data/spec/validates_confirmation_of_spec.rb +0 -55
  174. data/spec/validates_format_of_spec.rb +0 -78
  175. data/spec/validates_length_of_spec.rb +0 -117
  176. data/spec/validates_uniqueness_of_spec.rb +0 -92
  177. data/spec/validations/number_validator.rb +0 -59
  178. data/spec/validations/string_validator.rb +0 -14
  179. data/spec/validations_spec.rb +0 -141
  180. data/tasks/fixtures.rb +0 -53
@@ -1,23 +0,0 @@
1
- Copyright (C) 2005 Kent Sibilev <ksibilev@yahoo.com>
2
- All rights reserved.
3
- *
4
- Redistribution and use in source and binary forms, with or without
5
- modification, are permitted provided that the following conditions
6
- are met:
7
- 1. Redistributions of source code must retain the above copyright
8
- notice, this list of conditions and the following disclaimer.
9
- 2. Redistributions in binary form must reproduce the above copyright
10
- notice, this list of conditions and the following disclaimer in the
11
- documentation and/or other materials provided with the distribution.
12
- *
13
- THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
14
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16
- ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
17
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19
- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21
- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22
- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23
- SUCH DAMAGE.
@@ -1,4 +0,0 @@
1
- ActsAsSphinx
2
- ============
3
-
4
- Description goes here
@@ -1 +0,0 @@
1
- 21
@@ -1,22 +0,0 @@
1
- require 'rake'
2
- require 'rake/testtask'
3
- require 'rake/rdoctask'
4
-
5
- desc 'Default: run unit tests.'
6
- task :default => :test
7
-
8
- desc 'Test the acts_as_sphinx plugin.'
9
- Rake::TestTask.new(:test) do |t|
10
- t.libs << 'lib'
11
- t.pattern = 'test/**/*_test.rb'
12
- t.verbose = true
13
- end
14
-
15
- desc 'Generate documentation for the acts_as_sphinx plugin.'
16
- Rake::RDocTask.new(:rdoc) do |rdoc|
17
- rdoc.rdoc_dir = 'rdoc'
18
- rdoc.title = 'ActsAsSphinx'
19
- rdoc.options << '--line-numbers' << '--inline-source'
20
- rdoc.rdoc_files.include('README')
21
- rdoc.rdoc_files.include('lib/**/*.rb')
22
- end
@@ -1 +0,0 @@
1
- require "acts_as_sphinx"
@@ -1 +0,0 @@
1
- # Install hook code here
@@ -1,123 +0,0 @@
1
- require "sphinx"
2
-
3
- module ActsAsSphinx
4
- module ClassMethods
5
- # Associates the model class with a sphinx index, which will be used by find_with_sphinx method.
6
- # You can pass the following options:
7
- #
8
- # :host is the host name or an IP address where searchd daemon is running, default is localhost
9
- # :port is the port number of the searchd process, default is 3312
10
- # :index is the name of the index to be used, default is the name of the table for the current model class.
11
- def acts_as_sphinx(options = {})
12
- options.assert_valid_keys(SphinxClassMethods::VALID_OPTIONS)
13
-
14
- default_options = {:host => 'localhost', :port => 3312, :index => name.tableize}
15
- write_inheritable_attribute 'sphinx_options', options.reverse_merge(default_options)
16
- extend SphinxClassMethods
17
- end
18
- end
19
-
20
- def self.included(receiver)
21
- receiver.extend(ClassMethods)
22
- end
23
-
24
- module SphinxClassMethods
25
- VALID_OPTIONS = %w[mode offset page limit index weights host
26
- port range filter filter_range group_by sort_mode].map(&:to_sym)
27
-
28
- def sphinx_index
29
- read_inheritable_attribute('sphinx_options')[:index]
30
- end
31
-
32
- def sphinx_options
33
- read_inheritable_attribute 'sphinx_options'
34
- end
35
-
36
- # Performs a sphinx search and returns a hash object as defined by Sphinx#query method.
37
- # This methods accepts the same set of options as :sphinx option of find_with_sphinx method.
38
- def ask_sphinx(query, options = {})
39
- options.assert_valid_keys(VALID_OPTIONS)
40
-
41
- default_options = {:offset => 0, :limit => 20}
42
- default_options.merge! sphinx_options
43
- options.reverse_merge! default_options
44
-
45
- if options[:page] && options[:limit]
46
- options[:offset] = options[:limit] * (options[:page].to_i - 1)
47
- options[:offset] = 0 if options[:offset] < 0
48
- end
49
-
50
- sphinx = Sphinx.new
51
- sphinx.set_server options[:host], options[:port]
52
- sphinx.set_limits options[:offset], options[:limit]
53
- sphinx.set_weights options[:weights] if options[:weights]
54
- sphinx.set_id_range options[:range] if options[:range]
55
-
56
- options[:filter].each do |attr, values|
57
- sphinx.set_filter attr, [*values]
58
- end if options[:filter]
59
-
60
- options[:filter_range].each do |attr, (min, max)|
61
- sphinx.set_filter_range attr, min, max
62
- end if options[:filter_range]
63
-
64
- options[:group_by].each do |attr, func|
65
- funcion = Sphinx.const_get("SPH_GROUPBY_#{func.to_s.upcase}") \
66
- rescue raise("Unknown group by function #{func}")
67
- sphinx.set_group_by attr, funcion
68
- end if options[:group_by]
69
-
70
- if options[:mode]
71
- match_mode = Sphinx.const_get("SPH_MATCH_#{options[:mode].to_s.upcase}") \
72
- rescue raise("Unknown search mode #{options[:mode]}")
73
- sphinx.set_match_mode match_mode
74
- end
75
-
76
- if options[:sort_mode]
77
- sort_mode, sort_expr = options[:sort_mode]
78
- sort_mode = Sphinx.const_get("SPH_SORT_#{sort_mode.to_s.upcase}") \
79
- rescue raise("Unknown sort mode #{sort_mode}")
80
- sphinx.set_sort_mode sort_mode, sort_expr
81
- end
82
-
83
- sphinx.query query, options[:index]
84
- end
85
-
86
- # Find all model objects using sphinx index.
87
- # Besides regular ActiveRecord::Base#find method's options, you can specify
88
- # :sphinx key that points to a hash with the following sphinx specific parameters:
89
- #
90
- # :mode defines the search mode (:all, :any, :boolean, :extended)
91
- # :sort_mode defines the sort mode (:relevance, :attr_desc, :attr_asc, :time_segments, :extended),
92
- # for example :sort_mode => [:attr_desc, 'myattr']
93
- # :limit restricts result to a specified number of objects, default is 20
94
- # :offset make this method return from a specific offset, default is 0
95
- # :page can be used instead of :offset option to specify the page number
96
- # :host overrides the default value of this option, see acts_as_sphinx method
97
- # :port overrides the default value of this option, see acts_as_sphinx method
98
- # :index overrides the default index name
99
- # :weight is an array of weights for each index component (used in the relevance algorithm)
100
- # :range is an array that defines the range document ids to be used, e.g. :range => [min, max]
101
- # :fiter and :filter_range
102
- # options define a search filter by an attribute
103
- # :group_by makes the search result to be grouped by an attribute, e.g. :group_by => [attr, function],
104
- # where function is :day, :week, :month, :year, or :attr
105
- #
106
- # The returned array has three special attributes:
107
- #
108
- # ary.total returns a total hits retrieved for this search
109
- # ary.total_found returns a total number of hits found while scanning indexes.
110
- # ary.time returns a time spent performing the search.
111
- def find_with_sphinx(query, options = {})
112
- result = ask_sphinx(query, options.delete(:sphinx) || {})
113
- records = result[:matches].empty? ? [] : find(result[:matches].keys, options)
114
- records = records.sort_by{|r| -result[:matches][r.id][:weight] }
115
- %w[total total_found time].map(&:to_sym).each do |method|
116
- class << records; self end.send(:define_method, method) {result[method]}
117
- end
118
- records
119
- end
120
- end
121
- end
122
-
123
- ActiveRecord::Base.send :include, ActsAsSphinx
@@ -1,460 +0,0 @@
1
- require "socket"
2
- # = sphinx.rb - Sphinx Client Library
3
- #
4
- # Author:: Dmytro Shteflyuk <mailto:kpumuk@kpumuk.info>.
5
- # Copyright:: Copyright (c) 2006 Wildbit, LLC
6
- # License:: Distributes under the same terms as Ruby
7
- #
8
- # This library is distributed under the terms of the Ruby license.
9
- # You can freely distribute/modify this library.
10
-
11
- # ==Sphinx Client Library
12
- #
13
- # The Sphinx Client Library is used to communicate with <tt>searchd</tt>
14
- # daemon and get search results from Sphinx.
15
- #
16
- # ===Usage
17
- #
18
- # sphinx = Sphinx.new
19
- # result = sphinx.query('test')
20
- # ids = result[:matches].map { |id, value| id }.join(',')
21
- # posts = Post.find :all, :conditions => "id IN (#{ids})"
22
- #
23
- # docs = posts.map { |post| post.body }
24
- # excerpts = sphinx.build_excerpts(docs, 'index', 'test')
25
- #
26
- class Sphinx
27
-
28
- # :stopdoc:
29
- class SphinxError < StandardError; end
30
- class SphinxConnectError < SphinxError; end
31
- class SphinxResponseError < SphinxError; end
32
- class SphinxInternalError < SphinxError; end
33
- class SphinxTemporaryError < SphinxError; end
34
- class SphinxUnknownError < SphinxError; end
35
- # :startdoc:
36
-
37
- # known searchd commands
38
- SEARCHD_COMMAND_SEARCH = 0
39
- SEARCHD_COMMAND_EXCERPT = 1
40
-
41
- # current client-side command implementation versions
42
- VER_COMMAND_SEARCH = 0x104
43
- VER_COMMAND_EXCERPT = 0x100
44
-
45
- # known searchd status codes
46
- SEARCHD_OK = 0
47
- SEARCHD_ERROR = 1
48
- SEARCHD_RETRY = 2
49
-
50
- # known match modes
51
- SPH_MATCH_ALL = 0
52
- SPH_MATCH_ANY = 1
53
- SPH_MATCH_PHRASE = 2
54
- SPH_MATCH_BOOLEAN = 3
55
- SPH_MATCH_EXTENDED = 4
56
-
57
- # known sort modes
58
- SPH_SORT_RELEVANCE = 0
59
- SPH_SORT_ATTR_DESC = 1
60
- SPH_SORT_ATTR_ASC = 2
61
- SPH_SORT_TIME_SEGMENTS = 3
62
- SPH_SORT_EXTENDED = 4
63
-
64
- # known attribute types
65
- SPH_ATTR_INTEGER = 1
66
- SPH_ATTR_TIMESTAMP = 2
67
-
68
- # known grouping functions
69
- SPH_GROUPBY_DAY = 0
70
- SPH_GROUPBY_WEEK = 1
71
- SPH_GROUPBY_MONTH = 2
72
- SPH_GROUPBY_YEAR = 3
73
- SPH_GROUPBY_ATTR = 4
74
-
75
- # Constructs the Sphinx object and sets options to their default values.
76
- def initialize
77
- @host = 'localhost' # searchd host (default is "localhost")
78
- @port = 3312 # searchd port (default is 3312)
79
- @offset = 0 # how much records to seek from result-set start (default is 0)
80
- @limit = 20 # how much records to return from result-set starting at offset (default is 20)
81
- @mode = SPH_MATCH_ALL # query matching mode (default is SPH_MATCH_ALL)
82
- @weights = [] # per-field weights (default is 1 for all fields)
83
- @sort = SPH_SORT_RELEVANCE # match sorting mode (default is SPH_SORT_RELEVANCE)
84
- @sortby = '' # attribute to sort by (defualt is "")
85
- @min_id = 0 # min ID to match (default is 0)
86
- @max_id = 0xFFFFFFFF # max ID to match (default is UINT_MAX)
87
- @min = {} # attribute name to min-value hash (for range filters)
88
- @max = {} # attribute name to max-value hash (for range filters)
89
- @filter = {} # attribute name to values set hash (for values-set filters)
90
- @groupby = '' # group-by attribute name
91
- @groupfunc = SPH_GROUPBY_DAY # function to pre-process group-by attribute value with
92
- @maxmatches = 1000 # max matches to retrieve
93
-
94
- @error = '' # last error message
95
- @warning = '' # last warning message
96
- end
97
-
98
- # Get last error message.
99
- def last_error
100
- @error
101
- end
102
-
103
- # Get last warning message.
104
- def last_warning
105
- @warning
106
- end
107
-
108
- # Set searchd server.
109
- def set_server(host, port)
110
- @host = host
111
- @port = port
112
- end
113
-
114
- # Set match offset, count, and max number to retrieve.
115
- def set_limits(offset, limit, max = 0)
116
- @offset = offset
117
- @limit = limit
118
- @maxmatches = max if max > 0
119
- end
120
-
121
- # Set match mode.
122
- def set_match_mode(mode)
123
- @mode = mode
124
- end
125
-
126
- # Set sort mode.
127
- def set_sort_mode(mode, sortby = '')
128
- @sort = mode
129
- @sortby = sortby
130
- end
131
-
132
- # Set per-field weights.
133
- def set_weights(weights)
134
- @weights = weights
135
- end
136
-
137
- # Set IDs range to match.
138
- #
139
- # Only match those records where document ID is beetwen <tt>min_id</tt> and <tt>max_id</tt>
140
- # (including <tt>min_id</tt> and <tt>max_id</tt>).
141
- def set_id_range(min_id, max_id)
142
- @min_id = min_id
143
- @max_id = max_id
144
- end
145
-
146
- # Set values filter.
147
- #
148
- # Only match those records where <tt>attr</tt> column values
149
- # are in specified set.
150
- def set_filter(attr, values)
151
- @filter[attr] = values
152
- end
153
-
154
- # Set range filter.
155
- #
156
- # Only match those records where <tt>attr</tt> column value
157
- # is beetwen <tt>min</tt> and <tt>max</tt> (including <tt>min</tt> and <tt>max</tt>).
158
- def set_filter_range(attr, min, max)
159
- @min[attr] = min
160
- @max[attr] = max
161
- end
162
-
163
- # Set grouping.
164
- #
165
- # if grouping
166
- def set_group_by(attr, func)
167
- @groupby = attr
168
- @groupfunc = func
169
- end
170
-
171
- # Connect to searchd server and run given search query.
172
- #
173
- # * <tt>query</tt> -- query string
174
- # * <tt>index</tt> -- index name to query, default is "*" which means to query all indexes
175
- #
176
- # returns hash which has the following keys on success:
177
- #
178
- # * <tt>:matches</tt> -- hash which maps found document_id to ( "weight", "group" ) hash
179
- # * <tt>:total</tt> -- total amount of matches retrieved (upto SPH_MAX_MATCHES, see sphinx.h)
180
- # * <tt>:total_found</tt> -- total amount of matching documents in index
181
- # * <tt>:time</tt> -- search time
182
- # * <tt>:words</tt> -- hash which maps query terms (stemmed!) to ( :docs, :hits ) hash
183
- def query(query, index = '*')
184
- sock = connect
185
-
186
- # build request
187
-
188
- # mode and limits
189
- req = [@offset, @limit, @mode, @sort].pack('NNNN')
190
- req << [@sortby.length].pack('N')
191
- req << @sortby
192
- # query itself
193
- req << [query.length].pack('N')
194
- req << query
195
- # weights
196
- req << [@weights.length].pack('N')
197
- req << @weights.pack('N' * @weights.length)
198
- # indexes
199
- req << [index.length].pack('N')
200
- req << index
201
- # id range
202
- req << [@min_id.to_i, @max_id.to_i].pack('NN')
203
-
204
- # filters
205
- req << [@min.length + @filter.length].pack('N')
206
- @min.each do |attribute, min|
207
- req << [attribute.length].pack('N')
208
- req << attribute
209
- req << [0, min, @max[attribute]].pack('NNN')
210
- end
211
-
212
- @filter.each do |attribute, values|
213
- req << [attribute.length].pack('N')
214
- req << attribute
215
- req << [values.length].pack('N')
216
- req << values.pack('N' * values.length)
217
- end
218
-
219
- # group-by
220
- req << [@groupfunc, @groupby.length].pack('NN')
221
- req << @groupby
222
-
223
- # max matches to retrieve
224
- req << [@maxmatches].pack('N')
225
-
226
- # send query, get response
227
- len = req.length
228
- # add header
229
- req = [SEARCHD_COMMAND_SEARCH, VER_COMMAND_SEARCH, len].pack('nnN') + req
230
- sock.send(req, 0)
231
-
232
- response = get_response(sock, VER_COMMAND_SEARCH)
233
-
234
- # parse response
235
- result = {}
236
- max = response.length # protection from broken response
237
-
238
- #read schema
239
- p = 0
240
- fields = []
241
- attrs = {}
242
-
243
- nfields = response[p, 4].unpack('N*').first
244
- p += 4
245
- while nfields > 0 and p < max
246
- nfields -= 1
247
- len = response[p, 4].unpack('N*').first
248
- p += 4
249
- fields << response[p, len]
250
- p += len
251
- end
252
- result[:fields] = fields
253
-
254
- nattrs = response[p, 4].unpack('N*').first
255
- p += 4
256
- while nattrs > 0 && p < max
257
- nattrs -= 1
258
- len = response[p, 4].unpack('N*').first
259
- p += 4
260
- attr = response[p, len]
261
- p += len
262
- type = response[p, 4].unpack('N*').first
263
- p += 4
264
- attrs[attr.to_sym] = type;
265
- end
266
- result[:attrs] = attrs
267
-
268
- # read match count
269
- count = response[p, 4].unpack('N*').first
270
- p += 4
271
-
272
- # read matches
273
- result[:matches] = {}
274
- while count > 0 and p < max
275
- count -= 1
276
- doc, weight = response[p, 8].unpack('N*N*')
277
- p += 8
278
-
279
- result[:matches][doc] ||= {}
280
- result[:matches][doc][:weight] = weight
281
- attrs.each do |attr, type|
282
- val = response[p, 4].unpack('N*').first
283
- p += 4
284
- result[:matches][doc][:attrs] ||= {}
285
- result[:matches][doc][:attrs][attr] = val
286
- end
287
- end
288
- result[:total], result[:total_found], result[:time], words = \
289
- response[p, 16].unpack('N*N*N*N*')
290
- result[:time] = '%.3f' % (result[:time] / 1000)
291
- p += 16
292
-
293
- result[:words] = {}
294
- while words > 0 and p < max
295
- words -= 1
296
- len = response[p, 4].unpack('N*').first
297
- p += 4
298
- word = response[p, len]
299
- p += len
300
- docs, hits = response[p, 8].unpack('N*N*')
301
- p += 8
302
- result[:words][word] = {:docs => docs, :hits => hits}
303
- end
304
-
305
- result
306
- end
307
-
308
- # Connect to searchd server and generate exceprts from given documents.
309
- #
310
- # * <tt>index</tt> -- a string specifiying the index which settings will be used
311
- # for stemming, lexing and case folding
312
- # * <tt>docs</tt> -- an array of strings which represent the documents' contents
313
- # * <tt>words</tt> -- a string which contains the words to highlight
314
- # * <tt>opts</tt> is a hash which contains additional optional highlighting parameters.
315
- #
316
- # You can use following parameters:
317
- # * <tt>:before_match</tt> -- a string to insert before a set of matching words, default is "<b>"
318
- # * <tt>:after_match</tt> -- a string to insert after a set of matching words, default is "<b>"
319
- # * <tt>:chunk_separator</tt> -- a string to insert between excerpts chunks, default is " ... "
320
- # * <tt>:limit</tt> -- max excerpt size in symbols (codepoints), default is 256
321
- # * <tt>:around</tt> -- how much words to highlight around each match, default is 5
322
- #
323
- # Returns an array of string excerpts on success.
324
- def build_excerpts(docs, index, words, opts = {})
325
- sock = connect
326
-
327
- # fixup options
328
- opts[:before_match] ||= '<b>';
329
- opts[:after_match] ||= '</b>';
330
- opts[:chunk_separator] ||= ' ... ';
331
- opts[:limit] ||= 256;
332
- opts[:around] ||= 5;
333
-
334
- # build request
335
-
336
- # v.1.0 req
337
- req = [0, 1].pack('N2'); # mode=0, flags=1 (remove spaces)
338
- # req index
339
- req << [index.length].pack('N')
340
- req << index
341
- # req words
342
- req << [words.length].pack('N')
343
- req << words
344
-
345
- # options
346
- req << [opts[:before_match].length].pack('N')
347
- req << opts[:before_match]
348
- req << [opts[:after_match].length].pack('N')
349
- req << opts[:after_match]
350
- req << [opts[:chunk_separator].length].pack('N')
351
- req << opts[:chunk_separator]
352
- req << [opts[:limit].to_i, opts[:around].to_i].pack('NN')
353
-
354
- # documents
355
- req << [docs.size].pack('N');
356
- docs.each do |doc|
357
- req << [doc.length].pack('N')
358
- req << doc
359
- end
360
-
361
- # send query, get response
362
- len = req.length
363
- # add header
364
- req = [SEARCHD_COMMAND_EXCERPT, VER_COMMAND_EXCERPT, len].pack('nnN') + req
365
- sock.send(req, 0)
366
-
367
- response = get_response(sock, VER_COMMAND_EXCERPT)
368
-
369
- # parse response
370
- p = 0
371
- res = []
372
- rlen = response.length
373
- docs.each do |doc|
374
- len = response[p, 4].unpack('N*').first;
375
- p += 4
376
- if p + len > rlen
377
- @error = 'incomplete reply'
378
- raise SphinxResponseError, @error
379
- end
380
- res << response[p, len]
381
- p += len
382
- end
383
- return res;
384
- end
385
-
386
- # Connect to searchd server.
387
- def connect
388
- begin
389
- sock = TCPSocket.new(@host, @port)
390
- rescue
391
- @error = "connection to #{@host}:#{@port} failed"
392
- raise SphinxConnectError, @error
393
- end
394
-
395
- v = sock.recv(4).unpack('N*').first
396
- if v < 1
397
- sock.close
398
- @error = "expected searchd protocol version 1+, got version '#{v}'"
399
- raise SphinxConnectError, @error
400
- end
401
-
402
- sock.send([1].pack('N'), 0)
403
- sock
404
- end
405
- private :connect
406
-
407
- # get and check response packet from searchd server
408
- def get_response(sock, client_version)
409
- header = sock.recv(8)
410
- status, ver, len = header.unpack('n2N')
411
- response = ''
412
- left = len
413
- while left > 0 do
414
- begin
415
- chunk = sock.recv(left)
416
- if chunk
417
- response << chunk
418
- left -= chunk.length
419
- end
420
- rescue EOFError
421
- end
422
- end if left
423
- sock.close
424
-
425
- # check response
426
- read = response.length
427
- if not response or read != len
428
- @error = len \
429
- ? "failed to read searchd response (status=#{status}, ver=#{ver}, len=#{len}, read=#{read})" \
430
- : "received zero-sized searchd response"
431
- raise SphinxResponseError, @error
432
- end
433
-
434
- # check status
435
- if status == SEARCHD_ERROR
436
- @error = "searchd error: " + response[4,].to_s
437
- raise SphinxInternalError, @error
438
- end
439
-
440
- if status == SEARCHD_RETRY
441
- @error = "temporary searchd error: " + response[4,]
442
- raise SphinxTemporaryError, @error
443
- end
444
-
445
- unless status == SEARCHD_OK
446
- @error = "unknown status code '#{status}'"
447
- raise SphinxUnknownError, @error
448
- end
449
-
450
- # check version
451
- if ver < client_version
452
- @warning = "searchd command v.%d.%d older than client's v.%d.%d, some options might not work" % \
453
- ver >> 8, ver & 0xff, client_ver >> 8, client_ver & 0xff
454
- end
455
-
456
- return response
457
- end
458
- private :get_response
459
-
460
- end