Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
a5f488b
Incremented version to 1.0.2
JanHolger Nov 6, 2021
e316723
Update pom.xml
JulianFun123 Nov 8, 2021
b2290a5
Added parent class support for models.
x7airworker Nov 29, 2021
1aabe50
Added test case for non-abstract parent
x7airworker Nov 29, 2021
d9c3c2e
Added support for n amount of super classes
x7airworker Nov 30, 2021
1cace0b
Splitted table and column analysis into two methods
x7airworker Dec 2, 2021
c939910
Merge pull request #31 from JavaWebStack/feature/parentClass
JanHolger Dec 2, 2021
d46558d
Order of analyzeColumns and analyzeTable was wrong
x7airworker Dec 2, 2021
a6880f7
Merge pull request #32 from JavaWebStack/feature/parentClass
JanHolger Dec 2, 2021
a954e80
Added a fork() method to the SQL interface and implemented a thread l…
JanHolger Feb 14, 2022
a798304
Merge remote-tracking branch 'origin/dev' into dev
JanHolger Feb 14, 2022
75d8596
Added grouping for the Accessible in order to improve security.
JanHolger Mar 21, 2022
804d8aa
Fixed issue with empty where in combination with the accessible
JanHolger Mar 21, 2022
abe4f8b
Fixed issue with empty where in combination with the accessible
JanHolger Mar 21, 2022
4ea3b03
Fixed #34 (refresh throwing exception) and optimized imports
JanHolger May 1, 2022
a63f495
Merge remote-tracking branch 'origin/dev' into dev
JanHolger May 1, 2022
1b1a25c
Implemented #36 (don't render empty groups)
JanHolger May 1, 2022
9d146e8
Implemented #35 (render empty IN as 1=2)
JanHolger May 1, 2022
ce66dbe
Updated abstract-data to 1.0.2
JanHolger May 1, 2022
cf52c50
Fixed create not using the session system
JanHolger May 18, 2022
9f73d83
Added hotfix for missing braces in DefaultMapper and added support fo…
JanHolger Aug 13, 2022
309e612
Fixed data type for abstract data json mapper
JanHolger Aug 19, 2022
a0a1548
Upgraded abstract-data
JanHolger Oct 7, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 24 additions & 5 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<buildVersion>1.0.1-SNAPSHOT</buildVersion>
<buildVersion>1.0.2-SNAPSHOT</buildVersion>
</properties>

<groupId>org.javawebstack</groupId>
Expand All @@ -32,6 +32,18 @@
<organization>JavaWebStack</organization>
<organizationUrl>https://javawebstack.org</organizationUrl>
</developer>
<developer>
<name>Timothy Gillespie</name>
<email>timothy@gillespie.eu</email>
<organization>JavaWebStack</organization>
<organizationUrl>https://javawebstack.org</organizationUrl>
</developer>
<developer>
<name>Julian Gojani</name>
<email>julian@gojani.xyz</email>
<organization>JavaWebStack</organization>
<organizationUrl>https://javawebstack.org</organizationUrl>
</developer>
</developers>

<scm>
Expand All @@ -44,8 +56,15 @@
<dependency>
<groupId>org.javawebstack</groupId>
<artifactId>abstract-data</artifactId>
<version>1.0.0</version>
<version>1.0.4</version>
</dependency>
<!--- Temporary fix for transitive vulnerabilities -->
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.33</version>
</dependency>
<!--- ============================================ -->
<dependency>
<groupId>org.atteo</groupId>
<artifactId>evo-inflector</artifactId>
Expand All @@ -59,7 +78,7 @@
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.8.1</version>
<version>5.9.0</version>
<scope>test</scope>
</dependency>
<dependency>
Expand All @@ -71,13 +90,13 @@
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<version>1.18.24</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
<version>8.0.30</version>
<scope>test</scope>
</dependency>
</dependencies>
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/org/javawebstack/orm/Accessible.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package org.javawebstack.orm;

import org.javawebstack.orm.query.Query;
import org.javawebstack.orm.query.QueryGroup;

public interface Accessible {
<T extends Model> Query<T> access(Query<T> query, Object accessor);
<T extends Model> QueryGroup<T> access(Query<T> query, QueryGroup<T> accessChecks, Object accessor);
}
9 changes: 4 additions & 5 deletions src/main/java/org/javawebstack/orm/Repo.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Stream;

public class Repo<T extends Model> {

Expand Down Expand Up @@ -73,11 +71,11 @@ public Query<T> whereId(Object right) {
}

public Query<T> accessible(Object accessor) {
return accessible(query(), accessor);
return query().accessible(accessor);
}

public Query<T> accessible(Query<T> query, Object accessor) {
return accessible == null ? query : accessible.access(query, accessor);
public Accessible getAccessible() {
return accessible;
}

public void save(T entry) {
Expand Down Expand Up @@ -122,6 +120,7 @@ private void executeCreate(T entry) {
map.remove(idCol);
}
SQLQueryString qs = getConnection().builder().buildInsert(info, map);
SQL connection = Session.current() != null ? Session.current().getConnection() : this.connection;
int id = connection.write(qs.getQuery(), qs.getParameters().toArray());
if (info.isAutoIncrement())
info.getField(info.getIdField()).set(entry, id);
Expand Down
46 changes: 46 additions & 0 deletions src/main/java/org/javawebstack/orm/Session.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package org.javawebstack.orm;

import org.javawebstack.orm.wrapper.SQL;

import java.util.function.Consumer;

public class Session {

private static ThreadLocal<Session> sessions = new ThreadLocal<>();

public static Session current() {
return sessions.get();
}

private SQL connection;

private Session() {

}

public Session via(SQL connection) {
this.connection = connection;
return this;
}

public SQL getConnection() {
return connection;
}

public static void session(Consumer<Session> consumer) {
Session session = begin();
consumer.accept(session);
end();
}

public static Session begin() {
Session session = new Session();
sessions.set(session);
return session;
}

public static void end() {
sessions.remove();
}

}
80 changes: 52 additions & 28 deletions src/main/java/org/javawebstack/orm/TableInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import org.javawebstack.orm.util.Helper;
import org.javawebstack.orm.util.KeyType;

import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
Expand All @@ -29,7 +28,7 @@ public class TableInfo {
private final Class<? extends Model> modelClass;
private String primaryKey;
private final List<String> uniqueKeys = new ArrayList<>();
private final Constructor<?> constructor;
private Constructor<?> constructor;
private String relationField;
private final Map<String, String> filterable = new HashMap<>();
private final List<String> searchable = new ArrayList<>();
Expand All @@ -42,6 +41,36 @@ public class TableInfo {
public TableInfo(Class<? extends Model> model, ORMConfig config) throws ORMConfigurationException {
this.config = config;
this.modelClass = model;

Stack<Class<?>> superClasses = Helper.getSuperClassesTill(model, Model.class);
while (!superClasses.isEmpty()) {
Class<? extends Model> superClass = (Class<? extends Model>) superClasses.pop();
if (Modifier.isAbstract(superClass.getModifiers())) {
analyzeColumns(superClass);
} else {
throw new ORMConfigurationException("The parent model has to be abstract!");
}
}

constructInfo(model);
}

private void constructInfo (Class<? extends Model> model) throws ORMConfigurationException {
analyzeColumns(model);
analyzeTable(model);

if (!fields.containsKey(idField))
idField = "uuid";
if (!fields.containsKey(idField))
throw new ORMConfigurationException("No id field found!");

if (config.isIdPrimaryKey()) {
if (primaryKey == null)
primaryKey = idField;
}
}

private void analyzeTable(Class<? extends Model> model) throws ORMConfigurationException {
if (model.isAnnotationPresent(Table.class)) {
Table table = model.getDeclaredAnnotationsByType(Table.class)[0];
tableName = table.value();
Expand All @@ -59,6 +88,26 @@ public TableInfo(Class<? extends Model> model, ORMConfig config) throws ORMConfi
} catch (NoSuchMethodException e) {
throw new ORMConfigurationException("The model class has no empty constructor!");
}
if (model.isAnnotationPresent(RelationField.class)) {
relationField = model.getDeclaredAnnotationsByType(RelationField.class)[0].value();
} else {
relationField = Helper.pascalToCamelCase(model.getSimpleName()) + ((getIdType().equals(UUID.class) && !idField.equalsIgnoreCase("id")) ? "UUID" : "Id");
}
if (model.isAnnotationPresent(SoftDelete.class)) {
softDelete = model.getDeclaredAnnotationsByType(SoftDelete.class)[0];
if (!fields.containsKey(softDelete.value()))
throw new ORMConfigurationException("Missing soft-delete field '" + softDelete.value() + "'");
}
if (model.isAnnotationPresent(Dates.class)) {
dates = model.getDeclaredAnnotationsByType(Dates.class)[0];
if (!fields.containsKey(dates.create()))
throw new ORMConfigurationException("Missing dates field '" + dates.create() + "'");
if (!fields.containsKey(dates.update()))
throw new ORMConfigurationException("Missing dates field '" + dates.update() + "'");
}
}

private void analyzeColumns(Class<? extends Model> model) throws ORMConfigurationException {
for (Field field : model.getDeclaredFields()) {
if (Modifier.isStatic(field.getModifiers()))
continue;
Expand All @@ -82,7 +131,7 @@ public TableInfo(Class<? extends Model> model, ORMConfig config) throws ORMConfi
else
fieldSize = fieldConfig.size();

SQLType sqlType = config.getType(field.getType(), fieldSize);
SQLType sqlType = config.getType(field.getType(), fieldSize);
if (sqlType != null) {
sqlTypes.put(fieldName, sqlType);
sqlTypeParameters.put(fieldName, config.getTypeParameters(field.getType(), fieldSize));
Expand All @@ -106,31 +155,6 @@ public TableInfo(Class<? extends Model> model, ORMConfig config) throws ORMConfi
if (field.isAnnotationPresent(Searchable.class))
this.searchable.add(fieldName);
}
if (!fields.containsKey(idField))
idField = "uuid";
if (!fields.containsKey(idField))
throw new ORMConfigurationException("No id field found!");
if (model.isAnnotationPresent(RelationField.class)) {
relationField = model.getDeclaredAnnotationsByType(RelationField.class)[0].value();
} else {
relationField = Helper.pascalToCamelCase(model.getSimpleName()) + ((getIdType().equals(UUID.class) && !idField.equalsIgnoreCase("id")) ? "UUID" : "Id");
}
if (config.isIdPrimaryKey()) {
if (primaryKey == null)
primaryKey = idField;
}
if (model.isAnnotationPresent(SoftDelete.class)) {
softDelete = model.getDeclaredAnnotationsByType(SoftDelete.class)[0];
if (!fields.containsKey(softDelete.value()))
throw new ORMConfigurationException("Missing soft-delete field '" + softDelete.value() + "'");
}
if (model.isAnnotationPresent(Dates.class)) {
dates = model.getDeclaredAnnotationsByType(Dates.class)[0];
if (!fields.containsKey(dates.create()))
throw new ORMConfigurationException("Missing dates field '" + dates.create() + "'");
if (!fields.containsKey(dates.update()))
throw new ORMConfigurationException("Missing dates field '" + dates.update() + "'");
}
}

public boolean isSoftDelete() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@
import org.javawebstack.orm.SQLType;

public class AbstractDataTypeMapper implements TypeMapper {

private static final int BYTES_OVERHEAD_TEXT = 2;
private static final int BYTES_OVERHEAD_MEDIUMTEXT = 3;
private static final int BYTES_OVERHEAD_LONGTEXT = 4;

private static final long MAX_SIZE_TEXT = (long) Math.floor((65535 - BYTES_OVERHEAD_TEXT) / 4);
private static final long MAX_SIZE_MEDIUMTEXT = (long) Math.floor((16777215 - BYTES_OVERHEAD_MEDIUMTEXT) / 4);
private static final long MAX_SIZE_LONGTEXT = (long) Math.floor((4294967295L - BYTES_OVERHEAD_LONGTEXT) / 4);

public Object mapToSQL(Object source, Class<?> type) {
if (source == null)
return null;
Expand All @@ -21,8 +30,13 @@ public Object mapToJava(Object source, Class<?> type) {
}

public SQLType getType(Class<?> type, int size) {
if (AbstractElement.class.isAssignableFrom(type))
if (AbstractElement.class.isAssignableFrom(type)) {
if (size > MAX_SIZE_MEDIUMTEXT)
return SQLType.LONGTEXT;
if (size > MAX_SIZE_TEXT)
return SQLType.MEDIUMTEXT;
return SQLType.TEXT;
}
return null;
}

Expand Down
21 changes: 16 additions & 5 deletions src/main/java/org/javawebstack/orm/mapper/DefaultMapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public Object mapToJava(Object source, Class<?> type) {
}

public SQLType getType(Class<?> type, int size) {
if (type.equals(String.class) || type.equals(char[].class))
if (type.equals(String.class) || type.equals(char[].class)) {
// Upper limit of 4294967295 exceeds the int boundaries
if (size > MAX_SIZE_MEDIUMTEXT)
return SQLType.LONGTEXT;
Expand All @@ -119,12 +119,18 @@ public SQLType getType(Class<?> type, int size) {
return SQLType.VARCHAR;
if (size == 1)
return SQLType.CHAR;
}
if (type.equals(UUID.class))
return SQLType.VARCHAR;
if (type.equals(char.class))
return SQLType.CHAR;
if (type.isEnum())
return SQLType.ENUM;
if (type.isEnum()) {
if(size < 1) {
return SQLType.ENUM;
} else {
return SQLType.VARCHAR;
}
}
if (type.equals(boolean.class) || type.equals(Boolean.class) || type.equals(byte.class) || type.equals(Byte.class))
return SQLType.TINYINT;
if (type.equals(short.class) || type.equals(Short.class))
Expand All @@ -147,8 +153,13 @@ public SQLType getType(Class<?> type, int size) {
}

public String getTypeParameters(Class<?> type, int size) {
if (type.isEnum())
return Arrays.stream(((Class<? extends Enum<?>>) type).getEnumConstants()).map(c -> "'" + c.name() + "'").collect(Collectors.joining(","));
if (type.isEnum()) {
if(size < 1) {
return Arrays.stream(((Class<? extends Enum<?>>) type).getEnumConstants()).map(c -> "'" + c.name() + "'").collect(Collectors.joining(","));
} else {
return String.valueOf(size);
}
}
if (type.equals(String.class) || type.equals(char[].class))
return size > MAX_SIZE_VARCHAR || size < 1 ? null : String.valueOf(size);
if (type.equals(byte[].class))
Expand Down
Loading