Skip to content

Commit d8817da

Browse files
authored
Merge pull request #12 from ZorTik/development
Development
2 parents bf62d20 + ecd336b commit d8817da

13 files changed

Lines changed: 192 additions & 26 deletions

File tree

core/src/main/java/me/zort/sqllib/SQLConnectionBuilder.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,15 @@ public SQLConnectionBuilder withDriver(String driver) {
7878
return this;
7979
}
8080

81-
public SQLDatabaseConnectionImpl build() {
81+
public SQLDatabaseConnection build() {
8282
return build(null);
8383
}
8484

85-
public SQLDatabaseConnectionImpl build(@Nullable SQLDatabaseOptions options) {
85+
public SQLDatabaseConnection build(@Nullable SQLDatabaseOptions options) {
8686
return build(driver, options);
8787
}
8888

89-
public SQLDatabaseConnectionImpl build(@Nullable String driver, @Nullable SQLDatabaseOptions options) {
89+
public SQLDatabaseConnection build(@Nullable String driver, @Nullable SQLDatabaseOptions options) {
9090
Objects.requireNonNull(endpoint, "Endpoint must be set!");
9191
Objects.requireNonNull(jdbc);
9292
if(driver == null) {

core/src/main/java/me/zort/sqllib/SQLDatabaseConnection.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,37 @@ public SQLDatabaseConnection(SQLConnectionFactory connectionFactory) {
3333
SQLConnectionPool.register(this);
3434
}
3535

36+
/**
37+
* Constructs a mapping repository based on provided interface.
38+
* The interface should follow rules for creating mapping repositories
39+
* in this library.
40+
* <p>
41+
* Example:
42+
* <pre>
43+
* &#64;Table("users")
44+
* public interface MyRepository {
45+
* &#64;Select("*")
46+
* &#64;Where(&#64;Where.Condition(column = "firstname", value = "{First Name}"))
47+
* &#64;Limit(1)
48+
* Optional&lt;User&gt; getUser(&#64;Placeholder("First Name") String firstName);
49+
*
50+
* &#64;Select
51+
* List&lt;User&gt; getUsers();
52+
*
53+
* &#64;Delete
54+
* QueryResult deleteUsers();
55+
* }
56+
*
57+
* SQLDatabaseConnection connection = ...;
58+
* MyRepository repository = connection.createGate(MyRepository.class);
59+
*
60+
* Optional&lt;User&gt; user = repository.getUser("John");
61+
* </pre>
62+
*
63+
* @param mappingInterface Interface to create mapping repository for.
64+
* @return Mapping repository.
65+
* @param <T> Type of mapping repository.
66+
*/
3667
@ApiStatus.Experimental
3768
public abstract <T> T createGate(Class<T> mappingInterface);
3869

core/src/main/java/me/zort/sqllib/SQLDatabaseConnectionImpl.java

Lines changed: 80 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
*
4040
* @author ZorTik
4141
*/
42+
@SuppressWarnings("unused")
4243
public class SQLDatabaseConnectionImpl extends SQLDatabaseConnection {
4344

4445
// --***-- Default Constants --***--
@@ -123,14 +124,38 @@ public void setObjectMapper(@NotNull ObjectMapper objectMapper) {
123124
* Constructs a mapping repository based on provided interface.
124125
* The interface should follow rules for creating mapping repositories
125126
* in this library.
127+
* <p>
128+
* Example:
129+
* <pre>
130+
* &#64;Table("users")
131+
* public interface MyRepository {
132+
* &#64;Select("*")
133+
* &#64;Where(&#64;Where.Condition(column = "firstname", value = "{First Name}"))
134+
* &#64;Limit(1)
135+
* Optional&lt;User&gt; getUser(&#64;Placeholder("First Name") String firstName);
136+
*
137+
* &#64;Select
138+
* List&lt;User&gt; getUsers();
139+
*
140+
* &#64;Delete
141+
* QueryResult deleteUsers();
142+
* }
143+
*
144+
* SQLDatabaseConnection connection = ...;
145+
* MyRepository repository = connection.createGate(MyRepository.class);
146+
*
147+
* Optional&lt;User&gt; user = repository.getUser("John");
148+
* </pre>
126149
*
127150
* @param mappingInterface Interface to create mapping repository for.
128151
* @return Mapping repository.
129152
* @param <T> Type of mapping repository.
130153
*/
131154
@SuppressWarnings("unchecked")
132155
@ApiStatus.Experimental
133-
public <T> T createGate(Class<T> mappingInterface) {
156+
public final <T> T createGate(Class<T> mappingInterface) {
157+
Objects.requireNonNull(mappingInterface, "Mapping interface cannot be null!");
158+
134159
StatementMappingStrategy<T> statementMapping = mappingFactory.create(mappingInterface, this);
135160
return (T) Proxy.newProxyInstance(mappingInterface.getClassLoader(),
136161
new Class[]{mappingInterface}, (proxy, method, args) -> {
@@ -145,15 +170,35 @@ public <T> T createGate(Class<T> mappingInterface) {
145170
return mappingResultAdapter.adaptResult(method, result);
146171
}
147172

148-
return method.invoke(this, args);
173+
throw new UnsupportedOperationException("Method " + method.getName() + " is not supported by this mapping repository!");
149174
});
150175
}
151176

152177
/**
153-
* @see SQLDatabaseConnection#query(Query, Class)
178+
* Performs new query and returns the result. This result is never null.
179+
* See: {@link QueryRowsResult#isSuccessful()}
180+
*
181+
* Examples:
182+
* <p>
183+
* query(Select.of().from("players"), Player.class)
184+
* .stream()
185+
* .map(Player::getNickname)
186+
* .forEach(System.out::println);
187+
* <p>
188+
* query(() -> "SELECT * FROM players;");
189+
*
190+
* @param query The query to use while constructing query string.
191+
* @param typeClass Type class of object which will be instantiated and
192+
* populated with column values.
193+
* @param <T> Type of objects in result.
194+
*
195+
* @return Collection of row objects.
154196
*/
155197
@Override
156198
public <T> QueryRowsResult<T> query(Query query, Class<T> typeClass) {
199+
Objects.requireNonNull(query);
200+
Objects.requireNonNull(typeClass);
201+
157202
QueryRowsResult<Row> resultRows = query(query.getAncestor());
158203
QueryRowsResult<T> result = new QueryRowsResult<>(resultRows.isSuccessful());
159204

@@ -165,7 +210,9 @@ public <T> QueryRowsResult<T> query(Query query, Class<T> typeClass) {
165210
}
166211

167212
/**
168-
* @see SQLDatabaseConnectionImpl#query(Query, Class)
213+
* Performs new query and returns the result. This result is never null.
214+
*
215+
* @see SQLDatabaseConnection#query(Query, Class)
169216
*/
170217
@Override
171218
public QueryRowsResult<Row> query(Query query) {
@@ -200,7 +247,14 @@ public QueryRowsResult<Row> query(Query query) {
200247
}
201248

202249
/**
203-
* @see SQLDatabaseConnection#exec(Query)
250+
* Executes given query and returns execution result.
251+
* This result does not contain any rows. If you want to
252+
* execute query return result of rows, see method
253+
* {@link SQLDatabaseConnection#query(Query)}
254+
*
255+
* @param query Query to use for building query string.
256+
* @return Blank rows result that only informs
257+
* about success state of the request.
204258
*/
205259
public QueryResult exec(Query query) {
206260
if(!handleAutoReconnect()) {
@@ -216,7 +270,14 @@ public QueryResult exec(Query query) {
216270
}
217271

218272
/**
219-
* @see SQLDatabaseConnection#save(String, Object)
273+
* Saves this mapping object into database using upsert query.
274+
* <p>
275+
* All mapping strategies are described in:
276+
* {@link SQLDatabaseConnection#query(Query, Class)}.
277+
*
278+
* @param table Table to save into.
279+
* @param obj The object to save.
280+
* @return Result of the query.
220281
*/
221282
@Override
222283
public QueryResult save(String table, Object obj) { // by default, it creates and upsert request.
@@ -285,6 +346,7 @@ protected Pair<String[], UnknownValueWrapper[]> buildDefsVals(Object obj) {
285346
return new Pair<>(defs, vals);
286347
}
287348

349+
@SuppressWarnings("all")
288350
private boolean handleAutoReconnect() {
289351
if(options.isAutoReconnect() && !isConnected()) {
290352
debug("Trying to make a new connection with the database!");
@@ -296,6 +358,8 @@ private boolean handleAutoReconnect() {
296358
return true;
297359
}
298360

361+
// --***-- Query builders --***--
362+
299363
public SelectQuery select(String... cols) {
300364
return new SelectQuery(this, cols);
301365
}
@@ -367,6 +431,16 @@ public boolean isDebug() {
367431
return options.isDebug();
368432
}
369433

434+
public final SQLDatabaseOptions cloneOptions() {
435+
SQLDatabaseOptions cloned = new SQLDatabaseOptions();
436+
cloned.setDebug(options.isDebug());
437+
cloned.setLogSqlErrors(options.isLogSqlErrors());
438+
cloned.setNamingStrategy(options.getNamingStrategy());
439+
cloned.setGson(options.getGson());
440+
cloned.setAutoReconnect(options.isAutoReconnect());
441+
return cloned;
442+
}
443+
370444
@SuppressWarnings("unchecked")
371445
private PreparedStatement buildStatement(Query query) throws SQLException {
372446
StatementFactory<PreparedStatement> factory = new DefaultStatementFactory(query);

core/src/main/java/me/zort/sqllib/internal/query/QueryNode.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,15 @@ public QueryNode(@Nullable P parent, List<QueryNode<?>> initial, int priority) {
3636
this.details = new ConcurrentHashMap<>();
3737
}
3838

39+
/**
40+
* Builds the query string with placeholders containing values
41+
* for passing into PreparedStatement.
42+
* <p>
43+
* Query example: SELECT * FROM table WHERE id = &lt;id&gt;;
44+
* Values example: [AnyId]
45+
*
46+
* @return QueryDetails object.
47+
*/
3948
public abstract QueryDetails buildQueryDetails();
4049

4150
@Override

core/src/main/java/me/zort/sqllib/mapping/QueryAnnotation.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import me.zort.sqllib.internal.query.QueryNode;
88
import me.zort.sqllib.mapping.annotation.*;
99
import me.zort.sqllib.mapping.builder.DeleteQueryBuilder;
10+
import me.zort.sqllib.mapping.builder.InsertQueryBuilder;
1011
import me.zort.sqllib.mapping.builder.SaveQueryBuilder;
1112
import me.zort.sqllib.mapping.builder.SelectQueryBuilder;
1213
import me.zort.sqllib.mapping.exception.SQLMappingException;
@@ -40,6 +41,7 @@ public class QueryAnnotation {
4041
QUERY_ANNOT.put(Select.class, new QueryAnnotation(true, new SelectQueryBuilder()));
4142
QUERY_ANNOT.put(Delete.class, new QueryAnnotation(false, new DeleteQueryBuilder()));
4243
QUERY_ANNOT.put(Save.class, new QueryAnnotation(false, new SaveQueryBuilder()));
44+
QUERY_ANNOT.put(Insert.class, new QueryAnnotation(false, new InsertQueryBuilder()));
4345
// TODO: Populate
4446
}
4547

@@ -66,10 +68,6 @@ public interface QueryBuilder<T extends Annotation> {
6668
}
6769

6870
public static class Validator {
69-
public static void requireTableDefinition(Method method, PlaceholderMapper placeholderMapper) {
70-
if (Table.Util.getFromContext(method, placeholderMapper) == null)
71-
throw new SQLMappingException("Method " + method.getName() + " requires @Table annotation", method, null);
72-
}
7371
public static void requireWhereDefinition(Method method) {
7472
if (!method.isAnnotationPresent(Where.class))
7573
throw new SQLMappingException("Method " + method.getName() + " requires @Where annotation", method, null);
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package me.zort.sqllib.mapping.annotation;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.RetentionPolicy;
6+
import java.lang.annotation.Target;
7+
8+
@Retention(RetentionPolicy.RUNTIME)
9+
@Target(ElementType.METHOD)
10+
public @interface Insert {
11+
12+
String[] cols();
13+
String[] vals();
14+
15+
}

core/src/main/java/me/zort/sqllib/mapping/annotation/Table.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package me.zort.sqllib.mapping.annotation;
22

33
import me.zort.sqllib.mapping.PlaceholderMapper;
4+
import me.zort.sqllib.mapping.QueryAnnotation;
5+
import me.zort.sqllib.mapping.exception.SQLMappingException;
6+
import me.zort.sqllib.util.ParameterPair;
47
import org.jetbrains.annotations.Nullable;
58

69
import java.lang.annotation.ElementType;
@@ -16,13 +19,14 @@
1619

1720
class Util {
1821
@Nullable
19-
public static String getFromContext(Method method, PlaceholderMapper mapper) {
22+
public static String getFromContext(Method method, ParameterPair[] parameters) {
23+
PlaceholderMapper mapper = new PlaceholderMapper(parameters);
2024
if (method.isAnnotationPresent(Table.class)) {
2125
return mapper.assignValues(method.getAnnotation(Table.class).value());
2226
} else if(method.getDeclaringClass().isAnnotationPresent(Table.class)) {
2327
return mapper.assignValues(method.getDeclaringClass().getAnnotation(Table.class).value());
2428
} else {
25-
return null;
29+
throw new SQLMappingException("Method " + method.getName() + " requires @Table annotation", method, null);
2630
}
2731
}
2832
}

core/src/main/java/me/zort/sqllib/mapping/builder/DeleteQueryBuilder.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ public class DeleteQueryBuilder implements QueryAnnotation.QueryBuilder<Delete>
1919
@Override
2020
public QueryNode<?> build(SQLConnection connection, Delete queryAnnotation, Method method, ParameterPair[] parameters) {
2121
PlaceholderMapper placeholderMapper = new PlaceholderMapper(parameters);
22-
QueryAnnotation.Validator.requireTableDefinition(method, placeholderMapper);
23-
String table = Table.Util.getFromContext(method, placeholderMapper);
22+
String table = Table.Util.getFromContext(method, parameters);
2423

2524
QueryNode<?> node = new DeleteQuery(null, table);
2625
if (method.isAnnotationPresent(Where.class)) {
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package me.zort.sqllib.mapping.builder;
2+
3+
import me.zort.sqllib.SQLDatabaseConnection;
4+
import me.zort.sqllib.api.SQLConnection;
5+
import me.zort.sqllib.internal.query.InsertQuery;
6+
import me.zort.sqllib.internal.query.QueryNode;
7+
import me.zort.sqllib.mapping.PlaceholderMapper;
8+
import me.zort.sqllib.mapping.QueryAnnotation;
9+
import me.zort.sqllib.mapping.annotation.Insert;
10+
import me.zort.sqllib.mapping.annotation.Table;
11+
import me.zort.sqllib.util.ParameterPair;
12+
13+
import java.lang.reflect.Method;
14+
15+
public class InsertQueryBuilder implements QueryAnnotation.QueryBuilder<Insert> {
16+
@Override
17+
public QueryNode<?> build(SQLConnection connection, Insert queryAnnotation, Method method, ParameterPair[] parameters) {
18+
if (!(connection instanceof SQLDatabaseConnection))
19+
throw new IllegalArgumentException("The connection must be a SQLDatabaseConnection");
20+
21+
String table = Table.Util.getFromContext(method, parameters);
22+
InsertQuery query = ((SQLDatabaseConnection) connection).insert();
23+
query.into(table, queryAnnotation.cols());
24+
25+
PlaceholderMapper mapper = new PlaceholderMapper(parameters);
26+
27+
String[] vals = queryAnnotation.vals();
28+
for (int i = 0; i < vals.length; i++) {
29+
vals[i] = mapper.assignValues(vals[i]);
30+
}
31+
32+
query.values((Object[]) vals);
33+
return query;
34+
}
35+
}

core/src/main/java/me/zort/sqllib/mapping/builder/SaveQueryBuilder.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import me.zort.sqllib.api.SQLConnection;
66
import me.zort.sqllib.internal.query.QueryNode;
77
import me.zort.sqllib.internal.query.UpsertQuery;
8-
import me.zort.sqllib.mapping.PlaceholderMapper;
98
import me.zort.sqllib.mapping.QueryAnnotation;
109
import me.zort.sqllib.mapping.annotation.Save;
1110
import me.zort.sqllib.mapping.annotation.Table;
@@ -19,9 +18,7 @@ public QueryNode<?> build(SQLConnection connection, Save queryAnnotation, Method
1918
if (!(connection instanceof SQLDatabaseConnectionImpl))
2019
throw new IllegalArgumentException("The connection must be an instance of SQLDatabaseConnectionImpl");
2120

22-
PlaceholderMapper placeholderMapper = new PlaceholderMapper(parameters);
23-
QueryAnnotation.Validator.requireTableDefinition(method, placeholderMapper);
24-
String table = Table.Util.getFromContext(method, placeholderMapper);
21+
String table = Table.Util.getFromContext(method, parameters);
2522

2623
UpsertQuery query = ((SQLDatabaseConnectionImpl) connection).save(getSaveableObject(parameters));
2724
query.table(table);

0 commit comments

Comments
 (0)