package com.revolsys.jdbc.io;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import com.revolsys.io.PathUtil;
import com.revolsys.record.Record;
import com.revolsys.record.property.ShortNameProperty;
import com.revolsys.record.schema.FieldDefinition;
import com.revolsys.record.schema.RecordDefinition;
import com.revolsys.util.Property;
import com.revolsys.util.Strings;
import com.revolsys.util.number.Numbers;
public abstract class JdbcDdlWriter implements Cloneable {
private PrintWriter out;
public JdbcDdlWriter() {
}
public JdbcDdlWriter(final PrintWriter out) {
this.out = out;
}
@Override
public JdbcDdlWriter clone() {
try {
return (JdbcDdlWriter)super.clone();
} catch (final CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
public JdbcDdlWriter clone(final File file) {
final JdbcDdlWriter clone = clone();
clone.setOut(file);
return clone;
}
public void close() {
this.out.flush();
this.out.close();
}
public PrintWriter getOut() {
return this.out;
}
public String getSequenceName(final RecordDefinition recordDefinition) {
throw new UnsupportedOperationException();
}
public String getTableAlias(final RecordDefinition recordDefinition) {
final String shortName = ShortNameProperty.getShortName(recordDefinition);
if (shortName == null) {
final String path = recordDefinition.getPath();
return PathUtil.getName(path);
} else {
return shortName;
}
}
public void println() {
this.out.println();
}
public void setOut(final File file) {
try {
final FileWriter writer = new FileWriter(file);
this.out = new PrintWriter(writer);
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
public void setOut(final PrintWriter out) {
this.out = out;
}
public void writeAddForeignKeyConstraint(final RecordDefinition recordDefinition,
final String fieldName, final RecordDefinition referencedRecordDefinition) {
final String typePath = recordDefinition.getPath();
final String referencedTypeName = referencedRecordDefinition.getPath();
final String referencedFieldName = referencedRecordDefinition.getIdFieldName();
final String constraintName = getTableAlias(recordDefinition) + "_"
+ getTableAlias(referencedRecordDefinition) + "_FK";
writeAddForeignKeyConstraint(typePath, constraintName, fieldName, referencedTypeName,
referencedFieldName);
}
public void writeAddForeignKeyConstraint(final RecordDefinition recordDefinition,
final String fieldName, final String referenceTablePrefix,
final RecordDefinition referencedRecordDefinition) {
final String typePath = recordDefinition.getPath();
final String referencedTypeName = referencedRecordDefinition.getPath();
final String referencedFieldName = referencedRecordDefinition.getIdFieldName();
final String constraintName = getTableAlias(recordDefinition) + "_" + referenceTablePrefix + "_"
+ getTableAlias(referencedRecordDefinition) + "_FK";
writeAddForeignKeyConstraint(typePath, constraintName, fieldName, referencedTypeName,
referencedFieldName);
}
public void writeAddForeignKeyConstraint(final String typePath, final String constraintName,
final String fieldName, final String referencedTypeName, final String referencedFieldName) {
this.out.print("ALTER TABLE ");
writeTableName(typePath);
this.out.print(" ADD CONSTRAINT ");
this.out.print(constraintName);
this.out.print(" FOREIGN KEY (");
this.out.print(fieldName);
this.out.print(") REFERENCES ");
writeTableName(referencedTypeName);
this.out.print(" (");
this.out.print(referencedFieldName);
this.out.println(");");
}
public void writeAddPrimaryKeyConstraint(final RecordDefinition recordDefinition) {
final String idFieldName = recordDefinition.getIdFieldName();
if (idFieldName != null) {
final String typePath = recordDefinition.getPath();
final String constraintName = getTableAlias(recordDefinition) + "_PK";
writeAddPrimaryKeyConstraint(typePath, constraintName, idFieldName);
}
}
public void writeAddPrimaryKeyConstraint(final String typePath, final String constraintName,
final String columnName) {
this.out.print("ALTER TABLE ");
writeTableName(typePath);
this.out.print(" ADD CONSTRAINT ");
this.out.print(constraintName);
this.out.print(" PRIMARY KEY (");
this.out.print(columnName);
this.out.println(");");
}
public abstract void writeColumnDataType(final FieldDefinition attribute);
public void writeCreateSchema(final String schemaName) {
}
public String writeCreateSequence(final RecordDefinition recordDefinition) {
final String sequenceName = getSequenceName(recordDefinition);
writeCreateSequence(sequenceName);
return sequenceName;
}
public void writeCreateSequence(final String sequenceName) {
this.out.print("CREATE SEQUENCE ");
this.out.print(sequenceName);
this.out.println(";");
}
public void writeCreateTable(final RecordDefinition recordDefinition) {
final String typePath = recordDefinition.getPath();
this.out.println();
this.out.print("CREATE TABLE ");
writeTableName(typePath);
this.out.println(" (");
for (int i = 0; i < recordDefinition.getFieldCount(); i++) {
final FieldDefinition attribute = recordDefinition.getField(i);
if (i > 0) {
this.out.println(",");
}
final String name = attribute.getName();
this.out.print(" ");
this.out.print(name);
for (int j = name.length(); j < 32; j++) {
this.out.print(' ');
}
writeColumnDataType(attribute);
if (attribute.isRequired()) {
this.out.print(" NOT NULL");
}
}
this.out.println();
this.out.println(");");
writeAddPrimaryKeyConstraint(recordDefinition);
writeGeometryRecordDefinition(recordDefinition);
final FieldDefinition idField = recordDefinition.getIdField();
if (idField != null) {
if (Number.class.isAssignableFrom(idField.getDataType().getJavaClass())) {
writeCreateSequence(recordDefinition);
}
}
}
public void writeCreateView(final String typePath, final String queryTypeName,
final List<String> columnNames) {
this.out.println();
this.out.print("CREATE VIEW ");
writeTableName(typePath);
this.out.println(" AS ( ");
this.out.println(" SELECT ");
this.out.print(" ");
this.out.println(Strings.toString(",\n ", columnNames));
this.out.print(" FROM ");
writeTableName(queryTypeName);
this.out.println();
this.out.println(");");
}
public abstract void writeGeometryRecordDefinition(final RecordDefinition recordDefinition);
public void writeGrant(final String typePath, final String username, final boolean select,
final boolean insert, final boolean update, final boolean delete) {
this.out.print("GRANT ");
final List<String> perms = new ArrayList<>();
if (select) {
perms.add("SELECT");
}
if (insert) {
perms.add("INSERT");
}
if (update) {
perms.add("UPDATE");
}
if (delete) {
perms.add("DELETE");
}
this.out.print(Strings.toString(", ", perms));
this.out.print(" ON ");
writeTableName(typePath);
this.out.print(" TO ");
this.out.print(username);
this.out.println(";");
}
public void writeInsert(final Record row) {
final RecordDefinition recordDefinition = row.getRecordDefinition();
final String typePath = recordDefinition.getPath();
this.out.print("INSERT INTO ");
writeTableName(typePath);
this.out.print(" (");
for (int i = 0; i < recordDefinition.getFieldCount(); i++) {
if (i > 0) {
this.out.print(", ");
}
this.out.print(recordDefinition.getFieldName(i));
}
this.out.print(" ) VALUES (");
for (int i = 0; i < recordDefinition.getFieldCount(); i++) {
if (i > 0) {
this.out.print(", ");
}
final Object value = row.getValue(i);
if (value == null) {
this.out.print("NULL");
} else if (value instanceof Number) {
final Number number = (Number)value;
this.out.print(Numbers.toString(number));
} else {
this.out.print("'");
this.out.print(value.toString().replaceAll("'", "''"));
this.out.print("'");
}
}
this.out.println(");");
}
public void writeInserts(final List<Record> rows) {
for (final Record row : rows) {
writeInsert(row);
}
}
public void writeResetSequence(final RecordDefinition recordDefinition,
final List<Record> values) {
throw new UnsupportedOperationException();
}
public void writeTableName(final String typePath) {
final String schemaName = PathUtil.getPath(typePath).substring(1);
final String tableName = PathUtil.getName(typePath);
writeTableName(schemaName, tableName);
}
public void writeTableName(final String schemaName, final String tableName) {
if (Property.hasValue(schemaName)) {
this.out.print(schemaName);
this.out.print('.');
}
this.out.print(tableName);
}
}