Skip to content

Commit a328f1e

Browse files
committed
Add SqlTable constructor with single Supplier
Also rename the table name "getter" to be more accurate.
1 parent 971d65a commit a328f1e

File tree

10 files changed

+111
-42
lines changed

10 files changed

+111
-42
lines changed

src/main/java/org/mybatis/dynamic/sql/SqlTable.java

+10-4
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,16 @@ public class SqlTable {
2424

2525
private Supplier<String> nameSupplier;
2626

27-
protected SqlTable(String fullyQualifiedTableName) {
28-
Objects.requireNonNull(fullyQualifiedTableName);
27+
protected SqlTable(String tableName) {
28+
Objects.requireNonNull(tableName);
29+
30+
this.nameSupplier = () -> tableName;
31+
}
32+
33+
protected SqlTable(Supplier<String> tableNameSupplier) {
34+
Objects.requireNonNull(tableNameSupplier);
2935

30-
this.nameSupplier = () -> fullyQualifiedTableName;
36+
this.nameSupplier = tableNameSupplier;
3137
}
3238

3339
protected SqlTable(Supplier<Optional<String>> schemaSupplier, String tableName) {
@@ -69,7 +75,7 @@ private String composeCatalogSchemaAndAndTable(String catalog, String schema, St
6975
return catalog + "." + schema + "." + tableName; //$NON-NLS-1$ //$NON-NLS-2$
7076
}
7177

72-
public String fullyQualifiedTableName() {
78+
public String tableNameAtRuntime() {
7379
return nameSupplier.get();
7480
}
7581

src/main/java/org/mybatis/dynamic/sql/delete/render/DeleteRenderer.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ private Optional<WhereClauseProvider> renderWhereClause(WhereModel whereModel) {
5858

5959
private String calculateDeleteStatement(Optional<WhereClauseProvider> whereClause) {
6060
return "delete from" //$NON-NLS-1$
61-
+ spaceBefore(deleteModel.table().fullyQualifiedTableName())
61+
+ spaceBefore(deleteModel.table().tableNameAtRuntime())
6262
+ spaceBefore(whereClause.map(WhereClauseProvider::getWhereClause));
6363
}
6464

src/main/java/org/mybatis/dynamic/sql/insert/render/BatchInsertRenderer.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ private FieldAndValue toFieldAndValue(ValuePhraseVisitor visitor, InsertMapping
5454

5555
private String calculateInsertStatement(FieldAndValueCollector<T> collector) {
5656
return "insert into" //$NON-NLS-1$
57-
+ spaceBefore(model.table().fullyQualifiedTableName())
57+
+ spaceBefore(model.table().tableNameAtRuntime())
5858
+ spaceBefore(collector.columnsPhrase())
5959
+ spaceBefore(collector.valuesPhrase());
6060
}

src/main/java/org/mybatis/dynamic/sql/insert/render/InsertRenderer.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public InsertStatementProvider<T> render() {
4646

4747
private String calculateInsertStatement(FieldAndValueCollector<T> collector) {
4848
return "insert into" //$NON-NLS-1$
49-
+ spaceBefore(model.table().fullyQualifiedTableName())
49+
+ spaceBefore(model.table().tableNameAtRuntime())
5050
+ spaceBefore(collector.columnsPhrase())
5151
+ spaceBefore(collector.valuesPhrase());
5252
}

src/main/java/org/mybatis/dynamic/sql/insert/render/InsertSelectRenderer.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public InsertSelectStatementProvider render() {
4747

4848
private String calculateInsertStatement(SelectStatementProvider selectStatement) {
4949
return "insert into" //$NON-NLS-1$
50-
+ spaceBefore(model.table().fullyQualifiedTableName())
50+
+ spaceBefore(model.table().tableNameAtRuntime())
5151
+ spaceBefore(calculateColumnsPhrase())
5252
+ spaceBefore(selectStatement.getSelectStatement());
5353
}

src/main/java/org/mybatis/dynamic/sql/render/GuaranteedTableAliasCalculator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ private GuaranteedTableAliasCalculator(Map<SqlTable, String> aliases) {
3737
public Optional<String> aliasForColumn(SqlTable table) {
3838
return super.aliasForColumn(table)
3939
.map(Optional::of)
40-
.orElse(Optional.of(table.fullyQualifiedTableName()));
40+
.orElse(Optional.of(table.tableNameAtRuntime()));
4141
}
4242

4343
public static TableAliasCalculator of(Map<SqlTable, String> aliases) {

src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionModel.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ public Optional<GroupByModel> groupByModel() {
8888
}
8989

9090
public String calculateTableNameIncludingAlias(SqlTable table) {
91-
return table.fullyQualifiedTableName()
91+
return table.tableNameAtRuntime()
9292
+ spaceBefore(tableAliasCalculator.aliasForTable(table));
9393
}
9494

src/main/java/org/mybatis/dynamic/sql/update/render/UpdateRenderer.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ private FragmentCollector calculateColumnMappings() {
6565

6666
private String calculateUpdateStatement(FragmentCollector fc, Optional<WhereClauseProvider> whereClause) {
6767
return "update" //$NON-NLS-1$
68-
+ spaceBefore(updateModel.table().fullyQualifiedTableName())
68+
+ spaceBefore(updateModel.table().tableNameAtRuntime())
6969
+ spaceBefore(calculateSetPhrase(fc))
7070
+ spaceBefore(whereClause.map(WhereClauseProvider::getWhereClause));
7171
}

src/site/markdown/docs/databaseObjects.md

+57-15
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,25 @@ MyBatis Dynamic SQL works with Java objects that represent relational tables or
33

44
## Table or View Representation
55

6-
The class `SqlTable` is used to represent a table or view in a database. An `SqlTable` holds a name, and a collection of `SqlColumn` objects that represent the columns in a table or view.
6+
The class `org.mybatis.dynamic.sql.SqlTable` is used to represent a table or view in a database. An `SqlTable` holds a name, and a collection of `SqlColumn` objects that represent the columns in a table or view.
77

8-
A fully qualified name has three parts:
8+
A table or view name in SQL has three parts:
99

10-
1. The catalog - which is rarely used outside of Microsoft SQL Server
11-
1. The schema - which is often specified, but may be left blank if you are operating on tables in the default schema
12-
1. The name - which is required
10+
1. The catalog - which is optional and is rarely used outside of Microsoft SQL Server. If unspecified the default catalog will be used - and many databases only have one catalog
11+
1. The schema - which is optional but is very often specified. If unspecified the default schema will be used
12+
1. The table name - which is required
1313

14-
Typical examples of fully qualified names are as follows:
14+
Typical examples of names are as follows:
1515

16-
- `"dbo..bar"` - a fully qualified name with a catalog (dbo) and a name (bar). This is typical for SQL Server
17-
- `"foo.bar"` - a fully qualified name with a schema (foo) and a name (bar). This is typical in many databases when you want to access tables that are not in the default schema
18-
- `"bar"` - a fully qualified name with just a name (bar). This will access a table or view in the default catalog and schema for a connection
16+
- `"dbo..bar"` - a name with a catalog (dbo) and a table name (bar). This is typical for SQL Server
17+
- `"foo.bar"` - a name with a schema (foo) and a table name (bar). This is typical in many databases when you want to access tables that are not in the default schema
18+
- `"bar"` - a name with just a table name (bar). This will access a table or view in the default catalog and schema for a connection
1919

20+
In MyBatis Dynamic SQL, the table or view name can be specified in different ways:
2021

21-
In MyBatis Dynamic SQL, the fully qualified name can be specified in different ways:
22-
23-
1. The fully qualified table name can be a constant String
24-
1. The fully qualified table name can be calculated at runtime based on a dynamic catalog and/or schema and a constant table name
22+
1. The name can be a constant String
23+
1. The name can be calculated at runtime based on a catalog and/or schema supplier functions and a constant table name
24+
1. The name can be calculated at runtime with a name supplier function
2525

2626
### Constant Names
2727

@@ -45,8 +45,7 @@ public class MyTable extends SqlTable {
4545
}
4646
```
4747

48-
49-
### Dynamic Names
48+
### Dynamic Catalog and/or Schema Names
5049
MyBatis Dynamic SQL allows you to dynamically specify a catalog and/or schema. This is useful for applications where the schema may change for different users or environments, or if you are using different schemas to shard the database. Dynamic names are used when you use a `SqlTable` constructor that accepts one or more `java.util.function.Supplier` arguments.
5150

5251
For example, suppose you wanted to change the schema based on the value of a system property. You could write a class like this:
@@ -98,5 +97,48 @@ Catalog Supplier Value | Schema Supplier Value | Name | Fully Qualified Name
9897
&lt;empty&gt; | &lt;empty&gt; | "MyTable" | "MyTable"
9998

10099

100+
### Fully Dynamic Names
101+
MyBatis Dynamic SQL allows you to dynamically specify a full table name. This is useful for applications where the database is sharded with different tables representing different shards of the whole. Dynamic names are used when you use a `SqlTable` constructor that accepts a single `java.util.function.Supplier` argument.
102+
103+
Note that this functionality should only be used for tables that have different names, but are otherwise identical.
104+
105+
For example, suppose you wanted to change the name based on the value of a system property. You could write a class like this:
106+
107+
```java
108+
public class NameSupplier {
109+
public static final String name_property = "nameToUse";
110+
111+
public static String namePropertyReader() {
112+
return System.getProperty(name_property);
113+
}
114+
}
115+
```
116+
117+
This class has a static method `namePropertyReader` that will return an `String` containing the value of a system property. You could then reference this method in the constructor of the `SqlTable` like this:
118+
119+
```java
120+
public static final class User extends SqlTable {
121+
public User() {
122+
super(NameSupplier::namePropertyReader);
123+
}
124+
}
125+
```
126+
127+
Whenever the table is referenced for rendering SQL, the name will be calculated based on the current value of the system property.
128+
129+
101130

102131
## Column Representation
132+
133+
The class `org.mybatis.dynamic.sql.SqlColumn` is used to represent a column in a table or view. An `SqlColumn` is always associated with a `SqlTable`. In it's most basic form, the `SqlColumn` class holds a name and a reference to the `SqlTable` it is associated with.
134+
135+
The `SqlColumn` class has additional optional attributes that are useful for SQL rendering - especially in MyBatis3. These include:
136+
137+
* The `java.sql.JDBCType` of the column. This will be rendered into the MyBatis3 compatible parameter marker - which helps with picking type handlers and also inserting or updating null capable fields
138+
* A String containing a type handler - either a type handler alias or the fully qualified type of a type handler. This will be rendered into the MyBatis3 compatible parameter marker
139+
140+
If you are not using MyBatis3, then you will not need to specify the JDBC Type or type handler.
141+
142+
Finally, the `SqlColumn` class has methods to designate a column alias or sort order for use in different SQL statements.
143+
144+
We recommend a usage pattern for creating table and column objects that provides quite a bit of flexibility for usage. See the [Quick Start](quickStart.html) page for a complete example.

src/test/java/org/mybatis/dynamic/sql/SqlTableTest.java

+37-16
Original file line numberDiff line numberDiff line change
@@ -23,82 +23,103 @@
2323
import org.junit.jupiter.api.Test;
2424

2525
public class SqlTableTest {
26+
27+
private static final String NAME_PROPERTY = "nameProperty";
28+
29+
@Test
30+
public void testFullName() {
31+
SqlTable table = new SqlTable("my_table");
32+
assertThat(table.tableNameAtRuntime()).isEqualTo("my_table");
33+
}
34+
35+
@Test
36+
public void testFullNameSupplier() {
37+
38+
System.setProperty(NAME_PROPERTY, "my_table");
39+
SqlTable table = new SqlTable(SqlTableTest::namePropertyReader);
40+
assertThat(table.tableNameAtRuntime()).isEqualTo("my_table");
41+
System.clearProperty(NAME_PROPERTY);
42+
}
2643

2744
@Test
2845
public void testSchemaSupplierEmpty() {
2946
SqlTable table = new SqlTable(Optional::empty, "my_table");
30-
assertThat(table.fullyQualifiedTableName()).isEqualTo("my_table");
47+
assertThat(table.tableNameAtRuntime()).isEqualTo("my_table");
3148
}
3249

3350
@Test
3451
public void testSchemaSupplierWithValue() {
3552
SqlTable table = new SqlTable(() -> Optional.of("my_schema"), "my_table");
36-
assertThat(table.fullyQualifiedTableName()).isEqualTo("my_schema.my_table");
53+
assertThat(table.tableNameAtRuntime()).isEqualTo("my_schema.my_table");
3754
}
3855

3956
@Test
4057
public void testSingletonSchemaSupplier() {
4158
SqlTable table = new SqlTable(MySchemaSupplier.instance(), "my_table");
42-
assertThat(table.fullyQualifiedTableName()).isEqualTo("first_schema.my_table");
59+
assertThat(table.tableNameAtRuntime()).isEqualTo("first_schema.my_table");
4360
}
4461

4562
@Test
4663
public void testThatSchemaSupplierDoesDelay() {
4764
MySchemaSupplier schemaSupplier = new MySchemaSupplier();
4865
SqlTable table = new SqlTable(schemaSupplier, "my_table");
49-
assertThat(table.fullyQualifiedTableName()).isEqualTo("first_schema.my_table");
66+
assertThat(table.tableNameAtRuntime()).isEqualTo("first_schema.my_table");
5067

5168
schemaSupplier.setFirst(false);
52-
assertThat(table.fullyQualifiedTableName()).isEqualTo("second_schema.my_table");
69+
assertThat(table.tableNameAtRuntime()).isEqualTo("second_schema.my_table");
5370
}
5471

5572
@Test
5673
public void testCatalogAndSchemaSupplierEmpty() {
5774
SqlTable table = new SqlTable(Optional::empty, Optional::empty, "my_table");
58-
assertThat(table.fullyQualifiedTableName()).isEqualTo("my_table");
75+
assertThat(table.tableNameAtRuntime()).isEqualTo("my_table");
5976
}
6077

6178
@Test
6279
public void testCatalogSupplierWithValue() {
6380
SqlTable table = new SqlTable(() -> Optional.of("my_catalog"), Optional::empty, "my_table");
64-
assertThat(table.fullyQualifiedTableName()).isEqualTo("my_catalog..my_table");
81+
assertThat(table.tableNameAtRuntime()).isEqualTo("my_catalog..my_table");
6582
}
6683

6784
@Test
6885
public void testThatCatalogSupplierDoesDelay() {
6986
MyCatalogSupplier catalogSupplier = new MyCatalogSupplier();
7087
SqlTable table = new SqlTable(catalogSupplier, Optional::empty, "my_table");
71-
assertThat(table.fullyQualifiedTableName()).isEqualTo("first_catalog..my_table");
88+
assertThat(table.tableNameAtRuntime()).isEqualTo("first_catalog..my_table");
7289

7390
catalogSupplier.setFirst(false);
74-
assertThat(table.fullyQualifiedTableName()).isEqualTo("second_catalog..my_table");
91+
assertThat(table.tableNameAtRuntime()).isEqualTo("second_catalog..my_table");
7592
}
7693

7794
@Test
7895
public void testThatCatalogSupplierAndSchemaSupplierBothDelay() {
7996
MyCatalogSupplier catalogSupplier = new MyCatalogSupplier();
8097
MySchemaSupplier schemaSupplier = new MySchemaSupplier();
8198
SqlTable table = new SqlTable(catalogSupplier, schemaSupplier, "my_table");
82-
assertThat(table.fullyQualifiedTableName()).isEqualTo("first_catalog.first_schema.my_table");
99+
assertThat(table.tableNameAtRuntime()).isEqualTo("first_catalog.first_schema.my_table");
83100

84101
catalogSupplier.setFirst(false);
85-
assertThat(table.fullyQualifiedTableName()).isEqualTo("second_catalog.first_schema.my_table");
102+
assertThat(table.tableNameAtRuntime()).isEqualTo("second_catalog.first_schema.my_table");
86103

87104
catalogSupplier.setFirst(true);
88105
schemaSupplier.setFirst(false);
89-
assertThat(table.fullyQualifiedTableName()).isEqualTo("first_catalog.second_schema.my_table");
106+
assertThat(table.tableNameAtRuntime()).isEqualTo("first_catalog.second_schema.my_table");
90107

91108
catalogSupplier.setFirst(false);
92-
assertThat(table.fullyQualifiedTableName()).isEqualTo("second_catalog.second_schema.my_table");
109+
assertThat(table.tableNameAtRuntime()).isEqualTo("second_catalog.second_schema.my_table");
93110

94111
catalogSupplier.setEmpty(true);
95-
assertThat(table.fullyQualifiedTableName()).isEqualTo("second_schema.my_table");
112+
assertThat(table.tableNameAtRuntime()).isEqualTo("second_schema.my_table");
96113

97114
schemaSupplier.setEmpty(true);
98-
assertThat(table.fullyQualifiedTableName()).isEqualTo("my_table");
115+
assertThat(table.tableNameAtRuntime()).isEqualTo("my_table");
99116

100117
catalogSupplier.setEmpty(false);
101-
assertThat(table.fullyQualifiedTableName()).isEqualTo("second_catalog..my_table");
118+
assertThat(table.tableNameAtRuntime()).isEqualTo("second_catalog..my_table");
119+
}
120+
121+
private static String namePropertyReader() {
122+
return System.getProperty(NAME_PROPERTY);
102123
}
103124

104125
public static class MySchemaSupplier implements Supplier<Optional<String>> {

0 commit comments

Comments
 (0)