Created
March 8, 2018 00:47
-
-
Save gurpreet-/8062ba4fff9e43797ecc40bc4852e74d to your computer and use it in GitHub Desktop.
Making Apache Cayenne respect default values in Postgres
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Modified from http://objectstyle.org/cayenne/lists/cayenne-user/2007/12/0084.html | |
* for use with Postgres. However, it performs many SELECTs which may or may not be | |
* efficient depending on your application. | |
*/ | |
private void setNewObjectDefaults() { | |
BaseDataObject mainObj = (BaseDataObject) this; | |
ObjEntity ent = Cayenne.getObjEntity(mainObj); | |
Collection attribs = ent.getAttributes(); | |
// Try and get the default values from the database | |
String defaultSql = getDefaultValueLookupQuery(ent.getDbEntityName()); | |
SQLTemplate rawSelect = new SQLTemplate(mainObj.getClass(), defaultSql); | |
rawSelect.setFetchingDataRows(true); | |
// Now get a list of column names and results. | |
List defList = mainObj.getObjectContext().performQuery(rawSelect); | |
// Loop over the attributes that the mainObj has. | |
for (int i = 0; i <= attribs.size() - 1; i++) { | |
ObjAttribute attr = (ObjAttribute) attribs.toArray()[i]; | |
// We need to find something out about this attribute | |
DbAttribute att = attr.getDbAttribute(); | |
String propName = attr.getName(); | |
Object propertyValue = mainObj.readProperty(propName); | |
Class propertyType = attr.getJavaClass(); | |
Object def = null; | |
// Do not process if there is already a value | |
// in the object's attributes | |
if (propertyValue != null) { | |
continue; | |
} | |
// Now that we're looping over the attributes, | |
// we should also loop over the default values returned above | |
// and check if they are both in each others' list | |
for (int j = 0; j <= defList.size() - 1; j++) { | |
Map row = (Map) defList.get(j); | |
String rowFieldName = (String) row.get("column_name"); | |
// If they are in each others' list then set the column default | |
// as the default object | |
if (rowFieldName.equals(att.getName())) { | |
def = row.get("column_default"); | |
break; | |
} | |
} | |
Object result = getDefaultValue(def, mainObj.getObjectContext()); | |
// If the value is null then write null | |
if (result == null) { | |
mainObj.writeProperty(propName, null); | |
continue; | |
} | |
// Here we check what class the result is. | |
// The result may be a Date or a String or anything defined | |
// by SQLDataTypes, so we have to check what type it is below. | |
Class<?> keyClass = result.getClass(); | |
// TODO: This may need modifying depending on what you get returned | |
if (keyClass.equals(Date.class)) { | |
Date d = (Date) result; | |
String ds = d.toString(); | |
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy"); | |
LocalDateTime l = LocalDateTime.parse(ds, dtf); | |
mainObj.writeProperty(propName, l); | |
} else if (keyClass.equals(Long.class)) { | |
mainObj.writeProperty(propName, result); | |
} else if (keyClass.equals(Integer.class)) { | |
mainObj.writeProperty(propName, result); | |
} else { | |
// Just try writing - warning this may error | |
// because I haven't written in all the classes | |
// that the default value may return | |
mainObj.writeProperty(propName, result); | |
} | |
} | |
} | |
/** | |
* Because the defaultValue may be an expression, here what we're doing | |
* is SELECTing that expression to return it. | |
* @param defaultValue The default value returned from a query, should be a String | |
* @param context An ObjectContext to perform finding | |
* @return The actual default value | |
*/ | |
public Object getDefaultValue(Object defaultValue, ObjectContext context) { | |
SQLTemplate sel = new SQLTemplate("SELECT " + defaultValue, true); | |
List query = context.performQuery(sel); | |
// This returns a one column table with for example "now" | |
// or "int8" as the heading and the value. | |
Map table = (Map) query.get(0); | |
// Grab that one column's entry | |
java.util.HashMap.Entry firstCol = (java.util.HashMap.Entry) table.entrySet().toArray()[0]; | |
// .. and then return the value | |
return firstCol.getValue(); | |
} | |
protected String getDefaultValueLookupQuery(String entName) { | |
String def = "SELECT column_name, column_default " + | |
"FROM information_schema.columns " + | |
"WHERE (table_schema, table_name) = ('public', '" + entName + "') " + | |
"ORDER BY ordinal_position;"; | |
return def; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment