All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jooq.impl.AbstractMeta Maven / Gradle / Ivy

There is a newer version: 3.19.15
Show newest version
/*
 * 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
 *
 *  https://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: https://www.jooq.org/legal/licensing
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */
package org.jooq.impl;

import static org.jooq.impl.DSL.name;
import static org.jooq.impl.Tools.findAny;
import static org.jooq.impl.Tools.flatMap;
import static org.jooq.impl.Tools.map;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;

import org.jooq.Catalog;
import org.jooq.Configuration;
import org.jooq.DDLExportConfiguration;
import org.jooq.Domain;
import org.jooq.ForeignKey;
import org.jooq.Index;
import org.jooq.Meta;
import org.jooq.Name;
import org.jooq.Named;
import org.jooq.Queries;
import org.jooq.Query;
import org.jooq.Record;
import org.jooq.Schema;
import org.jooq.Sequence;
import org.jooq.Table;
import org.jooq.TableField;
import org.jooq.UniqueKey;
import org.jooq.util.xml.jaxb.InformationSchema;

/**
 * @author Lukas Eder
 */
abstract class AbstractMeta extends AbstractScope implements Meta, Serializable {

    // [#9010] TODO: Allow for opting out of this cache
    private Map                cachedCatalogs;
    private Map                 cachedQualifiedSchemas;
    private Map>               cachedQualifiedTables;
    private Map>              cachedQualifiedDomains;
    private Map>            cachedQualifiedSequences;
    private Map>           cachedQualifiedPrimaryKeys;
    private Map>           cachedQualifiedUniqueKeys;
    private Map>       cachedQualifiedForeignKeys;
    private Map                  cachedQualifiedIndexes;
    private Map>           cachedUnqualifiedSchemas;
    private Map>>         cachedUnqualifiedTables;
    private Map>>        cachedUnqualifiedDomains;
    private Map>>      cachedUnqualifiedSequences;
    private Map>>     cachedUnqualifiedPrimaryKeys;
    private Map>>     cachedUnqualifiedUniqueKeys;
    private Map>> cachedUnqualifiedForeignKeys;
    private Map>            cachedUnqualifiedIndexes;

    AbstractMeta(Configuration configuration) {
        super(configuration);
    }

    @Override
    public final Catalog getCatalog(String name) {
        return getCatalog(name(name));
    }

    @Override
    public final Catalog getCatalog(Name name) {
        initCatalogs();
        return cachedCatalogs.get(name);
    }

    @Override
    public final List getCatalogs() {
        initCatalogs();
        return Collections.unmodifiableList(new ArrayList<>(cachedCatalogs.values()));
    }

    private final void initCatalogs() {
        if (cachedCatalogs == null) {
            cachedCatalogs = new LinkedHashMap<>();

            for (Catalog catalog : getCatalogs0())
                cachedCatalogs.put(catalog.getQualifiedName(), catalog);
        }
    }

    abstract List getCatalogs0();

    @Override
    public final List getSchemas(String name) {
        return getSchemas(name(name));
    }

    @Override
    public final List getSchemas(Name name) {
        initSchemas();
        return get(name, () -> getSchemas0().iterator(), cachedQualifiedSchemas, cachedUnqualifiedSchemas);
    }

    @Override
    public final List getSchemas() {
        initSchemas();
        return Collections.unmodifiableList(new ArrayList<>(cachedQualifiedSchemas.values()));
    }

    private final void initSchemas() {
        if (cachedQualifiedSchemas == null) {
            cachedQualifiedSchemas = new LinkedHashMap<>();
            cachedUnqualifiedSchemas = new LinkedHashMap<>();
            get(name(""), () -> getSchemas0().iterator(), cachedQualifiedSchemas, cachedUnqualifiedSchemas);
        }
    }

    List getSchemas0() {
        return flatMap(getCatalogs(), c -> c.getSchemas());
    }

    @Override
    public final List> getTables(String name) {
        return getTables(name(name));
    }

    @Override
    public final List> getTables(Name name) {
        initTables();
        return get(name, () -> getTables().iterator(), cachedQualifiedTables, cachedUnqualifiedTables);
    }

    @Override
    public final List> getTables() {
        initTables();
        return Collections.unmodifiableList(new ArrayList<>(cachedQualifiedTables.values()));
    }

    private final void initTables() {
        if (cachedQualifiedTables == null) {
            cachedQualifiedTables = new LinkedHashMap<>();
            cachedUnqualifiedTables = new LinkedHashMap<>();
            get(name(""), () -> getTables0().iterator(), cachedQualifiedTables, cachedUnqualifiedTables);
        }
    }

    List> getTables0() {
        return flatMap(getSchemas(), s -> s.getTables());
    }

    @Override
    public final List> getDomains(String name) {
        return getDomains(name(name));
    }

    @Override
    public final List> getDomains(Name name) {
        initDomains();
        return get(name, () -> getDomains().iterator(), cachedQualifiedDomains, cachedUnqualifiedDomains);
    }

    @Override
    public final List> getDomains() {
        initDomains();
        return Collections.unmodifiableList(new ArrayList<>(cachedQualifiedDomains.values()));
    }

    private final void initDomains() {
        if (cachedQualifiedDomains == null) {
            cachedQualifiedDomains = new LinkedHashMap<>();
            cachedUnqualifiedDomains = new LinkedHashMap<>();
            get(name(""), () -> getDomains0().iterator(), cachedQualifiedDomains, cachedUnqualifiedDomains);
        }
    }

    List> getDomains0() {
        return flatMap(getSchemas(), s -> s.getDomains());
    }

    @Override
    public final List> getSequences(String name) {
        return getSequences(name(name));
    }

    @Override
    public final List> getSequences(Name name) {
        initSequences();
        return get(name, () -> getSequences().iterator(), cachedQualifiedSequences, cachedUnqualifiedSequences);
    }

    @Override
    public final List> getSequences() {
        initSequences();
        return Collections.unmodifiableList(new ArrayList<>(cachedQualifiedSequences.values()));
    }

    private final void initSequences() {
        if (cachedQualifiedSequences == null) {
            cachedQualifiedSequences = new LinkedHashMap<>();
            cachedUnqualifiedSequences = new LinkedHashMap<>();
            get(name(""), () -> getSequences0().iterator(), cachedQualifiedSequences, cachedUnqualifiedSequences);
        }
    }

    final List> getSequences0() {
        return flatMap(getSchemas(), s -> s.getSequences());
    }

    @Override
    public final List> getPrimaryKeys(String name) {
        return getPrimaryKeys(name(name));
    }

    @Override
    public final List> getPrimaryKeys(Name name) {
        initPrimaryKeys();
        return get(name, () -> getPrimaryKeys().iterator(), cachedQualifiedPrimaryKeys, cachedUnqualifiedPrimaryKeys);
    }

    @Override
    public final List> getPrimaryKeys() {
        initPrimaryKeys();
        return Collections.unmodifiableList(new ArrayList<>(cachedQualifiedPrimaryKeys.values()));
    }

    private final void initPrimaryKeys() {
        if (cachedQualifiedPrimaryKeys == null) {
            cachedQualifiedPrimaryKeys = new LinkedHashMap<>();
            cachedUnqualifiedPrimaryKeys = new LinkedHashMap<>();
            get(name(""), () -> getPrimaryKeys0().iterator(), cachedQualifiedPrimaryKeys, cachedUnqualifiedPrimaryKeys);
        }
    }

    List> getPrimaryKeys0() {
        List> result = new ArrayList<>();

        for (Table table : getTables())
            if (table.getPrimaryKey() != null)
                result.add(table.getPrimaryKey());

        return result;
    }

    @Override
    public final List> getUniqueKeys(String name) {
        return getUniqueKeys(name(name));
    }

    @Override
    public final List> getUniqueKeys(Name name) {
        initUniqueKeys();
        return get(name, () -> getUniqueKeys().iterator(), cachedQualifiedUniqueKeys, cachedUnqualifiedUniqueKeys);
    }

    @Override
    public final List> getUniqueKeys() {
        initUniqueKeys();
        return Collections.unmodifiableList(new ArrayList<>(cachedQualifiedUniqueKeys.values()));
    }

    private final void initUniqueKeys() {
        if (cachedQualifiedUniqueKeys == null) {
            cachedQualifiedUniqueKeys = new LinkedHashMap<>();
            cachedUnqualifiedUniqueKeys = new LinkedHashMap<>();
            get(name(""), () -> getUniqueKeys0().iterator(), cachedQualifiedUniqueKeys, cachedUnqualifiedUniqueKeys);
        }
    }

    List> getUniqueKeys0() {
        return flatMap(getTables(), t -> t.getUniqueKeys());
    }

    @Override
    public final List> getForeignKeys(String name) {
        return getForeignKeys(name(name));
    }

    @Override
    public final List> getForeignKeys(Name name) {
        initForeignKeys();
        return get(name, () -> getForeignKeys().iterator(), cachedQualifiedForeignKeys, cachedUnqualifiedForeignKeys);
    }

    @Override
    public final List> getForeignKeys() {
        initForeignKeys();
        return Collections.unmodifiableList(new ArrayList<>(cachedQualifiedForeignKeys.values()));
    }

    private final void initForeignKeys() {
        if (cachedQualifiedForeignKeys == null) {
            cachedQualifiedForeignKeys = new LinkedHashMap<>();
            cachedUnqualifiedForeignKeys = new LinkedHashMap<>();
            get(name(""), () -> getForeignKeys0().iterator(), cachedQualifiedForeignKeys, cachedUnqualifiedForeignKeys);
        }
    }

    List> getForeignKeys0() {
        return flatMap(getTables(), (Table t) -> t.getReferences());
    }

    @Override
    public final List getIndexes(String name) {
        return getIndexes(name(name));
    }

    @Override
    public final List getIndexes(Name name) {
        initIndexes();
        return get(name, () -> getIndexes().iterator(), cachedQualifiedIndexes, cachedUnqualifiedIndexes);
    }

    @Override
    public final List getIndexes() {
        initIndexes();
        return Collections.unmodifiableList(new ArrayList<>(cachedQualifiedIndexes.values()));
    }

    private final void initIndexes() {
        if (cachedQualifiedIndexes == null) {
            cachedQualifiedIndexes = new LinkedHashMap<>();
            cachedUnqualifiedIndexes = new LinkedHashMap<>();
            get(name(""), () -> getIndexes0().iterator(), cachedQualifiedIndexes, cachedUnqualifiedIndexes);
        }
    }

    List getIndexes0() {
        return flatMap(getTables(), t -> t.getIndexes());
    }

    private final  List get(Name name, Iterable i, Map qualified, Map> unqualified) {
        if (qualified.isEmpty()) {
            for (T object : i) {
                Name q = object.getQualifiedName();
                Name u = object.getUnqualifiedName();

                qualified.put(q, object);
                unqualified.computeIfAbsent(u, n -> new ArrayList<>()).add(object);
            }
        }

        T object = qualified.get(name);
        if (object != null)
            return Collections.singletonList(object);

        List list = unqualified.get(name);
        if (list == null)
            return Collections.emptyList();
        else
            return Collections.unmodifiableList(list);
    }

    @Override
    public Meta filterCatalogs(Predicate filter) {
        return new FilteredMeta(
            this,
            filter,
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            null
        );
    }

    @Override
    public Meta filterSchemas(Predicate filter) {
        return new FilteredMeta(
            this,
            null,
            filter,
            null,
            null,
            null,
            null,
            null,
            null,
            null
        );
    }

    @Override
    public Meta filterTables(Predicate> filter) {
        return new FilteredMeta(
            this,
            null,
            null,
            filter,
            null,
            null,
            null,
            null,
            null,
            null
        );
    }

    @Override
    public Meta filterDomains(Predicate> filter) {
        return new FilteredMeta(
            this,
            null,
            null,
            null,
            filter,
            null,
            null,
            null,
            null,
            null
        );
    }

    @Override
    public Meta filterSequences(Predicate> filter) {
        return new FilteredMeta(
            this,
            null,
            null,
            null,
            null,
            filter,
            null,
            null,
            null,
            null
        );
    }

    @Override
    public Meta filterPrimaryKeys(Predicate> filter) {
        return new FilteredMeta(
            this,
            null,
            null,
            null,
            null,
            null,
            filter,
            null,
            null,
            null
        );
    }

    @Override
    public Meta filterUniqueKeys(Predicate> filter) {
        return new FilteredMeta(
            this,
            null,
            null,
            null,
            null,
            null,
            null,
            filter,
            null,
            null
        );
    }

    @Override
    public Meta filterForeignKeys(Predicate> filter) {
        return new FilteredMeta(
            this,
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            filter,
            null
        );
    }

    @Override
    public Meta filterIndexes(Predicate filter) {
        return new FilteredMeta(
            this,
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            filter
        );
    }

    @Override
    public final Meta snapshot() {
        return new Snapshot(this);
    }

    @Override
    public final Queries ddl() {
        return ddl(new DDLExportConfiguration());
    }

    // [#9396] TODO Fix this. Subclasses should not need to override this to get
    //         correct results
    @Override
    public /* non-final */ Queries ddl(DDLExportConfiguration exportConfiguration) {
        return new DDL(dsl(), exportConfiguration).queries(this);
    }

    @Override
    public final Meta apply(String migration) {
        return apply(dsl().parser().parse(migration));
    }

    @Override
    public final Meta apply(Query... migration) {
        return apply(dsl().queries(migration));
    }

    @Override
    public final Meta apply(Collection migration) {
        return apply(dsl().queries(migration));
    }

    @Override
    public final Meta apply(Queries migration) {
        return dsl().meta(ddl().concat(migration).queries());
    }

    @Override
    public final Queries migrateTo(Meta other) {
        return migrateTo(other, new org.jooq.MigrationConfiguration());
    }

    @Override
    public final Queries migrateTo(Meta other, org.jooq.MigrationConfiguration c) {
        return new Diff(configuration(), c, this, other).queries();
    }

    // [#9396] TODO Fix this. Subclasses should not need to override this to get
    //         correct results
    @Override
    public /* non-final */ InformationSchema informationSchema() {
        return InformationSchemaExport.exportCatalogs(configuration(), getCatalogs());
    }

    final Table lookupTable(Table table) {
        Catalog c = table.getCatalog();
        Schema s = table.getSchema();

        // 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?
        Catalog catalog = getCatalog(c == null ? "" : c.getName());
        if (catalog == null)
            return null;

        Schema schema = catalog.getSchema(s == null ? "" : s.getName());
        if (schema == null)
            return null;

        return schema.getTable(table.getName());
    }

    final  UniqueKey lookupKey(Table in, UniqueKey uk) {
        Set ukFields = new HashSet<>(uk.getFields());

        // [#10279] [#10281] Cannot use Key::equals here, because that is
        // name-based. 1) The name is irrelevant for this lookup, 2) some
        // key implementations (e.g. MetaPrimaryKey for H2) don't produce
        // the correct key name, but the index name.
        // [#11258] Also, we need position agnostic comparison, using sets
        return Tools.findAny(in.getKeys(), k -> ukFields.equals(new HashSet<>(k.getFields())));
    }

    final UniqueKey lookupUniqueKey(ForeignKey fk) {
        Table table = lookupTable(fk.getKey().getTable());

        if (table == null)
            return null;

        return lookupKey(table, fk.getKey());
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    static final  ForeignKey copyFK(Table fkTable, UniqueKey uk, ForeignKey oldFk) {
        Table ukTable = uk.getTable();

        return Internal.createForeignKey(
            fkTable,
            oldFk.getQualifiedName(),
            map(oldFk.getFieldsArray(), f -> (TableField) fkTable.field(f), TableField[]::new),
            uk,
            map(oldFk.getKeyFieldsArray(), f -> (TableField) ukTable.field(f), TableField[]::new),
            oldFk.enforced()
        );
    }

    @Override
    public int hashCode() {
        return ddl().hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Meta m)
            return ddl().equals(m.ddl());

        return false;
    }

    @Override
    public String toString() {
        return ddl().toString();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy