Skip to content

Commit 0f1d1f4

Browse files
authored
Add SQLite support to the Criteria API (#1259)
2 parents 4c8192c + c454837 commit 0f1d1f4

File tree

50 files changed

+545
-137
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+545
-137
lines changed

doma-core/src/main/java/org/seasar/doma/jdbc/criteria/query/AliasManager.java

Lines changed: 97 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,53 @@
55
import java.util.Objects;
66
import java.util.function.BiFunction;
77
import java.util.function.Function;
8+
import org.seasar.doma.jdbc.Config;
89
import org.seasar.doma.jdbc.criteria.context.Context;
910
import org.seasar.doma.jdbc.criteria.metamodel.EntityMetamodel;
1011
import org.seasar.doma.jdbc.criteria.metamodel.PropertyMetamodel;
1112

13+
/**
14+
* The {@code AliasManager} class is responsible for managing alias mappings for entity and property
15+
* metamodels. It helps in generating and retrieving unique aliases for entities and their
16+
* associated properties to ensure consistency in database queries.
17+
*
18+
* <p>This class provides both static factory methods for instantiation and functionality to link to
19+
* a parent {@code AliasManager} to resolve aliases hierarchically.
20+
*/
1221
public class AliasManager {
13-
private final AliasManager parent;
14-
private final Map<EntityMetamodel<?>, String> entityAliasMap = new HashMap<>();
15-
private final Map<PropertyMetamodel<?>, String> propertyAliasMap = new HashMap<>();
22+
protected final Context context;
23+
protected final AliasManager parent;
24+
protected final Map<EntityMetamodel<?>, String> entityAliasMap = new HashMap<>();
25+
protected final Map<PropertyMetamodel<?>, String> propertyAliasMap = new HashMap<>();
1626
private final int index;
1727

28+
/**
29+
* Constructs an instance of {@code AliasManager}.
30+
*
31+
* <p>This constructor is marked as {@code @Deprecated}. Usage of {@code of(Config, Context)} or
32+
* {@code of(Config, Context, AliasManager)} is recommended.
33+
*
34+
* @param context the context containing the entity metamodels; must not be null
35+
* @throws NullPointerException if {@code context} is null
36+
*/
37+
@Deprecated
1838
public AliasManager(Context context) {
1939
this(context, null);
2040
}
2141

42+
/**
43+
* Constructs an instance of {@code AliasManager}.
44+
*
45+
* <p>This constructor is marked as {@code @Deprecated}. Usage of {@code of(Config, Context)} or
46+
* {@code of(Config, Context, AliasManager)} is recommended.
47+
*
48+
* @param context the context containing the entity metamodels; must not be null
49+
* @param parent the parent {@code AliasManager}, or null if none
50+
* @throws NullPointerException if {@code context} is null
51+
*/
52+
@Deprecated
2253
public AliasManager(Context context, AliasManager parent) {
23-
Objects.requireNonNull(context);
54+
this.context = Objects.requireNonNull(context);
2455
this.parent = parent;
2556
int index = parent != null ? parent.index : 0;
2657
for (EntityMetamodel<?> entityMetamodel : context.getEntityMetamodels()) {
@@ -34,10 +65,24 @@ public AliasManager(Context context, AliasManager parent) {
3465
this.index = index;
3566
}
3667

68+
/**
69+
* Retrieves the alias corresponding to the given {@code EntityMetamodel}.
70+
*
71+
* @param entityMetamodel the entity metamodel for which the alias is to be retrieved; must not be
72+
* null
73+
* @return the alias as a {@code String}, or {@code null} if no alias is found
74+
*/
3775
public String getAlias(EntityMetamodel<?> entityMetamodel) {
3876
return getAlias(entityMetamodel, AliasManager::getAlias, entityAliasMap::get);
3977
}
4078

79+
/**
80+
* Retrieves the alias for the given {@code PropertyMetamodel}.
81+
*
82+
* @param propertyMetamodel the property metamodel for which the alias is to be retrieved; must
83+
* not be null
84+
* @return the alias as a {@code String}, or {@code null} if no alias is found
85+
*/
4186
public String getAlias(PropertyMetamodel<?> propertyMetamodel) {
4287
return getAlias(propertyMetamodel, AliasManager::getAlias, propertyAliasMap::get);
4388
}
@@ -54,4 +99,52 @@ private <KEY> String getAlias(
5499
}
55100
return getCurrentAlias.apply(key);
56101
}
102+
103+
protected AliasManager asParent() {
104+
return this;
105+
}
106+
107+
/**
108+
* Creates a new instance of {@code AliasManager} using the provided configuration and context.
109+
*
110+
* @param config the runtime configuration for DAOs; must not be null
111+
* @param context the context containing the entity metamodels; must not be null
112+
* @return a new instance of {@code AliasManager}
113+
* @throws NullPointerException if {@code config} or {@code context} is null
114+
*/
115+
public static AliasManager create(Config config, Context context) {
116+
// The config will be used in future refactoring.
117+
Objects.requireNonNull(config);
118+
return new AliasManager(context);
119+
}
120+
121+
/**
122+
* Creates an empty instance of {@code AliasManager} with the provided configuration and context.
123+
*
124+
* @param config the runtime configuration for DAOs; must not be null
125+
* @param context the context containing the entity metamodels; must not be null
126+
* @return a new instance of {@code EmptyAliasManager} with a default aliasing strategy
127+
* @throws NullPointerException if {@code config} or {@code context} is null
128+
*/
129+
public static AliasManager createEmpty(Config config, Context context) {
130+
return new EmptyAliasManager(config, context);
131+
}
132+
133+
/**
134+
* Creates a child instance of {@code AliasManager} using the provided configuration, context, and
135+
* parent {@code AliasManager}.
136+
*
137+
* @param config the runtime configuration for DAOs; must not be null
138+
* @param context the context containing the entity metamodels; must not be null
139+
* @param parent the parent {@code AliasManager}; must not be null
140+
* @return a new child instance of {@code AliasManager}
141+
* @throws NullPointerException if {@code config}, {@code context}, or {@code parent} is null
142+
*/
143+
public static AliasManager createChild(Config config, Context context, AliasManager parent) {
144+
// The config will be used in future refactoring.
145+
Objects.requireNonNull(config);
146+
Objects.requireNonNull(context);
147+
Objects.requireNonNull(parent);
148+
return new AliasManager(context, parent.asParent());
149+
}
57150
}

doma-core/src/main/java/org/seasar/doma/jdbc/criteria/query/BuilderSupport.java

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,7 @@ public void with(List<WithContext> withContexts) {
7171
var entityMetamodel = withContext.entityMetamodel();
7272
var setOperationContext = withContext.setOperationContext();
7373
// cte name
74-
buf.appendSql(
75-
entityMetamodel
76-
.asType()
77-
.getQualifiedTableName(config.getNaming()::apply, config.getDialect()::applyQuote));
74+
buf.appendSql(getQualifiedTableName(entityMetamodel));
7875
// cte column list
7976
buf.appendSql("(");
8077
for (PropertyMetamodel<?> propertyMetamodel : entityMetamodel.allPropertyMetamodels()) {
@@ -166,15 +163,18 @@ private List<PropertyMetamodel<?>> wrapAliasExpression(
166163
}
167164

168165
public void table(EntityMetamodel<?> entityMetamodel) {
169-
EntityType<?> entityType = entityMetamodel.asType();
170-
buf.appendSql(
171-
entityType.getQualifiedTableName(
172-
config.getNaming()::apply, config.getDialect()::applyQuote));
166+
String table = getQualifiedTableName(entityMetamodel);
167+
buf.appendSql(table);
173168
buf.appendSql(" ");
174169
String alias = getAlias(entityMetamodel);
175170
buf.appendSql(alias);
176171
}
177172

173+
public void tableOnly(EntityMetamodel<?> entityMetamodel) {
174+
String table = getQualifiedTableName(entityMetamodel);
175+
buf.appendSql(table);
176+
}
177+
178178
public void alias(EntityMetamodel<?> entityMetamodel) {
179179
String alias = getAlias(entityMetamodel);
180180
buf.appendSql(alias);
@@ -239,6 +239,12 @@ public void visitCriterion(int index, Criterion criterion) {
239239
criterion.accept(new CriterionVisitor(index));
240240
}
241241

242+
private String getQualifiedTableName(EntityMetamodel<?> entityMetamodel) {
243+
return entityMetamodel
244+
.asType()
245+
.getQualifiedTableName(config.getNaming()::apply, config.getDialect()::applyQuote);
246+
}
247+
242248
private class OperandVisitor implements Operand.Visitor<Void> {
243249
@Override
244250
public Void visit(Operand.Param param) {
@@ -496,7 +502,7 @@ public void inSingleSubQuery(Operand.Prop left, SelectContext right, boolean not
496502
buf.appendSql(" not");
497503
}
498504
buf.appendSql(" in (");
499-
AliasManager child = new AliasManager(right, aliasManager);
505+
AliasManager child = AliasManager.createChild(config, right, aliasManager);
500506
SelectBuilder builder = new SelectBuilder(config, right, commenter, buf, child);
501507
builder.interpret();
502508
buf.appendSql(")");
@@ -542,7 +548,7 @@ private void inPairSubQuery(
542548
buf.appendSql(" not");
543549
}
544550
buf.appendSql(" in (");
545-
AliasManager child = new AliasManager(right, aliasManager);
551+
AliasManager child = AliasManager.createChild(config, right, aliasManager);
546552
SelectBuilder builder = new SelectBuilder(config, right, commenter, buf, child);
547553
builder.interpret();
548554
buf.appendSql(")");
@@ -594,7 +600,7 @@ private void inTripleSubQuery(
594600
buf.appendSql(" not");
595601
}
596602
buf.appendSql(" in (");
597-
AliasManager child = new AliasManager(right, aliasManager);
603+
AliasManager child = AliasManager.createChild(config, right, aliasManager);
598604
SelectBuilder builder = new SelectBuilder(config, right, commenter, buf, child);
599605
builder.interpret();
600606
buf.appendSql(")");
@@ -605,7 +611,7 @@ public void exists(SelectContext context, boolean not) {
605611
buf.appendSql("not ");
606612
}
607613
buf.appendSql("exists (");
608-
AliasManager child = new AliasManager(context, aliasManager);
614+
AliasManager child = AliasManager.createChild(config, context, aliasManager);
609615
SelectBuilder builder = new SelectBuilder(config, context, commenter, buf, child);
610616
builder.interpret();
611617
buf.appendSql(")");
@@ -696,6 +702,9 @@ protected Optional<String> getAlias(PropertyMetamodel<?> propertyMetamodel) {
696702
if (alias == null) {
697703
throw new DomaException(Message.DOMA6004, propertyMetamodel.getName());
698704
}
705+
if (alias.isEmpty()) {
706+
return Optional.empty();
707+
}
699708
return Optional.of(alias);
700709
}
701710

@@ -842,7 +851,7 @@ public void visit(CaseExpression<?> expression) {
842851
@Override
843852
public void visit(SelectExpression<?> expression) {
844853
buf.appendSql("(");
845-
AliasManager child = new AliasManager(expression.context, aliasManager);
854+
AliasManager child = AliasManager.createChild(config, expression.context, aliasManager);
846855
SelectBuilder builder = new SelectBuilder(config, expression.context, commenter, buf, child);
847856
builder.interpret();
848857
buf.appendSql(")");

doma-core/src/main/java/org/seasar/doma/jdbc/criteria/query/DeleteBuilder.java

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77
import org.seasar.doma.jdbc.PreparedSql;
88
import org.seasar.doma.jdbc.SqlKind;
99
import org.seasar.doma.jdbc.SqlLogType;
10+
import org.seasar.doma.jdbc.criteria.context.Context;
1011
import org.seasar.doma.jdbc.criteria.context.Criterion;
1112
import org.seasar.doma.jdbc.criteria.context.DeleteContext;
1213
import org.seasar.doma.jdbc.criteria.metamodel.EntityMetamodel;
14+
import org.seasar.doma.jdbc.dialect.Dialect;
1315

1416
public class DeleteBuilder {
1517
private final Config config;
@@ -28,7 +30,7 @@ public DeleteBuilder(
2830
context,
2931
commenter,
3032
new PreparedSqlBuilder(config, SqlKind.DELETE, sqlLogType),
31-
new AliasManager(context));
33+
createAliasManager(config, context));
3234
}
3335

3436
public DeleteBuilder(
@@ -46,14 +48,29 @@ public DeleteBuilder(
4648
support = new BuilderSupport(config, commenter, buf, aliasManager);
4749
}
4850

51+
private static AliasManager createAliasManager(Config config, Context context) {
52+
Objects.requireNonNull(config);
53+
Objects.requireNonNull(context);
54+
Dialect dialect = config.getDialect();
55+
if (dialect.supportsAliasInDeleteClause() || dialect.supportsAliasInDeleteStatement()) {
56+
return AliasManager.create(config, context);
57+
} else {
58+
return AliasManager.createEmpty(config, context);
59+
}
60+
}
61+
4962
public PreparedSql build() {
5063
buf.appendSql("delete");
5164
if (config.getDialect().supportsAliasInDeleteClause()) {
5265
buf.appendSql(" ");
5366
alias(context.entityMetamodel);
5467
}
5568
buf.appendSql(" from ");
56-
table(context.entityMetamodel);
69+
tableOnly(context.entityMetamodel);
70+
if (config.getDialect().supportsAliasInDeleteStatement()) {
71+
buf.appendSql(" ");
72+
alias(context.entityMetamodel);
73+
}
5774
if (!context.where.isEmpty()) {
5875
buf.appendSql(" where ");
5976
int index = 0;
@@ -70,8 +87,8 @@ private void alias(EntityMetamodel<?> entityMetamodel) {
7087
support.alias(entityMetamodel);
7188
}
7289

73-
private void table(EntityMetamodel<?> entityMetamodel) {
74-
support.table(entityMetamodel);
90+
private void tableOnly(EntityMetamodel<?> entityMetamodel) {
91+
support.tableOnly(entityMetamodel);
7592
}
7693

7794
private void visitCriterion(int index, Criterion criterion) {
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package org.seasar.doma.jdbc.criteria.query;
2+
3+
import java.util.List;
4+
import java.util.Map;
5+
import java.util.Objects;
6+
import java.util.function.Function;
7+
import org.seasar.doma.jdbc.Config;
8+
import org.seasar.doma.jdbc.criteria.context.Context;
9+
import org.seasar.doma.jdbc.criteria.metamodel.EntityMetamodel;
10+
import org.seasar.doma.jdbc.criteria.metamodel.PropertyMetamodel;
11+
12+
/**
13+
* The {@code EmptyAliasManager} class is a specialized implementation of {@code AliasManager} where
14+
* all aliases for entity and property metamodels are resolved to empty strings by default.
15+
*
16+
* <p>This class can be used when aliasing is not required, providing a simple and minimal alias
17+
* management strategy.
18+
*
19+
* <p>It provides functionality to manage alias mappings in a way that clears existing mappings and
20+
* replaces them with the provided or default alias resolution logic.
21+
*/
22+
class EmptyAliasManager extends AliasManager {
23+
24+
private final Config config;
25+
26+
EmptyAliasManager(Config config, Context context) {
27+
this(config, context, (__) -> "");
28+
}
29+
30+
@SuppressWarnings("deprecation")
31+
private EmptyAliasManager(
32+
Config config, Context context, Function<EntityMetamodel<?>, String> aliasResolver) {
33+
super(context);
34+
this.config = Objects.requireNonNull(config);
35+
replaceAliases(context.getEntityMetamodels(), entityAliasMap, propertyAliasMap, aliasResolver);
36+
}
37+
38+
private static void replaceAliases(
39+
List<EntityMetamodel<?>> entityMetamodels,
40+
Map<EntityMetamodel<?>, String> entityAliasMap,
41+
Map<PropertyMetamodel<?>, String> propertyAliasMap,
42+
Function<EntityMetamodel<?>, String> aliasResolver) {
43+
entityAliasMap.clear();
44+
propertyAliasMap.clear();
45+
for (EntityMetamodel<?> entityMetamodel : entityMetamodels) {
46+
String alias = aliasResolver.apply(entityMetamodel);
47+
entityAliasMap.put(entityMetamodel, alias);
48+
for (PropertyMetamodel<?> propertyMetamodel : entityMetamodel.allPropertyMetamodels()) {
49+
propertyAliasMap.put(propertyMetamodel, alias);
50+
}
51+
}
52+
}
53+
54+
@Override
55+
protected AliasManager asParent() {
56+
Function<EntityMetamodel<?>, String> aliasResolver = (m) -> getQualifiedTableName(config, m);
57+
return new EmptyAliasManager(config, context, aliasResolver);
58+
}
59+
60+
private static String getQualifiedTableName(Config config, EntityMetamodel<?> entityMetamodel) {
61+
return entityMetamodel
62+
.asType()
63+
.getQualifiedTableName(config.getNaming()::apply, config.getDialect()::applyQuote);
64+
}
65+
}

doma-core/src/main/java/org/seasar/doma/jdbc/criteria/query/InsertBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ private void select() {
8989
});
9090
buf.cutBackSql(2);
9191
buf.appendSql(") ");
92-
AliasManager aliasManager = new AliasManager(context.selectContext);
92+
AliasManager aliasManager = AliasManager.create(config, context.selectContext);
9393
SelectBuilder builder =
9494
new SelectBuilder(config, context.selectContext, Function.identity(), buf, aliasManager);
9595
builder.interpret();

doma-core/src/main/java/org/seasar/doma/jdbc/criteria/query/SelectBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public SelectBuilder(
4141
context,
4242
commenter,
4343
new PreparedSqlBuilder(config, SqlKind.SELECT, sqlLogType),
44-
new AliasManager(context));
44+
AliasManager.create(config, context));
4545
}
4646

4747
public SelectBuilder(

0 commit comments

Comments
 (0)