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
@@ -1,21 +0,0 @@
1
- module Trax
2
- module Model
3
- module MTI
4
- module Namespace
5
- extend ::Trax::Core::EagerAutoloadNamespace
6
-
7
- class << self
8
- attr_reader :base_mti_model
9
- end
10
-
11
- def self.base_model(model)
12
- @base_mti_model = model
13
- end
14
-
15
- def self.all
16
- @all ||= base_mti_model.subclasses
17
- end
18
- end
19
- end
20
- end
21
- end
@@ -1,61 +0,0 @@
1
- module Trax
2
- module Model
3
- module Restorable
4
- extend ::Trax::Model::Mixin
5
-
6
- define_configuration_options! do
7
- option :field, :default => :is_deleted
8
- option :timestamp_field, :default => :deleted_at
9
- option :hide_deleted, :default => true
10
- option :alias_destroy, :default => true
11
- end
12
-
13
- included do
14
- define_configuration_options!(:restorable) do
15
- option :field, :default => ::Trax::Model::Restorable.config.field
16
- option :timestamp_field, :default => ::Trax::Model::Restorable.config.timestamp_field
17
- option :hide_deleted, :default => ::Trax::Model::Restorable.config.hide_deleted
18
- option :alias_destroy, :default => ::Trax::Model::Restorable.config.alias_destroy
19
- end
20
- end
21
-
22
- module ClassMethods
23
- def setup_restorable!
24
- self.class_eval do
25
- if(self.restorable_config.hide_deleted)
26
- default_scope { by_not_deleted }
27
- end
28
-
29
- if(self.restorable_config.alias_destroy)
30
- alias_method :destroy!, :destroy
31
- end
32
-
33
- ### Clear default deleted scope ###
34
- scope :by_is_deleted, lambda { |*|
35
- unscope(:where => self.restorable_config.field).where(self.restorable_config.field => true)
36
- }
37
- scope :by_not_deleted, lambda { |*|
38
- where(self.restorable_config.field => false)
39
- }
40
-
41
- default_value_for(self.restorable_config.field) { false }
42
- end
43
- end
44
- end
45
-
46
- def destroy
47
- self.update_attributes(self.class.restorable_config.field => true, self.class.restorable_config.timestamp_field => ::DateTime.now)
48
- end
49
-
50
- def restore
51
- self.update_attributes(self.class.restorable_config.field => false, self.class.restorable_config.timestamp_field => ::DateTime.now)
52
- end
53
-
54
- def self.apply_mixin(target, options)
55
- target.restorable_config.merge!(options)
56
-
57
- target.setup_restorable!
58
- end
59
- end
60
- end
61
- end
@@ -1,16 +0,0 @@
1
- module Trax
2
- module Model
3
- module Scopes
4
- extend ::ActiveSupport::Concern
5
-
6
- module ClassMethods
7
- def field_scope(attr_name)
8
- scope attr_name, lambda{ |*_scope_values|
9
- _scope_values.flat_compact_uniq!
10
- where(attr_name => _scope_values)
11
- }
12
- end
13
- end
14
- end
15
- end
16
- end
@@ -1,94 +0,0 @@
1
- module Trax
2
- module Model
3
- module STI
4
- module Attributes
5
- extend ::ActiveSupport::Concern
6
-
7
- #not configurable atm as you can see below
8
-
9
- included do
10
- class_attribute :_attribute_set_column,
11
- :_attribute_set_class_name,
12
- :_attribute_set_relation_name,
13
- :_sti_attributes
14
-
15
- self._sti_attributes = []
16
-
17
- self._attribute_set_relation_name = :attribute_set
18
- self._attribute_set_column = :attribute_set_id
19
- self._attribute_set_class_name = "#{name}AttributeSet"
20
-
21
- self.belongs_to(self._attribute_set_relation_name, :class_name => self._attribute_set_class_name, :validate => true)
22
- self.validates(self._attribute_set_relation_name, :presence => true)
23
-
24
- self.before_create(:attribute_set)
25
- end
26
-
27
- def attributes
28
- super.merge!(sti_attributes)
29
- end
30
-
31
- def attribute_set
32
- build_attribute_set if super.nil?
33
-
34
- super
35
- end
36
-
37
- def sti_attributes
38
- sti_attribute_hash = self.class._sti_attributes.inject({}) do |result, attribute|
39
- result["#{attribute}"] = __send__(attribute)
40
- result
41
- end
42
-
43
- sti_attribute_hash
44
- end
45
-
46
- def super!(*args)
47
- method_caller = caller_locations(1,1)[0].label
48
- attribute_set.send(method_caller, *args)
49
- end
50
-
51
- module ClassMethods
52
- def sti_attribute(*args)
53
- options = args.extract_options!
54
-
55
- args.each do |attribute_name|
56
- return unless self._attribute_set_class_name.constantize.table_exists?
57
- raise ::Trax::Model::Errors::STIAttributeNotFound unless self._attribute_set_class_name.constantize.column_names.include?("#{attribute_name}")
58
-
59
- self._sti_attributes << attribute_name
60
-
61
- self.delegate(attribute_name, :to => :attribute_set)
62
- self.delegate("#{attribute_name}=", :to => :attribute_set) unless options.key?(:writer) && options[:writer] == false
63
- end
64
- end
65
-
66
- def validates_uniqueness_of!(*args)
67
- options = args.extract_options!
68
-
69
- args.each do |arg|
70
- validation_method_name = :"validate_#{arg.to_s}"
71
-
72
- self.send(:define_method, :"validate_#{arg.to_s}") do |*_args|
73
- where_scope_hash = {}
74
- field_value = self.__send__(arg)
75
- where_scope_hash[arg] = field_value
76
-
77
- where_scope = self._attribute_set_class_name.constantize.where(where_scope_hash).all
78
-
79
- options[:scope].each do |field|
80
- scoped_field_value = self.__send__(field)
81
- where_scope.merge(self.class.where({field => scoped_field_value}))
82
- end if options.has_key?(:scope)
83
-
84
- errors.add(arg, "has already been taken") if where_scope.limit(1).any?
85
- end
86
-
87
- self.validate(validation_method_name)
88
- end
89
- end
90
- end
91
- end
92
- end
93
- end
94
- end
@@ -1,11 +0,0 @@
1
- module Trax
2
- module Model
3
- module StringExtensions
4
- extend ::ActiveSupport::Concern
5
-
6
- def uuid
7
- ::Trax::Model::UUID === self ? ::Trax::Model::UUID.new(self) : nil
8
- end
9
- end
10
- end
11
- end
@@ -1,185 +0,0 @@
1
- module Trax
2
- module Model
3
- module StructExtensions
4
- extend ::ActiveSupport::Concern
5
- include ::ActiveModel::Validations
6
-
7
- included do
8
- attr_reader :record
9
- end
10
-
11
- def inspect
12
- self.to_hash.inspect
13
- end
14
-
15
- def to_json
16
- self.to_hash.to_json
17
- end
18
-
19
- def value
20
- self
21
- end
22
-
23
- module ClassMethods
24
- #bit of a hack for the sake of strong params for now
25
- def permitted_keys
26
- @permitted_keys ||= properties.map(&:to_sym)
27
- end
28
-
29
- def define_model_scopes_for(*attribute_names)
30
- attribute_names.each do |attribute_name|
31
- define_model_scope_for(attribute_name)
32
- end
33
- end
34
-
35
- def define_model_scope_for(attribute_name, **options)
36
- attribute_klass = fields[attribute_name]
37
-
38
- case fields[attribute_name].type
39
- when :boolean
40
- define_where_scopes_for_boolean_property(attribute_name, attribute_klass, **options)
41
- when :enum
42
- define_scopes_for_enum(attribute_name, attribute_klass, **options)
43
- when :array
44
- define_scopes_for_array(attribute_name, attribute_klass, **options)
45
- when :integer
46
- define_scopes_for_numeric(attribute_name, attribute_klass, **options)
47
- when :time
48
- define_scopes_for_time(attribute_name, attribute_klass, **options)
49
- else
50
- define_where_scopes_for_property(attribute_name, attribute_klass, **options)
51
- end
52
- end
53
-
54
- def define_scopes_for_array(attribute_name, property_klass, as:nil)
55
- return unless has_active_record_ancestry?(property_klass)
56
-
57
- model_class = model_class_for_property(property_klass)
58
- field_name = property_klass.parent_definition.name.demodulize.underscore
59
- attribute_name = property_klass.name.demodulize.underscore
60
- scope_name = as || :"by_#{field_name}_#{attribute_name}"
61
-
62
- model_class.scope(scope_name, lambda{ |*_scope_values|
63
- _scope_values.flat_compact_uniq!
64
- model_class.where("#{field_name} -> '#{attribute_name}' ?| array[:values]", :values => _scope_values)
65
- })
66
- end
67
-
68
- def define_scopes_for_numeric(attribute_name, property_klass, as:nil)
69
- return unless has_active_record_ancestry?(property_klass)
70
-
71
- model_class = model_class_for_property(property_klass)
72
- field_name = property_klass.parent_definition.name.demodulize.underscore
73
- attribute_name = property_klass.name.demodulize.underscore
74
- cast_type = property_klass.type
75
-
76
- { :gt => '>', :gte => '>=', :lt => '<', :lte => '<=', :eq => '='}.each_pair do |k, operator|
77
- scope_name = as ? :"#{as}_#{k}" : :"by_#{field_name}_#{attribute_name}_#{k}"
78
-
79
- model_class.scope(scope_name, lambda{ |*_scope_values|
80
- _scope_values.flat_compact_uniq!
81
- model_class.where("(#{field_name} ->> '#{attribute_name}')::#{cast_type} #{operator} ?", _scope_values)
82
- })
83
- end
84
- end
85
-
86
- def define_scopes_for_time(attribute_name, property_klass, as:nil)
87
- return unless has_active_record_ancestry?(property_klass)
88
-
89
- model_class = model_class_for_property(property_klass)
90
- field_name = property_klass.parent_definition.name.demodulize.underscore
91
- attribute_name = property_klass.name.demodulize.underscore
92
- cast_type = 'timestamp'
93
-
94
- { :gt => '>', :lt => '<'}.each_pair do |k, operator|
95
- scope_prefix = as ? as : :"by_#{field_name}_#{attribute_name}"
96
- scope_name = "#{scope_prefix}_#{k}"
97
- scope_alias = "#{scope_prefix}_#{{:gt => 'after', :lt => 'before' }[k]}"
98
-
99
- model_class.scope(scope_name, lambda{ |*_scope_values|
100
- _scope_values.flat_compact_uniq!
101
- model_class.where("(#{field_name} ->> '#{attribute_name}')::#{cast_type} #{operator} ?", _scope_values)
102
- })
103
- model_class.singleton_class.__send__("alias_method", scope_alias.to_sym, scope_name)
104
- end
105
- end
106
-
107
- #this only supports properties 1 level deep, but works beautifully
108
- #I.E. for this structure
109
- # define_attributes do
110
- # struct :custom_fields do
111
- # enum :color, :default => :blue do
112
- # define :blue, 1
113
- # define :red, 2
114
- # define :green, 3
115
- # end
116
- # end
117
- # end
118
- # ::Product.by_custom_fields_color(:blue, :red)
119
- # will return #{Product color=blue}, #{Product color=red}
120
- def define_scopes_for_enum(attribute_name, enum_klass, as:nil)
121
- return unless has_active_record_ancestry?(enum_klass)
122
-
123
- model_class = model_class_for_property(enum_klass)
124
- field_name = enum_klass.parent_definition.name.demodulize.underscore
125
- attribute_name = enum_klass.name.demodulize.underscore
126
- scope_name = as || :"by_#{field_name}_#{attribute_name}"
127
- model_class.scope(scope_name, lambda{ |*_scope_values|
128
- _integer_values = enum_klass.select_values(*_scope_values.flat_compact_uniq!)
129
- _integer_values.map!(&:to_s)
130
- model_class.where("#{field_name} -> '#{attribute_name}' IN(?)", _integer_values)
131
- })
132
- end
133
-
134
- def define_where_scopes_for_boolean_property(attribute_name, property_klass, as:nil)
135
- return unless has_active_record_ancestry?(property_klass)
136
-
137
- model_class = model_class_for_property(property_klass)
138
- field_name = property_klass.parent_definition.name.demodulize.underscore
139
- attribute_name = property_klass.name.demodulize.underscore
140
- scope_name = as || :"by_#{field_name}_#{attribute_name}"
141
- model_class.scope(scope_name, lambda{ |*_scope_values|
142
- _scope_values.map!(&:to_s).flat_compact_uniq!
143
- model_class.where("#{field_name} -> '#{attribute_name}' IN(?)", _scope_values)
144
- })
145
- end
146
-
147
- def define_where_scopes_for_property(attribute_name, property_klass, as:nil)
148
- return unless has_active_record_ancestry?(property_klass)
149
-
150
- model_class = model_class_for_property(property_klass)
151
- field_name = property_klass.parent_definition.name.demodulize.underscore
152
- attribute_name = property_klass.name.demodulize.underscore
153
- scope_name = as || :"by_#{field_name}_#{attribute_name}"
154
-
155
- model_class.scope(scope_name, lambda{ |*_scope_values|
156
- _scope_values.map!(&:to_s).flat_compact_uniq!
157
- model_class.where("#{field_name} ->> '#{attribute_name}' IN(?)", _scope_values)
158
- })
159
- end
160
-
161
- def has_active_record_ancestry?(property_klass)
162
- return false unless property_klass.respond_to?(:parent_definition)
163
-
164
- result = if property_klass.parent_definition.ancestors.include?(::ActiveRecord::Base)
165
- true
166
- else
167
- has_active_record_ancestry?(property_klass.parent_definition)
168
- end
169
-
170
- result
171
- end
172
-
173
- def model_class_for_property(property_klass)
174
- result = if property_klass.parent_definition.ancestors.include?(::ActiveRecord::Base)
175
- property_klass.parent_definition
176
- else
177
- model_class_for_property(property_klass.parent_definition)
178
- end
179
-
180
- result
181
- end
182
- end
183
- end
184
- end
185
- end
@@ -1,83 +0,0 @@
1
- module Trax
2
- module Model
3
- module UniqueId
4
- extend ::Trax::Model::Mixin
5
-
6
- define_configuration_options! do
7
- option :uuid_column, :default => :id
8
- option :uuid_map, :default => {}
9
- end
10
-
11
- after_included do |options|
12
- define_configuration_options!(:unique_id) do
13
- option :uuid_prefix,
14
- :validates => {
15
- :exclusion => {
16
- :in => ::Trax::Model::Registry.uuid_map.values
17
- },
18
- :inclusion => {
19
- :in => ::Trax::Model::UUIDPrefix.all,
20
- :message => "%{value} not a valid uuid prefix!\nRun Trax::Model::UUIDPrefix.all for valid prefix list"
21
- },
22
- :allow_nil => true
23
- }
24
-
25
- option :uuid_column, :default => ::Trax::Model::UniqueId.config.uuid_column
26
-
27
- klass do
28
- def uuid_prefix=(prefix)
29
- if(::Trax::Model::UniqueId.config.uuid_map.values.include?(prefix) && ::Trax::Model::UniqueId.config.uuid_map[self.source.name] != prefix)
30
- raise ::Trax::Model::Errors::DuplicatePrefixRegistered.new(:prefix => prefix, :model => self.source.name)
31
- end
32
-
33
- ::Trax::Model::UniqueId.config.uuid_map[self.source.name] = prefix
34
- super(::Trax::Model::UUIDPrefix.new(prefix))
35
- end
36
- end
37
-
38
- end
39
-
40
- #grab prefix from uuid registry if uuids are defined in an initializer
41
- if ::Trax::Model.mixin_registry.key?(:unique_id) && ::Trax::Model::UUID.klass_prefix_map.key?(self.name)
42
- self.unique_id_config.uuid_prefix = ::Trax::Model::UUID.klass_prefix_map[self.name]
43
- end
44
-
45
- self.unique_id_config.merge!(options)
46
-
47
- if(self.unique_id_config.uuid_prefix)
48
- default_value_for(:"#{self.unique_id_config.uuid_column}") {
49
- ::Trax::Model::UUID.generate(self.unique_id_config.uuid_prefix)
50
- }
51
- end
52
- end
53
-
54
- def uuid
55
- uuid_column = self.class.unique_id_config.uuid_column
56
- uuid_value = (uuid_column == "uuid") ? super : __send__(uuid_column)
57
-
58
- ::Trax::Model::UUID.new(uuid_value)
59
- end
60
-
61
- #i.e. Blog::Post
62
- def uuid_type
63
- uuid.record_type
64
- end
65
-
66
- #i.e. 'Blog::Post'
67
- def uuid_type_name
68
- uuid.record_type.name
69
- end
70
-
71
- #i.e, Blog::Post will = post
72
- def uuid_type_slug
73
- uuid.record_type.name.demodulize.underscore
74
- end
75
-
76
- module ClassMethods
77
- def uuid_prefix
78
- self.unique_id_config.uuid_prefix
79
- end
80
- end
81
- end
82
- end
83
- end