pgmq-ruby 0.8.2 → 0.9.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/CHANGELOG.md +34 -1
- data/README.md +5 -6
- data/lib/pgmq/client/producer.rb +1 -9
- data/lib/pgmq/client/topics.rb +7 -2
- data/lib/pgmq/client.rb +22 -0
- data/lib/pgmq/connection.rb +40 -8
- data/lib/pgmq/contractable/contract.rb +12 -9
- data/lib/pgmq/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 79570c7c6e4591584c43e16f99064d7d249148601a74d8ff853791511d9d87ee
|
|
4
|
+
data.tar.gz: 235af4a2895ffb1dd3a3b29b2e2f7448b8c0e32899af3a62d7f30fc9c7277d50
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9483f8855343ad8a5a9292d76544726624380bef0d14dcfe8321ade758ebb32d71543a28a87176ffe323a4577bc0d1c2a9407510d1bf6bd5e41d360ec416aedd
|
|
7
|
+
data.tar.gz: 8a09f3994b147dece5c30e449362331337e89e0fbe0315b18b727552b234a5de2f7c74a48fd0329ff9b650d9c0ddc27080a89b4910d807d61b83afbe000421d9
|
data/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,45 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.9.0 (2026-11-10)
|
|
4
|
+
|
|
5
|
+
### Producer
|
|
6
|
+
- **[Breaking]** `produce_topic` and `produce_batch_topic` raise `PGMQ::Errors::MessageInvalidError` when a message is
|
|
7
|
+
not a String or its headers are neither a String nor `nil`, like `produce` and `produce_batch`. Most such calls
|
|
8
|
+
succeeded before and now raise: non-String messages and headers were stored as JSON (Integer, Float, `true`, `false`
|
|
9
|
+
and Array values) or as NULL (a `nil` message; Hash headers in `produce_topic` with an integer delay), and
|
|
10
|
+
`produce_topic` with an integer delay dropped `false` headers. The other `nil` and Hash cases raised
|
|
11
|
+
`PGMQ::Errors::ConnectionError`.
|
|
12
|
+
|
|
13
|
+
### Validation
|
|
14
|
+
- **[Change]** A contract check allocates its errors Array on the first error only, so valid input allocates one
|
|
15
|
+
object less per validated message in `produce`, `produce_batch`, `produce_topic` and `produce_batch_topic`.
|
|
16
|
+
Until then a `PGMQ::Contractable::Contract` rule gets a frozen empty `errors` Array: a custom rule that appends to it
|
|
17
|
+
raises `FrozenError`.
|
|
18
|
+
|
|
19
|
+
### Connection Management
|
|
20
|
+
- **[Fix]** `PGMQ::Connection#verify_connection!` resets a pooled connection whose status is anything other than
|
|
21
|
+
`PG::CONNECTION_OK` (#217). It reset only `CONNECTION_BAD` before, so a connection left in an intermediate state
|
|
22
|
+
(`CONNECTION_STARTED`, `CONNECTION_MADE`, ...) by a reset or connect interrupted before it completed (a
|
|
23
|
+
`Thread#raise` during `PG::Connection#reset`, a `reset_start` never polled to completion) passed the health check,
|
|
24
|
+
and every call on it, the `auto_reconnect` retry included, raised `PGMQ::Errors::ConnectionError` (`PG::UnableToSend:
|
|
25
|
+
no connection to the server`) until `reload` or a process restart. The next checkout now resets it.
|
|
26
|
+
- **[Fix]** `PGMQ::Connection#with_connection` resets a pooled connection when the block raises `PG::ConnectionBad`
|
|
27
|
+
or `PG::UnableToSend`, before the connection goes back to the pool. A connection can pass the checkout health check
|
|
28
|
+
and still fail on the next send; it went back to the pool broken, and with `auto_reconnect: false` (or when it still
|
|
29
|
+
reported `PG::CONNECTION_OK`) every later checkout failed the same way until `reload`. The caller still gets
|
|
30
|
+
`PGMQ::Errors::ConnectionError`. When the reset fails too, the connection is closed: with `auto_reconnect` the next
|
|
31
|
+
checkout resets it; without it, the next operation on it fails once and that failure resets it. Connections returned
|
|
32
|
+
by a callable (e.g. ActiveRecord's raw connection) are not reset or closed.
|
|
33
|
+
|
|
3
34
|
## 0.8.2 (2026-11-02)
|
|
4
35
|
|
|
5
36
|
### Queue Naming
|
|
6
37
|
- **[Fix]** The `InvalidQueueNameError` message for a too-long queue name states the real limit: "exceeds maximum
|
|
7
38
|
length of 47 characters" (was 48; a 48-character name was already rejected). The README now gives 47 as the maximum
|
|
8
39
|
and no longer calls queue names case-sensitive: names differing only in case share one table (PGMQ lower-cases
|
|
9
|
-
table names) but get separate `pgmq.meta` rows, so use one spelling per queue
|
|
40
|
+
table names) but get separate `pgmq.meta` rows, so use one spelling per queue.
|
|
41
|
+
|
|
42
|
+
### Documentation
|
|
10
43
|
- **[Fix]** The README `wait_for_notify` example said the call returns the notification payload; it returns the
|
|
11
44
|
channel name (`nil` on timeout).
|
|
12
45
|
|
data/README.md
CHANGED
|
@@ -93,7 +93,6 @@ This gem provides complete support for all core PGMQ SQL functions. Based on the
|
|
|
93
93
|
| | Consumer | Minimal single-threaded `PGMQ::Consumer` loop over one or more queues with ack on success | ✅ |
|
|
94
94
|
| | Queue Validation | 47-character limit and name validation | ✅ |
|
|
95
95
|
| | Connection Pooling | Thread-safe connection pool for concurrency | ✅ |
|
|
96
|
-
| | Pluggable Serializers | JSON (default) with custom serializer support | ✅ |
|
|
97
96
|
|
|
98
97
|
## Requirements
|
|
99
98
|
|
|
@@ -308,6 +307,9 @@ Every PGMQ operation checks out a pooled connection through `client.with_connect
|
|
|
308
307
|
The method is public, so you can run PostgreSQL statements PGMQ does not wrap
|
|
309
308
|
without standing up a second connection pool. The connection is health-checked
|
|
310
309
|
(when `auto_reconnect` is enabled) and returned to the pool when the block exits.
|
|
310
|
+
If the block raises `PG::ConnectionBad` or `PG::UnableToSend`, the connection is
|
|
311
|
+
reset before it goes back to the pool (connections from a callable are left as
|
|
312
|
+
they are); you still get `PGMQ::Errors::ConnectionError`.
|
|
311
313
|
|
|
312
314
|
```ruby
|
|
313
315
|
# Fire a custom NOTIFY alongside your queues
|
|
@@ -1230,8 +1232,8 @@ end
|
|
|
1230
1232
|
|
|
1231
1233
|
Invalid arguments are rejected by a contract before they reach PostgreSQL, with a validation error:
|
|
1232
1234
|
|
|
1233
|
-
- `PGMQ::Errors::MessageInvalidError` from `produce`, `produce_batch` and `produce_batch_topic`, for
|
|
1234
|
-
message is not a String or its headers are neither a String nor `nil`
|
|
1235
|
+
- `PGMQ::Errors::MessageInvalidError` from `produce`, `produce_batch`, `produce_topic` and `produce_batch_topic`, for
|
|
1236
|
+
example when a message is not a String or its headers are neither a String nor `nil`
|
|
1235
1237
|
- `PGMQ::Errors::MultiQueueInvalidError` from the multi-queue operations (`read_multi`, `read_multi_with_poll`,
|
|
1236
1238
|
`pop_multi`, `delete_multi`, `archive_multi`, `set_vt_multi`)
|
|
1237
1239
|
- `PGMQ::Errors::AutovacuumSettingsInvalidError` from `tune_autovacuum` for an unknown storage parameter or a
|
|
@@ -1268,9 +1270,6 @@ bin/integrations
|
|
|
1268
1270
|
|
|
1269
1271
|
# Run a specific integration spec
|
|
1270
1272
|
bin/integrations spec/integration/basic_produce_consume_spec.rb
|
|
1271
|
-
|
|
1272
|
-
# Run console
|
|
1273
|
-
bundle exec bin/console
|
|
1274
1273
|
```
|
|
1275
1274
|
|
|
1276
1275
|
## Author
|
data/lib/pgmq/client/producer.rb
CHANGED
|
@@ -103,17 +103,9 @@ module PGMQ
|
|
|
103
103
|
delay: 0
|
|
104
104
|
)
|
|
105
105
|
validate_queue_name!(queue_name)
|
|
106
|
-
|
|
106
|
+
validate_messages!(messages, headers)
|
|
107
107
|
return [] if messages.empty?
|
|
108
108
|
|
|
109
|
-
messages.each_with_index do |message, index|
|
|
110
|
-
MESSAGE_CONTRACT.validate!(
|
|
111
|
-
{ message: message, headers: headers && headers[index] },
|
|
112
|
-
Errors::MessageInvalidError,
|
|
113
|
-
scope: ["messages", index]
|
|
114
|
-
)
|
|
115
|
-
end
|
|
116
|
-
|
|
117
109
|
result = with_connection do |conn|
|
|
118
110
|
encoder = PG::TextEncoder::Array.new
|
|
119
111
|
encoded_messages = encoder.encode(messages)
|
data/lib/pgmq/client/topics.rb
CHANGED
|
@@ -73,6 +73,8 @@ module PGMQ
|
|
|
73
73
|
# @param delay [Numeric, ActiveSupport::Duration] delay in seconds before message becomes visible (integer,
|
|
74
74
|
# float or Duration; a float such as 1.5 needs PGMQ v1.10.0+)
|
|
75
75
|
# @return [Integer] count of queues the message was delivered to
|
|
76
|
+
# @raise [PGMQ::Errors::MessageInvalidError] if message is not a String, or headers is neither a String nor
|
|
77
|
+
# nil
|
|
76
78
|
#
|
|
77
79
|
# @example Basic topic send
|
|
78
80
|
# count = client.produce_topic("orders.new", '{"order_id":123}')
|
|
@@ -83,6 +85,8 @@ module PGMQ
|
|
|
83
85
|
# headers: '{"trace_id":"abc"}',
|
|
84
86
|
# delay: 30)
|
|
85
87
|
def produce_topic(routing_key, message, headers: nil, delay: 0)
|
|
88
|
+
MESSAGE_CONTRACT.validate!({ message: message, headers: headers }, Errors::MessageInvalidError)
|
|
89
|
+
|
|
86
90
|
# send_topic takes whole seconds only, so a fractional delay goes through send_batch_topic
|
|
87
91
|
if delay.is_a?(Numeric) && !delay.integer?
|
|
88
92
|
return produce_batch_topic(routing_key, [message], headers: headers && [headers], delay: delay).size
|
|
@@ -122,7 +126,8 @@ module PGMQ
|
|
|
122
126
|
# become visible, including ActiveSupport::TimeWithZone (PGMQ v1.10.0+)
|
|
123
127
|
# @return [Array<Hash>] array of hashes with :queue_name and :msg_id
|
|
124
128
|
# @raise [PGMQ::Errors::MessageInvalidError] if messages is not an Array, headers is neither an Array nor nil,
|
|
125
|
-
#
|
|
129
|
+
# headers length doesn't match messages length, a message is not a String, or a header is neither a String
|
|
130
|
+
# nor nil
|
|
126
131
|
#
|
|
127
132
|
# @example Batch topic send
|
|
128
133
|
# results = client.produce_batch_topic("orders.new", [
|
|
@@ -131,7 +136,7 @@ module PGMQ
|
|
|
131
136
|
# ])
|
|
132
137
|
# # => [{ queue_name: "new_orders", msg_id: "1" }, ...]
|
|
133
138
|
def produce_batch_topic(routing_key, messages, headers: nil, delay: 0)
|
|
134
|
-
|
|
139
|
+
validate_messages!(messages, headers)
|
|
135
140
|
return [] if messages.empty?
|
|
136
141
|
|
|
137
142
|
result = with_connection do |conn|
|
data/lib/pgmq/client.rb
CHANGED
|
@@ -173,6 +173,28 @@ module PGMQ
|
|
|
173
173
|
nil
|
|
174
174
|
end
|
|
175
175
|
|
|
176
|
+
# Validates a batch of messages and their headers before they are bound
|
|
177
|
+
#
|
|
178
|
+
# @param messages [Array<String>] message payloads as JSON strings
|
|
179
|
+
# @param headers [Array<String, nil>, nil] headers as JSON strings, one per message
|
|
180
|
+
# @return [void]
|
|
181
|
+
# @raise [PGMQ::Errors::MessageInvalidError] if messages is not an Array, headers is neither an Array nor nil,
|
|
182
|
+
# headers length doesn't match messages length, a message is not a String, or a header is neither a String nor
|
|
183
|
+
# nil
|
|
184
|
+
def validate_messages!(messages, headers)
|
|
185
|
+
BATCH_CONTRACT.validate!({ messages: messages, headers: headers }, Errors::MessageInvalidError)
|
|
186
|
+
|
|
187
|
+
messages.each_with_index do |message, index|
|
|
188
|
+
MESSAGE_CONTRACT.validate!(
|
|
189
|
+
{ message: message, headers: headers && headers[index] },
|
|
190
|
+
Errors::MessageInvalidError,
|
|
191
|
+
scope: ["messages", index]
|
|
192
|
+
)
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
nil
|
|
196
|
+
end
|
|
197
|
+
|
|
176
198
|
# Builds the SQL argument and bind value for a +delay:+ given in seconds or as an absolute Time
|
|
177
199
|
#
|
|
178
200
|
# PostgreSQL rejects a Float such as +1.5+ for an +integer+ bind, so a non-Integer Numeric is passed to the
|
data/lib/pgmq/connection.rb
CHANGED
|
@@ -116,11 +116,17 @@ module PGMQ
|
|
|
116
116
|
@pool_size = pool_size
|
|
117
117
|
@pool_timeout = pool_timeout
|
|
118
118
|
@auto_reconnect = auto_reconnect
|
|
119
|
+
# A callable hands us connections it may share with its owner (e.g. ActiveRecord's raw connection), so we never
|
|
120
|
+
# reset or close them after a failure; only connections we open ourselves are reset.
|
|
121
|
+
@owns_connections = !conn_params.respond_to?(:call)
|
|
119
122
|
@pool = create_pool
|
|
120
123
|
end
|
|
121
124
|
|
|
122
125
|
# Executes a block with a connection from the pool
|
|
123
126
|
#
|
|
127
|
+
# When the block raises `PG::ConnectionBad` or `PG::UnableToSend`, the connection is reset before it goes back to
|
|
128
|
+
# the pool, so the next checkout gets a working one. Connections from a callable are left as they are.
|
|
129
|
+
#
|
|
124
130
|
# @yield [PG::Connection] database connection
|
|
125
131
|
# @return [Object] result of the block
|
|
126
132
|
# @raise [PGMQ::Errors::ConnectionError] if the block raises any `PG::Error` (the original is in `#cause`), or a
|
|
@@ -134,7 +140,12 @@ module PGMQ
|
|
|
134
140
|
# Health check: verify connection is alive
|
|
135
141
|
verify_connection!(conn) if @auto_reconnect
|
|
136
142
|
|
|
137
|
-
|
|
143
|
+
begin
|
|
144
|
+
yield conn
|
|
145
|
+
rescue *LOST_CONNECTION_ERRORS
|
|
146
|
+
reset_lost_connection(conn) if @owns_connections
|
|
147
|
+
raise
|
|
148
|
+
end
|
|
138
149
|
end
|
|
139
150
|
rescue PG::Error => e
|
|
140
151
|
attempts += 1
|
|
@@ -161,8 +172,8 @@ module PGMQ
|
|
|
161
172
|
#
|
|
162
173
|
# Use this to recover from a connection that libpq still reports as +CONNECTION_OK+ but which is in fact wedged -
|
|
163
174
|
# e.g. after a wall-clock timeout (+Timeout.timeout+) interrupted a query mid-flight, leaving the socket poisoned so
|
|
164
|
-
# it re-hangs on reuse. {#verify_connection!} cannot catch that case (the connection
|
|
165
|
-
# +
|
|
175
|
+
# it re-hangs on reuse. {#verify_connection!} cannot catch that case (the connection still reports
|
|
176
|
+
# +CONNECTION_OK+), so the caller must discard it explicitly; +reload+ is the safe, pool-wide way to do so.
|
|
166
177
|
#
|
|
167
178
|
# @return [void]
|
|
168
179
|
# @example Discard the pool after a query had to be force-interrupted
|
|
@@ -191,6 +202,10 @@ module PGMQ
|
|
|
191
202
|
|
|
192
203
|
private
|
|
193
204
|
|
|
205
|
+
# libpq's dedicated connection-failure classes. A pooled connection that raises one of them mid-operation is reset.
|
|
206
|
+
LOST_CONNECTION_ERRORS = [PG::ConnectionBad, PG::UnableToSend].freeze
|
|
207
|
+
private_constant :LOST_CONNECTION_ERRORS
|
|
208
|
+
|
|
194
209
|
# Messages libpq raises when the server/pooler has already torn down the socket. The list has grown organically with
|
|
195
210
|
# each pooler/TLS variant we see in the wild; the class check below catches future variants that libpq raises as
|
|
196
211
|
# `PG::ConnectionBad` or `PG::UnableToSend` without waiting for a new message to hit production.
|
|
@@ -220,7 +235,7 @@ module PGMQ
|
|
|
220
235
|
# @return [Boolean] true if the connection was lost and a retry on a
|
|
221
236
|
# fresh connection is appropriate
|
|
222
237
|
def connection_lost_error?(error)
|
|
223
|
-
return true if
|
|
238
|
+
return true if LOST_CONNECTION_ERRORS.any? { |klass| error.is_a?(klass) }
|
|
224
239
|
|
|
225
240
|
extra_classes = self.class.reconnectable_error_classes
|
|
226
241
|
return true if extra_classes.any? { |klass| error.is_a?(klass) }
|
|
@@ -240,19 +255,36 @@ module PGMQ
|
|
|
240
255
|
|
|
241
256
|
# Verifies a connection is alive and working.
|
|
242
257
|
#
|
|
243
|
-
# Also resets when the connection reports `PG::CONNECTION_BAD
|
|
244
|
-
# pooler such as PgBouncer)
|
|
245
|
-
#
|
|
258
|
+
# Also resets when the connection reports any status other than `PG::CONNECTION_OK`: `CONNECTION_BAD` when the
|
|
259
|
+
# server (or an intermediate pooler such as PgBouncer) closed the socket while the client-side `PG::Connection`
|
|
260
|
+
# object still exists, and an intermediate state (`CONNECTION_STARTED`, `CONNECTION_MADE`, ...) when a previous
|
|
261
|
+
# reset or connect was interrupted before it completed. libpq refuses to send on either. `#finished?` alone only
|
|
262
|
+
# catches connections closed explicitly from the client side.
|
|
246
263
|
#
|
|
247
264
|
# @param conn [PG::Connection] connection to verify
|
|
248
265
|
# @raise [PG::Error] if the reset itself fails
|
|
249
266
|
def verify_connection!(conn)
|
|
250
267
|
return conn.reset if conn.finished?
|
|
251
|
-
return conn.reset
|
|
268
|
+
return conn.reset unless conn.status == PG::CONNECTION_OK
|
|
252
269
|
|
|
253
270
|
nil
|
|
254
271
|
end
|
|
255
272
|
|
|
273
|
+
# Resets a connection that failed mid-operation so it does not go back to the pool broken. A connection can pass
|
|
274
|
+
# {#verify_connection!} at checkout (`CONNECTION_OK`) and still fail on the next send.
|
|
275
|
+
#
|
|
276
|
+
# A failing reset must not replace the error the caller sees, so it is swallowed and the connection is closed
|
|
277
|
+
# instead. With `auto_reconnect`, the next checkout sees it as `finished?` and resets it. Without it, the next
|
|
278
|
+
# operation on it fails with `PG::ConnectionBad` ("connection is closed"), and that failure resets it.
|
|
279
|
+
#
|
|
280
|
+
# @param conn [PG::Connection] connection the failed operation used
|
|
281
|
+
# @return [void]
|
|
282
|
+
def reset_lost_connection(conn)
|
|
283
|
+
conn.reset
|
|
284
|
+
rescue
|
|
285
|
+
conn.close unless conn.finished?
|
|
286
|
+
end
|
|
287
|
+
|
|
256
288
|
# Normalizes various connection parameter formats
|
|
257
289
|
# @param params [String, Hash, Proc]
|
|
258
290
|
# @return [Hash, Proc]
|
|
@@ -21,7 +21,8 @@ module PGMQ
|
|
|
21
21
|
DIG_MISS = Object.new
|
|
22
22
|
|
|
23
23
|
# Empty array for scope default to avoid allocating a new Array on each `#call` / `#validate!` invocation. Safe
|
|
24
|
-
# because scope is never mutated - it is only used in `scope + rule.path` which creates a new Array.
|
|
24
|
+
# because scope is never mutated - it is only used in `scope + rule.path` which creates a new Array. Also passed
|
|
25
|
+
# to validators as `errors` until the first error.
|
|
25
26
|
EMPTY_ARRAY = [].freeze
|
|
26
27
|
|
|
27
28
|
private_constant :DIG_MISS, :EMPTY_ARRAY
|
|
@@ -77,7 +78,7 @@ module PGMQ
|
|
|
77
78
|
#
|
|
78
79
|
# @param block [Proc] validation rule, called with `(data, errors, contract)`. It must return either a
|
|
79
80
|
# non-Array (`true`/`nil`/`false`) for "no errors", or an `Array` of `[path, message]` error pairs (where
|
|
80
|
-
# `path` is itself an `Array` of symbols).
|
|
81
|
+
# `path` is itself an `Array` of symbols). `errors` holds the errors found so far and must not be mutated.
|
|
81
82
|
#
|
|
82
83
|
# @note The returned error `Array` is owned by the contract: `#call` prepends the current scope onto each pair
|
|
83
84
|
# in place and collects them, so a rule must return a freshly built `Array` on every call.
|
|
@@ -102,39 +103,41 @@ module PGMQ
|
|
|
102
103
|
# needed if contract starts from root
|
|
103
104
|
# @return [Result] validation result
|
|
104
105
|
def call(data, scope: EMPTY_ARRAY)
|
|
105
|
-
|
|
106
|
+
# Allocated on the first error, so valid data allocates no Array
|
|
107
|
+
errors = nil
|
|
106
108
|
|
|
107
109
|
# A non-Hash root has no keys to dig, so every required rule reports missing
|
|
108
110
|
data_is_hash = data.is_a?(Hash)
|
|
109
111
|
|
|
110
112
|
self.class.rules.each do |rule|
|
|
111
113
|
if rule.type == :virtual
|
|
112
|
-
result = rule.validator.call(data, errors, self)
|
|
114
|
+
result = rule.validator.call(data, errors || EMPTY_ARRAY, self)
|
|
113
115
|
|
|
114
116
|
# Any non-Array result (true, but also nil/false) means "no errors"
|
|
115
117
|
next unless result.is_a?(Array)
|
|
118
|
+
next if result.empty?
|
|
116
119
|
|
|
117
120
|
result.each do |sub_result|
|
|
118
121
|
sub_result[0] = scope + sub_result[0]
|
|
119
122
|
end
|
|
120
123
|
|
|
121
|
-
errors.push(*result)
|
|
124
|
+
(errors ||= []).push(*result)
|
|
122
125
|
else
|
|
123
126
|
for_checking = data_is_hash ? dig(data, rule.path) : DIG_MISS
|
|
124
127
|
|
|
125
128
|
if DIG_MISS.equal?(for_checking)
|
|
126
|
-
errors << [scope + rule.path, :missing] if rule.type == :required
|
|
129
|
+
(errors ||= []) << [scope + rule.path, :missing] if rule.type == :required
|
|
127
130
|
else
|
|
128
|
-
result = rule.validator.call(for_checking, data, errors, self)
|
|
131
|
+
result = rule.validator.call(for_checking, data, errors || EMPTY_ARRAY, self)
|
|
129
132
|
|
|
130
133
|
next if result == true
|
|
131
134
|
|
|
132
|
-
errors << [scope + rule.path, result || :format]
|
|
135
|
+
(errors ||= []) << [scope + rule.path, result || :format]
|
|
133
136
|
end
|
|
134
137
|
end
|
|
135
138
|
end
|
|
136
139
|
|
|
137
|
-
return Result.success
|
|
140
|
+
return Result.success unless errors
|
|
138
141
|
|
|
139
142
|
Result.new(errors, self)
|
|
140
143
|
end
|
data/lib/pgmq/version.rb
CHANGED