package fr.lteconsulting.hexa.persistence.client.legacy.persistence;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javax.persistence.criteria.Root;
import fr.lteconsulting.hexa.client.sql.SQLiteResult;
import fr.lteconsulting.hexa.client.sql.SQLiteResult.Row;
import fr.lteconsulting.hexa.client.sql.SQLiteTypeManagerManager;
import fr.lteconsulting.hexa.client.sql.SQLiteTypeManagerManager.SQLiteTypeManager;
import fr.lteconsulting.hexa.persistence.client.legacy.persistence.ManagedObjectPool.AttachedObjectInfo;
import fr.lteconsulting.hexa.persistence.client.legacy.persistence.PersistenceConfiguration.EntityConfiguration;
import fr.lteconsulting.hexa.persistence.client.legacy.persistence.PersistenceConfiguration.FieldConfiguration;
import fr.lteconsulting.hexa.persistence.client.legacy.persistence.PersistenceConfiguration.ManyToOneFieldConfiguration;
public class QueryStructure
{
PersistenceConfiguration configuration;
ArrayList<RootImpl<?>> roots = new ArrayList<RootImpl<?>>();
ArrayList<SqlRenderable> whereClauses = new ArrayList<SqlRenderable>();
Selection selection;
QueryStructure( PersistenceConfiguration configuration )
{
this.configuration = configuration;
}
public <X> Root<X> from( Class<X> entityClass )
{
RootImpl<X> root = new RootImpl<X>( entityClass, configuration );
roots.add( root );
return root;
}
public void where( Object... clauses )
{
for( int i=0; i<clauses.length; i++ )
whereClauses.add( (SqlRenderable) clauses[i] );
}
public void multiselect( Object[] selections )
{
selection = new ObjectSelection( selections );
}
public String getSQL()
{
StringBuilder sb = new StringBuilder();
sb.append( "select " );
if( selection == null )
selection = new DefaultSelection();
selection.processSelectClause( sb );
sb.append( " from " );
boolean addComa = false;
for( RootImpl<?> root : roots )
{
if( addComa )
sb.append( ", " );
addComa = true;
EntityConfiguration entityConfig = configuration.getConfigurationForEntity( root.entityClass );
sb.append( entityConfig.tableName );
sb.append( " " );
sb.append( root.sqlAlias );
}
if( ! whereClauses.isEmpty() )
sb.append( " where " );
boolean addAnd = false;
for( SqlRenderable whereClause : whereClauses )
{
if( addAnd )
sb.append( " and " );
addAnd = true;
whereClause.appendSql( sb );
}
return sb.toString();
}
public List<?> interpretResultAndFeedEntityManager( SQLiteResult results, EntityManagerImpl em )
{
ArrayList<?> list = new ArrayList<>();
for( SQLiteResult.Row row : results )
{
selection.processResultRow( row, em, list );
}
return list;
}
interface Selection
{
void processResultRow( Row row, EntityManagerImpl em, ArrayList<?> list );
void processSelectClause( StringBuilder sb );
}
class ObjectSelection implements Selection
{
Object[] selections;
HashMap<Object, String> aliases = new HashMap<Object, String>();
public ObjectSelection( Object[] selections )
{
this.selections = selections;
}
@Override
public void processSelectClause( StringBuilder sb )
{
for( int i=0; i<selections.length; i++ )
{
if( i > 0 )
sb.append( ", " );
SqlRenderable sqlRenderable = (SqlRenderable) selections[i];
sqlRenderable.appendSql( sb );
sb.append( " as " );
String alias = AliasGeneration.nextAlias();
aliases.put( sqlRenderable, alias );
sb.append( alias );
}
}
@SuppressWarnings( { "unchecked", "rawtypes" } )
@Override
public void processResultRow( Row row, EntityManagerImpl em, ArrayList<?> list )
{
Object[] result = new Object[selections.length];
for( int i=0; i<selections.length; i++ )
{
String stringValue = row.getColumnValue( aliases.get( selections[i] ) );
if( selections[i] instanceof PathImpl )
{
PathImpl<?> path = (PathImpl<?>) selections[i];
EntityConfiguration config = path.root.configuration.getConfigurationForEntity( path.root.entityClass );
SQLiteTypeManager sqlMng = SQLiteTypeManagerManager.get( config.getFieldConfiguration( path.path ).fieldClass );
result[i] = sqlMng.getValueFromString( stringValue );
}
}
((List)list).add( result );
}
}
// default selection : selects all fields from all root entities
class DefaultSelection implements Selection
{
@Override
public void processSelectClause( StringBuilder sb )
{
boolean addComa = false;
for( RootImpl<?> root : roots )
{
EntityConfiguration entityConfig = configuration.getConfigurationForEntity( root.entityClass );
addOneSelectedField( sb, addComa, root.sqlAlias, entityConfig.idField.columnName );
addComa = true;
for( FieldConfiguration field : entityConfig.directFields )
addOneSelectedField( sb, addComa, root.sqlAlias, field.columnName );
for( ManyToOneFieldConfiguration field : entityConfig.manyToOneFields )
addOneSelectedField( sb, addComa, root.sqlAlias, field.columnName );
}
}
@SuppressWarnings( { "unchecked", "rawtypes" } )
@Override
public void processResultRow( Row row, EntityManagerImpl em, ArrayList<?> list )
{
assert roots.size() == 1 : "not yet implemented !";
RootImpl<?> root = roots.get( 0 );
EntityConfiguration entityConfig = configuration.getConfigurationForEntity( root.entityClass );
// for this root entity, what is the id of the selected object ?
String idValue = row.getColumnValue( root.sqlAlias + "_" + entityConfig.idField.columnName );
Object id = SQLiteTypeManagerManager.get( entityConfig.idField.fieldClass ).getValueFromString( idValue );
// is it already in the managed object pool ?
AttachedObjectInfo entityInfo = em.pool.findAttachedObjectByTableAndId( entityConfig.tableName, id );
if( entityInfo != null )
{
// if yes, the registered object will be added to the list
((List)list).add( entityInfo.managedObject );
}
else
{
// if not, we create the object and register it, and add it to the list
SQLiteResult.Row convertedRow = new Row();
convertedRow.addCell( entityConfig.idField.columnName, row.getColumnValue( root.sqlAlias + "_" + entityConfig.idField.columnName ) );
for( FieldConfiguration field : entityConfig.directFields )
convertedRow.addCell( field.columnName, row.getColumnValue( root.sqlAlias + "_" + field.columnName ) );
for( ManyToOneFieldConfiguration field : entityConfig.manyToOneFields )
convertedRow.addCell( field.columnName, row.getColumnValue( root.sqlAlias + "_" + field.columnName ) );
Object entity = em.createObjectAndRegisterIt( convertedRow, id, entityConfig );
((List)list).add( entity );
}
}
private void addOneSelectedField( StringBuilder sb, boolean addComa, String tableAlias, String columnName )
{
if( addComa )
sb.append( ", " );
sb.append( tableAlias + "." + columnName );
sb.append( " as " );
sb.append( tableAlias + "_" + columnName );
}
}
}