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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3b36c460a09b84442c33ba78d7e8ead9aff3b4597ae4aacdd9c0f1ed339b9b93
4
- data.tar.gz: 60f52c35685ecf7b1457e31663c443fcb890da204c2186cbf24df944eebfc73f
3
+ metadata.gz: eb88a2aa2aecbb6bb9fabcfb9dfb8881e93021fa41657293736aba140468ec56
4
+ data.tar.gz: 349d77c3cafb00bae525bc36e0a51b377ca43cd0ff18f10a2dc38dfd44ea1884
5
5
  SHA512:
6
- metadata.gz: 9c2dbbb0ebc2ec7e658aa0451c32bd6238ab3b70e0f93cd269e9be198a122d37d89cb22882dee234df43de2fed1bab13ee09386eb653979daad16b96856b75f6
7
- data.tar.gz: d0513b3efc1766fc1fd48508fd6d20bd18a1786dc40bb3540c51e55e946b27071d09abfe002c728a2f9a3fe06a09f407fa4b924c21cbb0307225d96652ba61f2
6
+ metadata.gz: 0bca4ade2466cbffb2575a3c3701a4128dec040a270c9008fba0d53be29b897acd51e983a4a45c03df112b96292adcdce3d06bbcd8531fe1e47302e01cfe8530
7
+ data.tar.gz: d6e4520d4f2ef389acff98ea0c873b74999c049286cce517f458ae0364af476875437650114bfd42774ffa2774ec794f90b3fce4a96f18175b2a7ad79fc92332
@@ -18,9 +18,9 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_dependency "activerecord" #, "~> 4.0"
22
- spec.add_dependency "pg" #, "~> 0.17"
23
- # spec.add_dependency "hashie", ">=3.4.0"
21
+ spec.add_dependency "activerecord", ">=5.2"
22
+ spec.add_dependency "pg"
24
23
  spec.add_development_dependency "bundler", "~> 1.7"
25
24
  spec.add_development_dependency "rake", "~> 10.0"
25
+ spec.add_development_dependency "simplecov"
26
26
  end
@@ -3,32 +3,42 @@ require "ar_doc_store/storage"
3
3
  require "ar_doc_store/embedding"
4
4
  require "ar_doc_store/model"
5
5
  require "ar_doc_store/embeddable_model"
6
+ require "ar_doc_store/embedded_collection"
6
7
 
7
8
  module ArDocStore
8
9
 
9
- module AttributeTypes
10
- autoload :BaseAttribute, "ar_doc_store/attribute_types/base_attribute"
11
- autoload :ArrayAttribute, "ar_doc_store/attribute_types/array_attribute"
12
- autoload :BooleanAttribute, "ar_doc_store/attribute_types/boolean_attribute"
13
- autoload :EnumerationAttribute, "ar_doc_store/attribute_types/enumeration_attribute"
14
- autoload :FloatAttribute, "ar_doc_store/attribute_types/float_attribute"
15
- autoload :IntegerAttribute, "ar_doc_store/attribute_types/integer_attribute"
16
- autoload :StringAttribute, "ar_doc_store/attribute_types/string_attribute"
17
- autoload :UuidAttribute, "ar_doc_store/attribute_types/uuid_attribute"
18
- autoload :EmbedsOneAttribute, "ar_doc_store/attribute_types/embeds_one_attribute"
19
- autoload :EmbedsManyAttribute, "ar_doc_store/attribute_types/embeds_many_attribute"
20
- autoload :DatetimeAttribute, "ar_doc_store/attribute_types/datetime_attribute"
10
+ module Attributes
11
+ autoload :Base, "ar_doc_store/attributes/base"
12
+ autoload :Array, "ar_doc_store/attributes/array"
13
+ autoload :Boolean, "ar_doc_store/attributes/boolean"
14
+ autoload :Enumeration, "ar_doc_store/attributes/enumeration"
15
+ autoload :Float, "ar_doc_store/attributes/float"
16
+ autoload :Integer, "ar_doc_store/attributes/integer"
17
+ autoload :String, "ar_doc_store/attributes/string"
18
+ autoload :EmbedsOne, "ar_doc_store/attributes/embeds_one"
19
+ autoload :EmbedsMany, "ar_doc_store/attributes/embeds_many"
20
+ autoload :Datetime, "ar_doc_store/attributes/datetime"
21
+ autoload :Date, "ar_doc_store/attributes/date"
22
+ autoload :Decimal, "ar_doc_store/attributes/decimal"
23
+ autoload :CallbackSupport, "ar_doc_store/attributes/callback_support"
24
+ autoload :EmbedsBase, "ar_doc_store/attributes/embeds_base"
25
+ end
26
+
27
+ module Types
28
+ autoload :EmbedsOne, "ar_doc_store/types/embeds_one"
29
+ autoload :EmbedsMany, "ar_doc_store/types/embeds_many"
21
30
  end
22
31
 
23
32
  @mappings = Hash.new
24
- @mappings[:array] = 'ArDocStore::AttributeTypes::ArrayAttribute'
25
- @mappings[:boolean] = 'ArDocStore::AttributeTypes::BooleanAttribute'
26
- @mappings[:enumeration] = 'ArDocStore::AttributeTypes::EnumerationAttribute'
27
- @mappings[:float] = 'ArDocStore::AttributeTypes::FloatAttribute'
28
- @mappings[:integer] = 'ArDocStore::AttributeTypes::IntegerAttribute'
29
- @mappings[:string] = 'ArDocStore::AttributeTypes::StringAttribute'
30
- @mappings[:uuid] = 'ArDocStore::AttributeTypes::UuidAttribute'
31
- @mappings[:datetime] = 'ArDocStore::AttributeTypes::DatetimeAttribute'
33
+ @mappings[:array] = 'ArDocStore::Attributes::Array'
34
+ @mappings[:boolean] = 'ArDocStore::Attributes::Boolean'
35
+ @mappings[:enumeration] = 'ArDocStore::Attributes::Enumeration'
36
+ @mappings[:float] = 'ArDocStore::Attributes::Float'
37
+ @mappings[:integer] = 'ArDocStore::Attributes::Integer'
38
+ @mappings[:string] = 'ArDocStore::Attributes::String'
39
+ @mappings[:datetime] = 'ArDocStore::Attributes::Datetime'
40
+ @mappings[:date] = 'ArDocStore::Attributes::Date'
41
+ @mappings[:decimal] = 'ArDocStore::Attributes::Decimal'
32
42
 
33
43
  def self.mappings
34
44
  @mappings
@@ -48,12 +58,4 @@ module ArDocStore
48
58
  return nil
49
59
  end
50
60
  end
51
-
52
- def self.clobber_attribute_method!
53
- ArDocStore::Storage::ClassMethods.module_eval do
54
- def attribute(*args)
55
- json_attribute *args
56
- end
57
- end
58
- end
59
61
  end
@@ -0,0 +1,25 @@
1
+ module ArDocStore
2
+ module Attributes
3
+ class Array < Base
4
+ def define_query_method
5
+ model.class_eval <<-CODE, __FILE__, __LINE__ + 1
6
+ def #{attribute}?
7
+ #{attribute}.present?
8
+ end
9
+ CODE
10
+ end
11
+
12
+ def type
13
+ :array
14
+ end
15
+
16
+ def attribute_type
17
+ ActiveModel::Type::Value
18
+ end
19
+
20
+ def attribute_options
21
+ { array: true }
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,72 @@
1
+ module ArDocStore
2
+ module Attributes
3
+ class Base
4
+ include CallbackSupport
5
+
6
+ attr_accessor :conversion, :predicate, :options, :model, :attribute, :default
7
+
8
+ after_build :add_ransacker
9
+ after_build :define_query_method
10
+
11
+ def self.build(model, attribute, options={})
12
+ new(model, attribute, options).build
13
+ end
14
+
15
+ def initialize(model, attribute, options)
16
+ @model, @attribute, @options = model, attribute, options
17
+ @default = options.delete(:default)
18
+ end
19
+
20
+ def build
21
+ run_callbacks :build do
22
+ store_attribute
23
+ end
24
+ self
25
+ end
26
+
27
+ #:nodoc:
28
+ def store_attribute
29
+ attribute_name = @attribute
30
+ attribute_type = self.attribute_type
31
+ options = attribute_options
32
+ options.merge!(default: default) if default.present?
33
+ model.class_eval do
34
+ attribute attribute_name, attribute_type.new, **options
35
+ define_method "#{attribute_name}=".to_sym, -> (value) {
36
+ value = nil if value == '' || value == ['']
37
+ send :attribute=, attribute_name, value
38
+ new_value = send :attribute, attribute_name
39
+ write_store_attribute(json_column, attribute_name, new_value)
40
+ new_value
41
+ }
42
+ end
43
+ end
44
+
45
+ def attribute_type
46
+ ActiveModel::Type::Value
47
+ end
48
+
49
+ def attribute_options
50
+ {}
51
+ end
52
+
53
+ def embedded?
54
+ false
55
+ end
56
+
57
+ def add_ransacker
58
+ model.class_eval <<-CODE, __FILE__, __LINE__ + 1
59
+ add_ransacker :#{attribute}, "#{predicate}"
60
+ CODE
61
+ end
62
+
63
+ def define_query_method
64
+ model.class_eval <<-CODE, __FILE__, __LINE__ + 1
65
+ def #{attribute}?
66
+ !!#{attribute}
67
+ end
68
+ CODE
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,17 @@
1
+ module ArDocStore
2
+ module Attributes
3
+ class Boolean < Base
4
+ def predicate
5
+ 'bool'
6
+ end
7
+
8
+ def type
9
+ :boolean
10
+ end
11
+
12
+ def attribute_type
13
+ ActiveModel::Type::Boolean
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,21 @@
1
+ module ArDocStore
2
+ module Attributes
3
+ module CallbackSupport
4
+ def self.included(mod)
5
+ mod.send :include, ActiveSupport::Callbacks
6
+ mod.send :extend, ClassMethods
7
+ mod.define_callbacks :build
8
+ end
9
+
10
+ module ClassMethods
11
+ def before_build(method)
12
+ set_callback :build, :before, method
13
+ end
14
+
15
+ def after_build(method)
16
+ set_callback :build, :after, method
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ module ArDocStore
2
+ module Attributes
3
+ class Date < Base
4
+ def define_query_method
5
+ model.class_eval <<-CODE, __FILE__, __LINE__ + 1
6
+ def #{attribute}?
7
+ #{attribute}.present?
8
+ end
9
+ CODE
10
+ end
11
+
12
+ def type
13
+ :date
14
+ end
15
+
16
+ def attribute_type
17
+ ActiveRecord::Type::Date
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ module ArDocStore
2
+ module Attributes
3
+ class Datetime < Base
4
+ def define_query_method
5
+ model.class_eval <<-CODE, __FILE__, __LINE__ + 1
6
+ def #{attribute}?
7
+ #{attribute}.present?
8
+ end
9
+ CODE
10
+ end
11
+
12
+ def type
13
+ :datetime
14
+ end
15
+
16
+ def attribute_type
17
+ ActiveRecord::Type::DateTime
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,17 @@
1
+ module ArDocStore
2
+ module Attributes
3
+ class Decimal < Base
4
+ def predicate
5
+ 'number'
6
+ end
7
+
8
+ def type
9
+ :number
10
+ end
11
+
12
+ def attribute_type
13
+ ActiveModel::Type::Decimal
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,35 @@
1
+ module ArDocStore
2
+ module Attributes
3
+ class EmbedsBase < Base
4
+ attr_reader :class_name
5
+ before_build :handle_options
6
+ after_build :create_build_method
7
+ after_build :create_ensure_method
8
+ after_build :create_attributes_method
9
+ after_build :create_validation
10
+
11
+ def embedded?
12
+ true
13
+ end
14
+
15
+ private
16
+
17
+ def handle_options
18
+ @class_name = options[:class_name] || attribute.to_s.classify
19
+ @attribute = attribute.to_sym
20
+ end
21
+
22
+ def create_build_method
23
+ end
24
+
25
+ def create_ensure_method
26
+ end
27
+
28
+ def create_attributes_method
29
+ end
30
+
31
+ def create_validation
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,143 @@
1
+ module ArDocStore
2
+ module Attributes
3
+ class EmbedsMany < EmbedsBase
4
+ private
5
+
6
+ def store_attribute
7
+ model.class_eval <<-CODE, __FILE__, __LINE__ + 1
8
+ attribute :#{attribute}, ArDocStore::Types::EmbedsMany.new("#{@class_name}")
9
+ def #{attribute}
10
+ value = send :attribute, :#{attribute}
11
+ if value && !value.is_a?(ArDocStore::EmbeddedCollection)
12
+ value = ArDocStore::EmbeddedCollection.new value
13
+ else
14
+ value ||= ArDocStore::EmbeddedCollection.new
15
+ end
16
+ value.parent = self
17
+ value.embedded_as = :#{attribute}
18
+ value.each do |item|
19
+ item.parent = value
20
+ end
21
+ value
22
+ end
23
+ def #{attribute}=(value)
24
+ value = nil if value == '' || value == ['']
25
+ send :attribute=, :#{attribute}, value
26
+ new_value = send :attribute, :#{attribute}
27
+ new_value.parent = self
28
+ new_value.embedded_as = :#{attribute}
29
+ new_value.each do |item|
30
+ item.parent = new_value
31
+ end
32
+ write_store_attribute json_column, :#{attribute}, new_value
33
+ new_value
34
+ end
35
+ CODE
36
+ end
37
+
38
+ def create_build_method
39
+ model.class_eval <<-CODE, __FILE__, __LINE__ + 1
40
+ def build_#{attribute.to_s.singularize}(attributes = {})
41
+ items = #{attribute} || ArDocStore::EmbeddedCollection.new
42
+ items.embedded_as = :#{attribute}
43
+ items.parent = self
44
+ item = #{@class_name}.new attributes
45
+ item.parent = #{attribute}
46
+ items << item
47
+ self.#{attribute} = items
48
+ item
49
+ end
50
+ CODE
51
+ end
52
+
53
+ def create_ensure_method
54
+ attr_singular = attribute.to_s.singularize
55
+ model.class_eval <<-CODE, __FILE__, __LINE__ + 1
56
+ def ensure_#{attribute}(attributes = nil)
57
+ #{attribute}.first || build_#{attr_singular}(attributes)
58
+ end
59
+ def ensure_#{attr_singular}(attributes = nil)
60
+ #{attribute}.first || build_#{attr_singular}(attributes)
61
+ end
62
+ CODE
63
+ end
64
+
65
+ def create_attributes_method
66
+ model.class_eval <<-CODE, __FILE__, __LINE__ + 1
67
+ def #{attribute}_attributes=(values)
68
+ return if values.blank?
69
+ if values.respond_to?(:each)
70
+ if values.respond_to?(:values)
71
+ values = values.values
72
+ end
73
+ else
74
+ values = [values]
75
+ end
76
+ self.#{attribute} = AssignEmbedsManyAttributes.new(self, #{@class_name}, :#{attribute}, #{attribute}, values).models
77
+ end
78
+ CODE
79
+ end
80
+
81
+ def create_validation
82
+ model.class_eval <<-CODE, __FILE__, __LINE__ + 1
83
+ def validate_embedded_record_for_#{attribute}
84
+ validate_embeds_many :#{attribute}
85
+ end
86
+ validate :validate_embedded_record_for_#{attribute}
87
+ CODE
88
+ end
89
+ end
90
+
91
+ class AssignEmbedsManyAttributes
92
+ attr_reader :models, :assn_name, :parent, :class_name
93
+ def initialize(parent, class_name, assn_name, models, values)
94
+ @parent, @class_name, @assn_name, @models, @values = parent, class_name, assn_name, models, values
95
+ @models ||= ArDocStore::EmbeddedCollection.new
96
+ values.each { |value|
97
+ value = value.symbolize_keys
98
+ if value.key?(:id)
99
+ process_existing_model(value)
100
+ else
101
+ next if value.values.all? { |value| value.nil? || value == '' }
102
+ add(value)
103
+ end
104
+ }
105
+ end
106
+
107
+ private
108
+
109
+ attr_writer :models, :values
110
+ attr_reader :values, :assn_name
111
+
112
+ def process_existing_model(value)
113
+ return false unless value.key?(:id)
114
+ model = find_model_by_value(value)
115
+ model && destroy_or_update(model, value) or add(value)
116
+ end
117
+
118
+ def destroy_or_update(model, value)
119
+ destroy(model, value) or update_attributes(model, value)
120
+ end
121
+
122
+ def add(value)
123
+ models << class_name.new(value)
124
+ end
125
+
126
+ def destroy(model, value)
127
+ wants_to_die?(value) && models.delete(model)
128
+ end
129
+
130
+ def update_attributes(model, value)
131
+ model.attributes = value
132
+ end
133
+
134
+ def wants_to_die?(value)
135
+ value.key?(:_destroy) && ArDocStore.convert_boolean(value[:_destroy])
136
+ end
137
+
138
+ def find_model_by_value(value)
139
+ models.detect { |item| item.id == value[:id] }
140
+ end
141
+ end
142
+ end
143
+ end