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.
- checksums.yaml +4 -4
- data/Gemfile +4 -0
- data/lib/trax/model.rb +6 -16
- data/lib/trax/model/attributes.rb +1 -1
- data/lib/trax/model/attributes/definitions.rb +4 -0
- data/lib/trax/model/attributes/{mixin.rb → dsl.rb} +2 -12
- data/lib/trax/model/attributes/types/boolean.rb +1 -2
- data/lib/trax/model/attributes/types/enum.rb +0 -2
- data/lib/trax/model/attributes/types/integer.rb +2 -2
- data/lib/trax/model/attributes/types/set.rb +67 -0
- data/lib/trax/model/attributes/types/string.rb +3 -3
- data/lib/trax/model/attributes/types/struct.rb +5 -3
- data/lib/trax/model/attributes/types/uuid_array.rb +0 -2
- data/lib/trax/model/{sti.rb → core_extensions.rb} +2 -2
- data/lib/trax/model/core_extensions/string.rb +17 -0
- data/lib/trax/model/extensions_for.rb +18 -0
- data/lib/trax/model/extensions_for/base.rb +31 -0
- data/lib/trax/model/extensions_for/boolean.rb +29 -0
- data/lib/trax/model/extensions_for/enumerable.rb +18 -0
- data/lib/trax/model/extensions_for/integer.rb +10 -0
- data/lib/trax/model/extensions_for/numeric.rb +46 -0
- data/lib/trax/model/extensions_for/set.rb +10 -0
- data/lib/trax/model/extensions_for/string.rb +30 -0
- data/lib/trax/model/extensions_for/struct.rb +191 -0
- data/lib/trax/model/extensions_for/struct_fields.rb +21 -0
- data/lib/trax/model/extensions_for/struct_fields/boolean.rb +32 -0
- data/lib/trax/model/extensions_for/struct_fields/enum.rb +20 -0
- data/lib/trax/model/extensions_for/struct_fields/float.rb +12 -0
- data/lib/trax/model/extensions_for/struct_fields/integer.rb +12 -0
- data/lib/trax/model/extensions_for/struct_fields/numeric.rb +52 -0
- data/lib/trax/model/extensions_for/struct_fields/string.rb +29 -0
- data/lib/trax/model/extensions_for/struct_fields/time.rb +54 -0
- data/lib/trax/model/matchable.rb +3 -10
- data/lib/trax/model/mixins.rb +3 -0
- data/lib/trax/model/mixins/freezable.rb +31 -0
- data/lib/trax/model/mixins/restorable.rb +63 -0
- data/lib/trax/model/mixins/sti_enum.rb +4 -5
- data/lib/trax/model/mixins/unique_id.rb +85 -0
- data/lib/trax/model/railtie.rb +4 -2
- data/lib/trax/validators/json_attribute_validator.rb +1 -0
- data/lib/trax_model/version.rb +1 -1
- data/spec/db/schema/default_tables.rb +1 -17
- data/spec/db/schema/pg_tables.rb +15 -0
- data/spec/support/models.rb +11 -16
- data/spec/support/pg/models.rb +31 -6
- data/spec/trax/model/attributes/types/set_spec.rb +68 -0
- data/spec/trax/model/attributes/types/struct_spec.rb +6 -0
- data/spec/trax/model/extensions_for/boolean_spec.rb +26 -0
- data/spec/trax/model/extensions_for/numeric_spec.rb +53 -0
- data/spec/trax/model/extensions_for/string_spec.rb +25 -0
- data/spec/trax/model/extensions_for/struct_spec.rb +223 -0
- data/spec/trax/model/extensions_for_spec.rb +0 -0
- data/spec/trax/model/{freezable_spec.rb → mixins/freezable_spec.rb} +1 -1
- data/spec/trax/model/{restorable_spec.rb → mixins/restorable_spec.rb} +1 -1
- data/spec/trax/model/{unique_id_spec.rb → mixins/unique_id_spec.rb} +1 -1
- data/trax_model.gemspec +4 -5
- metadata +49 -59
- data/lib/trax/model/enum.rb +0 -64
- data/lib/trax/model/freezable.rb +0 -29
- data/lib/trax/model/mti.rb +0 -11
- data/lib/trax/model/mti/abstract.rb +0 -65
- data/lib/trax/model/mti/entity.rb +0 -62
- data/lib/trax/model/mti/namespace.rb +0 -21
- data/lib/trax/model/restorable.rb +0 -61
- data/lib/trax/model/scopes.rb +0 -16
- data/lib/trax/model/sti/attributes.rb +0 -94
- data/lib/trax/model/string_extensions.rb +0 -11
- data/lib/trax/model/struct_extensions.rb +0 -185
- data/lib/trax/model/unique_id.rb +0 -83
- data/spec/trax/model/sti/attributes_spec.rb +0 -15
- 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,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,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
|