ru.curs.celesta.score.CelestaSerializer Maven / Gradle / Ivy
package ru.curs.celesta.score;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.stream.Collectors;
import ru.curs.celesta.score.SequenceElement.Argument;
/**
* Serializes grain and its components to CelestaSQL.
*
* The class name reflects its counterpart - {@link CelestaParser}
*
* @author Pavel Perminov ([email protected])
* @since 2019-03-07
*/
public final class CelestaSerializer {
private final PrintWriter writer;
public CelestaSerializer(PrintWriter writer) {
this.writer = writer;
}
static String toString(MaterializedView mv) throws IOException {
try (StringWriter sw = new StringWriter()) {
new CelestaSerializer(new PrintWriter(sw)).save(mv);
return sw.toString();
}
}
/**
* Returns a query based on which the view is going to be created.
*
* @param v view
* @return
* @throws IOException if query creation fails
*/
public static String toQueryString(View v) throws IOException {
try (StringWriter sw = new StringWriter()) {
new CelestaSerializer(new PrintWriter(sw)).saveQuery(v);
return sw.toString();
}
}
/**
* Serializes grain part to its CelestaSQL representation.
*
* @param gp grain part
* @throws IOException if serialization fails
*/
public void save(GrainPart gp) throws IOException {
save(gp.getGrain(), gp);
}
/**
* Serializes grain to its CelestaSQL representation.
*
* @param grain grain
* @throws IOException if serialization fails
*/
public void save(Grain grain) throws IOException {
save(grain, null);
}
private void save(Grain grain, GrainPart gp) throws IOException {
writeCelestaDoc(grain);
writer.printf("CREATE SCHEMA %s VERSION '%s'", grain.getName(), grain.getVersion());
if (!grain.isAutoupdate()) {
writer.printf(" WITH NO AUTOUPDATE");
}
writer.printf(";%n");
writer.println();
writer.println("-- *** SEQUENCES ***");
Collection sequences = grain.getElements(SequenceElement.class, gp);
for (SequenceElement s : sequences) {
save(s);
}
writer.println("-- *** TABLES ***");
Collection tables = grain.getElements(Table.class, gp);
for (Table t : tables) {
save(t);
}
Collection roTables = grain.getElements(ReadOnlyTable.class, gp);
for (ReadOnlyTable rot : roTables) {
save(rot);
}
writer.println("-- *** FOREIGN KEYS ***");
for (BasicTable t : tables) {
for (ForeignKey fk : t.getForeignKeys()) {
save(fk);
}
}
writer.println("-- *** INDICES ***");
Collection indices = grain.getElements(Index.class, gp);
for (Index i : indices) {
save(i);
}
writer.println("-- *** VIEWS ***");
Collection views = grain.getElements(View.class, gp);
for (View v : views) {
save(v);
}
writer.println("-- *** MATERIALIZED VIEWS ***");
Collection materializedViews = grain.getElements(MaterializedView.class, gp);
for (MaterializedView mv : materializedViews) {
save(mv);
}
writer.println("-- *** PARAMETERIZED VIEWS ***");
Collection parameterizedViews = grain.getElements(ParameterizedView.class, gp);
for (ParameterizedView pv : parameterizedViews) {
save(pv);
}
}
private boolean writeCelestaDoc(NamedElement e) {
String doc = e.getCelestaDoc();
if (doc == null) {
return false;
} else {
writer.printf("/**%s*/%n", doc);
return true;
}
}
void save(SequenceElement s) {
writeCelestaDoc(s);
writer.printf("CREATE SEQUENCE %s ", s.getName());
if (s.hasArgument(Argument.START_WITH)) {
writer.printf("START WITH %s ", s.getStartWith());
}
if (s.hasArgument(Argument.INCREMENT_BY)) {
writer.printf("INCREMENT BY %s ", s.getIncrementBy());
}
if (s.hasArgument(Argument.MINVALUE)) {
writer.printf("MINVALUE %s ", s.getMinValue());
}
if (s.hasArgument(Argument.MAXVALUE)) {
writer.printf("MAXVALUE %s ", s.getMaxValue());
}
if (s.hasArgument(Argument.CYCLE) && s.isCycle()) {
writer.write("CYCLE ");
}
writer.println(";");
writer.println();
}
/**
* Serializes table to its CelestaSQL representation.
*
* @param t table
* @throws IOException if serialization fails
*/
void save(Table t) throws IOException {
saveHead(t);
if (!t.isVersioned()) {
writer.write(" WITH NO VERSION CHECK");
saveTail(t, false);
} else {
saveTail(t, true);
}
}
/**
* Serializes read only table to its CelestaSQL representation.
*
* @param t table
* @throws IOException if serialization fails
*/
void save(ReadOnlyTable t) throws IOException {
saveHead(t);
writer.write(" WITH READ ONLY");
saveTail(t, false);
}
private void saveHead(BasicTable t) throws IOException {
writeCelestaDoc(t);
writer.printf("CREATE TABLE %s(%n", t.getQuotedNameIfNeeded());
boolean comma = false;
for (Column> c : t.getColumns().values()) {
if (comma) {
writer.println(",");
}
save(c);
comma = true;
}
// Here we write the PK
if (!t.getPrimaryKey().isEmpty()) {
if (comma) {
writer.write(",");
}
writer.println();
writer.write(" CONSTRAINT ");
writer.write(t.getPkConstraintName());
writer.write(" PRIMARY KEY (");
comma = false;
for (Column> c : t.getPrimaryKey().values()) {
if (comma) {
writer.write(", ");
}
writer.write(c.getQuotedNameIfNeeded());
comma = true;
}
writer.println(")");
}
writer.write(")");
}
private void saveTail(BasicTable t, boolean isWith) {
if (!t.isAutoUpdate()) {
if (isWith) {
writer.write(" WITH");
}
writer.write(" NO AUTOUPDATE");
}
writer.println(";");
writer.println();
}
/**
* Serializes column to its CelestaSQL representation.
*
* @param c column
* @throws IOException if serialization fails
*/
void save(Column> c) throws IOException {
writer.write(" ");
if (writeCelestaDoc(c)) {
writer.write(" ");
}
writer.write(c.getName());
switch (c.getCelestaType()) {
case BinaryColumn.CELESTA_TYPE:
saveColumn((BinaryColumn) c);
break;
case BooleanColumn.CELESTA_TYPE:
saveColumn((BooleanColumn) c);
break;
case DateTimeColumn.CELESTA_TYPE:
saveColumn((DateTimeColumn) c);
break;
case DecimalColumn.CELESTA_TYPE:
saveColumn((DecimalColumn) c);
break;
case ZonedDateTimeColumn.CELESTA_TYPE:
saveColumn((ZonedDateTimeColumn) c);
break;
case FloatingColumn.CELESTA_TYPE:
saveColumn((FloatingColumn) c);
break;
case IntegerColumn.CELESTA_TYPE:
saveColumn((IntegerColumn) c);
break;
case StringColumn.VARCHAR:
case StringColumn.TEXT:
saveColumn((StringColumn) c);
break;
default:
throw new IOException(String.format("No serializer for column of type %s was found!",
c.getCelestaType()));
}
}
private void saveColumn(BinaryColumn c) {
writer.write(" BLOB");
if (!c.isNullable()) {
writer.write(" NOT NULL");
}
String defaultVal = c.getDefaultValue();
if (defaultVal != null) {
writer.write(" DEFAULT ");
writer.write(defaultVal);
}
}
private void saveColumn(BooleanColumn c) {
writer.write(" BIT");
if (!c.isNullable()) {
writer.write(" NOT NULL");
}
Boolean defaultVal = c.getDefaultValue();
if (defaultVal != null) {
writer.write(" DEFAULT '");
writer.write(defaultVal.toString().toUpperCase());
writer.write("'");
}
}
private void saveColumn(DateTimeColumn c) {
writer.write(" DATETIME");
if (!c.isNullable()) {
writer.write(" NOT NULL");
}
if (c.isGetdate()) {
writer.write(" DEFAULT GETDATE()");
} else {
Date defaultVal = c.getDefaultValue();
if (defaultVal != null) {
writer.write(" DEFAULT '");
DateFormat df = new SimpleDateFormat("yyyyMMdd");
writer.write(df.format(defaultVal));
writer.write("'");
}
}
}
private void saveColumn(DecimalColumn c) {
writer.write(" DECIMAL");
if (!c.isNullable()) {
writer.write(" NOT NULL");
}
BigDecimal defaultVal = c.getDefaultValue();
if (defaultVal != null) {
writer.write(" DEFAULT ");
writer.write(defaultVal.toString());
}
}
private void saveColumn(FloatingColumn c) {
writer.write(" REAL");
if (!c.isNullable()) {
writer.write(" NOT NULL");
}
Double defaultVal = c.getDefaultValue();
if (defaultVal != null) {
writer.write(" DEFAULT ");
writer.write(defaultVal.toString());
}
}
private void saveColumn(IntegerColumn c) {
writer.write(" INT");
if (!c.isNullable()) {
writer.write(" NOT NULL");
}
Integer defaultVal = c.getDefaultValue();
if (defaultVal != null) {
writer.write(" DEFAULT ");
writer.write(defaultVal.toString());
}
}
private void saveColumn(StringColumn c) {
if (c.isMax()) {
writer.write(" TEXT");
} else {
writer.write(" VARCHAR(");
writer.write(Integer.toString(c.getLength()));
writer.write(")");
}
if (!c.isNullable()) {
writer.write(" NOT NULL");
}
String defaultVal = c.getDefaultValue();
if (defaultVal != null) {
writer.write(" DEFAULT ");
writer.write(StringColumn.quoteString(defaultVal));
}
}
private void saveColumn(ZonedDateTimeColumn c) {
writer.write(" " + ZonedDateTimeColumn.CELESTA_TYPE);
if (!c.isNullable()) {
writer.write(" NOT NULL");
}
}
/**
* Serializes foreign key to its CelestaSQL representation.
*
* @param fk foreign key
* @throws IOException if serialization fails
*/
void save(ForeignKey fk) {
writer.write("ALTER TABLE ");
writer.write(fk.getParentTable().getQuotedNameIfNeeded());
writer.write(" ADD CONSTRAINT ");
String name = fk.getConstraintName();
writer.write(name);
writer.write(" FOREIGN KEY (");
boolean comma = false;
for (Column> c : fk.getColumns().values()) {
if (comma) {
writer.write(", ");
}
writer.write(c.getQuotedNameIfNeeded());
comma = true;
}
writer.write(") REFERENCES ");
writer.write(fk.getReferencedTable().getGrain().getQuotedNameIfNeeded());
writer.write(".");
writer.write(fk.getReferencedTable().getQuotedNameIfNeeded());
writer.write("(");
comma = false;
for (Column> c : fk.getReferencedTable().getPrimaryKey().values()) {
if (comma) {
writer.write(", ");
}
writer.write(c.getQuotedNameIfNeeded());
comma = true;
}
writer.write(")");
switch (fk.getUpdateRule()) {
case CASCADE:
writer.write(" ON UPDATE CASCADE");
break;
case SET_NULL:
writer.write(" ON UPDATE SET NULL");
break;
case NO_ACTION:
default:
break;
}
switch (fk.getDeleteRule()) {
case CASCADE:
writer.write(" ON DELETE CASCADE");
break;
case SET_NULL:
writer.write(" ON DELETE SET NULL");
break;
case NO_ACTION:
default: break;
}
writer.println(";");
}
/**
* Serializes index to its CelestaSQL representation.
*
* @param i index
* @throws IOException if serialization fails
*/
void save(Index i) {
writeCelestaDoc(i);
writer.write("CREATE INDEX ");
writer.write(i.getQuotedNameIfNeeded());
writer.write(" ON ");
writer.write(i.getTable().getQuotedNameIfNeeded());
writer.write("(");
boolean comma = false;
for (Column> c : i.getColumns().values()) {
if (comma) {
writer.write(", ");
}
writer.write(c.getQuotedNameIfNeeded());
comma = true;
}
writer.println(");");
}
/**
* Serializes view to its CelestaSQL representation.
*
* @param v view
* @throws IOException if serialization fails
*/
void save(View v) throws IOException {
writeCelestaDoc(v);
v.createViewScript(writer, new ViewCelestaSQLGen(v));
writer.println(";");
writer.println();
}
private void saveQuery(View v) throws IOException {
v.selectScript(writer, new ViewCelestaSQLGen(v));
}
/**
* Serializes materialized view to its CelestaSQL representation.
*
* @param mv materialized view
* @throws IOException if serialization fails
*/
void save(MaterializedView mv) throws IOException {
writeCelestaDoc(mv);
SQLGenerator gen = new MaterializedViewCelestaSQLGen(mv);
writer.println(gen.preamble(mv));
mv.selectScript(writer, gen);
writer.println(";");
writer.println();
}
/**
* Serializes parameterized view to its CelestaSQL representation.
*
* @param pv parameterized view
* @throws IOException if serialization fails
*/
void save(ParameterizedView pv) throws IOException {
writeCelestaDoc(pv);
pv.createViewScript(writer, new ParameterizedViewCelestaSQLGen(pv));
writer.println(";");
writer.println();
}
private abstract static class AbstractViewCelestaSQLGen extends SQLGenerator {
final V view;
AbstractViewCelestaSQLGen(V view) {
this.view = view;
}
@Override
protected String preamble(AbstractView dummyView) {
return String.format("create %s %s as", view.viewType(), viewName(view));
}
@Override
protected String viewName(AbstractView dummyView) {
return view.getQuotedNameIfNeeded();
}
@Override
protected String tableName(TableRef tRef) {
TableElement t = tRef.getTable();
if (t.getGrain() == view.getGrain()) {
return String.format("%s as %s", t.getQuotedNameIfNeeded(), tRef.getAlias());
} else {
return String.format("%s.%s as %s",
t.getGrain().getQuotedNameIfNeeded(), t.getQuotedNameIfNeeded(),
tRef.getAlias());
}
}
@Override
protected boolean quoteNames() {
return false;
}
}
private static class ViewCelestaSQLGen extends AbstractViewCelestaSQLGen {
ViewCelestaSQLGen(View view) {
super(view);
}
}
private static class MaterializedViewCelestaSQLGen extends AbstractViewCelestaSQLGen {
MaterializedViewCelestaSQLGen(MaterializedView view) {
super(view);
}
}
private static class ParameterizedViewCelestaSQLGen extends AbstractViewCelestaSQLGen {
ParameterizedViewCelestaSQLGen(ParameterizedView view) {
super(view);
}
@Override
protected String preamble(AbstractView dummyView) {
return String.format("create %s %s (%s) as",
view.viewType(),
viewName(view),
view.getParameters().values().stream()
.map(p -> p.getName() + " " + p.getType().toString())
.collect(Collectors.joining(", ")));
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy