package io.cattle.platform.object.jooq.utils;
import io.cattle.platform.object.meta.ObjectMetaDataManager;
import io.github.ibuildthecloud.gdapi.condition.Condition;
import io.github.ibuildthecloud.gdapi.factory.SchemaFactory;
import io.github.ibuildthecloud.gdapi.model.Schema;
import java.util.List;
import java.util.Map;
import org.jooq.DSLContext;
import org.jooq.ForeignKey;
import org.jooq.Table;
import org.jooq.TableField;
import org.jooq.TableRecord;
import org.jooq.UniqueKey;
import org.jooq.UpdatableRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class JooqUtils {
private static final Logger log = LoggerFactory.getLogger(JooqUtils.class);
@SuppressWarnings("unchecked")
public static <T extends UpdatableRecord<?>> T findById(DSLContext context, Class<T> clz, Object id) {
if (id == null)
return null;
Table<?> table = getTableFromRecordClass(clz);
if (table == null)
return null;
UniqueKey<?> key = table.getPrimaryKey();
if (key == null || key.getFieldsArray().length != 1)
return null;
TableField<?, Object> keyField = (TableField<?, Object>) key.getFieldsArray()[0];
/* Convert object because we are abusing type safety here */
Object converted = keyField.getDataType().convert(id);
return (T) context.selectFrom(table).where(keyField.eq(converted)).fetchOne();
}
public static Table<?> getTable(SchemaFactory schemaFactory, Class<?> clz) {
return getTableFromRecordClass(getRecordClass(schemaFactory, clz));
}
@SuppressWarnings("unchecked")
public static Table<?> getTableFromRecordClass(Class<?> clz) {
if (clz == null)
return null;
if (TableRecord.class.isAssignableFrom(clz)) {
try {
TableRecord<?> record = ((Class<TableRecord<?>>) clz).newInstance();
return record.getTable();
} catch (InstantiationException e) {
log.error("Failed to determine table for [{}]", clz, e);
} catch (IllegalAccessException e) {
log.error("Failed to determine table for [{}]", clz, e);
}
}
return null;
}
@SuppressWarnings("unchecked")
public static Class<UpdatableRecord<?>> getRecordClass(SchemaFactory factory, Class<?> clz) {
if (UpdatableRecord.class.isAssignableFrom(clz)) {
return (Class<UpdatableRecord<?>>) clz;
}
if (factory != null) {
Schema schema = factory.getSchema(clz);
Class<?> testClz = factory.getSchemaClass(schema.getId());
if (clz.isAssignableFrom(testClz)) {
if (!UpdatableRecord.class.isAssignableFrom(testClz)) {
throw new IllegalArgumentException("Class [" + testClz + "] is not an instanceof UpdatableRecord");
}
return (Class<UpdatableRecord<?>>) testClz;
}
}
throw new IllegalArgumentException("Failed to find UpdatableRecord class for [" + clz + "]");
}
public static UpdatableRecord<?> getRecord(Class<UpdatableRecord<?>> clz) {
try {
return clz.newInstance();
} catch (InstantiationException e) {
throw new IllegalStateException("Failed to instantiate [" + clz + "]", e);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Failed to instantiate [" + clz + "]", e);
}
}
@SuppressWarnings("unchecked")
public static <T extends UpdatableRecord<?>> T getRecordObject(Object obj) {
if (obj == null)
return null;
if (obj instanceof UpdatableRecord<?>) {
return (T) obj;
}
throw new IllegalArgumentException("Expected instance of [" + UpdatableRecord.class + "] got [" + obj.getClass() + "]");
}
public static org.jooq.Condition toConditions(ObjectMetaDataManager metaData, String type, Map<Object, Object> criteria) {
org.jooq.Condition existingCondition = null;
for (Map.Entry<Object, Object> entry : criteria.entrySet()) {
Object value = entry.getValue();
Object key = entry.getKey();
TableField<?, Object> field = null;
if (key == org.jooq.Condition.class) {
if (!(value instanceof org.jooq.Condition)) {
throw new IllegalArgumentException("If key is Condition, value must be an instanceof Condition got key [" + key +
"] value [" + value + "]");
}
} else {
field = getTableField(metaData, type, key);
if (field == null) {
continue;
}
}
org.jooq.Condition newCondition = null;
if (value instanceof org.jooq.Condition) {
newCondition = (org.jooq.Condition) value;
} else if (value instanceof Condition) {
newCondition = toCondition(field, (Condition) value);
} else if (value instanceof List) {
newCondition = listToCondition(field, (List<?>) value);
} else if (value == null) {
newCondition = field.isNull();
} else {
newCondition = field.eq(value);
}
if (existingCondition == null) {
existingCondition = newCondition;
} else {
existingCondition = existingCondition.and(newCondition);
}
}
return existingCondition;
}
@SuppressWarnings("unchecked")
public static TableField<?, Object> getTableField(ObjectMetaDataManager metaData, String type, Object key) {
Object objField = metaData.convertFieldNameFor(type, key);
if (objField instanceof TableField) {
return (TableField<?, Object>) objField;
} else {
return null;
}
}
/**
* Determines if a table's primary key is referenced at all by other tables.
*
* @param table
* @param others
* @return
*/
public static boolean isReferencedBy(Table<?> table, List<Table<?>> others) {
for (Table<?> other : others) {
for (ForeignKey<?, ?> key : other.getReferences()) {
if (key.getKey().getTable().equals(table)) {
return true;
}
}
}
return false;
}
protected static org.jooq.Condition listToCondition(TableField<?, Object> field, List<?> list) {
org.jooq.Condition condition = null;
for (Object value : list) {
if (value instanceof Condition) {
org.jooq.Condition newCondition = toCondition(field, (Condition) value);
condition = condition == null ? newCondition : condition.and(newCondition);
} else {
condition = condition == null ? field.eq(value) : condition.and(field.eq(value));
}
}
return condition;
}
protected static org.jooq.Condition toCondition(TableField<?, Object> field, Condition value) {
Condition condition = value;
switch (condition.getConditionType()) {
case EQ:
return field.eq(condition.getValue());
case GT:
return field.gt(condition.getValue());
case GTE:
return field.ge(condition.getValue());
case IN:
List<Object> values = condition.getValues();
if (values.size() == 1) {
return field.eq(values.get(0));
} else {
return field.in(condition.getValues());
}
case NOTIN:
List<Object> vals = condition.getValues();
if (vals.size() == 1) {
return field.ne(vals.get(0));
} else {
return field.notIn(condition.getValues());
}
case LIKE:
return field.like(condition.getValue().toString());
case LT:
return field.lt(condition.getValue());
case LTE:
return field.le(condition.getValue());
case NE:
return field.ne(condition.getValue());
case NOTLIKE:
return field.notLike(condition.getValue().toString());
case NOTNULL:
return field.isNotNull();
case NULL:
return field.isNull();
case PREFIX:
return field.like(condition.getValue() + "%");
case OR:
return toCondition(field, condition.getLeft()).or(toCondition(field, condition.getRight()));
default:
throw new IllegalArgumentException("Invalid condition type [" + condition.getConditionType() + "]");
}
}
}