[jOOQ/jOOQ#11672] Function and QueryPartCollectionView formatting

improvements

This includes:
- [jOOQ/jOOQ#11673] Emulate NVL using COALESCE instead of CASE, where possible
- [jOOQ/jOOQ9085] NVL should generate NVL for the DEFAULT dialect
This commit is contained in:
Lukas Eder 2021-03-19 11:07:11 +01:00
parent fadd3aa05a
commit d43fc234ef
25 changed files with 55 additions and 56 deletions

View File

@ -54,7 +54,7 @@ import org.jooq.WindowSpecification;
*
* @author Lukas Eder
*/
abstract class AbstractName extends AbstractQueryPart implements Name {
abstract class AbstractName extends AbstractQueryPart implements Name, SimpleQueryPart {
/**
* Generated UID

View File

@ -64,7 +64,7 @@ import org.jooq.tools.StringUtils;
*
* @author Lukas Eder
*/
abstract class AbstractParam<T> extends AbstractParamX<T> {
abstract class AbstractParam<T> extends AbstractParamX<T> implements SimpleQueryPart {
/**
* Generated UID

View File

@ -124,7 +124,7 @@ abstract class AbstractRow extends AbstractQueryPart implements Row {
ctx.sql("(")
.visit(wrap(fields.fields).indentSize(0))
.visit(wrap(fields.fields))
.sql(")");
}

View File

@ -305,7 +305,7 @@ final class Alias<Q extends QueryPart> extends AbstractQueryPart {
if (context.declareTables() && o instanceof ArrayTable)
context.sql('(')
.visit(wrap(((ArrayTable) o).fields()).qualify(false).indentSize(0))
.visit(wrap(((ArrayTable) o).fields()).qualify(false))
.sql(')');
break;
@ -352,7 +352,7 @@ final class Alias<Q extends QueryPart> extends AbstractQueryPart {
}
private final void toSQLDerivedColumnList(Context<?> ctx) {
ctx.sql(" (").visit(wrap(fieldAliases).indentSize(0)).sql(')');
ctx.sql(" (").visit(wrap(fieldAliases)).sql(')');
}
@Override

View File

@ -80,7 +80,7 @@ final class Coalesce<T> extends AbstractField<T> {
default: {
ctx.visit(DSL.function("coalesce", getDataType(), fields));
ctx.visit(DSL.function(N_COALESCE, getDataType(), fields));
break;
}
}

View File

@ -160,7 +160,7 @@ final class ForLock extends AbstractQueryPart {
// Render the OF [table-names] clause
default:
ctx.visit(wrap(forLockOfTables).qualify(false).indentSize(0));
ctx.visit(wrap(forLockOfTables).qualify(false));
break;
}
}

View File

@ -170,7 +170,7 @@ implements
public final void accept(Context<?> ctx) {
ctx.start(Clause.GRANT_PRIVILEGE)
.visit(K_GRANT).sql(' ')
.visit(QueryPartCollectionView.wrap(privileges).indentSize(0))
.visit(QueryPartCollectionView.wrap(privileges))
.end(Clause.GRANT_PRIVILEGE).sql(' ')
.start(Clause.GRANT_ON)
.visit(K_ON).sql(' ')

View File

@ -475,7 +475,7 @@ implements
ctx.formatSeparator()
.start(TABLE_JOIN_USING)
.visit(K_USING)
.sql(" (").visit(wrap(using).indentSize(0).qualify(false)).sql(')')
.sql(" (").visit(wrap(using).qualify(false)).sql(')')
.end(TABLE_JOIN_USING);
}

View File

@ -90,7 +90,6 @@ final class Keywords {
static final Keyword K_CHANGE_COLUMN = keyword("change column");
static final Keyword K_CHARACTER_SET = keyword("character set");
static final Keyword K_CHECK = keyword("check");
static final Keyword K_COALESCE = keyword("coalesce");
static final Keyword K_COLLATE = keyword("collate");
static final Keyword K_COLLATION = keyword("collation");
static final Keyword K_COLUMN = keyword("column");

View File

@ -37,6 +37,7 @@
*/
package org.jooq.impl;
import static org.jooq.impl.DSL.function;
import static org.jooq.impl.Keywords.K_NULL;
import static org.jooq.impl.Names.N_IIF;
import static org.jooq.impl.Names.N_NULLIF;
@ -74,7 +75,7 @@ final class NullIf<T> extends AbstractField<T> {
default:
ctx.visit(N_NULLIF).sql('(').visit(arg1).sql(", ").visit(arg2).sql(')');
ctx.visit(function(N_NULLIF, getDataType(), arg1, arg2));
break;
}
}

View File

@ -37,7 +37,7 @@
*/
package org.jooq.impl;
import static org.jooq.impl.Keywords.K_COALESCE;
import static org.jooq.impl.DSL.function;
import static org.jooq.impl.Keywords.K_IS_NULL;
import static org.jooq.impl.Names.N_IFNULL;
import static org.jooq.impl.Names.N_IIF;
@ -79,16 +79,22 @@ final class Nvl<T> extends AbstractField<T> {
case H2:
case HSQLDB:
ctx.visit(N_NVL).sql('(').visit(arg1).sql(", ").visit(arg2).sql(')');
break;
case CUBRID:
case DERBY:
case IGNITE:
case FIREBIRD:
case POSTGRES:
ctx.visit(K_COALESCE).sql('(').visit(arg1).sql(", ").visit(arg2).sql(')');
ctx.visit(DSL.coalesce(arg1, arg2));
break;
@ -97,11 +103,11 @@ final class Nvl<T> extends AbstractField<T> {
case MARIADB:
case MYSQL:
case SQLITE:
ctx.visit(N_IFNULL).sql('(').visit(arg1).sql(", ").visit(arg2).sql(')');
ctx.visit(function(N_IFNULL, getDataType(), arg1, arg2));
break;
default:
ctx.visit(DSL.when(arg1.isNotNull(), arg1).otherwise(arg2));
ctx.visit(function(N_NVL, getDataType(), arg1, arg2));
break;
}
}

View File

@ -39,7 +39,7 @@ package org.jooq.impl;
import static org.jooq.conf.ParamType.INLINED;
import static org.jooq.impl.DSL.inlined;
import static org.jooq.impl.Keywords.K_COALESCE;
import static org.jooq.impl.Names.N_COALESCE;
import static org.jooq.impl.PositionalWindowFunction.PositionalFunctionType.LAG;
import static org.jooq.impl.PositionalWindowFunction.PositionalFunctionType.LEAD;

View File

@ -47,7 +47,7 @@ import org.jooq.Privilege;
/**
* @author Timur Shaidullin
*/
final class PrivilegeImpl extends AbstractQueryPart implements Privilege {
final class PrivilegeImpl extends AbstractQueryPart implements Privilege, SimpleQueryPart {
/**
* Generated UID

View File

@ -65,7 +65,6 @@ class QueryPartCollectionView<T extends QueryPart> extends AbstractQueryPart imp
private static final long serialVersionUID = -2936922742534009564L;
final Collection<T> wrapped;
int indentSize;
Boolean qualify;
String separator;
Function<? super T, ? extends T> mapper;
@ -76,18 +75,9 @@ class QueryPartCollectionView<T extends QueryPart> extends AbstractQueryPart imp
QueryPartCollectionView(Collection<T> wrapped) {
this.wrapped = wrapped != null ? wrapped : Collections.emptyList();
this.indentSize = 2;
this.separator = ",";
}
/**
* Whether to indent this list, and after what size indentation is applied.
*/
QueryPartCollectionView<T> indentSize(int newIndentSize) {
this.indentSize = newIndentSize <= 0 ? Integer.MAX_VALUE : newIndentSize;
return this;
}
QueryPartCollectionView<T> qualify(boolean newQualify) {
this.qualify = newQualify;
return this;
@ -121,7 +111,7 @@ class QueryPartCollectionView<T extends QueryPart> extends AbstractQueryPart imp
rendersContent.set(i++, ((QueryPartInternal) e).rendersContent(ctx));
int size = rendersContent.cardinality();
boolean format = ctx.format() && size >= indentSize;
boolean format = ctx.format() && (size >= 2 && requireIndentation());
boolean previousQualify = ctx.qualify();
boolean previousAlreadyIndented = TRUE.equals(ctx.data(DATA_LIST_ALREADY_INDENTED));
boolean indent = format && !previousAlreadyIndented;
@ -194,6 +184,14 @@ class QueryPartCollectionView<T extends QueryPart> extends AbstractQueryPart imp
ctx.data(DATA_LIST_ALREADY_INDENTED, previousAlreadyIndented);
}
private final boolean requireIndentation() {
for (T t : this)
if (!Tools.isSimple(t))
return true;
return false;
}
/**
* Subclasses may override this method
*/

View File

@ -68,11 +68,6 @@ class QueryPartList<T extends QueryPart> extends QueryPartListView<T> {
addAll(wrappedList);
}
@Override
QueryPartList<T> indentSize(int newIndentSize) {
return (QueryPartList<T>) super.indentSize(newIndentSize);
}
@Override
QueryPartList<T> qualify(boolean newQualify) {
return (QueryPartList<T>) super.qualify(newQualify);

View File

@ -76,11 +76,6 @@ class QueryPartListView<T extends QueryPart> extends QueryPartCollectionView<T>
super(wrappedList);
}
@Override
QueryPartListView<T> indentSize(int newIndentSize) {
return (QueryPartListView<T>) super.indentSize(newIndentSize);
}
@Override
QueryPartListView<T> qualify(boolean newQualify) {
return (QueryPartListView<T>) super.qualify(newQualify);

View File

@ -169,7 +169,7 @@ implements
ctx.visit(K_GRANT_OPTION_FOR)
.sql(' ');
ctx.visit(QueryPartCollectionView.wrap(privileges).indentSize(0))
ctx.visit(QueryPartCollectionView.wrap(privileges))
.end(Clause.REVOKE_PRIVILEGE).sql(' ')
.start(Clause.REVOKE_ON)
.visit(K_ON).sql(' ')

View File

@ -47,5 +47,4 @@ import org.jooq.QueryPartInternal;
*
* @author Lukas Eder
*/
interface ScopeMappable extends QueryPartInternal {
}
interface ScopeMappable extends QueryPartInternal {}

View File

@ -37,8 +37,6 @@
*/
package org.jooq.impl;
import org.jooq.Context;
import org.jooq.QueryPart;
import org.jooq.QueryPartInternal;
/**
@ -46,5 +44,4 @@ import org.jooq.QueryPartInternal;
*
* @author Lukas Eder
*/
interface ScopeNestable extends QueryPartInternal {
}
interface ScopeNestable extends QueryPartInternal {}

View File

@ -67,7 +67,7 @@ import org.jooq.SQLDialect;
import org.jooq.SortField;
import org.jooq.SortOrder;
final class SortFieldImpl<T> extends AbstractQueryPart implements SortField<T> {
final class SortFieldImpl<T> extends AbstractQueryPart implements SortField<T>, SimpleQueryPart {
/**
* Generated UID
@ -87,6 +87,11 @@ final class SortFieldImpl<T> extends AbstractQueryPart implements SortField<T> {
this.order = order;
}
@Override
public boolean isSimple() {
return !nullsFirst && !nullsLast && Tools.isSimple(field);
}
@Override
public final String getName() {
return field.getName();

View File

@ -126,6 +126,7 @@ extends
case MARIADB:

View File

@ -162,9 +162,9 @@ extends
}
if (length == null)
ctx.visit(functionName).sql('(').visit(string).sql(", ").visit(startingPosition).sql(')');
ctx.visit(function(functionName, getDataType(), string, startingPosition));
else
ctx.visit(functionName).sql('(').visit(string).sql(", ").visit(startingPosition).sql(", ").visit(length).sql(')');
ctx.visit(function(functionName, getDataType(), string, startingPosition, length));
}

View File

@ -58,7 +58,7 @@ import org.jooq.tools.StringUtils;
*
* @author Lukas Eder
*/
class TableFieldImpl<R extends Record, T> extends AbstractField<T> implements TableField<R, T> {
class TableFieldImpl<R extends Record, T> extends AbstractField<T> implements TableField<R, T>, SimpleQueryPart {
private static final long serialVersionUID = -2211214195583539735L;
private static final Clause[] CLAUSES = { FIELD, FIELD_REFERENCE };

View File

@ -84,7 +84,7 @@ import org.jooq.tools.StringUtils;
* @author Lukas Eder
*/
@org.jooq.Internal
public class TableImpl<R extends Record> extends AbstractTable<R> implements ScopeMappable, ScopeNestable {
public class TableImpl<R extends Record> extends AbstractTable<R> implements ScopeMappable, ScopeNestable, SimpleQueryPart {
private static final long serialVersionUID = 261033315221985068L;
private static final Clause[] CLAUSES_TABLE_REFERENCE = { TABLE, TABLE_REFERENCE };

View File

@ -3149,8 +3149,11 @@ final class Tools {
}
static final boolean isWindow(Field<?> f) {
return f instanceof AbstractWindowFunction
&& ((AbstractWindowFunction<?>) f).isWindow();
return f instanceof AbstractWindowFunction && ((AbstractWindowFunction<?>) f).isWindow();
}
static final boolean isSimple(QueryPart part) {
return part instanceof SimpleQueryPart && ((SimpleQueryPart) part).isSimple();
}
static final Val<?> extractVal(Field<?> field) {