content: /*****************************************************************
   *   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
   *
   *    https://www.apache.org/licenses/LICENSE-2.0
   *
   *  Unless required by applicable law or agreed to in writing,
   *  software distributed under the License is distributed on an
   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   *  KIND, either express or implied.  See the License for the
   *  specific language governing permissions and limitations
   *  under the License.
   ****************************************************************/
  package org.apache.cayenne.dbsync.merge;
  
  import static org.junit.Assert.assertFalse;
  import static org.junit.Assert.assertNotNull;
  import static org.junit.Assert.assertNull;
  
  import java.sql.Types;
  
  import org.apache.cayenne.GenericPersistentObject;
  import org.apache.cayenne.access.DataContext;
  import org.apache.cayenne.di.Inject;
  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;
  import org.junit.Test;
  
  public class MergerFactoryIT extends MergeCase {
  
      @Inject
      private DataContext context;
  
      @Test
      public void testAddAndDropColumnToDb() throws Exception {
          DbEntity dbEntity = map.getDbEntity("PAINTING");
          assertNotNull(dbEntity);
  
          // create and add new column to model and db
          DbAttribute column = new DbAttribute("NEWCOL1", Types.VARCHAR, dbEntity);
  
          column.setMandatory(false);
          column.setMaxLength(10);
          dbEntity.addAttribute(column);
          assertTokensAndExecute(1, 0);
  
          // try merge once more to check that is was merged
          assertTokensAndExecute(0, 0);
  
          // remove it from model and db
          dbEntity.removeAttribute(column.getName());
          assertTokensAndExecute(1, 0);
          assertTokensAndExecute(0, 0);
      }
  
      @Test
      public void testChangeVarcharSizeToDb() throws Exception {
          DbEntity dbEntity = map.getDbEntity("PAINTING");
          assertNotNull(dbEntity);
  
          // create and add new column to model and db
          DbAttribute column = new DbAttribute("NEWCOL2", Types.VARCHAR, dbEntity);
  
          column.setMandatory(false);
          column.setMaxLength(10);
          dbEntity.addAttribute(column);
          assertTokensAndExecute(1, 0);
  
          // check that is was merged
          assertTokensAndExecute(0, 0);
  
          // change size
          column.setMaxLength(20);
  
          // merge to db
          assertTokensAndExecute(1, 0);
  
          // check that is was merged
          assertTokensAndExecute(0, 0);
  
          // clean up
          dbEntity.removeAttribute(column.getName());
          assertTokensAndExecute(1, 0);
          assertTokensAndExecute(0, 0);
      }
  
      @Test
      public void testMultipleTokensToDb() throws Exception {
          DbEntity dbEntity = map.getDbEntity("PAINTING");
          assertNotNull(dbEntity);
  
          DbAttribute column1 = new DbAttribute("NEWCOL3", Types.VARCHAR, dbEntity);
          column1.setMandatory(false);
          column1.setMaxLength(10);
          dbEntity.addAttribute(column1);
          DbAttribute column2 = new DbAttribute("NEWCOL4", Types.VARCHAR, dbEntity);
          column2.setMandatory(false);
          column2.setMaxLength(10);
          dbEntity.addAttribute(column2);
  
          assertTokensAndExecute(2, 0);
  
          // check that is was merged
          assertTokensAndExecute(0, 0);
  
          // change size
          column1.setMaxLength(20);
          column2.setMaxLength(30);
  
          // merge to db
          assertTokensAndExecute(2, 0);
  
          // check that is was merged
          assertTokensAndExecute(0, 0);
  
          // clean up
          dbEntity.removeAttribute(column1.getName());
          dbEntity.removeAttribute(column2.getName());
          assertTokensAndExecute(2, 0);
          assertTokensAndExecute(0, 0);
      }
  
      @Test
      public void testAddTableToDb() throws Exception {
          dropTableIfPresent("NEW_TABLE");
  
          assertTokensAndExecute(0, 0);
  
          DbEntity dbEntity = new DbEntity("NEW_TABLE");
  
          DbAttribute column1 = new DbAttribute("ID", Types.INTEGER, dbEntity);
          column1.setMandatory(true);
          column1.setPrimaryKey(true);
          dbEntity.addAttribute(column1);
  
          DbAttribute column2 = new DbAttribute("NAME", Types.VARCHAR, dbEntity);
          column2.setMaxLength(10);
          column2.setMandatory(false);
          dbEntity.addAttribute(column2);
  
          map.addDbEntity(dbEntity);
  
          assertTokensAndExecute(1, 0);
          assertTokensAndExecute(0, 0);
  
          ObjEntity objEntity = new ObjEntity("NewTable");
          objEntity.setDbEntity(dbEntity);
          ObjAttribute oatr1 = new ObjAttribute("name");
          oatr1.setDbAttributePath(column2.getName());
          oatr1.setType("java.lang.String");
          objEntity.addAttribute(oatr1);
          map.addObjEntity(objEntity);
  
          for (int i = 0; i < 5; i++) {
              GenericPersistentObject dao = (GenericPersistentObject) context.newObject(objEntity
                      .getName());
              dao.writeProperty(oatr1.getName(), "test " + i);
          }
          context.commitChanges();
  
          // clear up
          map.removeObjEntity(objEntity.getName(), true);
          map.removeDbEntity(dbEntity.getName(), true);
          resolver.refreshMappingCache();
          assertNull(map.getObjEntity(objEntity.getName()));
          assertNull(map.getDbEntity(dbEntity.getName()));
          assertFalse(map.getDbEntities().contains(dbEntity));
  
          assertTokensAndExecute(1, 0);
          assertTokensAndExecute(0, 0);
      }
  
      @Test
      public void testAddForeignKeyWithTable() throws Exception {
          dropTableIfPresent("NEW_TABLE");
  
          assertTokensAndExecute(0, 0);
  
          DbEntity dbEntity = new DbEntity("NEW_TABLE");
  
          attr(dbEntity, "ID", Types.INTEGER, true, true);
          attr(dbEntity, "NAME", Types.VARCHAR, false, false).setMaxLength(10);
          attr(dbEntity, "ARTIST_ID", Types.BIGINT, false, false);
  
          map.addDbEntity(dbEntity);
  
          DbEntity artistDbEntity = map.getDbEntity("ARTIST");
          assertNotNull(artistDbEntity);
  
          // relation from new_table to artist
          DbRelationship r1 = new DbRelationship("toArtistR1");
          r1.setSourceEntity(dbEntity);
          r1.setTargetEntityName(artistDbEntity);
          r1.setToMany(false);
          r1.addJoin(new DbJoin(r1, "ARTIST_ID", "ARTIST_ID"));
          dbEntity.addRelationship(r1);
  
          // relation from artist to new_table
          DbRelationship r2 = new DbRelationship("toNewTableR2");
          r2.setSourceEntity(artistDbEntity);
          r2.setTargetEntityName(dbEntity);
          r2.setToMany(true);
          r2.addJoin(new DbJoin(r2, "ARTIST_ID", "ARTIST_ID"));
          artistDbEntity.addRelationship(r2);
  
          assertTokensAndExecute(2, 0);
          assertTokensAndExecute(0, 0);
  
          // remove relationships
          dbEntity.removeRelationship(r1.getName());
          artistDbEntity.removeRelationship(r2.getName());
          resolver.refreshMappingCache();
          /*
           * Db -Rel 'toArtistR1' - NEW_TABLE 1 -> 1 ARTIST"
  r2 =     * Db -Rel 'toNewTableR2' - ARTIST 1 -> * NEW_TABLE" -- Not generated any more
           * */
          assertTokensAndExecute(1, 0);
          assertTokensAndExecute(0, 0);
  
          // clear up
          // map.removeObjEntity(objEntity.getName(), true);
          map.removeDbEntity(dbEntity.getName(), true);
          resolver.refreshMappingCache();
          // assertNull(map.getObjEntity(objEntity.getName()));
          assertNull(map.getDbEntity(dbEntity.getName()));
          assertFalse(map.getDbEntities().contains(dbEntity));
  
          assertTokensAndExecute(1, 0);
          assertTokensAndExecute(0, 0);
      }
  
      @Test
      public void testAddForeignKeyAfterTable() throws Exception {
          dropTableIfPresent("NEW_TABLE");
  
          assertTokensAndExecute(0, 0);
  
          DbEntity dbEntity = new DbEntity("NEW_TABLE");
          attr(dbEntity, "ID", Types.INTEGER, true, true);
          attr(dbEntity, "NAME", Types.VARCHAR, false, false).setMaxLength(10);
          attr(dbEntity, "ARTIST_ID", Types.BIGINT, false, false);
  
          map.addDbEntity(dbEntity);
  
          DbEntity artistDbEntity = map.getDbEntity("ARTIST");
          assertNotNull(artistDbEntity);
  
          assertTokensAndExecute(1, 0);
          assertTokensAndExecute(0, 0);
  
          // relation from new_table to artist
          DbRelationship r1 = new DbRelationship("toArtistR1");
          r1.setSourceEntity(dbEntity);
          r1.setTargetEntityName(artistDbEntity);
          r1.setToMany(false);
          r1.addJoin(new DbJoin(r1, "ARTIST_ID", "ARTIST_ID"));
          dbEntity.addRelationship(r1);
  
          // relation from artist to new_table
          DbRelationship r2 = new DbRelationship("toNewTableR2");
          r2.setSourceEntity(artistDbEntity);
          r2.setTargetEntityName(dbEntity);
          r2.setToMany(true);
          r2.addJoin(new DbJoin(r2, "ARTIST_ID", "ARTIST_ID"));
          artistDbEntity.addRelationship(r2);
  
          assertTokensAndExecute(1, 0);
          assertTokensAndExecute(0, 0);
  
          // remove relationships
          dbEntity.removeRelationship(r1.getName());
          artistDbEntity.removeRelationship(r2.getName());
          resolver.refreshMappingCache();
          /*
          * Add Relationship ARTIST->NEW_TABLE To Model -- Not generated any more
          * Drop Relationship NEW_TABLE->ARTIST To DB
          * */
          assertTokensAndExecute(1, 0);
          assertTokensAndExecute(0, 0);
  
          // clear up
          // map.removeObjEntity(objEntity.getName(), true);
          map.removeDbEntity(dbEntity.getName(), true);
          resolver.refreshMappingCache();
          // assertNull(map.getObjEntity(objEntity.getName()));
          assertNull(map.getDbEntity(dbEntity.getName()));
          assertFalse(map.getDbEntities().contains(dbEntity));
  
          assertTokensAndExecute(1, 0);
          assertTokensAndExecute(0, 0);
      }
  
      private static DbAttribute attr(DbEntity dbEntity, String name, int type, boolean mandatory, boolean primaryKey) {
          DbAttribute column1 = new DbAttribute(name, type, dbEntity);
          column1.setMandatory(mandatory);
          column1.setPrimaryKey(primaryKey);
  
          dbEntity.addAttribute(column1);
          return column1;
      }
  }
  