trax_model 0.0.95 → 0.0.96

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2e9c4e45cdc76295880d1e087727ec1414889bdc
4
- data.tar.gz: eb26cfa1732eaa1e2ba69b3b5448e71e8c229837
3
+ metadata.gz: 41cea382b5de1b943f513df7167f86adb4912f94
4
+ data.tar.gz: 86a810a545fe00b3de9b759f1be14b82fa632069
5
5
  SHA512:
6
- metadata.gz: fc5388aaf9d9a351bc4412357e4d7d2b01ccac35934ac02d9b193aa8eb24814f852e482efa6ee455318c8fe4129c65fda97e2d2e11b19fd8a4a943372eec0dab
7
- data.tar.gz: 0847884f74518a4fe603b92d2e2366b08218ccf7a56a07d4ae057f5ebc783d952fefcfe532de86117fd7e02656e9b682bab9ee463aa94b5f40e8e30c15ecb696
6
+ metadata.gz: 93c99a50811671b71bb4a4156ac3200e019d28a03611a80e8ddb0cc9184d830d8129d9f20f6c88c67ec2b93e03bfd82684bbdfb7df7da99c683ba54c1fd2b7bd
7
+ data.tar.gz: 2b90612a719954a3f0027c6792d14af4a5e445a99b15fd392b57ea597d5439354e54cec3530f223a44cdf46f5f0e5ca0a840e6ddf012cfac4a06ce937334b254
@@ -8,10 +8,13 @@ module Trax
8
8
  #note: we dont validate enum attribute value because typecaster will turn it into nil which we allow
9
9
  def self.define_attribute(klass, attribute_name, **options, &block)
10
10
  klass_name = "#{klass.fields_module.name.underscore}/#{attribute_name}".camelize
11
- attribute_klass = if options.key?(:class_name)
12
- options[:class_name].constantize
11
+
12
+ attribute_klass = if options.key?(:extend)
13
+ _klass_prototype = options[:extend].constantize
14
+ _klass = ::Trax::Core::NamedClass.new(klass_name, _klass_prototype, :parent_definition => klass, &block)
15
+ _klass
13
16
  else
14
- ::Trax::Core::NamedClass.new(klass_name, ::Enum, :parent_definition => klass, &block)
17
+ ::Trax::Core::NamedClass.new(klass_name, ::Trax::Core::Types::Enum, :parent_definition => klass, &block)
15
18
  end
16
19
 
17
20
  klass.attribute(attribute_name, ::Trax::Model::Attributes::Types::Enum::TypeCaster.new(target_klass: attribute_klass))
@@ -8,6 +8,8 @@ module Trax
8
8
  module ValueExtensions
9
9
  extend ::ActiveSupport::Concern
10
10
 
11
+ include ::ActiveModel::Validations
12
+
11
13
  def inspect
12
14
  self.to_hash.inspect
13
15
  end
@@ -16,20 +18,108 @@ module Trax
16
18
  self.to_hash.to_json
17
19
  end
18
20
 
21
+ def to_serializable_hash
22
+ _serializable_hash = to_hash
23
+
24
+ self.class.fields_module.enums.keys.each do |attribute_name|
25
+ _serializable_hash[attribute_name] = _serializable_hash[attribute_name].try(:to_i)
26
+ end if self.class.fields_module.enums.keys.any?
27
+
28
+ _serializable_hash
29
+ end
30
+
19
31
  module ClassMethods
20
32
  def type; :struct end;
21
33
 
22
34
  def permitted_keys
23
35
  @permitted_keys ||= properties.map(&:to_sym)
24
36
  end
37
+
38
+ #this only supports properties 1 level deep, but works beautifully
39
+ #I.E. for this structure
40
+ # define_attributes do
41
+ # struct :custom_fields do
42
+ # enum :color, :default => :blue do
43
+ # define :blue, 1
44
+ # define :red, 2
45
+ # define :green, 3
46
+ # end
47
+ # end
48
+ # end
49
+ # ::Product.by_custom_fields_color(:blue, :red)
50
+ # will return #{Product color=blue}, #{Product color=red}
51
+ def define_scopes_for_enum(attribute_name, enum_klass)
52
+ return unless has_active_record_ancestry?(enum_klass)
53
+
54
+ model_class = model_class_for_property(enum_klass)
55
+ field_name = enum_klass.parent_definition.name.demodulize.underscore
56
+ attribute_name = enum_klass.name.demodulize.underscore
57
+ scope_name = :"by_#{field_name}_#{attribute_name}"
58
+ model_class.scope(scope_name, lambda{ |*_scope_values|
59
+ _integer_values = enum_klass.select_values(*_scope_values.flat_compact_uniq!)
60
+ _integer_values.map!(&:to_s)
61
+ model_class.where("#{field_name} -> '#{attribute_name}' IN(?)", _integer_values)
62
+ })
63
+ end
64
+
65
+ def define_where_scopes_for_boolean_property(attribute_name, property_klass)
66
+ return unless has_active_record_ancestry?(property_klass)
67
+
68
+ model_class = model_class_for_property(property_klass)
69
+ field_name = property_klass.parent_definition.name.demodulize.underscore
70
+ attribute_name = property_klass.name.demodulize.underscore
71
+ scope_name = :"by_#{field_name}_#{attribute_name}"
72
+ model_class.scope(scope_name, lambda{ |*_scope_values|
73
+ _scope_values.map!(&:to_s).flat_compact_uniq!
74
+ model_class.where("#{field_name} -> '#{attribute_name}' IN(?)", _scope_values)
75
+ })
76
+ end
77
+
78
+ def define_where_scopes_for_property(attribute_name, property_klass)
79
+ return unless has_active_record_ancestry?(property_klass)
80
+
81
+ model_class = model_class_for_property(property_klass)
82
+ field_name = property_klass.parent_definition.name.demodulize.underscore
83
+ attribute_name = property_klass.name.demodulize.underscore
84
+ scope_name = :"by_#{field_name}_#{attribute_name}"
85
+
86
+ model_class.scope(scope_name, lambda{ |*_scope_values|
87
+ _scope_values.map!(&:to_s).flat_compact_uniq!
88
+ model_class.where("#{field_name} ->> '#{attribute_name}' IN(?)", _scope_values)
89
+ })
90
+ end
91
+
92
+ def has_active_record_ancestry?(property_klass)
93
+ return false unless property_klass.respond_to?(:parent_definition)
94
+
95
+ result = if property_klass.parent_definition.ancestors.include?(::ActiveRecord::Base)
96
+ true
97
+ else
98
+ has_active_record_ancestry?(property_klass.parent_definition)
99
+ end
100
+
101
+ result
102
+ end
103
+
104
+ def model_class_for_property(property_klass)
105
+ result = if property_klass.parent_definition.ancestors.include?(::ActiveRecord::Base)
106
+ property_klass.parent_definition
107
+ else
108
+ model_class_for_property(property_klass.parent_definition)
109
+ end
110
+
111
+ result
112
+ end
113
+
25
114
  end
26
115
  end
27
116
 
28
117
  def self.define_attribute(klass, attribute_name, **options, &block)
29
118
  klass_name = "#{klass.fields_module.name.underscore}/#{attribute_name}".camelize
30
- attribute_klass = if options.key?(:class_name)
31
- _klass = options[:class_name].constantize
32
- _klass.include(ValueExtensions)
119
+ attribute_klass = if options.key?(:extend)
120
+ _klass_prototype = options[:extend].constantize
121
+ _klass = ::Trax::Core::NamedClass.new(klass_name, _klass_prototype, :parent_definition => klass, &block)
122
+ _klass.include(ValueExtensions) unless klass.const_defined?("ValueExtensions")
33
123
  _klass
34
124
  else
35
125
  ::Trax::Core::NamedClass.new(klass_name, Value, :parent_definition => klass, &block)
@@ -39,6 +129,7 @@ module Trax
39
129
  klass.validates(attribute_name, :json_attribute => true) unless options.key?(:validate) && !options[:validate]
40
130
  klass.default_value_for(attribute_name) { {} }
41
131
  define_model_accessors(klass, attribute_name, attribute_klass, options[:model_accessors]) if options.key?(:model_accessors) && options[:model_accessors]
132
+ define_model_scopes(klass, attribute_name, attribute_klass, options[:model_scopes]) if options.key?(:model_scopes) && options[:model_scopes]
42
133
  end
43
134
 
44
135
  class Value < ::Trax::Model::Struct
@@ -59,11 +150,11 @@ module Trax
59
150
  end
60
151
 
61
152
  def type_cast_from_user(value)
62
- value.is_a?(@target_klass) ? @target_klass : @target_klass.new(value || {})
153
+ value.is_a?(@target_klass) ? value : @target_klass.new(value || {})
63
154
  end
64
155
 
65
156
  def type_cast_from_database(value)
66
- value.present? ? @target_klass.new(JSON.parse(value)) : value
157
+ value.present? ? @target_klass.new(::JSON.parse(value)) : value
67
158
  end
68
159
 
69
160
  def type_cast_for_database(value)
@@ -76,15 +167,43 @@ module Trax
76
167
 
77
168
  private
78
169
 
170
+ def self.define_model_scopes(model, attribute_name, struct_attribute, option_value)
171
+ properties_to_define = if [ true ].include?(option_value)
172
+ struct_attribute.properties.to_a
173
+ elsif option_value.is_a?(Hash) && option_value.has_key?(:only)
174
+ struct_attribute.properties.to_a & option_value[:only]
175
+ elsif option_value.is_a?(Hash) && option_value.has_key?(:except)
176
+ struct_attribute.properties.to_a - option_value[:except]
177
+ elsif option_value.is_a?(Array)
178
+ struct_attribute.properties.to_a & option_value
179
+ else
180
+ raise Trax::Model::Errors::InvalidOption.new(
181
+ :option => :model_scopes,
182
+ :valid_choices => ["true", "array of properties", "hash with :only or :except keys"]
183
+ )
184
+ end
185
+
186
+ properties_to_define.each do |_property|
187
+ getter_method, setter_method = _property.to_sym, :"#{_property}="
188
+
189
+ model.__send__(:define_method, setter_method) do |val|
190
+ self[attribute_name] = {} unless self[attribute_name]
191
+ self.__send__(attribute_name).__send__(setter_method, val)
192
+ end
193
+
194
+ model.delegate(getter_method, :to => attribute_name)
195
+ end
196
+ end
197
+
79
198
  def self.define_model_accessors(model, attribute_name, struct_attribute, option_value)
80
199
  properties_to_define = if [ true ].include?(option_value)
81
200
  struct_attribute.properties.to_a
82
- elsif option_value.is_a(Hash) && option_value.has_key?(:only)
83
- struct_attribute.properties.to_a.only(*option_value[:only])
84
- elsif option_value.is_a(Hash) && option_value.has_key?(:except)
85
- struct_attribute.properties.to_a.except(*option_value[:except])
86
- elsif option_value.is_a(Array)
87
- struct_attribute.properties.to_a.only(*option_value[:only])
201
+ elsif option_value.is_a?(Hash) && option_value.has_key?(:only)
202
+ struct_attribute.properties.to_a & option_value[:only]
203
+ elsif option_value.is_a?(Hash) && option_value.has_key?(:except)
204
+ struct_attribute.properties.to_a - option_value[:except]
205
+ elsif option_value.is_a?(Array)
206
+ struct_attribute.properties.to_a & option_value
88
207
  else
89
208
  raise Trax::Model::Errors::InvalidOption.new(
90
209
  :option => :model_accessors,
@@ -96,16 +96,6 @@ module Trax
96
96
 
97
97
  def self.type; :struct end;
98
98
 
99
- def to_serializable_hash
100
- _serializable_hash = to_hash
101
-
102
- self.class.fields_module.enums.keys.each do |attribute_name|
103
- _serializable_hash[attribute_name] = _serializable_hash[attribute_name].try(:to_i)
104
- end if self.class.fields_module.enums.keys.any?
105
-
106
- _serializable_hash
107
- end
108
-
109
99
  class << self
110
100
  alias :boolean :boolean_property
111
101
  alias :enum :enum_property
@@ -10,7 +10,6 @@ module Trax
10
10
 
11
11
  after_included do |options|
12
12
  define_configuration_options!(:unique_id) do
13
-
14
13
  option :uuid_prefix,
15
14
  :validates => {
16
15
  :exclusion => {
@@ -10,7 +10,7 @@ class JsonAttributeValidator < ActiveModel::EachValidator
10
10
  unless value.is_a?(json_attribute) && value.valid?
11
11
  if value.is_a?(json_attribute)
12
12
  value.errors.messages.each_pair do |k,v|
13
- v.flatten.join(", ") if v.is_a?(Array)
13
+ v = v.flatten.join(", ") if v.is_a?(Array)
14
14
  object.errors.add("#{attribute}.#{k}", v)
15
15
  end
16
16
  else
@@ -1,3 +1,3 @@
1
1
  module TraxModel
2
- VERSION = '0.0.95'
2
+ VERSION = '0.0.96'
3
3
  end
@@ -18,7 +18,7 @@ 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 "trax_core", "~> 0.0.76"
21
+ spec.add_dependency "trax_core", "~> 0.0.80"
22
22
  spec.add_dependency "default_value_for", "~> 3.0.0"
23
23
  spec.add_dependency "simple_enum"
24
24
  spec.add_development_dependency "hashie", ">= 3.4.2"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trax_model
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.95
4
+ version: 0.0.96
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason Ayre
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-09-09 00:00:00.000000000 Z
11
+ date: 2015-10-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: trax_core
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.0.76
19
+ version: 0.0.80
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.0.76
26
+ version: 0.0.80
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: default_value_for
29
29
  requirement: !ruby/object:Gem::Requirement