Repository navigation
Add TS.NRANGE / TS.NREVRANGE support - #98
Conversation
Implements TS.NRANGE and TS.NREVRANGE (Redis 8.10+), which query an explicit list of keys and group results by timestamp rather than by key. Adds RsTsNAggregation (per-key AGGREGATION lists sharing one bucketDuration) and RsTsNRangeRow, and refactors RsTsAggregation to expose aggregatorsString for reuse. Both commands share a single private executor in RsRedisEndpoint, mirroring the existing TS.MRANGE/TS.MREVRANGE pattern. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
| nAgg bucketDuration: 1000 ]. | ||
|
|
||
| self assert: result notEmpty. | ||
| self assert: result first values size equals: 3 |
There was a problem hiding this comment.
Optional: This is the crucible test for the novel AGGREGATION per-key contract, but it only asserts the value count (3), not that aggregators mapped to the right keys or produced the right numbers. Give the data (key1: 10,20 → avg 15; key2: 100,200 → min 100, max 200), it would pass even if the aggregator→key mapping or the shared bucketDuration were wrong. Suggest asserting exact values, e.g. self assertCollection: result first values equals: #(15 100 200). That locks the "first agg-list↔first key, second↔second key" ordering, which is the most error-prone part of the wire format.
There was a problem hiding this comment.
Fixed in f3a949e — now asserts exact values #(15 100 200) instead of just the count.
|
|
||
| self assert: result second timestamp equals: 2000. | ||
| self assert: result second values size equals: 2. | ||
| self assert: result second values first equals: 30 |
There was a problem hiding this comment.
FYI / Optional: At timestamp 2000, key2 has no sample. Redis reports that as NaN; through the reused tsParseValue: it surfaces to callers as the string 'NaN' (the package convention of returning unparseable values as raw strings, same as single-key TS.RANGE). This test checks result second values first (key1=30) but not the missing slot, so the representation is not pinned. Consider asserting it (e.g. 'NaN') so consumers know what a missing value looks like rather than a Smalltalk Float.
There was a problem hiding this comment.
Fixed in f3a949e — the missing slot is actually a Smalltalk Float nan (not a string), since tsParseValue: parses the wire value via NumberParser. Now asserted with isNaN.
| @@ -0,0 +1,47 @@ | |||
| Class { | |||
There was a problem hiding this comment.
Nit / Consider: RsTsNAggregation is a surface-area-heavy class with no class comment, and the N prefix is only meaningful to someone who already knows it stands for the TS.NRANGE/TS.NREVRANGE family (note the asymmetry vs. RsTsRangeOptions, which is reused here rather than duplicated). A short comment documenting the contract would help a lot: one RsTsAggregation per key in key order, comma-joined multi-aggregator lists allowed per key, one shared bucketDuration, and that asArray deliberately bypasses the single-aggregator check (via aggregatorsString) because per-key multi-aggregators are legal here.
There was a problem hiding this comment.
Fixed in f3a949e — added a CRC-style class comment documenting the per-key AGGREGATION contract (one RsTsAggregation per key in order, shared bucketDuration, and why asArray uses aggregatorsString to bypass the single-aggregator check).
mumez
left a comment
There was a problem hiding this comment.
Verdict: Approve — well-scoped, correctly-verified implementation; all findings below are Optional/FYI/Nit and non-blocking.
What I verified
- Wire grammar (highest-leverage check): compared
tsNRangeArgsFor:against the officialTS.NRANGEdoc. Order is exactly right:cmdName numkeys key... fromTimestamp toTimestamp, thenLATEST/FILTER_BY_TS/FILTER_BY_VALUE/COUNT, thenALIGN/AGGREGATION <per-key lists> bucketDuration/BUCKETTIMESTAMP/EMPTY. ReusingRsTsRangeOptionsunchanged is safe (itsasArrayemits exactly those 4 range tokens in grammar order), and injectingRsTsNAggregationinto the unchangedRsTsAggregationOptionsproduces the correctAGGREGATION <list...> bucketDurationshape. TheaggregatorsStringrefactor exists precisely so per-key comma-joined lists bypass the single-aggregator check — good design. - Reply parsing: rows are
{timestamp. flatValuesArray}, ordered by key/aggregator input order;tsParseNRangeResult:mirrors the existing parse helpers. Missing values (NaN) surface as the raw string'NaN'via the package's existingtsParseValue:convention — consistent, no special-casing added. - CI: green on Pharo 11/12/13 (smalltalkCI runs the
TimeSeriesTestsgroup). - Doc convention: the
.scripting.mdmatches 13 existing siblings underdoc/scripting-features/. - DRY/responsibility: the 8 forwarding shims (4× NRANGE, 4× NREVRANGE) and the single shared
tsExecuteNRange:executor mirror the establishedtsMRange/tsMRevRangepattern; NREVRANGE reuses the same executor with onlycmdNameswapped — no duplicated command building or parsing.
Inline comments (3, all non-blocking)
- Optional — aggregation integration test (
RsTsNRangeTest) only asserts value count, not that per-key aggregators mapped to the right keys or computed correctly; add exact value assertions (#(15 100 200)). - FYI/Optional — missing-value slot (key2 absent at ts 2000) returns the string
'NaN'; not asserted or documented. - Nit/Consider —
RsTsNAggregationhas no class comment; theNprefix is cryptic in isolation and asymmetric with the reusedRsTsRangeOptions. A short doc note would help.
No Critical, Required, or security/performance issues found.
PR: #98
Pin exact aggregated values and the missing-value NaN representation in RsTsNRangeTest instead of only checking counts, and add a CRC-style class comment to RsTsNAggregation documenting its per-key AGGREGATION contract. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Summary
Changes
RsRedisEndpoint.extension.st: addstsNRangeBy:keys:.../tsNRevRangeBy:keys:...public methods (withusing:/aggregationBy:overloads) sharing a single private executor.RsTsAggregation.class.st: refactorsasArrayto extract a newaggregatorsStringmethod.RsTsNAggregation.class.st: builds per-keyAGGREGATIONlists sharing onebucketDuration.RsTsNRangeRow.class.st: holds a parsedtimestamp/valuesrow.RsTsNAggregationTest.class.st,RsTsNRangeTest.class.st,RsTsNRevRangeTest.class.st; adds a case toRsTsAggregationTest.class.st.doc/scripting-features/feature-ts-nrange-nrevrange.scripting.md(orchestration script used to generate this implementation).Commits Included
5d097da Add TS.NRANGE / TS.NREVRANGE support
Files Changed
doc/scripting-features/feature-ts-nrange-nrevrange.scripting.md
src/RediStick-TimeSeries-Tests/RsTsAggregationTest.class.st
src/RediStick-TimeSeries-Tests/RsTsNAggregationTest.class.st
src/RediStick-TimeSeries-Tests/RsTsNRangeTest.class.st
src/RediStick-TimeSeries-Tests/RsTsNRevRangeTest.class.st
src/RediStick-TimeSeries/RsRedisEndpoint.extension.st
src/RediStick-TimeSeries/RsTsAggregation.class.st
src/RediStick-TimeSeries/RsTsNAggregation.class.st
src/RediStick-TimeSeries/RsTsNRangeRow.class.st