package com.robotoworks.mechanoid.db.generator;
import java.util.Collection;
import java.util.LinkedHashMap;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.resource.XtextResourceSet;
import org.eclipse.xtext.xbase.lib.Functions.Function1;
import org.eclipse.xtext.xbase.lib.IterableExtensions;
import com.google.inject.Inject;
import com.robotoworks.mechanoid.db.sqliteModel.AlterTableAddColumnStatement;
import com.robotoworks.mechanoid.db.sqliteModel.AlterTableRenameStatement;
import com.robotoworks.mechanoid.db.sqliteModel.ColumnDef;
import com.robotoworks.mechanoid.db.sqliteModel.ColumnSource;
import com.robotoworks.mechanoid.db.sqliteModel.CreateIndexStatement;
import com.robotoworks.mechanoid.db.sqliteModel.CreateTableStatement;
import com.robotoworks.mechanoid.db.sqliteModel.CreateTriggerStatement;
import com.robotoworks.mechanoid.db.sqliteModel.CreateViewStatement;
import com.robotoworks.mechanoid.db.sqliteModel.DDLStatement;
import com.robotoworks.mechanoid.db.sqliteModel.DatabaseBlock;
import com.robotoworks.mechanoid.db.sqliteModel.DropIndexStatement;
import com.robotoworks.mechanoid.db.sqliteModel.DropTableStatement;
import com.robotoworks.mechanoid.db.sqliteModel.DropTriggerStatement;
import com.robotoworks.mechanoid.db.sqliteModel.DropViewStatement;
import com.robotoworks.mechanoid.db.sqliteModel.IndexedColumn;
import com.robotoworks.mechanoid.db.sqliteModel.MigrationBlock;
import com.robotoworks.mechanoid.db.sqliteModel.Model;
import com.robotoworks.mechanoid.db.sqliteModel.PrimaryConstraint;
import com.robotoworks.mechanoid.db.sqliteModel.SqliteModelFactory;
import com.robotoworks.mechanoid.db.sqliteModel.TableConstraint;
import com.robotoworks.mechanoid.db.sqliteModel.UniqueTableConstraint;
public class SqliteDatabaseSnapshot {
public static class Builder {
@Inject XtextResourceSet mSnapshotResourceSet;
private LinkedHashMap<String, CreateTableStatement> mTables = new LinkedHashMap<String, CreateTableStatement>();
private LinkedHashMap<String, CreateViewStatement> mViews = new LinkedHashMap<String, CreateViewStatement>();
private LinkedHashMap<String, CreateTriggerStatement> mTriggers = new LinkedHashMap<String, CreateTriggerStatement>();
private LinkedHashMap<String, CreateIndexStatement> mIndexes = new LinkedHashMap<String, CreateIndexStatement>();
private Model mSnapshotModel;
private Model mSourceModel;
private void buildSnapshot(Model model) {
DatabaseBlock database = model.getDatabase();
for(MigrationBlock migration : database.getMigrations()) {
EList<DDLStatement> statements = migration.getStatements();
for(DDLStatement statement : statements) {
if(statement instanceof CreateTableStatement) {
CreateTableStatement createTableStmt = (CreateTableStatement) statement;
CreateTableStatement copy = EcoreUtil2.copy(createTableStmt);
mTables.put(createTableStmt.getName(), copy);
} else if (statement instanceof CreateViewStatement) {
CreateViewStatement createViewStmt = (CreateViewStatement) statement;
mViews.put(createViewStmt.getName(), createViewStmt);
} else if(statement instanceof AlterTableRenameStatement) {
AlterTableRenameStatement renameStmt = (AlterTableRenameStatement) statement;
CreateTableStatement tableToAlter = mTables.get(renameStmt.getTable().getName());
tableToAlter.setName(renameStmt.getName());
mTables.put(renameStmt.getName(), tableToAlter);
mTables.remove(renameStmt.getTable().getName());
}
else if (statement instanceof AlterTableAddColumnStatement) {
AlterTableAddColumnStatement addColumnStmt = (AlterTableAddColumnStatement) statement;
CreateTableStatement tableToAlter = mTables.get(addColumnStmt.getTable().getName());
tableToAlter.getColumnDefs().add(EcoreUtil.copy(addColumnStmt.getColumnDef()));
}
else if (statement instanceof CreateTriggerStatement) {
CreateTriggerStatement createTriggerStmt = (CreateTriggerStatement) statement;
mTriggers.put(createTriggerStmt.getName(), createTriggerStmt);
}
else if (statement instanceof CreateIndexStatement) {
CreateIndexStatement createIndexStmt = (CreateIndexStatement) statement;
mIndexes.put(createIndexStmt.getName(), createIndexStmt);
}
else if (statement instanceof DropTableStatement) {
DropTableStatement dropTableStmt = (DropTableStatement) statement;
mTables.remove(dropTableStmt.getTable().getName());
}
else if (statement instanceof DropViewStatement) {
DropViewStatement dropViewStmt = (DropViewStatement) statement;
mViews.remove(dropViewStmt.getView().getName());
}
else if (statement instanceof DropTriggerStatement) {
DropTriggerStatement dropTriggerStmt = (DropTriggerStatement) statement;
mTriggers.remove(dropTriggerStmt.getTrigger().getName());
}
else if(statement instanceof DropIndexStatement) {
DropIndexStatement dropIndexStmt = (DropIndexStatement) statement;
mIndexes.remove(dropIndexStmt.getIndex().getName());
}
}
}
}
private void buildSnapshotModel() {
XtextResource resource = (XtextResource) mSnapshotResourceSet.createResource(URI.createURI("platform:/resource/app1/temp.mechdb"));
mSnapshotModel = (Model) SqliteModelFactory.eINSTANCE.createModel();
mSnapshotModel.setPackageName(mSourceModel.getPackageName());
resource.getContents().add(mSnapshotModel);
DatabaseBlock database = (DatabaseBlock) SqliteModelFactory.eINSTANCE.createDatabaseBlock();
database.setName(mSourceModel.getDatabase().getName());
mSnapshotModel.setDatabase(database);
MigrationBlock migration = (MigrationBlock) SqliteModelFactory.eINSTANCE.createMigrationBlock();
database.getMigrations().add(migration);
for(CreateTableStatement stmt : mTables.values()) {
migration.getStatements().add(stmt);
resolveIndexedColumnReferences(stmt);
}
EcoreUtil2.resolveAll(mSnapshotResourceSet);
}
private void resolveIndexedColumnReferences(CreateTableStatement stmt) {
Iterable<IndexedColumn> columns = null;
for(TableConstraint c : stmt.getConstraints()) {
if(c instanceof UniqueTableConstraint) {
UniqueTableConstraint uc = (UniqueTableConstraint) c;
columns = uc.getColumns();
} else if (c instanceof PrimaryConstraint) {
PrimaryConstraint pc = (PrimaryConstraint) c;
columns = pc.getColumns();
}
if(columns == null) {
return;
}
for(final IndexedColumn col : columns) {
ColumnSource source = IterableExtensions.findFirst(stmt.getColumnDefs(), new Function1<ColumnSource, Boolean>(){
public Boolean apply(ColumnSource p) {
if(p.getName().equals(col.getColumnReference().getName())) {
return true;
}
return false;
}
});
col.setColumnReference((ColumnDef) source);
}
}
}
public SqliteDatabaseSnapshot build(Model model) {
mSourceModel = model;
buildSnapshot(model);
buildSnapshotModel();
return new SqliteDatabaseSnapshot(mTables, mViews, mTriggers, mIndexes);
}
}
private Collection<CreateTableStatement> mTables;
private Collection<CreateViewStatement> mViews;
private Collection<CreateTriggerStatement> mTriggers;
private Collection<CreateIndexStatement> mIndexes;
public SqliteDatabaseSnapshot(
LinkedHashMap<String, CreateTableStatement> tables,
LinkedHashMap<String, CreateViewStatement> views,
LinkedHashMap<String, CreateTriggerStatement> triggers,
LinkedHashMap<String, CreateIndexStatement> indexes) {
mTables = tables.values();
mViews = views.values();
mTriggers = triggers.values();
mIndexes = indexes.values();
}
public Collection<CreateTableStatement> getTables() {
return mTables;
}
public Collection<CreateViewStatement> getViews() {
return mViews;
}
public Collection<CreateTriggerStatement> getTriggers() {
return mTriggers;
}
public Collection<CreateIndexStatement> getIndexes() {
return mIndexes;
}
public boolean containsDefinition(final String name) {
CreateTableStatement tableStmt = IterableExtensions.findFirst(mTables, new Function1<CreateTableStatement, Boolean>() {
@Override
public Boolean apply(CreateTableStatement p) {
return p.getName().equals(name);
}
});
if(tableStmt != null) {
return true;
}
CreateViewStatement viewStmt = IterableExtensions.findFirst(mViews, new Function1<CreateViewStatement, Boolean>() {
@Override
public Boolean apply(CreateViewStatement p) {
return p.getName().equals(name);
}
});
if(viewStmt != null) {
return true;
}
return false;
}
}