skaidb 1.3.0 → 1.4.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 +14 -0
- data/README.md +7 -4
- data/docs/api.md +4 -1
- data/docs/streaming.md +6 -0
- data/lib/skaidb.rb +45 -22
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f947092b55d66cc8d7c55153cbea09ebcdd0298f48fcb6c97ea0f3a5edd5ac01
|
|
4
|
+
data.tar.gz: 9b472d16803f161f2aa6d4554c19aede65f9a227b79d29c7f015204c04a7bcc7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 68d82f58f409113c18f1536023042343ffbfa86c8ec6029a0f799cd8f88fd038f418ced9c1be77beca7826c7d5756e523de221c6bf798e7069db1e14be7aaf12
|
|
7
|
+
data.tar.gz: f95915e0918b17e31d2b9e63cfbcbe92ee717f07b49075bbd1da055cb49f60f592c346eb579b6c65a8dc855ddf669c41d467086dec90ccb59abc0861c784dacc
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,20 @@ All notable changes to the skaidb Ruby driver. The format follows
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow
|
|
5
5
|
[Semantic Versioning](https://semver.org/).
|
|
6
6
|
|
|
7
|
+
## [1.4.0] - 2026-10-29
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- A streamed `CALL` whose procedure body `EMIT`s result sets returns them.
|
|
11
|
+
The server answers such a call with every set in one `ResultSets` frame
|
|
12
|
+
(tag 8) even to a stream request, and `conn.stream`, with or without
|
|
13
|
+
parameters, raised `QueryError` (`unexpected response tag 8 to stream
|
|
14
|
+
request`) and lost the sets. The frame is now decoded by the code `exec`
|
|
15
|
+
uses: the block receives the rows `exec`'s `Result` would yield (the
|
|
16
|
+
call's final result, the LAST set) and `stream` returns that same `:rows`
|
|
17
|
+
`Result`, every set in order under `result_sets`. Nothing is left in
|
|
18
|
+
flight, so the connection stays usable — the block may even run
|
|
19
|
+
statements on it.
|
|
20
|
+
|
|
7
21
|
## [1.3.0] - 2026-10-29
|
|
8
22
|
|
|
9
23
|
### Added
|
data/README.md
CHANGED
|
@@ -55,13 +55,13 @@ Xcode command-line tools on macOS). `gem install skaidb` and vendoring reuse
|
|
|
55
55
|
the `bigdecimal` already installed.
|
|
56
56
|
|
|
57
57
|
Or vendor the single file: copy
|
|
58
|
-
[`lib/skaidb.rb`](https://github.com/porcupin26/skaidb-ruby/blob/v1.
|
|
58
|
+
[`lib/skaidb.rb`](https://github.com/porcupin26/skaidb-ruby/blob/v1.4.0/lib/skaidb.rb)
|
|
59
59
|
into your project and `require_relative` it. It has no dependencies beyond
|
|
60
60
|
Ruby's standard library.
|
|
61
61
|
|
|
62
62
|
Every release is also attached as a `.gem` to its
|
|
63
63
|
[GitHub release](https://github.com/porcupin26/skaidb-ruby/releases) for
|
|
64
|
-
installs without registry access: `gem install ./skaidb-1.
|
|
64
|
+
installs without registry access: `gem install ./skaidb-1.4.0.gem`.
|
|
65
65
|
|
|
66
66
|
## Quick start
|
|
67
67
|
|
|
@@ -306,7 +306,10 @@ unordered or in storage-key order), and no scan budget applies to a streamed
|
|
|
306
306
|
page (server ≥ 0.330). With a block `stream` returns a `Result` whose `kind`
|
|
307
307
|
is `:stream` and whose `fields` are the column names (the rows went to the
|
|
308
308
|
block); a non-row statement returns its `:mutation` / `:ddl` Result without
|
|
309
|
-
yielding.
|
|
309
|
+
yielding. A `CALL` whose body `EMIT`s result sets is answered with all of
|
|
310
|
+
them in one frame even when streamed: the block receives the rows `exec`
|
|
311
|
+
would return (the last set), and `stream` returns that same `Result`, every
|
|
312
|
+
set under `result_sets`.
|
|
310
313
|
|
|
311
314
|
**The abandon/drain rule.** The connection is busy for the whole stream:
|
|
312
315
|
a statement from another thread waits for it. Leaving the block early —
|
|
@@ -458,7 +461,7 @@ frame after every handshake. It shows up as `client_name = 'ruby'` /
|
|
|
458
461
|
|
|
459
462
|
```sql
|
|
460
463
|
SELECT client_name, client_version FROM drivers;
|
|
461
|
-
-- ruby | 1.
|
|
464
|
+
-- ruby | 1.4.0
|
|
462
465
|
```
|
|
463
466
|
|
|
464
467
|
The server records the row asynchronously, so a `SELECT` immediately after
|
data/docs/api.md
CHANGED
|
@@ -67,7 +67,10 @@ Raises `Skaidb::Error` before dialing for an unknown `auth_mechanism`, a
|
|
|
67
67
|
`ArgumentError`. For a row stream the returned Result has
|
|
68
68
|
`kind == :stream`, the column names in `fields` and no `rows` (they went to
|
|
69
69
|
the block); a statement without rows returns its `:mutation` / `:ddl`
|
|
70
|
-
Result without yielding
|
|
70
|
+
Result without yielding; a `CALL` whose body `EMIT`s result sets (answered
|
|
71
|
+
in one frame even when streamed) yields the rows `exec` would return (the
|
|
72
|
+
last set) and returns that same `:rows` Result, every set under
|
|
73
|
+
`result_sets`. Without a block returns an Enumerator.
|
|
71
74
|
- `subscribe(stream_name, after: nil, poll: 0.5) { |event| … }` — yields a
|
|
72
75
|
`CREATE STREAM` log's events forever, each a Hash with `"id"`, `"op"`,
|
|
73
76
|
`"k"`, `"ts"`, `"doc"`. Polls `_stream_<name>` 500 rows at a time with a
|
data/docs/streaming.md
CHANGED
|
@@ -28,6 +28,12 @@ end
|
|
|
28
28
|
- A non-row statement (an `INSERT`, DDL, `USE`) answers with its ordinary
|
|
29
29
|
result over the same opcode; `stream` returns that Result (`kind`
|
|
30
30
|
`:mutation` with `cmd_tuples`, or `:ddl`) without yielding.
|
|
31
|
+
- A `CALL` whose procedure body `EMIT`s result sets answers with all of them
|
|
32
|
+
in one frame, as it does to `exec`: the block receives the rows `exec`
|
|
33
|
+
would return (the call's final result, the last set) and `stream` returns
|
|
34
|
+
that same `:rows` Result, every set in order under `result_sets`. Nothing
|
|
35
|
+
is left in flight, so the connection is free again before the first row
|
|
36
|
+
reaches the block.
|
|
31
37
|
- A server without the streaming opcode raises `Skaidb::QueryError`
|
|
32
38
|
(`server does not support streaming: …`).
|
|
33
39
|
|
data/lib/skaidb.rb
CHANGED
|
@@ -35,7 +35,7 @@ require "bigdecimal"
|
|
|
35
35
|
module Skaidb
|
|
36
36
|
# The package version — the single source of truth. The gemspec reads it,
|
|
37
37
|
# and it is what the driver reports to the server in the Hello frame.
|
|
38
|
-
VERSION = "1.
|
|
38
|
+
VERSION = "1.4.0"
|
|
39
39
|
|
|
40
40
|
# Base class for every error raised by this driver.
|
|
41
41
|
class Error < StandardError; end
|
|
@@ -973,7 +973,12 @@ module Skaidb
|
|
|
973
973
|
# +kind+ is +:stream+ and +fields+ holds the column names (known even when
|
|
974
974
|
# no row arrived) while +rows+ stays empty — the rows went to the block;
|
|
975
975
|
# a statement that produces no rows returns its ordinary +:mutation+ or
|
|
976
|
-
# +:ddl+ Result without yielding.
|
|
976
|
+
# +:ddl+ Result without yielding. A CALL whose body EMITs result sets is
|
|
977
|
+
# answered with all of them in one frame, streamed or not: the block
|
|
978
|
+
# receives the rows exec's Result would yield (the call's final result,
|
|
979
|
+
# the LAST set) and the return value is that same +:rows+ Result, every
|
|
980
|
+
# set under +result_sets+ — with nothing left in flight, so the block may
|
|
981
|
+
# use the connection.
|
|
977
982
|
def stream(sql, params = [], consistency: nil)
|
|
978
983
|
return enum_for(:stream, sql, params, consistency: consistency) unless block_given?
|
|
979
984
|
raise ConnectionError, "connection is closed" if @closed
|
|
@@ -991,6 +996,7 @@ module Skaidb
|
|
|
991
996
|
|
|
992
997
|
live = false
|
|
993
998
|
summary = nil
|
|
999
|
+
sets = nil
|
|
994
1000
|
@mutex.synchronize do
|
|
995
1001
|
started = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
996
1002
|
begin
|
|
@@ -1015,6 +1021,12 @@ module Skaidb
|
|
|
1015
1021
|
return Result.new(fields: [], rows: [], cmd_tuples: r.u64, kind: :mutation) # not row-producing
|
|
1016
1022
|
when 2
|
|
1017
1023
|
return Result.new(fields: [], rows: [], cmd_tuples: 0, kind: :ddl)
|
|
1024
|
+
when 8
|
|
1025
|
+
# ResultSets: a CALL whose body EMITted is answered with every set
|
|
1026
|
+
# in ONE frame, streamed or not — the frame exec receives, decoded
|
|
1027
|
+
# by the same code. Nothing follows it, so the rows are yielded
|
|
1028
|
+
# below, with the connection free.
|
|
1029
|
+
sets = parse_result_sets(r)
|
|
1018
1030
|
when 5
|
|
1019
1031
|
# The server has already committed to a row stream, so from here
|
|
1020
1032
|
# the socket carries frames this call owns — mark it BEFORE
|
|
@@ -1065,6 +1077,12 @@ module Skaidb
|
|
|
1065
1077
|
raise QueryError, "unexpected response tag #{tag} to stream request"
|
|
1066
1078
|
end
|
|
1067
1079
|
end
|
|
1080
|
+
if sets
|
|
1081
|
+
# What exec's Result yields (the call's final result, the LAST set),
|
|
1082
|
+
# and that same Result back, every set under +result_sets+.
|
|
1083
|
+
sets.each { |row| yield row }
|
|
1084
|
+
return sets
|
|
1085
|
+
end
|
|
1068
1086
|
summary
|
|
1069
1087
|
end
|
|
1070
1088
|
|
|
@@ -1388,27 +1406,9 @@ module Skaidb
|
|
|
1388
1406
|
tag = r.u8
|
|
1389
1407
|
case tag
|
|
1390
1408
|
when 0 # Rows
|
|
1391
|
-
|
|
1392
|
-
columns = Array.new(ncols) { r.text }
|
|
1393
|
-
nrows = r.u32
|
|
1394
|
-
rows = Array.new(nrows) do
|
|
1395
|
-
ncells = r.u32
|
|
1396
|
-
Array.new(ncells) { Skaidb.decode_value(Reader.new(r.blob)) }
|
|
1397
|
-
end
|
|
1398
|
-
Result.new(fields: columns, rows: rows, cmd_tuples: 0)
|
|
1409
|
+
parse_rows(r)
|
|
1399
1410
|
when 8 # ResultSets: a CALL whose body EMITted
|
|
1400
|
-
|
|
1401
|
-
ncols = r.u32
|
|
1402
|
-
columns = Array.new(ncols) { r.text }
|
|
1403
|
-
nrows = r.u32
|
|
1404
|
-
rows = Array.new(nrows) do
|
|
1405
|
-
ncells = r.u32
|
|
1406
|
-
Array.new(ncells) { Skaidb.decode_value(Reader.new(r.blob)) }
|
|
1407
|
-
end
|
|
1408
|
-
Result.new(fields: columns, rows: rows, cmd_tuples: 0)
|
|
1409
|
-
end
|
|
1410
|
-
last = sets.last || Result.new(fields: [], rows: [], cmd_tuples: 0)
|
|
1411
|
-
Result.new(fields: last.fields, rows: last.rows, cmd_tuples: 0, result_sets: sets)
|
|
1411
|
+
parse_result_sets(r)
|
|
1412
1412
|
when 1 # Mutation
|
|
1413
1413
|
Result.new(fields: [], rows: [], cmd_tuples: r.u64, kind: :mutation)
|
|
1414
1414
|
when 2 # Ddl
|
|
@@ -1419,6 +1419,29 @@ module Skaidb
|
|
|
1419
1419
|
raise ConnectionError, "unknown response tag #{tag}"
|
|
1420
1420
|
end
|
|
1421
1421
|
end
|
|
1422
|
+
|
|
1423
|
+
# A Rows body (PROTOCOL.md §3.2), also one set of ResultSets; +r+ sits
|
|
1424
|
+
# just past the tag.
|
|
1425
|
+
def parse_rows(r)
|
|
1426
|
+
ncols = r.u32
|
|
1427
|
+
columns = Array.new(ncols) { r.text }
|
|
1428
|
+
nrows = r.u32
|
|
1429
|
+
rows = Array.new(nrows) do
|
|
1430
|
+
ncells = r.u32
|
|
1431
|
+
Array.new(ncells) { Skaidb.decode_value(Reader.new(r.blob)) }
|
|
1432
|
+
end
|
|
1433
|
+
Result.new(fields: columns, rows: rows, cmd_tuples: 0)
|
|
1434
|
+
end
|
|
1435
|
+
|
|
1436
|
+
# A ResultSets body (a CALL whose body EMITted), +r+ just past the tag:
|
|
1437
|
+
# the LAST set is the Result's own rows, every set is under
|
|
1438
|
+
# +result_sets+. The buffered path and a stream request both receive
|
|
1439
|
+
# this frame, and both decode it here.
|
|
1440
|
+
def parse_result_sets(r)
|
|
1441
|
+
sets = Array.new(r.u32) { parse_rows(r) }
|
|
1442
|
+
last = sets.last || Result.new(fields: [], rows: [], cmd_tuples: 0)
|
|
1443
|
+
Result.new(fields: last.fields, rows: last.rows, cmd_tuples: 0, result_sets: sets)
|
|
1444
|
+
end
|
|
1422
1445
|
end
|
|
1423
1446
|
|
|
1424
1447
|
# ---- module entry point --------------------------------------------------
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: skaidb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- skaidb contributors
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-30 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bigdecimal
|