elasticsearch_record 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/README.md +22 -8
  4. data/docs/CHANGELOG.md +20 -1
  5. data/lib/active_record/connection_adapters/elasticsearch/column.rb +9 -2
  6. data/lib/active_record/connection_adapters/elasticsearch/schema_definitions/clone_table_definition.rb +88 -0
  7. data/lib/active_record/connection_adapters/elasticsearch/schema_definitions/column_methods.rb +1 -1
  8. data/lib/active_record/connection_adapters/elasticsearch/schema_definitions/create_table_definition.rb +29 -27
  9. data/lib/active_record/connection_adapters/elasticsearch/schema_definitions/table_definition.rb +67 -12
  10. data/lib/active_record/connection_adapters/elasticsearch/schema_definitions/table_mapping_definition.rb +48 -13
  11. data/lib/active_record/connection_adapters/elasticsearch/schema_definitions/table_meta_definition.rb +24 -0
  12. data/lib/active_record/connection_adapters/elasticsearch/schema_definitions/table_setting_definition.rb +9 -4
  13. data/lib/active_record/connection_adapters/elasticsearch/schema_definitions/update_table_definition.rb +38 -13
  14. data/lib/active_record/connection_adapters/elasticsearch/schema_definitions.rb +3 -0
  15. data/lib/active_record/connection_adapters/elasticsearch/schema_dumper.rb +41 -0
  16. data/lib/active_record/connection_adapters/elasticsearch/schema_statements.rb +36 -10
  17. data/lib/active_record/connection_adapters/elasticsearch/table_statements.rb +102 -8
  18. data/lib/active_record/connection_adapters/elasticsearch_adapter.rb +17 -2
  19. data/lib/arel/collectors/elasticsearch_query.rb +3 -0
  20. data/lib/arel/visitors/elasticsearch_query.rb +1 -0
  21. data/lib/arel/visitors/elasticsearch_schema.rb +48 -7
  22. data/lib/elasticsearch_record/core.rb +24 -8
  23. data/lib/elasticsearch_record/gem_version.rb +1 -1
  24. data/lib/elasticsearch_record/model_schema.rb +26 -2
  25. data/lib/elasticsearch_record/persistence.rb +45 -34
  26. data/lib/elasticsearch_record/query.rb +4 -1
  27. data/lib/elasticsearch_record/schema_migration.rb +49 -0
  28. data/lib/elasticsearch_record/tasks/elasticsearch_database_tasks.rb +15 -5
  29. data/lib/elasticsearch_record.rb +1 -0
  30. metadata +6 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6cf2af35e8ed5eb94892c5e1c6c5a7b11fab36539a48a3106b3444862c3654fc
4
- data.tar.gz: 63f47637943c1e65e8d2a53c9f887b57ca5bdb139c4b6575997abbd640f2586d
3
+ metadata.gz: 8c479344b27eac6994fc17c6607f42221b093ddfc5f6db36b88994f25f2a0e56
4
+ data.tar.gz: 884ba24246d3ab9ef3500546bca84dcb3eaea184ac20bcfde6a2713e0a6def79
5
5
  SHA512:
6
- metadata.gz: 96f3ce41b50dc97f5e4d9cdf79bf5b58af5bedcf219edee5d5d22a88b6517efcad0f3d7a0e26ca0042493d83a59d274a3f33d80ec4e16032c7ec50dfcb6790b2
7
- data.tar.gz: c041e7d0bc2e00dd006d1c5b87e403b03f2e9c98a55672f636b29821a318425dc72aabff46e439a4c1281c914f1a07ac86487961f06930fac4169d538a2b9888
6
+ metadata.gz: 554ca0302d07210beef1f8bcb4b49f65b9e734122ccbbfb4a44d619d7697d1e5ec4b4164890beacaab4106654e5cdb7c817adf81d5953d46ed9f600b395e8018
7
+ data.tar.gz: 2a6a3579a00f2734c623f364a1eea5ba9802896a122c74ea4503764c63ad0294f16279b02cf3ce0f6a8d924ef3cb15004c2e2a933e90f22d311f4cbae067597c
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- elasticsearch_record (1.1.0)
4
+ elasticsearch_record (1.2.0)
5
5
  activerecord (~> 7.0.0)
6
6
  elasticsearch (~> 8.4)
7
7
 
data/README.md CHANGED
@@ -240,20 +240,24 @@ total = scope.total
240
240
  - index_base_name
241
241
  - relay_id_attribute
242
242
 
243
- ### Useful model instance methods
243
+ ### Useful model class methods
244
+ - auto_increment?
245
+ - max_result_window
244
246
  - source_column_names
245
247
  - searchable_column_names
246
248
  - find_by_query
247
249
  - msearch
248
250
 
249
- ## ActiveRecord ConnectionAdapters schema-methods
251
+ ## ActiveRecord ConnectionAdapters table-methods
250
252
  Access these methods through the model's connection.
253
+
251
254
  ```ruby
252
255
  # returns mapping of provided table (index)
253
256
  model.connection.table_mappings('table-name')
254
257
  ```
255
258
 
256
259
  - table_mappings
260
+ - table_metas
257
261
  - table_settings
258
262
  - table_aliases
259
263
  - table_state
@@ -261,12 +265,14 @@ Access these methods through the model's connection.
261
265
  - alias_exists?
262
266
  - setting_exists?
263
267
  - mapping_exists?
268
+ - meta_exists?
264
269
  - max_result_window
265
270
  - cluster_info
266
271
 
267
272
  ## Active Record Schema migration methods
268
273
  Access these methods through the model's connection or within any `Migration`.
269
274
 
275
+ **cluster actions:**
270
276
  - open_table
271
277
  - open_tables
272
278
  - close_table
@@ -274,8 +280,15 @@ Access these methods through the model's connection or within any `Migration`.
274
280
  - truncate_table
275
281
  - truncate_tables
276
282
  - drop_table
283
+ - block_table
284
+ - unblock_table
285
+ - clone_table
277
286
  - create_table
278
287
  - change_table
288
+
289
+ **table actions:**
290
+ - change_meta
291
+ - delete_meta
279
292
  - add_mapping
280
293
  - change_mapping
281
294
  - change_mapping_meta
@@ -299,11 +312,15 @@ class AddTests < ActiveRecord::Migration[7.0]
299
312
  t.setting :number_of_shards, "1"
300
313
  t.setting :number_of_replicas, 0
301
314
  end
315
+
316
+ # changes the auto-increment value
317
+ change_meta "assignments", :auto_increment, 3625
302
318
 
303
319
  create_table "settings", force: true do |t|
304
320
  t.mapping :created_at, :date
305
- t.mapping :key, :keyword do |m|
321
+ t.mapping :key, :integer do |m|
306
322
  m.primary_key = true
323
+ m.auto_increment = 10
307
324
  end
308
325
  t.mapping :status, :keyword
309
326
  t.mapping :updated_at, :date
@@ -315,11 +332,11 @@ class AddTests < ActiveRecord::Migration[7.0]
315
332
  end
316
333
 
317
334
  add_mapping "settings", :active, :boolean do |m|
318
- m.comment = "Hans"
335
+ m.comment = "Contains the active state"
319
336
  end
320
337
 
321
338
  change_table 'settings', force: true do |t|
322
- t.add_setting( "index.search.idle.after", "20s")
339
+ t.add_setting("index.search.idle.after", "20s")
323
340
  t.add_setting("index.shard.check_on_startup", true)
324
341
  t.add_alias('supersettings')
325
342
  end
@@ -337,9 +354,6 @@ class AddTests < ActiveRecord::Migration[7.0]
337
354
  t.timestamps
338
355
  end
339
356
 
340
- change_mapping_meta "vintage", :number, auto_increment: 'true'
341
- change_mapping_meta "vintage", :number, peter: 'hans'
342
-
343
357
  change_mapping_attributes "vintage", :number, fields: {raw: {type: :keyword}}
344
358
  end
345
359
 
data/docs/CHANGELOG.md CHANGED
@@ -1,6 +1,25 @@
1
1
  # ElasticsearchRecord - CHANGELOG
2
2
 
3
- ## [1.1.0] - 2022-12-02
3
+ ## [1.2.0] - 2022-12-02
4
+ * [add] `ElasticsearchRecord::SchemaMigration` to fix connection-related differences (like table_name_prefix, table_name_suffix)
5
+ * [add] connection (config-related) 'table_name_prefix' & 'table_name_suffix' - now will be forwarded to all related models & schema-tables
6
+ * [add] `#block_table`, `#unblock_table`, `#clone_table`, `#table_metas`, `#meta_exists?`, `#change_meta`, `#delete_meta` methods for Elasticsearch ConnectionAdapter
7
+ * [add] `ElasticsearchRecord::Base.auto_increment?`
8
+ * [add] index 'meta' method to access the `_meta` mapping
9
+ * [add] `.ElasticsearchRecord::Base.relay_id_attribute` to relay a possible existing 'id'-attribute
10
+ * [add] new enabled attribute `enabled` - which defines 'searchable attributes & fields' and gets also read from the index-mappings
11
+ * [ref] insert a new record with primary_key & auto_increment through a wrapper `_insert_with_auto_increment`
12
+ * [ref] resolve `primary_keys` now from the index `_meta` mapping first (old mapping-related 'meta.primary_key:"true"' is still supported)
13
+ * [ref] disable 'strict' mode (= validation) of settings, alias, mappings as default (this can be still used with `strict: true`)
14
+ * [ref] silent unsupported methods 'create/drop' for `ElasticsearchRecord::Tasks::ElasticsearchDatabaseTasks`
15
+ * [ref] primary_key & auto_increment handling of custom defined mappings - now uses the index `_meta` mapping
16
+ * [fix] creating a record with different 'primary_key' fails with removed value (value no longer gets dropped)
17
+ * [fix] some index-settings not being ignored through `#transform_settings!`
18
+ * [fix] `ActiveRecord::ConnectionAdapters::Elasticsearch::SchemaDumper` dumping environment-related tables in the same database
19
+ * [fix] `ActiveRecord::ConnectionAdapters::Elasticsearch::TableMappingDefinition` fails with explicit assignable attributes (now uses ASSIGNABLE_ATTRIBUTES)
20
+ * [fix] tables with provided 'table_name_prefix' or 'table_name_suffix' not being ignored by the SchemaDumper
21
+
22
+ ## [1.1.0] - 2022-12-01
4
23
  * [add] support for schema dumps & migrations for Elasticsearch
5
24
  * [add] `buckets` query/relation result method to resolve the buckets as key->value hash from aggregations
6
25
  * [add] support for third-party gems (e.g. elasticsearch-dsl)
@@ -5,13 +5,14 @@ module ActiveRecord
5
5
  module Elasticsearch
6
6
  class Column < ConnectionAdapters::Column # :nodoc:
7
7
 
8
- attr_reader :virtual, :fields, :properties, :meta
8
+ attr_reader :virtual, :fields, :properties, :meta, :enabled
9
9
 
10
- def initialize(name, default, sql_type_metadata = nil, virtual: false, fields: nil, properties: nil, meta: nil, **kwargs)
10
+ def initialize(name, default, sql_type_metadata = nil, virtual: false, fields: nil, properties: nil, meta: nil, enabled: nil, **kwargs)
11
11
  @virtual = virtual
12
12
  @fields = fields.presence || []
13
13
  @properties = properties.presence || []
14
14
  @meta = meta.presence || {}
15
+ @enabled = enabled.nil? ? true : enabled
15
16
 
16
17
  super(name, default, sql_type_metadata, true, nil, **kwargs)
17
18
  end
@@ -21,6 +22,12 @@ module ActiveRecord
21
22
  meta? && meta['comment']
22
23
  end
23
24
 
25
+ # returns true if this column is enabled (= searchable by queries)
26
+ # @return [Boolean]
27
+ def enabled?
28
+ !!enabled
29
+ end
30
+
24
31
  # returns true if this column is virtual.
25
32
  # Virtual columns cannot be saved.
26
33
  # @return [Boolean]
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_record/connection_adapters/elasticsearch/schema_definitions/table_definition'
4
+
5
+ module ActiveRecord
6
+ module ConnectionAdapters
7
+ module Elasticsearch
8
+ class CloneTableDefinition < TableDefinition
9
+
10
+ attr_reader :target
11
+
12
+ def initialize(conn, name, target, settings: nil, aliases: nil, **opts)
13
+ super(conn, name, **opts)
14
+
15
+ @target = target
16
+ @settings = HashWithIndifferentAccess.new
17
+ @aliases = HashWithIndifferentAccess.new
18
+
19
+ transform_settings!(settings) if settings.present?
20
+ transform_aliases!(aliases) if aliases.present?
21
+ end
22
+
23
+ # returns an array with all +TableSettingDefinition+.
24
+ # @return [Array]
25
+ def settings
26
+ @settings.values
27
+ end
28
+
29
+ # returns an array with all +TableAliasDefinition+.
30
+ # @return [Array]
31
+ def aliases
32
+ @aliases.values
33
+ end
34
+
35
+ ######################
36
+ # DEFINITION METHODS #
37
+ ######################
38
+
39
+ def setting(name, value, force: false, **options, &block)
40
+ raise ArgumentError, "you cannot define an already defined setting '#{name}'!" if @settings.key?(name) && !force?(force)
41
+
42
+ @settings[name] = new_setting_definition(name, value, **options, &block)
43
+
44
+ self
45
+ end
46
+
47
+ def remove_setting(name)
48
+ @settings.delete name
49
+ end
50
+
51
+ # we can use +alias+ here, since the instance method is not a reserved keyword!
52
+
53
+ def alias(name, force: false, **options, &block)
54
+ raise ArgumentError, "you cannot define an already defined alias '#{name}'." if @aliases.key?(name) && !force?(force)
55
+
56
+ @aliases[name] = new_alias_definition(name, **options, &block)
57
+
58
+ self
59
+ end
60
+
61
+ def remove_alias(name)
62
+ @aliases.delete name
63
+ end
64
+
65
+ private
66
+
67
+ def _before_exec
68
+ block_table(self.name, :write)
69
+ end
70
+
71
+ def _after_exec
72
+ unblock_table(self.name, :write)
73
+ end
74
+
75
+ alias :_rescue_exec :_after_exec
76
+
77
+ def _exec
78
+ execute(schema_creation.accept(self), 'CLONE TABLE').dig('acknowledged')
79
+ end
80
+
81
+ # force empty states to prevent "Name is static for an open table" error.
82
+ def state
83
+ nil
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -17,7 +17,7 @@ module ActiveRecord
17
17
  # Appends a primary key definition to the table definition.
18
18
  # Can be called multiple times, but this is probably not a good idea.
19
19
  def primary_key(name, type = :primary_key, **options)
20
- mapping(name, type, **options.merge(primary_key: true))
20
+ mapping(name, type, **options.merge(primary_key: true, auto_increment: true))
21
21
  end
22
22
  end
23
23
 
@@ -12,6 +12,7 @@ module ActiveRecord
12
12
  @settings = HashWithIndifferentAccess.new
13
13
  @mappings = HashWithIndifferentAccess.new
14
14
  @aliases = HashWithIndifferentAccess.new
15
+ @metas = HashWithIndifferentAccess.new
15
16
 
16
17
  transform_settings!(settings) if settings.present?
17
18
  transform_mappings!(mappings) if mappings.present?
@@ -30,6 +31,12 @@ module ActiveRecord
30
31
  @mappings.values
31
32
  end
32
33
 
34
+ # returns an array with all +TableMetaDefinition+.
35
+ # @return [Array]
36
+ def metas
37
+ @metas.values
38
+ end
39
+
33
40
  # provide backwards compatibility to columns
34
41
  alias columns mappings
35
42
 
@@ -48,11 +55,32 @@ module ActiveRecord
48
55
  # DEFINITION METHODS #
49
56
  ######################
50
57
 
58
+ # adds a new meta
59
+ def meta(name, value, force: false, **options)
60
+ raise ArgumentError, "you cannot define an already defined meta '#{name}'!" if @metas.key?(name) && !force?(force)
61
+
62
+ @metas[name] = new_meta_definition(name, value, **options)
63
+
64
+ self
65
+ end
66
+
67
+ def remove_meta(name)
68
+ @metas.delete(name)
69
+ end
70
+
51
71
  # adds a new mapping
52
72
  def mapping(name, type, force: false, **options, &block)
53
73
  raise ArgumentError, "you cannot define an already defined mapping '#{name}'!" if @mappings.key?(name) && !force?(force)
54
74
 
55
- @mappings[name] = new_mapping_definition(name, type, **options, &block)
75
+ mapping = new_mapping_definition(name, type, **options, &block)
76
+ @mappings[name] = mapping
77
+
78
+
79
+ # check if the mapping is assigned as primary_key
80
+ if mapping.primary_key?
81
+ meta :primary_key, mapping.name
82
+ meta(:auto_increment, mapping.auto_increment) if mapping.auto_increment?
83
+ end
56
84
 
57
85
  self
58
86
  end
@@ -126,32 +154,6 @@ module ActiveRecord
126
154
  def state
127
155
  nil
128
156
  end
129
-
130
- def transform_mappings!(mappings)
131
- return unless mappings['properties'].present?
132
-
133
- mappings['properties'].each do |name, attributes|
134
- self.mapping(name, attributes.delete('type'), **attributes)
135
- end
136
- end
137
-
138
- def transform_settings!(settings)
139
- # exclude settings, that are provided through the API but are not part of the index-settings
140
- settings
141
- .with_indifferent_access
142
- .each { |name, value|
143
- # don't transform ignored names
144
- next if ActiveRecord::ConnectionAdapters::Elasticsearch::TableSettingDefinition.match_ignore_names?(name)
145
-
146
- self.setting(name, value)
147
- }
148
- end
149
-
150
- def transform_aliases!(aliases)
151
- aliases.each do |name, attributes|
152
- self.alias(name, **attributes)
153
- end
154
- end
155
157
  end
156
158
  end
157
159
  end
@@ -10,16 +10,19 @@ module ActiveRecord
10
10
  class TableDefinition
11
11
  include ColumnMethods
12
12
 
13
- delegate :execute, :schema_creation, :column_exists?, :mapping_exists?, :setting_exists?, :alias_exists?, :close_table, :open_table, :table_mappings, to: :conn
13
+ delegate :execute, :schema_creation,
14
+ :column_exists?, :mapping_exists?, :meta_exists?, :setting_exists?, :alias_exists?,
15
+ :close_table, :open_table, :block_table, :unblock_table,
16
+ :table_mappings, :table_metas, :table_settings, to: :conn
14
17
 
15
18
  attr_reader :conn
16
19
  attr_reader :name
17
20
  attr_reader :opts
18
21
 
19
22
  def initialize(conn, name, **opts)
20
- @conn = conn
21
- @name = name
22
- @opts = opts
23
+ @conn = conn
24
+ @name = name
25
+ @opts = opts
23
26
  @failed = false
24
27
  end
25
28
 
@@ -33,10 +36,11 @@ module ActiveRecord
33
36
  yield self
34
37
  rescue => e
35
38
  @failed = false
39
+ _rescue_assign
36
40
  raise e
37
- ensure
38
- _after_assign
39
41
  end
42
+
43
+ _after_assign
40
44
  end
41
45
 
42
46
  def exec!
@@ -47,10 +51,11 @@ module ActiveRecord
47
51
  _exec
48
52
  rescue => e
49
53
  @failed = false
54
+ _rescue_exec
50
55
  raise e
51
- ensure
52
- _after_exec
53
56
  end
57
+
58
+ _after_exec
54
59
  end
55
60
 
56
61
  def failed?
@@ -67,6 +72,10 @@ module ActiveRecord
67
72
  true
68
73
  end
69
74
 
75
+ def _rescue_assign
76
+ true
77
+ end
78
+
70
79
  def _before_exec
71
80
  true
72
81
  end
@@ -75,11 +84,23 @@ module ActiveRecord
75
84
  true
76
85
  end
77
86
 
87
+ def _rescue_exec
88
+ true
89
+ end
90
+
78
91
  def _exec
79
92
  raise ArgumentError, "you cannot execute a TableDefinition directly - use 'CreateTableDefinition' or 'UpdateTableDefinition' instead!"
80
93
  end
81
94
 
82
- def new_mapping_definition(name, type, strict: true, **attributes, &block)
95
+ def new_meta_definition(name, value, strict: false, **)
96
+ meta = TableMetaDefinition.new(name, value)
97
+
98
+ raise ArgumentError, "you cannot define an invalid meta '#{name}' (#{meta.error_messages})!" if strict?(strict) && !meta.valid?
99
+
100
+ meta
101
+ end
102
+
103
+ def new_mapping_definition(name, type, strict: false, **attributes, &block)
83
104
  mapping = TableMappingDefinition.new(name, type, attributes)
84
105
  block.call(mapping) if block_given?
85
106
 
@@ -90,7 +111,7 @@ module ActiveRecord
90
111
 
91
112
  alias :new_column_definition :new_mapping_definition
92
113
 
93
- def new_alias_definition(name, strict: true, **attributes, &block)
114
+ def new_alias_definition(name, strict: false, **attributes, &block)
94
115
  # create new alias
95
116
  tbl_alias = TableAliasDefinition.new(name, attributes)
96
117
  block.call(tbl_alias) if block_given?
@@ -100,7 +121,7 @@ module ActiveRecord
100
121
  tbl_alias
101
122
  end
102
123
 
103
- def new_setting_definition(name, value, strict: true, **, &block)
124
+ def new_setting_definition(name, value, strict: false, **, &block)
104
125
  # create new setting
105
126
  setting = TableSettingDefinition.new(name, value).with_state(state)
106
127
  block.call(setting) if block_given?
@@ -124,7 +145,41 @@ module ActiveRecord
124
145
  end
125
146
 
126
147
  def strict?(strict = nil)
127
- opts.fetch(:strict, true) && strict != false
148
+ opts.fetch(:strict, false) || strict
149
+ end
150
+
151
+ def transform_mappings!(mappings)
152
+ # transform +_meta+ mappings
153
+ if mappings['_meta'].present?
154
+ mappings['_meta'].each do |name, value|
155
+ self.meta(name, value)
156
+ end
157
+ end
158
+
159
+ # transform properties (=columns)
160
+ if mappings['properties'].present?
161
+ mappings['properties'].each do |name, attributes|
162
+ self.mapping(name, attributes.delete('type'), **attributes)
163
+ end
164
+ end
165
+ end
166
+
167
+ def transform_settings!(settings)
168
+ # exclude settings, that are provided through the API but are not part of the index-settings
169
+ settings
170
+ .with_indifferent_access
171
+ .each { |name, value|
172
+ # don't transform ignored names
173
+ next if ActiveRecord::ConnectionAdapters::Elasticsearch::TableSettingDefinition.match_ignore_names?(name)
174
+
175
+ self.setting(name, value)
176
+ }
177
+ end
178
+
179
+ def transform_aliases!(aliases)
180
+ aliases.each do |name, attributes|
181
+ self.alias(name, **attributes)
182
+ end
128
183
  end
129
184
  end
130
185
  end
@@ -16,6 +16,9 @@ module ActiveRecord
16
16
  :index_prefixes, :index, :meta, :normalizer, :norms, :null_value, :position_increment_gap,
17
17
  :properties, :search_analyzer, :similarity, :subobjects, :store, :term_vector].freeze
18
18
 
19
+ # define virtual attributes, that must be assigned due a special logic
20
+ ASSIGNABLE_ATTRIBUTES = [:comment, :primary_key, :auto_increment, :meta].freeze
21
+
19
22
  build_attribute_methods! *ATTRIBUTES
20
23
 
21
24
  # attributes
@@ -27,10 +30,7 @@ module ActiveRecord
27
30
  validates_presence_of :name
28
31
  validates_presence_of :type
29
32
  validates_inclusion_of :__attributes_keys, in: ATTRIBUTES, allow_blank: true
30
-
31
- # disable validation for meta attribute - maybe future updates of Elasticsearch have other restrictions.
32
- # To not be hooked on those possible changes we
33
- #validate :_validate_meta
33
+ validate :_validate_meta
34
34
 
35
35
  # sets the default value (alias for null_value)
36
36
  alias_method :default=, :null_value=
@@ -41,32 +41,62 @@ module ActiveRecord
41
41
  ####################
42
42
 
43
43
  def initialize(name, type, attributes)
44
- @name = name.to_sym
45
- @attributes = attributes.symbolize_keys
44
+ @name = name.to_sym
45
+
46
+ attributes = attributes.symbolize_keys
47
+ # directly set attributes, that cannot be assigned
48
+ @attributes = attributes.except(*ASSIGNABLE_ATTRIBUTES)
49
+ # assign special attributes
50
+ __assign(attributes.slice(*ASSIGNABLE_ATTRIBUTES))
46
51
 
47
52
  @type = _resolve_type(type)
48
53
  end
49
54
 
50
- # comment is handled as nested key from 'meta' attribute
55
+ # returns the +comment+ from 'meta' attribute
56
+ # @return [String, nil]
51
57
  def comment
52
58
  __get_nested(:meta, :comment)
53
59
  end
54
60
 
61
+ # sets the +comment+ as 'meta' attribute
62
+ # @param [String] value
55
63
  def comment=(value)
56
64
  # important: meta-values can only be strings!
57
65
  __set_nested(:meta, :comment, value.to_s)
58
66
  end
59
67
 
68
+ # returns true if the +primary_key+ 'attribute' was provided
69
+ # @return [Boolean]
60
70
  def primary_key
61
- __get_nested(:meta, :primary_key) == 'true'
71
+ !!_lazy_attributes[:primary_key]
62
72
  end
63
73
 
64
74
  alias_method :primary_key?, :primary_key
65
75
 
66
- # defines this mapping as a primary key
76
+ # sets the +primary_key+ as 'lazy_attribute'
77
+ # @param [Boolean] value
67
78
  def primary_key=(value)
68
- # important: meta-values can only be strings!
69
- __set_nested(:meta, :primary_key, value ? 'true' : nil)
79
+ _lazy_attributes[:primary_key] = value
80
+ end
81
+
82
+ # returns the +auto_increment+ value, if provided
83
+ # @return [Integer]
84
+ def auto_increment
85
+ return nil unless _lazy_attributes[:auto_increment]
86
+ return 0 if _lazy_attributes[:auto_increment] == true
87
+ _lazy_attributes[:auto_increment].to_i
88
+ end
89
+
90
+ # returns true if the +auto_increment+ 'attribute' was provided
91
+ # @return [Boolean]
92
+ def auto_increment?
93
+ !!auto_increment
94
+ end
95
+
96
+ # sets the +auto_increment+ as 'lazy_attribute'
97
+ # @param [Boolean, Integer] value
98
+ def auto_increment=(value)
99
+ _lazy_attributes[:auto_increment] = value
70
100
  end
71
101
 
72
102
  def meta=(value)
@@ -79,6 +109,11 @@ module ActiveRecord
79
109
 
80
110
  private
81
111
 
112
+ # non persistent attributes
113
+ def _lazy_attributes
114
+ @_lazy_attributes ||= {}
115
+ end
116
+
82
117
  # resolves the provided type.
83
118
  # prevents to set a nil type (sets +:object+ or +:nested+ - depends on existing properties)
84
119
  # @return [Symbol, nil]
@@ -99,8 +134,8 @@ module ActiveRecord
99
134
  return invalid!("'meta' is not supported on object or nested types", :attributes) if [:object, :nested].include?(type)
100
135
 
101
136
  # allow only strings
102
- vkey = meta.keys.detect { |key| !meta[key].is_a?(String) }
103
- return invalid!("'meta' has a key '#{vkey}' with a none string value", :attributes) if vkey.present?
137
+ failed_key = meta.keys.detect { |key| !meta[key].is_a?(String) }
138
+ return invalid!("'meta' has a key '#{failed_key}' with a none string value", :attributes) if failed_key.present?
104
139
 
105
140
  true
106
141
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_model/validations'
4
+
5
+ module ActiveRecord
6
+ module ConnectionAdapters
7
+ module Elasticsearch
8
+ class TableMetaDefinition
9
+ include ActiveModel::Validations
10
+
11
+ # attributes
12
+ attr_accessor :name
13
+ attr_accessor :value
14
+
15
+ validates_presence_of :name
16
+
17
+ def initialize(name, value)
18
+ @name = name.to_sym
19
+ @value = value
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end