ar_doc_store 1.0.5 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/ar_doc_store.gemspec +3 -3
  3. data/lib/ar_doc_store.rb +30 -28
  4. data/lib/ar_doc_store/attributes/array.rb +25 -0
  5. data/lib/ar_doc_store/attributes/base.rb +72 -0
  6. data/lib/ar_doc_store/attributes/boolean.rb +17 -0
  7. data/lib/ar_doc_store/attributes/callback_support.rb +21 -0
  8. data/lib/ar_doc_store/attributes/date.rb +21 -0
  9. data/lib/ar_doc_store/attributes/datetime.rb +21 -0
  10. data/lib/ar_doc_store/attributes/decimal.rb +17 -0
  11. data/lib/ar_doc_store/attributes/embeds_base.rb +35 -0
  12. data/lib/ar_doc_store/attributes/embeds_many.rb +143 -0
  13. data/lib/ar_doc_store/{attribute_types/embeds_one_attribute.rb → attributes/embeds_one.rb} +25 -30
  14. data/lib/ar_doc_store/{attribute_types/enumeration_attribute.rb → attributes/enumeration.rb} +2 -6
  15. data/lib/ar_doc_store/{attribute_types/float_attribute.rb → attributes/float.rb} +5 -8
  16. data/lib/ar_doc_store/{attribute_types/integer_attribute.rb → attributes/integer.rb} +5 -8
  17. data/lib/ar_doc_store/attributes/string.rb +13 -0
  18. data/lib/ar_doc_store/embeddable_model.rb +51 -75
  19. data/lib/ar_doc_store/embedded_collection.rb +14 -0
  20. data/lib/ar_doc_store/embedding.rb +0 -2
  21. data/lib/ar_doc_store/model.rb +18 -8
  22. data/lib/ar_doc_store/storage.rb +4 -127
  23. data/lib/ar_doc_store/types/embeds_many.rb +52 -0
  24. data/lib/ar_doc_store/types/embeds_one.rb +42 -0
  25. data/lib/ar_doc_store/version.rb +1 -1
  26. data/test/{attribute_types → attributes}/array_attribute_test.rb +5 -1
  27. data/test/{attribute_types → attributes}/boolean_attribute_test.rb +7 -1
  28. data/test/attributes/date_attribute_test.rb +52 -0
  29. data/test/attributes/datetime_attribute_test.rb +54 -0
  30. data/test/attributes/decimal_attribute_test.rb +38 -0
  31. data/test/attributes/embeds_many_attribute_test.rb +78 -0
  32. data/test/attributes/embeds_one_attribute_test.rb +80 -0
  33. data/test/{attribute_types → attributes}/enumeration_attribute_test.rb +5 -0
  34. data/test/{attribute_types → attributes}/float_attribute_test.rb +6 -1
  35. data/test/attributes/integer_attribute_test.rb +63 -0
  36. data/test/{attribute_types → attributes}/string_attribute_test.rb +6 -0
  37. data/test/test_helper.rb +22 -94
  38. metadata +57 -35
  39. data/lib/ar_doc_store/attribute_types/array_attribute.rb +0 -30
  40. data/lib/ar_doc_store/attribute_types/base_attribute.rb +0 -61
  41. data/lib/ar_doc_store/attribute_types/boolean_attribute.rb +0 -25
  42. data/lib/ar_doc_store/attribute_types/datetime_attribute.rb +0 -17
  43. data/lib/ar_doc_store/attribute_types/embeds_many_attribute.rb +0 -165
  44. data/lib/ar_doc_store/attribute_types/string_attribute.rb +0 -17
  45. data/lib/ar_doc_store/attribute_types/uuid_attribute.rb +0 -30
  46. data/test/attribute_types/datetime_attribute_test.rb +0 -35
  47. data/test/attribute_types/integer_attribute_test.rb +0 -33
  48. data/test/originals/dirty_attributes_test.rb +0 -35
  49. data/test/originals/embedded_model_attribute_test.rb +0 -23
  50. data/test/originals/embedding_test.rb +0 -82
@@ -1,25 +0,0 @@
1
- module ArDocStore
2
- module AttributeTypes
3
-
4
- class BooleanAttribute < BaseAttribute
5
- def build
6
- key = attribute.to_sym
7
- model.class_eval do
8
- store_accessor json_column, key
9
- define_method "#{key}?".to_sym, -> { public_send(key) == true }
10
- define_method "#{key}=".to_sym, -> (value) {
11
- res = ArDocStore.convert_boolean(value)
12
- write_store_attribute(json_column, key, res)
13
- }
14
- add_ransacker(key, 'bool')
15
- end
16
- end
17
-
18
- def type
19
- :boolean
20
- end
21
-
22
- end
23
-
24
- end
25
- end
@@ -1,17 +0,0 @@
1
- module ArDocStore
2
- module AttributeTypes
3
- class DatetimeAttribute < BaseAttribute
4
- def type
5
- :datetime
6
- end
7
-
8
- def load
9
- :to_time
10
- end
11
-
12
- def dump
13
- :to_s
14
- end
15
- end
16
- end
17
- end
@@ -1,165 +0,0 @@
1
- module ArDocStore
2
-
3
- class EmbeddedCollection < Array
4
- attr_accessor :parent
5
- end
6
-
7
- module AttributeTypes
8
-
9
- class EmbedsManyAttribute < BaseAttribute
10
-
11
- def build
12
- assn_name = attribute.to_sym
13
- class_name = options[:class_name] || attribute.to_s.classify
14
- model.store_accessor model.json_column, assn_name
15
- create_reader_for assn_name, class_name
16
- create_writer_for assn_name, class_name
17
- create_build_method_for assn_name, class_name
18
- create_ensure_method_for assn_name
19
- create_embeds_many_attributes_method(class_name, assn_name)
20
- create_embeds_many_validation(assn_name)
21
- end
22
-
23
- private
24
-
25
- def add_method(method, block)
26
- model.class_eval do
27
- define_method method, block
28
- end
29
- end
30
-
31
- def create_reader_for(assn_name, class_name)
32
- add_method assn_name.to_sym, -> {
33
- ivar = "@#{assn_name}"
34
- instance_variable_get(ivar) || begin
35
- my_class_name = class_name.constantize
36
- items = read_store_attribute(json_column, assn_name)
37
- if items.is_a?(Array) || items.is_a?(ArDocStore::EmbeddedCollection)
38
- items = ArDocStore::EmbeddedCollection.new items.map { |item| item.is_a?(my_class_name) ? item : my_class_name.build(item) }
39
- else
40
- items ||= ArDocStore::EmbeddedCollection.new
41
- end
42
- instance_variable_set ivar, (items)
43
- items.parent = self
44
- items.map {|item| item.parent = self }
45
- items
46
- end
47
- }
48
- end
49
- def create_writer_for(assn_name, class_name)
50
- add_method "#{assn_name}=".to_sym, -> (values) {
51
- if values && values.respond_to?(:map)
52
- items = ArDocStore::EmbeddedCollection.new values.map { |item|
53
- my_class_name = class_name.constantize
54
- item = item.is_a?(my_class_name) ? item : my_class_name.new(item)
55
- item.id
56
- item.parent = self
57
- item
58
- }
59
- else
60
- items = []
61
- end
62
- items.parent = self
63
- instance_variable_set "@#{assn_name}", write_store_attribute(json_column, assn_name, items)
64
- }
65
- end
66
-
67
- def create_build_method_for(assn_name, class_name)
68
- add_method "build_#{assn_name.to_s.singularize}", -> (attributes=nil) {
69
- assns = self.public_send assn_name
70
- item = class_name.constantize.build attributes
71
- item.parent = self
72
- assns << item
73
- public_send "#{assn_name}=", assns
74
- item
75
- }
76
- end
77
-
78
- def create_ensure_method_for(assn_name)
79
- method = -> { public_send "build_#{assn_name.to_s.singularize}" if self.public_send(assn_name).blank? }
80
- add_method "ensure_#{assn_name.to_s.singularize}", method
81
- add_method "ensure_#{assn_name}", method
82
- end
83
-
84
- def create_embeds_many_attributes_method(class_name, assn_name)
85
- add_method "#{assn_name}_attributes=", -> (values) {
86
- return if values.blank?
87
- # if it's a single item then wrap it in an array but how to tell?
88
-
89
- if values.respond_to?(:each)
90
- if values.respond_to?(:values)
91
- values = values.values
92
- end
93
- else
94
- values = [values]
95
- end
96
- models = public_send assn_name
97
- public_send "#{assn_name}=", AssignEmbedsManyAttributes.new(self, class_name, assn_name, models, values).models
98
- }
99
- end
100
-
101
- def create_embeds_many_validation(assn_name)
102
- model.class_eval do
103
- validate_method = "validate_embedded_record_for_#{assn_name}".to_sym
104
- define_method validate_method, -> { validate_embeds_many assn_name }
105
- validate validate_method
106
- end
107
- end
108
-
109
-
110
- end
111
-
112
- class AssignEmbedsManyAttributes
113
- attr_reader :models, :assn_name, :parent, :class_name
114
- def initialize(parent, class_name, assn_name, models, values)
115
- @parent, @class_name, @assn_name, @models, @values = parent, class_name, assn_name, models, values
116
- values.each { |value|
117
- value = value.symbolize_keys
118
- if value.key?(:id)
119
- process_existing_model(value)
120
- else
121
- next if values.all?(&:nil?)
122
- add(value)
123
- end
124
- }
125
- end
126
-
127
- private
128
-
129
- attr_writer :models, :values
130
- attr_reader :values, :assn_name
131
-
132
- def process_existing_model(value)
133
- return false unless value.key?(:id)
134
- model = find_model_by_value(value)
135
- model && destroy_or_update(model, value) or add(value)
136
- end
137
-
138
- def destroy_or_update(model, value)
139
- destroy(model, value) or update_attributes(model, value)
140
- end
141
-
142
- def add(value)
143
- models << class_name.constantize.new(value)
144
- end
145
-
146
- def destroy(model, value)
147
- wants_to_die?(value) && models.delete(model)
148
- end
149
-
150
- def update_attributes(model, value)
151
- model.attributes = value
152
- end
153
-
154
- def wants_to_die?(value)
155
- value.key?(:_destroy) && ArDocStore.convert_boolean(value[:_destroy])
156
- end
157
-
158
- def find_model_by_value(value)
159
- models.detect { |item| item.id == value[:id] }
160
- end
161
- end
162
-
163
-
164
- end
165
- end
@@ -1,17 +0,0 @@
1
- module ArDocStore
2
- module AttributeTypes
3
-
4
- class StringAttribute < BaseAttribute
5
- def conversion
6
- :to_s
7
- end
8
-
9
- def predicate
10
- 'text'
11
- end
12
-
13
- end
14
-
15
- end
16
- end
17
-
@@ -1,30 +0,0 @@
1
- require 'securerandom'
2
-
3
- module ArDocStore
4
- module AttributeTypes
5
-
6
- class UuidAttribute < BaseAttribute
7
- def build
8
- key = attribute.to_sym
9
- model.class_eval do
10
- store_accessor json_column, key
11
- define_method key, -> {
12
- value = read_store_attribute(json_column, key)
13
- unless value
14
- value = SecureRandom.uuid
15
- write_store_attribute json_column, key, value
16
- end
17
- value
18
- }
19
- define_method "#{key}=".to_sym, -> (value) {
20
- write_store_attribute(json_column, key, value)
21
- }
22
- add_ransacker(key, 'text')
23
- end
24
- end
25
-
26
-
27
- end
28
-
29
- end
30
- end
@@ -1,35 +0,0 @@
1
- require_relative './../test_helper'
2
-
3
- class DatetimeAttributeTest < MiniTest::Test
4
-
5
- def test_attribute_on_model_init
6
- approved_at = Time.new(1984, 3, 6)
7
- po = PurchaseOrder.new approved_at: approved_at
8
- assert approved_at == po.approved_at
9
- end
10
-
11
- def test_attribute_on_existing_model
12
- approved_at = Time.new(1984, 3, 6)
13
- po = PurchaseOrder.new
14
- po.approved_at = approved_at
15
- assert approved_at == po.approved_at
16
- assert po.approved_at_changed?
17
- end
18
-
19
- def test_question_mark_method
20
- approved_at = Time.new(1984, 3, 6)
21
- po = PurchaseOrder.new approved_at: approved_at
22
- assert_equal true, po.approved_at?
23
- end
24
-
25
- def test_conversion
26
- approved_at = Time.new(1984, 3, 6)
27
- po = PurchaseOrder.new approved_at: approved_at.to_s
28
- assert_kind_of Time, po.approved_at
29
- end
30
-
31
- def test_no_op
32
- po = PurchaseOrder.new
33
- assert_nil po.approved_at
34
- end
35
- end
@@ -1,33 +0,0 @@
1
- require_relative './../test_helper'
2
-
3
- class IntegerAttributeTest < MiniTest::Test
4
-
5
- def test_string_attribute_on_model_init
6
- b = Building.new stories: 5
7
- assert_equal 5, b.stories
8
- end
9
-
10
- def test_string_attribute_on_existing_model
11
- b = Building.new
12
- b.stories = 5
13
- assert_equal 5, b.stories
14
- assert b.stories_changed?
15
- end
16
-
17
- def test_question_mark_method
18
- b = Building.new stories: 5
19
- assert_equal true, b.stories?
20
- end
21
-
22
- def test_type_conversion_on_init
23
- b = Building.new stories: '5'
24
- assert_equal 5, b.stories
25
- end
26
-
27
- def test_type_conversion_on_existing
28
- b = Building.new
29
- b.stories = '5'
30
- assert_equal 5, b.stories
31
- end
32
-
33
- end
@@ -1,35 +0,0 @@
1
- require_relative './../test_helper'
2
-
3
- class DirtyAttributeTest < MiniTest::Test
4
-
5
- def test_on_model
6
- b = Building.new name: 'Foo!'
7
- # This used to work but started failing. AR behavior is to make it true.
8
- # send :clear_changes_information not working yields undefined method.
9
- # assert !b.name_changed?
10
- b.name = 'Bar.'
11
- assert_equal 'Bar.', b.name
12
- assert b.name_changed?
13
- # Somehow this worked at one point, but should only work when the record is loaded via instantiate:
14
- # assert_equal 'Foo!', b.name_was
15
- end
16
-
17
- #This test fails here but passes elsewhere.
18
- def test_on_embedded_model
19
- b = Building.new
20
- r = b.build_restroom restroom_type: 'dirty'
21
- assert !r.restroom_type_changed?
22
- r.restroom_type = 'nasty'
23
- assert r.restroom_type_changed?
24
- assert_equal 'dirty', r.restroom_type_was
25
- assert_equal 'nasty', r.restroom_type
26
- end
27
-
28
- def test_id_does_not_change_on_init
29
- b = Building.new
30
- r = b.build_restroom
31
- assert !r.id_changed?
32
- assert !r.changes.keys.include?('id')
33
- end
34
-
35
- end
@@ -1,23 +0,0 @@
1
- require_relative './../test_helper'
2
-
3
- class EmbeddedModelAttributeTest < MiniTest::Test
4
-
5
- def test_can_set_attribute_on_embedded_model_init
6
- b = Route.new route_surface: 'test'
7
- assert_equal 'test', b.route_surface
8
- end
9
-
10
- def test_can_set_attribute_on_existing_embedded_model
11
- b = Route.new
12
- b.route_surface = 'test'
13
- assert_equal 'test', b.route_surface
14
- end
15
-
16
- def test_can_set_enumeration_created_with_enumerates
17
- door = Door.new
18
- door.door_type = %w{sliding push}
19
- assert_equal %w{sliding push}, door.door_type
20
- end
21
-
22
- end
23
-
@@ -1,82 +0,0 @@
1
- require_relative './../test_helper'
2
-
3
- class EmbeddingTest < MiniTest::Test
4
-
5
- def test_can_build_embedded_model
6
- restroom = Restroom.new
7
- door = restroom.build_door
8
- assert door.is_a?(Door)
9
- end
10
-
11
- def test_ensure_door_returns_existing_door
12
- restroom = Restroom.new
13
- restroom.build_door
14
- restroom.door.open_handle = %w{knob}
15
- restroom.ensure_door
16
- assert_equal %w{knob}, restroom.door.open_handle
17
- end
18
-
19
- def test_attributes_equals_sets_attributes
20
- restroom = Restroom.new door_attributes: { clear_distance: 5, opening_force: 13, clear_space: 43 }
21
- assert_equal 5, restroom.door.clear_distance
22
- restroom.door_attributes = { _destroy: '1' }
23
- assert_nil restroom.door.clear_distance
24
- end
25
-
26
- def test_attributes_equals_sets_partial_attributes
27
- restroom = Restroom.new door_attributes: { clear_distance: 5, opening_force: 13, clear_space: 43 }
28
- restroom.door_attributes = { clear_distance: 7 }
29
- assert_equal 7, restroom.door.clear_distance
30
- assert_equal 13, restroom.door.opening_force
31
- end
32
-
33
- def test_embeds_many_attributes_equals_sets_partial_attributes
34
- building = Building.new
35
- building.restrooms << Restroom.new(door_attributes: { clear_distance: 5, opening_force: 13, clear_space: 43 })
36
- building.restrooms << Restroom.new(door_attributes: { clear_distance: 6, opening_force: 14, clear_space: 44 })
37
- building.restrooms << Restroom.new(door_attributes: { clear_distance: 7, opening_force: 15, clear_space: 45 })
38
- restrooms_attributes = {
39
- a1: { id: building.restrooms[0].id, door_attributes: { clear_distance: 10 } },
40
- a2: { id: building.restrooms[1].id, _destroy: true },
41
- a3: { id: building.restrooms[2].id, door_attributes: { clear_distance: 1 } }
42
- }
43
- building.restrooms_attributes = restrooms_attributes
44
- assert_equal 2, building.restrooms.size
45
- assert_equal 10, building.restrooms.first.door.clear_distance
46
- assert_equal 15, building.restrooms.last.door.opening_force
47
- assert_equal 1, building.restrooms.last.door.clear_distance
48
- assert_nil building.restrooms.detect {|restroom| restroom.id == restrooms_attributes[:a2][:id] }
49
- end
50
-
51
- def test_attributes_method_embeds_many_does_not_clobber_existing_embeds_that_are_not_in_array
52
- building = Building.new
53
- building.restrooms << Restroom.new(door_attributes: { clear_distance: 5, opening_force: 13, clear_space: 43 })
54
- building.restrooms << Restroom.new(door_attributes: { clear_distance: 6, opening_force: 14, clear_space: 44 })
55
- building.restrooms << Restroom.new(door_attributes: { clear_distance: 7, opening_force: 15, clear_space: 45 })
56
- restrooms_attributes = {
57
- a1: { id: building.restrooms[0].id, door_attributes: { clear_distance: 10 } },
58
- }
59
- building.restrooms_attributes = restrooms_attributes
60
- assert_equal 3, building.restrooms.size
61
- assert_equal 10, building.restrooms.first.door.clear_distance
62
- assert_equal 15, building.restrooms.last.door.opening_force
63
- end
64
-
65
- def test_attribute_validity_of_embedded_model_from_model
66
- b = Building.new
67
- r = Restroom.new
68
- b.restrooms << r
69
- assert !b.valid?
70
- end
71
-
72
- def test_model_with_no_attributes
73
- item = ThingWithEmptyModel.new
74
- item.build_empty_model
75
- assert item.empty_model.is_a?(EmptyModel)
76
- end
77
-
78
- def test_model_subclassing
79
- assert_equal EmbeddableB.virtual_attributes.size, 3
80
- end
81
-
82
- end