Skip to content

Commit 37e263e

Browse files
dfa1claude
andcommitted
feat(scan): add withColumns/withLimit/withFilter fluent methods to ScanOptions
Allows chaining: ScanOptions.columns("price").withLimit(10).withFilter(...) without touching the 3-arg record constructor. All methods return new instances; original is unchanged. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 8fc22d4 commit 37e263e

2 files changed

Lines changed: 83 additions & 0 deletions

File tree

reader/src/main/java/io/github/dfa1/vortex/scan/ScanOptions.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,18 @@ public static ScanOptions limit(long limit) {
2525
return new ScanOptions(List.of(), null, limit);
2626
}
2727

28+
public ScanOptions withColumns(String... names) {
29+
return new ScanOptions(List.of(names), rowFilter, limit);
30+
}
31+
32+
public ScanOptions withLimit(long limit) {
33+
return new ScanOptions(columns, rowFilter, limit);
34+
}
35+
36+
public ScanOptions withFilter(RowFilter filter) {
37+
return new ScanOptions(columns, filter, limit);
38+
}
39+
2840
public boolean hasProjection() {
2941
return !columns.isEmpty();
3042
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package io.github.dfa1.vortex.scan;
2+
3+
import org.junit.jupiter.api.Test;
4+
5+
import static org.assertj.core.api.Assertions.assertThat;
6+
7+
class ScanOptionsTest {
8+
9+
@Test
10+
void withLimit_setsLimit() {
11+
// Given / When
12+
ScanOptions sut = ScanOptions.all().withLimit(10);
13+
14+
// Then
15+
assertThat(sut.limit()).isEqualTo(10);
16+
assertThat(sut.hasLimit()).isTrue();
17+
assertThat(sut.columns()).isEmpty();
18+
assertThat(sut.rowFilter()).isNull();
19+
}
20+
21+
@Test
22+
void withColumns_setsProjection() {
23+
// Given / When
24+
ScanOptions sut = ScanOptions.all().withColumns("price", "qty");
25+
26+
// Then
27+
assertThat(sut.columns()).containsExactly("price", "qty");
28+
assertThat(sut.hasProjection()).isTrue();
29+
assertThat(sut.limit()).isEqualTo(ScanOptions.NO_LIMIT);
30+
}
31+
32+
@Test
33+
void withFilter_setsFilter() {
34+
// Given
35+
RowFilter filter = new RowFilter.Gte("price", 100);
36+
37+
// When
38+
ScanOptions sut = ScanOptions.all().withFilter(filter);
39+
40+
// Then
41+
assertThat(sut.rowFilter()).isEqualTo(filter);
42+
assertThat(sut.hasFilter()).isTrue();
43+
}
44+
45+
@Test
46+
void fluent_chainingPreservesAllFields() {
47+
// Given / When
48+
ScanOptions sut = ScanOptions.all()
49+
.withColumns("price", "qty")
50+
.withLimit(10)
51+
.withFilter(new RowFilter.Gte("price", 50));
52+
53+
// Then
54+
assertThat(sut.columns()).containsExactly("price", "qty");
55+
assertThat(sut.limit()).isEqualTo(10);
56+
assertThat(sut.hasFilter()).isTrue();
57+
}
58+
59+
@Test
60+
void withMethods_doNotMutateOriginal() {
61+
// Given
62+
ScanOptions original = ScanOptions.all();
63+
64+
// When
65+
original.withLimit(5).withColumns("x");
66+
67+
// Then
68+
assertThat(original.limit()).isEqualTo(ScanOptions.NO_LIMIT);
69+
assertThat(original.columns()).isEmpty();
70+
}
71+
}

0 commit comments

Comments
 (0)