ar_doc_store 1.0.5 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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