sequent 4.0.0 → 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 +2 -0
- data/lib/sequent/application_record.rb +2 -0
- data/lib/sequent/configuration.rb +24 -31
- data/lib/sequent/core/aggregate_repository.rb +17 -13
- 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 +17 -9
- data/lib/sequent/core/command_record.rb +8 -3
- data/lib/sequent/core/command_service.rb +18 -18
- 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 +16 -15
- data/lib/sequent/core/event_record.rb +7 -7
- data/lib/sequent/core/event_store.rb +57 -50
- 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 +45 -28
- 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 -5
- 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 +5 -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 +2 -0
- data/lib/sequent/generator/project.rb +2 -0
- data/lib/sequent/generator/template_project/Gemfile +1 -1
- data/lib/sequent/generator.rb +2 -0
- data/lib/sequent/migrations/executor.rb +22 -13
- 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 +84 -45
- data/lib/sequent/rake/migration_tasks.rb +58 -22
- data/lib/sequent/rake/tasks.rb +5 -2
- data/lib/sequent/sequent.rb +2 -0
- data/lib/sequent/support/database.rb +30 -15
- 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 +35 -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 +11 -8
- data/lib/sequent/util/printer.rb +6 -5
- data/lib/sequent/util/skip_if_already_processing.rb +3 -1
- data/lib/sequent/util/timer.rb +2 -0
- data/lib/sequent/util/util.rb +2 -0
- data/lib/sequent.rb +2 -0
- data/lib/version.rb +3 -1
- metadata +81 -66
@@ -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,17 +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 = {})
|
11
|
-
warn
|
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
|
12
15
|
attrs.each do |name, value|
|
13
|
-
|
16
|
+
send("#{name}=", value)
|
14
17
|
end
|
15
18
|
self
|
16
19
|
end
|
17
|
-
|
18
20
|
end
|
19
21
|
end
|
20
22
|
end
|
21
23
|
end
|
22
|
-
|
@@ -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
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_model'
|
2
4
|
|
3
5
|
module Sequent
|
@@ -5,7 +7,6 @@ module Sequent
|
|
5
7
|
TypeConversionError = Class.new(RuntimeError)
|
6
8
|
|
7
9
|
module Helpers
|
8
|
-
|
9
10
|
# Will parse all values to the correct types.
|
10
11
|
# The raw values are typically posted from the web and are therefor mostly strings.
|
11
12
|
# To parse a raw value your class must have a parse_from_string method that returns the parsed values.
|
@@ -14,8 +15,9 @@ module Sequent
|
|
14
15
|
def parse_attrs_to_correct_types
|
15
16
|
the_copy = dup
|
16
17
|
the_copy.class.types.each do |name, type|
|
17
|
-
raw_value = the_copy.send(
|
18
|
+
raw_value = the_copy.send(name.to_s)
|
18
19
|
next if raw_value.nil?
|
20
|
+
|
19
21
|
if raw_value.respond_to?(:parse_attrs_to_correct_types)
|
20
22
|
the_copy.send("#{name}=", raw_value.parse_attrs_to_correct_types)
|
21
23
|
else
|
@@ -24,7 +26,7 @@ module Sequent
|
|
24
26
|
end
|
25
27
|
end
|
26
28
|
the_copy
|
27
|
-
rescue => e
|
29
|
+
rescue StandardError => e
|
28
30
|
raise TypeConversionError, e.message
|
29
31
|
end
|
30
32
|
end
|
@@ -1,12 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'securerandom'
|
2
4
|
|
3
5
|
module Sequent
|
4
6
|
module Core
|
5
7
|
module Helpers
|
6
8
|
module UuidHelper
|
7
|
-
|
8
9
|
def new_uuid
|
9
|
-
warn
|
10
|
+
warn <<~EOS
|
11
|
+
DEPRECATION WARNING: Sequent::Core::Helpers::UuidHelper.new_uuid is deprecated. Use Sequent.new_uuid instead
|
12
|
+
EOS
|
10
13
|
Sequent.new_uuid
|
11
14
|
end
|
12
15
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative '../ext/ext'
|
2
4
|
|
3
5
|
module Sequent
|
@@ -6,7 +8,7 @@ module Sequent
|
|
6
8
|
class ValueValidators
|
7
9
|
INVALID_STRING_CHARS = [
|
8
10
|
"\u0000",
|
9
|
-
]
|
11
|
+
].freeze
|
10
12
|
|
11
13
|
VALIDATORS = {
|
12
14
|
::Symbol => ->(_) { true },
|
@@ -14,36 +16,48 @@ module Sequent
|
|
14
16
|
::Integer => ->(value) { valid_integer?(value) },
|
15
17
|
::Boolean => ->(value) { valid_bool?(value) },
|
16
18
|
::Date => ->(value) { valid_date?(value) },
|
17
|
-
::DateTime => ->(value) { valid_date_time?(value) }
|
18
|
-
}
|
19
|
+
::DateTime => ->(value) { valid_date_time?(value) },
|
20
|
+
}.freeze
|
19
21
|
|
20
22
|
def self.valid_integer?(value)
|
21
23
|
value.blank? || Integer(value)
|
22
|
-
rescue
|
24
|
+
rescue StandardError
|
23
25
|
false
|
24
26
|
end
|
25
27
|
|
26
28
|
def self.valid_bool?(value)
|
27
29
|
return true if value.blank?
|
28
|
-
|
30
|
+
|
31
|
+
value.is_a?(TrueClass) || value.is_a?(FalseClass) || value == 'true' || value == 'false'
|
29
32
|
end
|
30
33
|
|
31
34
|
def self.valid_date?(value)
|
32
35
|
return true if value.blank?
|
33
36
|
return true if value.is_a?(Date)
|
34
37
|
return false unless value =~ /\d{4}-\d{2}-\d{2}/
|
35
|
-
|
38
|
+
|
39
|
+
begin
|
40
|
+
!!Date.iso8601(value)
|
41
|
+
rescue StandardError
|
42
|
+
false
|
43
|
+
end
|
36
44
|
end
|
37
45
|
|
38
46
|
def self.valid_date_time?(value)
|
39
47
|
return true if value.blank?
|
40
|
-
|
48
|
+
|
49
|
+
begin
|
50
|
+
value.is_a?(DateTime) || !!DateTime.iso8601(value.dup)
|
51
|
+
rescue StandardError
|
52
|
+
false
|
53
|
+
end
|
41
54
|
end
|
42
55
|
|
43
56
|
def self.valid_string?(value)
|
44
57
|
return true if value.nil?
|
45
|
-
|
46
|
-
|
58
|
+
|
59
|
+
value.to_s && INVALID_STRING_CHARS.none? { |invalid_char| value.to_s.include?(invalid_char) }
|
60
|
+
rescue StandardError
|
47
61
|
false
|
48
62
|
end
|
49
63
|
|
@@ -1,10 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_record'
|
2
4
|
require_relative './persistor'
|
3
5
|
|
4
6
|
module Sequent
|
5
7
|
module Core
|
6
8
|
module Persistors
|
7
|
-
|
8
9
|
#
|
9
10
|
# The ActiveRecordPersistor uses ActiveRecord to update the projection
|
10
11
|
#
|
@@ -17,14 +18,21 @@ module Sequent
|
|
17
18
|
class ActiveRecordPersistor
|
18
19
|
include Persistor
|
19
20
|
|
20
|
-
def update_record(record_class, event, where_clause = {aggregate_id: event.aggregate_id}, options = {}
|
21
|
+
def update_record(record_class, event, where_clause = {aggregate_id: event.aggregate_id}, options = {})
|
21
22
|
record = record_class.unscoped.where(where_clause).first
|
22
|
-
|
23
|
+
unless record
|
24
|
+
fail(<<~EOS)
|
25
|
+
Record of class #{record_class} with where clause #{where_clause} not found while handling event #{event}
|
26
|
+
EOS
|
27
|
+
end
|
28
|
+
|
23
29
|
record.updated_at = event.created_at if record.respond_to?(:updated_at)
|
24
30
|
yield record if block_given?
|
25
|
-
update_sequence_number = options.key?(:update_sequence_number)
|
26
|
-
options[:update_sequence_number]
|
31
|
+
update_sequence_number = if options.key?(:update_sequence_number)
|
32
|
+
options[:update_sequence_number]
|
33
|
+
else
|
27
34
|
record.respond_to?(:sequence_number=)
|
35
|
+
end
|
28
36
|
record.sequence_number = event.sequence_number if update_sequence_number
|
29
37
|
record.save!
|
30
38
|
end
|
@@ -42,11 +50,13 @@ module Sequent
|
|
42
50
|
query = array_of_value_hashes.map do |values|
|
43
51
|
insert_manager = new_insert_manager
|
44
52
|
insert_manager.into(table)
|
45
|
-
insert_manager.insert(
|
46
|
-
|
47
|
-
|
53
|
+
insert_manager.insert(
|
54
|
+
values.map do |key, value|
|
55
|
+
convert_to_values(key, table, value)
|
56
|
+
end,
|
57
|
+
)
|
48
58
|
insert_manager.to_sql
|
49
|
-
end.join(
|
59
|
+
end.join(';')
|
50
60
|
|
51
61
|
execute_sql(query)
|
52
62
|
end
|