Skip to content

Commit 150ce72

Browse files
committed
version 0.7
* Add Subqueries It's now possible to construct query with nested queries in the from clause or in where clause.
1 parent 9c35a90 commit 150ce72

File tree

13 files changed

+236
-43
lines changed

13 files changed

+236
-43
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ sourceCompatibility = '1.6'
55
targetCompatibility = '1.6'
66

77
group = 'com.thibaultdelor'
8-
version = '0.6'
8+
version = '0.7'
99

1010
repositories {
1111
mavenCentral()

src/main/java/com/thibaultdelor/JSQL/Column.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,20 @@
44

55
public class Column implements SQLOutputable {
66

7-
private final Table table;
7+
private final ITable table;
88
private final String name;
99
private final String alias;
1010
private boolean isInUsing = false;
1111

1212

13-
protected Column(Table table, String name, String alias) {
13+
protected Column(ITable table, String name, String alias) {
1414
super();
1515
this.table = table;
1616
this.name = name;
1717
this.alias = alias;
1818
}
1919

20-
protected Column(Table table, String name) {
20+
protected Column(ITable table, String name) {
2121
this(table, name, null);
2222
}
2323

@@ -96,7 +96,7 @@ public String toString() {
9696
+ "]";
9797
}
9898

99-
public Table getTable() {
99+
public ITable getTable() {
100100
return table;
101101
}
102102

@@ -111,8 +111,9 @@ public void setInUsing(boolean inUsing) {
111111

112112
@Override
113113
public void addNeededTables(Set<Table> tables) {
114-
tables.add(table);
115-
114+
if (table instanceof Table) {
115+
tables.add((Table) table);
116+
}
116117
}
117118

118119

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.thibaultdelor.JSQL;
2+
3+
4+
public interface ITable extends SQLOutputable {
5+
6+
String getAlias();
7+
8+
Column get(String colName);
9+
10+
Column get(Column col);
11+
12+
}

src/main/java/com/thibaultdelor/JSQL/JoinResolver.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public void setDepth(int depth) {
5757
* the join type
5858
*/
5959
public void resolve(JoinType joinType) {
60-
Set<Table> existingTables = query.getExistingTables();
60+
Set<ITable> existingTables = query.getExistingTables();
6161
buildNodes(existingTables);
6262
Set<Table> missingTables = query.getMissingTables();
6363
if (existingTables.size() == 0) {
@@ -99,10 +99,12 @@ public void resolve(JoinType joinType) {
9999
* @param existingTables
100100
* the existing tables in query
101101
*/
102-
private void buildNodes(Set<Table> existingTables) {
102+
private void buildNodes(Set<ITable> existingTables) {
103103
nodes.clear();
104-
for (Table table : existingTables) {
105-
nodes.add(new TableNode(table, 0, null, null, true));
104+
for (ITable table : existingTables) {
105+
if (table instanceof Table) {
106+
nodes.add(new TableNode((Table) table, 0, null, null, true));
107+
}
106108
}
107109
addJoinNodes(new ArrayList<JoinResolver.TableNode>(nodes));
108110
}
@@ -120,7 +122,7 @@ private void addJoinNodes(Collection<TableNode> baseNodes) {
120122
continue;
121123

122124
for (ForeignKey fk : tableNode.table.getForeignKeys()) {
123-
Table remotetable = fk.getRemoteColumn().getTable();
125+
Table remotetable = (Table) fk.getRemoteColumn().getTable();
124126
TableNode myNode = findNodeByTableName(remotetable.getName());
125127
if (myNode == null) {
126128
myNode = new TableNode(remotetable, tableNode.depth + 1, fk, tableNode, false);
@@ -155,7 +157,7 @@ private void updateBestNode(TableNode myNode, TableNode baseNode) {
155157
// update myNode property to use this better path
156158
myNode.bestForeignKey = null;
157159
for (ForeignKey fk : myNode.table.getForeignKeys()) {
158-
if (fk.getRemoteColumn().getTable().isSameTable(baseNode.table)) {
160+
if (((Table) fk.getRemoteColumn().getTable()).isSameTable(baseNode.table)) {
159161
myNode.bestForeignKey = fk;
160162
break;
161163
}
@@ -169,7 +171,7 @@ private void updateBestNode(TableNode myNode, TableNode baseNode) {
169171

170172
// recursively update childs
171173
for (ForeignKey fk : myNode.table.getForeignKeys()) {
172-
TableNode child = findNodeByTableName(fk.getRemoteColumn().getTable()
174+
TableNode child = findNodeByTableName(((Table) fk.getRemoteColumn().getTable())
173175
.getName());
174176
if (child != null)
175177
updateBestNode(child, myNode);

src/main/java/com/thibaultdelor/JSQL/SelectQuery.java

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public class SelectQuery {
2323

2424
private final List<SQLOutputable> hints = new ArrayList<SQLOutputable>(0);
2525
private final List<SQLOutputable> columns = new ArrayList<SQLOutputable>();
26-
private final LinkedHashSet<Table> from = new LinkedHashSet<Table>();
26+
private final LinkedHashSet<ITable> from = new LinkedHashSet<ITable>();
2727
private final List<JoinClause> join = new ArrayList<JoinClause>();
2828
private final LogicalExpression where = new LogicalExpression("", "\nAND ",
2929
"");
@@ -53,7 +53,7 @@ public SelectQuery hints(SQLOutputable... hints) {
5353
return this;
5454
}
5555

56-
public SelectQuery from(Table t) {
56+
public SelectQuery from(ITable t) {
5757
if (from.add(t))
5858
t.addNeededTables(allReferencedTables);
5959
return this;
@@ -71,21 +71,21 @@ public SelectQuery join(JoinClause jc) {
7171
return this;
7272
}
7373

74-
public SelectQuery join(Table joinTable, Criterion criterion) {
74+
public SelectQuery join(ITable joinTable, Criterion criterion) {
7575
return join(new ImplicitJoin(joinTable, criterion));
7676
}
7777

78-
public SelectQuery join(Table joinTable, Column mycolumn,
78+
public SelectQuery join(ITable joinTable, Column mycolumn,
7979
Column foreigncolumn) {
8080
return join(joinTable, new BinaryCriterion(mycolumn,
8181
BinaryOperator.EQUAL, foreigncolumn));
8282
}
8383

84-
public SelectQuery join(JoinType type, Table joinTable, Criterion criterion) {
84+
public SelectQuery join(JoinType type, ITable joinTable, Criterion criterion) {
8585
return join(new OnJoin(type, joinTable, criterion));
8686
}
8787

88-
public SelectQuery join(JoinType type, Table joinTable, Column mycolumn,
88+
public SelectQuery join(JoinType type, ITable joinTable, Column mycolumn,
8989
Column foreigncolumn) {
9090
return join(type, joinTable, new BinaryCriterion(mycolumn,
9191
BinaryOperator.EQUAL, foreigncolumn));
@@ -100,6 +100,9 @@ public SelectQuery where(Criterion c) {
100100
public SelectQuery whereIn(Column col, String... values) {
101101
return where(new InCriterion(col, new LiteralSet(values)));
102102
}
103+
public SelectQuery whereIn(Column col, SubQueryTable sq) {
104+
return where(new InCriterion(col, sq));
105+
}
103106

104107
public SelectQuery groupBy(SQLOutputable groupCol) {
105108
if (groupBy.add(groupCol))
@@ -124,6 +127,10 @@ public SelectQuery orderBy(Column c, boolean asc) {
124127
return orderBy(new OrderClause(c, asc));
125128
}
126129

130+
131+
public SubQueryTable as(String alias){
132+
return new SubQueryTable(this, alias);
133+
}
127134
/**
128135
* Add all necessary missing tables in the from clause.
129136
*/
@@ -184,8 +191,8 @@ public void autoJoin(JoinType joinType, int depth) {
184191
joinResolver.resolve(joinType);
185192
}
186193

187-
Set<Table> getExistingTables() {
188-
Set<Table> joinedTables = new HashSet<Table>(from);
194+
Set<ITable> getExistingTables() {
195+
Set<ITable> joinedTables = new HashSet<ITable>(from);
189196
for (JoinClause jc : join) {
190197
joinedTables.add(jc.getJoinTable());
191198
}
@@ -196,13 +203,15 @@ Set<Table> getMissingTables() {
196203
missingTables.removeAll(from);
197204
Set<Table> joinedTables = new HashSet<Table>(4);
198205
for (JoinClause jc : join) {
199-
joinedTables.add(jc.getJoinTable());
206+
if (jc.getJoinTable() instanceof Table) {
207+
joinedTables.add((Table) jc.getJoinTable());
208+
}
200209
}
201210
missingTables.removeAll(joinedTables);
202211
return missingTables;
203212
}
204213

205-
public String toSQLString() {
214+
public StringBuilder toSQLStringBuilder() {
206215
StringBuilder query = new StringBuilder();
207216
appendSelect(query);
208217
appendFrom(query);
@@ -211,7 +220,11 @@ public String toSQLString() {
211220
appendHaving(query);
212221
appendOrderBy(query);
213222

214-
return query.toString();
223+
return query;
224+
}
225+
226+
public String toSQLString() {
227+
return toSQLStringBuilder().toString();
215228
}
216229

217230
private void appendSelect(StringBuilder query) {
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package com.thibaultdelor.JSQL;
2+
3+
import java.util.Set;
4+
5+
public class SubQueryTable implements ITable {
6+
7+
private final String alias;
8+
private final SelectQuery query;
9+
10+
public SubQueryTable(SelectQuery query, String alias) {
11+
if(alias==null)
12+
throw new ExceptionInInitializerError("alias cannot be null!");
13+
this.alias = alias;
14+
15+
if(query==null)
16+
throw new ExceptionInInitializerError("alias cannot be null!");
17+
this.query = query;
18+
}
19+
20+
@Override
21+
public void output(StringBuilder sb, SQLContext context) {
22+
switch (context) {
23+
case FROM:
24+
sb.append('(');
25+
sb.append(query.toSQLStringBuilder());
26+
sb.append(") ");
27+
sb.append(alias);
28+
break;
29+
case WHERE:
30+
sb.append(query.toSQLStringBuilder());
31+
break;
32+
33+
default:
34+
throw new RuntimeException("Invalid context " + context + " for "
35+
+ this);
36+
}
37+
38+
}
39+
40+
@Override
41+
public void addNeededTables(Set<Table> tables) {
42+
}
43+
44+
@Override
45+
public String getAlias() {
46+
return alias;
47+
}
48+
49+
@Override
50+
public Column get(String colName) {
51+
return new Column(this, colName);
52+
}
53+
54+
@Override
55+
public Column get(Column col) {
56+
return get(col.getName());
57+
}
58+
59+
}

src/main/java/com/thibaultdelor/JSQL/Table.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import java.util.List;
88
import java.util.Set;
99

10-
public class Table implements SQLOutputable {
10+
public class Table implements ITable {
1111

1212
class ForeignKey {
1313
private Column foreignKey;
@@ -106,6 +106,7 @@ public Table(String name) {
106106
this(name, null);
107107
}
108108

109+
@Override
109110
public String getAlias() {
110111
return (alias == null) ? name : alias;
111112
}
@@ -133,6 +134,7 @@ public Table as(String alias) {
133134
return table;
134135
}
135136

137+
@Override
136138
public Column get(String colName) {
137139
Column c = new Column(this, colName);
138140
int indexOf = columns.indexOf(c);
@@ -143,13 +145,17 @@ public Column get(String colName) {
143145
return c;
144146
}
145147

148+
@Override
146149
public Column get(Column col) {
147150
return get(col.getName());
148151
}
149152

150153
public void addForeignKey(Column origin, Column reference) {
151154
foreignKeys.add(new ForeignKey(origin, reference));
152-
Table table = reference.getTable();
155+
if (! (reference.getTable() instanceof Table)) {
156+
throw new IllegalArgumentException(reference+" is not in a concrete table and so cannot be used in a foreign key");
157+
}
158+
Table table = (Table) reference.getTable();
153159
table.foreignKeys.add(table.new ForeignKey(reference, origin));
154160
}
155161

src/main/java/com/thibaultdelor/JSQL/criteria/InCriterion.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,41 @@
33
import java.util.Set;
44

55
import com.thibaultdelor.JSQL.SQLOutputable;
6+
import com.thibaultdelor.JSQL.SubQueryTable;
67
import com.thibaultdelor.JSQL.Table;
78
import com.thibaultdelor.JSQL.literal.LiteralSet;
89

910
public class InCriterion implements Criterion{
1011

1112
private SQLOutputable column;
12-
private LiteralSet values;
13+
private SQLOutputable inElement;
1314

14-
public InCriterion(SQLOutputable col, LiteralSet values) {
15+
16+
private InCriterion(SQLOutputable col, SQLOutputable inElement) {
1517
this.column = col;
16-
this.values = values ;
18+
this.inElement = inElement ;
19+
}
20+
21+
public InCriterion(SQLOutputable col, LiteralSet values) {
22+
this(col, (SQLOutputable)values);
23+
}
24+
public InCriterion(SQLOutputable col, SubQueryTable subQuery) {
25+
this(col, (SQLOutputable)subQuery);
1726
}
1827

1928
@Override
2029
public void output(StringBuilder sb, SQLContext context) {
2130
column.output(sb, context);
2231
sb.append(" IN (");
23-
values.output(sb, context);
32+
inElement.output(sb, context);
2433
sb.append(")");
2534

2635
}
2736

2837
@Override
2938
public void addNeededTables(Set<Table> tables) {
3039
column.addNeededTables(tables);
31-
values.addNeededTables(tables);
40+
inElement.addNeededTables(tables);
3241

3342
}
3443

0 commit comments

Comments
 (0)