trax_model 0.0.98 → 0.0.99

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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +4 -0
  3. data/lib/trax/model.rb +6 -16
  4. data/lib/trax/model/attributes.rb +1 -1
  5. data/lib/trax/model/attributes/definitions.rb +4 -0
  6. data/lib/trax/model/attributes/{mixin.rb → dsl.rb} +2 -12
  7. data/lib/trax/model/attributes/types/boolean.rb +1 -2
  8. data/lib/trax/model/attributes/types/enum.rb +0 -2
  9. data/lib/trax/model/attributes/types/integer.rb +2 -2
  10. data/lib/trax/model/attributes/types/set.rb +67 -0
  11. data/lib/trax/model/attributes/types/string.rb +3 -3
  12. data/lib/trax/model/attributes/types/struct.rb +5 -3
  13. data/lib/trax/model/attributes/types/uuid_array.rb +0 -2
  14. data/lib/trax/model/{sti.rb → core_extensions.rb} +2 -2
  15. data/lib/trax/model/core_extensions/string.rb +17 -0
  16. data/lib/trax/model/extensions_for.rb +18 -0
  17. data/lib/trax/model/extensions_for/base.rb +31 -0
  18. data/lib/trax/model/extensions_for/boolean.rb +29 -0
  19. data/lib/trax/model/extensions_for/enumerable.rb +18 -0
  20. data/lib/trax/model/extensions_for/integer.rb +10 -0
  21. data/lib/trax/model/extensions_for/numeric.rb +46 -0
  22. data/lib/trax/model/extensions_for/set.rb +10 -0
  23. data/lib/trax/model/extensions_for/string.rb +30 -0
  24. data/lib/trax/model/extensions_for/struct.rb +191 -0
  25. data/lib/trax/model/extensions_for/struct_fields.rb +21 -0
  26. data/lib/trax/model/extensions_for/struct_fields/boolean.rb +32 -0
  27. data/lib/trax/model/extensions_for/struct_fields/enum.rb +20 -0
  28. data/lib/trax/model/extensions_for/struct_fields/float.rb +12 -0
  29. data/lib/trax/model/extensions_for/struct_fields/integer.rb +12 -0
  30. data/lib/trax/model/extensions_for/struct_fields/numeric.rb +52 -0
  31. data/lib/trax/model/extensions_for/struct_fields/string.rb +29 -0
  32. data/lib/trax/model/extensions_for/struct_fields/time.rb +54 -0
  33. data/lib/trax/model/matchable.rb +3 -10
  34. data/lib/trax/model/mixins.rb +3 -0
  35. data/lib/trax/model/mixins/freezable.rb +31 -0
  36. data/lib/trax/model/mixins/restorable.rb +63 -0
  37. data/lib/trax/model/mixins/sti_enum.rb +4 -5
  38. data/lib/trax/model/mixins/unique_id.rb +85 -0
  39. data/lib/trax/model/railtie.rb +4 -2
  40. data/lib/trax/validators/json_attribute_validator.rb +1 -0
  41. data/lib/trax_model/version.rb +1 -1
  42. data/spec/db/schema/default_tables.rb +1 -17
  43. data/spec/db/schema/pg_tables.rb +15 -0
  44. data/spec/support/models.rb +11 -16
  45. data/spec/support/pg/models.rb +31 -6
  46. data/spec/trax/model/attributes/types/set_spec.rb +68 -0
  47. data/spec/trax/model/attributes/types/struct_spec.rb +6 -0
  48. data/spec/trax/model/extensions_for/boolean_spec.rb +26 -0
  49. data/spec/trax/model/extensions_for/numeric_spec.rb +53 -0
  50. data/spec/trax/model/extensions_for/string_spec.rb +25 -0
  51. data/spec/trax/model/extensions_for/struct_spec.rb +223 -0
  52. data/spec/trax/model/extensions_for_spec.rb +0 -0
  53. data/spec/trax/model/{freezable_spec.rb → mixins/freezable_spec.rb} +1 -1
  54. data/spec/trax/model/{restorable_spec.rb → mixins/restorable_spec.rb} +1 -1
  55. data/spec/trax/model/{unique_id_spec.rb → mixins/unique_id_spec.rb} +1 -1
  56. data/trax_model.gemspec +4 -5
  57. metadata +49 -59
  58. data/lib/trax/model/enum.rb +0 -64
  59. data/lib/trax/model/freezable.rb +0 -29
  60. data/lib/trax/model/mti.rb +0 -11
  61. data/lib/trax/model/mti/abstract.rb +0 -65
  62. data/lib/trax/model/mti/entity.rb +0 -62
  63. data/lib/trax/model/mti/namespace.rb +0 -21
  64. data/lib/trax/model/restorable.rb +0 -61
  65. data/lib/trax/model/scopes.rb +0 -16
  66. data/lib/trax/model/sti/attributes.rb +0 -94
  67. data/lib/trax/model/string_extensions.rb +0 -11
  68. data/lib/trax/model/struct_extensions.rb +0 -185
  69. data/lib/trax/model/unique_id.rb +0 -83
  70. data/spec/trax/model/sti/attributes_spec.rb +0 -15
  71. data/spec/trax/model/struct_extensions_spec.rb +0 -16
@@ -0,0 +1,46 @@
1
+ module Trax
2
+ module Model
3
+ module ExtensionsFor
4
+ module Numeric
5
+ extend ::ActiveSupport::Concern
6
+
7
+ include ::Trax::Model::ExtensionsFor::Base
8
+
9
+ module ClassMethods
10
+ def between(lower_value, upper_value)
11
+ gt(lower_value).merge(lt(upper_value))
12
+ end
13
+
14
+ def in_range(lower_value, upper_value)
15
+ gte(lower_value).merge(lte(upper_value))
16
+ end
17
+
18
+ def eq(*_scope_values)
19
+ _scope_values.flat_compact_uniq!
20
+ model_class.where({field_name => _scope_values})
21
+ end
22
+
23
+ def gt(value)
24
+ operator = '>'
25
+ model_class.where("#{field_name} #{operator} ?", value)
26
+ end
27
+
28
+ def gte(value)
29
+ operator = '>='
30
+ model_class.where("#{field_name} #{operator} ?", value)
31
+ end
32
+
33
+ def lt(value)
34
+ operator = '<'
35
+ model_class.where("#{field_name} #{operator} ?", value)
36
+ end
37
+
38
+ def lte(value)
39
+ operator = '<='
40
+ model_class.where("#{field_name} #{operator} ?", value)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,10 @@
1
+ module Trax
2
+ module Model
3
+ module ExtensionsFor
4
+ module Set
5
+ extend ::ActiveSupport::Concern
6
+ include ::Trax::Model::ExtensionsFor::Enumerable
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,30 @@
1
+ module Trax
2
+ module Model
3
+ module ExtensionsFor
4
+ module String
5
+ extend ::ActiveSupport::Concern
6
+
7
+ include ::Trax::Model::ExtensionsFor::Base
8
+
9
+ module ClassMethods
10
+ def eq(*_values)
11
+ _values.flat_compact_uniq!
12
+ model_class.where({field_name => _values})
13
+ end
14
+
15
+ def eq_lower(*_values)
16
+ _values.flat_compact_uniq!
17
+ _values.map!(&:downcase)
18
+ model_class.where("lower(#{field_name}) IN(?)", _values)
19
+ end
20
+
21
+ def matches(*_values)
22
+ _values.flat_compact_uniq!
23
+ _values.map!(&:to_matchable)
24
+ model_class.where("(#{field_name}) ilike ANY(array[?])", _values)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,191 @@
1
+ module Trax
2
+ module Model
3
+ module ExtensionsFor
4
+ module Struct
5
+ extend ::ActiveSupport::Concern
6
+ include ::ActiveModel::Validations
7
+ include ::Trax::Model::ExtensionsFor::Base
8
+
9
+ included do
10
+ attr_reader :record
11
+ end
12
+
13
+ def inspect
14
+ self.to_hash.inspect
15
+ end
16
+
17
+ def to_json
18
+ self.to_hash.to_json
19
+ end
20
+
21
+ def value
22
+ self
23
+ end
24
+
25
+ module ClassMethods
26
+ def [](val)
27
+ fields[val]
28
+ end
29
+ #bit of a hack for the sake of strong params for now
30
+ def permitted_keys
31
+ @permitted_keys ||= properties.map(&:to_sym)
32
+ end
33
+
34
+ def property(property_name, *args, **options)
35
+ super(property_name, *args, **options)
36
+
37
+ extensions_for_property_type = ::Trax::Model::ExtensionsFor::StructFields[self.fields[property_name].type]
38
+
39
+ if extensions_for_property_type
40
+ self.fields[property_name].include(extensions_for_property_type)
41
+ end
42
+ end
43
+
44
+ def define_model_scopes_for(*attribute_names)
45
+ attribute_names.each do |attribute_name|
46
+ define_model_scope_for(attribute_name)
47
+ end
48
+ end
49
+
50
+ def define_model_scope_for(attribute_name, **options)
51
+ attribute_klass = fields[attribute_name]
52
+
53
+ case fields[attribute_name].type
54
+ when :boolean
55
+ define_where_scopes_for_boolean_property(attribute_name, attribute_klass, **options)
56
+ when :enum
57
+ define_scopes_for_enum(attribute_name, attribute_klass, **options)
58
+ when :array
59
+ define_scopes_for_array(attribute_name, attribute_klass, **options)
60
+ when :integer
61
+ define_scopes_for_numeric(attribute_name, attribute_klass, **options)
62
+ when :time
63
+ define_scopes_for_time(attribute_name, attribute_klass, **options)
64
+ else
65
+ define_where_scopes_for_property(attribute_name, attribute_klass, **options)
66
+ end
67
+ end
68
+
69
+ def define_scopes_for_array(attribute_name, property_klass, as:nil)
70
+ return unless has_active_record_ancestry?(property_klass)
71
+
72
+ model_class = model_class_for_property(property_klass)
73
+ field_name = property_klass.parent_definition.name.demodulize.underscore
74
+ attribute_name = property_klass.name.demodulize.underscore
75
+ scope_name = as || :"by_#{field_name}_#{attribute_name}"
76
+
77
+ model_class.scope(scope_name, lambda{ |*_scope_values|
78
+ _scope_values.flat_compact_uniq!
79
+ model_class.where("#{field_name} -> '#{attribute_name}' ?| array[:values]", :values => _scope_values)
80
+ })
81
+ end
82
+
83
+ def define_scopes_for_numeric(attribute_name, property_klass, as:nil)
84
+ return unless has_active_record_ancestry?(property_klass)
85
+
86
+ model_class = model_class_for_property(property_klass)
87
+ field_name = property_klass.parent_definition.name.demodulize.underscore
88
+ attribute_name = property_klass.name.demodulize.underscore
89
+ cast_type = property_klass.type
90
+
91
+ { :gt => '>', :gte => '>=', :lt => '<', :lte => '<=', :eq => '='}.each_pair do |k, operator|
92
+ scope_name = as ? :"#{as}_#{k}" : :"by_#{field_name}_#{attribute_name}_#{k}"
93
+
94
+ model_class.scope(scope_name, lambda{ |*_scope_values|
95
+ _scope_values.flat_compact_uniq!
96
+ model_class.where("(#{field_name} ->> '#{attribute_name}')::#{cast_type} #{operator} ?", _scope_values)
97
+ })
98
+ end
99
+ end
100
+
101
+ def define_scopes_for_time(attribute_name, property_klass, as:nil)
102
+ return unless has_active_record_ancestry?(property_klass)
103
+
104
+ model_class = model_class_for_property(property_klass)
105
+ field_name = property_klass.parent_definition.name.demodulize.underscore
106
+ attribute_name = property_klass.name.demodulize.underscore
107
+ cast_type = 'timestamp'
108
+
109
+ { :gt => '>', :lt => '<'}.each_pair do |k, operator|
110
+ scope_prefix = as ? as : :"by_#{field_name}_#{attribute_name}"
111
+ scope_name = "#{scope_prefix}_#{k}"
112
+ scope_alias = "#{scope_prefix}_#{{:gt => 'after', :lt => 'before' }[k]}"
113
+
114
+ model_class.scope(scope_name, lambda{ |*_scope_values|
115
+ _scope_values.flat_compact_uniq!
116
+ model_class.where("(#{field_name} ->> '#{attribute_name}')::#{cast_type} #{operator} ?", _scope_values)
117
+ })
118
+ model_class.singleton_class.__send__("alias_method", scope_alias.to_sym, scope_name)
119
+ end
120
+ end
121
+
122
+ #this only supports properties 1 level deep, but works beautifully
123
+ #I.E. for this structure
124
+ # define_attributes do
125
+ # struct :custom_fields do
126
+ # enum :color, :default => :blue do
127
+ # define :blue, 1
128
+ # define :red, 2
129
+ # define :green, 3
130
+ # end
131
+ # end
132
+ # end
133
+ # ::Product.by_custom_fields_color(:blue, :red)
134
+ # will return #{Product color=blue}, #{Product color=red}
135
+ def define_scopes_for_enum(attribute_name, enum_klass, as:nil)
136
+ return unless has_active_record_ancestry?(enum_klass)
137
+
138
+ model_class = model_class_for_property(enum_klass)
139
+ field_name = enum_klass.parent_definition.name.demodulize.underscore
140
+ attribute_name = enum_klass.name.demodulize.underscore
141
+ scope_name = as || :"by_#{field_name}_#{attribute_name}"
142
+ model_class.scope(scope_name, lambda{ |*_scope_values|
143
+ _integer_values = enum_klass.select_values(*_scope_values.flat_compact_uniq!)
144
+ _integer_values.map!(&:to_s)
145
+ model_class.where("#{field_name} -> '#{attribute_name}' IN(?)", _integer_values)
146
+ })
147
+ end
148
+
149
+ def define_where_scopes_for_boolean_property(attribute_name, property_klass, as:nil)
150
+ return unless has_active_record_ancestry?(property_klass)
151
+
152
+ model_class = model_class_for_property(property_klass)
153
+ field_name = property_klass.parent_definition.name.demodulize.underscore
154
+ attribute_name = property_klass.name.demodulize.underscore
155
+ scope_name = as || :"by_#{field_name}_#{attribute_name}"
156
+ model_class.scope(scope_name, lambda{ |*_scope_values|
157
+ _scope_values.map!(&:to_s).flat_compact_uniq!
158
+ model_class.where("#{field_name} -> '#{attribute_name}' IN(?)", _scope_values)
159
+ })
160
+ end
161
+
162
+ def define_where_scopes_for_property(attribute_name, property_klass, as:nil)
163
+ return unless has_active_record_ancestry?(property_klass)
164
+
165
+ model_class = model_class_for_property(property_klass)
166
+ field_name = property_klass.parent_definition.name.demodulize.underscore
167
+ attribute_name = property_klass.name.demodulize.underscore
168
+ scope_name = as || :"by_#{field_name}_#{attribute_name}"
169
+
170
+ model_class.scope(scope_name, lambda{ |*_scope_values|
171
+ _scope_values.map!(&:to_s).flat_compact_uniq!
172
+ model_class.where("#{field_name} ->> '#{attribute_name}' IN(?)", _scope_values)
173
+ })
174
+ end
175
+
176
+ def has_active_record_ancestry?(property_klass)
177
+ return false unless property_klass.respond_to?(:parent_definition)
178
+
179
+ result = if property_klass.parent_definition.ancestors.include?(::ActiveRecord::Base)
180
+ true
181
+ else
182
+ has_active_record_ancestry?(property_klass.parent_definition)
183
+ end
184
+
185
+ result
186
+ end
187
+ end
188
+ end
189
+ end
190
+ end
191
+ end
@@ -0,0 +1,21 @@
1
+ module Trax
2
+ module Model
3
+ module ExtensionsFor
4
+ module StructFields
5
+ extend ::ActiveSupport::Autoload
6
+
7
+ autoload :Boolean
8
+ autoload :Enum
9
+ autoload :Float
10
+ autoload :Integer
11
+ autoload :Numeric
12
+ autoload :String
13
+ autoload :Time
14
+
15
+ def self.[](val)
16
+ "#{name}::#{val.to_s.classify}".safe_constantize
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,32 @@
1
+ module Trax
2
+ module Model
3
+ module ExtensionsFor
4
+ module StructFields
5
+ module Boolean
6
+ extend ::ActiveSupport::Concern
7
+ include ::Trax::Model::ExtensionsFor::Base
8
+
9
+ module ClassMethods
10
+ def eq(*_scope_values)
11
+ _scope_values.flat_compact_uniq!
12
+ cast_type = type
13
+ model_class.where("(#{parent_definition.field_name} ->> '#{field_name}')::#{cast_type} IN(?)", _scope_values)
14
+ end
15
+
16
+ def is_nil
17
+ eq(nil)
18
+ end
19
+
20
+ def is_true
21
+ eq(true)
22
+ end
23
+
24
+ def is_false
25
+ eq(false)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,20 @@
1
+ module Trax
2
+ module Model
3
+ module ExtensionsFor
4
+ module StructFields
5
+ module Enum
6
+ extend ::ActiveSupport::Concern
7
+ include ::Trax::Model::ExtensionsFor::Base
8
+
9
+ module ClassMethods
10
+ def eq(*_scope_values)
11
+ _integer_values = select_values(*_scope_values.flat_compact_uniq!)
12
+ _integer_values.map!(&:to_s)
13
+ model_class.where("#{parent_definition.field_name} -> '#{field_name}' IN(?)", _integer_values)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,12 @@
1
+ module Trax
2
+ module Model
3
+ module ExtensionsFor
4
+ module StructFields
5
+ module Float
6
+ extend ::ActiveSupport::Concern
7
+ include ::Trax::Model::ExtensionsFor::StructFields::Numeric
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module Trax
2
+ module Model
3
+ module ExtensionsFor
4
+ module StructFields
5
+ module Integer
6
+ extend ::ActiveSupport::Concern
7
+ include ::Trax::Model::ExtensionsFor::StructFields::Numeric
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,52 @@
1
+ module Trax
2
+ module Model
3
+ module ExtensionsFor
4
+ module StructFields
5
+ module Numeric
6
+ extend ::ActiveSupport::Concern
7
+ include ::Trax::Model::ExtensionsFor::Base
8
+
9
+ module ClassMethods
10
+ def between(lower_value, upper_value)
11
+ gt(lower_value).merge(lt(upper_value))
12
+ end
13
+
14
+ def in_range(lower_value, upper_value)
15
+ gte(lower_value).merge(lte(upper_value))
16
+ end
17
+
18
+ def eq(*_scope_values)
19
+ _scope_values.flat_compact_uniq!
20
+ cast_type = type
21
+ model_class.where("(#{parent_definition.field_name} ->> '#{field_name}')::#{cast_type} IN(?)", _scope_values)
22
+ end
23
+
24
+ def gt(value)
25
+ cast_type = type
26
+ operator = '>'
27
+ model_class.where("(#{parent_definition.field_name} ->> '#{field_name}')::#{cast_type} #{operator} ?", value)
28
+ end
29
+
30
+ def gte(value)
31
+ cast_type = type
32
+ operator = '>='
33
+ model_class.where("(#{parent_definition.field_name} ->> '#{field_name}')::#{cast_type} #{operator} ?", value)
34
+ end
35
+
36
+ def lt(value)
37
+ cast_type = type
38
+ operator = '<'
39
+ model_class.where("(#{parent_definition.field_name} ->> '#{field_name}')::#{cast_type} #{operator} ?", value)
40
+ end
41
+
42
+ def lte(value)
43
+ cast_type = type
44
+ operator = '<='
45
+ model_class.where("(#{parent_definition.field_name} ->> '#{field_name}')::#{cast_type} #{operator} ?", value)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,29 @@
1
+ module Trax
2
+ module Model
3
+ module ExtensionsFor
4
+ module StructFields
5
+ module String
6
+ extend ::ActiveSupport::Concern
7
+ include ::Trax::Model::ExtensionsFor::Base
8
+
9
+ module ClassMethods
10
+ def eq(*_scope_values)
11
+ _scope_values.flat_compact_uniq!
12
+ model_class.where("(#{parent_definition.field_name} ->> '#{field_name}') IN(?)", _scope_values)
13
+ end
14
+
15
+ def eq_lower(*_scope_values)
16
+ _scope_values.flat_compact_uniq!
17
+ model_class.where("lower(#{parent_definition.field_name} ->> '#{field_name}') IN(?)", _scope_values.map(&:downcase))
18
+ end
19
+
20
+ def matches(*_scope_values)
21
+ _scope_values.flat_compact_uniq!
22
+ model_class.where("(#{parent_definition.field_name} ->> '#{field_name}') ilike ANY(array[?])", _scope_values.map(&:to_matchable))
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end