sequent 3.3.1 → 4.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|