package org.jooq.impl;
import static org.jooq.SQLDialect.CUBRID;
import static org.jooq.SQLDialect.MARIADB;
import static org.jooq.SQLDialect.MYSQL;
import static org.jooq.SQLDialect.SQLITE;
import static org.jooq.impl.DSL.nvl2;
import static org.jooq.impl.DSL.one;
import static org.jooq.impl.DSL.zero;
import static org.jooq.impl.Keywords.K_NULLS_FIRST;
import static org.jooq.impl.Keywords.K_NULLS_LAST;
import java.util.Set;
import org.jooq.Context;
import org.jooq.Field;
import org.jooq.SQLDialect;
import org.jooq.SortField;
import org.jooq.SortOrder;
final class SortFieldImpl<T> extends AbstractQueryPart implements SortField<T> {
private static final long serialVersionUID = 1223739398544155873L;
private static final Set<SQLDialect> NO_SUPPORT_NULLS = SQLDialect.supportedUntil(CUBRID, MARIADB, MYSQL);
private final Field<T> field;
private final SortOrder order;
private boolean nullsFirst;
private boolean nullsLast;
SortFieldImpl(Field<T> field, SortOrder order) {
this.field = field;
this.order = order;
}
@Override
public final String getName() {
return field.getName();
}
@Override
public final SortOrder getOrder() {
return order;
}
final Field<T> getField() {
return field;
}
final boolean getNullsFirst() {
return nullsFirst;
}
final boolean getNullsLast() {
return nullsLast;
}
@SuppressWarnings("unchecked")
final <U> SortField<U> transform(Field<U> newField) {
if (newField == field)
return (SortFieldImpl<U>) this;
SortField<U> r = newField.sort(order);
return nullsFirst ? r.nullsFirst() : nullsLast ? r.nullsLast() : r;
}
@Override
public final SortField<T> nullsFirst() {
nullsFirst = true;
nullsLast = false;
return this;
}
@Override
public final SortField<T> nullsLast() {
nullsFirst = false;
nullsLast = true;
return this;
}
@Override
public final void accept(Context<?> ctx) {
if (nullsFirst || nullsLast) {
if (NO_SUPPORT_NULLS.contains(ctx.dialect())) {
Field<Integer> ifNull = nullsFirst ? zero() : one();
Field<Integer> ifNotNull = nullsFirst ? one() : zero();
ctx.visit(nvl2(field, ifNotNull, ifNull))
.sql(", ");
acceptFieldAndOrder(ctx, false);
}
else {
acceptFieldAndOrder(ctx, true);
}
}
else {
acceptFieldAndOrder(ctx, false);
}
}
private final void acceptFieldAndOrder(Context<?> ctx, boolean includeNulls) {
String separator = "";
for (Field<?> f : Tools.flatten(field)) {
ctx.sql(separator).visit(f);
if (order != SortOrder.DEFAULT)
ctx.sql(' ')
.visit(order.toKeyword());
if (includeNulls)
if (nullsFirst)
ctx.sql(' ').visit(K_NULLS_FIRST);
else
ctx.sql(' ').visit(K_NULLS_LAST);
separator = ", ";
}
}
}