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
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