forked from elastic/elasticsearch-rails
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmodel.rb
135 lines (110 loc) · 4.44 KB
/
model.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
require 'active_support/core_ext/module/delegation'
require 'active_model'
require 'virtus'
require 'elasticsearch/persistence'
require 'elasticsearch/persistence/model/base'
require 'elasticsearch/persistence/model/errors'
require 'elasticsearch/persistence/model/store'
require 'elasticsearch/persistence/model/find'
module Elasticsearch
module Persistence
# When included, extends a plain Ruby class with persistence-related features via the ActiveRecord pattern
#
# @example Include the repository in a custom class
#
# require 'elasticsearch/persistence/model'
#
# class MyObject
# include Elasticsearch::Persistence::Repository
# end
#
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
extend ActiveModel::Callbacks
define_model_callbacks :create, :save, :update, :destroy
define_model_callbacks :find, :touch, only: :after
include Elasticsearch::Persistence::Model::Base::InstanceMethods
extend Elasticsearch::Persistence::Model::Store::ClassMethods
include Elasticsearch::Persistence::Model::Store::InstanceMethods
extend Elasticsearch::Persistence::Model::Find::ClassMethods
class << self
# Re-define the Virtus' `attribute` method, to configure Elasticsearch mapping as well
#
def attribute(name, type=nil, options={}, &block)
mapping = options.delete(:mapping) || {}
super
gateway.mapping do
indexes name, {type: Utils::lookup_type(type)}.merge(mapping)
end
gateway.mapping(&block) if block_given?
end
# Return the {Repository::Class} instance
#
def gateway(&block)
@gateway ||= Elasticsearch::Persistence::Repository::Class.new host: self
block.arity < 1 ? @gateway.instance_eval(&block) : block.call(@gateway) if block_given?
@gateway
end
# Delegate methods to repository
#
delegate :settings,
:mappings,
:mapping,
:document_type=,
:index_name,
:index_name=,
:find,
:exists?,
:create_index!,
:refresh_index!,
to: :gateway
# forward document type to mappings when set
def document_type(type = nil)
return gateway.document_type unless type
gateway.document_type type
mapping.type = type
end
end
# Configure the repository based on the model (set up index_name, etc)
#
gateway do
klass base
index_name base.model_name.collection.gsub(/\//, '-')
document_type base.model_name.element
def serialize(document)
document.to_hash.except(:id, 'id')
end
def deserialize(document)
object = klass.new document['_source']
# Set the meta attributes when fetching the document from Elasticsearch
#
object.instance_variable_set :@_id, document['_id']
object.instance_variable_set :@_index, document['_index']
object.instance_variable_set :@_type, document['_type']
object.instance_variable_set :@_version, document['_version']
object.instance_variable_set :@_source, document['_source']
# Store the "hit" information (highlighting, score, ...)
#
object.instance_variable_set :@hit,
Hashie::Mash.new(document.except('_index', '_type', '_id', '_version', '_source'))
object.instance_variable_set(:@persisted, true)
object
end
end
# 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 }
attr_reader :hit
end
end
end
end
end