sequent 3.3.1 → 4.1.0
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/bin/sequent +31 -25
- data/lib/notices.rb +6 -0
- data/lib/sequent/application_record.rb +2 -0
- data/lib/sequent/configuration.rb +29 -29
- data/lib/sequent/core/aggregate_repository.rb +24 -14
- data/lib/sequent/core/aggregate_root.rb +16 -7
- data/lib/sequent/core/aggregate_roots.rb +24 -0
- data/lib/sequent/core/aggregate_snapshotter.rb +8 -5
- data/lib/sequent/core/base_command_handler.rb +4 -2
- data/lib/sequent/core/command.rb +30 -11
- data/lib/sequent/core/command_record.rb +12 -4
- data/lib/sequent/core/command_service.rb +41 -25
- data/lib/sequent/core/core.rb +2 -0
- data/lib/sequent/core/current_event.rb +2 -0
- data/lib/sequent/core/event.rb +16 -11
- data/lib/sequent/core/event_publisher.rb +20 -15
- data/lib/sequent/core/event_record.rb +7 -7
- data/lib/sequent/core/event_store.rb +75 -49
- data/lib/sequent/core/ext/ext.rb +9 -1
- data/lib/sequent/core/helpers/array_with_type.rb +4 -1
- data/lib/sequent/core/helpers/association_validator.rb +9 -7
- data/lib/sequent/core/helpers/attribute_support.rb +64 -33
- data/lib/sequent/core/helpers/autoset_attributes.rb +4 -4
- data/lib/sequent/core/helpers/boolean_validator.rb +6 -1
- data/lib/sequent/core/helpers/copyable.rb +2 -2
- data/lib/sequent/core/helpers/date_time_validator.rb +4 -1
- data/lib/sequent/core/helpers/date_validator.rb +6 -1
- data/lib/sequent/core/helpers/default_validators.rb +12 -10
- data/lib/sequent/core/helpers/equal_support.rb +8 -6
- data/lib/sequent/core/helpers/helpers.rb +2 -0
- data/lib/sequent/core/helpers/mergable.rb +6 -4
- data/lib/sequent/core/helpers/message_handler.rb +3 -1
- data/lib/sequent/core/helpers/param_support.rb +19 -15
- data/lib/sequent/core/helpers/secret.rb +14 -12
- data/lib/sequent/core/helpers/string_support.rb +5 -4
- data/lib/sequent/core/helpers/string_to_value_parsers.rb +7 -2
- data/lib/sequent/core/helpers/string_validator.rb +6 -1
- data/lib/sequent/core/helpers/type_conversion_support.rb +5 -3
- data/lib/sequent/core/helpers/uuid_helper.rb +5 -2
- data/lib/sequent/core/helpers/value_validators.rb +23 -9
- data/lib/sequent/core/persistors/active_record_persistor.rb +19 -9
- data/lib/sequent/core/persistors/persistor.rb +16 -14
- data/lib/sequent/core/persistors/persistors.rb +2 -0
- data/lib/sequent/core/persistors/replay_optimized_postgres_persistor.rb +70 -47
- data/lib/sequent/core/projector.rb +25 -22
- data/lib/sequent/core/random_uuid_generator.rb +2 -0
- data/lib/sequent/core/sequent_oj.rb +2 -0
- data/lib/sequent/core/stream_record.rb +9 -3
- data/lib/sequent/core/transactions/active_record_transaction_provider.rb +7 -9
- data/lib/sequent/core/transactions/no_transactions.rb +2 -1
- data/lib/sequent/core/transactions/transactions.rb +2 -0
- data/lib/sequent/core/value_object.rb +8 -10
- data/lib/sequent/core/workflow.rb +7 -5
- data/lib/sequent/generator/aggregate.rb +16 -10
- data/lib/sequent/generator/command.rb +26 -19
- data/lib/sequent/generator/event.rb +19 -17
- data/lib/sequent/generator/generator.rb +6 -0
- data/lib/sequent/generator/project.rb +3 -1
- data/lib/sequent/generator/template_project/Gemfile +1 -1
- data/lib/sequent/generator/template_project/spec/app/projectors/post_projector_spec.rb +1 -1
- data/lib/sequent/generator/template_project/spec/lib/post/post_command_handler_spec.rb +1 -1
- data/lib/sequent/generator.rb +3 -4
- data/lib/sequent/migrations/executor.rb +30 -9
- data/lib/sequent/migrations/functions.rb +5 -6
- data/lib/sequent/migrations/migrate_events.rb +12 -9
- data/lib/sequent/migrations/migrations.rb +2 -1
- data/lib/sequent/migrations/planner.rb +33 -23
- data/lib/sequent/migrations/projectors.rb +4 -3
- data/lib/sequent/migrations/sql.rb +2 -0
- data/lib/sequent/migrations/view_schema.rb +93 -44
- data/lib/sequent/rake/migration_tasks.rb +59 -23
- data/lib/sequent/rake/tasks.rb +5 -2
- data/lib/sequent/sequent.rb +6 -1
- data/lib/sequent/support/database.rb +39 -17
- data/lib/sequent/support/view_projection.rb +6 -3
- data/lib/sequent/support/view_schema.rb +2 -0
- data/lib/sequent/support.rb +2 -0
- data/lib/sequent/test/command_handler_helpers.rb +39 -17
- data/lib/sequent/test/event_handler_helpers.rb +10 -4
- data/lib/sequent/test/event_stream_helpers.rb +7 -3
- data/lib/sequent/test/time_comparison.rb +12 -5
- data/lib/sequent/test.rb +2 -0
- data/lib/sequent/util/dry_run.rb +194 -0
- data/lib/sequent/util/printer.rb +6 -5
- data/lib/sequent/util/skip_if_already_processing.rb +21 -5
- data/lib/sequent/util/timer.rb +2 -0
- data/lib/sequent/util/util.rb +3 -0
- data/lib/sequent.rb +4 -0
- data/lib/version.rb +3 -1
- metadata +110 -59
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_support'
|
2
4
|
require_relative '../ext/ext'
|
3
5
|
require_relative 'array_with_type'
|
@@ -9,33 +11,44 @@ require_relative 'association_validator'
|
|
9
11
|
module Sequent
|
10
12
|
module Core
|
11
13
|
module Helpers
|
12
|
-
# Provides functionality for defining attributes with their types
|
14
|
+
# Provides functionality for defining attributes with their types.
|
13
15
|
#
|
14
|
-
# Since our Commands and ValueObjects are not backed by a database like e.g.
|
16
|
+
# Since our Commands and ValueObjects are not backed by a database like e.g. Rails
|
15
17
|
# we can not infer their types. We need the types to be able to parse from and to json.
|
16
|
-
# We could have stored te type information in the json, but we didn't.
|
17
|
-
#
|
18
18
|
# You typically do not need to include this module in your classes. If you extend from
|
19
|
-
# Sequent::
|
19
|
+
# Sequent::ValueObject, Sequent::Event or Sequent::Command you will
|
20
20
|
# get this functionality for free.
|
21
21
|
#
|
22
|
+
# Example:
|
23
|
+
#
|
24
|
+
# attrs name: String, age: Integer, born: Date
|
25
|
+
#
|
26
|
+
# Currently Sequent supports the following types:
|
27
|
+
#
|
28
|
+
# - String
|
29
|
+
# - Integer
|
30
|
+
# - Boolean
|
31
|
+
# - Date
|
32
|
+
# - DateTime
|
33
|
+
# - Subclasses of Sequent::ValueObject
|
34
|
+
# - Lists defined as `array(String)`
|
35
|
+
# - BigDecimal
|
36
|
+
# - Sequent::Secret
|
37
|
+
#
|
22
38
|
module AttributeSupport
|
23
39
|
class UnknownAttributeError < StandardError; end
|
24
40
|
|
25
41
|
# module containing class methods to be added
|
26
42
|
module ClassMethods
|
27
|
-
|
28
43
|
def types
|
29
44
|
@types ||= {}
|
30
|
-
if @merged_types
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
@merged_types.merge!(mod.types)
|
36
|
-
end
|
37
|
-
@merged_types
|
45
|
+
return @merged_types if @merged_types
|
46
|
+
|
47
|
+
@merged_types = is_a?(Class) && superclass.respond_to?(:types) ? @types.merge(superclass.types) : @types
|
48
|
+
included_modules.select { |m| m.include? Sequent::Core::Helpers::AttributeSupport }.each do |mod|
|
49
|
+
@merged_types.merge!(mod.types)
|
38
50
|
end
|
51
|
+
@merged_types
|
39
52
|
end
|
40
53
|
|
41
54
|
def attrs(args)
|
@@ -44,14 +57,15 @@ module Sequent
|
|
44
57
|
associations = []
|
45
58
|
args.each do |attribute, type|
|
46
59
|
attr_accessor attribute
|
60
|
+
|
47
61
|
if included_modules.include?(Sequent::Core::Helpers::TypeConversionSupport)
|
48
62
|
Sequent::Core::Helpers::DefaultValidators.for(type).add_validations_for(self, attribute)
|
49
63
|
end
|
50
64
|
|
51
|
-
if type.
|
65
|
+
if type.instance_of?(Sequent::Core::Helpers::ArrayWithType)
|
52
66
|
associations << attribute
|
53
67
|
elsif included_modules.include?(ActiveModel::Validations) &&
|
54
|
-
|
68
|
+
type.included_modules.include?(Sequent::Core::Helpers::AttributeSupport)
|
55
69
|
associations << attribute
|
56
70
|
end
|
57
71
|
end
|
@@ -63,9 +77,9 @@ module Sequent
|
|
63
77
|
def update_all_attributes(attrs)
|
64
78
|
super if defined?(super)
|
65
79
|
ensure_known_attributes(attrs)
|
66
|
-
#{@types.map
|
67
|
-
|
68
|
-
|
80
|
+
#{@types.map do |attribute, _|
|
81
|
+
"@#{attribute} = attrs[:#{attribute}]"
|
82
|
+
end.join("\n ")}
|
69
83
|
self
|
70
84
|
end
|
71
85
|
EOS
|
@@ -73,9 +87,9 @@ EOS
|
|
73
87
|
class_eval <<EOS
|
74
88
|
def update_all_attributes_from_json(attrs)
|
75
89
|
super if defined?(super)
|
76
|
-
#{@types.map
|
77
|
-
|
78
|
-
|
90
|
+
#{@types.map do |attribute, type|
|
91
|
+
"@#{attribute} = #{type}.deserialize_from_json(attrs['#{attribute}'])"
|
92
|
+
end.join("\n ")}
|
79
93
|
end
|
80
94
|
EOS
|
81
95
|
end
|
@@ -92,17 +106,33 @@ EOS
|
|
92
106
|
|
93
107
|
def deserialize_from_json(args)
|
94
108
|
unless args.nil?
|
95
|
-
obj = allocate
|
109
|
+
obj = allocate
|
110
|
+
|
111
|
+
upcast!(args)
|
112
|
+
|
96
113
|
obj.update_all_attributes_from_json(args)
|
97
114
|
obj
|
98
115
|
end
|
99
116
|
end
|
100
117
|
|
101
|
-
|
102
118
|
def numeric?(object)
|
103
|
-
true if Float(object)
|
119
|
+
true if Float(object)
|
120
|
+
rescue StandardError
|
121
|
+
false
|
122
|
+
end
|
123
|
+
|
124
|
+
def upcast(&block)
|
125
|
+
@upcasters ||= []
|
126
|
+
@upcasters.push(block)
|
104
127
|
end
|
105
128
|
|
129
|
+
def upcast!(hash)
|
130
|
+
return if @upcasters.nil?
|
131
|
+
|
132
|
+
@upcasters.each do |upcaster|
|
133
|
+
upcaster.call(hash)
|
134
|
+
end
|
135
|
+
end
|
106
136
|
end
|
107
137
|
|
108
138
|
# extend host class with class methods when we're included
|
@@ -110,11 +140,10 @@ EOS
|
|
110
140
|
host_class.extend(ClassMethods)
|
111
141
|
end
|
112
142
|
|
113
|
-
|
114
143
|
def attributes
|
115
144
|
hash = HashWithIndifferentAccess.new
|
116
145
|
self.class.types.each do |name, _|
|
117
|
-
value =
|
146
|
+
value = instance_variable_get("@#{name}")
|
118
147
|
hash[name] = if value.respond_to?(:attributes)
|
119
148
|
value.attributes
|
120
149
|
else
|
@@ -127,7 +156,7 @@ EOS
|
|
127
156
|
def as_json(opts = {})
|
128
157
|
hash = HashWithIndifferentAccess.new
|
129
158
|
self.class.types.each do |name, _|
|
130
|
-
value =
|
159
|
+
value = instance_variable_get("@#{name}")
|
131
160
|
hash[name] = if value.respond_to?(:as_json)
|
132
161
|
value.as_json(opts)
|
133
162
|
else
|
@@ -144,15 +173,15 @@ EOS
|
|
144
173
|
def validation_errors(prefix = nil)
|
145
174
|
result = errors.to_hash
|
146
175
|
self.class.types.each do |field|
|
147
|
-
value =
|
176
|
+
value = instance_variable_get("@#{field[0]}")
|
148
177
|
if value.respond_to? :validation_errors
|
149
|
-
value.validation_errors.each { |k, v| result["#{field[0]
|
150
|
-
elsif field[1].
|
178
|
+
value.validation_errors.each { |k, v| result["#{field[0]}_#{k}".to_sym] = v }
|
179
|
+
elsif field[1].instance_of?(ArrayWithType) && value.present?
|
151
180
|
value
|
152
181
|
.select { |val| val.respond_to?(:validation_errors) }
|
153
182
|
.each_with_index do |val, index|
|
154
183
|
val.validation_errors.each do |k, v|
|
155
|
-
result["#{field[0]
|
184
|
+
result["#{field[0]}_#{index}_#{k}".to_sym] = v
|
156
185
|
end
|
157
186
|
end
|
158
187
|
end
|
@@ -164,7 +193,9 @@ EOS
|
|
164
193
|
return unless Sequent.configuration.strict_check_attributes_on_apply_events
|
165
194
|
|
166
195
|
unknowns = attrs.keys.map(&:to_s) - self.class.types.keys.map(&:to_s)
|
167
|
-
|
196
|
+
if unknowns.any?
|
197
|
+
fail UnknownAttributeError, "#{self.class.name} does not specify attrs: #{unknowns.join(', ')}"
|
198
|
+
end
|
168
199
|
end
|
169
200
|
end
|
170
201
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Sequent
|
2
4
|
module Core
|
3
5
|
module Helpers
|
@@ -24,8 +26,7 @@ module Sequent
|
|
24
26
|
#
|
25
27
|
module AutosetAttributes
|
26
28
|
module ClassMethods
|
27
|
-
|
28
|
-
@@autoset_ignore_attributes = %w{aggregate_id sequence_number created_at}
|
29
|
+
@@autoset_ignore_attributes = %w[aggregate_id sequence_number created_at]
|
29
30
|
|
30
31
|
def set_autoset_ignore_attributes(attribute_names)
|
31
32
|
@@autoset_ignore_attributes = attribute_names
|
@@ -39,7 +40,7 @@ module Sequent
|
|
39
40
|
event_classes.each do |event_class|
|
40
41
|
on event_class do |event|
|
41
42
|
self.class.event_attribute_keys(event_class).each do |attribute_name|
|
42
|
-
instance_variable_set(:"@#{attribute_name
|
43
|
+
instance_variable_set(:"@#{attribute_name}", event.send(attribute_name.to_sym))
|
43
44
|
end
|
44
45
|
end
|
45
46
|
end
|
@@ -53,4 +54,3 @@ module Sequent
|
|
53
54
|
end
|
54
55
|
end
|
55
56
|
end
|
56
|
-
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_model'
|
2
4
|
require_relative 'value_validators'
|
3
5
|
|
@@ -18,7 +20,10 @@ module Sequent
|
|
18
20
|
# They will be converted to `true`, `false` or `nil`
|
19
21
|
class BooleanValidator < ActiveModel::EachValidator
|
20
22
|
def validate_each(subject, attribute, value)
|
21
|
-
|
23
|
+
unless Sequent::Core::Helpers::ValueValidators.for(Boolean).valid_value?(value)
|
24
|
+
subject.errors.add attribute,
|
25
|
+
:invalid_boolean
|
26
|
+
end
|
22
27
|
end
|
23
28
|
end
|
24
29
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_model'
|
2
4
|
|
3
5
|
module Sequent
|
@@ -10,8 +12,9 @@ module Sequent
|
|
10
12
|
class DateTimeValidator < ActiveModel::EachValidator
|
11
13
|
def validate_each(subject, attribute, value)
|
12
14
|
return if value.is_a?(DateTime)
|
15
|
+
|
13
16
|
DateTime.deserialize_from_json(value)
|
14
|
-
rescue
|
17
|
+
rescue StandardError
|
15
18
|
subject.errors.add attribute, :invalid_date_time
|
16
19
|
end
|
17
20
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_model'
|
2
4
|
require_relative 'value_validators'
|
3
5
|
|
@@ -10,7 +12,10 @@ module Sequent
|
|
10
12
|
# attrs value: Date
|
11
13
|
class DateValidator < ActiveModel::EachValidator
|
12
14
|
def validate_each(subject, attribute, value)
|
13
|
-
|
15
|
+
unless Sequent::Core::Helpers::ValueValidators.for(Date).valid_value?(value)
|
16
|
+
subject.errors.add attribute,
|
17
|
+
:invalid_date
|
18
|
+
end
|
14
19
|
end
|
15
20
|
end
|
16
21
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'string_validator'
|
2
4
|
require_relative 'boolean_validator'
|
3
5
|
require_relative 'date_time_validator'
|
@@ -13,18 +15,18 @@ module Sequent
|
|
13
15
|
klass.validates_numericality_of field, only_integer: true, allow_nil: true, allow_blank: true
|
14
16
|
end,
|
15
17
|
Date => ->(klass, field) do
|
16
|
-
klass.validates field,
|
18
|
+
klass.validates field, 'sequent::Core::Helpers::Date' => true
|
17
19
|
end,
|
18
20
|
DateTime => ->(klass, field) do
|
19
|
-
klass.validates field,
|
21
|
+
klass.validates field, 'sequent::Core::Helpers::DateTime' => true
|
20
22
|
end,
|
21
|
-
Boolean => ->
|
22
|
-
klass.validates field,
|
23
|
+
Boolean => ->(klass, field) do
|
24
|
+
klass.validates field, 'sequent::Core::Helpers::Boolean' => true
|
23
25
|
end,
|
24
|
-
String => ->
|
25
|
-
klass.validates field,
|
26
|
+
String => ->(klass, field) do
|
27
|
+
klass.validates field, 'sequent::Core::Helpers::String' => true
|
26
28
|
end,
|
27
|
-
Sequent::Core::Helpers::Secret => ->
|
29
|
+
Sequent::Core::Helpers::Secret => ->(klass, field) do
|
28
30
|
klass.after_validation do |object|
|
29
31
|
if object.errors&.any?
|
30
32
|
object.send("#{field}=", nil)
|
@@ -33,8 +35,8 @@ module Sequent
|
|
33
35
|
object.send("#{field}=", Sequent::Secret.new(raw_value)) if raw_value
|
34
36
|
end
|
35
37
|
end
|
36
|
-
end
|
37
|
-
}
|
38
|
+
end,
|
39
|
+
}.freeze
|
38
40
|
|
39
41
|
def self.for(type)
|
40
42
|
new(type)
|
@@ -46,7 +48,7 @@ module Sequent
|
|
46
48
|
|
47
49
|
def add_validations_for(klass, field)
|
48
50
|
validator = VALIDATORS[@type]
|
49
|
-
validator
|
51
|
+
validator&.call(klass, field)
|
50
52
|
end
|
51
53
|
end
|
52
54
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Sequent
|
2
4
|
module Core
|
3
5
|
module Helpers
|
@@ -8,16 +10,17 @@ module Sequent
|
|
8
10
|
#
|
9
11
|
module EqualSupport
|
10
12
|
def ==(other)
|
11
|
-
return false if other
|
13
|
+
return false if other.nil?
|
12
14
|
return false if self.class != other.class
|
15
|
+
|
13
16
|
self.class.types.each do |name, _|
|
14
|
-
self_value =
|
17
|
+
self_value = send(name)
|
15
18
|
other_value = other.send(name)
|
16
19
|
if self_value.class == DateTime && other_value.class == DateTime
|
17
20
|
# we don't care about milliseconds. If you know a better way of checking for equality please improve.
|
18
|
-
return false unless
|
21
|
+
return false unless self_value.iso8601 == other_value.iso8601
|
19
22
|
else
|
20
|
-
return false unless
|
23
|
+
return false unless self_value == other_value
|
21
24
|
end
|
22
25
|
end
|
23
26
|
true
|
@@ -26,7 +29,7 @@ module Sequent
|
|
26
29
|
def hash
|
27
30
|
hash = 17
|
28
31
|
self.class.types.each do |name, _|
|
29
|
-
hash = hash * 31 +
|
32
|
+
hash = hash * 31 + send(name).hash
|
30
33
|
end
|
31
34
|
hash
|
32
35
|
end
|
@@ -35,7 +38,6 @@ module Sequent
|
|
35
38
|
self == other
|
36
39
|
end
|
37
40
|
end
|
38
|
-
|
39
41
|
end
|
40
42
|
end
|
41
43
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Sequent
|
2
4
|
module Core
|
3
5
|
module Helpers
|
@@ -6,16 +8,16 @@ module Sequent
|
|
6
8
|
# ben = Person.new(name: 'Ben').merge!(name: 'Ben Vonk')
|
7
9
|
#
|
8
10
|
module Mergable
|
9
|
-
|
10
11
|
def merge!(attrs = {})
|
12
|
+
warn <<~EOS
|
13
|
+
[DEPRECATION] `merge!` is deprecated. Please use `copy` instead. This method will no longer be included in the next version of Sequent. You can still use it but you will have to include the module `Sequent::Core::Helpers::Mergable` yourself.
|
14
|
+
EOS
|
11
15
|
attrs.each do |name, value|
|
12
|
-
|
16
|
+
send("#{name}=", value)
|
13
17
|
end
|
14
18
|
self
|
15
19
|
end
|
16
|
-
|
17
20
|
end
|
18
21
|
end
|
19
22
|
end
|
20
23
|
end
|
21
|
-
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Sequent
|
2
4
|
module Core
|
3
5
|
module Helpers
|
@@ -56,7 +58,7 @@ module Sequent
|
|
56
58
|
|
57
59
|
def handle_message(message)
|
58
60
|
handlers = self.class.message_mapping[message.class]
|
59
|
-
handlers
|
61
|
+
handlers&.each { |handler| instance_exec(message, &handler) }
|
60
62
|
end
|
61
63
|
end
|
62
64
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_support'
|
2
4
|
|
3
5
|
module Sequent
|
@@ -21,7 +23,6 @@ module Sequent
|
|
21
23
|
def from_form_data(params = {})
|
22
24
|
from_params(params, false)
|
23
25
|
end
|
24
|
-
|
25
26
|
end
|
26
27
|
|
27
28
|
# extend host class with class methods when we're included
|
@@ -35,7 +36,8 @@ module Sequent
|
|
35
36
|
value = params[attribute]
|
36
37
|
|
37
38
|
next if strict_nil_check && value.nil?
|
38
|
-
next if
|
39
|
+
next if !strict_nil_check && value.blank?
|
40
|
+
|
39
41
|
if type.respond_to? :from_params
|
40
42
|
value = type.from_params(value)
|
41
43
|
elsif value.is_a?(Array)
|
@@ -58,10 +60,12 @@ module Sequent
|
|
58
60
|
def as_params
|
59
61
|
hash = HashWithIndifferentAccess.new
|
60
62
|
self.class.types.each do |field|
|
61
|
-
value =
|
62
|
-
next if field[0] ==
|
63
|
-
|
63
|
+
value = instance_variable_get("@#{field[0]}")
|
64
|
+
next if field[0] == 'errors'
|
65
|
+
|
66
|
+
hash[field[0]] = if value.is_a?(Array)
|
64
67
|
next if value.blank?
|
68
|
+
|
65
69
|
value.map { |v| value_to_string(v) }
|
66
70
|
else
|
67
71
|
value_to_string(value)
|
@@ -86,16 +90,16 @@ module Sequent
|
|
86
90
|
|
87
91
|
def make_params(key, enumerable, memo = {})
|
88
92
|
case enumerable
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
93
|
+
when Array
|
94
|
+
enumerable.each_with_index do |object, index|
|
95
|
+
make_params("#{key}[#{index}]", object, memo)
|
96
|
+
end
|
97
|
+
when Hash
|
98
|
+
enumerable.each do |hash_key, object|
|
99
|
+
make_params("#{key}[#{hash_key}]", object, memo)
|
100
|
+
end
|
101
|
+
else
|
102
|
+
memo[key] = enumerable
|
99
103
|
end
|
100
104
|
memo
|
101
105
|
end
|
@@ -1,9 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'bcrypt'
|
2
4
|
|
3
5
|
module Sequent
|
4
6
|
module Core
|
5
7
|
module Helpers
|
6
|
-
|
7
8
|
#
|
8
9
|
# You can use this in Commands to handle for instance passwords
|
9
10
|
# safely. It uses BCrypt to encrypt the Secret.
|
@@ -55,7 +56,6 @@ module Sequent
|
|
55
56
|
# See +re_encrypt_secret+
|
56
57
|
# See +verify_secret+
|
57
58
|
class Secret
|
58
|
-
|
59
59
|
class << self
|
60
60
|
def deserialize_from_json(value)
|
61
61
|
new(value)
|
@@ -65,7 +65,8 @@ module Sequent
|
|
65
65
|
# Creates a hash for the given clear text password.
|
66
66
|
#
|
67
67
|
def encrypt_secret(clear_text_secret)
|
68
|
-
fail ArgumentError
|
68
|
+
fail ArgumentError, 'clear_text_secret can not be blank' if clear_text_secret.blank?
|
69
|
+
|
69
70
|
BCrypt::Password.create(clear_text_secret)
|
70
71
|
end
|
71
72
|
|
@@ -74,8 +75,8 @@ module Sequent
|
|
74
75
|
# (essentially re-creating the secret hash).
|
75
76
|
#
|
76
77
|
def re_encrypt_secret(clear_text_secret, hashed_secret)
|
77
|
-
fail ArgumentError
|
78
|
-
fail ArgumentError
|
78
|
+
fail ArgumentError, 'clear_text_secret can not be blank' if clear_text_secret.blank?
|
79
|
+
fail ArgumentError, 'hashed_secret can not be blank' if hashed_secret.blank?
|
79
80
|
|
80
81
|
BCrypt::Engine.hash_secret(clear_text_secret, hashed_secret)
|
81
82
|
end
|
@@ -84,7 +85,7 @@ module Sequent
|
|
84
85
|
# Verifies that the hashed and clear text secret are equal.
|
85
86
|
#
|
86
87
|
def verify_secret(hashed_secret, clear_text_secret)
|
87
|
-
return false if
|
88
|
+
return false if hashed_secret.blank? || clear_text_secret.blank?
|
88
89
|
|
89
90
|
BCrypt::Password.new(hashed_secret) == clear_text_secret
|
90
91
|
end
|
@@ -93,12 +94,13 @@ module Sequent
|
|
93
94
|
attr_reader :value
|
94
95
|
|
95
96
|
def initialize(value)
|
96
|
-
fail ArgumentError
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
97
|
+
fail ArgumentError, 'value can not be blank' if value.blank?
|
98
|
+
|
99
|
+
@value = if value.is_a?(Secret)
|
100
|
+
value.value
|
101
|
+
else
|
102
|
+
value
|
103
|
+
end
|
102
104
|
end
|
103
105
|
|
104
106
|
def encrypt
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Sequent
|
2
4
|
module Core
|
3
5
|
module Helpers
|
@@ -9,14 +11,13 @@ module Sequent
|
|
9
11
|
module StringSupport
|
10
12
|
def to_s
|
11
13
|
s = "#{self.class.name}: "
|
12
|
-
|
13
|
-
value =
|
14
|
+
instance_variables.each do |name|
|
15
|
+
value = instance_variable_get(name.to_s)
|
14
16
|
s += "#{name}=[#{value}], "
|
15
17
|
end
|
16
|
-
|
18
|
+
'{' + s.chomp(', ') + '}'
|
17
19
|
end
|
18
20
|
end
|
19
|
-
|
20
21
|
end
|
21
22
|
end
|
22
23
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative '../ext/ext'
|
2
4
|
require_relative 'array_with_type'
|
3
5
|
|
@@ -16,10 +18,11 @@ module Sequent
|
|
16
18
|
::DateTime => ->(value) { parse_to_date_time(value) },
|
17
19
|
::Sequent::Core::Helpers::ArrayWithType => ->(values, type_in_array) { parse_array(values, type_in_array) },
|
18
20
|
::Sequent::Core::Helpers::Secret => ->(value) { Sequent::Core::Helpers::Secret.new(value).encrypt },
|
19
|
-
}
|
21
|
+
}.freeze
|
20
22
|
|
21
23
|
def self.parse_to_integer(value)
|
22
24
|
return value if value.is_a?(Integer)
|
25
|
+
|
23
26
|
Integer(value, 10) unless value.blank?
|
24
27
|
end
|
25
28
|
|
@@ -35,12 +38,13 @@ module Sequent
|
|
35
38
|
if value.blank? && !(value.is_a?(TrueClass) || value.is_a?(FalseClass))
|
36
39
|
nil
|
37
40
|
else
|
38
|
-
(value.is_a?(TrueClass) || value ==
|
41
|
+
(value.is_a?(TrueClass) || value == 'true')
|
39
42
|
end
|
40
43
|
end
|
41
44
|
|
42
45
|
def self.parse_to_date(value)
|
43
46
|
return if value.blank?
|
47
|
+
|
44
48
|
value.is_a?(Date) ? value : Date.iso8601(value.dup)
|
45
49
|
end
|
46
50
|
|
@@ -50,6 +54,7 @@ module Sequent
|
|
50
54
|
|
51
55
|
def self.parse_array(values, type_in_array)
|
52
56
|
fail "invalid value for array(): \"#{values}\"" unless values.is_a?(Array)
|
57
|
+
|
53
58
|
values.map do |item|
|
54
59
|
if item.respond_to?(:parse_attrs_to_correct_types)
|
55
60
|
item.parse_attrs_to_correct_types
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_model'
|
2
4
|
require_relative 'value_validators'
|
3
5
|
|
@@ -16,7 +18,10 @@ module Sequent
|
|
16
18
|
#
|
17
19
|
class StringValidator < ActiveModel::EachValidator
|
18
20
|
def validate_each(subject, attribute, value)
|
19
|
-
|
21
|
+
unless Sequent::Core::Helpers::ValueValidators.for(String).valid_value?(value)
|
22
|
+
subject.errors.add attribute,
|
23
|
+
:invalid_string
|
24
|
+
end
|
20
25
|
end
|
21
26
|
end
|
22
27
|
end
|