mirror of https://github.com/tasks/tasks
Convert sql package to Kotlin
parent
71721f982a
commit
3841a16607
@ -1,143 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
|
||||
package com.todoroo.andlib.data;
|
||||
|
||||
import static org.tasks.Strings.isNullOrEmpty;
|
||||
|
||||
import com.todoroo.andlib.sql.Field;
|
||||
|
||||
/**
|
||||
* Property represents a typed column in a database.
|
||||
*
|
||||
* <p>Within a given database row, the parameter may not exist, in which case the value is null, it
|
||||
* may be of an incorrect type, in which case an exception is thrown, or the correct type, in which
|
||||
* case the value is returned.
|
||||
*
|
||||
* @param <TYPE> a database supported type, such as String or Integer
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*/
|
||||
public abstract class Property<TYPE> extends Field implements Cloneable {
|
||||
|
||||
// --- implementation
|
||||
|
||||
/** The database column name for this property */
|
||||
public final String name;
|
||||
/** The database table name this property */
|
||||
private final Table table;
|
||||
|
||||
/**
|
||||
* Create a property by table and column name. Uses the default property expression which is
|
||||
* derived from default table name
|
||||
*/
|
||||
Property(Table table, String columnName) {
|
||||
this(table, columnName, (table == null) ? (columnName) : (table.name() + "." + columnName));
|
||||
}
|
||||
|
||||
/** Create a property by table and column name, manually specifying an expression to use in SQL */
|
||||
Property(Table table, String columnName, String expression) {
|
||||
super(expression);
|
||||
this.table = table;
|
||||
this.name = columnName;
|
||||
}
|
||||
|
||||
/** Return a clone of this property */
|
||||
@Override
|
||||
public Property<TYPE> clone() {
|
||||
try {
|
||||
return (Property<TYPE>) super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Return a clone of this property */
|
||||
Property<TYPE> cloneAs(String tableAlias, String columnAlias) {
|
||||
Table aliasedTable = this.table;
|
||||
if (!isNullOrEmpty(tableAlias)) {
|
||||
aliasedTable = table.as(tableAlias);
|
||||
}
|
||||
|
||||
try {
|
||||
Property<TYPE> newInstance =
|
||||
this.getClass()
|
||||
.getConstructor(Table.class, String.class)
|
||||
.newInstance(aliasedTable, this.name);
|
||||
if (!isNullOrEmpty(columnAlias)) {
|
||||
return (Property<TYPE>) newInstance.as(columnAlias);
|
||||
}
|
||||
return newInstance;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Integer property type. See {@link Property}
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*/
|
||||
public static class IntegerProperty extends Property<Integer> {
|
||||
|
||||
public IntegerProperty(Table table, String name) {
|
||||
super(table, name);
|
||||
}
|
||||
|
||||
IntegerProperty(String name, String expression) {
|
||||
super(null, name, expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntegerProperty as(String newAlias) {
|
||||
return (IntegerProperty) super.as(newAlias);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* String property type. See {@link Property}
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*/
|
||||
public static class StringProperty extends Property<String> {
|
||||
|
||||
public StringProperty(Table table, String name) {
|
||||
super(table, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringProperty as(String newAlias) {
|
||||
return (StringProperty) super.as(newAlias);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Long property type. See {@link Property}
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*/
|
||||
public static class LongProperty extends Property<Long> {
|
||||
|
||||
public LongProperty(Table table, String name) {
|
||||
super(table, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LongProperty cloneAs(String tableAlias, String columnAlias) {
|
||||
return (LongProperty) super.cloneAs(tableAlias, columnAlias);
|
||||
}
|
||||
}
|
||||
|
||||
// --- pseudo-properties
|
||||
|
||||
/** Runs a SQL function and returns the result as a string */
|
||||
public static class CountProperty extends IntegerProperty {
|
||||
|
||||
public CountProperty() {
|
||||
super("count", "COUNT(1)");
|
||||
alias = "count";
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package com.todoroo.andlib.data
|
||||
|
||||
import com.todoroo.andlib.sql.Field
|
||||
|
||||
class Property internal constructor(@JvmField val name: String?, expression: String) : Field(expression) {
|
||||
|
||||
constructor(table: Table, columnName: String) : this(columnName, "${table.name()}.$columnName")
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
|
||||
package com.todoroo.andlib.data;
|
||||
|
||||
import com.todoroo.andlib.sql.SqlTable;
|
||||
|
||||
/**
|
||||
* Table class. Most fields are final, so methods such as <code>as</code> will clone the table when
|
||||
* it returns.
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*/
|
||||
public final class Table extends SqlTable {
|
||||
|
||||
private final String name;
|
||||
|
||||
public Table(String name) {
|
||||
this(name, null);
|
||||
}
|
||||
|
||||
private Table(String name, String alias) {
|
||||
super(name);
|
||||
this.name = name;
|
||||
this.alias = alias;
|
||||
}
|
||||
|
||||
/** Create a new join table based on this table, but with an alias */
|
||||
@Override
|
||||
public Table as(String newAlias) {
|
||||
return new Table(name, newAlias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (hasAlias()) {
|
||||
return expression + " AS " + alias; // $NON-NLS-1$
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
|
||||
public String name() {
|
||||
if (hasAlias()) {
|
||||
return alias;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.todoroo.andlib.data
|
||||
|
||||
import com.todoroo.andlib.sql.DBObject
|
||||
|
||||
class Table private constructor(private val name: String, alias: String?) : DBObject<Table>(name) {
|
||||
|
||||
constructor(name: String) : this(name, null)
|
||||
|
||||
fun column(column: String): Property = Property(this, column)
|
||||
|
||||
override fun `as`(newAlias: String) = Table(name, newAlias)
|
||||
|
||||
override fun toString(): String = alias?.let { "$expression AS $alias" } ?: expression
|
||||
|
||||
fun name() = alias ?: name
|
||||
|
||||
init {
|
||||
this.alias = alias
|
||||
}
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
import static com.todoroo.andlib.sql.SqlConstants.AND;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.LEFT_PARENTHESIS;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.OR;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.RIGHT_PARENTHESIS;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
|
||||
|
||||
public abstract class Criterion {
|
||||
|
||||
final Operator operator;
|
||||
|
||||
public Criterion(Operator operator) {
|
||||
this.operator = operator;
|
||||
}
|
||||
|
||||
public static Criterion and(final Criterion criterion, final Criterion... criterions) {
|
||||
return new Criterion(Operator.and) {
|
||||
|
||||
@Override
|
||||
protected void populate(StringBuilder sb) {
|
||||
sb.append(criterion);
|
||||
for (Criterion c : criterions) {
|
||||
sb.append(SPACE).append(AND).append(SPACE).append(c);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Criterion or(final Criterion criterion, final Criterion... criterions) {
|
||||
return new Criterion(Operator.or) {
|
||||
|
||||
@Override
|
||||
protected void populate(StringBuilder sb) {
|
||||
sb.append(criterion);
|
||||
for (Criterion c : criterions) {
|
||||
sb.append(SPACE).append(OR).append(SPACE).append(c.toString());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected abstract void populate(StringBuilder sb);
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder(LEFT_PARENTHESIS);
|
||||
populate(builder);
|
||||
builder.append(RIGHT_PARENTHESIS);
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.todoroo.andlib.sql
|
||||
|
||||
abstract class Criterion(val operator: Operator) {
|
||||
|
||||
protected abstract fun populate(): String
|
||||
|
||||
override fun toString() = "(${populate()})"
|
||||
|
||||
companion object {
|
||||
@JvmStatic fun and(criterion: Criterion?, vararg criterions: Criterion?): Criterion {
|
||||
return object : Criterion(Operator.and) {
|
||||
override fun populate() = criterion.plus(criterions).joinToString(" AND ")
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic fun or(criterion: Criterion?, vararg criterions: Criterion): Criterion {
|
||||
return object : Criterion(Operator.or) {
|
||||
override fun populate() = criterion.plus(criterions).joinToString(" OR ")
|
||||
}
|
||||
}
|
||||
|
||||
operator fun <T> T.plus(tail: Array<out T>): List<T> {
|
||||
val list = ArrayList<T>(1 + tail.size)
|
||||
|
||||
list.add(this)
|
||||
list.addAll(tail)
|
||||
|
||||
return list
|
||||
}
|
||||
}
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
import static com.todoroo.andlib.sql.SqlConstants.AS;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public abstract class DBObject<T extends DBObject<?>> implements Cloneable {
|
||||
|
||||
protected final String expression;
|
||||
protected String alias;
|
||||
|
||||
DBObject(String expression) {
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
public T as(String newAlias) {
|
||||
try {
|
||||
T clone = (T) clone();
|
||||
clone.alias = newAlias;
|
||||
return clone;
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean hasAlias() {
|
||||
return alias != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof DBObject)) {
|
||||
return false;
|
||||
}
|
||||
DBObject<?> dbObject = (DBObject<?>) o;
|
||||
return Objects.equals(expression, dbObject.expression) && Objects.equals(alias, dbObject.alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(expression, alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (hasAlias()) {
|
||||
return alias;
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
|
||||
public final String toStringInSelect() {
|
||||
StringBuilder sb = new StringBuilder(expression);
|
||||
if (hasAlias()) {
|
||||
sb.append(SPACE).append(AS).append(SPACE).append(alias);
|
||||
} else {
|
||||
int pos = expression.indexOf('.');
|
||||
if (pos > 0 && !expression.endsWith("*")) {
|
||||
sb.append(SPACE).append(AS).append(SPACE).append(expression.substring(pos + 1));
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package com.todoroo.andlib.sql
|
||||
|
||||
import java.util.*
|
||||
|
||||
abstract class DBObject<T : DBObject<T>> internal constructor(@JvmField val expression: String) : Cloneable {
|
||||
@JvmField var alias: String? = null
|
||||
|
||||
open fun `as`(newAlias: String): T {
|
||||
return try {
|
||||
val clone = clone() as T
|
||||
clone.alias = newAlias
|
||||
clone
|
||||
} catch (e: CloneNotSupportedException) {
|
||||
throw RuntimeException(e)
|
||||
}
|
||||
}
|
||||
|
||||
protected fun hasAlias() = alias != null
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) {
|
||||
return true
|
||||
}
|
||||
if (other !is DBObject<*>) {
|
||||
return false
|
||||
}
|
||||
return expression == other.expression && alias == other.alias
|
||||
}
|
||||
|
||||
override fun hashCode() = Objects.hash(expression, alias)
|
||||
|
||||
override fun toString() = alias ?: expression
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
import static com.todoroo.andlib.sql.SqlConstants.LEFT_PARENTHESIS;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.RIGHT_PARENTHESIS;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import java.util.List;
|
||||
|
||||
public class Field extends DBObject<Field> {
|
||||
|
||||
protected Field(String expression) {
|
||||
super(expression);
|
||||
}
|
||||
|
||||
public static Field field(String expression) {
|
||||
return new Field(expression);
|
||||
}
|
||||
|
||||
public Criterion eq(Object value) {
|
||||
if (value == null) {
|
||||
return UnaryCriterion.isNull(this);
|
||||
}
|
||||
return UnaryCriterion.eq(this, value);
|
||||
}
|
||||
|
||||
public Criterion gt(Object value) {
|
||||
return UnaryCriterion.gt(this, value);
|
||||
}
|
||||
|
||||
public Criterion gte(Object value) {
|
||||
return UnaryCriterion.gte(this, value);
|
||||
}
|
||||
|
||||
public Criterion lt(final Object value) {
|
||||
return UnaryCriterion.lt(this, value);
|
||||
}
|
||||
|
||||
public Criterion lte(final Object value) {
|
||||
return UnaryCriterion.lte(this, value);
|
||||
}
|
||||
|
||||
public Criterion like(final String value) {
|
||||
return UnaryCriterion.like(this, value);
|
||||
}
|
||||
|
||||
public Criterion in(final Query query) {
|
||||
final Field field = this;
|
||||
return new Criterion(Operator.in) {
|
||||
|
||||
@Override
|
||||
protected void populate(StringBuilder sb) {
|
||||
sb.append(field)
|
||||
.append(SPACE)
|
||||
.append(Operator.in)
|
||||
.append(SPACE)
|
||||
.append(LEFT_PARENTHESIS)
|
||||
.append(query)
|
||||
.append(RIGHT_PARENTHESIS);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public <T> Criterion in(List<T> entries) {
|
||||
final Field field = this;
|
||||
return new Criterion(Operator.in) {
|
||||
@Override
|
||||
protected void populate(StringBuilder sb) {
|
||||
sb.append(field)
|
||||
.append(SPACE)
|
||||
.append(Operator.in)
|
||||
.append(SPACE)
|
||||
.append(LEFT_PARENTHESIS)
|
||||
.append(Joiner.on(",").join(entries))
|
||||
.append(RIGHT_PARENTHESIS);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package com.todoroo.andlib.sql
|
||||
|
||||
open class Field(expression: String) : DBObject<Field>(expression) {
|
||||
fun eq(value: Any?): Criterion = if (value == null) {
|
||||
UnaryCriterion.isNull(this)
|
||||
} else {
|
||||
UnaryCriterion.eq(this, value)
|
||||
}
|
||||
|
||||
fun gt(value: Any?): Criterion = UnaryCriterion.gt(this, value)
|
||||
|
||||
fun gte(value: Any?): Criterion = UnaryCriterion.gte(this, value)
|
||||
|
||||
fun lt(value: Any?): Criterion = UnaryCriterion.lt(this, value)
|
||||
|
||||
fun lte(value: Any?): Criterion = UnaryCriterion.lte(this, value)
|
||||
|
||||
fun like(value: String?): Criterion = UnaryCriterion.like(this, value)
|
||||
|
||||
fun `in`(query: Query?): Criterion {
|
||||
val field = this
|
||||
return object : Criterion(Operator.`in`) {
|
||||
override fun populate() = "$field IN ($query)"
|
||||
}
|
||||
}
|
||||
|
||||
fun `in`(entries: List<*>): Criterion {
|
||||
val field = this
|
||||
return object : Criterion(Operator.`in`) {
|
||||
override fun populate() = "$field IN (${entries.joinToString(",")})"
|
||||
}
|
||||
}
|
||||
|
||||
fun toStringInSelect(): String {
|
||||
val sb = StringBuilder(expression)
|
||||
if (hasAlias()) {
|
||||
sb.append(" AS $alias")
|
||||
} else {
|
||||
val pos = expression.indexOf('.')
|
||||
if (pos > 0 && !expression.endsWith("*")) {
|
||||
sb.append(" AS ${expression.substring(pos + 1)}")
|
||||
}
|
||||
}
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic fun field(expression: String): Field = Field(expression)
|
||||
@JvmStatic val COUNT = Field("COUNT(*)")
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
public final class Functions {
|
||||
|
||||
public static Field upper(Field title) {
|
||||
return new Field("UPPER(" + title.toString() + ")");
|
||||
}
|
||||
|
||||
/** @return SQL now (in milliseconds) */
|
||||
public static Field now() {
|
||||
return new Field("(strftime('%s','now')*1000)");
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.todoroo.andlib.sql
|
||||
|
||||
object Functions {
|
||||
@JvmStatic fun upper(title: Field): Field = Field("UPPER($title)")
|
||||
|
||||
@JvmStatic fun now(): Field = Field("(strftime('%s','now')*1000)")
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
import static com.todoroo.andlib.sql.SqlConstants.AND;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.JOIN;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.ON;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
|
||||
|
||||
public class Join {
|
||||
|
||||
private final SqlTable joinTable;
|
||||
private final JoinType joinType;
|
||||
private final Criterion[] criterions;
|
||||
|
||||
private Join(SqlTable table, JoinType joinType, Criterion... criterions) {
|
||||
joinTable = table;
|
||||
this.joinType = joinType;
|
||||
this.criterions = criterions;
|
||||
}
|
||||
|
||||
public static Join inner(SqlTable expression, Criterion... criterions) {
|
||||
return new Join(expression, JoinType.INNER, criterions);
|
||||
}
|
||||
|
||||
public static Join left(SqlTable table, Criterion... criterions) {
|
||||
return new Join(table, JoinType.LEFT, criterions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(joinType)
|
||||
.append(SPACE)
|
||||
.append(JOIN)
|
||||
.append(SPACE)
|
||||
.append(joinTable)
|
||||
.append(SPACE)
|
||||
.append(ON)
|
||||
.append(SPACE)
|
||||
.append("(");
|
||||
for (int i = 0; i < criterions.length; i++) {
|
||||
sb.append(criterions[i]);
|
||||
if (i < criterions.length - 1) {
|
||||
sb.append(SPACE).append(AND).append(SPACE);
|
||||
}
|
||||
}
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.todoroo.andlib.sql
|
||||
|
||||
import com.todoroo.andlib.data.Table
|
||||
|
||||
class Join private constructor(private val joinTable: Table, private val joinType: JoinType, criterions: List<Criterion>) { private val criterions = criterions.toList()
|
||||
|
||||
override fun toString() = "$joinType JOIN $joinTable ON (${criterions.joinToString(" AND ")})"
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun inner(expression: Table, vararg criterions: Criterion?): Join {
|
||||
return Join(expression, JoinType.INNER, criterions.filterNotNull())
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun left(table: Table, vararg criterions: Criterion?): Join {
|
||||
return Join(table, JoinType.LEFT, criterions.filterNotNull())
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
public enum JoinType {
|
||||
INNER,
|
||||
LEFT
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package com.todoroo.andlib.sql
|
||||
|
||||
enum class JoinType {
|
||||
INNER, LEFT
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
public final class Operator {
|
||||
|
||||
public static final Operator eq = new Operator("=");
|
||||
public static final Operator isNull = new Operator("IS NULL");
|
||||
public static final Operator and = new Operator("AND");
|
||||
public static final Operator or = new Operator("OR");
|
||||
public static final Operator not = new Operator("NOT");
|
||||
public static final Operator like = new Operator("LIKE");
|
||||
public static final Operator in = new Operator("IN");
|
||||
static final Operator gt = new Operator(">");
|
||||
static final Operator gte = new Operator(">=");
|
||||
static final Operator lt = new Operator("<");
|
||||
static final Operator lte = new Operator("<=");
|
||||
private final String operator;
|
||||
|
||||
private Operator(String operator) {
|
||||
this.operator = operator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.operator;
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.todoroo.andlib.sql
|
||||
|
||||
class Operator private constructor(private val operator: String) {
|
||||
override fun toString() = operator
|
||||
|
||||
companion object {
|
||||
val eq = Operator("=")
|
||||
val isNull = Operator("IS NULL")
|
||||
val and = Operator("AND")
|
||||
val or = Operator("OR")
|
||||
val not = Operator("NOT")
|
||||
val like = Operator("LIKE")
|
||||
val `in` = Operator("IN")
|
||||
val gt = Operator(">")
|
||||
val gte = Operator(">=")
|
||||
val lt = Operator("<")
|
||||
val lte = Operator("<=")
|
||||
}
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Order {
|
||||
|
||||
private final Object expression;
|
||||
private final List<Order> secondaryExpressions;
|
||||
private final OrderType orderType;
|
||||
|
||||
private Order(Object expression) {
|
||||
this(expression, OrderType.ASC);
|
||||
}
|
||||
|
||||
private Order(Object expression, OrderType orderType) {
|
||||
this.expression = expression;
|
||||
this.orderType = orderType;
|
||||
this.secondaryExpressions = new ArrayList<>();
|
||||
}
|
||||
|
||||
public static Order asc(Object expression) {
|
||||
return new Order(expression);
|
||||
}
|
||||
|
||||
public static Order desc(Object expression) {
|
||||
return new Order(expression, OrderType.DESC);
|
||||
}
|
||||
|
||||
public void addSecondaryExpression(Order secondary) {
|
||||
secondaryExpressions.add(secondary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(expression.toString()).append(SPACE).append(orderType.toString());
|
||||
|
||||
for (Order secondary : secondaryExpressions) {
|
||||
sb.append(", ").append(secondary.toString()); // $NON-NLS-1$
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public Order reverse() {
|
||||
if (orderType == OrderType.ASC) {
|
||||
return new Order(expression, OrderType.DESC);
|
||||
} else {
|
||||
return new Order(expression, OrderType.ASC);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.todoroo.andlib.sql
|
||||
|
||||
import com.todoroo.andlib.sql.OrderType.ASC
|
||||
import com.todoroo.andlib.sql.OrderType.DESC
|
||||
import java.util.*
|
||||
|
||||
class Order private constructor(private val expression: Any, private val orderType: OrderType = ASC) {
|
||||
private val secondaryExpressions = ArrayList<Order>()
|
||||
|
||||
fun addSecondaryExpression(secondary: Order) {
|
||||
secondaryExpressions.add(secondary)
|
||||
}
|
||||
|
||||
override fun toString() =
|
||||
"$expression $orderType${secondaryExpressions.takeIf { it.isNotEmpty() }?.joinToString(", ", ", ") ?: ""}"
|
||||
|
||||
fun reverse() = Order(expression, if (orderType === ASC) DESC else ASC)
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun asc(expression: Any) = Order(expression)
|
||||
|
||||
@JvmStatic
|
||||
fun desc(expression: Any) = Order(expression, DESC)
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
public enum OrderType {
|
||||
DESC,
|
||||
ASC
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package com.todoroo.andlib.sql
|
||||
|
||||
enum class OrderType {
|
||||
DESC, ASC
|
||||
}
|
@ -1,121 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
import static com.todoroo.andlib.sql.SqlConstants.ALL;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.COMMA;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.FROM;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.SELECT;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.WHERE;
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public final class Query {
|
||||
|
||||
private final ArrayList<Criterion> criterions = new ArrayList<>();
|
||||
private final ArrayList<Field> fields = new ArrayList<>();
|
||||
private final ArrayList<Join> joins = new ArrayList<>();
|
||||
private SqlTable table;
|
||||
private String queryTemplate = null;
|
||||
|
||||
private Query(Field... fields) {
|
||||
this.fields.addAll(asList(fields));
|
||||
}
|
||||
|
||||
public static Query select(Field... fields) {
|
||||
return new Query(fields);
|
||||
}
|
||||
|
||||
public Query from(SqlTable fromTable) {
|
||||
this.table = fromTable;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Query join(Join... join) {
|
||||
joins.addAll(asList(join));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Query where(Criterion criterion) {
|
||||
criterions.add(criterion);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return this == o
|
||||
|| !(o == null || getClass() != o.getClass()) && this.toString().equals(o.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return toString().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sql = new StringBuilder();
|
||||
visitSelectClause(sql);
|
||||
visitFromClause(sql);
|
||||
|
||||
visitJoinClause(sql);
|
||||
if (queryTemplate == null) {
|
||||
visitWhereClause(sql);
|
||||
} else {
|
||||
sql.append(queryTemplate);
|
||||
}
|
||||
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
private void visitWhereClause(StringBuilder sql) {
|
||||
if (criterions.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
sql.append(WHERE);
|
||||
for (Criterion criterion : criterions) {
|
||||
sql.append(SPACE).append(criterion).append(SPACE);
|
||||
}
|
||||
}
|
||||
|
||||
private void visitJoinClause(StringBuilder sql) {
|
||||
for (Join join : joins) {
|
||||
sql.append(join).append(SPACE);
|
||||
}
|
||||
}
|
||||
|
||||
private void visitFromClause(StringBuilder sql) {
|
||||
if (table == null) {
|
||||
return;
|
||||
}
|
||||
sql.append(FROM).append(SPACE).append(table).append(SPACE);
|
||||
}
|
||||
|
||||
private void visitSelectClause(StringBuilder sql) {
|
||||
sql.append(SELECT).append(SPACE);
|
||||
if (fields.isEmpty()) {
|
||||
sql.append(ALL).append(SPACE);
|
||||
return;
|
||||
}
|
||||
for (Field field : fields) {
|
||||
sql.append(field.toStringInSelect()).append(COMMA);
|
||||
}
|
||||
sql.deleteCharAt(sql.length() - 1).append(SPACE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the SQL query template (comes after the "from")
|
||||
*
|
||||
* @return query
|
||||
*/
|
||||
public Query withQueryTemplate(String template) {
|
||||
queryTemplate = template;
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package com.todoroo.andlib.sql
|
||||
|
||||
import com.todoroo.andlib.data.Table
|
||||
import com.todoroo.andlib.sql.StringBuilderExtensions.from
|
||||
import com.todoroo.andlib.sql.StringBuilderExtensions.join
|
||||
import com.todoroo.andlib.sql.StringBuilderExtensions.select
|
||||
import com.todoroo.andlib.sql.StringBuilderExtensions.where
|
||||
import java.util.*
|
||||
|
||||
class Query private constructor(vararg fields: Field?) {
|
||||
private val criterions = ArrayList<Criterion>()
|
||||
private val fields = ArrayList<Field>().apply { addAll(fields.filterNotNull()) }
|
||||
private val joins = ArrayList<Join>()
|
||||
private var table: Table? = null
|
||||
private var queryTemplate: String? = null
|
||||
|
||||
fun from(fromTable: Table?): Query {
|
||||
table = fromTable
|
||||
return this
|
||||
}
|
||||
|
||||
fun join(vararg join: Join): Query {
|
||||
joins.addAll(join)
|
||||
return this
|
||||
}
|
||||
|
||||
fun where(criterion: Criterion): Query {
|
||||
criterions.add(criterion)
|
||||
return this
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return this === other
|
||||
|| !(other == null || javaClass != other.javaClass) && this.toString() == other.toString()
|
||||
}
|
||||
|
||||
override fun hashCode() = toString().hashCode()
|
||||
|
||||
override fun toString(): String {
|
||||
val sql = StringBuilder()
|
||||
.select(fields)
|
||||
.from(table)
|
||||
.join(joins)
|
||||
if (queryTemplate == null) {
|
||||
sql.where(criterions)
|
||||
} else {
|
||||
sql.append(queryTemplate)
|
||||
}
|
||||
return sql.toString()
|
||||
}
|
||||
|
||||
fun withQueryTemplate(template: String?): Query {
|
||||
queryTemplate = template
|
||||
return this
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun select(vararg fields: Field?): Query {
|
||||
return Query(*fields)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
import static com.todoroo.andlib.sql.SqlConstants.COMMA;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.ORDER_BY;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.WHERE;
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Query Template returns a bunch of criteria that allows a query to be constructed
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*/
|
||||
public final class QueryTemplate {
|
||||
|
||||
private final ArrayList<Criterion> criterions = new ArrayList<>();
|
||||
private final ArrayList<Join> joins = new ArrayList<>();
|
||||
private final ArrayList<Order> orders = new ArrayList<>();
|
||||
|
||||
public QueryTemplate join(Join... join) {
|
||||
joins.addAll(asList(join));
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryTemplate where(Criterion criterion) {
|
||||
criterions.add(criterion);
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryTemplate orderBy(Order... order) {
|
||||
orders.addAll(asList(order));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sql = new StringBuilder();
|
||||
visitJoinClause(sql);
|
||||
visitWhereClause(sql);
|
||||
visitOrderByClause(sql);
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
private void visitOrderByClause(StringBuilder sql) {
|
||||
if (orders.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
sql.append(ORDER_BY);
|
||||
for (Order order : orders) {
|
||||
sql.append(SPACE).append(order).append(COMMA);
|
||||
}
|
||||
sql.deleteCharAt(sql.length() - 1).append(SPACE);
|
||||
}
|
||||
|
||||
private void visitWhereClause(StringBuilder sql) {
|
||||
if (criterions.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
sql.append(WHERE);
|
||||
for (Criterion criterion : criterions) {
|
||||
sql.append(SPACE).append(criterion).append(SPACE);
|
||||
}
|
||||
}
|
||||
|
||||
private void visitJoinClause(StringBuilder sql) {
|
||||
for (Join join : joins) {
|
||||
sql.append(join).append(SPACE);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.todoroo.andlib.sql
|
||||
|
||||
import com.todoroo.andlib.sql.StringBuilderExtensions.join
|
||||
import com.todoroo.andlib.sql.StringBuilderExtensions.orderBy
|
||||
import com.todoroo.andlib.sql.StringBuilderExtensions.where
|
||||
import java.util.*
|
||||
|
||||
class QueryTemplate {
|
||||
private val criterions = ArrayList<Criterion>()
|
||||
private val joins = ArrayList<Join>()
|
||||
private val orders = ArrayList<Order>()
|
||||
|
||||
fun join(vararg join: Join): QueryTemplate {
|
||||
joins.addAll(join)
|
||||
return this
|
||||
}
|
||||
|
||||
fun where(criterion: Criterion): QueryTemplate {
|
||||
criterions.add(criterion)
|
||||
return this
|
||||
}
|
||||
|
||||
fun orderBy(vararg order: Order): QueryTemplate {
|
||||
orders.addAll(order)
|
||||
return this
|
||||
}
|
||||
|
||||
override fun toString() =
|
||||
StringBuilder()
|
||||
.join(joins)
|
||||
.where(criterions)
|
||||
.orderBy(orders)
|
||||
.toString()
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
public final class SqlConstants {
|
||||
|
||||
public static final Field COUNT = Field.field("COUNT(*)");
|
||||
public static final String SELECT = "SELECT";
|
||||
static final String SPACE = " ";
|
||||
public static final String AS = "AS";
|
||||
public static final String FROM = "FROM";
|
||||
public static final String ON = "ON";
|
||||
static final String ALL = "*";
|
||||
public static final String AND = "AND";
|
||||
public static final String OR = "OR";
|
||||
public static final String WHERE = "WHERE";
|
||||
public static final String NOT = "NOT";
|
||||
static final String COMMA = ",";
|
||||
static final String JOIN = "JOIN";
|
||||
static final String LEFT_PARENTHESIS = "(";
|
||||
static final String RIGHT_PARENTHESIS = ")";
|
||||
static final String ORDER_BY = "ORDER BY";
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
public class SqlTable extends DBObject<SqlTable> {
|
||||
|
||||
protected SqlTable(String expression) {
|
||||
super(expression);
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package com.todoroo.andlib.sql
|
||||
|
||||
import com.todoroo.andlib.data.Table
|
||||
|
||||
object StringBuilderExtensions {
|
||||
fun StringBuilder.join(joins: List<Join>): StringBuilder {
|
||||
if (joins.isNotEmpty()) {
|
||||
append("${joins.joinToString(" ")} ")
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
fun StringBuilder.where(criterion: List<Criterion>): StringBuilder {
|
||||
if (criterion.isNotEmpty()) {
|
||||
append("WHERE ${criterion.joinToString(" ")} ")
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
fun StringBuilder.orderBy(orders: List<Order>): StringBuilder {
|
||||
if (orders.isNotEmpty()) {
|
||||
append("ORDER BY ${orders.joinToString(",")} ")
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
fun StringBuilder.from(table: Table?): StringBuilder {
|
||||
if (table != null) {
|
||||
append("FROM $table ")
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
fun StringBuilder.select(fields: List<Field>): StringBuilder {
|
||||
append("SELECT ${fields.joinToString(", ", transform = Field::toStringInSelect).ifEmpty { "*" }} ")
|
||||
return this
|
||||
}
|
||||
}
|
@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
|
||||
|
||||
public class UnaryCriterion extends Criterion {
|
||||
|
||||
private final Field expression;
|
||||
private final Object value;
|
||||
|
||||
private UnaryCriterion(Field expression, Operator operator, Object value) {
|
||||
super(operator);
|
||||
this.expression = expression;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static Criterion eq(Field expression, Object value) {
|
||||
return new UnaryCriterion(expression, Operator.eq, value);
|
||||
}
|
||||
|
||||
/** Sanitize the given input for SQL */
|
||||
public static String sanitize(String input) {
|
||||
return input.replace("'", "''");
|
||||
}
|
||||
|
||||
static Criterion gt(Field field, Object value) {
|
||||
return new UnaryCriterion(field, Operator.gt, value);
|
||||
}
|
||||
|
||||
static Criterion gte(Field field, Object value) {
|
||||
return new UnaryCriterion(field, Operator.gte, value);
|
||||
}
|
||||
|
||||
static Criterion lt(Field field, Object value) {
|
||||
return new UnaryCriterion(field, Operator.lt, value);
|
||||
}
|
||||
|
||||
static Criterion lte(Field field, Object value) {
|
||||
return new UnaryCriterion(field, Operator.lte, value);
|
||||
}
|
||||
|
||||
public static Criterion isNull(Field field) {
|
||||
return new UnaryCriterion(field, Operator.isNull, null) {
|
||||
@Override
|
||||
protected void populateOperator(StringBuilder sb) {
|
||||
sb.append(SPACE).append(operator);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Criterion like(Field field, String value) {
|
||||
return new UnaryCriterion(field, Operator.like, value) {
|
||||
@Override
|
||||
protected void populateOperator(StringBuilder sb) {
|
||||
sb.append(SPACE).append(operator).append(SPACE);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void populate(StringBuilder sb) {
|
||||
beforePopulateOperator(sb);
|
||||
populateOperator(sb);
|
||||
afterPopulateOperator(sb);
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
void beforePopulateOperator(StringBuilder sb) {
|
||||
sb.append(expression);
|
||||
}
|
||||
|
||||
void populateOperator(StringBuilder sb) {
|
||||
sb.append(operator);
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
void afterPopulateOperator(StringBuilder sb) {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (value instanceof String) {
|
||||
sb.append("'").append(sanitize((String) value)).append("'");
|
||||
} else {
|
||||
sb.append(value);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package com.todoroo.andlib.sql
|
||||
|
||||
open class UnaryCriterion private constructor(private val expression: Field, operator: Operator, private val value: Any?) : Criterion(operator) {
|
||||
override fun populate() = "$expression${populateOperator()}${afterPopulateOperator()}"
|
||||
|
||||
open fun populateOperator() = "$operator"
|
||||
|
||||
private fun afterPopulateOperator(): Any = if (value is String) {
|
||||
"'${sanitize(value)}'"
|
||||
} else {
|
||||
value ?: ""
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun eq(expression: Field, value: Any?): Criterion = UnaryCriterion(expression, Operator.eq, value)
|
||||
|
||||
/** Sanitize the given input for SQL */
|
||||
fun sanitize(input: String): String = input.replace("'", "''")
|
||||
|
||||
fun gt(field: Field, value: Any?): Criterion = UnaryCriterion(field, Operator.gt, value)
|
||||
|
||||
fun gte(field: Field, value: Any?): Criterion = UnaryCriterion(field, Operator.gte, value)
|
||||
|
||||
fun lt(field: Field, value: Any?): Criterion = UnaryCriterion(field, Operator.lt, value)
|
||||
|
||||
fun lte(field: Field, value: Any?): Criterion = UnaryCriterion(field, Operator.lte, value)
|
||||
|
||||
fun isNull(field: Field): Criterion {
|
||||
return object : UnaryCriterion(field, Operator.isNull, null) {
|
||||
override fun populateOperator() = " $operator"
|
||||
}
|
||||
}
|
||||
|
||||
fun like(field: Field, value: String?): Criterion {
|
||||
return object : UnaryCriterion(field, Operator.like, value) {
|
||||
override fun populateOperator() = " $operator "
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue