evt-message_store-postgres 0.1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/database/clear-events-table.sh +40 -0
- data/database/extensions.sql +1 -0
- data/database/functions/category.sql +10 -0
- data/database/functions/stream-version.sql +13 -0
- data/database/functions/write-event.sql +55 -0
- data/database/indexes/events-category-global-position.sql +1 -0
- data/database/indexes/events-category.sql +1 -0
- data/database/indexes/events-id.sql +1 -0
- data/database/indexes/events-stream-name-position-uniq.sql +1 -0
- data/database/indexes/events-stream-name.sql +1 -0
- data/database/install.sh +103 -0
- data/database/list-events.sh +52 -0
- data/database/table/events-table.sql +19 -0
- data/database/test/write-event-expected-version.sql +1 -0
- data/database/test/write-event.sql +1 -0
- data/database/uninstall.sh +60 -0
- data/lib/message_store/postgres.rb +24 -0
- data/lib/message_store/postgres/controls.rb +6 -0
- data/lib/message_store/postgres/controls/category.rb +34 -0
- data/lib/message_store/postgres/controls/message_data.rb +7 -0
- data/lib/message_store/postgres/controls/put.rb +26 -0
- data/lib/message_store/postgres/controls/stream_name.rb +22 -0
- data/lib/message_store/postgres/get.rb +91 -0
- data/lib/message_store/postgres/get/last.rb +111 -0
- data/lib/message_store/postgres/get/last/select_statement.rb +47 -0
- data/lib/message_store/postgres/get/select_statement.rb +88 -0
- data/lib/message_store/postgres/log.rb +11 -0
- data/lib/message_store/postgres/put.rb +145 -0
- data/lib/message_store/postgres/read.rb +12 -0
- data/lib/message_store/postgres/read/iterator.rb +17 -0
- data/lib/message_store/postgres/session.rb +128 -0
- data/lib/message_store/postgres/settings.rb +30 -0
- data/lib/message_store/postgres/stream_name.rb +52 -0
- data/lib/message_store/postgres/write.rb +46 -0
- data/scripts/evt-pg-create-db +7 -0
- data/scripts/evt-pg-delete-db +7 -0
- data/scripts/evt-pg-list-events +7 -0
- data/scripts/evt-pg-recreate-db +11 -0
- data/scripts/scripts_init.rb +12 -0
- metadata +156 -0
@@ -0,0 +1,26 @@
|
|
1
|
+
module MessageStore
|
2
|
+
module Postgres
|
3
|
+
module Controls
|
4
|
+
module Put
|
5
|
+
def self.call(instances: nil, stream_name: nil, message: nil, category: nil)
|
6
|
+
instances ||= 1
|
7
|
+
stream_name ||= StreamName.example(category: category)
|
8
|
+
|
9
|
+
message_specified = !message.nil?
|
10
|
+
|
11
|
+
message ||= MessageData::Write.example
|
12
|
+
|
13
|
+
instances.times do
|
14
|
+
MessageStore::Postgres::Put.(message, stream_name)
|
15
|
+
|
16
|
+
unless message_specified
|
17
|
+
message.id = MessageData::Write.id
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
stream_name
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# module MessageStore
|
2
|
+
# module Postgres
|
3
|
+
# module Controls
|
4
|
+
# StreamName = MessageStore::Controls::StreamName
|
5
|
+
# end
|
6
|
+
# end
|
7
|
+
# end
|
8
|
+
|
9
|
+
module MessageStore
|
10
|
+
module Postgres
|
11
|
+
module Controls
|
12
|
+
module StreamName
|
13
|
+
def self.example(category: nil, id: nil, type: nil, types: nil, randomize_category: nil)
|
14
|
+
category ||= Category.example(category: category, randomize_category: randomize_category)
|
15
|
+
id ||= Identifier::UUID.random
|
16
|
+
|
17
|
+
MessageStore::Postgres::StreamName.stream_name(category, id, type: type, types: types)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module MessageStore
|
2
|
+
module Postgres
|
3
|
+
class Get
|
4
|
+
include MessageStore::Get
|
5
|
+
|
6
|
+
initializer :batch_size
|
7
|
+
|
8
|
+
dependency :session, Session
|
9
|
+
|
10
|
+
def self.build(batch_size: nil, session: nil)
|
11
|
+
new(batch_size).tap do |instance|
|
12
|
+
instance.configure(session: session)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.configure(receiver, attr_name: nil, position: nil, batch_size: nil, session: nil)
|
17
|
+
attr_name ||= :get
|
18
|
+
instance = build(batch_size: batch_size, session: session)
|
19
|
+
receiver.public_send "#{attr_name}=", instance
|
20
|
+
end
|
21
|
+
|
22
|
+
def configure(session: nil)
|
23
|
+
Session.configure self, session: session
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.call(stream_name, position: nil, batch_size: nil, session: nil)
|
27
|
+
instance = build(batch_size: batch_size, session: session)
|
28
|
+
instance.(stream_name, position: position)
|
29
|
+
end
|
30
|
+
|
31
|
+
def call(stream_name, position: nil)
|
32
|
+
logger.trace { "Getting message data (Position: #{position.inspect}, Stream Name: #{stream_name}, Batch Size: #{batch_size.inspect})" }
|
33
|
+
|
34
|
+
records = get_records(stream_name, position)
|
35
|
+
|
36
|
+
messages = convert(records)
|
37
|
+
|
38
|
+
logger.info { "Finished getting message data (Count: #{messages.length}, Position: #{position.inspect}, Stream Name: #{stream_name}, Batch Size: #{batch_size.inspect})" }
|
39
|
+
logger.info(tags: [:data, :message_data]) { messages.pretty_inspect }
|
40
|
+
|
41
|
+
messages
|
42
|
+
end
|
43
|
+
|
44
|
+
def get_records(stream_name, position)
|
45
|
+
logger.trace { "Getting records (Stream: #{stream_name}, Position: #{position.inspect}, Batch Size: #{batch_size.inspect})" }
|
46
|
+
|
47
|
+
select_statement = SelectStatement.build(stream_name, position: position, batch_size: batch_size)
|
48
|
+
|
49
|
+
records = session.execute(select_statement.sql)
|
50
|
+
|
51
|
+
logger.debug { "Finished getting records (Count: #{records.ntuples}, Stream: #{stream_name}, Position: #{position.inspect}, Batch Size: #{batch_size.inspect})" }
|
52
|
+
|
53
|
+
records
|
54
|
+
end
|
55
|
+
|
56
|
+
def convert(records)
|
57
|
+
logger.trace { "Converting records to message data (Records Count: #{records.ntuples})" }
|
58
|
+
|
59
|
+
messages = records.map do |record|
|
60
|
+
record['data'] = Deserialize.data(record['data'])
|
61
|
+
record['metadata'] = Deserialize.metadata(record['metadata'])
|
62
|
+
record['time'] = Time.utc_coerced(record['time'])
|
63
|
+
|
64
|
+
MessageData::Read.build record
|
65
|
+
end
|
66
|
+
|
67
|
+
logger.debug { "Converted records to message data (Message Data Count: #{messages.length})" }
|
68
|
+
|
69
|
+
messages
|
70
|
+
end
|
71
|
+
|
72
|
+
module Deserialize
|
73
|
+
def self.data(serialized_data)
|
74
|
+
return nil if serialized_data.nil?
|
75
|
+
Transform::Read.(serialized_data, MessageData::Hash, :json)
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.metadata(serialized_metadata)
|
79
|
+
return nil if serialized_metadata.nil?
|
80
|
+
Transform::Read.(serialized_metadata, MessageData::Hash, :json)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
module Time
|
85
|
+
def self.utc_coerced(local_time)
|
86
|
+
Clock::UTC.coerce(local_time)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module MessageStore
|
2
|
+
module Postgres
|
3
|
+
class Get
|
4
|
+
class Last
|
5
|
+
include Log::Dependency
|
6
|
+
|
7
|
+
dependency :session, Session
|
8
|
+
|
9
|
+
def self.build(session: nil)
|
10
|
+
new.tap do |instance|
|
11
|
+
instance.configure(session: session)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.configure(receiver, attr_name: nil, session: nil)
|
16
|
+
attr_name ||= :get_last
|
17
|
+
instance = build(session: session)
|
18
|
+
receiver.public_send "#{attr_name}=", instance
|
19
|
+
end
|
20
|
+
|
21
|
+
def configure(session: nil)
|
22
|
+
Session.configure self, session: session
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.call(stream_name, session: nil)
|
26
|
+
instance = build(session: session)
|
27
|
+
instance.(stream_name)
|
28
|
+
end
|
29
|
+
|
30
|
+
def call(stream_name)
|
31
|
+
logger.trace { "Getting last message data (Stream Name: #{stream_name})" }
|
32
|
+
|
33
|
+
record = get_record(stream_name)
|
34
|
+
|
35
|
+
return nil if record.nil?
|
36
|
+
|
37
|
+
message_data = convert(record)
|
38
|
+
|
39
|
+
logger.info { "Finished getting message data (Stream Name: #{stream_name})" }
|
40
|
+
logger.info(tags: [:data, :message_data]) { message_data.pretty_inspect }
|
41
|
+
|
42
|
+
message_data
|
43
|
+
end
|
44
|
+
|
45
|
+
def get_record(stream_name)
|
46
|
+
logger.trace { "Getting last record (Stream: #{stream_name})" }
|
47
|
+
|
48
|
+
select_statement = SelectStatement.build(stream_name)
|
49
|
+
|
50
|
+
records = session.execute(select_statement.sql)
|
51
|
+
|
52
|
+
logger.debug { "Finished getting record (Stream: #{stream_name})" }
|
53
|
+
|
54
|
+
return nil if records.ntuples == 0
|
55
|
+
|
56
|
+
records[0]
|
57
|
+
end
|
58
|
+
|
59
|
+
def convert(record)
|
60
|
+
logger.trace { "Converting record to message data" }
|
61
|
+
|
62
|
+
record['data'] = Deserialize.data(record['data'])
|
63
|
+
record['metadata'] = Deserialize.metadata(record['metadata'])
|
64
|
+
record['time'] = Time.utc_coerced(record['time'])
|
65
|
+
|
66
|
+
message_data = MessageData::Read.build(record)
|
67
|
+
|
68
|
+
logger.debug { "Converted record to message data" }
|
69
|
+
|
70
|
+
message_data
|
71
|
+
end
|
72
|
+
|
73
|
+
def __convert(records)
|
74
|
+
logger.trace { "Converting records to message data (Records Count: #{records.ntuples})" }
|
75
|
+
|
76
|
+
messages = records.map do |record|
|
77
|
+
record['data'] = Deserialize.data(record['data'])
|
78
|
+
record['metadata'] = Deserialize.metadata(record['metadata'])
|
79
|
+
record['time'] = Time.utc_coerced(record['time'])
|
80
|
+
|
81
|
+
MessageData::Read.build record
|
82
|
+
|
83
|
+
break
|
84
|
+
end
|
85
|
+
|
86
|
+
logger.debug { "Converted records to message data (Message Data Count: #{messages.length})" }
|
87
|
+
|
88
|
+
messages
|
89
|
+
end
|
90
|
+
|
91
|
+
module Deserialize
|
92
|
+
def self.data(serialized_data)
|
93
|
+
return nil if serialized_data.nil?
|
94
|
+
Transform::Read.(serialized_data, MessageData::Hash, :json)
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.metadata(serialized_metadata)
|
98
|
+
return nil if serialized_metadata.nil?
|
99
|
+
Transform::Read.(serialized_metadata, MessageData::Hash, :json)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
module Time
|
104
|
+
def self.utc_coerced(local_time)
|
105
|
+
Clock::UTC.coerce(local_time)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module MessageStore
|
2
|
+
module Postgres
|
3
|
+
class Get
|
4
|
+
class Last
|
5
|
+
class SelectStatement
|
6
|
+
include Log::Dependency
|
7
|
+
|
8
|
+
initializer :stream_name
|
9
|
+
|
10
|
+
def self.build(stream_name)
|
11
|
+
new(stream_name)
|
12
|
+
end
|
13
|
+
|
14
|
+
def sql
|
15
|
+
logger.trace(tag: :sql) { "Composing select statement (Stream: #{stream_name})" }
|
16
|
+
|
17
|
+
statement = <<-SQL
|
18
|
+
SELECT
|
19
|
+
id::varchar,
|
20
|
+
stream_name::varchar,
|
21
|
+
position::int,
|
22
|
+
type::varchar,
|
23
|
+
global_position::bigint,
|
24
|
+
data::varchar,
|
25
|
+
metadata::varchar,
|
26
|
+
time::timestamp
|
27
|
+
FROM
|
28
|
+
events
|
29
|
+
WHERE
|
30
|
+
stream_name = '#{stream_name}'
|
31
|
+
ORDER BY
|
32
|
+
position DESC
|
33
|
+
LIMIT
|
34
|
+
1
|
35
|
+
;
|
36
|
+
SQL
|
37
|
+
|
38
|
+
logger.debug(tag: :sql) { "Composed select statement (Stream: #{stream_name})" }
|
39
|
+
logger.debug(tags: [:data, :sql]) { "Statement: #{statement}" }
|
40
|
+
|
41
|
+
statement
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module MessageStore
|
2
|
+
module Postgres
|
3
|
+
class Get
|
4
|
+
class SelectStatement
|
5
|
+
include Log::Dependency
|
6
|
+
|
7
|
+
initializer :stream_name, w(:position), w(:batch_size)
|
8
|
+
|
9
|
+
def position
|
10
|
+
@position ||= Defaults.position
|
11
|
+
end
|
12
|
+
|
13
|
+
def batch_size
|
14
|
+
@batch_size ||= Defaults.batch_size
|
15
|
+
end
|
16
|
+
|
17
|
+
def stream_type_list
|
18
|
+
@stream_type ||= StreamName.get_type_list(stream_name)
|
19
|
+
end
|
20
|
+
|
21
|
+
def category_stream?
|
22
|
+
is_category_stream ||= StreamName.category?(stream_name)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.build(stream_name, position: nil, batch_size: nil)
|
26
|
+
new(stream_name, position, batch_size)
|
27
|
+
end
|
28
|
+
|
29
|
+
def sql
|
30
|
+
logger.trace(tag: :sql) { "Composing select statement (Stream: #{stream_name}, Category: #{category_stream?}, Types: #{stream_type_list.inspect}, Position: #{position}, Batch Size: #{batch_size})" }
|
31
|
+
|
32
|
+
statement = <<-SQL
|
33
|
+
SELECT
|
34
|
+
id::varchar,
|
35
|
+
stream_name::varchar,
|
36
|
+
position::int,
|
37
|
+
type::varchar,
|
38
|
+
global_position::bigint,
|
39
|
+
data::varchar,
|
40
|
+
metadata::varchar,
|
41
|
+
time::timestamp
|
42
|
+
FROM
|
43
|
+
events
|
44
|
+
WHERE
|
45
|
+
#{where_clause_field} = '#{stream_name}' AND
|
46
|
+
#{position_field} >= #{position}
|
47
|
+
ORDER BY
|
48
|
+
#{position_field} ASC
|
49
|
+
LIMIT
|
50
|
+
#{batch_size}
|
51
|
+
;
|
52
|
+
SQL
|
53
|
+
|
54
|
+
logger.debug(tag: :sql) { "Composed select statement (Stream: #{stream_name}, Category: #{category_stream?}, Types: #{stream_type_list.inspect}, Position: #{position}, Batch Size: #{batch_size})" }
|
55
|
+
logger.debug(tags: [:data, :sql]) { "Statement: #{statement}" }
|
56
|
+
|
57
|
+
statement
|
58
|
+
end
|
59
|
+
|
60
|
+
def where_clause_field
|
61
|
+
unless category_stream?
|
62
|
+
'stream_name'
|
63
|
+
else
|
64
|
+
'category(stream_name)'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def position_field
|
69
|
+
unless category_stream?
|
70
|
+
'position'
|
71
|
+
else
|
72
|
+
'global_position'
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
module Defaults
|
77
|
+
def self.position
|
78
|
+
0
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.batch_size
|
82
|
+
1000
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
module MessageStore
|
2
|
+
module Postgres
|
3
|
+
class Put
|
4
|
+
include Log::Dependency
|
5
|
+
|
6
|
+
dependency :session, Session
|
7
|
+
dependency :identifier, Session
|
8
|
+
|
9
|
+
def self.build(session: nil)
|
10
|
+
new.tap do |instance|
|
11
|
+
instance.configure(session: session)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def configure(session: nil)
|
16
|
+
Session.configure(self, session: session)
|
17
|
+
Identifier::UUID::Random.configure(self)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.configure(receiver, session: nil, attr_name: nil)
|
21
|
+
attr_name ||= :put
|
22
|
+
instance = build(session: session)
|
23
|
+
receiver.public_send "#{attr_name}=", instance
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.call(write_message, stream_name, expected_version: nil, session: nil)
|
27
|
+
instance = build(session: session)
|
28
|
+
instance.(write_message, stream_name, expected_version: expected_version)
|
29
|
+
end
|
30
|
+
|
31
|
+
def call(write_message, stream_name, expected_version: nil)
|
32
|
+
logger.trace { "Putting message data (Stream Name: #{stream_name}, Type: #{write_message.type}, Expected Version: #{expected_version.inspect})" }
|
33
|
+
logger.trace(tags: [:data, :message_data]) { write_message.pretty_inspect }
|
34
|
+
|
35
|
+
write_message.id ||= identifier.get
|
36
|
+
|
37
|
+
id, type, data, metadata = destructure_message(write_message)
|
38
|
+
expected_version = ExpectedVersion.canonize(expected_version)
|
39
|
+
|
40
|
+
insert_message(id, stream_name, type, data, metadata, expected_version).tap do |position|
|
41
|
+
logger.info { "Put message data (Position: #{position}, Stream Name: #{stream_name}, Type: #{write_message.type}, Expected Version: #{expected_version.inspect}, ID: #{id.inspect})" }
|
42
|
+
logger.info(tags: [:data, :message_data]) { write_message.pretty_inspect }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def destructure_message(write_message)
|
47
|
+
id = write_message.id
|
48
|
+
type = write_message.type
|
49
|
+
data = write_message.data
|
50
|
+
metadata = write_message.metadata
|
51
|
+
|
52
|
+
logger.debug(tags: [:data, :message_data]) { "ID: #{id.pretty_inspect}" }
|
53
|
+
logger.debug(tags: [:data, :message_data]) { "Type: #{type.pretty_inspect}" }
|
54
|
+
logger.debug(tags: [:data, :message_data]) { "Data: #{data.pretty_inspect}" }
|
55
|
+
logger.debug(tags: [:data, :message_data]) { "Metadata: #{metadata.pretty_inspect}" }
|
56
|
+
|
57
|
+
return id, type, data, metadata
|
58
|
+
end
|
59
|
+
|
60
|
+
def insert_message(id, stream_name, type, data, metadata, expected_version)
|
61
|
+
serialized_data = serialized_data(data)
|
62
|
+
serialized_metadata = serialized_metadata(metadata)
|
63
|
+
records = execute_query(id, stream_name, type, serialized_data, serialized_metadata, expected_version)
|
64
|
+
position(records)
|
65
|
+
end
|
66
|
+
|
67
|
+
def execute_query(id, stream_name, type, serialized_data, serialized_metadata, expected_version)
|
68
|
+
logger.trace { "Executing insert (Stream Name: #{stream_name}, Type: #{type}, Expected Version: #{expected_version.inspect}, ID: #{id.inspect})" }
|
69
|
+
|
70
|
+
params = [
|
71
|
+
id,
|
72
|
+
stream_name,
|
73
|
+
type,
|
74
|
+
serialized_data,
|
75
|
+
serialized_metadata,
|
76
|
+
expected_version
|
77
|
+
]
|
78
|
+
|
79
|
+
begin
|
80
|
+
records = session.execute(self.class.statement, params)
|
81
|
+
rescue PG::RaiseException => e
|
82
|
+
raise_error e
|
83
|
+
end
|
84
|
+
|
85
|
+
logger.debug { "Executed insert (Stream Name: #{stream_name}, Type: #{type}, Expected Version: #{expected_version.inspect}, ID: #{id.inspect})" }
|
86
|
+
|
87
|
+
records
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.statement
|
91
|
+
@statement ||= "SELECT write_event($1::varchar, $2::varchar, $3::varchar, $4::jsonb, $5::jsonb, $6::int);"
|
92
|
+
end
|
93
|
+
|
94
|
+
def serialized_data(data)
|
95
|
+
serialized_data = nil
|
96
|
+
|
97
|
+
if data.is_a?(Hash) && data.empty?
|
98
|
+
data = nil
|
99
|
+
end
|
100
|
+
|
101
|
+
unless data.nil?
|
102
|
+
serializable_data = MessageData::Hash[data]
|
103
|
+
serialized_data = Transform::Write.(serializable_data, :json)
|
104
|
+
end
|
105
|
+
|
106
|
+
logger.debug(tags: [:data, :serialize]) { "Serialized Data: #{serialized_data.inspect}" }
|
107
|
+
serialized_data
|
108
|
+
end
|
109
|
+
|
110
|
+
def serialized_metadata(metadata)
|
111
|
+
serialized_metadata = nil
|
112
|
+
|
113
|
+
if metadata.is_a?(Hash) && metadata.empty?
|
114
|
+
metadata = nil
|
115
|
+
end
|
116
|
+
|
117
|
+
unless metadata.nil?
|
118
|
+
serializable_metadata = MessageData::Hash[metadata]
|
119
|
+
serialized_metadata = Transform::Write.(serializable_metadata, :json)
|
120
|
+
end
|
121
|
+
|
122
|
+
logger.debug(tags: [:data, :serialize]) { "Serialized Metadata: #{serialized_metadata.inspect}" }
|
123
|
+
serialized_metadata
|
124
|
+
end
|
125
|
+
|
126
|
+
def position(records)
|
127
|
+
position = nil
|
128
|
+
unless records[0].nil?
|
129
|
+
position = records[0].values[0]
|
130
|
+
end
|
131
|
+
position
|
132
|
+
end
|
133
|
+
|
134
|
+
def raise_error(pg_error)
|
135
|
+
error_message = pg_error.message
|
136
|
+
if error_message.include? 'Wrong expected version'
|
137
|
+
error_message.gsub!('ERROR:', '').strip!
|
138
|
+
logger.error { error_message }
|
139
|
+
raise ExpectedVersion::Error, error_message
|
140
|
+
end
|
141
|
+
raise pg_error
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|