Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix attribute mapping issues #78

Merged
merged 2 commits into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions lib/stretchy/attributes/type/array.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
module Stretchy::Attributes::Type
class Array < Stretchy::Attributes::Type::Base # :nodoc:
OPTIONS = [:data_type, :fields]
def type
:array
end

def type_for_database
data_type || :text
end

def mappings(name)
options = {type: type_for_database}
self.class::OPTIONS.each { |option| options[option] = send(option) unless send(option).nil? }
options.delete(:fields) if fields == false
options[:fields] = {keyword: {type: :keyword, ignore_above: 256}} if type_for_database == :text && fields.nil?
{ name => options }.as_json
end
end
end
6 changes: 5 additions & 1 deletion lib/stretchy/attributes/type/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,15 @@ def initialize(**args)
end

def mappings(name)
options = {type: type}
options = {type: type_for_database}
self.class::OPTIONS.each { |option| options[option] = send(option) unless send(option).nil? }
{ name => options }.as_json
end

def type_for_database
type
end

private

def define_option_methods!
Expand Down
4 changes: 4 additions & 0 deletions lib/stretchy/attributes/type/date_time.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,9 @@ class DateTime < Stretchy::Attributes::Type::Base
def type
:datetime
end

def type_for_database
:date
end
end
end
10 changes: 10 additions & 0 deletions lib/stretchy/attributes/type/hash.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@ def type
:hash
end

def type_for_database
:object
end

def mappings(name)
options = {}
OPTIONS.each { |option| options[option] = send(option) unless send(option).nil? }
{ name => options }.as_json
end

private

def cast_value(value)
Expand Down
2 changes: 1 addition & 1 deletion lib/stretchy/attributes/type/keyword.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module Stretchy::Attributes::Type
# Public: Defines a keyword attribute for the model.
#
# opts - The Hash options used to refine the attribute (default: {}):
#
# :doc_values - The Boolean indicating if the field should be stored on disk in a column-stride fashion. Defaults to true.
# :eager_global_ordinals - The Boolean indicating if global ordinals should be loaded eagerly on refresh. Defaults to false.
# :fields - The Hash of multi-fields for the same string value to be indexed in multiple ways.
Expand All @@ -20,7 +21,6 @@ module Stretchy::Attributes::Type
# :time_series_dimension - The Boolean indicating if the field is a time series dimension. Defaults to false.
#
# Examples
#
# class MyModel
# include StretchyModel
# attribute :tag, :keyword, ignore_above: 256, time_series_dimension: true
Expand Down
2 changes: 1 addition & 1 deletion lib/stretchy/attributes/type/string.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module Stretchy::Attributes::Type
class String < Stretchy::Attributes::Type::Base # :nodoc:
class String < Stretchy::Attributes::Type::Text # :nodoc:
def type
:string
end
Expand Down
15 changes: 14 additions & 1 deletion lib/stretchy/attributes/type/text.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ module Stretchy::Attributes::Type
# :eager_global_ordinals - The Boolean indicating if global ordinals should be loaded eagerly on refresh. Defaults to false.
# :fielddata - The Boolean indicating if the field can use in-memory fielddata for sorting, aggregations, or scripting. Defaults to false.
# :fielddata_frequency_filter - The Hash of expert settings which allow to decide which values to load in memory when fielddata is enabled.
# :fields - The Hash of multi-fields allow the same string value to be indexed in multiple ways for different purposes.
# :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.
# :index - The Boolean indicating if the field should be searchable. Defaults to true.
# :index_options - The String indicating what information should be stored in the index, for search and highlighting purposes. Defaults to 'positions'.
# :index_prefixes - The Hash indicating if term prefixes of between 2 and 5 characters are indexed into a separate field.
Expand All @@ -20,6 +20,7 @@ module Stretchy::Attributes::Type
# :term_vector - The String indicating if term vectors should be stored for the field. Defaults to 'no'.
# :meta - The Hash of metadata about the field.
#
#
# Examples
#
# class MyModel
Expand All @@ -34,5 +35,17 @@ class Text < Stretchy::Attributes::Type::Base
def type
:text
end

def type_for_database
:text
end

def mappings(name)
options = {type: type_for_database}
OPTIONS.each { |option| options[option] = send(option) unless send(option).nil? }
options.delete(:fields) if fields == false
options[:fields] = {keyword: {type: :keyword, ignore_above: 256}} if fields.nil?
{ name => options }.as_json
end
end
end
4 changes: 2 additions & 2 deletions lib/stretchy/delegation/gateway_delegation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ def reload_gateway_configuration!
def gateway(&block)
reload_gateway_configuration! if @gateway && @gateway.client != Stretchy.configuration.client

@gateway ||= Stretchy::Repository.create(client: Stretchy.configuration.client, index_name: index_name, klass: base_class)
block.arity < 1 ? @gateway.instance_eval(&block) : block.call(@gateway) if block_given?
@gateway ||= Stretchy::Repository.create(client: Stretchy.configuration.client, index_name: index_name, klass: base_class, mapping: base_class.attribute_mappings.merge(dynamic: true))
# block.arity < 1 ? @gateway.instance_eval(&block) : block.call(@gateway) if block_given?
@gateway
end

Expand Down
2 changes: 1 addition & 1 deletion spec/stretchy/associations/belongs_to_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class Book < Stretchy::Record

attribute :title, :keyword
attribute :description, :string
attribute :published_at, :date
attribute :published_at, :datetime
attribute :publisher_id, :keyword

belongs_to :publisher
Expand Down
127 changes: 95 additions & 32 deletions spec/stretchy/attributes_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,30 +20,16 @@

context 'in model' do
let(:model) do
class AttributeModel < Stretchy::Record
Object.send(:remove_const, :AttributeModel) if Object.const_defined?(:AttributeModel)
stub_const("AttributeModel", Class.new(Stretchy::Record) do
attribute :name, :text
attribute :age, :integer
attribute :tags, :array
attribute :data, :hash, properties: {weights: {type: :array}, biases: {type: :integer}}
attribute :data, :hash, properties: {weights: {type: :integer}, biases: {type: :integer}}
attribute :flagged, :boolean, default: false
end
AttributeModel
end

it 'array type is registered' do
expect(model.attribute_types['tags'].type).to eq(:array)
end

it 'hash type is registered' do
expect(model.attribute_types['data'].type).to eq(:hash)
end

it 'keyword type is registered' do
expect(model.attribute_types['name'].type).to eq(:text)
end

it 'text type is registered' do
expect(model.attribute_types['age'].type).to eq(:integer)
attribute :body, :text
attribute :only_text, :text, fields: false
end)
end

context 'hash' do
Expand All @@ -55,19 +41,96 @@ class AttributeModel < Stretchy::Record

context 'mappings' do

it 'returns mappings' do
expect(model.attribute_mappings).to eq({
properties: {
name: {type: :text},
age: {type: :integer},
tags: {type: :array},
data: {type: :hash, properties: {weights: {type: :array}, biases: {type: :integer}}},
flagged: {type: :boolean},
id: { type: :keyword },
created_at: { type: :datetime },
updated_at: { type: :datetime }

context 'auto keyword fields for text fields' do
it 'adds keyword to text fields' do
expect(model.attribute_mappings['properties']['body']).to eq({type: :text, fields: {keyword: {type: :keyword, ignore_above: 256}}}.as_json)
end

it 'does not add keyword to text fields when fields is false' do
expect(model.attribute_mappings['properties']['only_text']).to eq({type: :text}.as_json)
end

it 'does not add keyword to text fields when fields is present' do
model.attribute :location, :text, fields: {raw: {type: :keyword}}
expect(model.attribute_mappings['properties']['location']).to eq({type: :text, fields: {raw: {type: :keyword}}}.as_json)
end

let(:mapping) do
{
"attribute_models": {
"mappings": {
"dynamic": true,
"properties": {
"age": {
"type": "integer"
},
"body": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"created_at": {
"type": "date"
},
"data": {
"properties": {
"biases": {
"type": "integer"
},
"weights": {
"type": "integer"
}
}
},
"flagged": {
"type": "boolean"
},
"id": {
"type": "keyword"
},
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"only_text": {
"type": "text"
},
"tags": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"updated_at": {
"type": "date"
}
}
}
}
}.as_json)
}.with_indifferent_access
end

it 'creates index with attribute mappings' do
model.delete_index! if model.index_exists?
model.create_index!
# ap model.mappings.as_json
# ap mapping[:attribute_models][:mappings][:properties].as_json
expect(model.mappings.with_indifferent_access[:properties].as_json).to eq(mapping[:attribute_models][:mappings][:properties])
end

end


Expand Down
Loading