Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit d5ceeb2

Browse files
committedOct 25, 2019
Introduce Tarantool client DSL
This DSL includes set of request builders that can be used as a public API to construct requests. The main idea here is to provide more natural DSL-like approach to build operations instead of current abstract types like List<?> or List<Object>. Affects: #212
1 parent b591fab commit d5ceeb2

19 files changed

+1096
-114
lines changed
 

‎src/main/java/org/tarantool/AbstractTarantoolOps.java

Lines changed: 78 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -1,200 +1,164 @@
11
package org.tarantool;
22

3-
import static org.tarantool.TarantoolRequestArgumentFactory.cacheLookupValue;
4-
import static org.tarantool.TarantoolRequestArgumentFactory.value;
5-
3+
import static org.tarantool.dsl.Requests.callRequest;
4+
import static org.tarantool.dsl.Requests.deleteRequest;
5+
import static org.tarantool.dsl.Requests.evalRequest;
6+
import static org.tarantool.dsl.Requests.insertRequest;
7+
import static org.tarantool.dsl.Requests.pingRequest;
8+
import static org.tarantool.dsl.Requests.replaceRequest;
9+
import static org.tarantool.dsl.Requests.selectRequest;
10+
import static org.tarantool.dsl.Requests.updateRequest;
11+
import static org.tarantool.dsl.Requests.upsertRequest;
12+
13+
import org.tarantool.dsl.Operation;
14+
import org.tarantool.dsl.TarantoolRequestConvertible;
15+
import org.tarantool.logging.Logger;
16+
import org.tarantool.logging.LoggerFactory;
617
import org.tarantool.schema.TarantoolSchemaMeta;
718

19+
import java.util.Arrays;
820
import java.util.List;
921

1022
public abstract class AbstractTarantoolOps<Result>
1123
implements TarantoolClientOps<List<?>, Object, Result> {
1224

25+
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractTarantoolOps.class);
26+
1327
private Code callCode = Code.CALL;
1428

1529
protected abstract Result exec(TarantoolRequest request);
1630

1731
protected abstract TarantoolSchemaMeta getSchemaMeta();
1832

1933
public Result select(Integer space, Integer index, List<?> key, int offset, int limit, Iterator iterator) {
20-
return select(space, index, key, offset, limit, iterator.getValue());
34+
return execute(
35+
selectRequest(space, index)
36+
.key(key)
37+
.offset(offset).limit(limit)
38+
.iterator(iterator)
39+
);
2140
}
2241

2342
@Override
2443
public Result select(String space, String index, List<?> key, int offset, int limit, Iterator iterator) {
25-
return select(space, index, key, offset, limit, iterator.getValue());
44+
return execute(
45+
selectRequest(space, index)
46+
.key(key)
47+
.offset(offset).limit(limit)
48+
.iterator(iterator)
49+
);
2650
}
2751

2852
@Override
2953
public Result select(Integer space, Integer index, List<?> key, int offset, int limit, int iterator) {
30-
return exec(
31-
new TarantoolRequest(
32-
Code.SELECT,
33-
value(Key.SPACE), value(space),
34-
value(Key.INDEX), value(index),
35-
value(Key.KEY), value(key),
36-
value(Key.ITERATOR), value(iterator),
37-
value(Key.LIMIT), value(limit),
38-
value(Key.OFFSET), value(offset)
39-
)
54+
return execute(
55+
selectRequest(space, index)
56+
.key(key)
57+
.offset(offset).limit(limit)
58+
.iterator(iterator)
4059
);
4160
}
4261

4362
@Override
4463
public Result select(String space, String index, List<?> key, int offset, int limit, int iterator) {
45-
return exec(
46-
new TarantoolRequest(
47-
Code.SELECT,
48-
value(Key.SPACE), cacheLookupValue(() -> getSchemaMeta().getSpace(space).getId()),
49-
value(Key.INDEX), cacheLookupValue(() -> getSchemaMeta().getSpaceIndex(space, index).getId()),
50-
value(Key.KEY), value(key),
51-
value(Key.ITERATOR), value(iterator),
52-
value(Key.LIMIT), value(limit),
53-
value(Key.OFFSET), value(offset)
54-
)
64+
return execute(
65+
selectRequest(space, index)
66+
.key(key)
67+
.offset(offset).limit(limit)
68+
.iterator(iterator)
5569
);
5670
}
5771

5872
@Override
5973
public Result insert(Integer space, List<?> tuple) {
60-
return exec(new TarantoolRequest(
61-
Code.INSERT,
62-
value(Key.SPACE), value(space),
63-
value(Key.TUPLE), value(tuple)
64-
)
65-
);
74+
return execute(insertRequest(space, tuple));
6675
}
6776

6877
@Override
6978
public Result insert(String space, List<?> tuple) {
70-
return exec(
71-
new TarantoolRequest(
72-
Code.INSERT,
73-
value(Key.SPACE), cacheLookupValue(() -> getSchemaMeta().getSpace(space).getId()),
74-
value(Key.TUPLE), value(tuple)
75-
)
76-
);
79+
return execute(insertRequest(space, tuple));
7780
}
7881

7982
@Override
8083
public Result replace(Integer space, List<?> tuple) {
81-
return exec(
82-
new TarantoolRequest(
83-
Code.REPLACE,
84-
value(Key.SPACE), value(space),
85-
value(Key.TUPLE), value(tuple)
86-
)
87-
);
84+
return execute(replaceRequest(space, tuple));
8885
}
8986

9087
@Override
9188
public Result replace(String space, List<?> tuple) {
92-
return exec(
93-
new TarantoolRequest(
94-
Code.REPLACE,
95-
value(Key.SPACE), cacheLookupValue(() -> getSchemaMeta().getSpace(space).getId()),
96-
value(Key.TUPLE), value(tuple)
97-
)
98-
);
89+
return execute(replaceRequest(space, tuple));
9990
}
10091

10192
@Override
10293
public Result update(Integer space, List<?> key, Object... operations) {
103-
return exec(
104-
new TarantoolRequest(
105-
Code.UPDATE,
106-
value(Key.SPACE), value(space),
107-
value(Key.KEY), value(key),
108-
value(Key.TUPLE), value(operations)
109-
)
110-
);
94+
Operation[] ops = Arrays.stream(operations)
95+
.map(Operation::fromArray)
96+
.toArray(org.tarantool.dsl.Operation[]::new);
97+
return execute(updateRequest(space, key, ops));
11198
}
11299

113100
@Override
114101
public Result update(String space, List<?> key, Object... operations) {
115-
return exec(
116-
new TarantoolRequest(
117-
Code.UPDATE,
118-
value(Key.SPACE), cacheLookupValue(() -> getSchemaMeta().getSpace(space).getId()),
119-
value(Key.KEY), value(key),
120-
value(Key.TUPLE), value(operations)
121-
)
122-
);
102+
Operation[] ops = Arrays.stream(operations)
103+
.map(Operation::fromArray)
104+
.toArray(org.tarantool.dsl.Operation[]::new);
105+
return execute(updateRequest(space, key, ops));
123106
}
124107

125108
@Override
126109
public Result upsert(Integer space, List<?> key, List<?> defTuple, Object... operations) {
127-
return exec(
128-
new TarantoolRequest(
129-
Code.UPSERT,
130-
value(Key.SPACE), value(space),
131-
value(Key.KEY), value(key),
132-
value(Key.TUPLE), value(defTuple),
133-
value(Key.UPSERT_OPS), value(operations)
134-
)
135-
);
110+
Operation[] ops = Arrays.stream(operations)
111+
.map(Operation::fromArray)
112+
.toArray(Operation[]::new);
113+
return execute(upsertRequest(space, key, defTuple, ops));
136114
}
137115

138116
@Override
139117
public Result upsert(String space, List<?> key, List<?> defTuple, Object... operations) {
140-
return exec(
141-
new TarantoolRequest(
142-
Code.UPSERT,
143-
value(Key.SPACE), cacheLookupValue(() -> getSchemaMeta().getSpace(space).getId()),
144-
value(Key.KEY), value(key),
145-
value(Key.TUPLE), value(defTuple),
146-
value(Key.UPSERT_OPS), value(operations)
147-
)
148-
);
118+
Operation[] ops = Arrays.stream(operations)
119+
.map(Operation::fromArray)
120+
.toArray(Operation[]::new);
121+
return execute(upsertRequest(space, key, defTuple, ops));
149122
}
150123

151124
@Override
152125
public Result delete(Integer space, List<?> key) {
153-
return exec(
154-
new TarantoolRequest(
155-
Code.DELETE,
156-
value(Key.SPACE), value(space),
157-
value(Key.KEY), value(key)
158-
)
159-
);
126+
return execute(deleteRequest(space, key));
160127
}
161128

162129
@Override
163130
public Result delete(String space, List<?> key) {
164-
return exec(
165-
new TarantoolRequest(
166-
Code.DELETE,
167-
value(Key.SPACE), cacheLookupValue(() -> getSchemaMeta().getSpace(space).getId()),
168-
value(Key.KEY), value(key)
169-
)
170-
);
131+
return execute(deleteRequest(space, key));
171132
}
172133

173134
@Override
174135
public Result call(String function, Object... args) {
175-
return exec(
176-
new TarantoolRequest(
177-
callCode,
178-
value(Key.FUNCTION), value(function),
179-
value(Key.TUPLE), value(args)
180-
)
136+
return execute(
137+
callRequest(function)
138+
.arguments(args)
139+
.useCall16(callCode == Code.OLD_CALL)
181140
);
182141
}
183142

184143
@Override
185144
public Result eval(String expression, Object... args) {
186-
return exec(
187-
new TarantoolRequest(
188-
Code.EVAL,
189-
value(Key.EXPRESSION), value(expression),
190-
value(Key.TUPLE), value(args)
191-
)
192-
);
145+
return execute(evalRequest(expression).arguments(args));
193146
}
194147

195148
@Override
196149
public void ping() {
197-
exec(new TarantoolRequest(Code.PING));
150+
execute(pingRequest());
151+
}
152+
153+
@Override
154+
public Result execute(TarantoolRequestConvertible requestSpec) {
155+
TarantoolSchemaMeta schemaMeta = null;
156+
try {
157+
schemaMeta = getSchemaMeta();
158+
} catch (Exception cause) {
159+
LOGGER.warn(() -> "Could not get Tarantool schema meta-info", cause);
160+
}
161+
return exec(requestSpec.toTarantoolRequest(schemaMeta));
198162
}
199163

200164
public void setCallCode(Code callCode) {

‎src/main/java/org/tarantool/TarantoolClientOps.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.tarantool;
22

3+
import org.tarantool.dsl.TarantoolRequestConvertible;
4+
35
public interface TarantoolClientOps<O, P, R> {
46
R select(Integer space, Integer index, O key, int offset, int limit, int iterator);
57

@@ -33,7 +35,10 @@ public interface TarantoolClientOps<O, P, R> {
3335

3436
R eval(String expression, Object... args);
3537

38+
R execute(TarantoolRequestConvertible requestSpec);
39+
3640
void ping();
3741

3842
void close();
43+
3944
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package org.tarantool.dsl;
2+
3+
import org.tarantool.Code;
4+
import org.tarantool.TarantoolRequest;
5+
import org.tarantool.schema.TarantoolSchemaMeta;
6+
7+
import java.time.Duration;
8+
9+
public abstract class AbstractRequestSpec<B extends AbstractRequestSpec<B>>
10+
implements TarantoolRequestConvertible {
11+
12+
final Code code;
13+
Duration duration = Duration.ZERO;
14+
boolean useDefaultTimeout = true;
15+
16+
AbstractRequestSpec(Code code) {
17+
this.code = code;
18+
}
19+
20+
AbstractRequestSpec(Code code, Duration duration) {
21+
this.code = code;
22+
this.duration = duration;
23+
}
24+
25+
@SuppressWarnings("unchecked")
26+
public B timeout(Duration duration) {
27+
this.duration = duration;
28+
this.useDefaultTimeout = false;
29+
return (B) this;
30+
}
31+
32+
@SuppressWarnings("unchecked")
33+
public B useDefaultTimeout() {
34+
this.duration = Duration.ZERO;
35+
this.useDefaultTimeout = true;
36+
return (B) this;
37+
}
38+
39+
@Override
40+
public TarantoolRequest toTarantoolRequest(TarantoolSchemaMeta schemaMeta) {
41+
TarantoolRequest request = new TarantoolRequest(code);
42+
request.setTimeout(useDefaultTimeout ? null : duration);
43+
return request;
44+
}
45+
46+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package org.tarantool.dsl;
2+
3+
import static org.tarantool.TarantoolRequestArgumentFactory.value;
4+
5+
import org.tarantool.Code;
6+
import org.tarantool.Key;
7+
import org.tarantool.TarantoolRequest;
8+
import org.tarantool.schema.TarantoolSchemaMeta;
9+
10+
import java.util.ArrayList;
11+
import java.util.Collection;
12+
import java.util.Collections;
13+
import java.util.List;
14+
import java.util.Objects;
15+
16+
public class CallRequestSpec extends AbstractRequestSpec<CallRequestSpec> {
17+
18+
private String functionName;
19+
private List<Object> arguments = new ArrayList<>();
20+
private boolean useCall16 = false;
21+
22+
CallRequestSpec(String functionName) {
23+
super(Code.CALL);
24+
this.functionName = Objects.requireNonNull(functionName);
25+
}
26+
27+
public CallRequestSpec function(String functionName) {
28+
Objects.requireNonNull(functionName);
29+
this.functionName = functionName;
30+
return this;
31+
}
32+
33+
public CallRequestSpec arguments(Object... arguments) {
34+
this.arguments.clear();
35+
Collections.addAll(this.arguments, arguments);
36+
return this;
37+
}
38+
39+
public CallRequestSpec arguments(Collection<?> arguments) {
40+
this.arguments.clear();
41+
this.arguments.addAll(arguments);
42+
return this;
43+
}
44+
45+
public CallRequestSpec useCall16(boolean flag) {
46+
this.useCall16 = flag;
47+
return this;
48+
}
49+
50+
@Override
51+
public TarantoolRequest toTarantoolRequest(TarantoolSchemaMeta schemaMeta) {
52+
TarantoolRequest request = super.toTarantoolRequest(schemaMeta);
53+
if (useCall16) {
54+
request.setCode(Code.OLD_CALL);
55+
}
56+
request.addArguments(
57+
value(Key.FUNCTION), value(functionName),
58+
value(Key.TUPLE), value(arguments)
59+
);
60+
return request;
61+
}
62+
63+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package org.tarantool.dsl;
2+
3+
import static org.tarantool.TarantoolRequestArgumentFactory.cacheLookupValue;
4+
import static org.tarantool.TarantoolRequestArgumentFactory.value;
5+
6+
import org.tarantool.Code;
7+
import org.tarantool.Key;
8+
import org.tarantool.TarantoolRequest;
9+
import org.tarantool.schema.TarantoolSchemaMeta;
10+
11+
import java.util.ArrayList;
12+
import java.util.Arrays;
13+
import java.util.Collection;
14+
import java.util.Collections;
15+
import java.util.List;
16+
17+
public class DeleteRequestSpec extends SpaceRequestSpec<DeleteRequestSpec> {
18+
19+
private List<Object> key;
20+
21+
DeleteRequestSpec(int spaceId, List<?> key) {
22+
super(Code.DELETE, spaceId);
23+
this.key = new ArrayList<>(key);
24+
}
25+
26+
DeleteRequestSpec(int spaceId, Object... keyParts) {
27+
super(Code.DELETE, spaceId);
28+
this.key = Arrays.asList(keyParts);
29+
}
30+
31+
DeleteRequestSpec(String spaceName, List<?> key) {
32+
super(Code.DELETE, spaceName);
33+
this.key = new ArrayList<>(key);
34+
}
35+
36+
DeleteRequestSpec(String spaceName, Object... keyParts) {
37+
super(Code.DELETE, spaceName);
38+
this.key = Arrays.asList(keyParts);
39+
}
40+
41+
public DeleteRequestSpec primaryKey(Object... keyParts) {
42+
this.key.clear();
43+
Collections.addAll(this.key, keyParts);
44+
return this;
45+
}
46+
47+
public DeleteRequestSpec primaryKey(Collection<?> key) {
48+
this.key.clear();
49+
this.key.addAll(key);
50+
return this;
51+
}
52+
53+
@Override
54+
public TarantoolRequest toTarantoolRequest(TarantoolSchemaMeta schemaMeta) {
55+
TarantoolRequest request = super.toTarantoolRequest(schemaMeta);
56+
request.addArguments(
57+
value(Key.SPACE),
58+
spaceId == null
59+
? cacheLookupValue(() -> schemaMeta.getSpace(spaceName).getId())
60+
: value(spaceId),
61+
value(Key.KEY), value(key)
62+
);
63+
return request;
64+
}
65+
66+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package org.tarantool.dsl;
2+
3+
import static org.tarantool.TarantoolRequestArgumentFactory.value;
4+
5+
import org.tarantool.Code;
6+
import org.tarantool.Key;
7+
import org.tarantool.TarantoolRequest;
8+
import org.tarantool.schema.TarantoolSchemaMeta;
9+
10+
import java.util.ArrayList;
11+
import java.util.Collection;
12+
import java.util.Collections;
13+
import java.util.List;
14+
import java.util.Objects;
15+
16+
public class EvalRequestSpec extends AbstractRequestSpec<EvalRequestSpec> {
17+
18+
private String expression;
19+
private List<Object> arguments = new ArrayList<>();
20+
21+
EvalRequestSpec(String expression) {
22+
super(Code.EVAL);
23+
this.expression = Objects.requireNonNull(expression);
24+
}
25+
26+
public EvalRequestSpec expression(String expression) {
27+
Objects.requireNonNull(expression);
28+
this.expression = expression;
29+
return this;
30+
}
31+
32+
public EvalRequestSpec arguments(Object... arguments) {
33+
this.arguments.clear();
34+
Collections.addAll(this.arguments, arguments);
35+
return this;
36+
}
37+
38+
public EvalRequestSpec arguments(Collection<?> arguments) {
39+
this.arguments.clear();
40+
this.arguments.addAll(arguments);
41+
return this;
42+
}
43+
44+
@Override
45+
public TarantoolRequest toTarantoolRequest(TarantoolSchemaMeta schemaMeta) {
46+
TarantoolRequest request = super.toTarantoolRequest(schemaMeta);
47+
request.addArguments(
48+
value(Key.EXPRESSION), value(expression),
49+
value(Key.TUPLE), value(arguments)
50+
);
51+
return request;
52+
}
53+
54+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package org.tarantool.dsl;
2+
3+
import static org.tarantool.TarantoolRequestArgumentFactory.value;
4+
5+
import org.tarantool.Code;
6+
import org.tarantool.Key;
7+
import org.tarantool.TarantoolRequest;
8+
import org.tarantool.schema.TarantoolSchemaMeta;
9+
import org.tarantool.util.TupleTwo;
10+
11+
import java.util.ArrayList;
12+
import java.util.Collection;
13+
import java.util.Collections;
14+
import java.util.List;
15+
import java.util.Map;
16+
import java.util.Objects;
17+
import java.util.stream.Collectors;
18+
19+
public class ExecuteRequestSpec extends AbstractRequestSpec<ExecuteRequestSpec> {
20+
21+
private String sqlText;
22+
private List<Object> ordinalBindings = new ArrayList<>();
23+
private List<TupleTwo<String, Object>> namedBindings = new ArrayList<>();
24+
25+
ExecuteRequestSpec(String sqlText) {
26+
super(Code.EXECUTE);
27+
this.sqlText = Objects.requireNonNull(sqlText);
28+
}
29+
30+
public ExecuteRequestSpec sql(String text) {
31+
Objects.requireNonNull(text);
32+
this.sqlText = text;
33+
return this;
34+
}
35+
36+
public ExecuteRequestSpec ordinalParameters(Object... bindings) {
37+
this.ordinalBindings.clear();
38+
Collections.addAll(this.ordinalBindings, bindings);
39+
this.namedBindings.clear();
40+
return this;
41+
}
42+
43+
public ExecuteRequestSpec ordinalParameters(Collection<?> bindings) {
44+
this.ordinalBindings.clear();
45+
this.ordinalBindings.addAll(bindings);
46+
this.namedBindings.clear();
47+
return this;
48+
}
49+
50+
public ExecuteRequestSpec namedParameters(Map<String, ?> bindings) {
51+
this.namedBindings.clear();
52+
this.namedBindings.addAll(
53+
bindings.entrySet().stream()
54+
.map(e -> TupleTwo.<String, Object>of(e.getKey(), e.getValue()))
55+
.collect(Collectors.toList())
56+
);
57+
this.ordinalBindings.clear();
58+
return this;
59+
}
60+
61+
public ExecuteRequestSpec namedParameters(TupleTwo<String, ?>[] bindings) {
62+
this.namedBindings.clear();
63+
for (TupleTwo<String, ?> binding : bindings) {
64+
this.namedBindings.add(TupleTwo.of(binding.getFirst(), binding.getSecond()));
65+
}
66+
this.ordinalBindings.clear();
67+
return this;
68+
}
69+
70+
@Override
71+
public TarantoolRequest toTarantoolRequest(TarantoolSchemaMeta schemaMeta) {
72+
TarantoolRequest request = super.toTarantoolRequest(schemaMeta);
73+
request.addArguments(
74+
value(Key.SQL_TEXT),
75+
value(sqlText)
76+
);
77+
if (!ordinalBindings.isEmpty()) {
78+
request.addArguments(
79+
value(Key.SQL_BIND),
80+
value(ordinalBindings)
81+
);
82+
}
83+
if (!namedBindings.isEmpty()) {
84+
request.addArguments(
85+
value(Key.SQL_BIND),
86+
value(namedBindings)
87+
);
88+
}
89+
return request;
90+
}
91+
92+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package org.tarantool.dsl;
2+
3+
import static org.tarantool.TarantoolRequestArgumentFactory.cacheLookupValue;
4+
import static org.tarantool.TarantoolRequestArgumentFactory.value;
5+
6+
import org.tarantool.Code;
7+
import org.tarantool.Key;
8+
import org.tarantool.TarantoolRequest;
9+
import org.tarantool.schema.TarantoolSchemaMeta;
10+
11+
import java.util.ArrayList;
12+
import java.util.Arrays;
13+
import java.util.Collection;
14+
import java.util.Collections;
15+
import java.util.List;
16+
17+
public class InsertOrReplaceRequestSpec extends SpaceRequestSpec<InsertOrReplaceRequestSpec> {
18+
19+
public enum Mode {
20+
INSERT(Code.INSERT),
21+
REPLACE(Code.REPLACE);
22+
23+
final Code code;
24+
25+
Mode(Code code) {
26+
this.code = code;
27+
}
28+
29+
public Code getCode() {
30+
return code;
31+
}
32+
}
33+
34+
private List<Object> tuple;
35+
36+
InsertOrReplaceRequestSpec(Mode mode, int spaceId, List<?> tuple) {
37+
super(mode.getCode(), spaceId);
38+
this.tuple = new ArrayList<>(tuple);
39+
}
40+
41+
InsertOrReplaceRequestSpec(Mode mode, String spaceName, List<?> tuple) {
42+
super(mode.getCode(), spaceName);
43+
this.tuple = new ArrayList<>(tuple);
44+
}
45+
46+
InsertOrReplaceRequestSpec(Mode mode, int spaceId, Object... tupleItems) {
47+
super(mode.getCode(), spaceId);
48+
this.tuple = Arrays.asList(tupleItems);
49+
}
50+
51+
InsertOrReplaceRequestSpec(Mode mode, String spaceName, Object... tupleItems) {
52+
super(mode.getCode(), spaceName);
53+
this.tuple = Arrays.asList(tupleItems);
54+
}
55+
56+
public InsertOrReplaceRequestSpec tuple(Object... tupleItems) {
57+
this.tuple.clear();
58+
Collections.addAll(this.tuple, tupleItems);
59+
return this;
60+
}
61+
62+
public InsertOrReplaceRequestSpec tuple(Collection<?> tuple) {
63+
this.tuple.clear();
64+
this.tuple.addAll(tuple);
65+
return this;
66+
}
67+
68+
@Override
69+
public TarantoolRequest toTarantoolRequest(TarantoolSchemaMeta schemaMeta) {
70+
TarantoolRequest request = super.toTarantoolRequest(schemaMeta);
71+
request.addArguments(
72+
value(Key.SPACE),
73+
spaceId == null
74+
? cacheLookupValue(() -> schemaMeta.getSpace(spaceName).getId())
75+
: value(spaceId),
76+
value(Key.TUPLE), value(tuple)
77+
);
78+
return request;
79+
}
80+
81+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package org.tarantool.dsl;
2+
3+
import java.util.Arrays;
4+
import java.util.List;
5+
6+
public class Operation {
7+
8+
private final Operator operator;
9+
private final List<Object> operands;
10+
11+
public Operation(Operator operator, Object... operands) {
12+
this.operator = operator;
13+
this.operands = Arrays.asList(operands);
14+
}
15+
16+
public Operator getOperator() {
17+
return operator;
18+
}
19+
20+
public Object[] toArray() {
21+
Object[] array = new Object[operands.size() + 1];
22+
array[0] = operator.getOpCode();
23+
for (int i = 1; i < array.length; i++) {
24+
array[i] = operands.get(i - 1);
25+
}
26+
return array;
27+
}
28+
29+
/**
30+
* It's used to perform a transformation between raw type
31+
* and type safe DSL Operation class. This is required
32+
* because of being compatible with old operations interface
33+
* and a new DSL approach.
34+
*
35+
* This client expects an operation in format of simple
36+
* array or list like {opCode, args...}. For instance,
37+
* addition 3 to second field will be {"+", 2, 3}
38+
*
39+
* @param operation raw operation
40+
*
41+
* @return type safe operation
42+
*/
43+
public static Operation fromArray(Object operation) {
44+
try {
45+
if (operation instanceof Object[]) {
46+
Object[] opArray = (Object[]) operation;
47+
String code = opArray[0].toString();
48+
Object[] args = new Object[opArray.length - 1];
49+
System.arraycopy(opArray, 1, args, 0, args.length);
50+
return new Operation(Operator.byOpCode(code), args);
51+
}
52+
List<?> opList = (List<?>) operation;
53+
String code = opList.get(0).toString();
54+
Object[] args = opList.subList(1, opList.size()).toArray();
55+
return new Operation(Operator.byOpCode(code), args);
56+
} catch (Exception cause) {
57+
throw new IllegalArgumentException(
58+
"Operation is invalid. Use an array or list as {\"opCode\", args...}. " +
59+
"Or use request DSL to build type safe operation.",
60+
cause
61+
);
62+
}
63+
}
64+
65+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package org.tarantool.dsl;
2+
3+
import java.util.Objects;
4+
5+
public class Operations {
6+
7+
public static Operation add(int fieldNumber, long value) {
8+
return new Operation(Operator.ADDITION, fieldNumber, value);
9+
}
10+
11+
public static Operation subtract(int fieldNumber, long value) {
12+
return new Operation(Operator.SUBTRACTION, fieldNumber, value);
13+
}
14+
15+
public static Operation bitwiseAnd(int fieldNumber, long value) {
16+
return new Operation(Operator.BITWISE_AND, fieldNumber, value);
17+
}
18+
19+
public static Operation bitwiseOr(int fieldNumber, long value) {
20+
return new Operation(Operator.BITWISE_OR, fieldNumber, value);
21+
}
22+
23+
public static Operation bitwiseXor(int fieldNumber, long value) {
24+
return new Operation(Operator.BITWISE_XOR, fieldNumber, value);
25+
}
26+
27+
public static Operation splice(int fieldNumber, int position, int offset, String substitution) {
28+
return new Operation(Operator.SPLICE, fieldNumber, position, offset, substitution);
29+
}
30+
31+
public static Operation insert(int fieldNumber, Object value) {
32+
return new Operation(Operator.INSERT, fieldNumber, value);
33+
}
34+
35+
public static Operation delete(int fromField, int length) {
36+
return new Operation(Operator.DELETE, fromField, length);
37+
}
38+
39+
public static Operation assign(int fieldNumber, Object value) {
40+
return new Operation(Operator.ASSIGN, fieldNumber, value);
41+
}
42+
43+
private static Operation createOperation(Operator operator, int fieldNumber, Object value) {
44+
Objects.requireNonNull(value);
45+
return new Operation(operator, fieldNumber, value);
46+
}
47+
48+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package org.tarantool.dsl;
2+
3+
import java.util.stream.Stream;
4+
5+
public enum Operator {
6+
ADDITION("+"),
7+
SUBTRACTION("-"),
8+
BITWISE_AND("&"),
9+
BITWISE_OR("|"),
10+
BITWISE_XOR("^"),
11+
SPLICE(":"),
12+
INSERT("!"),
13+
DELETE("#"),
14+
ASSIGN("=");
15+
16+
private final String opCode;
17+
18+
Operator(String opCode) {
19+
this.opCode = opCode;
20+
}
21+
22+
public String getOpCode() {
23+
return opCode;
24+
}
25+
26+
public static Operator byOpCode(String opCode) {
27+
return Stream.of(Operator.values())
28+
.filter(s -> s.getOpCode().equals(opCode))
29+
.findFirst()
30+
.orElseThrow(IllegalArgumentException::new);
31+
}
32+
33+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package org.tarantool.dsl;
2+
3+
import org.tarantool.Code;
4+
5+
public class PingRequestSpec extends AbstractRequestSpec<PingRequestSpec> {
6+
7+
PingRequestSpec() {
8+
super(Code.PING);
9+
}
10+
11+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package org.tarantool.dsl;
2+
3+
import org.tarantool.dsl.InsertOrReplaceRequestSpec.Mode;
4+
5+
import java.util.List;
6+
7+
/**
8+
* Entry point to build requests
9+
* using DSL approach a.k.a Request DSL.
10+
*/
11+
public class Requests {
12+
13+
public static SelectRequestSpec selectRequest(int space, int index) {
14+
return new SelectRequestSpec(space, index);
15+
}
16+
17+
public static SelectRequestSpec selectRequest(String space, int index) {
18+
return new SelectRequestSpec(space, index);
19+
}
20+
21+
public static SelectRequestSpec selectRequest(int space, String index) {
22+
return new SelectRequestSpec(space, index);
23+
}
24+
25+
public static SelectRequestSpec selectRequest(String space, String index) {
26+
return new SelectRequestSpec(space, index);
27+
}
28+
29+
public static InsertOrReplaceRequestSpec insertRequest(int space, List<?> tuple) {
30+
return new InsertOrReplaceRequestSpec(Mode.INSERT, space, tuple);
31+
}
32+
33+
public static InsertOrReplaceRequestSpec insertRequest(int space, Object... tupleItems) {
34+
return new InsertOrReplaceRequestSpec(Mode.INSERT, space, tupleItems);
35+
}
36+
37+
public static InsertOrReplaceRequestSpec insertRequest(String space, List<?> tuple) {
38+
return new InsertOrReplaceRequestSpec(Mode.INSERT, space, tuple);
39+
}
40+
41+
public static InsertOrReplaceRequestSpec insertRequest(String space, Object... tupleItems) {
42+
return new InsertOrReplaceRequestSpec(Mode.INSERT, space, tupleItems);
43+
}
44+
45+
public static InsertOrReplaceRequestSpec replaceRequest(int space, List<?> tuple) {
46+
return new InsertOrReplaceRequestSpec(Mode.REPLACE, space, tuple);
47+
}
48+
49+
public static InsertOrReplaceRequestSpec replaceRequest(int space, Object... tupleItems) {
50+
return new InsertOrReplaceRequestSpec(Mode.REPLACE, space, tupleItems);
51+
}
52+
53+
public static InsertOrReplaceRequestSpec replaceRequest(String space, List<?> tuple) {
54+
return new InsertOrReplaceRequestSpec(Mode.REPLACE, space, tuple);
55+
}
56+
57+
public static InsertOrReplaceRequestSpec replaceRequest(String space, Object... tupleItems) {
58+
return new InsertOrReplaceRequestSpec(Mode.REPLACE, space, tupleItems);
59+
}
60+
61+
public static UpdateRequestSpec updateRequest(int space, List<?> key, Operation... operations) {
62+
return new UpdateRequestSpec(space, key, operations);
63+
}
64+
65+
public static UpdateRequestSpec updateRequest(String space, List<?> key, Operation... operations) {
66+
return new UpdateRequestSpec(space, key, operations);
67+
}
68+
69+
public static UpsertRequestSpec upsertRequest(int space, List<?> key, List<?> tuple, Operation... operations) {
70+
return new UpsertRequestSpec(space, key, tuple, operations);
71+
}
72+
73+
public static UpsertRequestSpec upsertRequest(String space, List<?> key, List<?> tuple, Operation... operations) {
74+
return new UpsertRequestSpec(space, key, tuple, operations);
75+
}
76+
77+
public static DeleteRequestSpec deleteRequest(int space, List<?> key) {
78+
return new DeleteRequestSpec(space, key);
79+
}
80+
81+
public static DeleteRequestSpec deleteRequest(int space, Object... keyParts) {
82+
return new DeleteRequestSpec(space, keyParts);
83+
}
84+
85+
public static DeleteRequestSpec deleteRequest(String space, List<?> key) {
86+
return new DeleteRequestSpec(space, key);
87+
}
88+
89+
public static DeleteRequestSpec deleteRequest(String space, Object... keyParts) {
90+
return new DeleteRequestSpec(space, keyParts);
91+
}
92+
93+
public static CallRequestSpec callRequest(String function) {
94+
return new CallRequestSpec(function);
95+
}
96+
97+
public static EvalRequestSpec evalRequest(String expression) {
98+
return new EvalRequestSpec(expression);
99+
}
100+
101+
public static PingRequestSpec pingRequest() {
102+
return new PingRequestSpec();
103+
}
104+
105+
public static ExecuteRequestSpec executeRequest(String sql) {
106+
return new ExecuteRequestSpec(sql);
107+
}
108+
109+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
package org.tarantool.dsl;
2+
3+
import static org.tarantool.TarantoolRequestArgumentFactory.cacheLookupValue;
4+
import static org.tarantool.TarantoolRequestArgumentFactory.value;
5+
6+
import org.tarantool.Code;
7+
import org.tarantool.Iterator;
8+
import org.tarantool.Key;
9+
import org.tarantool.TarantoolRequest;
10+
import org.tarantool.schema.TarantoolSchemaMeta;
11+
12+
import java.util.ArrayList;
13+
import java.util.Collection;
14+
import java.util.Collections;
15+
import java.util.List;
16+
import java.util.Objects;
17+
18+
public class SelectRequestSpec extends SpaceRequestSpec<SelectRequestSpec> {
19+
20+
private Integer indexId;
21+
private String indexName;
22+
private List<Object> key = new ArrayList<>();
23+
private Iterator iterator = Iterator.ALL;
24+
private int offset = 0;
25+
private int limit = Integer.MAX_VALUE;
26+
27+
public SelectRequestSpec(int spaceId, int indexId) {
28+
super(Code.SELECT, spaceId);
29+
this.indexId = indexId;
30+
}
31+
32+
public SelectRequestSpec(int spaceId, String indexName) {
33+
super(Code.SELECT, spaceId);
34+
this.indexName = Objects.requireNonNull(indexName);
35+
}
36+
37+
public SelectRequestSpec(String spaceName, int indexId) {
38+
super(Code.SELECT, spaceName);
39+
this.indexId = indexId;
40+
}
41+
42+
public SelectRequestSpec(String spaceName, String indexName) {
43+
super(Code.SELECT, spaceName);
44+
this.indexName = Objects.requireNonNull(indexName);
45+
}
46+
47+
public SelectRequestSpec index(int indexId) {
48+
this.indexId = indexId;
49+
this.indexName = null;
50+
return this;
51+
}
52+
53+
public SelectRequestSpec index(String indexName) {
54+
this.indexName = Objects.requireNonNull(indexName);
55+
this.indexId = null;
56+
return this;
57+
}
58+
59+
public SelectRequestSpec key(Object... keyParts) {
60+
this.key.clear();
61+
Collections.addAll(this.key, keyParts);
62+
return this;
63+
}
64+
65+
public SelectRequestSpec key(Collection<?> key) {
66+
this.key.clear();
67+
this.key.addAll(key);
68+
return this;
69+
}
70+
71+
public SelectRequestSpec iterator(Iterator iterator) {
72+
this.iterator = iterator;
73+
return this;
74+
}
75+
76+
public SelectRequestSpec iterator(int iterator) {
77+
this.iterator = Iterator.valueOf(iterator);
78+
return this;
79+
}
80+
81+
public SelectRequestSpec offset(int offset) {
82+
this.offset = offset;
83+
return this;
84+
}
85+
86+
public SelectRequestSpec limit(int limit) {
87+
this.limit = limit;
88+
return this;
89+
}
90+
91+
@Override
92+
public TarantoolRequest toTarantoolRequest(TarantoolSchemaMeta schemaMeta) {
93+
TarantoolRequest request = super.toTarantoolRequest(schemaMeta);
94+
request.addArguments(
95+
value(Key.SPACE),
96+
spaceId == null
97+
? cacheLookupValue(() -> schemaMeta.getSpace(spaceName).getId())
98+
: value(spaceId),
99+
value(Key.INDEX),
100+
indexId == null
101+
? cacheLookupValue(() -> schemaMeta.getSpaceIndex(spaceName, indexName).getId())
102+
: value(indexId),
103+
value(Key.KEY), value(key),
104+
value(Key.ITERATOR), value(iterator.getValue()),
105+
value(Key.LIMIT), value(limit),
106+
value(Key.OFFSET), value(offset)
107+
);
108+
return request;
109+
}
110+
111+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package org.tarantool.dsl;
2+
3+
import org.tarantool.Code;
4+
5+
import java.util.Objects;
6+
7+
/**
8+
* Supports space related DSL builders.
9+
*
10+
* @param <B> current build type
11+
*/
12+
public abstract class SpaceRequestSpec<B extends SpaceRequestSpec<B>>
13+
extends AbstractRequestSpec<B> {
14+
15+
Integer spaceId;
16+
String spaceName;
17+
18+
public SpaceRequestSpec(Code code) {
19+
super(code);
20+
}
21+
22+
public SpaceRequestSpec(Code code, int spaceId) {
23+
this(code);
24+
this.spaceId = spaceId;
25+
}
26+
27+
public SpaceRequestSpec(Code code, String spaceName) {
28+
this(code);
29+
this.spaceName = Objects.requireNonNull(spaceName);
30+
}
31+
32+
@SuppressWarnings("unchecked")
33+
public B space(int spaceId) {
34+
this.spaceId = spaceId;
35+
this.spaceName = null;
36+
return (B) this;
37+
}
38+
39+
@SuppressWarnings("unchecked")
40+
public B space(String spaceName) {
41+
this.spaceName = Objects.requireNonNull(spaceName);
42+
this.spaceId = null;
43+
return (B) this;
44+
}
45+
46+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package org.tarantool.dsl;
2+
3+
import org.tarantool.TarantoolRequest;
4+
import org.tarantool.schema.TarantoolSchemaMeta;
5+
6+
/**
7+
* Used to convert DSL builder to appropriate
8+
* Tarantool requests.
9+
*
10+
* This interface is not a part of public API.
11+
*/
12+
public interface TarantoolRequestConvertible {
13+
14+
/**
15+
* Converts the target to {@link TarantoolRequest}.
16+
*
17+
* @return converted request
18+
*/
19+
TarantoolRequest toTarantoolRequest(TarantoolSchemaMeta schemaMeta);
20+
21+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package org.tarantool.dsl;
2+
3+
import static org.tarantool.TarantoolRequestArgumentFactory.cacheLookupValue;
4+
import static org.tarantool.TarantoolRequestArgumentFactory.value;
5+
6+
import org.tarantool.Code;
7+
import org.tarantool.Key;
8+
import org.tarantool.TarantoolRequest;
9+
import org.tarantool.schema.TarantoolSchemaMeta;
10+
11+
import java.util.ArrayList;
12+
import java.util.Arrays;
13+
import java.util.Collection;
14+
import java.util.Collections;
15+
import java.util.List;
16+
import java.util.stream.Collectors;
17+
18+
public class UpdateRequestSpec extends SpaceRequestSpec<UpdateRequestSpec> {
19+
20+
private List<Object> key;
21+
private List<Operation> operations;
22+
23+
public UpdateRequestSpec(int spaceId, List<?> key, Operation... operations) {
24+
super(Code.UPDATE, spaceId);
25+
this.key = new ArrayList<>(key);
26+
this.operations = Arrays.asList(operations);
27+
}
28+
29+
public UpdateRequestSpec(String spaceName, List<?> key, Operation... operations) {
30+
super(Code.UPDATE, spaceName);
31+
this.key = new ArrayList<>(key);
32+
this.operations = Arrays.asList(operations);
33+
}
34+
35+
public UpdateRequestSpec primaryKey(Object... keyParts) {
36+
this.key.clear();
37+
Collections.addAll(this.key, keyParts);
38+
return this;
39+
}
40+
41+
public UpdateRequestSpec primaryKey(Collection<?> key) {
42+
this.key.clear();
43+
this.key.addAll(key);
44+
return this;
45+
}
46+
47+
public UpdateRequestSpec operations(Operation... operations) {
48+
this.operations.clear();
49+
Collections.addAll(this.operations, operations);
50+
return this;
51+
}
52+
53+
public UpdateRequestSpec operations(Collection<? extends Operation> operations) {
54+
this.operations.clear();
55+
this.operations.addAll(operations);
56+
return this;
57+
}
58+
59+
@Override
60+
public TarantoolRequest toTarantoolRequest(TarantoolSchemaMeta schemaMeta) {
61+
TarantoolRequest request = super.toTarantoolRequest(schemaMeta);
62+
request.addArguments(
63+
value(Key.SPACE),
64+
spaceId == null
65+
? cacheLookupValue(() -> schemaMeta.getSpace(spaceName).getId())
66+
: value(spaceId),
67+
value(Key.KEY), value(key),
68+
value(Key.TUPLE), value(operations.stream().map(Operation::toArray).collect(Collectors.toList()))
69+
);
70+
return request;
71+
}
72+
73+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package org.tarantool.dsl;
2+
3+
import static org.tarantool.TarantoolRequestArgumentFactory.cacheLookupValue;
4+
import static org.tarantool.TarantoolRequestArgumentFactory.value;
5+
6+
import org.tarantool.Code;
7+
import org.tarantool.Key;
8+
import org.tarantool.TarantoolRequest;
9+
import org.tarantool.schema.TarantoolSchemaMeta;
10+
11+
import java.util.ArrayList;
12+
import java.util.Arrays;
13+
import java.util.Collection;
14+
import java.util.Collections;
15+
import java.util.List;
16+
import java.util.stream.Collectors;
17+
18+
public class UpsertRequestSpec extends SpaceRequestSpec<UpsertRequestSpec> {
19+
20+
private List<Object> key;
21+
private List<Object> tuple;
22+
private List<Operation> operations;
23+
24+
public UpsertRequestSpec(int spaceId, List<?> key, List<?> tuple, Operation... operations) {
25+
super(Code.UPSERT, spaceId);
26+
this.key = new ArrayList<>(key);
27+
this.tuple = new ArrayList<>(tuple);
28+
this.operations = Arrays.asList(operations);
29+
}
30+
31+
public UpsertRequestSpec(String spaceName, List<?> key, List<?> tuple, Operation... operations) {
32+
super(Code.UPSERT, spaceName);
33+
this.key = new ArrayList<>(key);
34+
this.tuple = new ArrayList<>(tuple);
35+
this.operations = Arrays.asList(operations);
36+
}
37+
38+
public UpsertRequestSpec primaryKey(Object... keyParts) {
39+
this.key.clear();
40+
Collections.addAll(this.key, keyParts);
41+
return this;
42+
}
43+
44+
public UpsertRequestSpec primaryKey(Collection<?> key) {
45+
this.key.clear();
46+
this.key.addAll(key);
47+
return this;
48+
}
49+
50+
public UpsertRequestSpec tuple(Collection<?> tuple) {
51+
this.tuple.clear();
52+
this.tuple.addAll(tuple);
53+
return this;
54+
}
55+
56+
public UpsertRequestSpec tuple(Object... tupleItems) {
57+
this.tuple.clear();
58+
Collections.addAll(this.tuple, tupleItems);
59+
return this;
60+
}
61+
62+
public UpsertRequestSpec operations(Collection<? extends Operation> operations) {
63+
this.operations.clear();
64+
this.operations.addAll(operations);
65+
return this;
66+
}
67+
68+
public UpsertRequestSpec operations(Operation... operations) {
69+
this.operations.clear();
70+
Collections.addAll(this.operations, operations);
71+
return this;
72+
}
73+
74+
@Override
75+
public TarantoolRequest toTarantoolRequest(TarantoolSchemaMeta schemaMeta) {
76+
TarantoolRequest request = super.toTarantoolRequest(schemaMeta);
77+
request.addArguments(
78+
value(Key.SPACE),
79+
spaceId == null
80+
? cacheLookupValue(() -> schemaMeta.getSpace(spaceName).getId())
81+
: value(spaceId),
82+
value(Key.KEY), value(key),
83+
value(Key.TUPLE), value(tuple),
84+
value(Key.UPSERT_OPS), value(operations.stream().map(Operation::toArray).collect(Collectors.toList()))
85+
);
86+
return request;
87+
}
88+
}

‎src/test/java/org/tarantool/ClientAsyncOperationsIT.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import static org.junit.jupiter.api.Assertions.assertTrue;
88
import static org.tarantool.TestAssertions.checkRawTupleResult;
99

10+
import org.tarantool.dsl.TarantoolRequestConvertible;
1011
import org.tarantool.schema.TarantoolIndexNotFoundException;
1112
import org.tarantool.schema.TarantoolSpaceNotFoundException;
1213

@@ -550,6 +551,11 @@ public Future<List<?>> eval(String expression, Object... args) {
550551
return originOps.eval(expression, args).toCompletableFuture();
551552
}
552553

554+
@Override
555+
public Future<List<?>> execute(TarantoolRequestConvertible requestSpec) {
556+
return originOps.execute(requestSpec).toCompletableFuture();
557+
}
558+
553559
@Override
554560
public void ping() {
555561
originOps.ping();

0 commit comments

Comments
 (0)
Please sign in to comment.