Skip to content

Commit 54f0555

Browse files
Merge branch 'master' into TimothyGillespie/addTestForWhereClauses
2 parents 5176d4d + cfb3beb commit 54f0555

20 files changed

Lines changed: 631 additions & 26 deletions

File tree

‎pom.xml‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@
5353
<version>8.0.22</version>
5454
<scope>test</scope>
5555
</dependency>
56+
<dependency>
57+
<groupId>org.atteo</groupId>
58+
<artifactId>evo-inflector</artifactId>
59+
<version>1.2.2</version>
60+
</dependency>
5661
<dependency>
5762
<groupId>org.reflections</groupId>
5863
<artifactId>reflections</artifactId>
@@ -74,6 +79,18 @@
7479
<version>5.4.2</version>
7580
<scope>test</scope>
7681
</dependency>
82+
<dependency>
83+
<groupId>org.apache.commons</groupId>
84+
<artifactId>commons-lang3</artifactId>
85+
<version>3.5</version>
86+
<scope>test</scope>
87+
</dependency>
88+
<dependency>
89+
<groupId>org.projectlombok</groupId>
90+
<artifactId>lombok</artifactId>
91+
<version>1.18.16</version>
92+
<scope>test</scope>
93+
</dependency>
7794
</dependencies>
7895

7996
<distributionManagement>

‎src/main/java/org/javawebstack/orm/Model.java‎

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import java.lang.reflect.Field;
77
import java.lang.reflect.InvocationTargetException;
88
import java.lang.reflect.Method;
9+
import java.security.InvalidParameterException;
910
import java.util.ArrayList;
1011
import java.util.HashMap;
1112
import java.util.List;
@@ -165,26 +166,40 @@ public <T extends Model> Query<T> belongsTo(Class<T> parent) {
165166
}
166167

167168
public <T extends Model> Query<T> belongsTo(Class<T> parent, String fieldName) {
169+
return belongsTo(parent, fieldName, Repo.get(parent).getInfo().getIdField());
170+
}
171+
172+
public <T extends Model> Query<T> belongsTo(Class<T> parent, String fieldName, String otherFieldName) {
168173
try {
169174
Object id = Repo.get(getClass()).getInfo().getField(fieldName).get(this);
170-
return Repo.get(parent).whereId(id);
175+
return Repo.get(parent).where(otherFieldName, id);
171176
} catch (IllegalAccessException e) {
172177
throw new RuntimeException(e);
173178
}
174179
}
175180

181+
public <T extends Model> void assignTo(T value) {
182+
if(value == null)
183+
throw new InvalidParameterException("You need to specify a parent type if the value is null");
184+
assignTo((Class<T>) value.getClass(), value);
185+
}
186+
176187
public <T extends Model> void assignTo(Class<T> parent, T value) {
177188
assignTo(parent, value, Repo.get(parent).getInfo().getRelationField());
178189
}
179190

180191
public <T extends Model> void assignTo(Class<T> parent, T value, String fieldName) {
192+
assignTo(parent, value, fieldName, Repo.get(parent).getInfo().getIdField());
193+
}
194+
195+
public <T extends Model> void assignTo(Class<T> parent, T value, String fieldName, String otherFieldName) {
181196
try {
182197
Field f = Repo.get(getClass()).getInfo().getField(fieldName);
183198
if (value == null) {
184199
f.set(this, null);
185200
} else {
186201
Repo<T> repo = Repo.get(parent);
187-
Object id = repo.getInfo().getField(repo.getInfo().getIdField()).get(value);
202+
Object id = repo.getInfo().getField(otherFieldName).get(value);
188203
f.set(this, id);
189204
}
190205
} catch (IllegalAccessException e) {
@@ -197,9 +212,13 @@ public <T extends Model> Query<T> hasMany(Class<T> child) {
197212
}
198213

199214
public <T extends Model> Query<T> hasMany(Class<T> child, String fieldName) {
215+
return hasMany(child, fieldName, Repo.get(getClass()).getInfo().getIdField());
216+
}
217+
218+
public <T extends Model> Query<T> hasMany(Class<T> child, String fieldName, String ownFieldName) {
200219
try {
201220
Repo<?> ownRepo = Repo.get(getClass());
202-
Object id = ownRepo.getInfo().getField(ownRepo.getInfo().getIdField()).get(this);
221+
Object id = ownRepo.getInfo().getField(ownFieldName).get(this);
203222
return Repo.get(child).where(fieldName, id);
204223
} catch (IllegalAccessException e) {
205224
throw new RuntimeException(e);
@@ -214,17 +233,25 @@ public <T extends Model, P extends Model> Query<T> belongsToMany(Class<T> other,
214233
return belongsToMany(other, pivot, Repo.get(getClass()).getInfo().getRelationField(), Repo.get(other).getInfo().getRelationField(), pivotFilter);
215234
}
216235

217-
public <T extends Model, P extends Model> Query<T> belongsToMany(Class<T> other, Class<P> pivot, String selfFieldName, String otherFieldName) {
218-
return belongsToMany(other, pivot, selfFieldName, otherFieldName, null);
236+
public <T extends Model, P extends Model> Query<T> belongsToMany(Class<T> other, Class<P> pivot, String selfPivotFieldName, String otherPivotFieldName) {
237+
return belongsToMany(other, pivot, selfPivotFieldName, otherPivotFieldName, null);
238+
}
239+
240+
public <T extends Model, P extends Model> Query<T> belongsToMany(Class<T> other, Class<P> pivot, String selfPivotFieldName, String otherPivotFieldName, Function<Query<P>, Query<P>> pivotFilter) {
241+
return belongsToMany(other, pivot, selfPivotFieldName, otherPivotFieldName, Repo.get(getClass()).getInfo().getIdField(), Repo.get(other).getInfo().getIdField(), pivotFilter);
219242
}
220243

221-
public <T extends Model, P extends Model> Query<T> belongsToMany(Class<T> other, Class<P> pivot, String selfFieldName, String otherFieldName, Function<Query<P>, Query<P>> pivotFilter) {
244+
public <T extends Model, P extends Model> Query<T> belongsToMany(Class<T> other, Class<P> pivot, String selfPivotFieldName, String otherPivotFieldName, String selfFieldName, String otherFieldName) {
245+
return belongsToMany(other, pivot, selfPivotFieldName, otherPivotFieldName, selfFieldName, otherFieldName, null);
246+
}
247+
248+
public <T extends Model, P extends Model> Query<T> belongsToMany(Class<T> other, Class<P> pivot, String selfPivotFieldName, String otherPivotFieldName, String selfFieldName, String otherFieldName, Function<Query<P>, Query<P>> pivotFilter) {
222249
try {
223250
Repo<?> selfRepo = Repo.get(getClass());
224251
Repo<T> otherRepo = Repo.get(other);
225-
Object id = selfRepo.getInfo().getField(selfRepo.getInfo().getIdField()).get(this);
252+
Object id = selfRepo.getInfo().getField(selfFieldName).get(this);
226253
return otherRepo.whereExists(pivot, q -> {
227-
q.where(pivot, selfFieldName, "=", id).where(pivot, otherFieldName, "=", other, otherRepo.getInfo().getIdColumn());
254+
q.where(pivot, selfPivotFieldName, "=", id).where(pivot, otherPivotFieldName, "=", other, otherFieldName);
228255
if (pivotFilter != null)
229256
q = pivotFilter.apply(q);
230257
return q;
@@ -234,17 +261,4 @@ public <T extends Model, P extends Model> Query<T> belongsToMany(Class<T> other,
234261
}
235262
}
236263

237-
public void setMorph(String name, Class<? extends Model> type, Object id) {
238-
TableInfo info = Repo.get(getClass()).getInfo();
239-
try {
240-
info.getField(name + "Id").set(this, id);
241-
info.getField(name + "Type").set(this, Repo.get(type).getInfo().getMorphType());
242-
} catch (IllegalAccessException ignored) {
243-
}
244-
}
245-
246-
public void setMorph(String name, Model model) {
247-
setMorph(name, model.getClass(), Repo.get(model.getClass()).getId(model));
248-
}
249-
250264
}

‎src/main/java/org/javawebstack/orm/TableInfo.java‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.javawebstack.orm;
22

3+
import org.atteo.evo.inflector.English;
34
import org.javawebstack.orm.annotation.*;
45
import org.javawebstack.orm.exception.ORMConfigurationException;
56
import org.javawebstack.orm.util.Helper;
@@ -45,10 +46,7 @@ public TableInfo(Class<? extends Model> model, ORMConfig config) throws ORMConfi
4546
Table table = model.getDeclaredAnnotationsByType(Table.class)[0];
4647
tableName = table.value();
4748
} else {
48-
tableName = Helper.toSnakeCase(model.getSimpleName());
49-
tableName += tableName.endsWith("ss") ? "es" : "s";
50-
if (tableName.endsWith("ys"))
51-
tableName = tableName.substring(0, tableName.length() - 2) + "ies";
49+
tableName = Helper.toSnakeCase(English.plural(model.getSimpleName()));
5250
}
5351
if (model.isAnnotationPresent(MorphType.class)) {
5452
morphType = model.getDeclaredAnnotationsByType(MorphType.class)[0].value();

‎src/main/java/org/javawebstack/orm/query/Query.java‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,16 @@ public Query<T> notNull(Object left) {
164164
where.notNull(left);
165165
return this;
166166
}
167+
168+
public Query<T> whereNull(Object left) {
169+
where.isNull(left);
170+
return this;
171+
}
172+
173+
public Query<T> whereNotNull(Object left) {
174+
where.notNull(left);
175+
return this;
176+
}
167177

168178
public Query<T> lessThan(Object left, Object right) {
169179
where.lessThan(left, right);

‎src/main/java/org/javawebstack/orm/query/QueryGroup.java‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,14 @@ public QueryGroup<T> isNull(Object left) {
7979
public QueryGroup<T> notNull(Object left) {
8080
return where(left, "IS NOT NULL", null);
8181
}
82+
83+
public QueryGroup<T> whereNull(Object left) {
84+
return where(left, "IS NULL", null);
85+
}
86+
87+
public QueryGroup<T> whereNotNull(Object left) {
88+
return where(left, "IS NOT NULL", null);
89+
}
8290

8391
public QueryGroup<T> lessThan(Object left, Object right) {
8492
return where(left, "<", right);

‎src/test/java/org/javawebstack/orm/test/automigrate/DefaultSizeTest.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public class DefaultSizeTest extends ORMTestCase {
5656
final static String columnNameString = "string";
5757

5858
// Not renaming the table name as this is not focus of the test
59-
final static String tableNameCharArray = "just_char_arraies";
59+
final static String tableNameCharArray = "just_char_arrays";
6060
final static String columnNameCharArray = "char_array";
6161

6262
final static String tableNameDatatype = "datatypes";
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
package org.javawebstack.orm.test.other;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Getter;
5+
import org.apache.commons.lang3.RandomStringUtils;
6+
import org.javawebstack.orm.test.shared.util.QueryStringUtil;
7+
import org.junit.jupiter.api.Test;
8+
9+
import java.util.*;
10+
11+
import static org.junit.jupiter.api.Assertions.assertEquals;
12+
13+
14+
/*
15+
* The scope of this class is to test the QueryUtility as it will be used to write other tests.
16+
*/
17+
class QueryUtilTest {
18+
19+
@Test
20+
void testGetSectionSimple() {
21+
List<SectionRecord> list = new LinkedList<>(Arrays.asList(
22+
new SectionRecord("SELECT", RandomStringUtils.randomAlphanumeric(3, 12)),
23+
new SectionRecord("FROM", RandomStringUtils.randomAlphanumeric(3, 10)),
24+
new SectionRecord("WHERE", RandomStringUtils.randomAlphanumeric(3, 10)),
25+
new SectionRecord("ORDER BY", RandomStringUtils.randomAlphanumeric(3, 10)),
26+
new SectionRecord("GROUP BY", RandomStringUtils.randomAlphanumeric(3, 10)),
27+
new SectionRecord("HAVING", RandomStringUtils.randomAlphanumeric(3, 10)),
28+
new SectionRecord("LIMIT", RandomStringUtils.randomNumeric(1, 100)),
29+
new SectionRecord("OFFSET", RandomStringUtils.randomNumeric(1, 100))
30+
));
31+
32+
this.performStandardTestOnList(list);
33+
34+
}
35+
36+
@Test
37+
void testCasingDoesNotMatter() {
38+
List<SectionRecord> list = new LinkedList<>(Arrays.asList(
39+
new SectionRecord("select", RandomStringUtils.randomAlphanumeric(3, 12)),
40+
new SectionRecord("fRom", RandomStringUtils.randomAlphanumeric(3, 10)),
41+
new SectionRecord("where", RandomStringUtils.randomAlphanumeric(3, 10)),
42+
new SectionRecord("ordEr by", RandomStringUtils.randomAlphanumeric(3, 10)),
43+
new SectionRecord("Group By", RandomStringUtils.randomAlphanumeric(3, 10)),
44+
new SectionRecord("hAvIng", RandomStringUtils.randomAlphanumeric(3, 10)),
45+
new SectionRecord("limit", RandomStringUtils.randomNumeric(1, 100)),
46+
new SectionRecord("offset", RandomStringUtils.randomNumeric(1, 100))
47+
));
48+
49+
this.performStandardTestOnList(list);
50+
}
51+
52+
// Example from here: https://www.freecodecamp.org/news/sql-example/
53+
@Test
54+
void testGetUsualCase() {
55+
List<SectionRecord> list = new LinkedList<>(Arrays.asList(
56+
new SectionRecord("SELECT", "`Customers`.`CustomerName`, `Orders`.`OrderID`"),
57+
new SectionRecord("FROM", "`Customers`"),
58+
new SectionRecord("FULL OUTER JOIN", "`Orders` ON `Customers`.`CustomerID`=`Orders`.`CustomerID`"),
59+
new SectionRecord("ORDER BY", "`Customers`.`CustomerName`")
60+
));
61+
62+
this.performStandardTestOnList(list);
63+
}
64+
65+
@Test
66+
void testTrapExpressionsWhichAreEscaped() {
67+
List<SectionRecord> list = new LinkedList<>(Arrays.asList(
68+
new SectionRecord("SELECT", "`FROM`.`SELECT`, `GROUP BY`.`having`"),
69+
new SectionRecord("FROM", "`order by`"),
70+
new SectionRecord("WHERE", "`from` LIKE `where` AND 'from' = 'where'"),
71+
new SectionRecord("FULL OUTER JOIN", "`from` ON `FROM`.`SELECT`=`select`.`from`"),
72+
new SectionRecord("ORDER BY", "`limit`.`where`")
73+
));
74+
75+
this.performStandardTestOnList(list);
76+
}
77+
78+
@Test
79+
void testMultipleOccurrences() {
80+
List<SectionRecord> list = new LinkedList<>(Arrays.asList(
81+
new SectionRecord("SELECT", RandomStringUtils.randomAlphanumeric(3, 12)),
82+
new SectionRecord("FROM", RandomStringUtils.randomAlphanumeric(3, 12)),
83+
new SectionRecord("JOIN", RandomStringUtils.randomAlphanumeric(3, 12)),
84+
new SectionRecord("JOIN", RandomStringUtils.randomAlphanumeric(3, 12)),
85+
new SectionRecord("JOIN", RandomStringUtils.randomAlphanumeric(3, 12))
86+
));
87+
88+
String queryString = this.getQueryStringFromList(list);
89+
QueryStringUtil util = new QueryStringUtil(queryString);
90+
91+
SectionRecord currentRecord = list.get(0);
92+
assertEquals(currentRecord.getValue(), util.getTopLevelSectionsByKeyword(currentRecord.getKey()).get(0));
93+
94+
currentRecord = list.get(1);
95+
assertEquals(currentRecord.getValue(), util.getTopLevelSectionsByKeyword(currentRecord.getKey()).get(0));
96+
97+
currentRecord = list.get(2);
98+
assertEquals(currentRecord.getValue(), util.getTopLevelSectionsByKeyword(currentRecord.getKey()).get(0));
99+
100+
currentRecord = list.get(3);
101+
assertEquals(currentRecord.getValue(), util.getTopLevelSectionsByKeyword(currentRecord.getKey()).get(1));
102+
103+
currentRecord = list.get(4);
104+
assertEquals(currentRecord.getValue(), util.getTopLevelSectionsByKeyword(currentRecord.getKey()).get(2));
105+
106+
}
107+
/*
108+
* Boilerplate Code Reduction Methods
109+
*/
110+
111+
private String getQueryStringFromList(List<SectionRecord> list) {
112+
StringBuilder builder = new StringBuilder();
113+
114+
for(SectionRecord entry : list)
115+
builder
116+
.append(entry.getKey())
117+
.append(" ")
118+
.append(entry.getValue())
119+
.append(" ");
120+
121+
return builder.toString().trim();
122+
}
123+
124+
/*
125+
* The standard test in this case will be that each section cnly exists once and as defined per list.
126+
*/
127+
private void performStandardTestOnList(List<SectionRecord> list) {
128+
String query = this.getQueryStringFromList(list);
129+
QueryStringUtil verification = new QueryStringUtil(query);
130+
131+
for (SectionRecord entry : list) {
132+
List<String> foundSections = verification.getTopLevelSectionsByKeyword(entry.getKey());
133+
String firstSection = foundSections.get(0);
134+
assertEquals(1, foundSections.size(), "More than one section or no section was found, but only one unique section was expected.");
135+
assertEquals(
136+
entry.getValue(),
137+
firstSection,
138+
String.format(
139+
"The section name %s has been %s instead of %s.",
140+
entry.getKey(),
141+
firstSection,
142+
entry.getValue()
143+
)
144+
);
145+
}
146+
}
147+
148+
@Getter
149+
@AllArgsConstructor
150+
static class SectionRecord {
151+
String key;
152+
String value;
153+
}
154+
155+
}

0 commit comments

Comments
 (0)