trax_model 0.0.91 → 0.0.92
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/lib/trax/model.rb +71 -12
- data/lib/trax/model/attributes.rb +40 -0
- data/lib/trax/model/attributes/definitions.rb +19 -0
- data/lib/trax/model/attributes/errors.rb +15 -0
- data/lib/trax/model/attributes/mixin.rb +43 -0
- data/lib/trax/model/attributes/type.rb +11 -0
- data/lib/trax/model/attributes/types.rb +11 -0
- data/lib/trax/model/attributes/types/array.rb +92 -0
- data/lib/trax/model/attributes/types/enum.rb +32 -0
- data/lib/trax/model/attributes/types/json.rb +76 -0
- data/lib/trax/model/attributes/types/uuid_array.rb +83 -0
- data/lib/trax/model/attributes/value.rb +9 -0
- data/lib/trax/model/config.rb +1 -9
- data/lib/trax/model/enum.rb +3 -3
- data/lib/trax/model/errors.rb +30 -19
- data/lib/trax/model/freezable.rb +1 -1
- data/lib/trax/model/mixin.rb +16 -4
- data/lib/trax/model/railtie.rb +17 -0
- data/lib/trax/model/registry.rb +3 -3
- data/lib/trax/model/restorable.rb +26 -17
- data/lib/trax/model/struct.rb +31 -0
- data/lib/trax/model/unique_id.rb +56 -14
- data/lib/trax/model/uuid_array.rb +59 -0
- data/lib/trax/model/validators.rb +2 -0
- data/lib/trax/validators/boolean_validator.rb +14 -0
- data/lib/trax/validators/email_validator.rb +6 -2
- data/lib/trax/validators/enum_validator.rb +16 -0
- data/lib/trax/validators/json_attribute_validator.rb +19 -0
- data/lib/trax_model/version.rb +1 -1
- data/spec/support/schema.rb +26 -10
- data/spec/trax/model/struct_spec.rb +16 -0
- data/spec/trax/model_spec.rb +2 -4
- data/trax_model.gemspec +1 -0
- 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
|
data/lib/trax/model/config.rb
CHANGED
@@ -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)
|
data/lib/trax/model/enum.rb
CHANGED
@@ -20,7 +20,7 @@
|
|
20
20
|
module Trax
|
21
21
|
module Model
|
22
22
|
module Enum
|
23
|
-
|
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
|
data/lib/trax/model/errors.rb
CHANGED
@@ -1,32 +1,43 @@
|
|
1
|
+
require 'trax/core/errors'
|
2
|
+
|
1
3
|
module Trax
|
2
4
|
module Model
|
3
5
|
module Errors
|
4
|
-
class
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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::
|
12
|
-
|
13
|
-
|
14
|
-
|
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::
|
20
|
-
|
21
|
-
|
22
|
-
|
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::
|
27
|
-
|
28
|
-
|
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
|
data/lib/trax/model/freezable.rb
CHANGED
data/lib/trax/model/mixin.rb
CHANGED
@@ -1,12 +1,24 @@
|
|
1
1
|
module Trax
|
2
2
|
module Model
|
3
3
|
module Mixin
|
4
|
-
|
4
|
+
def self.extended(base)
|
5
|
+
base.extend(::ActiveSupport::Concern)
|
5
6
|
|
6
|
-
|
7
|
-
self.extend(::ActiveSupport::Concern)
|
7
|
+
super(base)
|
8
8
|
|
9
|
-
::Trax::Model.register_mixin(
|
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
|
data/lib/trax/model/registry.rb
CHANGED
@@ -3,7 +3,7 @@ module Trax
|
|
3
3
|
class Registry
|
4
4
|
class_attribute :models
|
5
5
|
|
6
|
-
self.models
|
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
|
-
|
4
|
+
extend ::Trax::Model::Mixin
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
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
|
-
|
12
|
-
|
13
|
-
:
|
14
|
-
:
|
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.
|
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.
|
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.
|
38
|
+
where(self.restorable_config.field => false)
|
31
39
|
}
|
32
40
|
|
33
|
-
default_value_for(self.
|
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.
|
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.
|
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.
|
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
|
data/lib/trax/model/unique_id.rb
CHANGED
@@ -1,17 +1,56 @@
|
|
1
1
|
module Trax
|
2
2
|
module Model
|
3
3
|
module UniqueId
|
4
|
-
|
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
|
-
|
8
|
-
|
9
|
-
|
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.
|
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
|
-
|
37
|
-
|
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
|