Skip to content

Commit 27a2fd7

Browse files
committed
Add BYPASS CACHE and partial USING TIMEOUT to mapper
Now Select, Insert and Update annotations used in DAOs can specify (usingTimeout = "durationString") in order to use Scylla CQL extension timeouts. Select annotations can specify (bypassCache = true). Fixes #168
1 parent 633f76c commit 27a2fd7

File tree

13 files changed

+732
-7
lines changed

13 files changed

+732
-7
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,315 @@
1+
/*
2+
* Copyright DataStax, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
/*
18+
* Copyright (C) 2022 ScyllaDB
19+
*
20+
* Modified by ScyllaDB
21+
*/
22+
package com.datastax.oss.driver.mapper;
23+
24+
import static org.assertj.core.api.Assertions.assertThat;
25+
import static org.assertj.core.api.Assumptions.assumeThat;
26+
27+
import com.datastax.oss.driver.api.core.CqlIdentifier;
28+
import com.datastax.oss.driver.api.core.CqlSession;
29+
import com.datastax.oss.driver.api.core.PagingIterable;
30+
import com.datastax.oss.driver.api.core.cql.SimpleStatement;
31+
import com.datastax.oss.driver.api.mapper.MapperBuilder;
32+
import com.datastax.oss.driver.api.mapper.annotations.ClusteringColumn;
33+
import com.datastax.oss.driver.api.mapper.annotations.Computed;
34+
import com.datastax.oss.driver.api.mapper.annotations.CqlName;
35+
import com.datastax.oss.driver.api.mapper.annotations.Dao;
36+
import com.datastax.oss.driver.api.mapper.annotations.DaoFactory;
37+
import com.datastax.oss.driver.api.mapper.annotations.DaoKeyspace;
38+
import com.datastax.oss.driver.api.mapper.annotations.Entity;
39+
import com.datastax.oss.driver.api.mapper.annotations.Insert;
40+
import com.datastax.oss.driver.api.mapper.annotations.Mapper;
41+
import com.datastax.oss.driver.api.mapper.annotations.PartitionKey;
42+
import com.datastax.oss.driver.api.mapper.annotations.Select;
43+
import com.datastax.oss.driver.api.testinfra.CassandraSkip;
44+
import com.datastax.oss.driver.api.testinfra.ScyllaRequirement;
45+
import com.datastax.oss.driver.api.testinfra.ccm.CcmBridge;
46+
import com.datastax.oss.driver.api.testinfra.ccm.CcmRule;
47+
import com.datastax.oss.driver.api.testinfra.session.SessionRule;
48+
import com.datastax.oss.driver.categories.ParallelizableTests;
49+
import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList;
50+
import java.util.HashMap;
51+
import java.util.Map;
52+
import java.util.Objects;
53+
import org.junit.BeforeClass;
54+
import org.junit.ClassRule;
55+
import org.junit.Test;
56+
import org.junit.experimental.categories.Category;
57+
import org.junit.rules.RuleChain;
58+
import org.junit.rules.TestRule;
59+
60+
@Category(ParallelizableTests.class)
61+
@CassandraSkip(description = "BYPASS CACHE clause is a ScyllaDB CQL Extension")
62+
@ScyllaRequirement(
63+
minOSS = "3.1.0",
64+
minEnterprise = "2020.1.0",
65+
description = "Based on labels attached to ecf3f92ec7")
66+
public class SelectBypassCacheIT {
67+
68+
private static final CcmRule CCM_RULE = CcmRule.getInstance();
69+
private static final SessionRule<CqlSession> SESSION_RULE = SessionRule.builder(CCM_RULE).build();
70+
71+
@ClassRule
72+
public static final TestRule CHAIN = RuleChain.outerRule(CCM_RULE).around(SESSION_RULE);
73+
74+
private static SimpleDao dao;
75+
76+
@BeforeClass
77+
public static void setup() {
78+
CqlSession session = SESSION_RULE.session();
79+
80+
for (String query :
81+
ImmutableList.of("CREATE TABLE simple (k int, cc int, v int, PRIMARY KEY (k, cc))")) {
82+
session.execute(
83+
SimpleStatement.builder(query).setExecutionProfile(SESSION_RULE.slowProfile()).build());
84+
}
85+
86+
TestMapper mapper = TestMapper.builder(session).build();
87+
dao = mapper.simpleDao(SESSION_RULE.keyspace());
88+
89+
for (int k = 0; k < 2; k++) {
90+
for (int cc = 0; cc < 10; cc++) {
91+
dao.insert(new Simple(k, cc, 1));
92+
}
93+
}
94+
}
95+
96+
@Test
97+
public void should_select_with_limit() {
98+
PagingIterable<Simple> elements = dao.selectWithLimit(10);
99+
assertThat(elements.isFullyFetched()).isTrue();
100+
assertThat(elements.getAvailableWithoutFetching()).isEqualTo(10);
101+
102+
elements = dao.selectWithLimit(0, 5);
103+
assertThat(elements.isFullyFetched()).isTrue();
104+
assertThat(elements.getAvailableWithoutFetching()).isEqualTo(5);
105+
106+
elements = dao.selectWithLimit(0, 0, 1);
107+
assertThat(elements.isFullyFetched()).isTrue();
108+
assertThat(elements.getAvailableWithoutFetching()).isEqualTo(1);
109+
}
110+
111+
@Test
112+
public void should_select_with_per_partition_limit() {
113+
assumeThat(CcmBridge.SCYLLA_ENABLEMENT).isFalse(); // @IntegrationTestDisabledScyllaFailure
114+
115+
PagingIterable<Simple> elements = dao.selectWithPerPartitionLimit(5);
116+
assertThat(elements.isFullyFetched()).isTrue();
117+
assertThat(elements.getAvailableWithoutFetching()).isEqualTo(10);
118+
119+
Map<Integer, Integer> elementCountPerPartition = new HashMap<>();
120+
for (Simple element : elements) {
121+
elementCountPerPartition.compute(element.getK(), (k, v) -> (v == null) ? 1 : v + 1);
122+
}
123+
assertThat(elementCountPerPartition).hasSize(2).containsEntry(0, 5).containsEntry(1, 5);
124+
}
125+
126+
@Test
127+
public void should_select_with_order_by() {
128+
PagingIterable<Simple> elements = dao.selectByCcDesc(0);
129+
int previousCc = Integer.MAX_VALUE;
130+
for (Simple element : elements) {
131+
assertThat(element.getCc()).isLessThan(previousCc);
132+
previousCc = element.getCc();
133+
}
134+
}
135+
136+
@Test
137+
public void should_select_with_group_by() {
138+
PagingIterable<Sum> sums = dao.selectSumByK();
139+
assertThat(sums.all()).hasSize(2).containsOnly(new Sum(0, 10), new Sum(1, 10));
140+
}
141+
142+
@Test
143+
public void should_select_with_allow_filtering() {
144+
PagingIterable<Simple> elements = dao.selectByCc(1);
145+
assertThat(elements.all()).hasSize(2).containsOnly(new Simple(0, 1, 1), new Simple(1, 1, 1));
146+
}
147+
148+
@Test
149+
public void should_select_with_bypass_cache() {
150+
// BYPASS CACHE is transparent for the driver - this just checks for exceptions
151+
PagingIterable<Simple> result = dao.selectWithBypassCache(0, 0);
152+
assertThat(result.all()).hasSize(1).containsOnly(new Simple(0, 0, 1));
153+
System.out.println(result.getExecutionInfo().getRequest());
154+
}
155+
156+
@Mapper
157+
public interface TestMapper {
158+
@DaoFactory
159+
SimpleDao simpleDao(@DaoKeyspace CqlIdentifier keyspace);
160+
161+
static MapperBuilder<TestMapper> builder(CqlSession session) {
162+
return new SelectBypassCacheIT_TestMapperBuilder(session);
163+
}
164+
}
165+
166+
@Dao
167+
public interface SimpleDao {
168+
@Insert
169+
void insert(Simple simple);
170+
171+
@Select(limit = ":l")
172+
PagingIterable<Simple> selectWithLimit(@CqlName("l") int l);
173+
174+
@Select(limit = ":l")
175+
PagingIterable<Simple> selectWithLimit(int k, @CqlName("l") int l);
176+
177+
/**
178+
* Contrived since the query will return at most a single row, but this is just to check that
179+
* {@code l} doesn't need an explicit name when the full primary key is provided.
180+
*/
181+
@Select(limit = ":l", bypassCache = true)
182+
PagingIterable<Simple> selectWithLimit(int k, int cc, int l);
183+
184+
@Select(perPartitionLimit = ":perPartitionLimit", bypassCache = true)
185+
PagingIterable<Simple> selectWithPerPartitionLimit(
186+
@CqlName("perPartitionLimit") int perPartitionLimit);
187+
188+
@Select(orderBy = "cc DESC", bypassCache = true)
189+
PagingIterable<Simple> selectByCcDesc(int k);
190+
191+
@Select(groupBy = "k", bypassCache = true)
192+
PagingIterable<Sum> selectSumByK();
193+
194+
@Select(customWhereClause = "cc = :cc", allowFiltering = true, bypassCache = true)
195+
PagingIterable<Simple> selectByCc(int cc);
196+
197+
@Select(bypassCache = true)
198+
PagingIterable<Simple> selectWithBypassCache(int k, int cc);
199+
}
200+
201+
@Entity
202+
public static class Simple {
203+
@PartitionKey private int k;
204+
@ClusteringColumn private int cc;
205+
private int v;
206+
207+
public Simple() {}
208+
209+
public Simple(int k, int cc, int v) {
210+
this.k = k;
211+
this.cc = cc;
212+
this.v = v;
213+
}
214+
215+
public int getK() {
216+
return k;
217+
}
218+
219+
public void setK(int k) {
220+
this.k = k;
221+
}
222+
223+
public int getCc() {
224+
return cc;
225+
}
226+
227+
public void setCc(int cc) {
228+
this.cc = cc;
229+
}
230+
231+
public int getV() {
232+
return v;
233+
}
234+
235+
public void setV(int v) {
236+
this.v = v;
237+
}
238+
239+
@Override
240+
public boolean equals(Object other) {
241+
if (other == this) {
242+
return true;
243+
} else if (other instanceof Simple) {
244+
Simple that = (Simple) other;
245+
return this.k == that.k && this.cc == that.cc && this.v == that.v;
246+
} else {
247+
return false;
248+
}
249+
}
250+
251+
@Override
252+
public int hashCode() {
253+
return Objects.hash(k, cc, v);
254+
}
255+
256+
@Override
257+
public String toString() {
258+
return String.format("Simple(%d, %d, %d)", k, cc, v);
259+
}
260+
}
261+
262+
@Entity
263+
@CqlName("simple")
264+
public static class Sum {
265+
private int k;
266+
267+
@Computed("sum(v)")
268+
private int value;
269+
270+
public Sum() {}
271+
272+
public Sum(int k, int value) {
273+
this.k = k;
274+
this.value = value;
275+
}
276+
277+
public int getK() {
278+
return k;
279+
}
280+
281+
public void setK(int k) {
282+
this.k = k;
283+
}
284+
285+
public int getValue() {
286+
return value;
287+
}
288+
289+
public void setValue(int value) {
290+
this.value = value;
291+
}
292+
293+
@Override
294+
public boolean equals(Object other) {
295+
if (other == this) {
296+
return true;
297+
} else if (other instanceof Sum) {
298+
Sum that = (Sum) other;
299+
return this.k == that.k && this.value == that.value;
300+
} else {
301+
return false;
302+
}
303+
}
304+
305+
@Override
306+
public int hashCode() {
307+
return Objects.hash(k, value);
308+
}
309+
310+
@Override
311+
public String toString() {
312+
return String.format("Sum(%d, %d)", k, value);
313+
}
314+
}
315+
}

0 commit comments

Comments
 (0)