Skip to content

Commit f8b1ede

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 f8b1ede

File tree

13 files changed

+709
-7
lines changed

13 files changed

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

0 commit comments

Comments
 (0)