Skip to content

[WIP] Convert from Virtus to ActiveAttr #395

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

Closed
wants to merge 4 commits into from
Closed
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
7 changes: 2 additions & 5 deletions elasticsearch-persistence/README.md
Original file line number Diff line number Diff line change
@@ -462,11 +462,8 @@ require 'elasticsearch/persistence/model'

#### Model Definition

The integration is implemented by including the module in a Ruby class.
The model attribute definition support is implemented with the
[_Virtus_](https://github.com/solnic/virtus) Rubygem, and the
naming, validation, etc. features with the
[_ActiveModel_](https://github.com/rails/rails/tree/master/activemodel) Rubygem.
The integration is implemented by including the module in a Ruby class. The model attribute definition support is implemented with the [_ActiveAttr_](https://github.com/cgriego/active_attr) Rubygem, and the naming,
validation, etc. features with the [_ActiveModel_](https://github.com/rails/rails/tree/master/activemodel) Rubygem.

```ruby
class Article
Original file line number Diff line number Diff line change
@@ -28,7 +28,7 @@ Gem::Specification.new do |s|
s.add_dependency "activesupport", '> 3'
s.add_dependency "activemodel", '> 3'
s.add_dependency "hashie"
s.add_dependency "virtus"
s.add_dependency "active_attr"

s.add_development_dependency "bundler", "~> 1.5"
s.add_development_dependency "rake", "~> 11.1"
12 changes: 6 additions & 6 deletions elasticsearch-persistence/examples/music/album.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class Meta
include Virtus.model
include ActiveAttr::Model

attribute :rating
attribute :have
@@ -18,16 +18,16 @@ class Album
end

attribute :artist
attribute :artist_id, String, mapping: { index: 'not_analyzed' }
attribute :label, Hash, mapping: { type: 'object' }
attribute :artist_id, type: String, mapping: { index: 'not_analyzed' }
attribute :label, type: Hash, mapping: { type: 'object' }

attribute :title
attribute :released, Date
attribute :released, type: Date
attribute :notes
attribute :uri

attribute :tracklist, Array, mapping: { type: 'object' }
attribute :tracklist, type: Array, mapping: { type: 'object' }

attribute :styles
attribute :meta, Meta, mapping: { type: 'object' }
attribute :meta, type: Meta, mapping: { type: 'object' }
end
22 changes: 8 additions & 14 deletions elasticsearch-persistence/lib/elasticsearch/persistence/model.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
require 'active_support/core_ext/module/delegation'

require 'active_model'
require 'virtus'
require 'active_attr'

require 'elasticsearch/persistence'
require 'elasticsearch/persistence/model/base'
require 'elasticsearch/persistence/model/errors'
require 'elasticsearch/persistence/model/store'
require 'elasticsearch/persistence/model/find'
require 'elasticsearch/persistence/model/time_with_zone_typecaster'

module Elasticsearch
module Persistence
@@ -25,13 +25,7 @@ module Persistence
module Model
def self.included(base)
base.class_eval do
include ActiveModel::Naming
include ActiveModel::Conversion
include ActiveModel::Serialization
include ActiveModel::Serializers::JSON
include ActiveModel::Validations

include Virtus.model
include ActiveAttr::Model

extend ActiveModel::Callbacks
define_model_callbacks :create, :save, :update, :destroy
@@ -45,14 +39,14 @@ def self.included(base)
extend Elasticsearch::Persistence::Model::Find::ClassMethods

class << self
# Re-define the Virtus' `attribute` method, to configure Elasticsearch mapping as well
# Re-define the active_attr `attribute` method, to configure Elasticsearch mapping as well
#
def attribute(name, type=nil, options={}, &block)
def attribute(name, options={}, &block)
mapping = options.delete(:mapping) || {}
super

gateway.mapping do
indexes name, {type: Utils::lookup_type(type)}.merge(mapping)
indexes name, {type: Utils::lookup_type(options.fetch(:type, Object))}.merge(mapping)
end

gateway.mapping(&block) if block_given?
@@ -122,8 +116,8 @@ def deserialize(document)

# Set up common attributes
#
attribute :created_at, Time, default: lambda { |o,a| Time.now.utc }
attribute :updated_at, Time, default: lambda { |o,a| Time.now.utc }
attribute :created_at, type: ActiveSupport::TimeWithZone, default: lambda { Time.now.utc }, typecaster: TimeWithZoneTypecaster.new
attribute :updated_at, type: ActiveSupport::TimeWithZone, default: lambda { Time.now.utc }, typecaster: TimeWithZoneTypecaster.new

attr_reader :hit
end
Original file line number Diff line number Diff line change
@@ -55,8 +55,12 @@ def _source
@_source
end

def to_h
attributes.symbolize_keys
end; alias :to_hash :to_h

def to_s
"#<#{self.class} #{attributes.to_hash.inspect.gsub(/:(\w+)=>/, '\1: ')}>"
"#<#{self.class} #{to_h.inspect.gsub(/:(\w+)=>/, '\1: ')}>"
end; alias :inspect :to_s
end
end
@@ -75,9 +79,9 @@ def lookup_type(type)
'integer'
when type == Float
'float'
when type == Date || type == Time || type == DateTime
when type == Date || type == Time || type == DateTime || type == ActiveSupport::TimeWithZone
'date'
when type == Virtus::Attribute::Boolean
when type == ActiveAttr::Typecasting::Boolean
'boolean'
end
end; module_function :lookup_type
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
module Elasticsearch
module Persistence
module Model
class TimeWithZoneTypecaster
def initialize(precision = nil)
@precision_override = precision
end

def call(value)
result = nil
if value.respond_to? :in_time_zone
result = value.in_time_zone
elsif value.respond_to? :to_s
result = Time.zone.parse(value)
end

precision = nil
if !@precision_override.nil?
precision = @precision_override
elsif !ActiveSupport::JSON::Encoding.use_standard_json_time_format
precision = 0
elsif active_support_version < Gem::Version.new('4.0')
precision = 0
elsif active_support_version >= Gem::Version.new('4.0') &&
active_support_version < Gem::Version.new('4.1')
precision = 3
else
precision = ActiveSupport::JSON::Encoding.time_precision
end

result.change(usec: (result.usec / (10**(6-precision))))
end

def active_support_version
if ActiveSupport.respond_to?(:version)
ActiveSupport.version
else
Gem::Version.new(ActiveSupport::VERSION::STRING)
end
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -14,16 +14,16 @@ class ::Person
settings index: { number_of_shards: 1 }
document_type 'human_being'

attribute :name, String,
attribute :name, type: String,
mapping: { fields: {
name: { type: 'string', analyzer: 'snowball' },
raw: { type: 'string', analyzer: 'keyword' }
} }

attribute :birthday, Date
attribute :department, String
attribute :salary, Integer
attribute :admin, Boolean, default: false
attribute :birthday, type: Date
attribute :department, type: String
attribute :salary, type: Integer
attribute :admin, type: Boolean, default: false

validates :name, presence: true
end
Original file line number Diff line number Diff line change
@@ -1,26 +1,30 @@
require 'test_helper'

require 'virtus'
require 'active_attr'

module Elasticsearch
module Persistence
class RepositoryWithVirtusIntegrationTest < Elasticsearch::Test::IntegrationTestCase
class RepositoryWithActiveAttrIntegrationTest < Elasticsearch::Test::IntegrationTestCase

class ::Page
include Virtus.model
include ActiveAttr::Model

attribute :id, String, writer: :private
attribute :title, String
attribute :views, Integer, default: 0
attribute :published, Boolean, default: false
attribute :slug, String, default: lambda { |page, attr| page.title.downcase.gsub(' ', '-') }
attribute :id, type: String, writer: :private
attribute :title, type: String
attribute :views, type: Integer, default: 0
attribute :published, type: Boolean, default: false
attribute :slug, type: String, default: lambda { title.downcase.gsub(' ', '-') }

def set_id(id)
self.id = id
end

def to_hash
attributes.symbolize_keys
end
end

context "The repository with a Virtus model" do
context "The repository with an active_attr model" do
setup do
@repository = Elasticsearch::Persistence::Repository.new do
index :pages
2 changes: 1 addition & 1 deletion elasticsearch-persistence/test/unit/model_base_test.rb
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ class Elasticsearch::Persistence::ModelBaseTest < Test::Unit::TestCase
class DummyBaseModel
include Elasticsearch::Persistence::Model

attribute :name, String
attribute :name, type: String
end
end

19 changes: 6 additions & 13 deletions elasticsearch-persistence/test/unit/model_find_test.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
require 'test_helper'

require 'active_model'
require 'virtus'
require 'active_attr'

require 'elasticsearch/persistence/model/errors'
require 'elasticsearch/persistence/model/find'
@@ -10,24 +9,18 @@ class Elasticsearch::Persistence::ModelFindTest < Test::Unit::TestCase
context "The model find module," do

class DummyFindModel
include ActiveModel::Naming
include ActiveModel::Conversion
include ActiveModel::Serialization
include ActiveModel::Serializers::JSON
include ActiveModel::Validations

include Virtus.model
include ActiveAttr::Model

extend Elasticsearch::Persistence::Model::Find::ClassMethods

extend ActiveModel::Callbacks
define_model_callbacks :create, :save, :update, :destroy
define_model_callbacks :find, :touch, only: :after

attribute :title, String
attribute :count, Integer, default: 0
attribute :created_at, DateTime, default: lambda { |o,a| Time.now.utc }
attribute :updated_at, DateTime, default: lambda { |o,a| Time.now.utc }
attribute :title, type: String
attribute :count, type: Integer, default: 0
attribute :created_at, type: DateTime, default: lambda { Time.now.utc }
attribute :updated_at, type: DateTime, default: lambda { Time.now.utc }
end

setup do
6 changes: 3 additions & 3 deletions elasticsearch-persistence/test/unit/model_gateway_test.rb
Original file line number Diff line number Diff line change
@@ -52,15 +52,15 @@ def run!; DummyGatewayModel.gateway { |g| @b += 1 }; end
end

should "configure the mapping via attribute" do
DummyGatewayModel.attribute :name, String, mapping: { analyzer: 'snowball' }
DummyGatewayModel.attribute :name, type: String, mapping: { analyzer: 'snowball' }

assert_respond_to DummyGatewayModel, :name
assert_equal 'snowball',
DummyGatewayModel.mapping.to_hash[:dummy_gateway_model][:properties][:name][:analyzer]
end

should "configure the mapping via an attribute block" do
DummyGatewayModel.attribute :name, String do
DummyGatewayModel.attribute :name, type: String do
indexes :name, analyzer: 'custom'
end

@@ -74,7 +74,7 @@ def run!; DummyGatewayModel.gateway { |g| @b += 1 }; end
assert_equal 'integer', Elasticsearch::Persistence::Model::Utils::lookup_type(Integer)
assert_equal 'float', Elasticsearch::Persistence::Model::Utils::lookup_type(Float)
assert_equal 'date', Elasticsearch::Persistence::Model::Utils::lookup_type(Date)
assert_equal 'boolean', Elasticsearch::Persistence::Model::Utils::lookup_type(Virtus::Attribute::Boolean)
assert_equal 'boolean', Elasticsearch::Persistence::Model::Utils::lookup_type(ActiveAttr::Typecasting::Boolean)
end

should "remove IDs from hash when serializing" do
6 changes: 3 additions & 3 deletions elasticsearch-persistence/test/unit/model_rails_test.rb
Original file line number Diff line number Diff line change
@@ -11,9 +11,9 @@ class ::MyRailsModel
include Elasticsearch::Persistence::Model
include Elasticsearch::Persistence::Model::Rails

attribute :name, String, mapping: { analyzer: 'string' }
attribute :published_at, DateTime
attribute :published_on, Date
attribute :name, type: String, mapping: { analyzer: 'string' }
attribute :published_at, type: DateTime
attribute :published_on, type: Date
end

class Application < Rails::Application
19 changes: 6 additions & 13 deletions elasticsearch-persistence/test/unit/model_store_test.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
require 'test_helper'

require 'active_model'
require 'virtus'
require 'active_attr'

require 'elasticsearch/persistence/model/base'
require 'elasticsearch/persistence/model/errors'
@@ -11,13 +10,7 @@ class Elasticsearch::Persistence::ModelStoreTest < Test::Unit::TestCase
context "The model store module," do

class DummyStoreModel
include ActiveModel::Naming
include ActiveModel::Conversion
include ActiveModel::Serialization
include ActiveModel::Serializers::JSON
include ActiveModel::Validations

include Virtus.model
include ActiveAttr::Model

include Elasticsearch::Persistence::Model::Base::InstanceMethods
extend Elasticsearch::Persistence::Model::Store::ClassMethods
@@ -27,10 +20,10 @@ class DummyStoreModel
define_model_callbacks :create, :save, :update, :destroy
define_model_callbacks :find, :touch, only: :after

attribute :title, String
attribute :count, Integer, default: 0
attribute :created_at, DateTime, default: lambda { |o,a| Time.now.utc }
attribute :updated_at, DateTime, default: lambda { |o,a| Time.now.utc }
attribute :title, type: String
attribute :count, type: Integer, default: 0
attribute :created_at, type: DateTime, default: lambda { Time.now.utc }
attribute :updated_at, type: DateTime, default: lambda { Time.now.utc }
end

setup do