http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DropColumnToModel.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DropColumnToModel.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DropColumnToModel.java new file mode 100644 index 0000000..ceb03bc --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DropColumnToModel.java @@ -0,0 +1,75 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + ****************************************************************/ +package org.apache.cayenne.dbsync.merge; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory; +import org.apache.cayenne.map.DbAttribute; +import org.apache.cayenne.map.DbEntity; +import org.apache.cayenne.map.DbJoin; +import org.apache.cayenne.map.DbRelationship; +import org.apache.cayenne.map.ObjAttribute; +import org.apache.cayenne.map.ObjEntity; + +/** + * A {@link MergerToken} to remove a {@link DbAttribute} from a {@link DbEntity}. + * + */ +public class DropColumnToModel extends AbstractToModelToken.EntityAndColumn { + + public DropColumnToModel(DbEntity entity, DbAttribute column) { + super("Drop Column", entity, column); + } + + public MergerToken createReverse(MergerTokenFactory factory) { + return factory.createAddColumnToDb(getEntity(), getColumn()); + } + + public void execute(MergerContext mergerContext) { + + // remove relationships mapped to column. duplicate List to prevent + // ConcurrentModificationException + List<DbRelationship> dbRelationships = new ArrayList<DbRelationship>(getEntity() + .getRelationships()); + for (DbRelationship dbRelationship : dbRelationships) { + for (DbJoin join : dbRelationship.getJoins()) { + if (join.getSource() == getColumn() || join.getTarget() == getColumn()) { + remove(mergerContext.getModelMergeDelegate(), dbRelationship, true); + } + } + } + + // remove ObjAttribute mapped to same column + for (ObjEntity objEntity : getEntity().mappedObjEntities()) { + ObjAttribute objAttribute = objEntity.getAttributeForDbAttribute(getColumn()); + if (objAttribute != null) { + objEntity.removeAttribute(objAttribute.getName()); + mergerContext.getModelMergeDelegate().objAttributeRemoved(objAttribute); + } + + } + + // remove DbAttribute + getEntity().removeAttribute(getColumn().getName()); + + mergerContext.getModelMergeDelegate().dbAttributeRemoved(getColumn()); + } +}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DropRelationshipToDb.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DropRelationshipToDb.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DropRelationshipToDb.java new file mode 100644 index 0000000..238a44a --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DropRelationshipToDb.java @@ -0,0 +1,72 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + ****************************************************************/ +package org.apache.cayenne.dbsync.merge; + +import java.util.Collections; +import java.util.List; + +import org.apache.cayenne.dba.DbAdapter; +import org.apache.cayenne.dba.QuotingStrategy; +import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory; +import org.apache.cayenne.map.DbEntity; +import org.apache.cayenne.map.DbRelationship; +import org.apache.cayenne.map.DbRelationshipDetected; + +public class DropRelationshipToDb extends AbstractToDbToken.Entity { + + private DbRelationship rel; + + public DropRelationshipToDb(DbEntity entity, DbRelationship rel) { + super("Drop foreign key", entity); + this.rel = rel; + } + + public String getFkName() { + if (rel instanceof DbRelationshipDetected) { + return ((DbRelationshipDetected) rel).getFkName(); + } + return null; + } + + @Override + public List<String> createSql(DbAdapter adapter) { + String fkName = getFkName(); + if (fkName == null) { + return Collections.emptyList(); + } + + QuotingStrategy context = adapter.getQuotingStrategy(); + return Collections.singletonList( + "ALTER TABLE " + context.quotedFullyQualifiedName(getEntity()) + " DROP CONSTRAINT " + fkName); + } + + public MergerToken createReverse(MergerTokenFactory factory) { + return factory.createAddRelationshipToModel(getEntity(), rel); + } + + @Override + public String getTokenValue() { + return rel.getSourceEntity().getName() + "->" + rel.getTargetEntityName(); + } + + public DbRelationship getRelationship() { + return rel; + } + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DropRelationshipToModel.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DropRelationshipToModel.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DropRelationshipToModel.java new file mode 100644 index 0000000..686df6e --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DropRelationshipToModel.java @@ -0,0 +1,51 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + ****************************************************************/ +package org.apache.cayenne.dbsync.merge; + +import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory; +import org.apache.cayenne.map.DbEntity; +import org.apache.cayenne.map.DbRelationship; + +public class DropRelationshipToModel extends AbstractToModelToken.Entity { + + private final DbRelationship rel; + + public DropRelationshipToModel(DbEntity entity, DbRelationship rel) { + super("Drop db-relationship ", entity); + this.rel = rel; + } + + public MergerToken createReverse(MergerTokenFactory factory) { + return factory.createAddRelationshipToDb(getEntity(), rel); + } + + public void execute(MergerContext mergerContext) { + remove(mergerContext.getModelMergeDelegate(), rel, true); + } + + @Override + public String getTokenValue() { + return AddRelationshipToModel.getTokenValue(rel); + } + + public DbRelationship getRelationship() { + return rel; + } + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DropTableToDb.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DropTableToDb.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DropTableToDb.java new file mode 100644 index 0000000..6b76646 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DropTableToDb.java @@ -0,0 +1,50 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + ****************************************************************/ +package org.apache.cayenne.dbsync.merge; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.cayenne.dba.DbAdapter; +import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory; +import org.apache.cayenne.map.DbEntity; + +public class DropTableToDb extends AbstractToDbToken.Entity { + + public DropTableToDb(DbEntity entity) { + super("Drop Table", entity); + } + + @Override + public List<String> createSql(DbAdapter adapter) { + List<String> sqls = new ArrayList<String>(); + // TODO: fix. some adapters drop the complete AUTO_PK_SUPPORT here + /* + sqls.addAll(adapter.getPkGenerator().dropAutoPkStatements( + Collections.singletonList(entity))); + */ + sqls.addAll(adapter.dropTableStatements(getEntity())); + return sqls; + } + + public MergerToken createReverse(MergerTokenFactory factory) { + return factory.createCreateTableToModel(getEntity()); + } + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DropTableToModel.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DropTableToModel.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DropTableToModel.java new file mode 100644 index 0000000..7a47f37 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DropTableToModel.java @@ -0,0 +1,49 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + ****************************************************************/ +package org.apache.cayenne.dbsync.merge; + +import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory; +import org.apache.cayenne.map.DataMap; +import org.apache.cayenne.map.DbEntity; +import org.apache.cayenne.map.ObjEntity; + +/** + * A {@link MergerToken} to remove a {@link DbEntity} from a {@link DataMap}. Any + * {@link ObjEntity} mapped to the {@link DbEntity} will also be removed. + * + */ +public class DropTableToModel extends AbstractToModelToken.Entity { + + public DropTableToModel(DbEntity entity) { + super("Drop Table", entity); + } + + public MergerToken createReverse(MergerTokenFactory factory) { + return factory.createCreateTableToDb(getEntity()); + } + + public void execute(MergerContext mergerContext) { + for (ObjEntity objEntity : getEntity().mappedObjEntities()) { + objEntity.getDataMap().removeObjEntity(objEntity.getName(), true); + mergerContext.getModelMergeDelegate().objEntityRemoved(objEntity); + } + getEntity().getDataMap().removeDbEntity(getEntity().getName(), true); + mergerContext.getModelMergeDelegate().dbEntityRemoved(getEntity()); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DummyReverseToken.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DummyReverseToken.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DummyReverseToken.java new file mode 100644 index 0000000..54b779b --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DummyReverseToken.java @@ -0,0 +1,60 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + ****************************************************************/ +package org.apache.cayenne.dbsync.merge; + +import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory; + +/** + * The reverse of a {@link MergerToken} that can not be reversed.. This will not execute + * any thing, but {@link #createReverse(MergerTokenFactory)} will get back the reverse that + * this was made from. + */ +class DummyReverseToken implements MergerToken { + + private MergerToken reverse; + + public DummyReverseToken(MergerToken reverse) { + this.reverse = reverse; + } + + public MergerToken createReverse(MergerTokenFactory factory) { + return reverse; + } + + public void execute(MergerContext mergerContext) { + // can not execute + } + + public MergeDirection getDirection() { + return reverse.getDirection().reverseDirection(); + } + + public String getTokenName() { + return "Can not execute the reverse of " + reverse.getTokenName(); + } + + public String getTokenValue() { + return reverse.getTokenValue(); + } + + public boolean isReversible() { + return true; + } + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/EmptyValueForNullProvider.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/EmptyValueForNullProvider.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/EmptyValueForNullProvider.java new file mode 100644 index 0000000..a484655 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/EmptyValueForNullProvider.java @@ -0,0 +1,40 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + ****************************************************************/ +package org.apache.cayenne.dbsync.merge; + +import java.util.Collections; +import java.util.List; + +import org.apache.cayenne.map.DbAttribute; +import org.apache.cayenne.map.DbEntity; + +/** + * A dummy {@link ValueForNullProvider} that are not able to provide any values + */ +class EmptyValueForNullProvider implements ValueForNullProvider { + + public List<String> createSql(DbEntity entity, DbAttribute column) { + return Collections.emptyList(); + } + + public boolean hasValueFor(DbEntity entity, DbAttribute column) { + return false; + } + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/EntityMergeSupport.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/EntityMergeSupport.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/EntityMergeSupport.java new file mode 100644 index 0000000..8aea02a --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/EntityMergeSupport.java @@ -0,0 +1,522 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + ****************************************************************/ + +package org.apache.cayenne.dbsync.merge; + +import org.apache.cayenne.dba.TypesMapping; +import org.apache.cayenne.map.DataMap; +import org.apache.cayenne.map.DbAttribute; +import org.apache.cayenne.map.DbEntity; +import org.apache.cayenne.map.DbJoin; +import org.apache.cayenne.map.DbRelationship; +import org.apache.cayenne.map.Entity; +import org.apache.cayenne.map.ObjAttribute; +import org.apache.cayenne.map.ObjEntity; +import org.apache.cayenne.map.ObjRelationship; +import org.apache.cayenne.map.naming.DefaultUniqueNameGenerator; +import org.apache.cayenne.map.naming.LegacyNameGenerator; +import org.apache.cayenne.map.naming.NameCheckers; +import org.apache.cayenne.map.naming.ObjectNameGenerator; +import org.apache.cayenne.util.DeleteRuleUpdater; +import org.apache.cayenne.util.EntityMergeListener; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/** + * Implements methods for entity merging. + */ +public class EntityMergeSupport { + + private static final Log LOG = LogFactory.getLog(EntityMergeSupport.class); + + private static final Map<String, String> CLASS_TO_PRIMITIVE; + + static { + CLASS_TO_PRIMITIVE = new HashMap<>(); + CLASS_TO_PRIMITIVE.put(Byte.class.getName(), "byte"); + CLASS_TO_PRIMITIVE.put(Long.class.getName(), "long"); + CLASS_TO_PRIMITIVE.put(Double.class.getName(), "double"); + CLASS_TO_PRIMITIVE.put(Boolean.class.getName(), "boolean"); + CLASS_TO_PRIMITIVE.put(Float.class.getName(), "float"); + CLASS_TO_PRIMITIVE.put(Short.class.getName(), "short"); + CLASS_TO_PRIMITIVE.put(Integer.class.getName(), "int"); + } + + private final DataMap map; + /** + * Strategy for choosing names for entities, attributes and relationships + */ + private final ObjectNameGenerator nameGenerator; + /** + * Listeners of merge process. + */ + private final List<EntityMergeListener> listeners = new ArrayList<EntityMergeListener>(); + protected boolean removeMeaningfulFKs; + protected boolean removeMeaningfulPKs; + protected boolean usePrimitives; + + public EntityMergeSupport(DataMap map) { + this(map, new LegacyNameGenerator(), true); + } + + /** + * @since 3.0 + */ + public EntityMergeSupport(DataMap map, ObjectNameGenerator nameGenerator, boolean removeMeaningfulPKs) { + this.map = map; + this.nameGenerator = nameGenerator; + this.removeMeaningfulFKs = true; + this.removeMeaningfulPKs = removeMeaningfulPKs; + + /** + * Adding a listener, so that all created ObjRelationships would have + * default delete rule + */ + addEntityMergeListener(DeleteRuleUpdater.getEntityMergeListener()); + } + + /** + * Updates each one of the collection of ObjEntities, adding attributes and + * relationships based on the current state of its DbEntity. + * + * @return true if any ObjEntity has changed as a result of synchronization. + * @since 1.2 changed signature to use Collection instead of List. + */ + public boolean synchronizeWithDbEntities(Iterable<ObjEntity> objEntities) { + boolean changed = false; + for (ObjEntity nextEntity : objEntities) { + if (synchronizeWithDbEntity(nextEntity)) { + changed = true; + } + } + + return changed; + } + + /** + * @since 4.0 + */ + protected boolean removePK(DbEntity dbEntity) { + return removeMeaningfulPKs; + } + + /** + * @since 4.0 + */ + protected boolean removeFK(DbEntity dbEntity) { + return removeMeaningfulFKs; + } + + /** + * Updates ObjEntity attributes and relationships based on the current state + * of its DbEntity. + * + * @return true if the ObjEntity has changed as a result of synchronization. + */ + public boolean synchronizeWithDbEntity(ObjEntity entity) { + + if (entity == null) { + return false; + } + + DbEntity dbEntity = entity.getDbEntity(); + if (dbEntity == null) { + return false; + } + + boolean changed = false; + + // synchronization on DataMap is some (weak) protection + // against simultaneous modification of the map (like double-clicking on sync button) + synchronized (map) { + + if (removeFK(dbEntity)) { + changed = getRidOfAttributesThatAreNowSrcAttributesForRelationships(entity); + } + + changed |= addMissingAttributes(entity); + changed |= addMissingRelationships(entity); + } + + return changed; + } + + /** + * @since 4.0 + */ + public boolean synchronizeOnDbAttributeAdded(ObjEntity entity, DbAttribute dbAttribute) { + + Collection<DbRelationship> incomingRels = getIncomingRelationships(dbAttribute.getEntity()); + if (isMissingFromObjEntity(entity, dbAttribute, incomingRels)) { + addMissingAttribute(entity, dbAttribute); + return true; + } + + return false; + } + + /** + * @since 4.0 + */ + public boolean synchronizeOnDbRelationshipAdded(ObjEntity entity, DbRelationship dbRelationship) { + + if (isMissingFromObjEntity(entity, dbRelationship)) { + addMissingRelationship(entity, dbRelationship); + } + + return true; + } + + private boolean addMissingRelationships(ObjEntity entity) { + List<DbRelationship> relationshipsToAdd = getRelationshipsToAdd(entity); + if (relationshipsToAdd.isEmpty()) { + return false; + } + + for (DbRelationship dr : relationshipsToAdd) { + addMissingRelationship(entity, dr); + } + + return true; + } + + private boolean createObjRelationship(ObjEntity entity, DbRelationship dr, String targetEntityName) { + String relationshipName = nameGenerator.createObjRelationshipName(dr); + relationshipName = DefaultUniqueNameGenerator.generate(NameCheckers.objRelationship, entity, relationshipName); + + ObjRelationship or = new ObjRelationship(relationshipName); + or.addDbRelationship(dr); + Map<String, ObjEntity> objEntities = entity.getDataMap().getSubclassesForObjEntity(entity); + + boolean hasFlattingAttributes = false; + boolean needGeneratedEntity = true; + + if (objEntities.containsKey(targetEntityName)) { + needGeneratedEntity = false; + } + + for (ObjEntity subObjEntity : objEntities.values()) { + for (ObjAttribute objAttribute : subObjEntity.getAttributes()) { + String path = objAttribute.getDbAttributePath(); + if (path != null) { + if (path.startsWith(or.getDbRelationshipPath())) { + hasFlattingAttributes = true; + break; + } + } + } + } + + if (!hasFlattingAttributes) { + if (needGeneratedEntity) { + or.setTargetEntityName(targetEntityName); + or.setSourceEntity(entity); + } + + entity.addRelationship(or); + fireRelationshipAdded(or); + } + + return needGeneratedEntity; + } + + private boolean addMissingAttributes(ObjEntity entity) { + boolean changed = false; + + for (DbAttribute da : getAttributesToAdd(entity)) { + addMissingAttribute(entity, da); + changed = true; + } + return changed; + } + + private void addMissingRelationship(ObjEntity entity, DbRelationship dbRelationship) { + DbEntity targetEntity = dbRelationship.getTargetEntity(); + + Collection<ObjEntity> mappedObjEntities = map.getMappedEntities(targetEntity); + if (!mappedObjEntities.isEmpty()) { + for (Entity mappedTarget : mappedObjEntities) { + createObjRelationship(entity, dbRelationship, mappedTarget.getName()); + } + } else { + + if (targetEntity == null) { + targetEntity = new DbEntity(dbRelationship.getTargetEntityName()); + } + + if (dbRelationship.getTargetEntityName() != null) { + boolean needGeneratedEntity = createObjRelationship(entity, dbRelationship, + nameGenerator.createObjEntityName(targetEntity)); + if (needGeneratedEntity) { + LOG.warn("Can't find ObjEntity for " + dbRelationship.getTargetEntityName()); + LOG.warn("Db Relationship (" + dbRelationship + ") will have GUESSED Obj Relationship reflection. "); + } + } + } + } + + private void addMissingAttribute(ObjEntity entity, DbAttribute da) { + String attrName = DefaultUniqueNameGenerator.generate(NameCheckers.objAttribute, entity, + nameGenerator.createObjAttributeName(da)); + + String type = TypesMapping.getJavaBySqlType(da.getType()); + if (usePrimitives) { + String primitive = CLASS_TO_PRIMITIVE.get(type); + if (primitive != null) { + type = primitive; + } + } + + ObjAttribute oa = new ObjAttribute(attrName, type, entity); + oa.setDbAttributePath(da.getName()); + entity.addAttribute(oa); + fireAttributeAdded(oa); + } + + private boolean getRidOfAttributesThatAreNowSrcAttributesForRelationships(ObjEntity entity) { + boolean changed = false; + for (DbAttribute da : getMeaningfulFKs(entity)) { + ObjAttribute oa = entity.getAttributeForDbAttribute(da); + while (oa != null) { + String attrName = oa.getName(); + entity.removeAttribute(attrName); + changed = true; + oa = entity.getAttributeForDbAttribute(da); + } + } + return changed; + } + + /** + * Returns a list of DbAttributes that are mapped to foreign keys. + * + * @since 1.2 + */ + public Collection<DbAttribute> getMeaningfulFKs(ObjEntity objEntity) { + List<DbAttribute> fks = new ArrayList<DbAttribute>(2); + + for (ObjAttribute property : objEntity.getAttributes()) { + DbAttribute column = property.getDbAttribute(); + + // check if adding it makes sense at all + if (column != null && column.isForeignKey()) { + fks.add(column); + } + } + + return fks; + } + + /** + * Returns a list of attributes that exist in the DbEntity, but are missing + * from the ObjEntity. + */ + protected List<DbAttribute> getAttributesToAdd(ObjEntity objEntity) { + DbEntity dbEntity = objEntity.getDbEntity(); + + List<DbAttribute> missing = new ArrayList<DbAttribute>(); + Collection<DbRelationship> incomingRels = getIncomingRelationships(dbEntity); + + for (DbAttribute dba : dbEntity.getAttributes()) { + + if (isMissingFromObjEntity(objEntity, dba, incomingRels)) { + missing.add(dba); + } + } + + return missing; + } + + protected boolean isMissingFromObjEntity(ObjEntity entity, DbAttribute dbAttribute, Collection<DbRelationship> incomingRels) { + + if (dbAttribute.getName() == null || entity.getAttributeForDbAttribute(dbAttribute) != null) { + return false; + } + + boolean removeMeaningfulPKs = removePK(dbAttribute.getEntity()); + if (removeMeaningfulPKs && dbAttribute.isPrimaryKey()) { + return false; + } + + // check FK's + boolean isFK = false; + Iterator<DbRelationship> rit = dbAttribute.getEntity().getRelationships().iterator(); + while (!isFK && rit.hasNext()) { + DbRelationship rel = rit.next(); + for (DbJoin join : rel.getJoins()) { + if (join.getSource() == dbAttribute) { + isFK = true; + break; + } + } + } + + if (!removeMeaningfulPKs) { + if (!dbAttribute.isPrimaryKey() && isFK) { + return false; + } + } else { + if (isFK) { + return false; + } + } + + // check incoming relationships + rit = incomingRels.iterator(); + while (!isFK && rit.hasNext()) { + DbRelationship rel = rit.next(); + for (DbJoin join : rel.getJoins()) { + if (join.getTarget() == dbAttribute) { + isFK = true; + break; + } + } + } + + if (!removeMeaningfulPKs) { + if (!dbAttribute.isPrimaryKey() && isFK) { + return false; + } + } else { + if (isFK) { + return false; + } + } + + return true; + } + + protected boolean isMissingFromObjEntity(ObjEntity entity, DbRelationship dbRelationship) { + return dbRelationship.getName() != null && entity.getRelationshipForDbRelationship(dbRelationship) == null; + } + + private Collection<DbRelationship> getIncomingRelationships(DbEntity entity) { + Collection<DbRelationship> incoming = new ArrayList<DbRelationship>(); + + for (DbEntity nextEntity : entity.getDataMap().getDbEntities()) { + for (DbRelationship relationship : nextEntity.getRelationships()) { + + // TODO: PERFORMANCE 'getTargetEntity' is generally slow, called + // in this iterator it is showing (e.g. in YourKit profiles).. + // perhaps use cheaper 'getTargetEntityName()' or even better - + // pre-cache all relationships by target entity to avoid O(n) + // search ? + // (need to profile to prove the difference) + if (entity == relationship.getTargetEntity()) { + incoming.add(relationship); + } + } + } + + return incoming; + } + + protected List<DbRelationship> getRelationshipsToAdd(ObjEntity objEntity) { + List<DbRelationship> missing = new ArrayList<DbRelationship>(); + for (DbRelationship dbRel : objEntity.getDbEntity().getRelationships()) { + if (isMissingFromObjEntity(objEntity, dbRel)) { + missing.add(dbRel); + } + } + + return missing; + } + + /** + * @since 1.2 + */ + public boolean isRemoveMeaningfulFKs() { + return removeMeaningfulFKs; + } + + /** + * @since 1.2 + */ + public void setRemoveMeaningfulFKs(boolean removeMeaningfulFKs) { + this.removeMeaningfulFKs = removeMeaningfulFKs; + } + + /** + * Registers new EntityMergeListener + */ + public void addEntityMergeListener(EntityMergeListener listener) { + listeners.add(listener); + } + + /** + * Unregisters an EntityMergeListener + */ + public void removeEntityMergeListener(EntityMergeListener listener) { + listeners.remove(listener); + } + + /** + * Returns registered listeners + */ + public EntityMergeListener[] getEntityMergeListeners() { + return listeners.toArray(new EntityMergeListener[listeners.size()]); + } + + /** + * Notifies all listeners that an ObjAttribute was added + */ + protected void fireAttributeAdded(ObjAttribute attr) { + for (EntityMergeListener listener : listeners) { + listener.objAttributeAdded(attr); + } + } + + /** + * Notifies all listeners that an ObjRelationship was added + */ + protected void fireRelationshipAdded(ObjRelationship rel) { + for (EntityMergeListener listener : listeners) { + listener.objRelationshipAdded(rel); + } + } + + /** + * @return naming strategy for reverse engineering + */ + public ObjectNameGenerator getNameGenerator() { + return nameGenerator; + } + + /** + * @since 4.0 + */ + public boolean isUsePrimitives() { + return usePrimitives; + } + + /** + * @param usePrimitives + * @since 4.0 + */ + public void setUsePrimitives(boolean usePrimitives) { + this.usePrimitives = usePrimitives; + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/MergeDirection.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/MergeDirection.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/MergeDirection.java new file mode 100644 index 0000000..4ac25e4 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/MergeDirection.java @@ -0,0 +1,70 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + ****************************************************************/ +package org.apache.cayenne.dbsync.merge; + +/** + * Represent a merge direction that can be either from the model to the db or from the db to the model. + */ +public enum MergeDirection { + + /** + * TO_DB Token means that changes was made in object model and should be reflected at DB + */ + TO_DB("To DB"), + + /** + * TO_MODEL Token represent database changes that should be allayed to object model + */ + TO_MODEL("To Model"); + + private String name; + + MergeDirection(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public boolean isToDb() { + return (this == TO_DB); + } + + public boolean isToModel() { + return (this == TO_MODEL); + } + + @Override + public String toString() { + return getName(); + } + + public MergeDirection reverseDirection() { + switch (this) { + case TO_DB: + return TO_MODEL; + case TO_MODEL: + return TO_DB; + default: + throw new IllegalStateException("Invalid direction: " + this); + } + } + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/MergerContext.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/MergerContext.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/MergerContext.java new file mode 100644 index 0000000..772de97 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/MergerContext.java @@ -0,0 +1,118 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + ****************************************************************/ +package org.apache.cayenne.dbsync.merge; + +import org.apache.cayenne.access.DataNode; +import org.apache.cayenne.dba.DbAdapter; +import org.apache.cayenne.map.DataMap; +import org.apache.cayenne.validation.ValidationResult; + +import javax.sql.DataSource; +import java.util.Objects; + +/** + * An object passed as an argument to {@link MergerToken#execute(MergerContext)}s that a + * {@link MergerToken} can do its work. + */ +public class MergerContext { + + private DataMap dataMap; + private DataNode dataNode; + private ValidationResult validationResult; + private ModelMergeDelegate delegate; + + protected MergerContext() { + } + + public static Builder builder(DataMap dataMap) { + return new Builder().dataMap(dataMap); + } + + /** + * @deprecated since 4.0 use {@link #getDataNode()} and its {@link DataNode#getAdapter()} method. + */ + @Deprecated + public DbAdapter getAdapter() { + return getDataNode().getAdapter(); + } + + /** + * Returns the DataMap that is the target of a the merge operation. + * + * @return the DataMap that is the target of a the merge operation. + */ + public DataMap getDataMap() { + return dataMap; + } + + public DataNode getDataNode() { + return dataNode; + } + + public ValidationResult getValidationResult() { + return validationResult; + } + + /** + * Returns a callback object that is invoked as the merge proceeds through tokens, modifying the DataMap. + * + * @return a callback object that is invoked as the merge proceeds through tokens, modifying the DataMap. + */ + public ModelMergeDelegate getModelMergeDelegate() { + return delegate; + } + + public static class Builder { + + private MergerContext context; + + private Builder() { + this.context = new MergerContext(); + this.context.validationResult = new ValidationResult(); + this.context.delegate = new DefaultModelMergeDelegate(); + this.context.dataNode = new DataNode(); + } + + public MergerContext build() { + return context; + } + + public Builder delegate(ModelMergeDelegate delegate) { + context.delegate = Objects.requireNonNull(delegate); + return this; + } + + public Builder dataNode(DataNode dataNode) { + this.context.dataNode = Objects.requireNonNull(dataNode); + return this; + } + + public Builder syntheticDataNode(DataSource dataSource, DbAdapter adapter) { + DataNode dataNode = new DataNode(); + dataNode.setDataSource(dataSource); + dataNode.setAdapter(adapter); + return dataNode(dataNode); + } + + public Builder dataMap(DataMap dataMap) { + context.dataMap = Objects.requireNonNull(dataMap); + return this; + } + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/MergerToken.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/MergerToken.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/MergerToken.java new file mode 100644 index 0000000..5359b62 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/MergerToken.java @@ -0,0 +1,53 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + ****************************************************************/ +package org.apache.cayenne.dbsync.merge; + +import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory; + +/** + * Represents a minimal atomic synchronization operation between database and Cayenne model. + */ +public interface MergerToken { + + String getTokenName(); + + String getTokenValue(); + + /** + * The direction of this token. One of {@link MergeDirection#TO_DB} or + * {@link MergeDirection#TO_MODEL} + */ + MergeDirection getDirection(); + + /** + * Create a complimentary token with the reverse direction. AddColumn in one direction becomes + * DropColumn in the other direction. + * <p> + * Not all tokens are reversible. + */ + MergerToken createReverse(MergerTokenFactory factory); + + /** + * Executes synchronization operation. + * + * @param mergerContext operation context. + */ + void execute(MergerContext mergerContext); + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/ModelMergeDelegate.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/ModelMergeDelegate.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/ModelMergeDelegate.java new file mode 100644 index 0000000..13f6ea5 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/ModelMergeDelegate.java @@ -0,0 +1,62 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + ****************************************************************/ +package org.apache.cayenne.dbsync.merge; + +import org.apache.cayenne.map.DbAttribute; +import org.apache.cayenne.map.DbEntity; +import org.apache.cayenne.map.DbRelationship; +import org.apache.cayenne.map.ObjAttribute; +import org.apache.cayenne.map.ObjEntity; +import org.apache.cayenne.map.ObjRelationship; + +/** + * A interface used to tell about modifications performed on the model by + * {@link MergerToken} with {@link MergeDirection#TO_MODEL} + */ +public interface ModelMergeDelegate { + + public void dbEntityAdded(DbEntity ent); + + public void dbEntityRemoved(DbEntity ent); + + public void objEntityAdded(ObjEntity ent); + + public void objEntityRemoved(ObjEntity ent); + + public void dbAttributeAdded(DbAttribute att); + + public void dbAttributeRemoved(DbAttribute att); + + public void dbAttributeModified(DbAttribute att); + + public void objAttributeAdded(ObjAttribute att); + + public void objAttributeRemoved(ObjAttribute att); + + public void objAttributeModified(ObjAttribute att); + + public void dbRelationshipAdded(DbRelationship rel); + + public void dbRelationshipRemoved(DbRelationship rel); + + public void objRelationshipAdded(ObjRelationship rel); + + public void objRelationshipRemoved(ObjRelationship rel); + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/ProxyModelMergeDelegate.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/ProxyModelMergeDelegate.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/ProxyModelMergeDelegate.java new file mode 100644 index 0000000..ba12824 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/ProxyModelMergeDelegate.java @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.apache.cayenne.dbsync.merge; + +import org.apache.cayenne.map.DbAttribute; +import org.apache.cayenne.map.DbEntity; +import org.apache.cayenne.map.DbRelationship; +import org.apache.cayenne.map.ObjAttribute; +import org.apache.cayenne.map.ObjEntity; +import org.apache.cayenne.map.ObjRelationship; + +/** + * @since 4.0 + */ +public class ProxyModelMergeDelegate implements ModelMergeDelegate { + + private final ModelMergeDelegate delegate; + + public ProxyModelMergeDelegate(ModelMergeDelegate delegate) { + this.delegate = delegate; + } + + @Override + public void dbEntityAdded(DbEntity ent) { + delegate.dbEntityAdded(ent); + } + + @Override + public void dbEntityRemoved(DbEntity ent) { + delegate.dbEntityRemoved(ent); + } + + @Override + public void objEntityAdded(ObjEntity ent) { + delegate.objEntityAdded(ent); + } + + @Override + public void objEntityRemoved(ObjEntity ent) { + delegate.objEntityRemoved(ent); + } + + @Override + public void dbAttributeAdded(DbAttribute att) { + delegate.dbAttributeAdded(att); + } + + @Override + public void dbAttributeRemoved(DbAttribute att) { + delegate.dbAttributeRemoved(att); + } + + @Override + public void dbAttributeModified(DbAttribute att) { + delegate.dbAttributeModified(att); + } + + @Override + public void objAttributeAdded(ObjAttribute att) { + delegate.objAttributeAdded(att); + } + + @Override + public void objAttributeRemoved(ObjAttribute att) { + delegate.objAttributeRemoved(att); + } + + @Override + public void objAttributeModified(ObjAttribute att) { + delegate.objAttributeModified(att); + } + + @Override + public void dbRelationshipAdded(DbRelationship rel) { + delegate.dbRelationshipAdded(rel); + } + + @Override + public void dbRelationshipRemoved(DbRelationship rel) { + delegate.dbRelationshipRemoved(rel); + } + + @Override + public void objRelationshipAdded(ObjRelationship rel) { + delegate.objRelationshipAdded(rel); + } + + @Override + public void objRelationshipRemoved(ObjRelationship rel) { + delegate.objRelationshipRemoved(rel); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetAllowNullToDb.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetAllowNullToDb.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetAllowNullToDb.java new file mode 100644 index 0000000..c69fb6f --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetAllowNullToDb.java @@ -0,0 +1,57 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + ****************************************************************/ +package org.apache.cayenne.dbsync.merge; + +import java.util.Collections; +import java.util.List; + +import org.apache.cayenne.dba.DbAdapter; +import org.apache.cayenne.dba.QuotingStrategy; +import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory; +import org.apache.cayenne.map.DbAttribute; +import org.apache.cayenne.map.DbEntity; + +/** + * A {@link MergerToken} to add a "allow null" clause to a column. + * + */ +public class SetAllowNullToDb extends AbstractToDbToken.EntityAndColumn { + + public SetAllowNullToDb(DbEntity entity, DbAttribute column) { + super("Set Allow Null", entity, column); + } + + @Override + public List<String> createSql(DbAdapter adapter) { + StringBuilder sqlBuffer = new StringBuilder(); + QuotingStrategy context = adapter.getQuotingStrategy(); + sqlBuffer.append("ALTER TABLE "); + sqlBuffer.append(context.quotedFullyQualifiedName(getEntity())); + sqlBuffer.append(" ALTER COLUMN "); + sqlBuffer.append(context.quotedName(getColumn())); + sqlBuffer.append(" DROP NOT NULL"); + + return Collections.singletonList(sqlBuffer.toString()); + } + + public MergerToken createReverse(MergerTokenFactory factory) { + return factory.createSetNotNullToModel(getEntity(), getColumn()); + } + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetAllowNullToModel.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetAllowNullToModel.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetAllowNullToModel.java new file mode 100644 index 0000000..71a0937 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetAllowNullToModel.java @@ -0,0 +1,43 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + ****************************************************************/ +package org.apache.cayenne.dbsync.merge; + +import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory; +import org.apache.cayenne.map.DbAttribute; +import org.apache.cayenne.map.DbEntity; + +/** + * A {@link MergerToken} to set the mandatory field of a {@link DbAttribute} to false + * + */ +public class SetAllowNullToModel extends AbstractToModelToken.EntityAndColumn { + + public SetAllowNullToModel(DbEntity entity, DbAttribute column) { + super("Set Allow Null", entity, column); + } + + public MergerToken createReverse(MergerTokenFactory factory) { + return factory.createSetNotNullToDb(getEntity(), getColumn()); + } + + public void execute(MergerContext mergerContext) { + getColumn().setMandatory(false); + mergerContext.getModelMergeDelegate().dbAttributeModified(getColumn()); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetColumnTypeToDb.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetColumnTypeToDb.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetColumnTypeToDb.java new file mode 100644 index 0000000..74a0034 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetColumnTypeToDb.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.apache.cayenne.dbsync.merge; + +import java.util.Collections; +import java.util.List; + +import org.apache.cayenne.dba.DbAdapter; +import org.apache.cayenne.dba.JdbcAdapter; +import org.apache.cayenne.dba.QuotingStrategy; +import org.apache.cayenne.dba.TypesMapping; +import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory; +import org.apache.cayenne.map.DbAttribute; +import org.apache.cayenne.map.DbEntity; + +/** + * An {@link MergerToken} to use to set type, length and precision. + */ +public class SetColumnTypeToDb extends AbstractToDbToken.Entity { + + private DbAttribute columnOriginal; + private DbAttribute columnNew; + + public SetColumnTypeToDb(DbEntity entity, DbAttribute columnOriginal, DbAttribute columnNew) { + super("Set Column Type", entity); + this.columnOriginal = columnOriginal; + this.columnNew = columnNew; + } + + /** + * append the part of the token before the actual column data type + * @param context + */ + protected void appendPrefix(StringBuffer sqlBuffer, QuotingStrategy context) { + sqlBuffer.append("ALTER TABLE "); + sqlBuffer.append(context.quotedFullyQualifiedName(getEntity())); + sqlBuffer.append(" ALTER "); + sqlBuffer.append(context.quotedName(columnNew)); + sqlBuffer.append(" TYPE "); + } + + @Override + public List<String> createSql(DbAdapter adapter) { + StringBuffer sqlBuffer = new StringBuffer(); + appendPrefix(sqlBuffer, adapter.getQuotingStrategy()); + + sqlBuffer.append(JdbcAdapter.getType(adapter, columnNew)); + sqlBuffer.append(JdbcAdapter.sizeAndPrecision(adapter, columnNew)); + + return Collections.singletonList(sqlBuffer.toString()); + } + + @Override + public String getTokenValue() { + StringBuilder sb = new StringBuilder(); + sb.append(getEntity().getName()); + sb.append("."); + sb.append(columnNew.getName()); + + if (columnOriginal.getType() != columnNew.getType()) { + sb.append(" type: "); + sb.append(TypesMapping.getSqlNameByType(columnOriginal.getType())); + sb.append(" -> "); + sb.append(TypesMapping.getSqlNameByType(columnNew.getType())); + } + + if (columnOriginal.getMaxLength() != columnNew.getMaxLength()) { + sb.append(" maxLength: "); + sb.append(columnOriginal.getMaxLength()); + sb.append(" -> "); + sb.append(columnNew.getMaxLength()); + } + + if (columnOriginal.getAttributePrecision() != columnNew.getAttributePrecision()) { + sb.append(" precision: "); + sb.append(columnOriginal.getAttributePrecision()); + sb.append(" -> "); + sb.append(columnNew.getAttributePrecision()); + } + + if (columnOriginal.getScale() != columnNew.getScale()) { + sb.append(" scale: "); + sb.append(columnOriginal.getScale()); + sb.append(" -> "); + sb.append(columnNew.getScale()); + } + + return sb.toString(); + } + + public MergerToken createReverse(MergerTokenFactory factory) { + return factory.createSetColumnTypeToModel(getEntity(), columnNew, columnOriginal); + } + + public DbAttribute getColumnOriginal() { + return columnOriginal; + } + + public DbAttribute getColumnNew() { + return columnNew; + } + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetColumnTypeToModel.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetColumnTypeToModel.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetColumnTypeToModel.java new file mode 100644 index 0000000..262c3a6 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetColumnTypeToModel.java @@ -0,0 +1,102 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + ****************************************************************/ +package org.apache.cayenne.dbsync.merge; + +import org.apache.cayenne.dba.TypesMapping; +import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory; +import org.apache.cayenne.map.DbAttribute; +import org.apache.cayenne.map.DbEntity; + +/** + * A {@link MergerToken} that modifies one original {@link DbAttribute} to match another + * new {@link DbAttribute}s type, maxLength and precision. The name and mandatory fields + * are not modified by this token. + * + */ +public class SetColumnTypeToModel extends AbstractToModelToken.Entity { + + private DbAttribute columnOriginal; + private DbAttribute columnNew; + + public SetColumnTypeToModel(DbEntity entity, DbAttribute columnOriginal, + DbAttribute columnNew) { + super("Set Column Type", entity); + this.columnOriginal = columnOriginal; + this.columnNew = columnNew; + } + + public MergerToken createReverse(MergerTokenFactory factory) { + return factory.createSetColumnTypeToDb(getEntity(), columnNew, columnOriginal); + } + + public void execute(MergerContext mergerContext) { + columnOriginal.setType(columnNew.getType()); + columnOriginal.setMaxLength(columnNew.getMaxLength()); + columnOriginal.setAttributePrecision(columnNew.getAttributePrecision()); + columnOriginal.setScale(columnNew.getScale()); + mergerContext.getModelMergeDelegate().dbAttributeModified(columnOriginal); + } + + @Override + public String getTokenValue() { + StringBuilder sb = new StringBuilder(); + sb.append(getEntity().getName()); + sb.append("."); + sb.append(columnNew.getName()); + + if (columnOriginal.getType() != columnNew.getType()) { + sb.append(" type: "); + sb.append(TypesMapping.getSqlNameByType(columnOriginal.getType())); + sb.append(" -> "); + sb.append(TypesMapping.getSqlNameByType(columnNew.getType())); + } + + if (columnOriginal.getMaxLength() != columnNew.getMaxLength()) { + sb.append(" maxLength: "); + sb.append(columnOriginal.getMaxLength()); + sb.append(" -> "); + sb.append(columnNew.getMaxLength()); + } + + if (columnOriginal.getAttributePrecision() != columnNew.getAttributePrecision()) { + sb.append(" precision: "); + sb.append(columnOriginal.getAttributePrecision()); + sb.append(" -> "); + sb.append(columnNew.getAttributePrecision()); + } + + if (columnOriginal.getScale() != columnNew.getScale()) { + sb.append(" scale: "); + sb.append(columnOriginal.getScale()); + sb.append(" -> "); + sb.append(columnNew.getScale()); + } + + return sb.toString(); + } + + public DbAttribute getColumnOriginal() { + return columnOriginal; + } + + public DbAttribute getColumnNew() { + return columnNew; + } + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetNotNullToDb.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetNotNullToDb.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetNotNullToDb.java new file mode 100644 index 0000000..169ea34 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetNotNullToDb.java @@ -0,0 +1,51 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + ****************************************************************/ +package org.apache.cayenne.dbsync.merge; + +import java.util.Collections; +import java.util.List; + +import org.apache.cayenne.dba.DbAdapter; +import org.apache.cayenne.dba.QuotingStrategy; +import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory; +import org.apache.cayenne.map.DbAttribute; +import org.apache.cayenne.map.DbEntity; + +/** + * A {@link MergerToken} to add a "not null" clause to a column. + */ +public class SetNotNullToDb extends AbstractToDbToken.EntityAndColumn { + + public SetNotNullToDb(DbEntity entity, DbAttribute column) { + super("Set Not Null", entity, column); + } + + @Override + public List<String> createSql(DbAdapter adapter) { + QuotingStrategy context = adapter.getQuotingStrategy(); + + return Collections.singletonList("ALTER TABLE " + context.quotedFullyQualifiedName(getEntity()) + + " ALTER COLUMN " + context.quotedName(getColumn()) + " SET NOT NULL"); + } + + public MergerToken createReverse(MergerTokenFactory factory) { + return factory.createSetAllowNullToModel(getEntity(), getColumn()); + } + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetNotNullToModel.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetNotNullToModel.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetNotNullToModel.java new file mode 100644 index 0000000..9ae95b5 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetNotNullToModel.java @@ -0,0 +1,43 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + ****************************************************************/ +package org.apache.cayenne.dbsync.merge; + +import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory; +import org.apache.cayenne.map.DbAttribute; +import org.apache.cayenne.map.DbEntity; + +/** + * A {@link MergerToken} to set the mandatory field of a {@link DbAttribute} to true + * + */ +public class SetNotNullToModel extends AbstractToModelToken.EntityAndColumn { + + public SetNotNullToModel(DbEntity entity, DbAttribute column) { + super("Set Not Null", entity, column); + } + + public MergerToken createReverse(MergerTokenFactory factory) { + return factory.createSetAllowNullToDb(getEntity(), getColumn()); + } + + public void execute(MergerContext mergerContext) { + getColumn().setMandatory(true); + mergerContext.getModelMergeDelegate().dbAttributeModified(getColumn()); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetPrimaryKeyToDb.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetPrimaryKeyToDb.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetPrimaryKeyToDb.java new file mode 100644 index 0000000..8161b87 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetPrimaryKeyToDb.java @@ -0,0 +1,86 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + ****************************************************************/ +package org.apache.cayenne.dbsync.merge; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import org.apache.cayenne.dba.DbAdapter; +import org.apache.cayenne.dba.QuotingStrategy; +import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory; +import org.apache.cayenne.map.DbAttribute; +import org.apache.cayenne.map.DbEntity; + +public class SetPrimaryKeyToDb extends AbstractToDbToken.Entity { + + private Collection<DbAttribute> primaryKeyOriginal; + private Collection<DbAttribute> primaryKeyNew; + private String detectedPrimaryKeyName; + + public SetPrimaryKeyToDb(DbEntity entity, Collection<DbAttribute> primaryKeyOriginal, + Collection<DbAttribute> primaryKeyNew, String detectedPrimaryKeyName) { + super("Set Primary Key", entity); + + this.primaryKeyOriginal = primaryKeyOriginal; + this.primaryKeyNew = primaryKeyNew; + this.detectedPrimaryKeyName = detectedPrimaryKeyName; + } + + @Override + public List<String> createSql(DbAdapter adapter) { + List<String> sqls = new ArrayList<String>(); + if (!primaryKeyOriginal.isEmpty()) { + appendDropOriginalPrimaryKeySQL(adapter, sqls); + } + appendAddNewPrimaryKeySQL(adapter, sqls); + return sqls; + } + + protected void appendDropOriginalPrimaryKeySQL(DbAdapter adapter, List<String> sqls) { + if (detectedPrimaryKeyName == null) { + return; + } + sqls.add("ALTER TABLE " + adapter.getQuotingStrategy().quotedFullyQualifiedName(getEntity()) + + " DROP CONSTRAINT " + detectedPrimaryKeyName); + } + + protected void appendAddNewPrimaryKeySQL(DbAdapter adapter, List<String> sqls) { + QuotingStrategy quotingStrategy = adapter.getQuotingStrategy(); + + StringBuilder sql = new StringBuilder(); + sql.append("ALTER TABLE "); + sql.append(quotingStrategy.quotedFullyQualifiedName(getEntity())); + sql.append(" ADD PRIMARY KEY ("); + for (Iterator<DbAttribute> it = primaryKeyNew.iterator(); it.hasNext();) { + sql.append(quotingStrategy.quotedName(it.next())); + if (it.hasNext()) { + sql.append(", "); + } + } + sql.append(")"); + sqls.add(sql.toString()); + } + + public MergerToken createReverse(MergerTokenFactory factory) { + return factory.createSetPrimaryKeyToModel(getEntity(), primaryKeyNew, primaryKeyOriginal, + detectedPrimaryKeyName); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetPrimaryKeyToModel.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetPrimaryKeyToModel.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetPrimaryKeyToModel.java new file mode 100644 index 0000000..6785a2f --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetPrimaryKeyToModel.java @@ -0,0 +1,78 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + ****************************************************************/ +package org.apache.cayenne.dbsync.merge; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory; +import org.apache.cayenne.map.DbAttribute; +import org.apache.cayenne.map.DbEntity; +import org.apache.cayenne.map.event.AttributeEvent; + +public class SetPrimaryKeyToModel extends AbstractToModelToken.Entity { + + private Collection<DbAttribute> primaryKeyOriginal; + private Collection<DbAttribute> primaryKeyNew; + private String detectedPrimaryKeyName; + private Set<String> primaryKeyNewAttributeNames = new HashSet<String>(); + + public SetPrimaryKeyToModel(DbEntity entity, + Collection<DbAttribute> primaryKeyOriginal, + Collection<DbAttribute> primaryKeyNew, String detectedPrimaryKeyName) { + super("Set Primary Key", entity); + + this.primaryKeyOriginal = primaryKeyOriginal; + this.primaryKeyNew = primaryKeyNew; + this.detectedPrimaryKeyName = detectedPrimaryKeyName; + + for (DbAttribute attr : primaryKeyNew) { + primaryKeyNewAttributeNames.add(attr.getName().toUpperCase()); + } + } + + public MergerToken createReverse(MergerTokenFactory factory) { + return factory.createSetPrimaryKeyToDb( + getEntity(), + primaryKeyNew, + primaryKeyOriginal, + detectedPrimaryKeyName); + } + + public void execute(MergerContext mergerContext) { + DbEntity e = getEntity(); + + for (DbAttribute attr : e.getAttributes()) { + + boolean wasPrimaryKey = attr.isPrimaryKey(); + boolean willBePrimaryKey = primaryKeyNewAttributeNames.contains(attr + .getName() + .toUpperCase()); + + if (wasPrimaryKey != willBePrimaryKey) { + attr.setPrimaryKey(willBePrimaryKey); + e.dbAttributeChanged(new AttributeEvent(this, attr, e)); + mergerContext.getModelMergeDelegate().dbAttributeModified(attr); + } + + } + + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetValueForNullToDb.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetValueForNullToDb.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetValueForNullToDb.java new file mode 100644 index 0000000..1ffdd49 --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/SetValueForNullToDb.java @@ -0,0 +1,47 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + ****************************************************************/ +package org.apache.cayenne.dbsync.merge; + +import java.util.List; + +import org.apache.cayenne.dba.DbAdapter; +import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory; +import org.apache.cayenne.map.DbAttribute; +import org.apache.cayenne.map.DbEntity; + + +public class SetValueForNullToDb extends AbstractToDbToken.EntityAndColumn { + + private ValueForNullProvider valueForNullProvider; + + public SetValueForNullToDb(DbEntity entity, DbAttribute column, ValueForNullProvider valueForNullProvider) { + super("Set value for null", entity, column); + this.valueForNullProvider = valueForNullProvider; + } + + @Override + public List<String> createSql(DbAdapter adapter) { + return valueForNullProvider.createSql(getEntity(), getColumn()); + } + + public MergerToken createReverse(MergerTokenFactory factory) { + return new DummyReverseToken(this); + } + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/ValueForNullProvider.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/ValueForNullProvider.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/ValueForNullProvider.java new file mode 100644 index 0000000..a07efff --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/ValueForNullProvider.java @@ -0,0 +1,42 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + ****************************************************************/ +package org.apache.cayenne.dbsync.merge; + +import java.util.List; + +import org.apache.cayenne.map.DbAttribute; +import org.apache.cayenne.map.DbEntity; + +/** + * Class that will be used to set value for null on not + * null columns + */ +public interface ValueForNullProvider { + + /** + * @return true if there exist a value that should be inserted for null values + */ + public boolean hasValueFor(DbEntity entity, DbAttribute column); + + /** + * @return a {@link List} of sql to set value for null + */ + public List<String> createSql(DbEntity entity, DbAttribute column); + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/factory/DB2MergerTokenFactory.java ---------------------------------------------------------------------- diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/factory/DB2MergerTokenFactory.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/factory/DB2MergerTokenFactory.java new file mode 100644 index 0000000..586a5cd --- /dev/null +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/factory/DB2MergerTokenFactory.java @@ -0,0 +1,47 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + ****************************************************************/ +package org.apache.cayenne.dbsync.merge.factory; + +import org.apache.cayenne.dba.QuotingStrategy; +import org.apache.cayenne.dbsync.merge.MergerToken; +import org.apache.cayenne.dbsync.merge.SetColumnTypeToDb; +import org.apache.cayenne.map.DbAttribute; +import org.apache.cayenne.map.DbEntity; + +public class DB2MergerTokenFactory extends DefaultMergerTokenFactory { + + @Override + public MergerToken createSetColumnTypeToDb( + final DbEntity entity, + DbAttribute columnOriginal, + final DbAttribute columnNew) { + + return new SetColumnTypeToDb(entity, columnOriginal, columnNew) { + + @Override + protected void appendPrefix(StringBuffer sqlBuffer, QuotingStrategy context) { + sqlBuffer.append("ALTER TABLE "); + sqlBuffer.append(context.quotedFullyQualifiedName(entity)); + sqlBuffer.append(" ALTER COLUMN "); + sqlBuffer.append(context.quotedName(columnNew)); + sqlBuffer.append(" SET DATA TYPE "); + } + }; + } +}