/*
* Copyright 2020 nightfall.
*
* 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
*
* http://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.
*/
package ua.net.uid.utils.db.query;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public abstract class Condition implements QueryPart {
public static Condition raw(CharSequence condition, Object... params) {
if (condition == null)
throw new IllegalArgumentException("condition is null");
return new Raw(condition, params);
}
public static Condition not(CharSequence condition, Object... params) {
return new Not(raw(condition, params));
}
public static Condition not(Condition condition) {
if (condition == null) {
return null;
} else if (condition instanceof Not) {
return ((Not) condition).condition;
} else {
return new Not(condition);
}
}
public static Condition and(Condition left, Condition right) {
if (left != null) {
return right == null ? left : new And(left, right);
} else {
return right;
}
}
public static Condition and(Condition... conditions) {
if (conditions == null || conditions.length == 0) return null;
return conditions.length == 1 ? conditions[0] : new And(conditions);
}
public static Condition or(Condition... conditions) {
if (conditions == null || conditions.length == 0) return null;
return conditions.length == 1 ? conditions[0] : new Or(conditions);
}
public static Condition in(CharSequence left, Collection<?> items) {
if (left == null || left.length() == 0)
throw new IllegalArgumentException("left side parameter for 'in' condition is null");
if (items == null || items.isEmpty()) return null;
return new In(left, items.toArray(new Object[items.size()]));
}
public static Condition in(CharSequence left, Object... items) {
if (left == null || left.length() == 0)
throw new IllegalArgumentException("left side parameter for 'in' condition is null");
if (items == null || items.length == 0) return null;
return new In(left, items);
}
public Object[] toParams(Object... post) {
ArrayList<Object> params = new ArrayList<>();
bind(params);
if (post != null) Collections.addAll(params, post);
return params.toArray();
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
build(builder);
return builder.toString();
}
static final class Raw extends Condition {
private final CharSequence condition;
private final Object[] params;
Raw(CharSequence condition, Object[] params) {
this.condition = condition;
this.params = params;
}
@Override
public void build(StringBuilder builder) {
builder.append(condition);
}
@Override
public void bind(List<Object> params) {
Collections.addAll(params, this.params);
}
}
static final class Not extends Condition {
private final Condition condition;
Not(Condition condition) {
this.condition = condition;
}
@Override
public void build(StringBuilder builder) {
builder.append("NOT(");
condition.build(builder);
builder.append(')');
}
@Override
public void bind(List<Object> params) {
condition.bind(params);
}
}
static abstract class Block extends Condition {
final List<Condition> conditions;
Block(Condition... conditions) {
this.conditions = new ArrayList<>(conditions.length);
for (Condition condition : conditions)
if (condition != null) {
if (condition.getClass() == getClass()) {
this.conditions.addAll(((Block) condition).conditions);
} else {
this.conditions.add(condition);
}
}
}
@Override
public final void bind(List<Object> params) {
for (Condition condition : conditions)
condition.bind(params);
}
final void build(StringBuilder builder, String div) {
if (conditions.size() > 1) {
builder.append("(");
conditions.get(0).build(builder);
for (int i = 1; i < conditions.size(); ++i) {
builder.append(div);
conditions.get(i).build(builder);
}
builder.append(")");
} else {
conditions.get(0).build(builder);
}
}
}
static final class And extends Block {
And(Condition... conditions) {
super(conditions);
}
@Override
public void build(StringBuilder builder) {
build(builder, ") AND (");
}
}
static final class Or extends Block {
Or(Condition... conditions) {
super(conditions);
}
@Override
public void build(StringBuilder builder) {
build(builder, ") OR (");
}
}
static final class In extends Condition {
private final CharSequence left;
private final Object[] items;
public In(CharSequence left, Object[] items) {
this.left = left;
this.items = items;
}
@Override
public void build(StringBuilder builder) {
builder.append(left).append(" IN (?");
for (int i = 1; i < items.length; ++i) builder.append(",?");
builder.append(')');
}
@Override
public void bind(List<Object> params) {
Collections.addAll(params, items);
}
}
}