[jOOQ/jOOQ#13640] [jOOQ/jOOQ#14155] Add QOM.Decode
This includes: - [jOOQ/jOOQ#13640] Adding QOM.Decode - [jOOQ/jOOQ#14155] Render correct empty Decode content - Refactoring CaseSimple and Decode to have a common base impl
This commit is contained in:
parent
b0de1c595c
commit
eadd4e885d
189
jOOQ/src/main/java/org/jooq/impl/AbstractCaseSimple.java
Normal file
189
jOOQ/src/main/java/org/jooq/impl/AbstractCaseSimple.java
Normal file
@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Other licenses:
|
||||
* -----------------------------------------------------------------------------
|
||||
* Commercial licenses for this work are available. These replace the above
|
||||
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
|
||||
* database integrations.
|
||||
*
|
||||
* For more information, please visit: https://www.jooq.org/legal/licensing
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.impl.Names.NQ_CASE;
|
||||
import static org.jooq.impl.QOM.tuple;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jooq.DataType;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.Function3;
|
||||
import org.jooq.Name;
|
||||
import org.jooq.impl.QOM.Tuple2;
|
||||
import org.jooq.impl.QOM.UnmodifiableList;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
abstract class AbstractCaseSimple<V, T, CS extends AbstractCaseSimple<V, T, CS>>
|
||||
extends
|
||||
AbstractField<T>
|
||||
{
|
||||
|
||||
final Field<V> value;
|
||||
final List<Tuple2<Field<V>, Field<T>>> when;
|
||||
Field<T> else_;
|
||||
|
||||
AbstractCaseSimple(Name name, Field<V> value, Field<V> compareValue, Field<T> result) {
|
||||
this(name, value, result.getDataType());
|
||||
|
||||
when(compareValue, result);
|
||||
}
|
||||
|
||||
AbstractCaseSimple(Name name, Field<V> value, Map<? extends Field<V>, ? extends Field<T>> map) {
|
||||
this(name, value, dataType(map));
|
||||
|
||||
mapFields(map);
|
||||
}
|
||||
|
||||
AbstractCaseSimple(Name name, Field<V> value, DataType<T> type) {
|
||||
super(name, type);
|
||||
|
||||
this.value = value;
|
||||
this.when = new QueryPartList<>();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static final <T> DataType<T> dataType(Map<? extends Field<?>, ? extends Field<T>> map) {
|
||||
if (map.isEmpty())
|
||||
return (DataType<T>) SQLDataType.OTHER;
|
||||
else
|
||||
return map.entrySet().iterator().next().getValue().getDataType();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX: QueryPart API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// @Override
|
||||
public final CS when(V compareValue, T result) {
|
||||
return when(Tools.field(compareValue, value), Tools.field(result));
|
||||
}
|
||||
|
||||
// @Override
|
||||
public final CS when(V compareValue, Field<T> result) {
|
||||
return when(Tools.field(compareValue, value), result);
|
||||
}
|
||||
|
||||
// @Override
|
||||
public final CS when(Field<V> compareValue, T result) {
|
||||
return when(compareValue, Tools.field(result));
|
||||
}
|
||||
|
||||
// @Override
|
||||
public final CS when(Field<V> compareValue, Field<T> result) {
|
||||
when.add(tuple(compareValue, result));
|
||||
|
||||
return (CS) this;
|
||||
}
|
||||
|
||||
// @Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public final CS mapValues(Map<V, T> values) {
|
||||
values.forEach((k, v) -> when(k, v));
|
||||
return (CS) this;
|
||||
}
|
||||
|
||||
// @Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public final CS mapFields(Map<? extends Field<V>, ? extends Field<T>> fields) {
|
||||
fields.forEach((k, v) -> when(k, v));
|
||||
return (CS) this;
|
||||
}
|
||||
|
||||
// @Override
|
||||
public final Field<T> else_(T result) {
|
||||
return else_(Tools.field(result));
|
||||
}
|
||||
|
||||
// @Override
|
||||
public final Field<T> else_(Field<T> result) {
|
||||
this.else_ = result;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX: Query Object Model
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
abstract CS construct(Field<V> v, DataType<T> t);
|
||||
|
||||
// @Override
|
||||
public final Function3<? super Field<V>, ? super UnmodifiableList<? extends Tuple2<Field<V>, Field<T>>>, ? super Field<T>, ? extends CS> $constructor() {
|
||||
return (v, w, e) -> {
|
||||
CS r = construct(v, getDataType());
|
||||
w.forEach(t -> r.when(t.$1(), t.$2()));
|
||||
r.else_(e);
|
||||
return r;
|
||||
};
|
||||
}
|
||||
|
||||
// @Override
|
||||
public final Field<V> $arg1() {
|
||||
return value;
|
||||
}
|
||||
|
||||
// @Override
|
||||
public final CS $arg1(Field<V> newArg1) {
|
||||
return $constructor().apply(newArg1, $arg2(), $arg3());
|
||||
}
|
||||
|
||||
// @Override
|
||||
public final UnmodifiableList<? extends Tuple2<Field<V>, Field<T>>> $arg2() {
|
||||
return QOM.unmodifiable(when);
|
||||
}
|
||||
|
||||
// @Override
|
||||
public final CS $arg2(UnmodifiableList<? extends Tuple2<Field<V>, Field<T>>> w) {
|
||||
return $constructor().apply($arg1(), w, $arg3());
|
||||
}
|
||||
|
||||
// @Override
|
||||
public final Field<T> $arg3() {
|
||||
return else_;
|
||||
}
|
||||
|
||||
// @Override
|
||||
public final CS $arg3(Field<T> e) {
|
||||
return $constructor().apply($arg1(), $arg2(), e);
|
||||
}
|
||||
}
|
||||
@ -48,10 +48,8 @@ import static org.jooq.impl.Keywords.K_THEN;
|
||||
import static org.jooq.impl.Keywords.K_TRUE;
|
||||
import static org.jooq.impl.Keywords.K_WHEN;
|
||||
import static org.jooq.impl.Names.NQ_CASE;
|
||||
import static org.jooq.impl.QOM.tuple;
|
||||
import static org.jooq.impl.Tools.BooleanDataKey.DATA_FORCE_CASE_ELSE_NULL;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jooq.CaseConditionStep;
|
||||
@ -59,51 +57,33 @@ import org.jooq.CaseWhenStep;
|
||||
import org.jooq.Context;
|
||||
import org.jooq.DataType;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.Function3;
|
||||
// ...
|
||||
import org.jooq.QueryPart;
|
||||
// ...
|
||||
// ...
|
||||
import org.jooq.impl.QOM.Tuple2;
|
||||
import org.jooq.impl.QOM.UnmodifiableList;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class CaseSimple<V, T>
|
||||
extends
|
||||
AbstractField<T>
|
||||
AbstractCaseSimple<V, T, CaseSimple<V, T>>
|
||||
implements
|
||||
CaseWhenStep<V, T>,
|
||||
QOM.CaseSimple<V, T>
|
||||
{
|
||||
|
||||
private final Field<V> value;
|
||||
private final List<Tuple2<Field<V>, Field<T>>> when;
|
||||
private Field<T> else_;
|
||||
|
||||
CaseSimple(Field<V> value, Field<V> compareValue, Field<T> result) {
|
||||
this(value, result.getDataType());
|
||||
|
||||
when(compareValue, result);
|
||||
super(NQ_CASE, value, compareValue, result);
|
||||
}
|
||||
|
||||
CaseSimple(Field<V> value, Map<? extends Field<V>, ? extends Field<T>> map) {
|
||||
this(value, dataType(map));
|
||||
|
||||
mapFields(map);
|
||||
super(NQ_CASE, value, map);
|
||||
}
|
||||
|
||||
CaseSimple(Field<V> value, DataType<T> type) {
|
||||
super(NQ_CASE, type);
|
||||
|
||||
this.value = value;
|
||||
this.when = new QueryPartList<>();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static final <T> DataType<T> dataType(Map<? extends Field<?>, ? extends Field<T>> map) {
|
||||
if (map.isEmpty())
|
||||
return (DataType<T>) SQLDataType.OTHER;
|
||||
else
|
||||
return map.entrySet().iterator().next().getValue().getDataType();
|
||||
super(NQ_CASE, value, type);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@ -120,52 +100,6 @@ implements
|
||||
return else_(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Field<T> else_(T result) {
|
||||
return else_(Tools.field(result));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Field<T> else_(Field<T> result) {
|
||||
this.else_ = result;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final CaseWhenStep<V, T> when(V compareValue, T result) {
|
||||
return when(Tools.field(compareValue, value), Tools.field(result));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final CaseWhenStep<V, T> when(V compareValue, Field<T> result) {
|
||||
return when(Tools.field(compareValue, value), result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final CaseWhenStep<V, T> when(Field<V> compareValue, T result) {
|
||||
return when(compareValue, Tools.field(result));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final CaseWhenStep<V, T> when(Field<V> compareValue, Field<T> result) {
|
||||
when.add(tuple(compareValue, result));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final CaseWhenStep<V, T> mapValues(Map<V, T> values) {
|
||||
values.forEach((k, v) -> when(k, v));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final CaseWhenStep<V, T> mapFields(Map<? extends Field<V>, ? extends Field<T>> fields) {
|
||||
fields.forEach((k, v) -> when(k, v));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void accept(Context<?> ctx) {
|
||||
if (when.isEmpty()) {
|
||||
@ -290,42 +224,21 @@ implements
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final Function3<? super Field<V>, ? super UnmodifiableList<? extends Tuple2<Field<V>, Field<T>>>, ? super Field<T>, ? extends CaseSimple<V, T>> $constructor() {
|
||||
return (v, w, e) -> {
|
||||
CaseSimple<V, T> r = new CaseSimple<>(v, getDataType());
|
||||
w.forEach(t -> r.when(t.$1(), t.$2()));
|
||||
r.else_(e);
|
||||
return r;
|
||||
};
|
||||
final CaseSimple<V, T> construct(Field<V> v, DataType<T> t) {
|
||||
return new CaseSimple<>(v, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Field<V> $arg1() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final CaseSimple<V, T> $arg1(Field<V> newArg1) {
|
||||
return $constructor().apply(newArg1, $when(), $else());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final UnmodifiableList<? extends Tuple2<Field<V>, Field<T>>> $arg2() {
|
||||
return QOM.unmodifiable(when);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final CaseSimple<V, T> $arg2(UnmodifiableList<? extends Tuple2<Field<V>, Field<T>>> w) {
|
||||
return $constructor().apply($value(), w, $else());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Field<T> $arg3() {
|
||||
return else_;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final CaseSimple<V, T> $arg3(Field<T> e) {
|
||||
return $constructor().apply($value(), $when(), e);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -37,58 +37,99 @@
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.SQLDialect.*;
|
||||
// ...
|
||||
// ...
|
||||
// ...
|
||||
// ...
|
||||
// ...
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.CUBRID;
|
||||
import static org.jooq.SQLDialect.DERBY;
|
||||
import static org.jooq.SQLDialect.FIREBIRD;
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.HSQLDB;
|
||||
// ...
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.MARIADB;
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.MYSQL;
|
||||
import static org.jooq.SQLDialect.POSTGRES;
|
||||
// ...
|
||||
// ...
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.SQLITE;
|
||||
// ...
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.YUGABYTEDB;
|
||||
import static org.jooq.impl.DSL.function;
|
||||
import static org.jooq.impl.Names.N_DECODE;
|
||||
import static org.jooq.impl.Names.N_MAP;
|
||||
import static org.jooq.impl.Tools.EMPTY_FIELD;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jooq.CaseConditionStep;
|
||||
import org.jooq.Context;
|
||||
import org.jooq.DataType;
|
||||
import org.jooq.Field;
|
||||
// ...
|
||||
import org.jooq.QueryPart;
|
||||
// ...
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.impl.QOM.UNotYetImplemented;
|
||||
// ...
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class Decode<T, Z> extends AbstractField<Z> implements UNotYetImplemented {
|
||||
final class Decode<V, T>
|
||||
extends
|
||||
AbstractCaseSimple<V, T, Decode<V, T>>
|
||||
implements
|
||||
QOM.Decode<V, T>
|
||||
{
|
||||
private static final Set<SQLDialect> EMULATE_DISTINCT = SQLDialect.supportedBy(CUBRID, DERBY, FIREBIRD, HSQLDB, MARIADB, MYSQL, POSTGRES, SQLITE, YUGABYTEDB);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private final Field<T> field;
|
||||
private final Field<T> search;
|
||||
private final Field<Z> result;
|
||||
private final Field<?>[] more;
|
||||
@SuppressWarnings("unchecked")
|
||||
Decode(Field<V> field, Field<V> search, Field<T> result, Field<?>[] more) {
|
||||
super(N_DECODE, field, result.getDataType());
|
||||
|
||||
public Decode(Field<T> field, Field<T> search, Field<Z> result, Field<?>[] more) {
|
||||
super(N_DECODE, result.getDataType());
|
||||
when(search, result);
|
||||
if (more.length > 1)
|
||||
for (int i = 0; i + 1 < more.length; i += 2)
|
||||
when((Field<V>) more[i], (Field<T>) more[i + 1]);
|
||||
|
||||
this.field = field;
|
||||
this.search = search;
|
||||
this.result = result;
|
||||
this.more = more;
|
||||
if (more.length % 2 != 0)
|
||||
else_((Field<T>) more[more.length - 1]);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Decode(Field<V> field, DataType<T> type) {
|
||||
super(N_DECODE, field, type);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX: QueryPart API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final void accept(Context<?> ctx) {
|
||||
if (EMULATE_DISTINCT.contains(ctx.dialect())) {
|
||||
ctx.visit(Tools.derivedTableIf(ctx, more.length > 1, field, f -> {
|
||||
CaseConditionStep<Z> when = DSL.choose().when(f.isNotDistinctFrom(search), result);
|
||||
ctx.visit(Tools.derivedTableIf(ctx, !when.isEmpty(), value, f -> {
|
||||
CaseSearched<T> c = new CaseSearched<>(getDataType());
|
||||
|
||||
for (int i = 0; i + 1 < more.length; i += 2)
|
||||
when = when.when(f.isNotDistinctFrom((Field<T>) more[i]), (Field<Z>) more[i + 1]);
|
||||
// .when(f.isNotDistinctFrom(search), result)
|
||||
when.forEach(t -> {
|
||||
c.when(f.isNotDistinctFrom(t.$1()), t.$2());
|
||||
});
|
||||
|
||||
if (more.length % 2 == 0)
|
||||
return when;
|
||||
if (else_ == null)
|
||||
return c;
|
||||
else
|
||||
return when.otherwise((Field<Z>) more[more.length - 1]);
|
||||
return c.else_(else_);
|
||||
}));
|
||||
}
|
||||
|
||||
@ -98,6 +139,44 @@ final class Decode<T, Z> extends AbstractField<Z> implements UNotYetImplemented
|
||||
|
||||
|
||||
else
|
||||
ctx.visit(function(N_DECODE, getDataType(), Tools.combine(field, search, result, more)));
|
||||
ctx.visit(function(N_DECODE, getDataType(), args()));
|
||||
}
|
||||
|
||||
final Field<?>[] args() {
|
||||
List<Field<?>> result = new ArrayList<>();
|
||||
|
||||
result.add(value);
|
||||
when.forEach(t -> {
|
||||
result.add(t.$1());
|
||||
result.add(t.$2());
|
||||
});
|
||||
|
||||
if (else_ != null)
|
||||
result.add(else_);
|
||||
|
||||
return result.toArray(EMPTY_FIELD);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX: Query Object Model
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
final Decode<V, T> construct(Field<V> v, DataType<T> t) {
|
||||
return new Decode<>(v, t);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -1242,6 +1242,19 @@ public final class QOM {
|
||||
@NotNull default CaseSearched<T> $else(Field<T> else_) { return $arg2(else_); }
|
||||
}
|
||||
|
||||
public /*sealed*/ interface Decode<V, T>
|
||||
extends
|
||||
Field<T>,
|
||||
UOperator3<Field<V>, UnmodifiableList<? extends Tuple2<Field<V>, Field<T>>>, Field<T>, Decode<V, T>>
|
||||
{
|
||||
@NotNull default Field<V> $value() { return $arg1(); }
|
||||
@NotNull default Decode<V, T> $value(Field<V> value) { return $arg1(value); }
|
||||
@NotNull default UnmodifiableList<? extends Tuple2<Field<V>, Field<T>>> $when() { return $arg2(); }
|
||||
@NotNull default Decode<V, T> $when(UnmodifiableList<? extends Tuple2<Field<V>, Field<T>>> when) { return $arg2(when); }
|
||||
@Nullable default Field<T> $else() { return $arg3(); }
|
||||
@NotNull default Decode<V, T> $else(Field<T> else_) { return $arg3(else_); }
|
||||
}
|
||||
|
||||
public /*sealed*/ interface Concat
|
||||
extends
|
||||
Field<String>,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user