package org.jooq.impl;
import static org.jooq.tools.StringUtils.isBlank;
import static org.jooq.util.xml.jaxb.TableConstraintType.CHECK;
import static org.jooq.util.xml.jaxb.TableConstraintType.FOREIGN_KEY;
import static org.jooq.util.xml.jaxb.TableConstraintType.PRIMARY_KEY;
import static org.jooq.util.xml.jaxb.TableConstraintType.UNIQUE;
import java.math.BigInteger;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.jooq.Catalog;
import org.jooq.Check;
import org.jooq.Configuration;
import org.jooq.Domain;
import org.jooq.Field;
import org.jooq.ForeignKey;
import org.jooq.Index;
import org.jooq.Key;
import org.jooq.Param;
import org.jooq.Qualified;
import org.jooq.Schema;
import org.jooq.Sequence;
import org.jooq.SortField;
import org.jooq.SortOrder;
import org.jooq.Table;
import org.jooq.UniqueKey;
import org.jooq.tools.Convert;
import org.jooq.util.xml.jaxb.CheckConstraint;
import org.jooq.util.xml.jaxb.Column;
import org.jooq.util.xml.jaxb.IndexColumnUsage;
import org.jooq.util.xml.jaxb.InformationSchema;
import org.jooq.util.xml.jaxb.KeyColumnUsage;
import org.jooq.util.xml.jaxb.ReferentialConstraint;
import org.jooq.util.xml.jaxb.TableConstraint;
import org.jooq.util.xml.jaxb.TableConstraintType;
import org.jooq.util.xml.jaxb.TableType;
final class InformationSchemaExport {
static final InformationSchema exportTables(Configuration configuration, List<Table<?>> tables) {
InformationSchema result = new InformationSchema();
Set<Catalog> includedCatalogs = new LinkedHashSet<>();
Set<Schema> includedSchemas = new LinkedHashSet<>();
Set<Table<?>> includedTables = new LinkedHashSet<>(tables);
for (Table<?> t : tables)
if (t.getSchema() != null)
includedSchemas.add(t.getSchema());
for (Schema s : includedSchemas)
if (s.getCatalog() != null)
includedCatalogs.add(s.getCatalog());
for (Catalog c : includedCatalogs)
exportCatalog0(result, c);
for (Schema s : includedSchemas)
exportSchema0(result, s);
for (Table<?> t : tables)
exportTable0(configuration, result, t, includedTables);
return result;
}
static final InformationSchema exportSchemas(Configuration configuration, List<Schema> schemas) {
InformationSchema result = new InformationSchema();
Set<Catalog> includedCatalogs = new LinkedHashSet<>();
Set<Table<?>> includedTables = new LinkedHashSet<>();
for (Schema s : schemas) {
if (s.getCatalog() != null)
includedCatalogs.add(s.getCatalog());
for (Table<?> t : s.getTables())
includedTables.add(t);
}
for (Catalog c : includedCatalogs)
exportCatalog0(result, c);
for (Schema s : schemas) {
exportSchema0(result, s);
for (Domain<?> d : s.getDomains())
exportDomain0(configuration, result, d);
for (Table<?> t : s.getTables())
exportTable0(configuration, result, t, includedTables);
for (Sequence<?> q : s.getSequences())
exportSequence0(configuration, result, q);
}
return result;
}
static final InformationSchema exportCatalogs(Configuration configuration, List<Catalog> catalogs) {
InformationSchema result = new InformationSchema();
Set<Table<?>> includedTables = new LinkedHashSet<>();
for (Catalog c : catalogs)
for (Schema s : c.getSchemas())
for (Table<?> t : s.getTables())
includedTables.add(t);
for (Catalog c : catalogs) {
exportCatalog0(result, c);
for (Schema s : c.getSchemas()) {
exportSchema0(result, s);
for (Domain<?> d : s.getDomains())
exportDomain0(configuration, result, d);
for (Table<?> t : s.getTables())
exportTable0(configuration, result, t, includedTables);
for (Sequence<?> q : s.getSequences())
exportSequence0(configuration, result, q);
}
}
return result;
}
private static final void exportDomain0(Configuration configuration, InformationSchema result, Domain<?> d) {
org.jooq.util.xml.jaxb.Domain id = new org.jooq.util.xml.jaxb.Domain();
String catalogName = catalogName(d);
String schemaName = schemaName(d);
String domainName = d.getName();
if (!isBlank(catalogName))
id.setDomainCatalog(catalogName);
if (!isBlank(schemaName))
id.setDomainSchema(schemaName);
id.setDomainName(domainName);
id.setDataType(d.getDataType().getTypeName(configuration));
if (d.getDataType().lengthDefined())
id.setCharacterMaximumLength(d.getDataType().length());
if (d.getDataType().precisionDefined())
id.setNumericPrecision(d.getDataType().precision());
if (d.getDataType().scaleDefined())
id.setNumericScale(d.getDataType().scale());
result.getDomains().add(id);
for (Check<?> c : d.getChecks()) {
org.jooq.util.xml.jaxb.DomainConstraint idc = new org.jooq.util.xml.jaxb.DomainConstraint();
org.jooq.util.xml.jaxb.CheckConstraint icc = new org.jooq.util.xml.jaxb.CheckConstraint();
if (!isBlank(catalogName)) {
idc.setDomainCatalog(catalogName);
idc.setConstraintCatalog(catalogName);
icc.setConstraintCatalog(catalogName);
}
if (!isBlank(schemaName)) {
idc.setDomainSchema(schemaName);
idc.setConstraintSchema(schemaName);
icc.setConstraintSchema(schemaName);
}
idc.setDomainName(domainName);
idc.setConstraintName(c.getName());
icc.setConstraintName(c.getName());
icc.setCheckClause(configuration.dsl().render(c.condition()));
result.getDomainConstraints().add(idc);
result.getCheckConstraints().add(icc);
}
}
private static final void exportSequence0(Configuration configuration, InformationSchema result, Sequence<?> q) {
org.jooq.util.xml.jaxb.Sequence iq = new org.jooq.util.xml.jaxb.Sequence();
String catalogName = catalogName(q);
String schemaName = schemaName(q);
if (!isBlank(catalogName))
iq.setSequenceCatalog(catalogName);
if (!isBlank(schemaName))
iq.setSequenceSchema(schemaName);
iq.setSequenceName(q.getName());
iq.setDataType(q.getDataType().getTypeName(configuration));
if (q.getDataType().lengthDefined())
iq.setCharacterMaximumLength(q.getDataType().length());
if (q.getDataType().precisionDefined())
iq.setNumericPrecision(q.getDataType().precision());
if (q.getDataType().scaleDefined())
iq.setNumericScale(q.getDataType().scale());
if (q.getStartWith() != null)
iq.setStartValue(Convert.convert(q.getStartWith() instanceof Param ? ((Param<?>) q.getStartWith()).getValue() : q.getStartWith().toString(), BigInteger.class));
if (q.getIncrementBy() != null)
iq.setIncrement(Convert.convert(q.getIncrementBy() instanceof Param ? ((Param<?>) q.getIncrementBy()).getValue() : q.getIncrementBy().toString(), BigInteger.class));
if (q.getMinvalue() != null)
iq.setMinimumValue(Convert.convert(q.getMinvalue() instanceof Param ? ((Param<?>) q.getMinvalue()).getValue() : q.getMinvalue().toString(), BigInteger.class));
if (q.getMaxvalue() != null)
iq.setMaximumValue(Convert.convert(q.getMaxvalue() instanceof Param ? ((Param<?>) q.getMaxvalue()).getValue() : q.getMaxvalue().toString(), BigInteger.class));
iq.setCycleOption(q.getCycle());
if (q.getCache() != null)
iq.setCache(Convert.convert(q.getCache() instanceof Param ? ((Param<?>) q.getCache()).getValue() : q.getCache().toString(), BigInteger.class));
result.getSequences().add(iq);
}
private static final void exportCatalog0(InformationSchema result, Catalog c) {
org.jooq.util.xml.jaxb.Catalog ic = new org.jooq.util.xml.jaxb.Catalog();
if (!isBlank(c.getName())) {
ic.setCatalogName(c.getName());
ic.setComment(c.getComment());
result.getCatalogs().add(ic);
}
}
private static final void exportSchema0(InformationSchema result, Schema s) {
org.jooq.util.xml.jaxb.Schema is = new org.jooq.util.xml.jaxb.Schema();
String catalogName = catalogName(s);
if (!isBlank(catalogName))
is.setCatalogName(catalogName);
if (!isBlank(s.getName())) {
is.setSchemaName(s.getName());
is.setComment(s.getComment());
result.getSchemata().add(is);
}
}
private static final void exportTable0(Configuration configuration, InformationSchema result, Table<?> t, Set<Table<?>> includedTables) {
org.jooq.util.xml.jaxb.Table it = new org.jooq.util.xml.jaxb.Table();
String catalogName = catalogName(t);
String schemaName = schemaName(t);
if (!isBlank(catalogName))
it.setTableCatalog(catalogName);
if (!isBlank(schemaName))
it.setTableSchema(schemaName);
switch (t.getOptions().type()) {
case MATERIALIZED_VIEW:
case VIEW: it.setTableType(TableType.VIEW); break;
case TEMPORARY: it.setTableType(TableType.GLOBAL_TEMPORARY); break;
case FUNCTION:
case TABLE:
case EXPRESSION:
case UNKNOWN:
default: it.setTableType(TableType.BASE_TABLE); break;
}
it.setTableName(t.getName());
it.setComment(t.getComment());
result.getTables().add(it);
if (t.getOptions().type() == org.jooq.TableOptions.TableType.VIEW) {
org.jooq.util.xml.jaxb.View iv = new org.jooq.util.xml.jaxb.View();
if (!isBlank(catalogName))
iv.setTableCatalog(catalogName);
if (!isBlank(schemaName))
iv.setTableSchema(schemaName);
iv.setTableName(t.getName());
iv.setViewDefinition(t.getOptions().source());
result.getViews().add(iv);
}
Field<?>[] fields = t.fields();
for (int i = 0; i < fields.length; i++) {
Field<?> f = fields[i];
Column ic = new Column();
if (!isBlank(catalogName))
ic.setTableCatalog(catalogName);
if (!isBlank(schemaName))
ic.setTableSchema(schemaName);
ic.setTableName(t.getName());
ic.setColumnName(f.getName());
ic.setComment(f.getComment());
ic.setDataType(f.getDataType().getTypeName(configuration));
if (f.getDataType().lengthDefined())
ic.setCharacterMaximumLength(f.getDataType().length());
if (f.getDataType().precisionDefined())
ic.setNumericPrecision(f.getDataType().precision());
if (f.getDataType().scaleDefined())
ic.setNumericScale(f.getDataType().scale());
ic.setColumnDefault(DSL.using(configuration).render(f.getDataType().defaultValue()));
ic.setIsNullable(f.getDataType().nullable());
ic.setOrdinalPosition(i + 1);
result.getColumns().add(ic);
}
for (UniqueKey<?> key : t.getKeys())
exportKey0(result, t, key, key.isPrimary() ? PRIMARY_KEY : UNIQUE);
for (ForeignKey<?, ?> fk : t.getReferences())
if (includedTables.contains(fk.getKey().getTable()))
exportKey0(result, t, fk, FOREIGN_KEY);
for (Check<?> chk : t.getChecks())
if (includedTables.contains(chk.getTable()))
exportCheck0(configuration, result, t, chk);
for (Index index : t.getIndexes())
exportIndex0(result, t, index);
}
private static final void exportCheck0(Configuration configuration, InformationSchema result, Table<?> t, Check<?> chk) {
exportTableConstraint(result, t, chk.getName(), CHECK);
CheckConstraint c = new CheckConstraint();
String catalogName = catalogName(t);
String schemaName = schemaName(t);
if (!isBlank(catalogName))
c.setConstraintCatalog(catalogName);
if (!isBlank(schemaName))
c.setConstraintSchema(schemaName);
c.setConstraintName(chk.getName());
c.setCheckClause(configuration.dsl().render(chk.condition()));
result.getCheckConstraints().add(c);
}
private static final void exportIndex0(InformationSchema result, Table<?> t, Index index) {
org.jooq.util.xml.jaxb.Index i = new org.jooq.util.xml.jaxb.Index();
String catalogName = catalogName(t);
String schemaName = schemaName(t);
if (!isBlank(catalogName))
i.withIndexCatalog(catalogName)
.withTableCatalog(catalogName);
if (!isBlank(schemaName))
i.withIndexSchema(schemaName)
.withTableSchema(schemaName);
i.setIndexName(index.getName());
i.setTableName(t.getName());
i.setIsUnique(index.getUnique());
result.getIndexes().add(i);
int position = 1;
for (SortField<?> sortField : index.getFields()) {
IndexColumnUsage ic = new IndexColumnUsage();
if (!isBlank(catalogName))
ic.withIndexCatalog(catalogName)
.withTableCatalog(catalogName);
if (!isBlank(schemaName))
ic.withIndexSchema(schemaName)
.withTableSchema(schemaName);
ic.setIndexName(index.getName());
ic.setTableName(t.getName());
ic.setOrdinalPosition(position++);
ic.setColumnName(sortField.getName());
ic.setIsDescending(sortField.getOrder() == SortOrder.DESC);
result.getIndexColumnUsages().add(ic);
}
}
private static final void exportKey0(InformationSchema result, Table<?> t, Key<?> key, TableConstraintType constraintType) {
exportTableConstraint(result, t, key.getName(), constraintType);
String catalogName = catalogName(t);
String schemaName = schemaName(t);
int i = 0;
for (Field<?> f : key.getFields()) {
KeyColumnUsage kc = new KeyColumnUsage();
if (!isBlank(catalogName)) {
kc.setConstraintCatalog(catalogName);
kc.setTableCatalog(catalogName);
}
if (!isBlank(schemaName)) {
kc.setConstraintSchema(schemaName);
kc.setTableSchema(schemaName);
}
kc.setColumnName(f.getName());
kc.setTableName(t.getName());
kc.setOrdinalPosition(++i);
kc.setConstraintName(key.getName());
result.getKeyColumnUsages().add(kc);
}
if (constraintType == FOREIGN_KEY) {
ReferentialConstraint rc = new ReferentialConstraint();
UniqueKey<?> uk = ((ForeignKey<?, ?>) key).getKey();
String ukCatalogName = catalogName(uk.getTable());
String ukSchemaName = schemaName(uk.getTable());
if (!isBlank(catalogName))
rc.setConstraintCatalog(catalogName);
if (!isBlank(ukCatalogName))
rc.setUniqueConstraintCatalog(ukCatalogName);
if (!isBlank(schemaName))
rc.setConstraintSchema(schemaName);
if (!isBlank(ukSchemaName))
rc.setUniqueConstraintSchema(ukSchemaName);
rc.setConstraintName(key.getName());
rc.setUniqueConstraintName(uk.getName());
result.getReferentialConstraints().add(rc);
}
}
private static final void exportTableConstraint(InformationSchema result, Table<?> t, String constraintName, TableConstraintType constraintType) {
TableConstraint tc = new TableConstraint();
String catalogName = catalogName(t);
String schemaName = schemaName(t);
tc.setConstraintName(constraintName);
tc.setConstraintType(constraintType);
if (!isBlank(catalogName))
tc.withConstraintCatalog(catalogName)
.withTableCatalog(catalogName);
if (!isBlank(schemaName))
tc.withConstraintSchema(schemaName)
.withTableSchema(schemaName);
tc.setTableName(t.getName());
result.getTableConstraints().add(tc);
}
private static final String catalogName(Schema s) {
return s.getCatalog() == null ? null : s.getCatalog().getName();
}
private static final String catalogName(Qualified q) {
return q.getCatalog() == null ? null : q.getCatalog().getName();
}
private static final String schemaName(Qualified q) {
return q.getSchema() == null ? null : q.getSchema().getName();
}
private InformationSchemaExport() {}
}