Skip to content

Commit 49447f1

Browse files
author
Oleg Obolenskiy
committed
Merge branch 'highpower/issue-215-fix' of https://github.com/tarantool/tarantool-java into highpower/issue-215-fix
2 parents b7d22a4 + 92767e9 commit 49447f1

29 files changed

+1650
-209
lines changed

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,18 @@ makes possible for the client to configure a socket provider.
122122
* `ComposableAsyncOps` - return the operation result as a `CompletionStage`
123123
* `FireAndForgetOps` - returns the query ID
124124

125+
Each operation that requires space or index to be executed, can work with
126+
number ID as well as string name of a space or an index.
127+
Assume, we have `my_space` space with space ID `512` and its primary index
128+
`primary` with index ID `0`. Then, for instance, `select` operations can be
129+
performed as the following:
130+
131+
```java
132+
client.syncOps().select(512, 0, Collections.singletonList(1), 0, 1, Iterator.EQ);
133+
// or using more convenient way
134+
client.syncOps().select("my_space", "primary", Collections.singletonList(1), 0, 1, Iterator.EQ);
135+
```
136+
125137
Feel free to override any method of `TarantoolClientImpl`. For example, to hook
126138
all the results, you could override this:
127139

Lines changed: 255 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,294 @@
11
package org.tarantool;
22

3+
import static org.tarantool.AbstractTarantoolOps.ArgumentFactory.allResolved;
4+
import static org.tarantool.AbstractTarantoolOps.ArgumentFactory.resolved;
5+
import static org.tarantool.AbstractTarantoolOps.ArgumentFactory.unresolved;
36

4-
public abstract class AbstractTarantoolOps<Space, Tuple, Operation, Result>
5-
implements TarantoolClientOps<Space, Tuple, Operation, Result> {
7+
import java.util.Arrays;
8+
import java.util.Objects;
9+
import java.util.function.BiFunction;
10+
import java.util.function.Function;
11+
import java.util.stream.Stream;
12+
13+
public abstract class AbstractTarantoolOps<Tuple, Operation, Result>
14+
implements TarantoolClientOps<Tuple, Operation, Result> {
15+
16+
private final Function<Object, Object> defaultSpaceResolver =
17+
space -> resolveSpace((String) space);
18+
private final BiFunction<Object, Object, Object> defaultSpaceIndexResolver =
19+
(space, index) -> resolveSpaceIndex((String) space, (String) index);
620

721
private Code callCode = Code.CALL;
822

9-
protected abstract Result exec(Code code, Object... args);
23+
protected Result exec(Code code, Object... args) {
24+
return exec(code, allResolved(args));
25+
}
26+
27+
protected Result exec(long timeoutMillis, Code code, Object... args) {
28+
return exec(timeoutMillis, code, allResolved(args));
29+
}
30+
31+
protected abstract Result exec(Code code, ResolvableOpArgument... args);
32+
33+
protected abstract Result exec(long timeoutMillis, Code code, ResolvableOpArgument... args);
34+
35+
protected abstract int resolveSpace(String space);
36+
37+
protected abstract int resolveSpaceIndex(String space, String index);
1038

11-
public Result select(Space space, Space index, Tuple key, int offset, int limit, Iterator iterator) {
39+
@Override
40+
public Result select(Integer space, Integer index, Tuple key, int offset, int limit, Iterator iterator) {
1241
return select(space, index, key, offset, limit, iterator.getValue());
1342
}
1443

15-
public Result select(Space space, Space index, Tuple key, int offset, int limit, int iterator) {
16-
return exec(
17-
Code.SELECT,
18-
Key.SPACE, space,
19-
Key.INDEX, index,
20-
Key.KEY, key,
21-
Key.ITERATOR, iterator,
22-
Key.LIMIT, limit,
23-
Key.OFFSET, offset
44+
@Override
45+
public Result select(String space, String index, Tuple key, int offset, int limit, Iterator iterator) {
46+
return select(space, index, key, offset, limit, iterator.getValue());
47+
}
48+
49+
@Override
50+
public Result select(Integer space, Integer index, Tuple key, int offset, int limit, int iterator) {
51+
return doSelect(resolved(space), resolved(index), key, offset, limit, iterator);
52+
}
53+
54+
@Override
55+
public Result select(String space, String index, Tuple key, int offset, int limit, int iterator) {
56+
return doSelect(
57+
unresolved(space, defaultSpaceResolver),
58+
unresolved(index, indexName -> defaultSpaceIndexResolver.apply(space, indexName)),
59+
key, offset, limit, iterator
2460
);
2561
}
2662

27-
public Result insert(Space space, Tuple tuple) {
28-
return exec(Code.INSERT, Key.SPACE, space, Key.TUPLE, tuple);
63+
@Override
64+
public Result insert(Integer space, Tuple tuple) {
65+
return doInsert(resolved(space), tuple);
66+
}
67+
68+
@Override
69+
public Result insert(String space, Tuple tuple) {
70+
return doInsert(unresolved(space, defaultSpaceResolver), tuple);
2971
}
3072

31-
public Result replace(Space space, Tuple tuple) {
32-
return exec(Code.REPLACE, Key.SPACE, space, Key.TUPLE, tuple);
73+
@Override
74+
public Result replace(Integer space, Tuple tuple) {
75+
return doReplace(resolved(space), tuple);
3376
}
3477

35-
public Result update(Space space, Tuple key, Operation... args) {
36-
return exec(Code.UPDATE, Key.SPACE, space, Key.KEY, key, Key.TUPLE, args);
78+
@Override
79+
public Result replace(String space, Tuple tuple) {
80+
return doReplace(unresolved(space, defaultSpaceResolver), tuple);
3781
}
3882

39-
public Result upsert(Space space, Tuple key, Tuple def, Operation... args) {
40-
return exec(Code.UPSERT, Key.SPACE, space, Key.KEY, key, Key.TUPLE, def, Key.UPSERT_OPS, args);
83+
@Override
84+
public Result update(Integer space, Tuple key, Operation... args) {
85+
return doUpdate(resolved(space), key, args);
4186
}
4287

43-
public Result delete(Space space, Tuple key) {
44-
return exec(Code.DELETE, Key.SPACE, space, Key.KEY, key);
88+
@Override
89+
public Result update(String space, Tuple key, Operation... tuple) {
90+
return doUpdate(unresolved(space, defaultSpaceResolver), key, tuple);
4591
}
4692

93+
@Override
94+
public Result upsert(Integer space, Tuple key, Tuple defTuple, Operation... ops) {
95+
return doUpsert(resolved(space), key, defTuple, ops);
96+
}
97+
98+
@Override
99+
public Result upsert(String space, Tuple key, Tuple defTuple, Operation... ops) {
100+
return doUpsert(unresolved(space, defaultSpaceResolver), key, defTuple, ops);
101+
}
102+
103+
@Override
104+
public Result delete(Integer space, Tuple key) {
105+
return doDelete(resolved(space), key);
106+
}
107+
108+
@Override
109+
public Result delete(String space, Tuple key) {
110+
return doDelete(unresolved(space, defaultSpaceResolver), key);
111+
}
112+
113+
@Override
47114
public Result call(String function, Object... args) {
48115
return exec(callCode, Key.FUNCTION, function, Key.TUPLE, args);
49116
}
50117

118+
@Override
51119
public Result eval(String expression, Object... args) {
52120
return exec(Code.EVAL, Key.EXPRESSION, expression, Key.TUPLE, args);
53121
}
54122

123+
@Override
55124
public void ping() {
56125
exec(Code.PING);
57126
}
58127

59128
public void setCallCode(Code callCode) {
60129
this.callCode = callCode;
61130
}
131+
132+
private Result doDelete(ResolvableOpArgument space, Tuple key) {
133+
return exec(Code.DELETE, resolved(Key.SPACE), space, resolved(Key.KEY), resolved(key));
134+
}
135+
136+
private Result doUpsert(ResolvableOpArgument space, Tuple key, Tuple defTuple, Operation... ops) {
137+
return exec(
138+
Code.UPSERT,
139+
resolved(Key.SPACE), space,
140+
resolved(Key.KEY), resolved(key),
141+
resolved(Key.TUPLE), resolved(defTuple),
142+
resolved(Key.UPSERT_OPS), resolved(ops)
143+
);
144+
}
145+
146+
private Result doUpdate(ResolvableOpArgument space, Tuple key, Operation... ops) {
147+
return exec(
148+
Code.UPDATE,
149+
resolved(Key.SPACE), space,
150+
resolved(Key.KEY), resolved(key),
151+
resolved(Key.TUPLE), resolved(ops)
152+
);
153+
}
154+
155+
private Result doReplace(ResolvableOpArgument space, Tuple tuple) {
156+
return exec(Code.REPLACE, resolved(Key.SPACE), space, resolved(Key.TUPLE), resolved(tuple));
157+
}
158+
159+
private Result doInsert(ResolvableOpArgument space, Tuple tuple) {
160+
return exec(Code.INSERT, resolved(Key.SPACE), space, resolved(Key.TUPLE), resolved(tuple));
161+
}
162+
163+
private Result doSelect(ResolvableOpArgument space,
164+
ResolvableOpArgument index,
165+
Tuple key,
166+
int offset,
167+
int limit,
168+
int iterator) {
169+
return exec(
170+
Code.SELECT,
171+
resolved(Key.SPACE), space,
172+
resolved(Key.INDEX), index,
173+
resolved(Key.KEY), resolved(key),
174+
resolved(Key.ITERATOR), resolved(iterator),
175+
resolved(Key.LIMIT), resolved(limit),
176+
resolved(Key.OFFSET), resolved(offset)
177+
);
178+
}
179+
180+
public static class ArgumentFactory {
181+
182+
public static ResolvableOpArgument resolved(Object value) {
183+
return new ResolvedArgument(value);
184+
}
185+
186+
public static ResolvableOpArgument unresolved(Object key, Function<Object, Object> resolver) {
187+
return new UnresolvedArgument(key, resolver);
188+
}
189+
190+
public static ResolvableOpArgument[] allResolved(Object[] values) {
191+
return Stream.of(values).map(ArgumentFactory::resolved).toArray(ResolvableOpArgument[]::new);
192+
}
193+
194+
}
195+
196+
/**
197+
* Wrapper over the target argument which possibly can't
198+
* be resolved at the moment.
199+
*/
200+
public interface ResolvableOpArgument {
201+
202+
/**
203+
* Checks whether an argument can be obtained instantly calling
204+
* {@link #getValue()}.
205+
*
206+
* @return {@literal true} if value can be retrieved right now.
207+
*/
208+
boolean hasValue();
209+
210+
/**
211+
* Gets a target argument value. It raises
212+
* an exception if the value is unavailable.
213+
* Availability can be checked via {@link #hasValue()}.
214+
*
215+
* @return wrapped argument value
216+
* @throws RuntimeException if the value is unavailable.
217+
*/
218+
Object getValue();
219+
220+
}
221+
222+
/**
223+
* Simple wrapper that holds the original value.
224+
*/
225+
public static class ResolvedArgument implements ResolvableOpArgument {
226+
227+
private final Object value;
228+
229+
private ResolvedArgument(Object value) {
230+
Objects.requireNonNull(value);
231+
this.value = value;
232+
}
233+
234+
@Override
235+
public boolean hasValue() {
236+
return true;
237+
}
238+
239+
@Override
240+
public Object getValue() {
241+
return value;
242+
}
243+
244+
@Override
245+
public String toString() {
246+
return "ResolvedArgument{" +
247+
"value=" + ((value instanceof Object[]) ? Arrays.toString((Object[])value) : value) +
248+
'}';
249+
}
250+
251+
}
252+
253+
/**
254+
* Wrapper that evaluates the value each time
255+
* it is requested.
256+
* <p>
257+
* It works like a function, where {@code argument = f(key)}.
258+
*/
259+
public static class UnresolvedArgument implements ResolvableOpArgument {
260+
261+
private final Object key;
262+
private final Function<Object, Object> resolver;
263+
264+
private UnresolvedArgument(Object key, Function<Object, Object> resolver) {
265+
Objects.requireNonNull(key);
266+
Objects.requireNonNull(resolver);
267+
268+
this.key = key;
269+
this.resolver = resolver;
270+
}
271+
272+
@Override
273+
public boolean hasValue() {
274+
try {
275+
resolver.apply(key);
276+
} catch (Exception ignored) {
277+
return false;
278+
}
279+
return true;
280+
}
281+
282+
@Override
283+
public Object getValue() {
284+
return resolver.apply(key);
285+
}
286+
287+
@Override
288+
public String toString() {
289+
return "UnresolvedArgument{" +
290+
"key=" + key +
291+
'}';
292+
}
293+
}
62294
}

src/main/java/org/tarantool/TarantoolBase.java

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import java.util.List;
1010
import java.util.concurrent.atomic.AtomicLong;
1111

12-
public abstract class TarantoolBase<Result> extends AbstractTarantoolOps<Integer, List<?>, Object, Result> {
12+
public abstract class TarantoolBase<Result> extends AbstractTarantoolOps<List<?>, Object, Result> {
1313
protected String serverVersion;
1414
protected MsgPackLite msgPackLite = MsgPackLite.INSTANCE;
1515
protected AtomicLong syncId = new AtomicLong();
@@ -42,16 +42,6 @@ protected void closeChannel(SocketChannel channel) {
4242
}
4343
}
4444

45-
protected void validateArgs(Object[] args) {
46-
if (args != null) {
47-
for (int i = 0; i < args.length; i += 2) {
48-
if (args[i + 1] == null) {
49-
throw new NullPointerException(((Key) args[i]).name() + " should not be null");
50-
}
51-
}
52-
}
53-
}
54-
5545
public void setInitialRequestSize(int initialRequestSize) {
5646
this.initialRequestSize = initialRequestSize;
5747
}

src/main/java/org/tarantool/TarantoolClient.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77
import java.util.concurrent.TimeUnit;
88

99
public interface TarantoolClient {
10-
TarantoolClientOps<Integer, List<?>, Object, List<?>> syncOps();
10+
TarantoolClientOps<List<?>, Object, List<?>> syncOps();
1111

12-
TarantoolClientOps<Integer, List<?>, Object, Future<List<?>>> asyncOps();
12+
TarantoolClientOps<List<?>, Object, Future<List<?>>> asyncOps();
1313

14-
TarantoolClientOps<Integer, List<?>, Object, CompletionStage<List<?>>> composableAsyncOps();
14+
TarantoolClientOps<List<?>, Object, CompletionStage<List<?>>> composableAsyncOps();
1515

16-
TarantoolClientOps<Integer, List<?>, Object, Long> fireAndForgetOps();
16+
TarantoolClientOps<List<?>, Object, Long> fireAndForgetOps();
1717

1818
TarantoolSQLOps<Object, Long, List<Map<String, Object>>> sqlSyncOps();
1919

0 commit comments

Comments
 (0)