[jOOQ/jOOQ#13631] Add Context.topLevel() and Context.topLevelForLanguageContext() to give access to the top level QueryPart type that is being rendered

This commit is contained in:
Lukas Eder 2022-06-02 09:50:13 +02:00
parent 91438c5122
commit 2bd740ecca
4 changed files with 137 additions and 70 deletions

View File

@ -272,6 +272,32 @@ public interface Context<C extends Context<C>> extends ExecuteScope {
@NotNull
C declareCTE(boolean declareCTE, Consumer<? super C> consumer);
/**
* The top level {@link QueryPart} that is being rendered.
*/
@Nullable
QueryPart topLevel();
/**
* Set the top level {@link QueryPart} that is being rendered.
*/
@NotNull
C topLevel(QueryPart topLevel);
/**
* The top level {@link QueryPart} that is being rendered in the current
* {@link #languageContext()}.
*/
@Nullable
QueryPart topLevelForLanguageContext();
/**
* Set the top level {@link QueryPart} that is being rendered in the current
* {@link #languageContext()}.
*/
@NotNull
C topLevelForLanguageContext(QueryPart topLevelForLanguageContext);
/**
* Whether the current context is rendering a subquery (nested query).
*/
@ -895,6 +921,13 @@ public interface Context<C extends Context<C>> extends ExecuteScope {
@NotNull
C languageContext(LanguageContext languageContext, Consumer<? super C> consumer);
/**
* Set the new language context for {@link #languageContext()} for the scope
* of a {@link Consumer}.
*/
@NotNull
C languageContext(LanguageContext languageContext, QueryPart topLevelForLanguageContext, Consumer<? super C> consumer);
/**
* Set the new language context for {@link #languageContext()}, if a
* condition is true.

View File

@ -104,8 +104,6 @@ import org.jooq.impl.Tools.DataKey;
import org.jooq.impl.Tools.DataKeyScopeStackPart;
import org.jooq.tools.StringUtils;
import org.jetbrains.annotations.Nullable;
/**
* @author Lukas Eder
@ -158,6 +156,8 @@ abstract class AbstractContext<C extends Context<C>> extends AbstractScope imple
boolean quote = true;
boolean qualifySchema = true;
boolean qualifyCatalog = true;
QueryPart topLevel;
QueryPart topLevelForLanguageContext;
// [#11711] Enforcing scientific notation
private transient DecimalFormat doubleFormat;
@ -257,6 +257,15 @@ abstract class AbstractContext<C extends Context<C>> extends AbstractScope imple
@Override
public final C visit(QueryPart part) {
if (part != null) {
if (topLevel == null) {
topLevel = topLevelForLanguageContext = part;
if (TRUE.equals(settings().isTransformPatterns()) && configuration().requireCommercial(() -> "SQL transformations are a commercial only feature. Please consider upgrading to the jOOQ Professional Edition or jOOQ Enterprise Edition.")) {
}
}
// Issue start clause events
// -----------------------------------------------------------------
@ -680,6 +689,28 @@ abstract class AbstractContext<C extends Context<C>> extends AbstractScope imple
return scopeStack.scopeLevel();
}
@Override
public final QueryPart topLevel() {
return topLevel;
}
@Override
public final C topLevel(QueryPart t) {
topLevel = t;
return (C) this;
}
@Override
public final QueryPart topLevelForLanguageContext() {
return topLevelForLanguageContext;
}
@Override
public final C topLevelForLanguageContext(QueryPart t) {
topLevelForLanguageContext = t;
return (C) this;
}
@Override
public final int subqueryLevel() {
return subquery;
@ -1036,6 +1067,20 @@ abstract class AbstractContext<C extends Context<C>> extends AbstractScope imple
return toggle(context, this::languageContext, this::languageContext, consumer);
}
@Override
public final C languageContext(LanguageContext context, QueryPart newTopLevelForLanguageContext, Consumer<? super C> consumer) {
return toggle(context,
this::languageContext,
this::languageContext,
c -> toggle(
newTopLevelForLanguageContext,
this::topLevelForLanguageContext,
this::topLevelForLanguageContext,
consumer
)
);
}
@Override
public final C languageContextIf(LanguageContext context, boolean condition) {
if (condition)

View File

@ -410,73 +410,72 @@ final class BlockImpl extends AbstractRowCountQuery implements Block {
}
}
else {
DefaultRenderContext r = ctx instanceof DefaultRenderContext d
? d
: null;
statementLoop:
for (Statement s : statements) {
if (s instanceof NullStatement && !SUPPORTS_NULL_STATEMENT.contains(ctx.dialect()))
continue statementLoop;
LanguageContext language = ctx.languageContext();
ctx.languageContextIf(LanguageContext.QUERY, s instanceof Query && !(s instanceof Block));
ctx.formatSeparator();
int position = r != null ? r.sql.length() : 0;
ctx.visit(s);
// [#11374] [#11367] TODO Improve this clunky semi colon decision logic
if (position < (r != null ? r.sql.length() : 0))
semicolonAfterStatement(ctx, s);
ctx.languageContext(language);
if (s instanceof Query && !(s instanceof Block))
ctx.languageContext(LanguageContext.QUERY, s, c -> accept2(c, s));
else
accept2(ctx, s);
}
}
}
private static final void accept2(Context<?> ctx, Statement s) {
ctx.formatSeparator();
int position = ctx instanceof DefaultRenderContext d ? d.sql.length() : 0;
ctx.visit(s);
// [#11374] [#11367] TODO Improve this clunky semi colon decision logic
if (position < (ctx instanceof DefaultRenderContext d ? d.sql.length() : 0))
semicolonAfterStatement(ctx, s);
}
private static final void semicolonAfterStatement(Context<?> ctx, Statement s) {
if (s instanceof Block)
return;

View File

@ -104,7 +104,6 @@ class DefaultRenderContext extends AbstractContext<RenderContext> implements Ren
private boolean separatorRequired;
private boolean separator;
private boolean newline;
private Boolean isQuery;
// [#1632] Cached values from Settings
RenderKeywordCase cachedRenderKeywordCase;
@ -385,7 +384,7 @@ class DefaultRenderContext extends AbstractContext<RenderContext> implements Ren
String prepend = null;
String append = null;
if (TRUE.equals(isQuery)) {
if (topLevel instanceof Query) {
prepend = (String) data(DATA_PREPEND_SQL);
append = (String) data(DATA_APPEND_SQL);
}
@ -712,15 +711,6 @@ class DefaultRenderContext extends AbstractContext<RenderContext> implements Ren
@Override
protected final void visit0(QueryPartInternal internal) {
if (isQuery == null) {
isQuery = internal instanceof Query;
if (TRUE.equals(settings().isTransformPatterns()) && configuration().requireCommercial(() -> "SQL transformations are a commercial only feature. Please consider upgrading to the jOOQ Professional Edition or jOOQ Enterprise Edition.")) {
}
}