[jOOQ/jOOQ#11838] Add Settings.namePathSeparator
This commit includes some work on: - [jOOQ/jOOQ#2620] Add BigQuery support (WIP)
This commit is contained in:
parent
8ddc36485e
commit
6fa32f50dd
@ -95,6 +95,8 @@ public class Settings
|
||||
protected Boolean renderOutputForSQLServerReturningClause = true;
|
||||
@XmlElement(defaultValue = "false")
|
||||
protected Boolean renderParenthesisAroundSetOperationQueries = false;
|
||||
@XmlElement(defaultValue = ".")
|
||||
protected String namePathSeparator = ".";
|
||||
@XmlElement(defaultValue = "false")
|
||||
protected Boolean bindOffsetDateTimeType = false;
|
||||
@XmlElement(defaultValue = "false")
|
||||
@ -867,6 +869,44 @@ public class Settings
|
||||
this.renderParenthesisAroundSetOperationQueries = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* The character(s) to be used as a separator in paths encoded in a {@link Name}
|
||||
* <p>
|
||||
* A few hierarchical mapping features work with paths encoded in names (specifically field aliases), such as the reflective mapping of nested values when aliasing fields as:
|
||||
* <p>
|
||||
* <code><pre>
|
||||
* SELECT
|
||||
* a.first_name AS "book.author.firstName"
|
||||
* a.last_name AS "book.author.lastName"
|
||||
* FROM ...
|
||||
* </pre></code>
|
||||
* <p>
|
||||
* Not all dialects support "." in identifiers. This setting allows for specifying an alternative String to use as separator, e.g. "__".
|
||||
*
|
||||
*/
|
||||
public String getNamePathSeparator() {
|
||||
return namePathSeparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* The character(s) to be used as a separator in paths encoded in a {@link Name}
|
||||
* <p>
|
||||
* A few hierarchical mapping features work with paths encoded in names (specifically field aliases), such as the reflective mapping of nested values when aliasing fields as:
|
||||
* <p>
|
||||
* <code><pre>
|
||||
* SELECT
|
||||
* a.first_name AS "book.author.firstName"
|
||||
* a.last_name AS "book.author.lastName"
|
||||
* FROM ...
|
||||
* </pre></code>
|
||||
* <p>
|
||||
* Not all dialects support "." in identifiers. This setting allows for specifying an alternative String to use as separator, e.g. "__".
|
||||
*
|
||||
*/
|
||||
public void setNamePathSeparator(String value) {
|
||||
this.namePathSeparator = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the <code>java.time</code> (JSR 310) type {@link java.time.OffsetDateTime} should be bound natively to JDBC.
|
||||
* <p>
|
||||
@ -2987,6 +3027,26 @@ public class Settings
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The character(s) to be used as a separator in paths encoded in a {@link Name}
|
||||
* <p>
|
||||
* A few hierarchical mapping features work with paths encoded in names (specifically field aliases), such as the reflective mapping of nested values when aliasing fields as:
|
||||
* <p>
|
||||
* <code><pre>
|
||||
* SELECT
|
||||
* a.first_name AS "book.author.firstName"
|
||||
* a.last_name AS "book.author.lastName"
|
||||
* FROM ...
|
||||
* </pre></code>
|
||||
* <p>
|
||||
* Not all dialects support "." in identifiers. This setting allows for specifying an alternative String to use as separator, e.g. "__".
|
||||
*
|
||||
*/
|
||||
public Settings withNamePathSeparator(String value) {
|
||||
setNamePathSeparator(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Settings withBindOffsetDateTimeType(Boolean value) {
|
||||
setBindOffsetDateTimeType(value);
|
||||
return this;
|
||||
@ -3752,6 +3812,7 @@ public class Settings
|
||||
builder.append("renderOrderByRownumberForEmulatedPagination", renderOrderByRownumberForEmulatedPagination);
|
||||
builder.append("renderOutputForSQLServerReturningClause", renderOutputForSQLServerReturningClause);
|
||||
builder.append("renderParenthesisAroundSetOperationQueries", renderParenthesisAroundSetOperationQueries);
|
||||
builder.append("namePathSeparator", namePathSeparator);
|
||||
builder.append("bindOffsetDateTimeType", bindOffsetDateTimeType);
|
||||
builder.append("bindOffsetTimeType", bindOffsetTimeType);
|
||||
builder.append("fetchTriggerValuesAfterSQLServerOutput", fetchTriggerValuesAfterSQLServerOutput);
|
||||
@ -4080,6 +4141,15 @@ public class Settings
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (namePathSeparator == null) {
|
||||
if (other.namePathSeparator!= null) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!namePathSeparator.equals(other.namePathSeparator)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (bindOffsetDateTimeType == null) {
|
||||
if (other.bindOffsetDateTimeType!= null) {
|
||||
return false;
|
||||
@ -4930,6 +5000,7 @@ public class Settings
|
||||
result = ((prime*result)+((renderOrderByRownumberForEmulatedPagination == null)? 0 :renderOrderByRownumberForEmulatedPagination.hashCode()));
|
||||
result = ((prime*result)+((renderOutputForSQLServerReturningClause == null)? 0 :renderOutputForSQLServerReturningClause.hashCode()));
|
||||
result = ((prime*result)+((renderParenthesisAroundSetOperationQueries == null)? 0 :renderParenthesisAroundSetOperationQueries.hashCode()));
|
||||
result = ((prime*result)+((namePathSeparator == null)? 0 :namePathSeparator.hashCode()));
|
||||
result = ((prime*result)+((bindOffsetDateTimeType == null)? 0 :bindOffsetDateTimeType.hashCode()));
|
||||
result = ((prime*result)+((bindOffsetTimeType == null)? 0 :bindOffsetTimeType.hashCode()));
|
||||
result = ((prime*result)+((fetchTriggerValuesAfterSQLServerOutput == null)? 0 :fetchTriggerValuesAfterSQLServerOutput.hashCode()));
|
||||
|
||||
@ -69,6 +69,7 @@ final class ConstantSortField<T> extends CustomField<T> {
|
||||
|
||||
|
||||
|
||||
|
||||
case DERBY:
|
||||
case HSQLDB:
|
||||
case POSTGRES:
|
||||
|
||||
@ -1524,7 +1524,7 @@ final class CursorImpl<R extends Record> extends AbstractCursor<R> {
|
||||
Field<?> f = field instanceof Coerce ? ((Coerce<?>) field).field : field;
|
||||
|
||||
if (f instanceof RowField && NO_NATIVE_SUPPORT.contains(ctx.dialect())) {
|
||||
nested = ((RowField<?, ?>) f).emulatedFields();
|
||||
nested = ((RowField<?, ?>) f).emulatedFields(configuration);
|
||||
recordType = Tools.recordType(nested.size());
|
||||
}
|
||||
else if (f.getDataType().isEmbeddable()) {
|
||||
|
||||
@ -316,6 +316,7 @@ public class DefaultRecordMapper<R extends Record, E> implements RecordMapper<R,
|
||||
* This configuration can be used for caching reflection information.
|
||||
*/
|
||||
private final Configuration configuration;
|
||||
private final String namePathSeparator;
|
||||
|
||||
/**
|
||||
* A delegate mapper created from type information in <code>type</code>.
|
||||
@ -351,6 +352,7 @@ public class DefaultRecordMapper<R extends Record, E> implements RecordMapper<R,
|
||||
this.fields = rowType.fields();
|
||||
this.type = type;
|
||||
this.configuration = configuration != null ? configuration : new DefaultConfiguration();
|
||||
this.namePathSeparator = this.configuration.settings().getNamePathSeparator();
|
||||
|
||||
init(instance);
|
||||
}
|
||||
@ -798,11 +800,11 @@ public class DefaultRecordMapper<R extends Record, E> implements RecordMapper<R,
|
||||
|
||||
// No annotations are present
|
||||
else {
|
||||
int dot = name.indexOf('.');
|
||||
int separator = name.indexOf(namePathSeparator);
|
||||
|
||||
// A nested mapping is applied
|
||||
if (dot > -1) {
|
||||
String prefix = name.substring(0, dot);
|
||||
if (separator > -1) {
|
||||
String prefix = name.substring(0, separator);
|
||||
|
||||
if (nestedMappedFields == null)
|
||||
nestedMappedFields = new HashMap<>();
|
||||
@ -1026,8 +1028,8 @@ public class DefaultRecordMapper<R extends Record, E> implements RecordMapper<R,
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
Field<?> field = fields[i];
|
||||
String name = field.getName();
|
||||
int dot = name.indexOf('.');
|
||||
propertyIndexes[i] = prefixes().get(dot > -1 ? name.substring(0, dot) : name);
|
||||
int separator = name.indexOf(namePathSeparator);
|
||||
propertyIndexes[i] = prefixes().get(separator > -1 ? name.substring(0, separator) : name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1061,7 +1063,7 @@ public class DefaultRecordMapper<R extends Record, E> implements RecordMapper<R,
|
||||
}
|
||||
|
||||
for (int j = 0; j < propertyNames.size(); j++) {
|
||||
if (name.startsWith(propertyNames.get(j) + ".")) {
|
||||
if (name.startsWith(propertyNames.get(j) + namePathSeparator)) {
|
||||
propertyIndexes[i] = j;
|
||||
continue fieldLoop;
|
||||
}
|
||||
@ -1090,7 +1092,7 @@ public class DefaultRecordMapper<R extends Record, E> implements RecordMapper<R,
|
||||
}
|
||||
|
||||
for (int j = 0; j < fields.length; j++) {
|
||||
if (fields[j].getName().startsWith(prefix + ".")) {
|
||||
if (fields[j].getName().startsWith(prefix + namePathSeparator)) {
|
||||
hasNestedFields = true;
|
||||
|
||||
if (nestedMappedFields[i] == null)
|
||||
@ -1211,8 +1213,8 @@ public class DefaultRecordMapper<R extends Record, E> implements RecordMapper<R,
|
||||
|
||||
for (Field<?> field : fields) {
|
||||
String name = field.getName();
|
||||
int dot = name.indexOf('.');
|
||||
prefixes.computeIfAbsent(dot > -1 ? name.substring(0, dot) : name, k -> i[0]++);
|
||||
int separator = name.indexOf(namePathSeparator);
|
||||
prefixes.computeIfAbsent(separator > -1 ? name.substring(0, separator) : name, k -> i[0]++);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -76,6 +76,7 @@ import static org.jooq.JoinType.RIGHT_OUTER_JOIN;
|
||||
// ...
|
||||
// ...
|
||||
// ...
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.CUBRID;
|
||||
// ...
|
||||
// ...
|
||||
|
||||
@ -301,12 +301,6 @@ final class Limit extends AbstractQueryPart {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
default: {
|
||||
acceptDefault(ctx, castMode);
|
||||
break;
|
||||
|
||||
@ -75,6 +75,7 @@ import static org.jooq.impl.Tools.BooleanDataKey.DATA_LIST_ALREADY_INDENTED;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.Context;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.Name;
|
||||
@ -90,7 +91,6 @@ final class RowField<ROW extends Row, REC extends Record> extends AbstractField<
|
||||
static final Set<SQLDialect> NO_NATIVE_SUPPORT = SQLDialect.supportedBy(CUBRID, DERBY, FIREBIRD, H2, HSQLDB, IGNITE, MARIADB, MYSQL, SQLITE);
|
||||
|
||||
private final ROW row;
|
||||
private final AbstractRow<REC> emulatedFields;
|
||||
|
||||
RowField(ROW row) {
|
||||
this(row, N_ROW);
|
||||
@ -113,11 +113,11 @@ final class RowField<ROW extends Row, REC extends Record> extends AbstractField<
|
||||
)));
|
||||
|
||||
this.row = row;
|
||||
this.emulatedFields = (AbstractRow<REC>) row0(map(row.fields(), x -> x.as(as.unquotedName() + "." + x.getName()), Field[]::new));
|
||||
}
|
||||
|
||||
AbstractRow<REC> emulatedFields() {
|
||||
return emulatedFields;
|
||||
@SuppressWarnings("unchecked")
|
||||
AbstractRow<REC> emulatedFields(Configuration configuration) {
|
||||
return (AbstractRow<REC>) row0(map(row.fields(), x -> x.as(getUnqualifiedName().unquotedName() + configuration.settings().getNamePathSeparator() + x.getName()), Field[]::new));
|
||||
}
|
||||
|
||||
ROW row() {
|
||||
@ -127,7 +127,7 @@ final class RowField<ROW extends Row, REC extends Record> extends AbstractField<
|
||||
@Override
|
||||
public final void accept(Context<?> ctx) {
|
||||
if (NO_NATIVE_SUPPORT.contains(ctx.dialect()))
|
||||
ctx.data(DATA_LIST_ALREADY_INDENTED, true, c -> c.visit(new SelectFieldList<>(emulatedFields.fields.fields)));
|
||||
ctx.data(DATA_LIST_ALREADY_INDENTED, true, c -> c.visit(new SelectFieldList<>(emulatedFields(ctx.configuration()).fields.fields)));
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1761,6 +1761,7 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
case CUBRID:
|
||||
|
||||
@ -195,6 +195,21 @@ When this setting is set to <code>true</code> the queries combined with set oper
|
||||
For details, see <a href="https://github.com/jOOQ/jOOQ/issues/3676">https://github.com/jOOQ/jOOQ/issues/3676</a> and <a href="https://github.com/jOOQ/jOOQ/issues/9751">https://github.com/jOOQ/jOOQ/issues/9751</a>.]]></jxb:javadoc></jxb:property></appinfo></annotation>
|
||||
</element>
|
||||
|
||||
<element name="namePathSeparator" type="string" minOccurs="0" maxOccurs="1" default=".">
|
||||
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[The character(s) to be used as a separator in paths encoded in a {@link Name}
|
||||
<p>
|
||||
A few hierarchical mapping features work with paths encoded in names (specifically field aliases), such as the reflective mapping of nested values when aliasing fields as:
|
||||
<p>
|
||||
<code><pre>
|
||||
SELECT
|
||||
a.first_name AS "book.author.firstName"
|
||||
a.last_name AS "book.author.lastName"
|
||||
FROM ...
|
||||
</pre></code>
|
||||
<p>
|
||||
Not all dialects support "." in identifiers. This setting allows for specifying an alternative String to use as separator, e.g. "__".]]></jxb:javadoc></jxb:property></appinfo></annotation>
|
||||
</element>
|
||||
|
||||
<element name="bindOffsetDateTimeType" type="boolean" minOccurs="0" maxOccurs="1" default="false">
|
||||
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Whether the <code>java.time</code> (JSR 310) type {@link java.time.OffsetDateTime} should be bound natively to JDBC.
|
||||
<p>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user