[jOOQ/jOOQ#9425] Add Meta.diff(Meta) WIP
This commit is contained in:
parent
a94ae56491
commit
dca2b4b6e3
@ -219,6 +219,14 @@ public interface Meta extends Scope {
|
||||
*/
|
||||
Queries ddl(DDLExportConfiguration configuration) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Generate a migration script to get from this meta data to another one.
|
||||
*
|
||||
* @throws DataAccessException If something went wrong fetching the meta
|
||||
* objects
|
||||
*/
|
||||
Queries diff(Meta other) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Export to the {@link InformationSchema} format.
|
||||
* <p>
|
||||
|
||||
@ -58,7 +58,6 @@ import org.jooq.Schema;
|
||||
import org.jooq.Sequence;
|
||||
import org.jooq.Table;
|
||||
import org.jooq.UniqueKey;
|
||||
import org.jooq.exception.DataAccessException;
|
||||
import org.jooq.util.xml.jaxb.InformationSchema;
|
||||
|
||||
/**
|
||||
@ -95,7 +94,7 @@ abstract class AbstractMeta extends AbstractScope implements Meta, Serializable
|
||||
}
|
||||
|
||||
@Override
|
||||
public final List<Catalog> getCatalogs() throws DataAccessException {
|
||||
public final List<Catalog> getCatalogs() {
|
||||
initCatalogs();
|
||||
return Collections.unmodifiableList(new ArrayList<>(cachedCatalogs.values()));
|
||||
}
|
||||
@ -108,7 +107,7 @@ abstract class AbstractMeta extends AbstractScope implements Meta, Serializable
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract List<Catalog> getCatalogs0() throws DataAccessException;
|
||||
protected abstract List<Catalog> getCatalogs0();
|
||||
|
||||
@Override
|
||||
public final List<Schema> getSchemas(String name) {
|
||||
@ -127,7 +126,7 @@ abstract class AbstractMeta extends AbstractScope implements Meta, Serializable
|
||||
}
|
||||
|
||||
@Override
|
||||
public final List<Schema> getSchemas() throws DataAccessException {
|
||||
public final List<Schema> getSchemas() {
|
||||
initSchemas();
|
||||
return Collections.unmodifiableList(new ArrayList<>(cachedQualifiedSchemas.values()));
|
||||
}
|
||||
@ -145,7 +144,7 @@ abstract class AbstractMeta extends AbstractScope implements Meta, Serializable
|
||||
}
|
||||
}
|
||||
|
||||
protected List<Schema> getSchemas0() throws DataAccessException {
|
||||
protected List<Schema> getSchemas0() {
|
||||
List<Schema> result = new ArrayList<>();
|
||||
for (Catalog catalog : getCatalogs())
|
||||
result.addAll(catalog.getSchemas());
|
||||
@ -169,7 +168,7 @@ abstract class AbstractMeta extends AbstractScope implements Meta, Serializable
|
||||
}
|
||||
|
||||
@Override
|
||||
public final List<Table<?>> getTables() throws DataAccessException {
|
||||
public final List<Table<?>> getTables() {
|
||||
initTables();
|
||||
return Collections.unmodifiableList(new ArrayList<>(cachedQualifiedTables.values()));
|
||||
}
|
||||
@ -187,7 +186,7 @@ abstract class AbstractMeta extends AbstractScope implements Meta, Serializable
|
||||
}
|
||||
}
|
||||
|
||||
protected List<Table<?>> getTables0() throws DataAccessException {
|
||||
protected List<Table<?>> getTables0() {
|
||||
List<Table<?>> result = new ArrayList<>();
|
||||
for (Schema schema : getSchemas())
|
||||
result.addAll(schema.getTables());
|
||||
@ -211,7 +210,7 @@ abstract class AbstractMeta extends AbstractScope implements Meta, Serializable
|
||||
}
|
||||
|
||||
@Override
|
||||
public final List<Sequence<?>> getSequences() throws DataAccessException {
|
||||
public final List<Sequence<?>> getSequences() {
|
||||
initSequences();
|
||||
return Collections.unmodifiableList(new ArrayList<>(cachedQualifiedSequences.values()));
|
||||
}
|
||||
@ -229,7 +228,7 @@ abstract class AbstractMeta extends AbstractScope implements Meta, Serializable
|
||||
}
|
||||
}
|
||||
|
||||
protected List<Sequence<?>> getSequences0() throws DataAccessException {
|
||||
protected List<Sequence<?>> getSequences0() {
|
||||
List<Sequence<?>> result = new ArrayList<>();
|
||||
for (Schema schema : getSchemas())
|
||||
result.addAll(schema.getSequences());
|
||||
@ -237,7 +236,7 @@ abstract class AbstractMeta extends AbstractScope implements Meta, Serializable
|
||||
}
|
||||
|
||||
@Override
|
||||
public final List<UniqueKey<?>> getPrimaryKeys() throws DataAccessException {
|
||||
public final List<UniqueKey<?>> getPrimaryKeys() {
|
||||
initPrimaryKeys();
|
||||
return Collections.unmodifiableList(cachedPrimaryKeys);
|
||||
}
|
||||
@ -247,7 +246,7 @@ abstract class AbstractMeta extends AbstractScope implements Meta, Serializable
|
||||
cachedPrimaryKeys = new ArrayList<>(getPrimaryKeys0());
|
||||
}
|
||||
|
||||
protected List<UniqueKey<?>> getPrimaryKeys0() throws DataAccessException {
|
||||
protected List<UniqueKey<?>> getPrimaryKeys0() {
|
||||
List<UniqueKey<?>> result = new ArrayList<>();
|
||||
for (Table<?> table : getTables())
|
||||
if (table.getPrimaryKey() != null)
|
||||
@ -285,21 +284,26 @@ abstract class AbstractMeta extends AbstractScope implements Meta, Serializable
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Queries ddl() throws DataAccessException {
|
||||
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) throws DataAccessException {
|
||||
public /* non-final */ Queries ddl(DDLExportConfiguration exportConfiguration) {
|
||||
return new DDL(this, exportConfiguration).queries();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Queries diff(Meta other) {
|
||||
return new Diff(configuration(), this, other).queries();
|
||||
}
|
||||
|
||||
// [#9396] TODO Fix this. Subclasses should not need to override this to get
|
||||
// correct results
|
||||
@Override
|
||||
public /* non-final */ InformationSchema informationSchema() throws DataAccessException {
|
||||
public /* non-final */ InformationSchema informationSchema() {
|
||||
return InformationSchemaExport.exportCatalogs(configuration(), getCatalogs());
|
||||
}
|
||||
}
|
||||
|
||||
229
jOOQ/src/main/java/org/jooq/impl/Diff.java
Normal file
229
jOOQ/src/main/java/org/jooq/impl/Diff.java
Normal file
@ -0,0 +1,229 @@
|
||||
/*
|
||||
* 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.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.jooq.Catalog;
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.DSLContext;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.Meta;
|
||||
import org.jooq.Named;
|
||||
import org.jooq.Queries;
|
||||
import org.jooq.Query;
|
||||
import org.jooq.Schema;
|
||||
import org.jooq.Table;
|
||||
|
||||
/**
|
||||
* A class producing a diff between two {@link Meta} objects.
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class Diff {
|
||||
|
||||
private static final NamedComparator COMP = new NamedComparator();
|
||||
private final DSLContext ctx;
|
||||
private final Meta meta1;
|
||||
private final Meta meta2;
|
||||
|
||||
Diff(Configuration configuration, Meta meta1, Meta meta2) {
|
||||
this.ctx = configuration.dsl();
|
||||
this.meta1 = meta1;
|
||||
this.meta2 = meta2;
|
||||
}
|
||||
|
||||
final Queries queries() {
|
||||
return ctx.queries(appendCatalogs(new ArrayList<>(), sorted(meta1.getCatalogs()), sorted(meta2.getCatalogs())));
|
||||
}
|
||||
|
||||
private final List<Query> appendCatalogs(final List<Query> queries, final Iterator<Catalog> i1, final Iterator<Catalog> i2) {
|
||||
return append(queries, i1, i2,
|
||||
null,
|
||||
null,
|
||||
new Merge<Catalog>() {
|
||||
@Override
|
||||
public void merge(List<Query> q, Catalog c1, Catalog c2) {
|
||||
appendSchemas(q, sorted(c1.getSchemas()), sorted(c2.getSchemas()));
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private final List<Query> appendSchemas(final List<Query> queries, final Iterator<Schema> i1, final Iterator<Schema> i2) {
|
||||
// TODO Cascade semantics when creating and deleting
|
||||
return append(queries, i1, i2,
|
||||
new Create<Schema>() {
|
||||
@Override
|
||||
public void create(List<Query> q, Schema s) {
|
||||
q.add(ctx.createSchema(s));
|
||||
}
|
||||
},
|
||||
new Drop<Schema>() {
|
||||
@Override
|
||||
public void drop(List<Query> q, Schema s) {
|
||||
q.add(ctx.dropSchema(s));
|
||||
}
|
||||
},
|
||||
new Merge<Schema>() {
|
||||
@Override
|
||||
public void merge(List<Query> q, Schema s1, Schema s2) {
|
||||
appendTables(q, sorted(s1.getTables()), sorted(s2.getTables()));
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private final List<Query> appendTables(final List<Query> queries, final Iterator<Table<?>> i1, final Iterator<Table<?>> i2) {
|
||||
// TODO Cascade semantics when creating and deleting
|
||||
return append(queries, i1, i2,
|
||||
new Create<Table<?>>() {
|
||||
@Override
|
||||
public void create(List<Query> q, Table<?> t) {
|
||||
q.addAll(Arrays.asList(ctx.ddl(t).queries()));
|
||||
}
|
||||
},
|
||||
new Drop<Table<?>>() {
|
||||
@Override
|
||||
public void drop(List<Query> q, Table<?> t) {
|
||||
q.add(ctx.dropTable(t));
|
||||
}
|
||||
},
|
||||
new Merge<Table<?>>() {
|
||||
@Override
|
||||
public void merge(List<Query> q, Table<?> t1, Table<?> t2) {
|
||||
appendColumns(queries, t1, t2, sorted(t1.fields()), sorted(t2.fields()));
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private final List<Query> appendColumns(final List<Query> queries, final Table<?> t1, final Table<?> t2, final Iterator<Field<?>> i1, final Iterator<Field<?>> i2) {
|
||||
return append(queries, i1, i2,
|
||||
(q, f) -> q.add(ctx.alterTable(t1).add(f)),
|
||||
(q, f) -> q.add(ctx.alterTable(t1).drop(f)),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
private final <N extends Named> List<Query> append(
|
||||
List<Query> queries,
|
||||
Iterator<N> i1,
|
||||
Iterator<N> i2,
|
||||
Create<N> create,
|
||||
Drop<N> drop,
|
||||
Merge<N> merge
|
||||
) {
|
||||
N s1 = null;
|
||||
N s2 = null;
|
||||
|
||||
for (;;) {
|
||||
if (s1 == null && i1.hasNext())
|
||||
s1 = i1.next();
|
||||
|
||||
if (s2 == null && i2.hasNext())
|
||||
s2 = i2.next();
|
||||
|
||||
if (s1 == null && s2 == null)
|
||||
break;
|
||||
|
||||
int comp = s1 == null
|
||||
? 1
|
||||
: s2 == null
|
||||
? -1
|
||||
: s1.getQualifiedName().compareTo(s2.getQualifiedName());
|
||||
|
||||
if (comp < 0) {
|
||||
if (drop != null)
|
||||
drop.drop(queries, s1);
|
||||
|
||||
s1 = null;
|
||||
}
|
||||
else if (comp > 0) {
|
||||
if (create != null)
|
||||
create.create(queries, s2);
|
||||
|
||||
s2 = null;
|
||||
}
|
||||
else {
|
||||
if (merge != null)
|
||||
merge.merge(queries, s1, s2);
|
||||
|
||||
s1 = s2 = null;
|
||||
}
|
||||
}
|
||||
|
||||
return queries;
|
||||
}
|
||||
|
||||
private static interface Create<N extends Named> {
|
||||
void create(List<Query> queries, N named);
|
||||
}
|
||||
|
||||
private static interface Drop<N extends Named> {
|
||||
void drop(List<Query> queries, N named);
|
||||
}
|
||||
|
||||
private static interface Merge<N extends Named> {
|
||||
void merge(List<Query> queries, N named1, N named2);
|
||||
}
|
||||
|
||||
private static final <N extends Named> Iterator<N> sorted(N... array) {
|
||||
List<N> result = Arrays.asList(array);
|
||||
Collections.sort(result, COMP);
|
||||
return result.iterator();
|
||||
}
|
||||
|
||||
private static final <N extends Named> Iterator<N> sorted(List<N> list) {
|
||||
List<N> result = new ArrayList<>(list);
|
||||
Collections.sort(result, COMP);
|
||||
return result.iterator();
|
||||
}
|
||||
|
||||
private static final class NamedComparator implements Comparator<Named> {
|
||||
@Override
|
||||
public int compare(Named o1, Named o2) {
|
||||
return o1.getQualifiedName().compareTo(o2.getQualifiedName());
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user