lycra 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 126274cca99ee2410f645b376c5996c4f431bba2
4
- data.tar.gz: 447266fffb8f6976dc8ab21955e3c582e9a93c2d
3
+ metadata.gz: 91043f8065e7fcf15adf93772387b25ad5e84259
4
+ data.tar.gz: 8319be6afc7ee3594784357ffb744dc4b9e71d4f
5
5
  SHA512:
6
- metadata.gz: 70daf0ce79d6ce0609018e69469f9f3e766c42bc647673a9a342ca8cef9ffa9cda3ab3d7cb223febd43049eac6168d619ff20fe9608a1f39f743d600668e201a
7
- data.tar.gz: 1918d122e52cf13dd060c501ce80368952b4a97de16a1867ba29ea8b466d7c9cfef878ce1345cdec295b280c51643bdd31ae8282a46f3cfe699c2947ad7c14de
6
+ metadata.gz: 06811b5b68df2ad87ddf8e35ba19873add41e5a4325dfa3615b822235bcaa615849bf75d846583e043b4d4472e0819c3bf553357f7e8afd489ca8cf29df7ca64
7
+ data.tar.gz: e30ee923b27916255f75c8be97dca2f806cbec8bdd2e770fa4a766baa0a555fb635b720f4364cb12faefbbd78c146c7369bc9969c77031d0bec4196525fcd4ac
@@ -0,0 +1,191 @@
1
+ require 'elasticsearch/persistence/model'
2
+
3
+ module Lycra
4
+ # TODO explain how this is used, what it is, why, etc.
5
+
6
+ # TODO add validations for the results of as_indexed_json against the mapped attributes
7
+
8
+ class Document
9
+ attr_reader :subject
10
+
11
+ INDEX_REGEX = /\A#{::Lycra.configuration.index_prefix}-?/
12
+
13
+ class << self
14
+ def inherited(base)
15
+ # Make sure we inherit the parent's class-level instance variables whenever we inherit from the class.
16
+ # TODO add more comments/examples explaining why we clone these vars
17
+ base.send :instance_variable_set, :@lycra_index_name, index_name.try(:dup)
18
+ base.send :instance_variable_set, :@lycra_document_type, document_type.try(:dup)
19
+ base.send :instance_variable_set, :@lycra_attributes, attributes.try(:dup)
20
+ base.send :instance_variable_set, :@lycra_mapping, mapping.try(:dup)
21
+ base.send :instance_variable_set, :@lycra_settings, settings.try(:dup)
22
+ end
23
+
24
+ def document_type(doctype=nil)
25
+ @lycra_document_type = doctype if doctype.present?
26
+ @lycra_document_type
27
+ end
28
+
29
+ def index_name(zindex_name=nil)
30
+ @lycra_index_name = prefixed_index_name(zindex_name) if zindex_name.present?
31
+ @lycra_index_name
32
+ end
33
+
34
+ def attribute(name, type, mappings={})
35
+ attributes[name] = {type: Elasticsearch::Persistence::Model::Utils.lookup_type(type)}.merge(mappings[:mapping] || {})
36
+ end
37
+
38
+ def attributes(attrs=nil)
39
+ @lycra_attributes = attrs if attrs.present?
40
+ @lycra_attributes ||= {}
41
+ end
42
+
43
+ def mapping(map=nil)
44
+ @lycra_mapping = map if map.present?
45
+ @lycra_mapping ||= {}
46
+ end
47
+ alias_method :mappings, :mapping
48
+
49
+ def settings(settings=nil)
50
+ @lycra_settings = settings if settings.present?
51
+ @lycra_settings ||= {}
52
+ end
53
+
54
+ def prefixed_index_name(idx)
55
+ [::Lycra.configuration.index_prefix, idx.to_s.gsub(INDEX_REGEX, '')].compact.join('-')
56
+ end
57
+
58
+ def index_basename
59
+ index_name.to_s.gsub(INDEX_REGEX, '')
60
+ end
61
+
62
+ def import(*models, **opts, &block)
63
+ models = [models].flatten
64
+ document = models.first.lycra_document
65
+ raise ArgumentError, 'All models must use the same index in order to be imported together' unless models.all? { |model| model.index_name == document.index_name }
66
+
67
+ index_name = opts.delete(:index_name) || document.index_name
68
+
69
+ if opts.delete(:force) == true && document.__elasticsearch__.client.indices.exists?(index: index_name)
70
+ # delete the index if it exists and the force-create option was passed
71
+ document.__elasticsearch__.client.indices.delete index: index_name
72
+ end
73
+
74
+ unless document.__elasticsearch__.client.indices.exists?(index: index_name)
75
+ document.__elasticsearch__.client.indices.create index: index_name, update_all_types: true, body: {
76
+ settings: document.settings,
77
+ mappings: models.inject({}) { |mappings, model| mappings.merge!(model.mappings) } # hacky, need to map all the document mappings
78
+ }
79
+ end
80
+
81
+ models.each do |model|
82
+ model.index_name index_name
83
+ model.import **opts, &block
84
+ model.index_name document.index_name
85
+ end
86
+ end
87
+
88
+ def rotate(*models, **opts, &block)
89
+ models = [models].flatten
90
+ document = models.first.lycra_document
91
+ raise ArgumentError, 'All models must use the same index in order to be imported together' unless models.all? { |model| model.index_name == document.index_name }
92
+
93
+ unstamped_alias = document.index_name
94
+ timestamped_index = [unstamped_alias, Time.now.to_i].compact.join('-')
95
+ existing_index = nil
96
+
97
+ import(*models, **opts.merge({index_name: timestamped_index}), &block)
98
+
99
+ if document.__elasticsearch__.client.indices.exists_alias? name: unstamped_alias
100
+ existing_index = document.__elasticsearch__.client.indices.get_alias(name: unstamped_alias).keys.first
101
+ document.__elasticsearch__.client.indices.delete_alias name: unstamped_alias, index: existing_index
102
+ elsif document.__elasticsearch__.client.indices.exists? index: unstamped_alias
103
+ document.__elasticsearch__.client.indices.delete index: unstamped_alias
104
+ end
105
+ document.__elasticsearch__.client.indices.put_alias name: unstamped_alias, index: timestamped_index
106
+ document.__elasticsearch__.client.indices.delete index: existing_index unless existing_index.nil?
107
+ end
108
+ end
109
+
110
+ # NOTE: HEADS UP! Yes, this is an INSTANCE METHOD!
111
+ # It is a shortcut, since this class represents both your model **class** (i.e. MyModel) and your model **records** (i.e. MyModel.find(1)).
112
+ #
113
+ # normal class usage allows for things like:
114
+ #
115
+ # MyDocument.new(MyModel) # interact with elasticsearch at the model level (index names, mappings, etc.)
116
+ # MyDocument.new(MyModel.find(1)) # interact with elasticsearch at the record level (as_indexed_json, also has access to index name, etc.)
117
+ #
118
+ # but with this, we also get:
119
+ #
120
+ # document = MyDocument.new(MyModel) # instantiate a class-level model document
121
+ # # ... do some stuff at the class-level ...
122
+ # document.new(my_model_record) # easily re-use the same document class to decorate your record without needing to know what it was
123
+ # # ... do some stuff with your record ...
124
+ def new(object)
125
+ self.class.new(object)
126
+ end
127
+
128
+ def initialize(subject)
129
+ @subject = subject
130
+
131
+ if subject.is_a?(Class)
132
+ # TODO explain why and/or maybe add some ! methods that are more explicit about what we're doing
133
+ unless self.class.index_name.present?
134
+ raise Lycra::UndefinedIndexError, self
135
+ end
136
+
137
+ index_name(self.class.index_name)
138
+ document_type(self.class.document_type)
139
+ mapping(self.class.mapping)
140
+ settings(self.class.settings)
141
+ end
142
+ end
143
+
144
+ def document_type(doctype=nil)
145
+ subject.__elasticsearch__.document_type doctype
146
+ end
147
+
148
+ def index_name(idx=nil)
149
+ if idx.present?
150
+ subject.__elasticsearch__.index_name self.class.prefixed_index_name(idx)
151
+ else
152
+ subject.__elasticsearch__.index_name
153
+ end
154
+ end
155
+
156
+ def mapping(options={}, &block)
157
+ self.class.attributes.each do |field, opts|
158
+ subject.__elasticsearch__.mapping.indexes field, opts
159
+ end
160
+
161
+ if options.present? || block_given?
162
+ subject.__elasticsearch__.mapping options, &block
163
+ end
164
+
165
+ subject.__elasticsearch__.mapping
166
+ end
167
+ alias_method :mappings, :mapping
168
+
169
+ def settings(settings=nil, &block)
170
+ subject.__elasticsearch__.settings settings, &block if settings.present? || block_given?
171
+ subject.__elasticsearch__.settings
172
+ end
173
+
174
+ def method_missing(meth, *args, &block)
175
+ return subject.send(meth, *args, &block) if respond_to_missing?(meth, true)
176
+ super
177
+ end
178
+
179
+ def respond_to_missing?(meth, include_private=false)
180
+ subject.respond_to?(meth, include_private)
181
+ end
182
+
183
+ def as_json(opts={})
184
+ subject.as_json(opts)
185
+ end
186
+
187
+ def as_indexed_json(opts={})
188
+ as_json(opts)
189
+ end
190
+ end
191
+ end
data/lib/lycra/version.rb CHANGED
@@ -2,7 +2,7 @@ module Lycra
2
2
  module Version
3
3
  MAJOR = '0'
4
4
  MINOR = '0'
5
- PATCH = '3'
5
+ PATCH = '4'
6
6
  VERSION = "#{MAJOR}.#{MINOR}.#{PATCH}"
7
7
 
8
8
  class << self
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lycra
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mark Rebec
@@ -158,6 +158,7 @@ executables: []
158
158
  extensions: []
159
159
  extra_rdoc_files: []
160
160
  files:
161
+ - app/documents/lycra/document.rb
161
162
  - lib/lycra.rb
162
163
  - lib/lycra/engine.rb
163
164
  - lib/lycra/errors.rb