sequent 4.3.0 → 6.0.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 +1 -1
- data/db/sequent_schema.rb +3 -3
- data/lib/sequent/configuration.rb +19 -1
- data/lib/sequent/core/aggregate_root.rb +2 -6
- data/lib/sequent/core/aggregate_roots.rb +2 -6
- data/lib/sequent/core/command.rb +8 -12
- data/lib/sequent/core/command_record.rb +1 -1
- data/lib/sequent/core/command_service.rb +13 -2
- data/lib/sequent/core/core.rb +1 -0
- data/lib/sequent/core/event.rb +2 -2
- data/lib/sequent/core/event_store.rb +15 -2
- data/lib/sequent/core/ext/ext.rb +17 -0
- data/lib/sequent/core/helpers/attr_matchers/argument_serializer.rb +35 -0
- data/lib/sequent/core/helpers/attr_matchers/attr_matchers.rb +10 -0
- data/lib/sequent/core/helpers/attr_matchers/dsl.rb +23 -0
- data/lib/sequent/core/helpers/attr_matchers/equals.rb +24 -0
- data/lib/sequent/core/helpers/attr_matchers/greater_than.rb +24 -0
- data/lib/sequent/core/helpers/attr_matchers/greater_than_equals.rb +24 -0
- data/lib/sequent/core/helpers/attr_matchers/less_than.rb +24 -0
- data/lib/sequent/core/helpers/attr_matchers/less_than_equals.rb +24 -0
- data/lib/sequent/core/helpers/attr_matchers/not_equals.rb +24 -0
- data/lib/sequent/core/helpers/attribute_support.rb +35 -9
- data/lib/sequent/core/helpers/autoset_attributes.rb +5 -5
- data/lib/sequent/core/helpers/default_validators.rb +3 -0
- data/lib/sequent/core/helpers/message_dispatcher.rb +20 -0
- data/lib/sequent/core/helpers/message_handler.rb +62 -8
- data/lib/sequent/core/helpers/message_handler_option_registry.rb +59 -0
- data/lib/sequent/core/helpers/message_matchers/any.rb +34 -0
- data/lib/sequent/core/helpers/message_matchers/argument_coercer.rb +24 -0
- data/lib/sequent/core/helpers/message_matchers/argument_serializer.rb +20 -0
- data/lib/sequent/core/helpers/message_matchers/dsl.rb +23 -0
- data/lib/sequent/core/helpers/message_matchers/except_opt.rb +24 -0
- data/lib/sequent/core/helpers/message_matchers/has_attrs.rb +54 -0
- data/lib/sequent/core/helpers/message_matchers/instance_of.rb +24 -0
- data/lib/sequent/core/helpers/message_matchers/is_a.rb +34 -0
- data/lib/sequent/core/helpers/message_matchers/message_matchers.rb +10 -0
- data/lib/sequent/core/helpers/message_router.rb +55 -0
- data/lib/sequent/core/helpers/param_support.rb +2 -0
- data/lib/sequent/core/helpers/string_to_value_parsers.rb +5 -0
- data/lib/sequent/core/helpers/time_validator.rb +23 -0
- data/lib/sequent/core/helpers/value_validators.rb +11 -0
- data/lib/sequent/core/middleware/chain.rb +37 -0
- data/lib/sequent/core/middleware/middleware.rb +3 -0
- data/lib/sequent/core/projector.rb +3 -11
- data/lib/sequent/core/workflow.rb +5 -13
- data/lib/sequent/generator/template_project/Rakefile +2 -2
- data/lib/sequent/generator/template_project/db/sequent_schema.rb +3 -3
- data/lib/sequent/generator/template_project/spec/spec_helper.rb +1 -1
- data/lib/sequent/migrations/migrations.rb +1 -0
- data/lib/sequent/migrations/projectors.rb +2 -2
- data/lib/sequent/migrations/sequent_schema.rb +40 -0
- data/lib/sequent/migrations/view_schema.rb +39 -3
- data/lib/sequent/rake/migration_tasks.rb +36 -33
- data/lib/sequent/support/database.rb +29 -13
- data/lib/sequent/test/command_handler_helpers.rb +3 -3
- data/lib/sequent/test/database_helpers.rb +20 -0
- data/lib/sequent/test/time_comparison.rb +2 -5
- data/lib/sequent/test/{event_handler_helpers.rb → workflow_helpers.rb} +24 -10
- data/lib/sequent/test.rb +2 -1
- data/lib/sequent/util/dry_run.rb +1 -1
- data/lib/version.rb +1 -1
- metadata +40 -15
- data/lib/sequent/rake/tasks.rb +0 -121
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 24d2ee32c038b179c4386d2df97025af873487c5fe333952e5fedbe5d3ed47d8
|
4
|
+
data.tar.gz: 8d0464ac057a6e458ee7f131caba027fbddbd751af5b9d4314907ed248d0734d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5b064934ae367d2e57baaa081c0b3f392bb932a1bb12fed00db337a6365f32c0949e5c6c4fe3eae6fa4a1374d931db517cf33efa911fdc265883bb122e8ce6ab
|
7
|
+
data.tar.gz: b5570de3a8b9deb24c1006486c37166f6e17d06d23a30d38a9de9b1e0755f1cbf4e57e1a2c1890ff9a68908f2077e90d7f8d1e79240ae3c5943de23f185be6f1
|
data/bin/sequent
CHANGED
@@ -31,7 +31,7 @@ def new_project(args)
|
|
31
31
|
bundle exec rake sequent:migrate:offline
|
32
32
|
|
33
33
|
Run the example specs:
|
34
|
-
|
34
|
+
SEQUENT_ENV=test bundle exec rake sequent:db:create
|
35
35
|
bundle exec rspec spec
|
36
36
|
|
37
37
|
To generate new aggregates use:
|
data/db/sequent_schema.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
ActiveRecord::Schema.define do
|
2
2
|
|
3
3
|
create_table "event_records", :force => true do |t|
|
4
|
-
t.
|
4
|
+
t.uuid "aggregate_id", :null => false
|
5
5
|
t.integer "sequence_number", :null => false
|
6
6
|
t.datetime "created_at", :null => false
|
7
7
|
t.string "event_type", :null => false
|
@@ -27,7 +27,7 @@ CREATE INDEX snapshot_events ON event_records (aggregate_id, sequence_number DES
|
|
27
27
|
|
28
28
|
create_table "command_records", :force => true do |t|
|
29
29
|
t.string "user_id"
|
30
|
-
t.
|
30
|
+
t.uuid "aggregate_id"
|
31
31
|
t.string "command_type", :null => false
|
32
32
|
t.string "event_aggregate_id"
|
33
33
|
t.integer "event_sequence_number"
|
@@ -40,7 +40,7 @@ CREATE INDEX snapshot_events ON event_records (aggregate_id, sequence_number DES
|
|
40
40
|
create_table "stream_records", :force => true do |t|
|
41
41
|
t.datetime "created_at", :null => false
|
42
42
|
t.string "aggregate_type", :null => false
|
43
|
-
t.
|
43
|
+
t.uuid "aggregate_id", :null => false
|
44
44
|
t.integer "snapshot_threshold"
|
45
45
|
end
|
46
46
|
|
@@ -32,6 +32,8 @@ module Sequent
|
|
32
32
|
|
33
33
|
DEFAULT_ERROR_LOCALE_RESOLVER = -> { I18n.locale || :en }
|
34
34
|
|
35
|
+
DEFAULT_TIME_PRECISION = ActiveSupport::JSON::Encoding.time_precision
|
36
|
+
|
35
37
|
attr_accessor :aggregate_repository,
|
36
38
|
:event_store,
|
37
39
|
:command_service,
|
@@ -43,6 +45,7 @@ module Sequent
|
|
43
45
|
:event_record_hooks_class,
|
44
46
|
:command_handlers,
|
45
47
|
:command_filters,
|
48
|
+
:command_middleware,
|
46
49
|
:event_handlers,
|
47
50
|
:uuid_generator,
|
48
51
|
:disable_event_handlers,
|
@@ -56,7 +59,11 @@ module Sequent
|
|
56
59
|
:database_config_directory,
|
57
60
|
:database_schema_directory,
|
58
61
|
:event_store_schema_name,
|
59
|
-
:strict_check_attributes_on_apply_events
|
62
|
+
:strict_check_attributes_on_apply_events,
|
63
|
+
:enable_multiple_database_support,
|
64
|
+
:primary_database_role,
|
65
|
+
:primary_database_key,
|
66
|
+
:time_precision
|
60
67
|
|
61
68
|
attr_reader :migrations_class_name,
|
62
69
|
:versions_table_name,
|
@@ -78,6 +85,7 @@ module Sequent
|
|
78
85
|
self.command_handlers = []
|
79
86
|
self.command_filters = []
|
80
87
|
self.event_handlers = []
|
88
|
+
self.command_middleware = Sequent::Core::Middleware::Chain.new
|
81
89
|
|
82
90
|
self.aggregate_repository = Sequent::Core::AggregateRepository.new
|
83
91
|
self.event_store = Sequent::Core::EventStore.new
|
@@ -107,6 +115,16 @@ module Sequent
|
|
107
115
|
|
108
116
|
self.logger = Logger.new(STDOUT).tap { |l| l.level = Logger::INFO }
|
109
117
|
self.error_locale_resolver = DEFAULT_ERROR_LOCALE_RESOLVER
|
118
|
+
|
119
|
+
self.enable_multiple_database_support = false
|
120
|
+
self.primary_database_role = :writing
|
121
|
+
self.primary_database_key = :primary
|
122
|
+
|
123
|
+
self.time_precision = DEFAULT_TIME_PRECISION
|
124
|
+
end
|
125
|
+
|
126
|
+
def can_use_multiple_databases?
|
127
|
+
enable_multiple_database_support && ActiveRecord.version > Gem::Version.new('6.1.0')
|
110
128
|
end
|
111
129
|
|
112
130
|
def replayed_ids_table_name=(table_name)
|
@@ -39,14 +39,10 @@ module Sequent
|
|
39
39
|
include Helpers::MessageHandler
|
40
40
|
include Helpers::AutosetAttributes
|
41
41
|
include SnapshotConfiguration
|
42
|
+
extend ActiveSupport::DescendantsTracker
|
42
43
|
|
43
44
|
attr_reader :id, :uncommitted_events, :sequence_number, :event_stream
|
44
45
|
|
45
|
-
def self.inherited(subclass)
|
46
|
-
super
|
47
|
-
AggregateRoots << subclass
|
48
|
-
end
|
49
|
-
|
50
46
|
def self.load_from_history(stream, events)
|
51
47
|
first, *rest = events
|
52
48
|
if first.is_a? SnapshotEvent
|
@@ -127,7 +123,7 @@ module Sequent
|
|
127
123
|
# Provide subclasses nice DSL to 'apply' events via:
|
128
124
|
#
|
129
125
|
# def send_invoice
|
130
|
-
# apply InvoiceSentEvent, send_date:
|
126
|
+
# apply InvoiceSentEvent, send_date: Time.now
|
131
127
|
# end
|
132
128
|
#
|
133
129
|
def apply(event, params = {})
|
@@ -3,21 +3,17 @@
|
|
3
3
|
module Sequent
|
4
4
|
module Core
|
5
5
|
#
|
6
|
-
# Utility class containing all subclasses of AggregateRoot
|
6
|
+
# Utility class containing all subclasses of AggregateRoot.
|
7
7
|
#
|
8
8
|
class AggregateRoots
|
9
9
|
class << self
|
10
10
|
def aggregate_roots
|
11
|
-
|
11
|
+
Sequent::AggregateRoot.descendants
|
12
12
|
end
|
13
13
|
|
14
14
|
def all
|
15
15
|
aggregate_roots
|
16
16
|
end
|
17
|
-
|
18
|
-
def <<(aggregate_root)
|
19
|
-
aggregate_roots << aggregate_root
|
20
|
-
end
|
21
17
|
end
|
22
18
|
end
|
23
19
|
end
|
data/lib/sequent/core/command.rb
CHANGED
@@ -28,17 +28,17 @@ module Sequent
|
|
28
28
|
include ActiveModel::Validations
|
29
29
|
include ActiveModel::Validations::Callbacks
|
30
30
|
include Sequent::Core::Helpers::TypeConversionSupport
|
31
|
+
extend ActiveSupport::DescendantsTracker
|
31
32
|
|
32
|
-
attrs created_at:
|
33
|
+
attrs created_at: Time
|
34
|
+
|
35
|
+
define_model_callbacks :initialize, only: :after
|
33
36
|
|
34
37
|
def initialize(args = {})
|
35
38
|
update_all_attributes args
|
36
|
-
@created_at =
|
37
|
-
end
|
39
|
+
@created_at = Time.now
|
38
40
|
|
39
|
-
|
40
|
-
super
|
41
|
-
Commands << subclass
|
41
|
+
_run_initialize_callbacks
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
@@ -56,22 +56,18 @@ module Sequent
|
|
56
56
|
end
|
57
57
|
|
58
58
|
#
|
59
|
-
# Utility class containing all subclasses of BaseCommand
|
59
|
+
# Utility class containing all subclasses of BaseCommand.
|
60
60
|
#
|
61
61
|
class Commands
|
62
62
|
class << self
|
63
63
|
def commands
|
64
|
-
|
64
|
+
Sequent::Core::BaseCommand.descendants
|
65
65
|
end
|
66
66
|
|
67
67
|
def all
|
68
68
|
commands
|
69
69
|
end
|
70
70
|
|
71
|
-
def <<(command)
|
72
|
-
commands << command
|
73
|
-
end
|
74
|
-
|
75
71
|
def find(command_name)
|
76
72
|
commands.find { |c| c.name == command_name }
|
77
73
|
end
|
@@ -8,7 +8,7 @@ module Sequent
|
|
8
8
|
module SerializesCommand
|
9
9
|
def command
|
10
10
|
args = Sequent::Core::Oj.strict_load(command_json)
|
11
|
-
Class.const_get(command_type
|
11
|
+
Class.const_get(command_type).deserialize_from_json(args)
|
12
12
|
end
|
13
13
|
|
14
14
|
def command=(command)
|
@@ -50,7 +50,12 @@ module Sequent
|
|
50
50
|
def process_commands
|
51
51
|
Sequent::Util.skip_if_already_processing(:command_service_process_commands) do
|
52
52
|
transaction_provider.transactional do
|
53
|
-
|
53
|
+
until command_queue.empty?
|
54
|
+
command = command_queue.pop
|
55
|
+
command_middleware.invoke(command) do
|
56
|
+
process_command(command)
|
57
|
+
end
|
58
|
+
end
|
54
59
|
Sequent::Util.done_processing(:command_service_process_commands)
|
55
60
|
end
|
56
61
|
ensure
|
@@ -66,7 +71,9 @@ module Sequent
|
|
66
71
|
|
67
72
|
filters.each { |filter| filter.execute(command) }
|
68
73
|
|
69
|
-
|
74
|
+
I18n.with_locale(Sequent.configuration.error_locale_resolver.call) do
|
75
|
+
fail CommandNotValid, command unless command.valid?
|
76
|
+
end
|
70
77
|
|
71
78
|
parsed_command = command.parse_attrs_to_correct_types
|
72
79
|
command_handlers.select do |h|
|
@@ -98,6 +105,10 @@ module Sequent
|
|
98
105
|
def command_handlers
|
99
106
|
Sequent.configuration.command_handlers
|
100
107
|
end
|
108
|
+
|
109
|
+
def command_middleware
|
110
|
+
Sequent.configuration.command_middleware
|
111
|
+
end
|
101
112
|
end
|
102
113
|
|
103
114
|
# Raised when BaseCommand.valid? returns false
|
data/lib/sequent/core/core.rb
CHANGED
@@ -4,6 +4,7 @@ require_relative 'sequent_oj'
|
|
4
4
|
require_relative 'helpers/helpers'
|
5
5
|
require_relative 'persistors/persistors'
|
6
6
|
require_relative 'transactions/transactions'
|
7
|
+
require_relative 'middleware/middleware'
|
7
8
|
require_relative 'event'
|
8
9
|
require_relative 'aggregate_repository'
|
9
10
|
require_relative 'aggregate_root'
|
data/lib/sequent/core/event.rb
CHANGED
@@ -13,14 +13,14 @@ module Sequent
|
|
13
13
|
include Sequent::Core::Helpers::AttributeSupport
|
14
14
|
include Sequent::Core::Helpers::EqualSupport
|
15
15
|
include Sequent::Core::Helpers::StringSupport
|
16
|
-
attrs aggregate_id: String, sequence_number: Integer, created_at:
|
16
|
+
attrs aggregate_id: String, sequence_number: Integer, created_at: Time
|
17
17
|
|
18
18
|
def initialize(args = {})
|
19
19
|
update_all_attributes args
|
20
20
|
fail 'Missing aggregate_id' unless @aggregate_id
|
21
21
|
fail 'Missing sequence_number' unless @sequence_number
|
22
22
|
|
23
|
-
@created_at ||=
|
23
|
+
@created_at ||= Time.now
|
24
24
|
end
|
25
25
|
|
26
26
|
def payload
|
@@ -26,8 +26,21 @@ module Sequent
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
-
|
30
|
-
|
29
|
+
##
|
30
|
+
# Disables event type caching (ie. for in development).
|
31
|
+
#
|
32
|
+
class NoEventTypesCache
|
33
|
+
def fetch_or_store(event_type)
|
34
|
+
yield(event_type)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def initialize(cache_event_types: true)
|
39
|
+
@event_types = if cache_event_types
|
40
|
+
ThreadSafe::Cache.new
|
41
|
+
else
|
42
|
+
NoEventTypesCache.new
|
43
|
+
end
|
31
44
|
end
|
32
45
|
|
33
46
|
##
|
data/lib/sequent/core/ext/ext.rb
CHANGED
@@ -68,6 +68,23 @@ class DateTime
|
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
71
|
+
class Time
|
72
|
+
def self.from_params(value)
|
73
|
+
value.blank? ? nil : Time.iso8601(value.dup)
|
74
|
+
rescue ArgumentError
|
75
|
+
value
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.deserialize_from_json(value)
|
79
|
+
value.blank? ? nil : Time.iso8601(value.dup)
|
80
|
+
rescue ArgumentError => e
|
81
|
+
return Time.parse(value.dup) if e.message =~ /invalid xmlschema format/ # ruby >= 3
|
82
|
+
return Time.parse(value.dup) if e.message =~ /invalid date:/ # ruby 2.7
|
83
|
+
|
84
|
+
raise
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
71
88
|
class Array
|
72
89
|
def self.deserialize_from_json(value)
|
73
90
|
value
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sequent
|
4
|
+
module Core
|
5
|
+
module Helpers
|
6
|
+
module AttrMatchers
|
7
|
+
class ArgumentSerializer
|
8
|
+
class << self
|
9
|
+
def serialize_value(value, enclose_hash: false)
|
10
|
+
return value.to_s if value.respond_to?(:matches_attr?)
|
11
|
+
return %("#{value}") if value.is_a?(String)
|
12
|
+
return serialize_hash(value, enclose_hash: enclose_hash) if value.is_a?(Hash)
|
13
|
+
|
14
|
+
value
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def serialize_hash(hash, enclose_hash:)
|
20
|
+
serialized = hash
|
21
|
+
.map do |(name, value)|
|
22
|
+
"#{name}: #{serialize_value(value, enclose_hash: true)}"
|
23
|
+
end
|
24
|
+
.join(', ')
|
25
|
+
|
26
|
+
return "{#{serialized}}" if enclose_hash
|
27
|
+
|
28
|
+
serialized
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'dsl'
|
4
|
+
require_relative 'argument_serializer'
|
5
|
+
require_relative 'equals'
|
6
|
+
require_relative 'not_equals'
|
7
|
+
require_relative 'greater_than_equals'
|
8
|
+
require_relative 'greater_than'
|
9
|
+
require_relative 'less_than_equals'
|
10
|
+
require_relative 'less_than'
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sequent
|
4
|
+
module Core
|
5
|
+
module Helpers
|
6
|
+
module AttrMatchers
|
7
|
+
module DSL
|
8
|
+
def register_matcher(name, matcher_class)
|
9
|
+
if respond_to?(name)
|
10
|
+
fail ArgumentError, "Cannot register attr matcher because it would overwrite existing method '#{name}'"
|
11
|
+
end
|
12
|
+
|
13
|
+
define_method(name) do |*expected|
|
14
|
+
matcher_class.new(*expected)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
extend DSL
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sequent
|
4
|
+
module Core
|
5
|
+
module Helpers
|
6
|
+
module AttrMatchers
|
7
|
+
Equals = Struct.new(:expected_value) do
|
8
|
+
def matches_attr?(actual_value)
|
9
|
+
actual_value == expected_value
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
"eq(#{ArgumentSerializer.serialize_value(expected_value)})"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
Sequent::Core::Helpers::AttrMatchers.register_matcher(
|
22
|
+
:eq,
|
23
|
+
Sequent::Core::Helpers::AttrMatchers::Equals,
|
24
|
+
)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sequent
|
4
|
+
module Core
|
5
|
+
module Helpers
|
6
|
+
module AttrMatchers
|
7
|
+
GreaterThan = Struct.new(:expected_value) do
|
8
|
+
def matches_attr?(actual_value)
|
9
|
+
actual_value > expected_value
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
"gt(#{ArgumentSerializer.serialize_value(expected_value)})"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
Sequent::Core::Helpers::AttrMatchers.register_matcher(
|
22
|
+
:gt,
|
23
|
+
Sequent::Core::Helpers::AttrMatchers::GreaterThan,
|
24
|
+
)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sequent
|
4
|
+
module Core
|
5
|
+
module Helpers
|
6
|
+
module AttrMatchers
|
7
|
+
GreaterThanEquals = Struct.new(:expected_value) do
|
8
|
+
def matches_attr?(actual_value)
|
9
|
+
actual_value >= expected_value
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
"gte(#{ArgumentSerializer.serialize_value(expected_value)})"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
Sequent::Core::Helpers::AttrMatchers.register_matcher(
|
22
|
+
:gte,
|
23
|
+
Sequent::Core::Helpers::AttrMatchers::GreaterThanEquals,
|
24
|
+
)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sequent
|
4
|
+
module Core
|
5
|
+
module Helpers
|
6
|
+
module AttrMatchers
|
7
|
+
LessThan = Struct.new(:expected_value) do
|
8
|
+
def matches_attr?(actual_value)
|
9
|
+
actual_value < expected_value
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
"lt(#{ArgumentSerializer.serialize_value(expected_value)})"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
Sequent::Core::Helpers::AttrMatchers.register_matcher(
|
22
|
+
:lt,
|
23
|
+
Sequent::Core::Helpers::AttrMatchers::LessThan,
|
24
|
+
)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sequent
|
4
|
+
module Core
|
5
|
+
module Helpers
|
6
|
+
module AttrMatchers
|
7
|
+
LessThanEquals = Struct.new(:expected_value) do
|
8
|
+
def matches_attr?(actual_value)
|
9
|
+
actual_value <= expected_value
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
"lte(#{ArgumentSerializer.serialize_value(expected_value)})"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
Sequent::Core::Helpers::AttrMatchers.register_matcher(
|
22
|
+
:lte,
|
23
|
+
Sequent::Core::Helpers::AttrMatchers::LessThanEquals,
|
24
|
+
)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sequent
|
4
|
+
module Core
|
5
|
+
module Helpers
|
6
|
+
module AttrMatchers
|
7
|
+
NotEquals = Struct.new(:expected_value) do
|
8
|
+
def matches_attr?(actual_value)
|
9
|
+
actual_value != expected_value
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
"neq(#{ArgumentSerializer.serialize_value(expected_value)})"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
Sequent::Core::Helpers::AttrMatchers.register_matcher(
|
22
|
+
:neq,
|
23
|
+
Sequent::Core::Helpers::AttrMatchers::NotEquals,
|
24
|
+
)
|
@@ -6,6 +6,7 @@ require_relative 'array_with_type'
|
|
6
6
|
require_relative 'default_validators'
|
7
7
|
require_relative 'type_conversion_support'
|
8
8
|
require_relative 'date_time_validator'
|
9
|
+
require_relative 'time_validator'
|
9
10
|
require_relative 'association_validator'
|
10
11
|
|
11
12
|
module Sequent
|
@@ -40,19 +41,19 @@ module Sequent
|
|
40
41
|
|
41
42
|
# module containing class methods to be added
|
42
43
|
module ClassMethods
|
43
|
-
|
44
|
-
@types ||= {}
|
45
|
-
return @merged_types if @merged_types
|
44
|
+
attr_reader :types
|
46
45
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
46
|
+
# Called when this module is included or when a class which includes this module is inherited from.
|
47
|
+
#
|
48
|
+
# All declared attrs are merged into @types in order to prevent superfluous calculation of types in a class
|
49
|
+
# hierarchy.
|
50
|
+
def initialize_types
|
51
|
+
@types = inherited_types
|
52
52
|
end
|
53
53
|
|
54
54
|
def attrs(args)
|
55
|
-
|
55
|
+
validate_attrs!(args)
|
56
|
+
|
56
57
|
@types.merge!(args)
|
57
58
|
associations = []
|
58
59
|
args.each do |attribute, type|
|
@@ -126,6 +127,18 @@ EOS
|
|
126
127
|
@upcasters.push(block)
|
127
128
|
end
|
128
129
|
|
130
|
+
private
|
131
|
+
|
132
|
+
def inherited_types
|
133
|
+
merged_types = is_a?(Class) && superclass.respond_to?(:types) ? superclass.types.dup : {}
|
134
|
+
|
135
|
+
included_modules
|
136
|
+
.select { |m| m.include? Sequent::Core::Helpers::AttributeSupport }
|
137
|
+
.reduce(merged_types) do |memo, mod|
|
138
|
+
memo.merge(mod.types)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
129
142
|
def upcast!(hash)
|
130
143
|
return if @upcasters.nil?
|
131
144
|
|
@@ -133,11 +146,24 @@ EOS
|
|
133
146
|
upcaster.call(hash)
|
134
147
|
end
|
135
148
|
end
|
149
|
+
|
150
|
+
def validate_attrs!(args)
|
151
|
+
duplicate_attrs = types.keys & args.keys
|
152
|
+
|
153
|
+
fail ArgumentError, "Attributes already defined: #{duplicate_attrs.join(', ')}" if duplicate_attrs.any?
|
154
|
+
end
|
155
|
+
|
156
|
+
def inherited(subclass)
|
157
|
+
super
|
158
|
+
|
159
|
+
subclass.initialize_types
|
160
|
+
end
|
136
161
|
end
|
137
162
|
|
138
163
|
# extend host class with class methods when we're included
|
139
164
|
def self.included(host_class)
|
140
165
|
host_class.extend(ClassMethods)
|
166
|
+
host_class.initialize_types
|
141
167
|
end
|
142
168
|
|
143
169
|
def attributes
|
@@ -36,11 +36,11 @@ module Sequent
|
|
36
36
|
event_class.types.keys.reject { |k| @@autoset_ignore_attributes.include?(k.to_s) }
|
37
37
|
end
|
38
38
|
|
39
|
-
def autoset_attributes_for_events(*
|
40
|
-
|
41
|
-
on
|
42
|
-
self.class.event_attribute_keys(
|
43
|
-
instance_variable_set(:"@#{attribute_name}", event.
|
39
|
+
def autoset_attributes_for_events(*args)
|
40
|
+
args.each do |arg|
|
41
|
+
on arg do |event|
|
42
|
+
self.class.event_attribute_keys(event.class).each do |attribute_name|
|
43
|
+
instance_variable_set(:"@#{attribute_name}", event.public_send(attribute_name.to_sym))
|
44
44
|
end
|
45
45
|
end
|
46
46
|
end
|
@@ -17,6 +17,9 @@ module Sequent
|
|
17
17
|
Date => ->(klass, field) do
|
18
18
|
klass.validates field, 'sequent::Core::Helpers::Date' => true
|
19
19
|
end,
|
20
|
+
Time => ->(klass, field) do
|
21
|
+
klass.validates field, 'sequent::Core::Helpers::Time' => true
|
22
|
+
end,
|
20
23
|
DateTime => ->(klass, field) do
|
21
24
|
klass.validates field, 'sequent::Core::Helpers::DateTime' => true
|
22
25
|
end,
|