sql.create_entity_manager.xslt Maven / Gradle / Ivy
package ;
import ch.epfl.labos.iu.orm.DBSet;
import ch.epfl.labos.iu.orm.LazySet;
import ch.epfl.labos.iu.orm.VectorSet;
import ch.epfl.labos.iu.orm.Pair;
import ch.epfl.labos.iu.orm.Triple;
import ch.epfl.labos.iu.orm.Quartic;
import ch.epfl.labos.iu.orm.Quintic;
import ch.epfl.labos.iu.orm.QueryList;
import ch.epfl.labos.iu.orm.query.RowReader;
import ch.epfl.labos.iu.orm.query.SelectFromWhere;
import ch.epfl.labos.iu.orm.query2.JDBCConnectionInfo;
import ch.epfl.labos.iu.orm.query2.SQLQueryComposer;
import ch.epfl.labos.iu.orm.query2.SQLReader;
import ch.epfl.labos.iu.orm.query2.SQLReaderColumnDescription;
import ch.epfl.labos.iu.orm.query2.EntityManagerBackdoor;
import org.jinq.orm.annotations.EntitySupplier;
import org.jinq.orm.annotations.NoSideEffects;
import org.jinq.orm.stream.JinqStream;
import org.jinq.orm.stream.QueryJinqStream;
import java.io.Serializable;
import java.util.List;
import java.util.Vector;
import java.util.Map;
import java.util.HashMap;
import java.util.HashSet;
import java.util.WeakHashMap;
import java.util.stream.Stream;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.lang.ref.WeakReference;
public class EntityManager implements EntityManagerBackdoor, Serializable
{
// Note: The EntityManager is not properly serializable, but some queries do access the
// entity manager. Those Java 8 lambdas need to be serialized to be decoded, so
// there needs to be a way to record some sort of placeholder entity manager when
// serializing the lambda.
transient DBManager db;
public int timeout = 0;
boolean cacheQueries = true;
boolean partialCacheQueries = true;
public EntityManager(DBManager db)
{
this.db = db;
this.timeout = db.timeout;
this.cacheQueries = db.useFullQueryCaching;
this.partialCacheQueries = db.usePartialQueryCaching;
}
void flushDirty()
{
// TODO: this
// TODO: Flushing of objects with references to other non-persisted objects that later become persisted
}
public abstract static class EntityReader<T> extends SQLReader <T>
{
EntityManager em;
String entityInternalClassName;
List<SQLReaderColumnDescription> columns = new Vector<SQLReaderColumnDescription>();
public EntityReader(EntityManager em, String entityInternalClassName)
{
this.em = em;
this.entityInternalClassName = entityInternalClassName;
}
public int getNumColumns()
{
// Currently assumes that each entry in the columns list takes
// up one column
//
return columns.size();
}
public int getColumnForField(String field)
{
for (int n = 0; n < columns.size(); n++)
{
if (field.equals(columns.get(n).field))
return n;
}
return -1;
}
public int getColumnIndexForColumnName(String col)
{
for (int n = 0; n < columns.size(); n++)
{
if (col.equals(columns.get(n).columnName))
return n;
}
return -1;
}
String [] getColumnNames()
{
String [] columnNames = new String[columns.size()];
for (int n = 0; n < columnNames.length; n++)
columnNames[n] = columns.get(n).columnName;
return columnNames;
}
SQLReader readerForType(String type)
{
if (type.equals("int"))
return new SQLReader.IntegerSQLReader();
else if (type.equals("float"))
return new SQLReader.FloatSQLReader();
else if (type.equals("double"))
return new SQLReader.DoubleSQLReader();
else if (type.equals("String"))
return new SQLReader.StringSQLReader();
else if (type.equals("Date"))
return new SQLReader.DateSQLReader();
return null;
}
public SQLReader getReaderForField(String field)
{
for (int n = 0; n < columns.size(); n++)
{
if (field.equals(columns.get(n).field))
{
String type = columns.get(n).type;
if (type != null)
return readerForType(type);
return null;
}
}
return null;
}
public boolean isCastConsistent(String internalName)
{
return entityInternalClassName.equals(internalName);
}
}
public SQLReader getReaderForEntity(String entity)
{
if (" ".equals(entity))
{
return new SQLReader(this);
}
return null;
}
public String[] getEntityColumnNames(String entity)
{
if (" ".equals(entity))
{
return new SQLReader(this).getColumnNames();
}
return null;
}
public String getTableForEntity(String entity)
{
if (" ".equals(entity))
{
return " ";
}
return null;
}
static class QueryCacheKey
{
QueryCacheKey(String context, Object baseQuery, Object lambda)
{
this.context = context;
this.baseQuery = baseQuery;
this.lambda = lambda;
}
public int hashCode()
{
return context.hashCode() ^ baseQuery.hashCode() ^ lambda.hashCode();
}
public boolean equals(Object o)
{
if (!(o instanceof QueryCacheKey)) return false;
QueryCacheKey other = (QueryCacheKey)o;
return other.context.equals(context)
&& other.baseQuery.equals(baseQuery)
&& other.lambda.equals(lambda);
}
String context;
Object baseQuery;
Object lambda;
}
static class QueryCacheValue
{
QueryCacheValue(QueryCacheKey key, Object cachedQuery)
{
this.key = key;
this.cachedQuery = cachedQuery;
}
QueryCacheKey key;
Object cachedQuery;
QueryCacheValue prev = null;
QueryCacheValue next = null;
}
transient Map<QueryCacheKey, QueryCacheValue> queryCache = new HashMap<QueryCacheKey, QueryCacheValue>();
final static int QUERY_CACHE_LIMIT = 500;
transient QueryCacheValue queryCacheLRU_head = null;
transient QueryCacheValue queryCacheLRU_tail = null;
int queryCacheSize = 0;
private void dequeueQueryCacheLRU(QueryCacheValue val)
{
queryCacheSize--;
if (val.next == null)
queryCacheLRU_tail = val.prev;
else
val.next.prev = val.prev;
if (val.prev == null)
queryCacheLRU_head = val.next;
else
val.prev.next = val.next;
val.prev = null;
val.next = null;
}
private void enqueueQueryCacheLRU(QueryCacheValue val)
{
// Add it to the end of the queue
if (queryCacheLRU_tail == null)
{
queryCacheLRU_tail = val;
queryCacheLRU_head = val;
}
else
{
val.prev = queryCacheLRU_tail;
queryCacheLRU_tail.next = val;
queryCacheLRU_tail = val;
}
// Check if we've overflowed
queryCacheSize++;
if (queryCacheSize > QUERY_CACHE_LIMIT)
{
QueryCacheValue toRemove = queryCacheLRU_head;
dequeueQueryCacheLRU(toRemove);
queryCache.remove(toRemove.key);
}
}
public Object getQueryCacheEntry(String context, Object baseQuery, Object lambda)
{
QueryCacheKey key = new QueryCacheKey(context, baseQuery, lambda);
QueryCacheValue cached = queryCache.get(key);
if (cached == null)
return null;
// Move it to the end of the queue
dequeueQueryCacheLRU(cached);
enqueueQueryCacheLRU(cached);
return cached.cachedQuery;
}
public void putQueryCacheEntry(String context, Object baseQuery, Object lambda, Object cachedQuery)
{
QueryCacheKey key = new QueryCacheKey(context, baseQuery, lambda);
QueryCacheValue cached = new QueryCacheValue(key, cachedQuery);
queryCache.put(key, cached);
enqueueQueryCacheLRU(cached);
}
static class GeneratedCachedQuery
{
GeneratedCachedQuery(Object key, Object cachedQuery)
{
this.key = key;
this.cachedQuery = cachedQuery;
}
Object key;
Object cachedQuery;
GeneratedCachedQuery prev = null;
GeneratedCachedQuery next = null;
}
transient Map<Object, GeneratedCachedQuery> generatedQueryCache = new HashMap<Object, GeneratedCachedQuery>();
final static int GENERATED_QUERY_CACHE_LIMIT = 500;
transient GeneratedCachedQuery generatedQueryCacheLRU_head = null;
transient GeneratedCachedQuery generatedQueryCacheLRU_tail = null;
int generatedQueryCacheSize = 0;
private void dequeueGeneratedQueryCacheLRU(GeneratedCachedQuery val)
{
generatedQueryCacheSize--;
if (val.next == null)
generatedQueryCacheLRU_tail = val.prev;
else
val.next.prev = val.prev;
if (val.prev == null)
generatedQueryCacheLRU_head = val.next;
else
val.prev.next = val.next;
val.prev = null;
val.next = null;
}
private void enqueueGeneratedQueryCacheLRU(GeneratedCachedQuery val)
{
// Add it to the end of the queue
if (generatedQueryCacheLRU_tail == null)
{
generatedQueryCacheLRU_tail = val;
generatedQueryCacheLRU_head = val;
}
else
{
val.prev = generatedQueryCacheLRU_tail;
generatedQueryCacheLRU_tail.next = val;
generatedQueryCacheLRU_tail = val;
}
// Check if we've overflowed
generatedQueryCacheSize++;
if (generatedQueryCacheSize > GENERATED_QUERY_CACHE_LIMIT)
{
GeneratedCachedQuery toRemove = generatedQueryCacheLRU_head;
dequeueGeneratedQueryCacheLRU(toRemove);
generatedQueryCache.remove(toRemove.key);
}
}
public Object getGeneratedQueryCacheEntry(Object queryRepresentation)
{
GeneratedCachedQuery cached = generatedQueryCache.get(queryRepresentation);
if (cached == null)
return null;
// Move it to the end of the queue
dequeueGeneratedQueryCacheLRU(cached);
enqueueGeneratedQueryCacheLRU(cached);
return cached.cachedQuery;
}
public void putGeneratedQueryCacheEntry(Object queryRepresentation, Object generatedQuery)
{
GeneratedCachedQuery cached = new GeneratedCachedQuery(queryRepresentation, generatedQuery);
generatedQueryCache.put(queryRepresentation, cached);
enqueueGeneratedQueryCacheLRU(cached);
}
public boolean isQueriesCached()
{
return cacheQueries || partialCacheQueries;
}
public boolean isPreparedStatementCached()
{
return cacheQueries;
}
}
// TODO: add plural forms of entity names
transient SQLQueryComposer< > Query;
transient DBSet< > ;
public DBSet< > all ()
{
return ;
}
@EntitySupplier(entityClass=" . ")
public JinqStream< > Stream()
{
return new QueryJinqStream<>( Query);
}
void dispose( obj)
{
flushDirty();
.remove(obj);
// delete from db immediately
String sql = "DELETE FROM "
+ " WHERE 1=1"
+ " AND = ? " ;
if (db.testOut != null) db.testOut.println(sql);
if (db.con != null)
{
try {
PreparedStatement stmt = db.con.prepareStatement(sql);
int idx = 0;
++idx;
stmt.setObject(idx, obj.get ());
stmt.executeUpdate();
stmt.close();
} catch (SQLException e)
{
e.printStackTrace();
}
}
}
void dirtyInstance( obj)
{
dirty .add(obj);
}
void newInstance( obj)
{
// TODO: Add handling of objects with auto-generated keys
// TODO: Add handling of objects whose keys are references to other objects
assert(obj.em == null);
obj.em = this;
// Fix references to other objects that happen to be keys
obj.set (
obj.get ().get ());
obj.set (
obj.get ().get ());
flushDirty();
// Add to DB immediately
.add(obj);
String sql = "INSERT INTO (";
boolean isFirst = true;
for (Map.Entry entry : map.entrySet())
{
if (!isFirst) sql = sql + ", ";
isFirst = false;
sql = sql + entry.getKey();
}
sql = sql + ") VALUES (";
for (int n = 0; n < map.size(); n++)
{
if (n != 0) sql = sql + ", ";
sql = sql + "?";
}
sql = sql + ")";
if (db.testOut != null) db.testOut.println(sql);
if (db.con != null)
{
try {
PreparedStatement stmt = db.con.prepareStatement(sql);
int idx = 1;
for (Map.Entry entry : map.entrySet())
{
stmt.setObject(idx, entry.getValue());
idx++;
}
stmt.executeUpdate();
stmt.close();
} catch (SQLException e)
{
e.printStackTrace();
}
}
known .put(obj.idKey(), new WeakReference< >(obj));
original .put(obj, ( )obj.copyForComparison());
}
create (ResultSet rs, int column) throws SQLException
{
obj = null;
key =
;
WeakReference< > ref = known .get(key);
if (ref != null) {
obj = ref.get();
if (obj != null)
{
// I'm not sure if this is necessary, but it's better to be safe
if (original .get(obj) == null)
original .put(obj, ( )obj.copyForComparison());
return obj;
}
}
obj = new (this, rs, column);
known .put(obj.idKey(), new WeakReference< >(obj));
original .put(obj, ( )obj.copyForComparison());
// TODO: this
return obj;
}
create (ResultSet rs, String prefix) throws SQLException
{
obj = null;
key =
;
WeakReference< > ref = known .get(key);
if (ref != null) {
obj = ref.get();
if (obj != null)
{
// I'm not sure if this is necessary, but it's better to be safe
if (original .get(obj) == null)
original .put(obj, ( )obj.copyForComparison());
return obj;
}
}
obj = new (this, rs, prefix);
known .put(obj.idKey(), new WeakReference< >(obj));
original .put(obj, ( )obj.copyForComparison());
// TODO: this
return obj;
}
transient HashSet< > dirty = new HashSet< >();
transient WeakHashMap< , > original = new WeakHashMap< , >();
transient WeakHashMap< , WeakReference< >> known = new WeakHashMap< , WeakReference< >>();
public static class SQLReader extends EntityReader< >
{
public SQLReader(EntityManager em)
{
super(em, " ");
columns.add(new SQLReaderColumnDescription(" ", " ", " "));
columns.add(new SQLReaderColumnDescription(null, " ", null));
columns.add(new SQLReaderColumnDescription(null, " ", null));
columns.add(new SQLReaderColumnDescription(null, " ", null));
columns.add(new SQLReaderColumnDescription(null, " ", null));
}
public readData(ResultSet result, int column)
{
try {
if (em.db.isQueryOnly)
return new (em, result, column);
else
return em.create (result, column);
} catch (SQLException e)
{
e.printStackTrace();
return null;
}
}
}
public class RowReader implements RowReader < >
{
public int column;
public String prefix;
public RowReader(String prefix)
{
this.prefix = prefix;
}
protected RowReader(String prefix, int column)
{
this.prefix = prefix;
this.column = column;
}
public readSqlRow(ResultSet rs)
{
try {
return create (rs, column);
} catch (SQLException e)
{
e.printStackTrace();
}
return null;
}
public void configureQuery(SelectFromWhere query)
{
int firstColumn = -1;
int col;
col = query.addSelection(prefix + ". ", prefix + "_ ");
if (firstColumn == -1) firstColumn = col;
col = query.addSelection(prefix + ". ", "LINK_" + prefix + "_ ");
if (firstColumn == -1) firstColumn = col;
col = query.addSelection(prefix + ". ", "LINK_" + prefix + "_ ");
if (firstColumn == -1) firstColumn = col;
col = query.addSelection(prefix + ". ", "LINK_" + prefix + "_ ");
if (firstColumn == -1) firstColumn = col;
col = query.addSelection(prefix + ". ", "LINK_" + prefix + "_ ");
if (firstColumn == -1) firstColumn = col;
column = firstColumn;
}
public RowReader < > copy()
{
return new RowReader(prefix, column);
}
public String queryString()
{
return prefix;
}
String Prefix;
public String materialize JoinString(SelectFromWhere query)
{
if ( Prefix == null)
{
String middlePrefix = query.addTable(" ");
Prefix = query.addTable(" ");
query.addWhereClause( Prefix + ". = " + prefix + ". ");
query.addWhereClause( Prefix + ". = " + middlePrefix + ". ");
query.addWhereClause(middlePrefix + ". = " + prefix + ". ");
}
return Prefix;
}
public RowReader materialize JoinRowReader(SelectFromWhere query)
{
return new RowReader(materialize JoinString(query));
}
String Prefix;
public String materialize JoinString(SelectFromWhere query)
{
if ( Prefix == null)
{
String middlePrefix = query.addTable(" ");
Prefix = query.addTable(" ");
query.addWhereClause(prefix + ". = " + Prefix + ". ");
query.addWhereClause(prefix + ". = " + middlePrefix + ". ");
query.addWhereClause(middlePrefix + ". = " + Prefix + ". ");
}
return Prefix;
}
public RowReader materialize JoinRowReader(SelectFromWhere query)
{
return new RowReader(materialize JoinString(query));
}
}
{
// SelectFromWhere query = new SelectFromWhere();
// String prefix = query.addTable(" ");
// RowReader < > reader = new RowReader(prefix);
// // TODO: Use of db con connection here that needs to be removed
// = new QueryLazySet< >(db.con, query, reader);
JDBCConnectionInfo jdbc = new JDBCConnectionInfo();
jdbc.connection = db.con;
jdbc.timeout = db.timeout;
jdbc.testOut = db.testOut;
SQLReader reader = new SQLReader(this);
SQLQueryComposer< > query =
new SQLQueryComposer< >(
this,
jdbc,
db.queryll,
reader,
reader.getColumnNames(),
" "
);
Query = query;
= new QueryList< >(query);
}
for ( obj : dirty )
{
String sql = "UPDATE SET ";
boolean isFirst = true;
for (Map.Entry entry : map.entrySet())
{
if (!isFirst) sql = sql + ", ";
isFirst = false;
sql = sql + entry.getKey() + "= ?";
}
sql = sql + " WHERE 1=1"
+ " AND = ? " ;
if (db.testOut != null) db.testOut.println(sql);
if (sql != null)
{
try {
PreparedStatement stmt = db.con.prepareStatement(sql);
int idx = 0;
for (Map.Entry entry : map.entrySet())
{
idx++;
stmt.setObject(idx, entry.getValue());
}
idx++;
stmt.setObject(idx, obj.get ());
stmt.executeUpdate();
stmt.close();
} catch (SQLException e)
{
e.printStackTrace();
}
}
DBSet< > added = obj.get ().comparisonClone();
added.removeAll(original .get(obj).get ());
DBSet< > removed = original .get(obj).get ().comparisonClone();
removed.removeAll(obj.get ());
for ( toobj: added)
{
HashMap<String, Object> linkmap = new HashMap<String, Object>();
linkmap.put(" ", obj.get ());
linkmap.put(" ", toobj.get ());
String linksql = "INSERT INTO (";
isFirst = true;
for (Map.Entry entry : linkmap.entrySet())
{
if (!isFirst) linksql = linksql + ", ";
isFirst = false;
linksql = linksql + entry.getKey();
}
linksql = linksql + ") VALUES (";
for (int n = 0; n < linkmap.size(); n++)
{
if (n != 0) linksql = linksql + ", ";
linksql = linksql + "?";
}
linksql = linksql + ")";
if (db.testOut != null) db.testOut.println(linksql);
if (db.con != null)
{
try {
PreparedStatement stmt = db.con.prepareStatement(linksql);
int idx = 0;
for (Map.Entry entry : linkmap.entrySet())
{
idx++;
stmt.setObject(idx, entry.getValue());
}
stmt.executeUpdate();
stmt.close();
} catch (SQLException e)
{
e.printStackTrace();
}
}
}
for ( toobj: removed)
{
HashMap<String, Object> linkmap = new HashMap<String, Object>();
linkmap.put(" ", obj.get ());
linkmap.put(" ", toobj.get ());
String linksql = "DELETE FROM "
+ " WHERE 1=1";
for (Map.Entry entry : linkmap.entrySet())
{
linksql = linksql + " AND " + entry.getKey() + " = ?";
}
if (db.testOut != null) db.testOut.println(linksql);
if (db.con != null)
{
try {
PreparedStatement stmt = db.con.prepareStatement(linksql);
int idx = 0;
for (Map.Entry entry : linkmap.entrySet())
{
idx++;
stmt.setObject(idx, entry.getValue());
}
stmt.executeUpdate();
stmt.close();
} catch (SQLException e)
{
e.printStackTrace();
}
}
}
}
dirty .clear();
NoKey
rs. (prefix + "_ ")
new <
,
>(
rs. (prefix + "_ ")
, rs. (prefix + "_ ")
)
NoKey
rs. (column + )
new <
,
>(
rs. (column + )
, rs. (column + )
)
© 2015 - 2025 Weber Informatics LLC | Privacy Policy