Skip to content

Commit c91ff60

Browse files
committed
Experimental: Mapping save builder
1 parent 6e2225c commit c91ff60

10 files changed

Lines changed: 207 additions & 80 deletions

File tree

api/src/main/java/me/zort/sqllib/api/data/Row.java

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,36 @@
44

55
public class Row extends HashMap<String, Object> {
66

7-
// TODO
7+
public String getString(String key) {
8+
return (String) get(key);
9+
}
10+
11+
public int getInt(String key) {
12+
return (int) get(key);
13+
}
14+
15+
public long getLong(String key) {
16+
return (long) get(key);
17+
}
18+
19+
public double getDouble(String key) {
20+
return (double) get(key);
21+
}
22+
23+
public float getFloat(String key) {
24+
return (float) get(key);
25+
}
26+
27+
public boolean getBoolean(String key) {
28+
return (boolean) get(key);
29+
}
30+
31+
public byte getByte(String key) {
32+
return (byte) get(key);
33+
}
34+
35+
public short getShort(String key) {
36+
return (short) get(key);
37+
}
838

939
}

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

Lines changed: 93 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -146,74 +146,6 @@ public <T> T createMapping(Class<T> mappingInterface) {
146146
});
147147
}
148148

149-
/**
150-
* @see SQLDatabaseConnection#save(String, Object)
151-
*/
152-
@Override
153-
public QueryResult save(String table, Object obj) { // by default, it creates and upsert request.
154-
Pair<String[], UnknownValueWrapper[]> defsValsPair = buildDefsVals(obj);
155-
if(defsValsPair == null) {
156-
return new QueryResultImpl(false);
157-
}
158-
159-
String[] defs = defsValsPair.getFirst();
160-
UnknownValueWrapper[] vals = defsValsPair.getSecond();
161-
162-
UpsertQuery upsert = upsert().into(table, defs);
163-
for(UnknownValueWrapper wrapper : vals) {
164-
upsert.appendVal(wrapper.getObject());
165-
}
166-
167-
SetStatement<InsertQuery> setStmt = upsert.onDuplicateKey();
168-
for(int i = 0; i < defs.length; i++) {
169-
setStmt.and(defs[i], vals[i].getObject());
170-
}
171-
172-
return setStmt.execute();
173-
}
174-
175-
@SuppressWarnings("unchecked")
176-
@Nullable
177-
protected Pair<String[], UnknownValueWrapper[]> buildDefsVals(Object obj) {
178-
Objects.requireNonNull(obj);
179-
180-
Class<?> aClass = obj.getClass();
181-
182-
Map<String, Object> fields = new HashMap<>();
183-
for(Field field : aClass.getDeclaredFields()) {
184-
185-
if(Modifier.isTransient(field.getModifiers())) {
186-
// Transient fields are ignored.
187-
continue;
188-
}
189-
190-
try {
191-
field.setAccessible(true);
192-
Object o = field.get(obj);
193-
if(field.isAnnotationPresent(JsonField.class)) {
194-
o = options.getGson().toJson(o);
195-
} else if(Validator.validateAutoIncrement(field) && field.get(obj) == null) {
196-
// If field is PrimaryKey and autoIncrement true and is null,
197-
// We will skip this to use auto increment strategy on SQL server.
198-
continue;
199-
}
200-
fields.put(options.getNamingStrategy().fieldNameToColumn(field.getName()), o);
201-
} catch (IllegalAccessException e) {
202-
e.printStackTrace();
203-
return null;
204-
}
205-
}
206-
// I make entry array for indexing safety.
207-
Map.Entry<String, Object>[] entryArray = fields.entrySet().toArray(new Map.Entry[0]);
208-
String[] defs = new String[entryArray.length];
209-
UnknownValueWrapper[] vals = new UnknownValueWrapper[entryArray.length];
210-
for(int i = 0; i < entryArray.length; i++) {
211-
defs[i] = entryArray[i].getKey();
212-
vals[i] = new UnknownValueWrapper(entryArray[i].getValue());
213-
}
214-
return new Pair<>(defs, vals);
215-
}
216-
217149
/**
218150
* @see SQLDatabaseConnection#query(Query, Class)
219151
*/
@@ -280,6 +212,76 @@ public QueryResult exec(Query query) {
280212
}
281213
}
282214

215+
/**
216+
* @see SQLDatabaseConnection#save(String, Object)
217+
*/
218+
@Override
219+
public QueryResult save(String table, Object obj) { // by default, it creates and upsert request.
220+
Pair<String[], UnknownValueWrapper[]> data = buildDefsVals(obj);
221+
222+
if(data == null) {
223+
return new QueryResultImpl(false);
224+
}
225+
226+
return save(obj).table(table).execute();
227+
}
228+
229+
public QueryResult insert(String table, Object obj) {
230+
Pair<String[], UnknownValueWrapper[]> data = buildDefsVals(obj);
231+
232+
if (data == null)
233+
return new QueryResultImpl(false);
234+
235+
InsertQuery query = insert().into(table, data.getFirst());
236+
for (UnknownValueWrapper valueWrapper : data.getSecond()) {
237+
query.appendVal(valueWrapper.getObject());
238+
}
239+
240+
return query.execute();
241+
}
242+
243+
@SuppressWarnings("unchecked")
244+
@Nullable
245+
protected Pair<String[], UnknownValueWrapper[]> buildDefsVals(Object obj) {
246+
Objects.requireNonNull(obj);
247+
248+
Class<?> aClass = obj.getClass();
249+
250+
Map<String, Object> fields = new HashMap<>();
251+
for(Field field : aClass.getDeclaredFields()) {
252+
253+
if(Modifier.isTransient(field.getModifiers())) {
254+
// Transient fields are ignored.
255+
continue;
256+
}
257+
258+
try {
259+
field.setAccessible(true);
260+
Object o = field.get(obj);
261+
if(field.isAnnotationPresent(JsonField.class)) {
262+
o = options.getGson().toJson(o);
263+
} else if(Validator.validateAutoIncrement(field) && field.get(obj) == null) {
264+
// If field is PrimaryKey and autoIncrement true and is null,
265+
// We will skip this to use auto increment strategy on SQL server.
266+
continue;
267+
}
268+
fields.put(options.getNamingStrategy().fieldNameToColumn(field.getName()), o);
269+
} catch (IllegalAccessException e) {
270+
e.printStackTrace();
271+
return null;
272+
}
273+
}
274+
// I make entry array for indexing safety.
275+
Map.Entry<String, Object>[] entryArray = fields.entrySet().toArray(new Map.Entry[0]);
276+
String[] defs = new String[entryArray.length];
277+
UnknownValueWrapper[] vals = new UnknownValueWrapper[entryArray.length];
278+
for(int i = 0; i < entryArray.length; i++) {
279+
defs[i] = entryArray[i].getKey();
280+
vals[i] = new UnknownValueWrapper(entryArray[i].getValue());
281+
}
282+
return new Pair<>(defs, vals);
283+
}
284+
283285
private boolean handleAutoReconnect() {
284286
if(options.isAutoReconnect() && !isConnected()) {
285287
debug("Trying to make a new connection with the database!");
@@ -323,6 +325,29 @@ public DeleteQuery delete() {
323325
return new DeleteQuery(this);
324326
}
325327

328+
public UpsertQuery save(Object obj) {
329+
Pair<String[], UnknownValueWrapper[]> data = buildDefsVals(obj);
330+
331+
if(data == null) {
332+
return null;
333+
}
334+
335+
String[] defs = data.getFirst();
336+
UnknownValueWrapper[] vals = data.getSecond();
337+
338+
UpsertQuery upsert = upsert().into(null, defs);
339+
for(UnknownValueWrapper wrapper : vals) {
340+
upsert.appendVal(wrapper.getObject());
341+
}
342+
343+
SetStatement<InsertQuery> setStmt = upsert.onDuplicateKey();
344+
for(int i = 0; i < defs.length; i++) {
345+
setStmt.and(defs[i], vals[i].getObject());
346+
}
347+
348+
return (UpsertQuery) setStmt.getAncestor();
349+
}
350+
326351
public void debug(String message) {
327352
if(options.isDebug()) {
328353
System.out.println(message);

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,12 @@ public InsertQuery(@Nullable SQLDatabaseConnection connection, @Nullable String
3535
}
3636

3737
public InsertQuery into(String table, String... defs) {
38-
this.table = table;
3938
this.defs = defs;
39+
return table(table);
40+
}
41+
42+
public InsertQuery table(String table) {
43+
this.table = table;
4044
return this;
4145
}
4246

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ public UpsertQuery into(String table, String... defs) {
2121
return (UpsertQuery) super.into(table, defs);
2222
}
2323

24+
@Override
25+
public UpsertQuery table(String table) {
26+
return (UpsertQuery) super.table(table);
27+
}
28+
2429
@Override
2530
public UpsertQuery values(Object... values) {
2631
return (UpsertQuery) super.values(values);

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

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@
33
import lombok.AccessLevel;
44
import lombok.Getter;
55
import lombok.RequiredArgsConstructor;
6+
import me.zort.sqllib.api.SQLConnection;
67
import me.zort.sqllib.internal.query.QueryNode;
7-
import me.zort.sqllib.mapping.annotation.Delete;
8-
import me.zort.sqllib.mapping.annotation.Select;
9-
import me.zort.sqllib.mapping.annotation.Table;
10-
import me.zort.sqllib.mapping.annotation.Where;
8+
import me.zort.sqllib.mapping.annotation.*;
119
import me.zort.sqllib.mapping.builder.DeleteQueryBuilder;
10+
import me.zort.sqllib.mapping.builder.SaveQueryBuilder;
1211
import me.zort.sqllib.mapping.builder.SelectQueryBuilder;
1312
import me.zort.sqllib.mapping.exception.SQLMappingException;
1413
import me.zort.sqllib.util.ParameterPair;
@@ -24,6 +23,8 @@
2423
* mapping proxy. Query that is wrapped appears on abstract methods
2524
* of the proxy instance created using:
2625
* {@link me.zort.sqllib.SQLDatabaseConnection#createMapping(Class)}
26+
*
27+
* @author ZorTik
2728
*/
2829
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
2930
@Getter
@@ -38,6 +39,7 @@ public class QueryAnnotation {
3839
static {
3940
QUERY_ANNOT.put(Select.class, new QueryAnnotation(true, new SelectQueryBuilder()));
4041
QUERY_ANNOT.put(Delete.class, new QueryAnnotation(false, new DeleteQueryBuilder()));
42+
QUERY_ANNOT.put(Save.class, new QueryAnnotation(false, new SaveQueryBuilder()));
4143
// TODO: Populate
4244
}
4345

@@ -59,7 +61,8 @@ public static boolean isQueryAnnotation(Class<? extends Annotation> annotation)
5961
* method annotations and parameters, to be executed by {@link DefaultStatementMapping}.
6062
*/
6163
public interface QueryBuilder<T extends Annotation> {
62-
QueryNode<?> build(T queryAnnotation, Method method, ParameterPair[] parameters);
64+
65+
QueryNode<?> build(SQLConnection connection, T queryAnnotation, Method method, ParameterPair[] parameters);
6366
}
6467

6568
public static class Validator {
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
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 Save {
11+
}

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

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

3+
import me.zort.sqllib.api.SQLConnection;
34
import me.zort.sqllib.internal.query.Conditional;
45
import me.zort.sqllib.internal.query.DeleteQuery;
56
import me.zort.sqllib.internal.query.Limitable;
@@ -16,7 +17,7 @@
1617

1718
public class DeleteQueryBuilder implements QueryAnnotation.QueryBuilder<Delete> {
1819
@Override
19-
public QueryNode<?> build(Delete queryAnnotation, Method method, ParameterPair[] parameters) {
20+
public QueryNode<?> build(SQLConnection connection, Delete queryAnnotation, Method method, ParameterPair[] parameters) {
2021
PlaceholderMapper placeholderMapper = new PlaceholderMapper(parameters);
2122
QueryAnnotation.Validator.requireTableDefinition(method, placeholderMapper);
2223
String table = Table.Util.getFromContext(method, placeholderMapper);
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package me.zort.sqllib.mapping.builder;
2+
3+
import com.google.gson.internal.Primitives;
4+
import me.zort.sqllib.SQLDatabaseConnectionImpl;
5+
import me.zort.sqllib.api.SQLConnection;
6+
import me.zort.sqllib.internal.query.QueryNode;
7+
import me.zort.sqllib.internal.query.UpsertQuery;
8+
import me.zort.sqllib.mapping.PlaceholderMapper;
9+
import me.zort.sqllib.mapping.QueryAnnotation;
10+
import me.zort.sqllib.mapping.annotation.Save;
11+
import me.zort.sqllib.mapping.annotation.Table;
12+
import me.zort.sqllib.util.ParameterPair;
13+
14+
import java.lang.reflect.Method;
15+
16+
public class SaveQueryBuilder implements QueryAnnotation.QueryBuilder<Save> {
17+
@Override
18+
public QueryNode<?> build(SQLConnection connection, Save queryAnnotation, Method method, ParameterPair[] parameters) {
19+
if (!(connection instanceof SQLDatabaseConnectionImpl))
20+
throw new IllegalArgumentException("The connection must be an instance of SQLDatabaseConnectionImpl");
21+
22+
PlaceholderMapper placeholderMapper = new PlaceholderMapper(parameters);
23+
QueryAnnotation.Validator.requireTableDefinition(method, placeholderMapper);
24+
String table = Table.Util.getFromContext(method, placeholderMapper);
25+
26+
UpsertQuery query = ((SQLDatabaseConnectionImpl) connection).save(getSaveableObject(parameters));
27+
query.table(table);
28+
29+
return query;
30+
}
31+
32+
private static Object getSaveableObject(ParameterPair[] parameters) {
33+
for (ParameterPair parameter : parameters) {
34+
Class<?> aClass = parameter.getValue().getClass();
35+
if (!Primitives.isWrapperType(Primitives.wrap(aClass)))
36+
return parameter.getValue();
37+
}
38+
39+
throw new IllegalArgumentException("No object to save found in paramaters!");
40+
}
41+
}

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

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

3+
import me.zort.sqllib.api.SQLConnection;
34
import me.zort.sqllib.internal.query.Conditional;
45
import me.zort.sqllib.internal.query.Limitable;
56
import me.zort.sqllib.internal.query.QueryNode;
@@ -18,7 +19,7 @@
1819

1920
public class SelectQueryBuilder implements QueryAnnotation.QueryBuilder<Select> {
2021
@Override
21-
public QueryNode<?> build(Select queryAnnotation, Method method, ParameterPair[] parameters) {
22+
public QueryNode<?> build(SQLConnection connection, Select queryAnnotation, Method method, ParameterPair[] parameters) {
2223
PlaceholderMapper placeholderMapper = new PlaceholderMapper(parameters);
2324
QueryAnnotation.Validator.requireTableDefinition(method, placeholderMapper);
2425
String table = Table.Util.getFromContext(method, placeholderMapper);

0 commit comments

Comments
 (0)