trax_model 0.0.91 → 0.0.92

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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/lib/trax/model.rb +71 -12
  4. data/lib/trax/model/attributes.rb +40 -0
  5. data/lib/trax/model/attributes/definitions.rb +19 -0
  6. data/lib/trax/model/attributes/errors.rb +15 -0
  7. data/lib/trax/model/attributes/mixin.rb +43 -0
  8. data/lib/trax/model/attributes/type.rb +11 -0
  9. data/lib/trax/model/attributes/types.rb +11 -0
  10. data/lib/trax/model/attributes/types/array.rb +92 -0
  11. data/lib/trax/model/attributes/types/enum.rb +32 -0
  12. data/lib/trax/model/attributes/types/json.rb +76 -0
  13. data/lib/trax/model/attributes/types/uuid_array.rb +83 -0
  14. data/lib/trax/model/attributes/value.rb +9 -0
  15. data/lib/trax/model/config.rb +1 -9
  16. data/lib/trax/model/enum.rb +3 -3
  17. data/lib/trax/model/errors.rb +30 -19
  18. data/lib/trax/model/freezable.rb +1 -1
  19. data/lib/trax/model/mixin.rb +16 -4
  20. data/lib/trax/model/railtie.rb +17 -0
  21. data/lib/trax/model/registry.rb +3 -3
  22. data/lib/trax/model/restorable.rb +26 -17
  23. data/lib/trax/model/struct.rb +31 -0
  24. data/lib/trax/model/unique_id.rb +56 -14
  25. data/lib/trax/model/uuid_array.rb +59 -0
  26. data/lib/trax/model/validators.rb +2 -0
  27. data/lib/trax/validators/boolean_validator.rb +14 -0
  28. data/lib/trax/validators/email_validator.rb +6 -2
  29. data/lib/trax/validators/enum_validator.rb +16 -0
  30. data/lib/trax/validators/json_attribute_validator.rb +19 -0
  31. data/lib/trax_model/version.rb +1 -1
  32. data/spec/support/schema.rb +26 -10
  33. data/spec/trax/model/struct_spec.rb +16 -0
  34. data/spec/trax/model_spec.rb +2 -4
  35. data/trax_model.gemspec +1 -0
  36. metadata +35 -2
@@ -0,0 +1,83 @@
1
+ require 'hashie/extensions/ignore_undeclared'
2
+
3
+ module Trax
4
+ module Model
5
+ module Attributes
6
+ module Types
7
+ class UuidArray < ::Trax::Model::Attributes::Type
8
+ class Value < ::Trax::Model::Attributes::Value
9
+ def initialize(*args)
10
+ @array = ::Trax::Model::UUIDArray.new(*args)
11
+ end
12
+
13
+ def __getobj__
14
+ @array
15
+ end
16
+
17
+ def inspect
18
+ @array.to_a.flatten.inspect
19
+ end
20
+ end
21
+
22
+ class TypeCaster < ActiveRecord::Type::Value
23
+ include ::ActiveRecord::Type::Mutable
24
+
25
+ def initialize(*args, target_klass:)
26
+ super(*args)
27
+
28
+ @target_klass = target_klass
29
+ end
30
+
31
+ def type
32
+ :uuid_array
33
+ end
34
+
35
+ def type_cast_from_user(value)
36
+ value.is_a?(@target_klass) ? @target_klass : @target_klass.new(value) || @target_klass.new
37
+ end
38
+
39
+ def type_cast_from_database(value)
40
+ value.present? ? @target_klass.new(*value) : @target_klass.new(nil)
41
+ end
42
+
43
+ def type_cast_for_database(value)
44
+ if value.present?
45
+ value.to_json
46
+ else
47
+ nil
48
+ end
49
+ end
50
+ end
51
+
52
+ module Mixin
53
+ def self.mixin_registry_key; :uuid_array_attributes end;
54
+
55
+ extend ::Trax::Model::Mixin
56
+ include ::Trax::Model::Attributes::Mixin
57
+
58
+ module ClassMethods
59
+ def uuid_array_attribute(attribute_name, **options, &block)
60
+ attributes_klass_name = "#{attribute_name}_attributes".classify
61
+ attributes_klass = const_set(attributes_klass_name, ::Class.new(::Trax::Model::Attributes[:uuid_array]::Value))
62
+ attributes_klass.instance_eval(&block) if block_given?
63
+
64
+ attributes_klass.element_class = options[:of] if options.has_key?(:of)
65
+
66
+ trax_attribute_fields[:uuid_array] ||= {}
67
+ trax_attribute_fields[:uuid_array][attribute_name] = attributes_klass
68
+
69
+ if options.has_key?(:default)
70
+ self.default_value_for(attribute_name, options[:default])
71
+ else
72
+ []
73
+ end
74
+
75
+ attribute(attribute_name, ::Trax::Model::Attributes[:uuid_array]::TypeCaster.new(target_klass: attributes_klass))
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,9 @@
1
+ module Trax
2
+ module Model
3
+ module Attributes
4
+ class Value < SimpleDelegator
5
+
6
+ end
7
+ end
8
+ end
9
+ end
@@ -1,20 +1,12 @@
1
1
  module Trax
2
2
  module Model
3
3
  class Config < ::Hashie::Dash
4
- ERROR_MESSAGES = {
5
- :invalid_uuid_prefix => [
6
- "UUID prefix must be 2 characters long",
7
- "and be 0-9 or a-f",
8
- "for hexadecimal id compatibility"
9
- ].join("\n")
10
- }.freeze
11
-
12
4
  property :uuid_prefix, :default => nil
13
5
  property :uuid_column, :default => :id
14
6
 
15
7
  def uuid_prefix=(prefix)
16
8
  if prefix.length != 2 || prefix.chars.any?{|char| char !~ /[0-9a-f]/ }
17
- raise ::Trax::Model::Errors::InvalidPrefixForUUID.new(prefix)
9
+ raise ::Trax::Model::Errors::InvalidPrefixForUUID.new(:prefix => prefix)
18
10
  end
19
11
 
20
12
  self[:uuid_prefix] = ::Trax::Model::UUIDPrefix.new(prefix)
@@ -20,7 +20,7 @@
20
20
  module Trax
21
21
  module Model
22
22
  module Enum
23
- include ::Trax::Model::Mixin
23
+ extend ::Trax::Model::Mixin
24
24
 
25
25
  module ClassMethods
26
26
  def define_scopes_for_trax_enum(enum_name)
@@ -50,13 +50,13 @@ module Trax
50
50
  validation_options = { :in => enum_values, :message => options.extract!(:message)[:message] }
51
51
 
52
52
  self.validates_inclusion_of(enum_name, validation_options) unless options.key?(:validate) && !options[:validate]
53
+
53
54
  options.delete(:validate) if options.key?(:validate)
54
55
 
55
56
  define_scopes_for_trax_enum(enum_name)
56
57
 
57
- self.default_value_for(enum_name) { default_value } if default_value
58
-
59
58
  super(enum_name, enum_mapping, options)
59
+ self.default_value_for(enum_name) { default_value } if default_value
60
60
  end
61
61
  end
62
62
  end
@@ -1,32 +1,43 @@
1
+ require 'trax/core/errors'
2
+
1
3
  module Trax
2
4
  module Model
3
5
  module Errors
4
- class Base < StandardError
5
- def initialize(*args)
6
- message = (self.class::MESSAGE + args).join("\n")
7
- super(message)
8
- end
6
+ class MixinNotRegistered < ::Trax::Core::Errors::Base
7
+ argument :mixin
8
+ argument :model
9
+
10
+ message {
11
+ "#{model} tried to load mixin: #{mixin}, whichdoes not exist in " \
12
+ "registry. Registered mixins were #{::Trax::Model.mixin_registry.keys.join(', ')} \n"
13
+ }
9
14
  end
10
15
 
11
- class InvalidPrefix < Trax::Model::Errors::Base
12
- MESSAGE = [
13
- "UUID prefix must be 2 characters long",
14
- "and be 0-9 or a-f",
16
+ class InvalidPrefix < ::Trax::Core::Errors::Base
17
+ argument :prefix, :required => true
18
+
19
+ message {
20
+ "Prefix #{prefix}"
21
+ "UUID prefix must be 2 characters long" \
22
+ "and be 0-9 or a-f" \
15
23
  "for hexadecimal id compatibility"
16
- ]
24
+ }
17
25
  end
18
26
 
19
- class DuplicatePrefixRegistered < Trax::Model::Errors::Base
20
- MESSAGE = [
21
- "UUID prefix must be unique, the",
22
- "following prefix was already registered"
23
- ]
27
+ class DuplicatePrefixRegistered < Trax::Core::Errors::Base
28
+ argument :prefix, :required => true
29
+ argument :model, :required => true
30
+
31
+ message {
32
+ "UUID prefix must be unique,\n" \
33
+ "#{prefix} was already registered by #{model}!"
34
+ }
24
35
  end
25
36
 
26
- class STIAttributeNotFound < ::Trax::Model::Errors::Base
27
- MESSAGE = [
28
- "STI Attribute was not found for attribute"
29
- ]
37
+ class STIAttributeNotFound < ::Trax::Core::Errors::Base
38
+ argument :attribute_name
39
+
40
+ message { "STI Attribute was not found for #{attribute_name}" }
30
41
  end
31
42
  end
32
43
  end
@@ -1,7 +1,7 @@
1
1
  module Trax
2
2
  module Model
3
3
  module Freezable
4
- include ::Trax::Model::Mixin
4
+ extend ::Trax::Model::Mixin
5
5
 
6
6
  included do
7
7
  class_attribute :freezable_fields
@@ -1,12 +1,24 @@
1
1
  module Trax
2
2
  module Model
3
3
  module Mixin
4
- extend ::ActiveSupport::Concern
4
+ def self.extended(base)
5
+ base.extend(::ActiveSupport::Concern)
5
6
 
6
- included do
7
- self.extend(::ActiveSupport::Concern)
7
+ super(base)
8
8
 
9
- ::Trax::Model.register_mixin(self)
9
+ ::Trax::Model.register_mixin(base)
10
+ end
11
+
12
+ def after_included(&block)
13
+ self.instance_variable_set(:@_after_included_block, block)
14
+ end
15
+
16
+ def mixed_in(&block)
17
+ after_included(&block)
18
+ end
19
+
20
+ def mixed(&block)
21
+ after_included(&block)
10
22
  end
11
23
  end
12
24
  end
@@ -0,0 +1,17 @@
1
+ module Trax
2
+ module Model
3
+ class Railtie < ::Rails::Railtie
4
+ ::ActiveSupport.on_load(:active_record) do
5
+ def self.inherited(subklass)
6
+ subklass.include(::Trax::Model) if ::Trax::Model.config.auto_include
7
+
8
+ super(subklass)
9
+
10
+ ::Trax::Model.config.auto_include_mixins.each do |mixin|
11
+ subklass.mixin(mixin)
12
+ end if ::Trax::Model.config.auto_include_mixins.any?
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -3,7 +3,7 @@ module Trax
3
3
  class Registry
4
4
  class_attribute :models
5
5
 
6
- self.models ||= ::Hashie::Mash.new
6
+ self.models = ::Hashie::Mash.new
7
7
 
8
8
  class << self
9
9
  delegate :key?, :to => :models
@@ -52,8 +52,8 @@ module Trax
52
52
  end
53
53
 
54
54
  def self.uuid_map
55
- models.values.reject{|model| model.try(:uuid_prefix) == nil }.inject(::Hashie::Mash.new) do |result, model|
56
- result[model.uuid_prefix] = model
55
+ models.values.reject{|model| model.try(:unique_id_config).try(:uuid_prefix) == nil }.inject(::Hashie::Mash.new) do |result, model|
56
+ result[model.unique_id_config.uuid_prefix] = model
57
57
  result
58
58
  end
59
59
  end
@@ -1,50 +1,59 @@
1
1
  module Trax
2
2
  module Model
3
3
  module Restorable
4
- include ::Trax::Model::Mixin
4
+ extend ::Trax::Model::Mixin
5
5
 
6
- included do
7
- class_attribute :_restorable_config
8
-
9
- alias_method :destroy!, :destroy
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
10
12
 
11
- self._restorable_config = {
12
- :field => :is_deleted,
13
- :timestamp_field => :deleted_at,
14
- :hide_deleted => true
15
- }
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
16
20
  end
17
21
 
18
22
  module ClassMethods
19
23
  def setup_restorable!
20
24
  self.class_eval do
21
- if(self._restorable_config[:hide_deleted])
25
+ if(self.restorable_config.hide_deleted)
22
26
  default_scope { by_not_deleted }
23
27
  end
24
28
 
29
+ if(self.restorable_config.alias_destroy)
30
+ alias_method :destroy!, :destroy
31
+ end
32
+
25
33
  ### Clear default deleted scope ###
26
34
  scope :by_is_deleted, lambda { |*|
27
- unscope(:where => self._restorable_config[:field]).where(self._restorable_config[:field] => true)
35
+ unscope(:where => self.restorable_config.field).where(self.restorable_config.field => true)
28
36
  }
29
37
  scope :by_not_deleted, lambda { |*|
30
- where(self._restorable_config[:field] => false)
38
+ where(self.restorable_config.field => false)
31
39
  }
32
40
 
33
- default_value_for(self._restorable_config[:field]) { false }
41
+ default_value_for(self.restorable_config.field) { false }
34
42
  end
35
43
  end
36
44
  end
37
45
 
38
46
  def destroy
39
- self.update_attributes(self._restorable_config[:field] => true, self._restorable_config[:timestamp_field] => ::DateTime.now)
47
+ self.update_attributes(self.class.restorable_config.field => true, self.class.restorable_config.timestamp_field => ::DateTime.now)
40
48
  end
41
49
 
42
50
  def restore
43
- self.update_attributes(self._restorable_config[:field] => false, self._restorable_config[:timestamp_field] => ::DateTime.now)
51
+ self.update_attributes(self.class.restorable_config.field => false, self.class.restorable_config.timestamp_field => ::DateTime.now)
44
52
  end
45
53
 
46
54
  def self.apply_mixin(target, options)
47
- target._restorable_config.merge!(options)
55
+ target.restorable_config.merge!(options)
56
+
48
57
  target.setup_restorable!
49
58
  end
50
59
  end
@@ -0,0 +1,31 @@
1
+ module Trax
2
+ module Model
3
+ class Struct < ::Hashie::Dash
4
+ include ::Hashie::Extensions::Dash::IndifferentAccess
5
+ include ::Hashie::Extensions::Coercion
6
+ include ::Hashie::Extensions::IgnoreUndeclared
7
+ include ::ActiveModel::Validations
8
+
9
+ class_attribute :property_types
10
+
11
+ def self.inherited(subklass)
12
+ super(subklass)
13
+
14
+ subklass.property_types = {}.dup.tap do |hash|
15
+ hash[:structs] = []
16
+ hash
17
+ end
18
+ end
19
+
20
+ def self.struct_property(name, *args, **options, &block)
21
+ struct_klass_name = "#{name}_structs".classify
22
+ struct_klass = const_set(struct_klass_name, ::Class.new(::Trax::Model::Struct))
23
+ struct_klass.instance_eval(&block)
24
+ options[:default] = {} unless options.key?(:default)
25
+ property(name, *args, **options)
26
+ coerce_key(name, struct_klass)
27
+ property_types[:structs].push(name)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,17 +1,56 @@
1
1
  module Trax
2
2
  module Model
3
3
  module UniqueId
4
- include ::Trax::Model::Mixin
4
+ extend ::Trax::Model::Mixin
5
+
6
+ define_configuration_options! do
7
+ option :uuid_column, :default => :id
8
+ option :uuid_map, :default => {}
9
+ end
5
10
 
6
11
  included do
7
- #grab prefix from uuid registry if using that
8
- if ::Trax::Model::UUID.klass_prefix_map.has_key?(self.name)
9
- self.trax_defaults.uuid_prefix = ::Trax::Model::UUIDPrefix.new(klass_prefix_map[self.name])
12
+ define_configuration_options!(:unique_id) do
13
+ option :uuid_prefix,
14
+ :setter => lambda{ |prefix|
15
+ if(::Trax::Model::UniqueId.config.uuid_map.values.include?(prefix) && ::Trax::Model::UniqueId.config.uuid_map[self.source.name] != prefix)
16
+ raise ::Trax::Model::Errors::DuplicatePrefixRegistered.new(:prefix => prefix, :model => self.source.name)
17
+ end
18
+
19
+ ::Trax::Model::UniqueId.config.uuid_map[self.source.name] = prefix
20
+ ::Trax::Model::UUIDPrefix.new(prefix)
21
+ },
22
+ :validates => {
23
+ :exclusion => {
24
+ :in => ::Trax::Model::Registry.uuid_map.values
25
+ },
26
+ :inclusion => {
27
+ :in => ::Trax::Model::UUIDPrefix.all,
28
+ :message => "%{value} not a valid uuid prefix!\nRun Trax::Model::UUIDPrefix.all for valid prefix list"
29
+ },
30
+ :allow_nil => true
31
+ }
32
+
33
+ option :uuid_column, :default => ::Trax::Model::UniqueId.config.uuid_column
34
+ end
35
+
36
+ #grab prefix from uuid registry if uuids are defined in an initializer
37
+ if ::Trax::Model.mixin_registry.key?(:unique_id) && ::Trax::Model::UUID.klass_prefix_map.key?(self.name)
38
+ self.unique_id_config.uuid_prefix = ::Trax::Model::UUID.klass_prefix_map[self.name]
39
+ end
40
+ end
41
+
42
+ after_included do |options|
43
+ self.unique_id_config.merge!(options)
44
+
45
+ if(self.unique_id_config.uuid_prefix)
46
+ default_value_for(:"#{self.unique_id_config.uuid_column}") {
47
+ ::Trax::Model::UUID.generate(self.unique_id_config.uuid_prefix)
48
+ }
10
49
  end
11
50
  end
12
51
 
13
52
  def uuid
14
- uuid_column = self.class.trax_defaults.uuid_column
53
+ uuid_column = self.class.unique_id_config.uuid_column
15
54
  uuid_value = (uuid_column == "uuid") ? super : __send__(uuid_column)
16
55
 
17
56
  ::Trax::Model::UUID.new(uuid_value)
@@ -33,17 +72,20 @@ module Trax
33
72
  end
34
73
 
35
74
  module ClassMethods
36
- delegate :uuid_prefix, :to => :trax_defaults
37
- delegate :uuid_column, :to => :trax_defaults
38
-
39
- def defaults(*args)
40
- super(*args)
41
-
42
- self.default_value_for(:"#{self.trax_defaults.uuid_column}") {
43
- ::Trax::Model::UUID.generate(self.trax_defaults.uuid_prefix)
44
- }
75
+ def uuid_prefix
76
+ self.unique_id_config.uuid_prefix
45
77
  end
46
78
  end
79
+
80
+ # def self.apply_mixin(target, options)
81
+ # target.unique_id_config.merge!(options)
82
+ #
83
+ # if(target.unique_id_config.uuid_prefix)
84
+ # target.default_value_for(:"#{target.unique_id_config.uuid_column}") {
85
+ # ::Trax::Model::UUID.generate(target.unique_id_config.uuid_prefix)
86
+ # }
87
+ # end
88
+ # end
47
89
  end
48
90
  end
49
91
  end