[jOOQ/jOOQ#10204] Refactor CatalogMetaImpl

- CatalogMetaImpl should use FilteredMeta
- SchemaMetaImpl and TableMetaImpl are no longer necessary
- [jOOQ/jOOQ#10274] [jOOQ/jOOQ#7172] Some equals methods were adapted
- Fixed check constraints and identities
- Create copies of PK and UK using Internal API
- Support FKs referencing UKs
- [jOOQ/jOOQ#10276] Don't export FKs pointing outside of a schema subset
This commit is contained in:
Lukas Eder 2020-06-12 15:51:11 +02:00
parent 27a1cc85ec
commit 9dce966193
13 changed files with 137 additions and 207 deletions

View File

@ -37,27 +37,30 @@
*/
package org.jooq.impl;
import static org.jooq.impl.Tools.EMPTY_CATALOG;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.jooq.Catalog;
import org.jooq.Configuration;
import org.jooq.Domain;
import org.jooq.Meta;
import org.jooq.Schema;
import org.jooq.Sequence;
import org.jooq.Table;
import org.jooq.UniqueKey;
/**
* @author Lukas Eder
*/
@SuppressWarnings("serial")
final class CatalogMetaImpl extends AbstractMeta {
private static final long serialVersionUID = 7582210274970452691L;
private final Catalog[] catalogs;
private static final long serialVersionUID = 7582210274970452691L;
private final Catalog[] catalogs;
CatalogMetaImpl(Configuration configuration, Catalog[] catalogs) {
private CatalogMetaImpl(Configuration configuration, Catalog[] catalogs) {
super(configuration);
this.catalogs = catalogs;
@ -68,59 +71,73 @@ final class CatalogMetaImpl extends AbstractMeta {
return Arrays.asList(catalogs);
}
@Override
final List<Schema> getSchemas0() {
List<Schema> result = new ArrayList<>();
for (Catalog catalog : catalogs)
result.addAll(catalog.getSchemas());
return result;
static final Meta filterCatalogs(Configuration configuration, Catalog[] catalogs) {
return filterCatalogs0(configuration, catalogs, new HashSet<>(Arrays.asList(catalogs)));
}
@Override
final List<Domain<?>> getDomains0() {
List<Domain<?>> result = new ArrayList<>();
for (Catalog catalog : catalogs)
for (Schema schema : catalog.getSchemas())
result.addAll(schema.getDomains());
return super.getDomains0();
static final Meta filterCatalogs(Configuration configuration, Set<Catalog> catalogs) {
return filterCatalogs0(configuration, catalogs.toArray(EMPTY_CATALOG), catalogs);
}
@Override
final List<Table<?>> getTables0() {
List<Table<?>> result = new ArrayList<>();
for (Catalog catalog : catalogs)
for (Schema schema : catalog.getSchemas())
result.addAll(schema.getTables());
return result;
private static final Meta filterCatalogs0(Configuration configuration, Catalog[] array, Set<Catalog> set) {
return new CatalogMetaImpl(configuration, array).filterCatalogs(new Predicate<Catalog>() {
@Override
public boolean test(Catalog catalog) {
return set.contains(catalog);
}
});
}
@Override
final List<Sequence<?>> getSequences0() {
List<Sequence<?>> result = new ArrayList<>();
for (Catalog catalog : catalogs)
for (Schema schema : catalog.getSchemas())
result.addAll(schema.getSequences());
return result;
static final Meta filterSchemas(Configuration configuration, Schema[] schemas) {
return filterSchemas(configuration, new HashSet<>(Arrays.asList(schemas)));
}
@Override
final List<UniqueKey<?>> getPrimaryKeys0() {
List<UniqueKey<?>> result = new ArrayList<>();
for (Catalog catalog : catalogs)
for (Schema schema : catalog.getSchemas())
for (Table<?> table : schema.getTables())
if (table.getPrimaryKey() != null)
result.add(table.getPrimaryKey());
static final Meta filterSchemas(Configuration configuration, Set<Schema> schemas) {
return result;
// TODO: Some schemas may belong to another catalog
Catalog defaultCatalog = new CatalogImpl("") {
@Override
public List<Schema> getSchemas() {
return new ArrayList<>(schemas);
}
};
Set<Catalog> c = new HashSet<>();
for (Schema schema : schemas)
c.add(schema.getCatalog() != null ? schema.getCatalog() : defaultCatalog);
return filterCatalogs(configuration, c).filterSchemas(new Predicate<Schema>() {
@Override
public boolean test(Schema schema) {
return schemas.contains(schema);
}
});
}
static final Meta filterTables(Configuration configuration, Table<?>[] tables) {
return filterTables(configuration, new HashSet<>(Arrays.asList(tables)));
}
static final Meta filterTables(Configuration configuration, Set<Table<?>> tables) {
// TODO: Some tables may belong to another schema
Schema defaultSchema = new SchemaImpl("") {
@Override
public List<Table<?>> getTables() {
return new ArrayList<Table<?>>(tables);
}
};
Set<Schema> s = new HashSet<>();
for (Table<?> table : tables)
s.add(table.getSchema() != null ? table.getSchema() : defaultSchema);
return filterSchemas(configuration, s).filterTables(new Predicate<Table<?>>() {
@Override
public boolean test(Table<?> table) {
return tables.contains(table);
}
});
}
}

View File

@ -60,6 +60,6 @@ public class CatalogMetaProvider implements MetaProvider {
@Override
public Meta provide() {
return new CatalogMetaImpl(configuration, catalogs);
return CatalogMetaImpl.filterCatalogs(configuration, catalogs);
}
}

View File

@ -197,7 +197,7 @@ final class DDL {
return s3.constraints(constraints);
}
private final Query createTable(Table<?> table) {
final Query createTable(Table<?> table) {
return createTable(table, constraints(table));
}

View File

@ -428,17 +428,17 @@ public class DefaultDSLContext extends AbstractScope implements DSLContext, Seri
@Override
public Meta meta(Catalog... catalogs) {
return new CatalogMetaImpl(configuration(), catalogs);
return CatalogMetaImpl.filterCatalogs(configuration(), catalogs);
}
@Override
public Meta meta(Schema... schemas) {
return new SchemaMetaImpl(configuration(), schemas);
return CatalogMetaImpl.filterSchemas(configuration(), schemas);
}
@Override
public Meta meta(Table<?>... tables) {
return new TableMetaImpl(configuration(), tables);
return CatalogMetaImpl.filterTables(configuration(), tables);
}
@Override

View File

@ -277,7 +277,9 @@ final class Diff {
private final Create<Table<?>> CREATE_TABLE = new Create<Table<?>>() {
@Override
public void create(DiffResult r, Table<?> t) {
r.queries.addAll(Arrays.asList(ctx.ddl(t, exportConf).queries()));
// [#10204] [#10276] DSLContext.ddl(Table) doesn't produce foreign keys
r.queries.addAll(Arrays.asList(ddl.queries(t).queries()));
}
};

View File

@ -42,9 +42,11 @@ import java.util.Collections;
import java.util.List;
import org.jooq.Catalog;
import org.jooq.Check;
import org.jooq.Domain;
import org.jooq.Field;
import org.jooq.ForeignKey;
import org.jooq.Identity;
import org.jooq.Index;
import org.jooq.Meta;
import org.jooq.QueryPart;
@ -319,10 +321,11 @@ final class FilteredMeta extends AbstractMeta {
private transient List<Index> indexes;
private transient List<UniqueKey<R>> keys;
private transient UniqueKey<R> primaryKey;
private transient Identity<R, ?> identity;
private transient List<ForeignKey<R, ?>> references;
private FilteredTable(FilteredSchema schema, Table<R> delegate) {
super(delegate.getQualifiedName(), schema, null, null, DSL.comment(delegate.getComment()));
super(delegate.getQualifiedName(), schema, null, null, DSL.comment(delegate.getComment()), delegate.getOptions());
this.delegate = delegate;
@ -344,22 +347,38 @@ final class FilteredMeta extends AbstractMeta {
}
@Override
@SuppressWarnings("unchecked")
public final List<UniqueKey<R>> getKeys() {
if (keys == null) {
keys = new ArrayList<>();
for (UniqueKey<R> key : delegate.getKeys())
keys.add(key);
keys.add(key(key));
UniqueKey<R> pk = delegate.getPrimaryKey();
if (pk != null)
if (primaryKeyFilter == null || primaryKeyFilter.test(pk))
primaryKey = pk;
primaryKey = key(pk);
Identity<R, ?> id = delegate.getIdentity();
if (id != null)
identity = Internal.createIdentity(this, (TableField<R, Object>) field(id.getField()));
}
return Collections.unmodifiableList(keys);
}
@SuppressWarnings("unchecked")
private final UniqueKey<R> key(UniqueKey<R> key) {
TableField<R, ?>[] fields1 = key.getFieldsArray();
TableField<R, ?>[] fields2 = new TableField[fields1.length];
for (int i = 0; i < fields2.length; i++)
fields2[i] = (TableField<R, ?>) field(fields1[i]);
return Internal.createUniqueKey(this, key.getName(), fields2, key.enforced());
}
@Override
public final UniqueKey<R> getPrimaryKey() {
getKeys();
@ -372,25 +391,44 @@ final class FilteredMeta extends AbstractMeta {
if (references == null) {
references = new ArrayList<>();
for (ForeignKey<R, ?> key : delegate.getReferences()) {
Table<?> table = lookupTable(key.getKey().getTable());
fkLoop:
for (ForeignKey<R, ?> fk : delegate.getReferences()) {
Table<?> table = lookupTable(fk.getKey().getTable());
// TODO: Support FKs referencing UKs
if (table != null && table.getPrimaryKey() != null) {
TableField<R, ?>[] fields1 = key.getFieldsArray();
TableField<R, ?>[] fields2 = new TableField[fields1.length];
if (table == null)
continue fkLoop;
for (int i = 0; i < fields2.length; i++)
fields2[i] = (TableField<R, ?>) field(fields1[i]);
UniqueKey<?> uk = null;
for (UniqueKey<?> k : table.getKeys())
if (k.equals(fk.getKey()))
uk = k;
references.add(Internal.createForeignKey(table.getPrimaryKey(), this, key.getName(), fields2));
}
if (uk == null)
continue fkLoop;
TableField<R, ?>[] fields1 = fk.getFieldsArray();
TableField<R, ?>[] fields2 = new TableField[fields1.length];
for (int i = 0; i < fields2.length; i++)
fields2[i] = (TableField<R, ?>) field(fields1[i]);
references.add(Internal.createForeignKey(uk, this, fk.getName(), fields2, fk.enforced()));
}
}
return Collections.unmodifiableList(references);
}
@Override
public final Identity<R, ?> getIdentity() {
return identity;
}
@Override
public final List<Check<R>> getChecks() {
return delegate.getChecks();
}
private final Table<?> lookupTable(Table<?> table) {
// TODO: This is a re-occurring pattern in Meta implementations. Should we have a more generic way to look up objects in a Catalog/Schema?

View File

@ -518,11 +518,6 @@ final class MigrationImpl extends AbstractScope implements Migration {
super(alias, null, aliased, parameters, DSL.comment("The migration log of jOOQ Migrations."));
}
@Override
public Schema getSchema() {
return new SchemaImpl("");
}
@Override
public Identity<JooqMigrationsChangelogRecord, Long> getIdentity() {
return Internal.createIdentity(JOOQ_MIGRATIONS_CHANGELOG, JOOQ_MIGRATIONS_CHANGELOG.ID);

View File

@ -1,126 +0,0 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Other licenses:
* -----------------------------------------------------------------------------
* Commercial licenses for this work are available. These replace the above
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
* database integrations.
*
* For more information, please visit: http://www.jooq.org/licenses
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package org.jooq.impl;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.jooq.Catalog;
import org.jooq.Configuration;
import org.jooq.Domain;
import org.jooq.Schema;
import org.jooq.Sequence;
import org.jooq.Table;
import org.jooq.UniqueKey;
/**
* @author Lukas Eder
*/
final class SchemaMetaImpl extends AbstractMeta {
private static final long serialVersionUID = -505810795492145873L;
private final Schema[] schemas;
SchemaMetaImpl(Configuration configuration, Schema[] schemas) {
super(configuration);
this.schemas = schemas;
}
@Override
final List<Catalog> getCatalogs0() {
Set<Catalog> result = new LinkedHashSet<>();
for (Schema schema : schemas)
if (schema.getCatalog() != null)
result.add(schema.getCatalog());
return new ArrayList<>(result);
}
@Override
final List<Schema> getSchemas0() {
return Collections.unmodifiableList(Arrays.asList(schemas));
}
@Override
final List<Domain<?>> getDomains0() {
List<Domain<?>> result = new ArrayList<>();
for (Schema schema : schemas)
result.addAll(schema.getDomains());
return result;
}
@Override
final List<Table<?>> getTables0() {
List<Table<?>> result = new ArrayList<>();
for (Schema schema : schemas)
result.addAll(schema.getTables());
return result;
}
@Override
final List<Sequence<?>> getSequences0() {
List<Sequence<?>> result = new ArrayList<>();
for (Schema schema : schemas)
result.addAll(schema.getSequences());
return result;
}
@Override
final List<UniqueKey<?>> getPrimaryKeys0() {
List<UniqueKey<?>> result = new ArrayList<>();
for (Schema schema : schemas)
for (Table<?> table : schema.getTables())
if (table.getPrimaryKey() != null)
result.add(table.getPrimaryKey());
return result;
}
}

View File

@ -60,6 +60,6 @@ public class SchemaMetaProvider implements MetaProvider {
@Override
public Meta provide() {
return new SchemaMetaImpl(configuration, schemas);
return CatalogMetaImpl.filterSchemas(configuration, schemas);
}
}

View File

@ -51,7 +51,6 @@ import org.jooq.Name;
import org.jooq.Record;
import org.jooq.Table;
import org.jooq.TableField;
import org.jooq.tools.StringUtils;
/**
* A common base type for table fields.
@ -112,9 +111,7 @@ final class TableFieldImpl<R extends Record, T> extends AbstractField<T> impleme
// rather expensive implementation of AbstractQueryPart.equals()
if (that instanceof TableField) {
TableField<?, ?> other = (TableField<?, ?>) that;
return
StringUtils.equals(getTable(), other.getTable()) &&
StringUtils.equals(getName(), other.getName());
return getQualifiedName().equals(other.getQualifiedName());
}
return super.equals(that);

View File

@ -364,7 +364,12 @@ public class TableImpl<R extends Record> extends AbstractTable<R> {
if (that instanceof TableImpl) {
TableImpl<?> other = (TableImpl<?>) that;
return
StringUtils.equals(getSchema(), other.getSchema()) &&
// [#7172] [#10274] Cannot use getQualifiedName() yet here
StringUtils.equals(
getSchema() == null ? "" : getSchema().getName(),
other.getSchema() == null ? "" : other.getSchema().getName()
) &&
StringUtils.equals(getName(), other.getName()) &&
Arrays.equals(parameters, other.parameters);
}

View File

@ -60,6 +60,6 @@ public class TableMetaProvider implements MetaProvider {
@Override
public Meta provide() {
return new TableMetaImpl(configuration, tables);
return CatalogMetaImpl.filterTables(configuration, tables);
}
}

View File

@ -299,6 +299,7 @@ final class Tools {
// ------------------------------------------------------------------------
static final byte[] EMPTY_BYTE = {};
static final Catalog[] EMPTY_CATALOG = {};
static final Check<?>[] EMPTY_CHECK = {};
static final Clause[] EMPTY_CLAUSE = {};
static final Collection<?>[] EMPTY_COLLECTION = {};
@ -313,6 +314,7 @@ final class Tools {
static final QueryPart[] EMPTY_QUERYPART = {};
static final Record[] EMPTY_RECORD = {};
static final Row[] EMPTY_ROW = {};
static final Schema[] EMTPY_SCHEMA = {};
static final SortField<?>[] EMPTY_SORTFIELD = {};
static final String[] EMPTY_STRING = {};
static final Table<?>[] EMPTY_TABLE = {};