Skip to content

Commit 4ad4472

Browse files
Bouncheckavelanarius
authored andcommitted
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 f31eb24 commit 4ad4472

File tree

13 files changed

+709
-7
lines changed

13 files changed

+709
-7
lines changed
Lines changed: 292 additions & 0 deletions
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)