<commit_before>/**
 * 
 */
package org.concord.otrunk.datamodel;

import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.concord.framework.otrunk.OTID;
import org.concord.framework.otrunk.OTXMLString;
import org.concord.otrunk.overlay.CompositeDataObject;

/**
 * @author scott
 *
 */
public class Copier 
{
	OTDatabase destinationDb;
	OTDatabase sourceDb;
	OTDataObject root;
	
	ArrayList<CopyEntry> toBeCopied;
	private OTDataList orphanList;
	private OTExternalIDProvider idProvider;
	private OTDataObjectFinder dataObjectFinder;
	private boolean onlyModifications;

    private static class CopyEntry
    {    	
    	OTDataObject original;
    	int maxDepth;
    	OTDataObject copy;
    	
    	public CopyEntry(OTDataObject original, int maxDepth, OTDataObject copy)
    	{
    		this.original = original;
    		this.maxDepth = maxDepth;
    		this.copy = copy;
    	}    	
    }
	
	public Copier(OTDatabase sourceDb, OTDatabase destinationDb, OTDataList orphanDataList, 
		OTExternalIDProvider idProvider, OTDataObjectFinder dataObjectFinder, boolean onlyModifications)
	{
		this.destinationDb = destinationDb;
		this.sourceDb = sourceDb;
		this.toBeCopied = new ArrayList<CopyEntry>();
		this.orphanList = orphanDataList;
		this.idProvider = idProvider;
		this.dataObjectFinder = dataObjectFinder;
		this.onlyModifications = onlyModifications;
	}
	
	/**
	 * This returns any object in the toBeCopiedList which has the same
	 * otid as the one we're passing in. If idProvider == null, this may
	 * fail to return an object because it will be comparing a globalid to
	 * a transient id.
	 * 
	 * @param originalId
	 * @return
	 */
    private CopyEntry getCopyEntry(OTID originalId)
    {
    	for(int i=0; i<toBeCopied.size(); i++){
    		CopyEntry entry = toBeCopied.get(i);
    		String entryObjectExternalID;
    		String originalExternalID;
    		
    		if (idProvider != null){
        		entryObjectExternalID = idProvider.getExternalID(entry.original.getGlobalId());
        		originalExternalID = idProvider.getExternalID(originalId);
    		} else {
    			entryObjectExternalID = entry.original.getGlobalId().toString();
    			originalExternalID = originalId.toString();
    		}
    		
    		if(entryObjectExternalID.equals(originalExternalID)){
    			return entry;
    		}
    	}
    	return null;
    }
    
     private Object handleChild(Object child, int maxDepth) 
    throws Exception
    {
		// check if the value is an OTID
		// and if we have more depth to go
		if(child instanceof OTID && (maxDepth == -1 || maxDepth > 0)){
			// check if this id has already been seen
			CopyEntry itemCopyEntry = getCopyEntry((OTID)child);
			
			if(itemCopyEntry == null){
				OTDataObject itemObj = 
					sourceDb.getOTDataObject(root, (OTID)child);
				if(itemObj == null){
					itemObj = dataObjectFinder.findDataObject((OTID)child);
					if(itemObj == null) {
						throw new IllegalStateException("Can't find child id: " + child);
					}
				}
				
				if (onlyModifications && itemObj instanceof CompositeDataObject && ! ((CompositeDataObject) itemObj).isModified()) {
					// don't copy the object if it's not modified and onlyModifications is true
					// instead, include an object reference to the original
					OTID itemID = itemObj.getGlobalId();
					if (itemID instanceof OTTransientMapID) {
						itemID = ((OTTransientMapID)itemID).getMappedId();
					}
					itemCopyEntry = new CopyEntry(itemObj, -1, destinationDb.getOTDataObject(root, itemID));
				} else {
    				int copyMaxDepth = -1;
    				OTDataObject itemCopy = 
    					destinationDb.createDataObject(itemObj.getType());
    				if(maxDepth != -1){
    					copyMaxDepth = maxDepth-1; 
    				}
    				itemCopyEntry = new CopyEntry(itemObj, copyMaxDepth, itemCopy);
    				toBeCopied.add(itemCopyEntry);
				}
			} else {
				// we should not return here, it should just use the copy's global id
			}

			// put this new list object 
			child = itemCopyEntry.copy.getGlobalId();
		}<commit_msg>Fixes to the onlyModifications version of the copy code. Instead of doing a full copy of a modified object, it requests the object from the destination db in effect copying only the modified values.<commit_after>/**
 * 
 */
package org.concord.otrunk.datamodel;

import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.concord.framework.otrunk.OTID;
import org.concord.framework.otrunk.OTXMLString;
import org.concord.otrunk.overlay.CompositeDataObject;

/**
 * @author scott
 *
 */
public class Copier 
{
	OTDatabase destinationDb;
	OTDatabase sourceDb;
	OTDataObject root;
	
	ArrayList<CopyEntry> toBeCopied;
	private OTDataList orphanList;
	private OTExternalIDProvider idProvider;
	private OTDataObjectFinder dataObjectFinder;
	private boolean onlyModifications;

    private static class CopyEntry
    {    	
    	OTDataObject original;
    	int maxDepth;
    	OTDataObject copy;
    	
    	public CopyEntry(OTDataObject original, int maxDepth, OTDataObject copy)
    	{
    		this.original = original;
    		this.maxDepth = maxDepth;
    		this.copy = copy;
    	}    	
    }
	
	public Copier(OTDatabase sourceDb, OTDatabase destinationDb, OTDataList orphanDataList, 
		OTExternalIDProvider idProvider, OTDataObjectFinder dataObjectFinder, boolean onlyModifications)
	{
		this.destinationDb = destinationDb;
		this.sourceDb = sourceDb;
		this.toBeCopied = new ArrayList<CopyEntry>();
		this.orphanList = orphanDataList;
		this.idProvider = idProvider;
		this.dataObjectFinder = dataObjectFinder;
		this.onlyModifications = onlyModifications;
	}
	
	/**
	 * This returns any object in the toBeCopiedList which has the same
	 * otid as the one we're passing in. If idProvider == null, this may
	 * fail to return an object because it will be comparing a globalid to
	 * a transient id.
	 * 
	 * @param originalId
	 * @return
	 */
    private CopyEntry getCopyEntry(OTID originalId)
    {
    	for(int i=0; i<toBeCopied.size(); i++){
    		CopyEntry entry = toBeCopied.get(i);
    		String entryObjectExternalID;
    		String originalExternalID;
    		
    		if (idProvider != null){
        		entryObjectExternalID = idProvider.getExternalID(entry.original.getGlobalId());
        		originalExternalID = idProvider.getExternalID(originalId);
    		} else {
    			entryObjectExternalID = entry.original.getGlobalId().toString();
    			originalExternalID = originalId.toString();
    		}
    		
    		if(entryObjectExternalID.equals(originalExternalID)){
    			return entry;
    		}
    	}
    	return null;
    }
    
     private Object handleChild(Object child, int maxDepth) 
    throws Exception
    {
		// check if the value is an OTID
		// and if we have more depth to go
		if(child instanceof OTID && (maxDepth == -1 || maxDepth > 0)){
			// check if this id has already been seen
			CopyEntry itemCopyEntry = getCopyEntry((OTID)child);
			
			if(itemCopyEntry == null){
				OTDataObject itemObj = 
					sourceDb.getOTDataObject(root, (OTID)child);
				if(itemObj == null){
					itemObj = dataObjectFinder.findDataObject((OTID)child);
					if(itemObj == null) {
						throw new IllegalStateException("Can't find child id: " + child);
					}
				}
				
				OTID itemID = itemObj.getGlobalId();
				if (itemID instanceof OTTransientMapID) {
					itemID = ((OTTransientMapID)itemID).getMappedId();
				}
				System.err.println("Copying object: " + itemObj.getGlobalId());
				if (onlyModifications && itemObj instanceof CompositeDataObject && ! ((CompositeDataObject) itemObj).isModified()) {
					// System.err.println("Not modified: only a reference");
					// don't copy the object if it's not modified and onlyModifications is true
					// instead, include an object reference to the original
					itemCopyEntry = new CopyEntry(itemObj, -1, destinationDb.getOTDataObject(root, itemID));
				} else {
					OTDataObject itemCopy;
					if (onlyModifications && itemObj instanceof CompositeDataObject && ((CompositeDataObject) itemObj).isModified() && (((CompositeDataObject) itemObj).getActiveDeltaObject() != null)) {
						// System.err.println("Modified: changed copy");
						// if the object has an active delta object, then it's only modified (not newly created) so if we request the data object from the destination db, it will handle creating the deltamap for us
						itemCopy = destinationDb.getOTDataObject(root, itemID);
					} else {
						// System.err.println("Modified: full copy");
						// the object is newly created *or* we're forcing a full copy
						itemCopy = destinationDb.createDataObject(itemObj.getType());
					}
    				int copyMaxDepth = -1;
    				
    				if(maxDepth != -1){
    					copyMaxDepth = maxDepth-1; 
    				}
    				itemCopyEntry = new CopyEntry(itemObj, copyMaxDepth, itemCopy);
    				toBeCopied.add(itemCopyEntry);
				}
			} else {
				// we should not return here, it should just use the copy's global id
			}

			// put this new list object 
			child = itemCopyEntry.copy.getGlobalId();
		}
{'fraction_non_alphanumeric': 0.09245742092457421, 'fraction_numerical': 0.0015483300154833, 'mean_word_length': 3.2455399061032866, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1556058', 'n_tokens_mistral': 3088, 'n_tokens_neox': 2717, 'n_words': 717}