[jOOQ/jOOQ#9677] Add Settings.interpreterSearchPath
This commit is contained in:
parent
37b11143f5
commit
c33cd0bd8d
@ -37,7 +37,8 @@
|
||||
*/
|
||||
package org.jooq;
|
||||
|
||||
import org.jooq.exception.DataDefinitionException;
|
||||
import org.jooq.exception.DataMigrationException;
|
||||
import org.jooq.exception.DataMigrationValidationException;
|
||||
|
||||
/**
|
||||
* An executable migration between two {@link Version} instances.
|
||||
@ -61,11 +62,26 @@ public interface Migration extends Scope {
|
||||
*/
|
||||
Queries queries();
|
||||
|
||||
/**
|
||||
* Validate a migration.
|
||||
*
|
||||
* @throws DataMigrationValidationException When something went wrong during
|
||||
* the validation of the migration.
|
||||
*/
|
||||
void validate() throws DataMigrationValidationException;
|
||||
|
||||
/**
|
||||
* Apply the migration.
|
||||
*
|
||||
* @throws DataDefinitionException When something went wrong during the
|
||||
* @throws DataMigrationException When something went wrong during the
|
||||
* application of the migration.
|
||||
*/
|
||||
MigrationResult execute() throws DataDefinitionException;
|
||||
MigrationResult execute() throws DataMigrationException;
|
||||
|
||||
/**
|
||||
* The result of a {@link Migration} execution.
|
||||
*/
|
||||
public interface MigrationResult {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
141
jOOQ/src/main/java/org/jooq/conf/InterpreterSearchSchema.java
Normal file
141
jOOQ/src/main/java/org/jooq/conf/InterpreterSearchSchema.java
Normal file
@ -0,0 +1,141 @@
|
||||
|
||||
package org.jooq.conf;
|
||||
|
||||
import java.io.Serializable;
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
import org.jooq.util.jaxb.tools.XMLAppendable;
|
||||
import org.jooq.util.jaxb.tools.XMLBuilder;
|
||||
|
||||
|
||||
/**
|
||||
* A schema that is on the search path.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(name = "InterpreterSearchSchema", propOrder = {
|
||||
|
||||
})
|
||||
@SuppressWarnings({
|
||||
"all"
|
||||
})
|
||||
public class InterpreterSearchSchema
|
||||
extends SettingsBase
|
||||
implements Serializable, Cloneable, XMLAppendable
|
||||
{
|
||||
|
||||
private final static long serialVersionUID = 31200L;
|
||||
protected String catalog;
|
||||
@XmlElement(required = true)
|
||||
protected String schema;
|
||||
|
||||
/**
|
||||
* The catalog qualifier of the schema, if applicable.
|
||||
*
|
||||
*/
|
||||
public String getCatalog() {
|
||||
return catalog;
|
||||
}
|
||||
|
||||
/**
|
||||
* The catalog qualifier of the schema, if applicable.
|
||||
*
|
||||
*/
|
||||
public void setCatalog(String value) {
|
||||
this.catalog = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* The schema qualifier whose elements can be found from the search path.
|
||||
*
|
||||
*/
|
||||
public String getSchema() {
|
||||
return schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* The schema qualifier whose elements can be found from the search path.
|
||||
*
|
||||
*/
|
||||
public void setSchema(String value) {
|
||||
this.schema = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* The catalog qualifier of the schema, if applicable.
|
||||
*
|
||||
*/
|
||||
public InterpreterSearchSchema withCatalog(String value) {
|
||||
setCatalog(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The schema qualifier whose elements can be found from the search path.
|
||||
*
|
||||
*/
|
||||
public InterpreterSearchSchema withSchema(String value) {
|
||||
setSchema(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void appendTo(XMLBuilder builder) {
|
||||
builder.append("catalog", catalog);
|
||||
builder.append("schema", schema);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
XMLBuilder builder = XMLBuilder.nonFormatting();
|
||||
appendTo(builder);
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object that) {
|
||||
if (this == that) {
|
||||
return true;
|
||||
}
|
||||
if (that == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass()!= that.getClass()) {
|
||||
return false;
|
||||
}
|
||||
InterpreterSearchSchema other = ((InterpreterSearchSchema) that);
|
||||
if (catalog == null) {
|
||||
if (other.catalog!= null) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!catalog.equals(other.catalog)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (schema == null) {
|
||||
if (other.schema!= null) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!schema.equals(other.schema)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = ((prime*result)+((catalog == null)? 0 :catalog.hashCode()));
|
||||
result = ((prime*result)+((schema == null)? 0 :schema.hashCode()));
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@ -49,6 +49,14 @@ public class ObjectFactory {
|
||||
return new ParseSearchSchema();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link InterpreterSearchSchema }
|
||||
*
|
||||
*/
|
||||
public InterpreterSearchSchema createInterpreterSearchSchema() {
|
||||
return new InterpreterSearchSchema();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link RenderMapping }
|
||||
*
|
||||
|
||||
@ -196,6 +196,8 @@ public class Settings
|
||||
@XmlElement(type = String.class)
|
||||
@XmlJavaTypeAdapter(LocaleAdapter.class)
|
||||
protected Locale interpreterLocale;
|
||||
@XmlElement(defaultValue = "true")
|
||||
protected Boolean migrationAutoValidation = true;
|
||||
@XmlElement(type = String.class)
|
||||
@XmlJavaTypeAdapter(LocaleAdapter.class)
|
||||
protected Locale locale;
|
||||
@ -223,6 +225,9 @@ public class Settings
|
||||
protected String parseIgnoreCommentStart = "[jooq ignore start]";
|
||||
@XmlElement(defaultValue = "[jooq ignore stop]")
|
||||
protected String parseIgnoreCommentStop = "[jooq ignore stop]";
|
||||
@XmlElementWrapper(name = "interpreterSearchPath")
|
||||
@XmlElement(name = "schema")
|
||||
protected List<InterpreterSearchSchema> interpreterSearchPath;
|
||||
@XmlElementWrapper(name = "parseSearchPath")
|
||||
@XmlElement(name = "schema")
|
||||
protected List<ParseSearchSchema> parseSearchPath;
|
||||
@ -1654,6 +1659,30 @@ public class Settings
|
||||
this.interpreterLocale = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a migration automatically runs a validation first.
|
||||
*
|
||||
* @return
|
||||
* possible object is
|
||||
* {@link Boolean }
|
||||
*
|
||||
*/
|
||||
public Boolean isMigrationAutoValidation() {
|
||||
return migrationAutoValidation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the migrationAutoValidation property.
|
||||
*
|
||||
* @param value
|
||||
* allowed object is
|
||||
* {@link Boolean }
|
||||
*
|
||||
*/
|
||||
public void setMigrationAutoValidation(Boolean value) {
|
||||
this.migrationAutoValidation = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Locale to be used with any locale dependent logic if there is not a more specific locale available. More specific locales include e.g. {@link #getRenderLocale()}, {@link #getParseLocale()}, or {@link #getInterpreterLocale()}.
|
||||
*
|
||||
@ -1822,6 +1851,17 @@ public class Settings
|
||||
this.parseIgnoreCommentStop = value;
|
||||
}
|
||||
|
||||
public List<InterpreterSearchSchema> getInterpreterSearchPath() {
|
||||
if (interpreterSearchPath == null) {
|
||||
interpreterSearchPath = new ArrayList<InterpreterSearchSchema>();
|
||||
}
|
||||
return interpreterSearchPath;
|
||||
}
|
||||
|
||||
public void setInterpreterSearchPath(List<InterpreterSearchSchema> interpreterSearchPath) {
|
||||
this.interpreterSearchPath = interpreterSearchPath;
|
||||
}
|
||||
|
||||
public List<ParseSearchSchema> getParseSearchPath() {
|
||||
if (parseSearchPath == null) {
|
||||
parseSearchPath = new ArrayList<ParseSearchSchema>();
|
||||
@ -2367,6 +2407,11 @@ public class Settings
|
||||
return this;
|
||||
}
|
||||
|
||||
public Settings withMigrationAutoValidation(Boolean value) {
|
||||
setMigrationAutoValidation(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Locale to be used with any locale dependent logic if there is not a more specific locale available. More specific locales include e.g. {@link #getRenderLocale()}, {@link #getParseLocale()}, or {@link #getInterpreterLocale()}.
|
||||
*
|
||||
@ -2453,6 +2498,27 @@ public class Settings
|
||||
return this;
|
||||
}
|
||||
|
||||
public Settings withInterpreterSearchPath(InterpreterSearchSchema... values) {
|
||||
if (values!= null) {
|
||||
for (InterpreterSearchSchema value: values) {
|
||||
getInterpreterSearchPath().add(value);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Settings withInterpreterSearchPath(Collection<InterpreterSearchSchema> values) {
|
||||
if (values!= null) {
|
||||
getInterpreterSearchPath().addAll(values);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Settings withInterpreterSearchPath(List<InterpreterSearchSchema> interpreterSearchPath) {
|
||||
setInterpreterSearchPath(interpreterSearchPath);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Settings withParseSearchPath(ParseSearchSchema... values) {
|
||||
if (values!= null) {
|
||||
for (ParseSearchSchema value: values) {
|
||||
@ -2542,6 +2608,7 @@ public class Settings
|
||||
builder.append("interpreterDialect", interpreterDialect);
|
||||
builder.append("interpreterNameLookupCaseSensitivity", interpreterNameLookupCaseSensitivity);
|
||||
builder.append("interpreterLocale", interpreterLocale);
|
||||
builder.append("migrationAutoValidation", migrationAutoValidation);
|
||||
builder.append("locale", locale);
|
||||
builder.append("parseDialect", parseDialect);
|
||||
builder.append("parseLocale", parseLocale);
|
||||
@ -2552,6 +2619,7 @@ public class Settings
|
||||
builder.append("parseIgnoreComments", parseIgnoreComments);
|
||||
builder.append("parseIgnoreCommentStart", parseIgnoreCommentStart);
|
||||
builder.append("parseIgnoreCommentStop", parseIgnoreCommentStop);
|
||||
builder.append("interpreterSearchPath", "schema", interpreterSearchPath);
|
||||
builder.append("parseSearchPath", "schema", parseSearchPath);
|
||||
}
|
||||
|
||||
@ -3168,6 +3236,15 @@ public class Settings
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (migrationAutoValidation == null) {
|
||||
if (other.migrationAutoValidation!= null) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!migrationAutoValidation.equals(other.migrationAutoValidation)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (locale == null) {
|
||||
if (other.locale!= null) {
|
||||
return false;
|
||||
@ -3258,6 +3335,15 @@ public class Settings
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (interpreterSearchPath == null) {
|
||||
if (other.interpreterSearchPath!= null) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!interpreterSearchPath.equals(other.interpreterSearchPath)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (parseSearchPath == null) {
|
||||
if (other.parseSearchPath!= null) {
|
||||
return false;
|
||||
@ -3340,6 +3426,7 @@ public class Settings
|
||||
result = ((prime*result)+((interpreterDialect == null)? 0 :interpreterDialect.hashCode()));
|
||||
result = ((prime*result)+((interpreterNameLookupCaseSensitivity == null)? 0 :interpreterNameLookupCaseSensitivity.hashCode()));
|
||||
result = ((prime*result)+((interpreterLocale == null)? 0 :interpreterLocale.hashCode()));
|
||||
result = ((prime*result)+((migrationAutoValidation == null)? 0 :migrationAutoValidation.hashCode()));
|
||||
result = ((prime*result)+((locale == null)? 0 :locale.hashCode()));
|
||||
result = ((prime*result)+((parseDialect == null)? 0 :parseDialect.hashCode()));
|
||||
result = ((prime*result)+((parseLocale == null)? 0 :parseLocale.hashCode()));
|
||||
@ -3350,6 +3437,7 @@ public class Settings
|
||||
result = ((prime*result)+((parseIgnoreComments == null)? 0 :parseIgnoreComments.hashCode()));
|
||||
result = ((prime*result)+((parseIgnoreCommentStart == null)? 0 :parseIgnoreCommentStart.hashCode()));
|
||||
result = ((prime*result)+((parseIgnoreCommentStop == null)? 0 :parseIgnoreCommentStop.hashCode()));
|
||||
result = ((prime*result)+((interpreterSearchPath == null)? 0 :interpreterSearchPath.hashCode()));
|
||||
result = ((prime*result)+((parseSearchPath == null)? 0 :parseSearchPath.hashCode()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -35,13 +35,38 @@
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.jooq;
|
||||
package org.jooq.exception;
|
||||
|
||||
import org.jooq.Migration;
|
||||
|
||||
/**
|
||||
* The result of a {@link Migration}.
|
||||
* An error occurred while running a {@link Migration}.
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
public interface MigrationResult {
|
||||
public class DataMigrationException extends DataAccessException {
|
||||
|
||||
/**
|
||||
* Generated UID
|
||||
*/
|
||||
private static final long serialVersionUID = -6460945824599280420L;
|
||||
|
||||
/**
|
||||
* Constructor for DataMigrationException.
|
||||
*
|
||||
* @param message the detail message
|
||||
*/
|
||||
public DataMigrationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for DataMigrationException.
|
||||
*
|
||||
* @param message the detail message
|
||||
* @param cause the cause
|
||||
*/
|
||||
public DataMigrationException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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.exception;
|
||||
|
||||
import org.jooq.Migration;
|
||||
|
||||
/**
|
||||
* An error occurred while running {@link Migration#validate()}.
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
public class DataMigrationValidationException extends DataAccessException {
|
||||
|
||||
/**
|
||||
* Generated UID
|
||||
*/
|
||||
private static final long serialVersionUID = -6460945824599280420L;
|
||||
|
||||
/**
|
||||
* Constructor for DataMigrationValidationException.
|
||||
*
|
||||
* @param message the detail message
|
||||
*/
|
||||
public DataMigrationValidationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for DataMigrationValidationException.
|
||||
*
|
||||
* @param message the detail message
|
||||
* @param cause the cause
|
||||
*/
|
||||
public DataMigrationValidationException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@ -44,6 +44,8 @@ import static org.jooq.impl.Cascade.CASCADE;
|
||||
import static org.jooq.impl.Cascade.RESTRICT;
|
||||
import static org.jooq.impl.ConstraintType.FOREIGN_KEY;
|
||||
import static org.jooq.impl.ConstraintType.PRIMARY_KEY;
|
||||
import static org.jooq.impl.DSL.name;
|
||||
import static org.jooq.impl.DSL.schema;
|
||||
import static org.jooq.impl.SQLDataType.BIGINT;
|
||||
import static org.jooq.impl.Tools.EMPTY_FIELD;
|
||||
import static org.jooq.impl.Tools.intersect;
|
||||
@ -93,6 +95,7 @@ import org.jooq.TableOptions.TableType;
|
||||
import org.jooq.UniqueKey;
|
||||
import org.jooq.Update;
|
||||
import org.jooq.conf.InterpreterNameLookupCaseSensitivity;
|
||||
import org.jooq.conf.InterpreterSearchSchema;
|
||||
import org.jooq.exception.DataAccessException;
|
||||
import org.jooq.exception.DataDefinitionException;
|
||||
import org.jooq.impl.ConstraintImpl.Action;
|
||||
@ -109,7 +112,6 @@ final class DDLInterpreter {
|
||||
private final Map<Name, MutableCatalog> catalogs = new LinkedHashMap<>();
|
||||
private final MutableCatalog defaultCatalog;
|
||||
private final MutableSchema defaultSchema;
|
||||
private MutableSchema currentSchema;
|
||||
|
||||
// Caches
|
||||
private final Map<Name, MutableCatalog.InterpretedCatalog> interpretedCatalogs = new HashMap<>();
|
||||
@ -127,7 +129,6 @@ final class DDLInterpreter {
|
||||
this.defaultCatalog = new MutableCatalog(NO_NAME);
|
||||
this.catalogs.put(defaultCatalog.name(), defaultCatalog);
|
||||
this.defaultSchema = new MutableSchema(NO_NAME, defaultCatalog);
|
||||
this.currentSchema = defaultSchema;
|
||||
}
|
||||
|
||||
final Meta meta() {
|
||||
@ -273,10 +274,6 @@ final class DDLInterpreter {
|
||||
mutableSchema.catalog.schemas.remove(mutableSchema);
|
||||
else
|
||||
throw schemaNotEmpty(schema);
|
||||
|
||||
// TODO: Is this needed?
|
||||
if (mutableSchema.equals(currentSchema))
|
||||
currentSchema = null;
|
||||
}
|
||||
|
||||
private final void accept0(CreateTableImpl query) {
|
||||
@ -1061,10 +1058,8 @@ final class DDLInterpreter {
|
||||
}
|
||||
|
||||
private final MutableSchema getSchema(Schema input, boolean create) {
|
||||
|
||||
// TODO It does not appear we should auto-create schema in the interpreter. Why is this being done?
|
||||
if (input == null)
|
||||
return currentSchema;
|
||||
return getInterpreterSearchPathSchema(create);
|
||||
|
||||
MutableCatalog catalog = defaultCatalog;
|
||||
if (input.getCatalog() != null) {
|
||||
@ -1084,6 +1079,16 @@ final class DDLInterpreter {
|
||||
return schema;
|
||||
}
|
||||
|
||||
private final MutableSchema getInterpreterSearchPathSchema(boolean create) {
|
||||
List<InterpreterSearchSchema> searchPath = configuration.settings().getInterpreterSearchPath();
|
||||
|
||||
if (searchPath.isEmpty())
|
||||
return defaultSchema;
|
||||
|
||||
InterpreterSearchSchema schema = searchPath.get(0);
|
||||
return getSchema(schema(name(schema.getCatalog(), schema.getSchema())), create);
|
||||
}
|
||||
|
||||
private final MutableTable newTable(
|
||||
Table<?> table,
|
||||
MutableSchema schema,
|
||||
|
||||
@ -37,6 +37,9 @@
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import static java.lang.Boolean.FALSE;
|
||||
import static org.jooq.impl.DSL.createSchemaIfNotExists;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
@ -48,9 +51,9 @@ import org.jooq.Constants;
|
||||
import org.jooq.ContextTransactionalCallable;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.Identity;
|
||||
import org.jooq.Meta;
|
||||
import org.jooq.Migration;
|
||||
import org.jooq.MigrationListener;
|
||||
import org.jooq.MigrationResult;
|
||||
import org.jooq.Name;
|
||||
import org.jooq.Queries;
|
||||
import org.jooq.Query;
|
||||
@ -61,7 +64,8 @@ import org.jooq.TableField;
|
||||
import org.jooq.UniqueKey;
|
||||
import org.jooq.Version;
|
||||
import org.jooq.exception.DataAccessException;
|
||||
import org.jooq.exception.DataDefinitionException;
|
||||
import org.jooq.exception.DataMigrationException;
|
||||
import org.jooq.exception.DataMigrationValidationException;
|
||||
import org.jooq.tools.JooqLogger;
|
||||
import org.jooq.tools.StopWatch;
|
||||
|
||||
@ -87,17 +91,10 @@ final class MigrationImpl extends AbstractScope implements Migration {
|
||||
|
||||
@Override
|
||||
public final Version from() {
|
||||
if (from == null) {
|
||||
if (from == null)
|
||||
|
||||
// TODO: Use pessimistic locking so no one else can migrate in between
|
||||
JooqMigrationsChangelogRecord currentRecord =
|
||||
dsl().selectFrom(CHANGELOG)
|
||||
.orderBy(CHANGELOG.MIGRATED_AT.desc(), CHANGELOG.ID.desc())
|
||||
.limit(1)
|
||||
.fetchOne();
|
||||
|
||||
from = currentRecord == null ? to().root() : versions().get(currentRecord.getMigratedTo());
|
||||
}
|
||||
from = currentVersion();
|
||||
|
||||
return from;
|
||||
}
|
||||
@ -126,16 +123,45 @@ final class MigrationImpl extends AbstractScope implements Migration {
|
||||
return versions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void validate() {
|
||||
JooqMigrationsChangelogRecord currentRecord = currentChangelogRecord();
|
||||
|
||||
if (currentRecord != null) {
|
||||
Version currentVersion = versions().get(currentRecord.getMigratedTo());
|
||||
|
||||
if (currentVersion == null)
|
||||
throw new DataMigrationValidationException("Version trying to migrate to is not available from VersionProvider: " + currentRecord.getMigratedTo());
|
||||
}
|
||||
|
||||
validateUnexpectedObjects();
|
||||
}
|
||||
|
||||
private final void validateUnexpectedObjects() {
|
||||
Version currentVersion = currentVersion();
|
||||
Meta currentMeta = currentVersion.meta();
|
||||
|
||||
Meta existingMeta = dsl().meta();
|
||||
|
||||
for (Schema schema : existingMeta.getSchemas())
|
||||
currentMeta = currentMeta.apply(createSchemaIfNotExists(schema));
|
||||
|
||||
System.out.println(existingMeta.migrateTo(currentMeta));
|
||||
}
|
||||
|
||||
private static final MigrationResult MIGRATION_RESULT = new MigrationResult() {};
|
||||
|
||||
@Override
|
||||
public final MigrationResult execute() throws DataDefinitionException {
|
||||
public final MigrationResult execute() {
|
||||
|
||||
// TODO: Transactions don't really make sense in most dialects. In some, they do
|
||||
// e.g. PostgreSQL supports transactional DDL. Check if we're getting this right.
|
||||
return run(new ContextTransactionalCallable<MigrationResult>() {
|
||||
@Override
|
||||
public MigrationResult run() {
|
||||
if (!FALSE.equals(dsl().settings().isMigrationAutoValidation()))
|
||||
validate();
|
||||
|
||||
DefaultMigrationContext ctx = new DefaultMigrationContext(configuration(), from(), to(), queries());
|
||||
MigrationListener listener = new MigrationListeners(configuration);
|
||||
|
||||
@ -147,6 +173,7 @@ final class MigrationImpl extends AbstractScope implements Migration {
|
||||
return MIGRATION_RESULT;
|
||||
}
|
||||
|
||||
// TODO: What to do if we're about to install things on a non-empty schema
|
||||
// TODO: Implement preconditions
|
||||
// TODO: Implement a listener with a variety of pro / oss features
|
||||
// TODO: Implement additional out-of-the-box sanity checks
|
||||
@ -230,7 +257,7 @@ final class MigrationImpl extends AbstractScope implements Migration {
|
||||
public final void init() {
|
||||
|
||||
// TODO: What to do when initialising jOOQ-migrations on an existing database?
|
||||
// - Should there be init() commands that can be run explicitl by the user?
|
||||
// - Should there be init() commands that can be run explicitly by the user?
|
||||
// - Will we reverse engineer the production Meta snapshot first?
|
||||
if (!existsChangelog())
|
||||
dsl().meta(CHANGELOG).ddl().executeBatch();
|
||||
@ -248,9 +275,31 @@ final class MigrationImpl extends AbstractScope implements Migration {
|
||||
return false;
|
||||
}
|
||||
|
||||
private final JooqMigrationsChangelogRecord currentChangelogRecord() {
|
||||
return existsChangelog()
|
||||
? dsl().selectFrom(CHANGELOG)
|
||||
.orderBy(CHANGELOG.MIGRATED_AT.desc(), CHANGELOG.ID.desc())
|
||||
.limit(1)
|
||||
.fetchOne()
|
||||
: null;
|
||||
}
|
||||
|
||||
private final Version currentVersion() {
|
||||
JooqMigrationsChangelogRecord currentRecord = currentChangelogRecord();
|
||||
return currentRecord == null ? to().root() : versions().get(currentRecord.getMigratedTo());
|
||||
}
|
||||
|
||||
private final <T> T run(final ContextTransactionalCallable<T> runnable) {
|
||||
init();
|
||||
return dsl().transactionResult(runnable);
|
||||
try {
|
||||
init();
|
||||
return dsl().transactionResult(runnable);
|
||||
}
|
||||
catch (DataMigrationException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new DataMigrationException("Exception during migration", e);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@ -206,7 +206,7 @@ final class QualifiedName extends AbstractName {
|
||||
|
||||
@Override
|
||||
public final Name unqualifiedName() {
|
||||
if (qualifiedName.length <= 1)
|
||||
if (qualifiedName.length == 0)
|
||||
return this;
|
||||
else
|
||||
return qualifiedName[qualifiedName.length - 1];
|
||||
|
||||
@ -399,6 +399,14 @@ jOOQ queries, for which no specific fetchSize value was specified.]]></jxb:javad
|
||||
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[The Locale to be used with any interpreter locale dependent logic, defaulting to {@link #getLocale()}.]]></jxb:javadoc></jxb:property></appinfo></annotation>
|
||||
</element>
|
||||
|
||||
<element name="interpreterSearchPath" type="jooq-runtime:InterpreterSearchSchemata" minOccurs="0" maxOccurs="1">
|
||||
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[[#9677] The search path to be used for unqualified table lookups by the interpreter.]]></jxb:javadoc></jxb:property></appinfo></annotation>
|
||||
</element>
|
||||
|
||||
<element name="migrationAutoValidation" type="boolean" minOccurs="0" maxOccurs="1" default="true">
|
||||
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Whether a migration automatically runs a validation first.]]></jxb:javadoc></jxb:property></appinfo></annotation>
|
||||
</element>
|
||||
|
||||
<element name="locale" type="string" minOccurs="0" maxOccurs="1">
|
||||
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[The Locale to be used with any locale dependent logic if there is not a more specific locale available. More specific locales include e.g. {@link #getRenderLocale()}, {@link #getParseLocale()}, or {@link #getInterpreterLocale()}.]]></jxb:javadoc></jxb:property></appinfo></annotation>
|
||||
</element>
|
||||
@ -463,6 +471,24 @@ jOOQ queries, for which no specific fetchSize value was specified.]]></jxb:javad
|
||||
</all>
|
||||
</complexType>
|
||||
|
||||
<complexType name="InterpreterSearchSchemata">
|
||||
<sequence>
|
||||
<element name="schema" type="jooq-runtime:InterpreterSearchSchema" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</sequence>
|
||||
</complexType>
|
||||
|
||||
<complexType name="InterpreterSearchSchema">
|
||||
<annotation><appinfo><jxb:class><jxb:javadoc><![CDATA[A schema that is on the search path.]]></jxb:javadoc></jxb:class></appinfo></annotation>
|
||||
<all>
|
||||
<element name="catalog" type="string" minOccurs="0" maxOccurs="1">
|
||||
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[The catalog qualifier of the schema, if applicable.]]></jxb:javadoc></jxb:property></appinfo></annotation>
|
||||
</element>
|
||||
<element name="schema" type="string" minOccurs="1" maxOccurs="1">
|
||||
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[The schema qualifier whose elements can be found from the search path.]]></jxb:javadoc></jxb:property></appinfo></annotation>
|
||||
</element>
|
||||
</all>
|
||||
</complexType>
|
||||
|
||||
<complexType name="RenderMapping">
|
||||
<annotation><appinfo><jxb:class><jxb:javadoc><![CDATA[The runtime schema and table mapping.]]></jxb:javadoc></jxb:class></appinfo></annotation>
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user