stretchy-model 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +1 -1
  3. data/README.md +19 -84
  4. data/lib/rails/instrumentation/railtie.rb +2 -0
  5. data/lib/stretchy/associations.rb +155 -15
  6. data/lib/stretchy/attributes/type/array.rb +20 -0
  7. data/lib/stretchy/attributes/type/base.rb +42 -0
  8. data/lib/stretchy/attributes/type/binary.rb +45 -0
  9. data/lib/stretchy/attributes/type/boolean.rb +48 -0
  10. data/lib/stretchy/attributes/type/completion.rb +25 -0
  11. data/lib/stretchy/attributes/type/constant_keyword.rb +38 -0
  12. data/lib/stretchy/attributes/type/date_time.rb +35 -0
  13. data/lib/stretchy/attributes/type/dense_vector.rb +59 -0
  14. data/lib/stretchy/attributes/type/flattened.rb +31 -0
  15. data/lib/stretchy/attributes/type/geo_point.rb +27 -0
  16. data/lib/stretchy/attributes/type/geo_shape.rb +27 -0
  17. data/lib/stretchy/attributes/type/hash.rb +40 -0
  18. data/lib/stretchy/attributes/type/histogram.rb +7 -0
  19. data/lib/stretchy/attributes/type/ip.rb +29 -0
  20. data/lib/stretchy/attributes/type/join.rb +22 -0
  21. data/lib/stretchy/attributes/type/keyword.rb +36 -10
  22. data/lib/stretchy/attributes/type/match_only_text.rb +8 -0
  23. data/lib/stretchy/attributes/type/nested.rb +25 -0
  24. data/lib/stretchy/attributes/type/numeric/base.rb +32 -0
  25. data/lib/stretchy/attributes/type/numeric/byte.rb +7 -0
  26. data/lib/stretchy/attributes/type/numeric/double.rb +7 -0
  27. data/lib/stretchy/attributes/type/numeric/float.rb +7 -0
  28. data/lib/stretchy/attributes/type/numeric/half_float.rb +7 -0
  29. data/lib/stretchy/attributes/type/numeric/integer.rb +7 -0
  30. data/lib/stretchy/attributes/type/numeric/long.rb +7 -0
  31. data/lib/stretchy/attributes/type/numeric/scaled_float.rb +23 -0
  32. data/lib/stretchy/attributes/type/numeric/short.rb +7 -0
  33. data/lib/stretchy/attributes/type/numeric/unsigned_long.rb +7 -0
  34. data/lib/stretchy/attributes/type/percolator.rb +23 -0
  35. data/lib/stretchy/attributes/type/point.rb +24 -0
  36. data/lib/stretchy/attributes/type/range/base.rb +9 -0
  37. data/lib/stretchy/attributes/type/range/date_range.rb +17 -0
  38. data/lib/stretchy/attributes/type/range/double_range.rb +17 -0
  39. data/lib/stretchy/attributes/type/range/float_range.rb +16 -0
  40. data/lib/stretchy/attributes/type/range/integer_range.rb +16 -0
  41. data/lib/stretchy/attributes/type/range/ip_range.rb +16 -0
  42. data/lib/stretchy/attributes/type/range/long_range.rb +16 -0
  43. data/lib/stretchy/attributes/type/rank_feature.rb +21 -0
  44. data/lib/stretchy/attributes/type/rank_features.rb +24 -0
  45. data/lib/stretchy/attributes/type/search_as_you_type.rb +30 -0
  46. data/lib/stretchy/attributes/type/shape.rb +24 -0
  47. data/lib/stretchy/attributes/type/sparse_vector.rb +37 -0
  48. data/lib/stretchy/attributes/type/string.rb +7 -0
  49. data/lib/stretchy/attributes/type/text.rb +51 -0
  50. data/lib/stretchy/attributes/type/token_count.rb +26 -0
  51. data/lib/stretchy/attributes/type/version.rb +21 -0
  52. data/lib/stretchy/attributes/type/wildcard.rb +35 -0
  53. data/lib/stretchy/attributes.rb +68 -2
  54. data/lib/stretchy/common.rb +5 -5
  55. data/lib/stretchy/delegation/gateway_delegation.rb +9 -5
  56. data/lib/stretchy/model/serialization.rb +1 -0
  57. data/lib/stretchy/querying.rb +4 -4
  58. data/lib/stretchy/record.rb +9 -10
  59. data/lib/stretchy/relation.rb +11 -17
  60. data/lib/stretchy/relations/finder_methods.rb +19 -2
  61. data/lib/stretchy/relations/merger.rb +5 -1
  62. data/lib/stretchy/relations/query_builder.rb +32 -3
  63. data/lib/stretchy/relations/query_methods.rb +66 -2
  64. data/lib/stretchy/scoping/named.rb +1 -1
  65. data/lib/stretchy/shared_scopes.rb +1 -1
  66. data/lib/stretchy/version.rb +1 -1
  67. data/lib/stretchy.rb +5 -3
  68. data/lib/stretchy_model.rb +9 -0
  69. metadata +49 -4
  70. data/lib/active_model/type/array.rb +0 -13
  71. data/lib/active_model/type/hash.rb +0 -15
@@ -0,0 +1,24 @@
1
+ module Stretchy::Attributes::Type
2
+ # Public: Defines a rank_features attribute for the model.
3
+ #
4
+ # A rank_features field can index numeric feature vectors, so that they can later be used to boost documents in queries with a rank_feature query.
5
+
6
+ # It is analogous to the rank_feature data type but is better suited when the list of features is sparse so that it wouldn’t be reasonable to add one field to the mappings for each of them.
7
+ # opts - The Hash options used to refine the attribute (default: {}):
8
+ # :positive_score_impact - The Boolean indicating if features correlate positively with the score. If set to false, the score decreases with the value of the feature instead of increasing. Defaults to true.
9
+ #
10
+ # Examples
11
+ #
12
+ # class MyModel < Stretchy::Record
13
+ # attribute :negative_reviews, :rank_features, positive_score_impact: false
14
+ # end
15
+ #
16
+ # Returns nothing.
17
+ class RankFeatures < Stretchy::Attributes::Type::Base
18
+ OPTIONS = [:positive_score_impact]
19
+
20
+ def type
21
+ :rank_features
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,30 @@
1
+ module Stretchy::Attributes::Type
2
+ # Public: Defines a search_as_you_type attribute for the model. This field type is optimized to provide out-of-the-box support for queries that serve an as-you-type completion use case.
3
+ #
4
+ # opts - The Hash options used to refine the attribute (default: {}):
5
+ # :max_shingle_size - The Integer indicating the largest shingle size to create. Valid values are 2 to 4. Defaults to 3.
6
+ # :analyzer - The String analyzer to be used for text fields, both at index-time and at search-time. Defaults to the default index analyzer, or the standard analyzer.
7
+ # :index - The Boolean indicating if the field should be searchable. Defaults to true.
8
+ # :index_options - The String indicating what information should be stored in the index, for search and highlighting purposes. Defaults to 'positions'.
9
+ # :norms - The Boolean indicating if field-length should be taken into account when scoring queries. Defaults to true.
10
+ # :store - The Boolean indicating if the field value should be stored and retrievable separately from the _source field. Defaults to false.
11
+ # :search_analyzer - The String analyzer that should be used at search time on text fields. Defaults to the analyzer setting.
12
+ # :search_quote_analyzer - The String analyzer that should be used at search time when a phrase is encountered. Defaults to the search_analyzer setting.
13
+ # :similarity - The String indicating which scoring algorithm or similarity should be used. Defaults to 'BM25'.
14
+ # :term_vector - The String indicating if term vectors should be stored for the field. Defaults to 'no'.
15
+ #
16
+ # Examples
17
+ #
18
+ # class MyModel < Stretchy::Record
19
+ # attribute :name, :search_as_you_type, max_shingle_size: 4
20
+ # end
21
+ #
22
+ # Returns nothing.
23
+ class SearchAsYouType < Stretchy::Attributes::Type::Base
24
+ OPTIONS = [:max_shingle_size, :analyzer, :index, :index_options, :norms, :store, :search_analyzer, :search_quote_analyzer, :similarity, :term_vector]
25
+
26
+ def type
27
+ :search_as_you_type
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,24 @@
1
+ module Stretchy::Attributes::Type
2
+ # Public: Defines a shape attribute for the model. This field type is used for complex shapes.
3
+ #
4
+ # opts - The Hash options used to refine the attribute (default: {}):
5
+ # :orientation - The String indicating how to interpret vertex order for polygons / multipolygons. Can be 'right', 'ccw', 'counterclockwise', 'left', 'cw', 'clockwise'. Defaults to 'ccw'.
6
+ # :ignore_malformed - The Boolean indicating if malformed GeoJSON or WKT shapes should be ignored. Defaults to false.
7
+ # :ignore_z_value - The Boolean indicating if the z value of three dimension points should be ignored. Defaults to true.
8
+ # :coerce - The Boolean indicating if unclosed linear rings in polygons will be automatically closed. Defaults to false.
9
+ #
10
+ # Examples
11
+ #
12
+ # class MyModel < Stretchy::Record
13
+ # attribute :boundary, :shape, orientation: 'cw'
14
+ # end
15
+ #
16
+ # Returns nothing.
17
+ class Shape < Stretchy::Attributes::Type::Base
18
+ OPTIONS = [:orientation, :ignore_malformed, :ignore_z_value, :coerce]
19
+
20
+ def type
21
+ :shape
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,37 @@
1
+ #
2
+ # attribute :ml, :sparse_vector
3
+ #
4
+ # {
5
+ # "mappings": {
6
+ # "properties": {
7
+ # "ml.tokens": {
8
+ # "type": "sparse_vector"
9
+ # }
10
+ # }
11
+ # }
12
+ # }
13
+ #
14
+
15
+
16
+ module Stretchy
17
+ module Attributes
18
+ module Type
19
+ class SparseVector < Stretchy::Attributes::Type::Base
20
+
21
+ def type
22
+ :sparse_vector
23
+ end
24
+
25
+ def mappings(name)
26
+ {
27
+ properties: {
28
+ "#{name}.tokens": {
29
+ type: "sparse_vector"
30
+ }
31
+ }
32
+ }.as_json
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,7 @@
1
+ module Stretchy::Attributes::Type
2
+ class String < Stretchy::Attributes::Type::Text # :nodoc:
3
+ def type
4
+ :string
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,51 @@
1
+ module Stretchy::Attributes::Type
2
+ # Public: Defines a text attribute for the model. This field type is used for text strings.
3
+ #
4
+ # opts - The Hash options used to refine the attribute (default: {}):
5
+ # :analyzer - The String analyzer to be used for the text field, both at index-time and at search-time. Defaults to the default index analyzer, or the standard analyzer.
6
+ # :eager_global_ordinals - The Boolean indicating if global ordinals should be loaded eagerly on refresh. Defaults to false.
7
+ # :fielddata - The Boolean indicating if the field can use in-memory fielddata for sorting, aggregations, or scripting. Defaults to false.
8
+ # :fielddata_frequency_filter - The Hash of expert settings which allow to decide which values to load in memory when fielddata is enabled.
9
+ # :fields - The Hash of multi-fields allow the same string value to be indexed in multiple ways for different purposes. By default, a 'keyword' field is added. Set to false to disable.
10
+ # :index - The Boolean indicating if the field should be searchable. Defaults to true.
11
+ # :index_options - The String indicating what information should be stored in the index, for search and highlighting purposes. Defaults to 'positions'.
12
+ # :index_prefixes - The Hash indicating if term prefixes of between 2 and 5 characters are indexed into a separate field.
13
+ # :index_phrases - The Boolean indicating if two-term word combinations (shingles) are indexed into a separate field. Defaults to false.
14
+ # :norms - The Boolean indicating if field-length should be taken into account when scoring queries. Defaults to true.
15
+ # :position_increment_gap - The Integer indicating the number of fake term position which should be inserted between each element of an array of strings. Defaults to 100.
16
+ # :store - The Boolean indicating if the field value should be stored and retrievable separately from the _source field. Defaults to false.
17
+ # :search_analyzer - The String analyzer that should be used at search time on the text field. Defaults to the analyzer setting.
18
+ # :search_quote_analyzer - The String analyzer that should be used at search time when a phrase is encountered. Defaults to the search_analyzer setting.
19
+ # :similarity - The String indicating which scoring algorithm or similarity should be used. Defaults to 'BM25'.
20
+ # :term_vector - The String indicating if term vectors should be stored for the field. Defaults to 'no'.
21
+ # :meta - The Hash of metadata about the field.
22
+ #
23
+ #
24
+ # Examples
25
+ #
26
+ # class MyModel
27
+ # include StretchyModel
28
+ # attribute :description, :text, analyzer: 'english'
29
+ # end
30
+ #
31
+ # Returns nothing.
32
+ class Text < Stretchy::Attributes::Type::Base
33
+ OPTIONS = [:analyzer, :eager_global_ordinals, :fielddata, :fielddata_frequency_filter, :fields, :index, :index_options, :index_prefixes, :index_phrases, :norms, :position_increment_gap, :store, :search_analyzer, :search_quote_analyzer, :similarity, :term_vector, :meta]
34
+
35
+ def type
36
+ :text
37
+ end
38
+
39
+ def type_for_database
40
+ :text
41
+ end
42
+
43
+ def mappings(name)
44
+ options = {type: type_for_database}
45
+ OPTIONS.each { |option| options[option] = send(option) unless send(option).nil? }
46
+ options.delete(:fields) if fields == false
47
+ options[:fields] = {keyword: {type: :keyword, ignore_above: 256}} if fields.nil?
48
+ { name => options }.as_json
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,26 @@
1
+ module Stretchy::Attributes::Type
2
+ # Public: Defines a token_count attribute for the model. This field type is used for counting the number of tokens in a string.
3
+ #
4
+ # opts - The Hash options used to refine the attribute (default: {}):
5
+ # :analyzer - The String analyzer to be used to analyze the string value. Required.
6
+ # :enable_position_increments - The Boolean indicating if position increments should be counted. Defaults to true.
7
+ # :doc_values - The Boolean indicating if the field should be stored on disk in a column-stride fashion. Defaults to true.
8
+ # :index - The Boolean indicating if the field should be searchable. Defaults to true.
9
+ # :null_value - The Numeric value to be substituted for any explicit null values. Defaults to null.
10
+ # :store - The Boolean indicating if the field value should be stored and retrievable separately from the _source field. Defaults to false.
11
+ #
12
+ # Examples
13
+ #
14
+ # class MyModel < Stretchy::Record
15
+ # attribute :description_token_count, :token_count, analyzer: 'standard'
16
+ # end
17
+ #
18
+ # Returns nothing.
19
+ class TokenCount < Stretchy::Attributes::Type::Base
20
+ OPTIONS = [:analyzer, :enable_position_increments, :doc_values, :index, :null_value, :store]
21
+
22
+ def type
23
+ :token_count
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,21 @@
1
+ module Stretchy::Attributes::Type
2
+ # Public: Defines a version attribute for the model. This field type is used for software versions following the Semantic Versioning rules.
3
+ #
4
+ # opts - The Hash options used to refine the attribute (default: {}):
5
+ # :meta - The Hash of metadata about the field.
6
+ #
7
+ # Examples
8
+ #
9
+ # class MyModel < Stretchy::Record
10
+ # attribute :software_version, :version
11
+ # end
12
+ #
13
+ # Returns nothing.
14
+ class Version < Stretchy::Attributes::Type::Base
15
+ OPTIONS = [:meta]
16
+
17
+ def type
18
+ :version
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,35 @@
1
+ module Stretchy::Attributes::Type
2
+ # Public: Defines a wildcard attribute for the model. This field type is a specialization of the keyword field, but it supports wildcard searches.
3
+ #
4
+ # opts - The Hash options used to refine the attribute (default: {}):
5
+ # :doc_values - The Boolean indicating if the field should be stored on disk in a column-stride fashion. Defaults to true.
6
+ # :eager_global_ordinals - The Boolean indicating if global ordinals should be loaded eagerly on refresh. Defaults to false.
7
+ # :fields - The Hash of multi-fields for the same string value to be indexed in multiple ways.
8
+ # :ignore_above - The Integer limit for the length of the string. Strings longer than this limit will not be indexed. Defaults to 2147483647.
9
+ # :index - The Boolean indicating if the field should be quickly searchable. Defaults to true.
10
+ # :index_options - The String indicating what information should be stored in the index for scoring purposes. Defaults to 'docs'.
11
+ # :meta - The Hash metadata about the field.
12
+ # :norms - The Boolean indicating if field-length should be taken into account when scoring queries. Defaults to false.
13
+ # :null_value - The String value to be substituted for any explicit null values. Defaults to null.
14
+ # :on_script_error - The String defining what to do if the script defined by the :script parameter throws an error at indexing time. Can be 'fail' or 'continue'.
15
+ # :script - The String script that will index values generated by this script, rather than reading the values directly from the source.
16
+ # :store - The Boolean indicating if the field value should be stored and retrievable separately from the _source field. Defaults to false.
17
+ # :similarity - The String scoring algorithm or similarity to be used. Defaults to 'BM25'.
18
+ # :normalizer - The String pre-processor for the keyword prior to indexing. Defaults to null.
19
+ # :split_queries_on_whitespace - The Boolean indicating if full text queries should split the input on whitespace. Defaults to false.
20
+ # :time_series_dimension - The Boolean indicating if the field is a time series dimension. Defaults to false.
21
+ #
22
+ # Examples
23
+ #
24
+ # class MyModel
25
+ # include StretchyModel
26
+ # attribute :description_wildcard, :wildcard
27
+ # end
28
+ #
29
+ # Returns nothing.
30
+ class Wildcard < Stretchy::Attributes::Type::Keyword
31
+ def type
32
+ :wildcard
33
+ end
34
+ end
35
+ end
@@ -1,10 +1,76 @@
1
1
  module Stretchy
2
2
  module Attributes
3
+ extend ActiveSupport::Concern
4
+
5
+ def [](attribute)
6
+ self.send(attribute)
7
+ end
8
+
9
+ def []=(attribute, value)
10
+ self.send("#{attribute}=", value)
11
+ end
12
+
13
+ def inspect
14
+ "#<#{self.class.name} #{attributes.map { |k,v| "#{k}: #{v.blank? ? 'nil' : v}" }.join(', ')}>"
15
+ end
16
+
17
+ class_methods do
18
+ def inspect
19
+ "#<#{self.name} #{attribute_types.map { |k,v| "#{k}: #{v.type}" }.join(', ')}>"
20
+ end
21
+
22
+ def attribute_mappings
23
+ {properties: attribute_types.map { |k,v| v.mappings(k) }.reduce({}, :merge)}.as_json
24
+ end
25
+ end
3
26
 
4
27
  def self.register!
5
- ActiveModel::Type.register(:array, ActiveModel::Type::Array)
6
- ActiveModel::Type.register(:hash, ActiveModel::Type::Hash)
28
+ ActiveModel::Type.register(:array, Stretchy::Attributes::Type::Array)
29
+ ActiveModel::Type.register(:binary, Stretchy::Attributes::Type::Binary)
30
+ ActiveModel::Type.register(:boolean, Stretchy::Attributes::Type::Boolean)
31
+ ActiveModel::Type.register(:constant_keyword, Stretchy::Attributes::Type::ConstantKeyword)
32
+ ActiveModel::Type.register(:datetime, Stretchy::Attributes::Type::DateTime)
33
+ ActiveModel::Type.register(:flattened, Stretchy::Attributes::Type::Flattened)
34
+ ActiveModel::Type.register(:geo_point, Stretchy::Attributes::Type::GeoPoint)
35
+ ActiveModel::Type.register(:geo_shape, Stretchy::Attributes::Type::GeoShape)
36
+ ActiveModel::Type.register(:histogram, Stretchy::Attributes::Type::Histogram)
37
+ ActiveModel::Type.register(:hash, Stretchy::Attributes::Type::Hash)
38
+ ActiveModel::Type.register(:ip, Stretchy::Attributes::Type::IP)
39
+ ActiveModel::Type.register(:join, Stretchy::Attributes::Type::Join)
7
40
  ActiveModel::Type.register(:keyword, Stretchy::Attributes::Type::Keyword)
41
+ ActiveModel::Type.register(:match_only_text, Stretchy::Attributes::Type::MatchOnlyText)
42
+ ActiveModel::Type.register(:nested, Stretchy::Attributes::Type::Nested)
43
+ ActiveModel::Type.register(:percolator, Stretchy::Attributes::Type::Percolator)
44
+ ActiveModel::Type.register(:point, Stretchy::Attributes::Type::Point)
45
+ ActiveModel::Type.register(:rank_feature, Stretchy::Attributes::Type::RankFeature)
46
+
47
+ ActiveModel::Type.register(:text, Stretchy::Attributes::Type::Text)
48
+ ActiveModel::Type.register(:token_count, Stretchy::Attributes::Type::TokenCount)
49
+ ActiveModel::Type.register(:dense_vector, Stretchy::Attributes::Type::DenseVector)
50
+
51
+ ActiveModel::Type.register(:search_as_you_type, Stretchy::Attributes::Type::SearchAsYouType)
52
+ ActiveModel::Type.register(:sparse_vector, Stretchy::Attributes::Type::SparseVector)
53
+ ActiveModel::Type.register(:string, Stretchy::Attributes::Type::String)
54
+ ActiveModel::Type.register(:version, Stretchy::Attributes::Type::Version)
55
+ ActiveModel::Type.register(:wildcard, Stretchy::Attributes::Type::Wildcard)
56
+ # Numerics
57
+ ActiveModel::Type.register(:long, Stretchy::Attributes::Type::Numeric::Long)
58
+ ActiveModel::Type.register(:integer, Stretchy::Attributes::Type::Numeric::Integer)
59
+ ActiveModel::Type.register(:short, Stretchy::Attributes::Type::Numeric::Short)
60
+ ActiveModel::Type.register(:byte, Stretchy::Attributes::Type::Numeric::Byte)
61
+ ActiveModel::Type.register(:double, Stretchy::Attributes::Type::Numeric::Double)
62
+ ActiveModel::Type.register(:float, Stretchy::Attributes::Type::Numeric::Float)
63
+ ActiveModel::Type.register(:half_float, Stretchy::Attributes::Type::Numeric::HalfFloat)
64
+ ActiveModel::Type.register(:scaled_float, Stretchy::Attributes::Type::Numeric::ScaledFloat)
65
+ ActiveModel::Type.register(:unsigned_long, Stretchy::Attributes::Type::Numeric::UnsignedLong)
66
+ # Ranges
67
+ ActiveModel::Type.register(:integer_range, Stretchy::Attributes::Type::Range::IntegerRange)
68
+ ActiveModel::Type.register(:float_range, Stretchy::Attributes::Type::Range::FloatRange)
69
+ ActiveModel::Type.register(:long_range, Stretchy::Attributes::Type::Range::LongRange)
70
+ ActiveModel::Type.register(:double_range, Stretchy::Attributes::Type::Range::DoubleRange)
71
+ ActiveModel::Type.register(:date_range, Stretchy::Attributes::Type::Range::DateRange)
72
+ ActiveModel::Type.register(:ip_range, Stretchy::Attributes::Type::Range::IpRange)
73
+
8
74
  end
9
75
  end
10
76
  end
@@ -2,11 +2,10 @@ module Stretchy
2
2
  module Common
3
3
  extend ActiveSupport::Concern
4
4
 
5
- def inspect
6
- "#<#{self.class.name} #{attributes.map { |k,v| "#{k}: #{v.blank? ? 'nil' : v}" }.join(', ')}>"
5
+ def highlights_for(attribute)
6
+ highlights[attribute.to_s]
7
7
  end
8
8
 
9
-
10
9
  class_methods do
11
10
 
12
11
  # Set the default sort key to be used in sort operations
@@ -16,8 +15,9 @@ module Stretchy
16
15
  @default_sort_key
17
16
  end
18
17
 
19
- def default_size(size = 10000)
20
- @default_size = size
18
+ def default_size(size = nil)
19
+ @default_size = size unless size.nil?
20
+ @default_size
21
21
  end
22
22
 
23
23
  private
@@ -18,8 +18,6 @@ module Stretchy
18
18
  :count,
19
19
  to: :gateway
20
20
 
21
- include Rails::Instrumentation::Publishers::Record
22
-
23
21
  def index_name(name=nil, &block)
24
22
  if name || block_given?
25
23
  return (@index_name = name || block)
@@ -28,13 +26,19 @@ module Stretchy
28
26
  if @index_name.respond_to?(:call)
29
27
  @index_name.call
30
28
  else
31
- @index_name || base_class.model_name.collection
29
+ @index_name || base_class.model_name.collection.parameterize.underscore
32
30
  end
33
31
  end
34
32
 
33
+ def reload_gateway_configuration!
34
+ @gateway = nil
35
+ end
36
+
35
37
  def gateway(&block)
36
- @gateway ||= Stretchy::Repository.create(client: Stretchy.configuration.client, index_name: index_name, klass: base_class)
37
- block.arity < 1 ? @gateway.instance_eval(&block) : block.call(@gateway) if block_given?
38
+ reload_gateway_configuration! if @gateway && @gateway.client != Stretchy.configuration.client
39
+
40
+ @gateway ||= Stretchy::Repository.create(client: Stretchy.configuration.client, index_name: index_name, klass: base_class, mapping: base_class.attribute_mappings.merge(dynamic: true))
41
+ # block.arity < 1 ? @gateway.instance_eval(&block) : block.call(@gateway) if block_given?
38
42
  @gateway
39
43
  end
40
44
 
@@ -9,6 +9,7 @@ module Stretchy
9
9
 
10
10
  def deserialize(document)
11
11
  attribs = ActiveSupport::HashWithIndifferentAccess.new(document['_source']).deep_symbolize_keys
12
+ attribs[:_highlights] = document["highlight"] if document["highlight"]
12
13
  _id = __get_id_from_document(document)
13
14
  attribs[:id] = _id if _id
14
15
  klass.new attribs
@@ -6,13 +6,13 @@ module Stretchy
6
6
  delegate *Stretchy::Relations::AggregationMethods::AGGREGATION_METHODS, to: :all
7
7
 
8
8
  delegate :skip_callbacks, :routing, :search_options, to: :all
9
- delegate :must, :must_not, :should, :where_not, :where, :filter_query, :query_string, to: :all
9
+ delegate :must, :must_not, :should, :where_not, :where, :filter_query, :query_string, :regexp, to: :all
10
10
 
11
11
  def fetch_results(es)
12
- unless es.count?
13
- base_class.search(es.to_elastic, es.search_options)
14
- else
12
+ if es.count?
15
13
  base_class.count(es.to_elastic, es.search_options)
14
+ else
15
+ base_class.search(es.to_elastic, es.search_options)
16
16
  end
17
17
  end
18
18
 
@@ -14,11 +14,6 @@ module Stretchy
14
14
  include ActiveModel::Conversion
15
15
  include ActiveModel::Serialization
16
16
  include ActiveModel::Serializers::JSON
17
- include ActiveModel::Validations
18
- include ActiveModel::Validations::Callbacks
19
- extend ActiveModel::Callbacks
20
-
21
-
22
17
 
23
18
  include Stretchy::Model::Callbacks
24
19
  include Stretchy::Indexing::Bulk
@@ -28,12 +23,14 @@ module Stretchy
28
23
  include Stretchy::Common
29
24
  include Stretchy::Scoping
30
25
  include Stretchy::Utils
26
+ include Stretchy::SharedScopes
27
+ include Stretchy::Attributes
31
28
 
32
29
  extend Stretchy::Delegation::DelegateCache
33
30
  extend Stretchy::Querying
34
31
 
35
32
  # Set up common attributes
36
- attribute :id, :string #, default: lambda { SecureRandom.uuid }
33
+ attribute :id, :keyword #, default: lambda { SecureRandom.uuid }
37
34
  attribute :created_at, :datetime, default: lambda { Time.now.utc }
38
35
  attribute :updated_at, :datetime, default: lambda { Time.now.utc }
39
36
 
@@ -44,11 +41,13 @@ module Stretchy
44
41
  # overriden by #size
45
42
  default_size 10000
46
43
 
47
- end
44
+ attr_accessor :highlights
45
+
46
+ def initialize(attributes = {})
47
+ @highlights = attributes.delete(:_highlights)
48
+ super(attributes)
49
+ end
48
50
 
49
- def initialize(attributes = {})
50
- self.assign_attributes(attributes) if attributes
51
- super()
52
51
  end
53
52
 
54
53
  end
@@ -3,20 +3,16 @@ module Stretchy
3
3
  # It provides methods for querying and manipulating the documents.
4
4
  class Relation
5
5
 
6
- # These methods can accept multiple values.
7
- MULTI_VALUE_METHODS = [:order, :where, :or_filter, :filter_query, :bind, :extending, :unscope, :skip_callbacks]
8
-
9
- # These methods can accept a single value.
10
- SINGLE_VALUE_METHODS = [:limit, :offset, :routing, :size]
11
-
12
6
  # These methods cannot be used with the `delete_all` method.
13
7
  INVALID_METHODS_FOR_DELETE_ALL = [:limit, :offset]
14
8
 
15
- # All value methods.
16
- VALUE_METHODS = MULTI_VALUE_METHODS + SINGLE_VALUE_METHODS
17
-
18
9
  # Include modules.
19
- include Relations::FinderMethods, Relations::SpawnMethods, Relations::QueryMethods, Relations::AggregationMethods, Relations::SearchOptionMethods, Delegation
10
+ include Relations::FinderMethods,
11
+ Relations::SpawnMethods,
12
+ Relations::QueryMethods,
13
+ Relations::AggregationMethods,
14
+ Relations::SearchOptionMethods,
15
+ Delegation
20
16
 
21
17
  # Getters.
22
18
  attr_reader :klass, :loaded
@@ -32,7 +28,7 @@ module Stretchy
32
28
  # @param values [Hash] The initial values for the relation.
33
29
  def initialize(klass, values={})
34
30
  @klass = klass
35
- @values = values
31
+ @values = values.merge(default_size: klass.default_size)
36
32
  @offsets = {}
37
33
  @loaded = false
38
34
  end
@@ -49,14 +45,13 @@ module Stretchy
49
45
  #
50
46
  # @return [Array] The results of the relation.
51
47
  def to_a
52
-
53
48
  load
54
49
  @records
55
50
  end
56
51
  alias :results :to_a
57
52
 
58
53
  def response
59
- to_a.response
54
+ results.response
60
55
  end
61
56
 
62
57
  # Returns the results of the relation as a JSON object.
@@ -64,7 +59,7 @@ module Stretchy
64
59
  # @param options [Hash] The options to pass to the `as_json` method.
65
60
  # @return [Hash] The results of the relation as a JSON object.
66
61
  def as_json(options = nil)
67
- to_a.as_json(options)
62
+ results.as_json(options)
68
63
  end
69
64
 
70
65
  # Returns the Elasticsearch query for the relation.
@@ -98,7 +93,6 @@ module Stretchy
98
93
  # @return [Relation] The relation object.
99
94
  def load
100
95
  exec_queries unless loaded?
101
-
102
96
  self
103
97
  end
104
98
  alias :fetch :load
@@ -146,8 +140,8 @@ module Stretchy
146
140
  begin
147
141
  entries = to_a.results.take([size_value.to_i + 1, 11].compact.min).map!(&:inspect)
148
142
  message = {}
149
- message = {total: to_a.total, max: to_a.total}
150
- message.merge!(aggregations: results.response.aggregations.keys) unless results.response.aggregations.nil?
143
+ message = {total: results.total, max: results.total}
144
+ message.merge!(aggregations: response.aggregations.keys) unless response.aggregations.nil?
151
145
  message = message.each_pair.collect { |k,v| "#{k}: #{v}" }
152
146
  message.unshift entries.join(', ') unless entries.size.zero?
153
147
  "#<#{self.class.name} #{message.join(', ')}>"
@@ -39,14 +39,31 @@ module Stretchy
39
39
  self
40
40
  end
41
41
 
42
+ # size is not permitted to the count API but queries are.
43
+ #
44
+ # if a query is supplied with `.count` then the user wants a count of the results
45
+ # matching the query
46
+ #
47
+ # however, the default_size is used to limit the number of results returned
48
+ # so we remove the size from the query and then call `.count` API
49
+ #
50
+ # but if the user supplies a limit, then we should assume they want a count of the results
51
+ # which could lead to some confusion
52
+ # suppose the user calls `.size(100).count` and the default_size is 100
53
+ # if we remove size from the query, then the count could be greater than 100
54
+ #
55
+ # I think the best way to handle this is to remove the size from the query only if it was
56
+ # applied by the default_size
57
+ # If the user supplies a limit, then we should assume they want a count of the results
58
+ #
59
+ # if size is called with a limit,
42
60
  def count
43
- return results.count if @loaded
61
+ return results.count if @loaded || @values[:size].present?
44
62
  spawn.count!
45
63
  end
46
64
 
47
65
  def count!
48
66
  @values[:count] = true
49
- @values.delete(:size)
50
67
  spawned = spawn
51
68
  spawned.order_values.clear
52
69
  spawned.results
@@ -7,8 +7,12 @@ module Stretchy
7
7
  class HashMerger # :nodoc:
8
8
  attr_reader :relation, :hash
9
9
 
10
+ VALUE_METHODS = Stretchy::Relations::QueryMethods::MULTI_VALUE_METHODS.concat(
11
+ Stretchy::Relations::QueryMethods::SINGLE_VALUE_METHODS
12
+ )
13
+
10
14
  def initialize(relation, hash)
11
- hash.assert_valid_keys(*Relation::VALUE_METHODS)
15
+ hash.assert_valid_keys(*VALUE_METHODS)
12
16
 
13
17
  @relation = relation
14
18
  @hash = hash