Make cross() function work for all columns (#2456)
* fix #1950 * migrate from join to lookup * reformat
This commit is contained in:
parent
cff88e6267
commit
9ad3b1080f
@ -1,187 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2010, Google Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
package com.google.refine;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.google.refine.expr.ExpressionUtils;
|
||||
import com.google.refine.expr.HasFieldsListImpl;
|
||||
import com.google.refine.expr.WrappedRow;
|
||||
import com.google.refine.model.Column;
|
||||
import com.google.refine.model.Project;
|
||||
import com.google.refine.model.Row;
|
||||
import com.google.refine.util.JoinException;
|
||||
|
||||
public class InterProjectModel {
|
||||
static public class ProjectJoin {
|
||||
final public long fromProjectID;
|
||||
final public String fromProjectColumnName;
|
||||
final public long toProjectID;
|
||||
final public String toProjectColumnName;
|
||||
|
||||
final public Map<Object, List<Integer>> valueToRowIndices =
|
||||
new HashMap<Object, List<Integer>>();
|
||||
|
||||
ProjectJoin(
|
||||
long fromProjectID,
|
||||
String fromProjectColumnName,
|
||||
long toProjectID,
|
||||
String toProjectColumnName
|
||||
) {
|
||||
this.fromProjectID = fromProjectID;
|
||||
this.fromProjectColumnName = fromProjectColumnName;
|
||||
this.toProjectID = toProjectID;
|
||||
this.toProjectColumnName = toProjectColumnName;
|
||||
}
|
||||
|
||||
public HasFieldsListImpl getRows(Object value) {
|
||||
if (ExpressionUtils.isNonBlankData(value) && valueToRowIndices.containsKey(value)) {
|
||||
Project toProject = ProjectManager.singleton.getProject(toProjectID);
|
||||
if (toProject != null) {
|
||||
HasFieldsListImpl rows = new HasFieldsListImpl();
|
||||
for (Integer r : valueToRowIndices.get(value)) {
|
||||
Row row = toProject.rows.get(r);
|
||||
rows.add(new WrappedRow(toProject, r, row));
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected Map<String, ProjectJoin> _joins = new HashMap<String, ProjectJoin>();
|
||||
|
||||
/**
|
||||
* Compute the ProjectJoin based on combination key, return the cached one from the HashMap if already computed
|
||||
*
|
||||
* @param fromProject
|
||||
* @param fromColumn
|
||||
* @param toProject
|
||||
* @param toColumn
|
||||
* @return
|
||||
*/
|
||||
public ProjectJoin getJoin(Long fromProject, String fromColumn, Long toProject, String toColumn) throws JoinException {
|
||||
String key = fromProject + ";" + fromColumn + ";" + toProject + ";" + toColumn;
|
||||
if (!_joins.containsKey(key)) {
|
||||
ProjectJoin join = new ProjectJoin(
|
||||
fromProject,
|
||||
fromColumn,
|
||||
toProject,
|
||||
toColumn
|
||||
);
|
||||
|
||||
computeJoin(join);
|
||||
|
||||
synchronized (_joins) {
|
||||
_joins.put(key, join);
|
||||
}
|
||||
}
|
||||
|
||||
return _joins.get(key);
|
||||
}
|
||||
|
||||
public void flushJoinsInvolvingProject(long projectID) {
|
||||
synchronized (_joins) {
|
||||
for (Iterator<Entry<String, ProjectJoin>> it = _joins.entrySet().iterator(); it.hasNext();) {
|
||||
Entry<String, ProjectJoin> entry = it.next();
|
||||
ProjectJoin join = entry.getValue();
|
||||
if (join.fromProjectID == projectID || join.toProjectID == projectID) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void flushJoinsInvolvingProjectColumn(long projectID, String columnName) {
|
||||
synchronized (_joins) {
|
||||
for (Iterator<Entry<String, ProjectJoin>> it = _joins.entrySet().iterator(); it.hasNext();) {
|
||||
Entry<String, ProjectJoin> entry = it.next();
|
||||
ProjectJoin join = entry.getValue();
|
||||
if (join.fromProjectID == projectID && join.fromProjectColumnName.equals(columnName) ||
|
||||
join.toProjectID == projectID && join.toProjectColumnName.equals(columnName)) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void computeJoin(ProjectJoin join) throws JoinException {
|
||||
if (join.fromProjectID < 0 || join.toProjectID < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Project fromProject = ProjectManager.singleton.getProject(join.fromProjectID);
|
||||
ProjectMetadata fromProjectMD = ProjectManager.singleton.getProjectMetadata(join.fromProjectID);
|
||||
Project toProject = ProjectManager.singleton.getProject(join.toProjectID);
|
||||
ProjectMetadata toProjectMD = ProjectManager.singleton.getProjectMetadata(join.toProjectID);
|
||||
|
||||
// split this test to check each one and throw an appropriate error
|
||||
if (fromProject == null || toProject == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Column fromColumn = fromProject.columnModel.getColumnByName(join.fromProjectColumnName);
|
||||
Column toColumn = toProject.columnModel.getColumnByName(join.toProjectColumnName);
|
||||
if (fromColumn == null) {
|
||||
throw new JoinException("Unable to find column " + join.fromProjectColumnName + " in project " + fromProjectMD.getName());
|
||||
}
|
||||
if (toColumn == null) {
|
||||
throw new JoinException("Unable to find column " + join.toProjectColumnName + " in project " + toProjectMD.getName());
|
||||
}
|
||||
|
||||
for (Row fromRow : fromProject.rows) {
|
||||
Object value = fromRow.getCellValue(fromColumn.getCellIndex());
|
||||
if (ExpressionUtils.isNonBlankData(value) && !join.valueToRowIndices.containsKey(value)) {
|
||||
join.valueToRowIndices.put(value, new ArrayList<Integer>());
|
||||
}
|
||||
}
|
||||
|
||||
int count = toProject.rows.size();
|
||||
for (int r = 0; r < count; r++) {
|
||||
Row toRow = toProject.rows.get(r);
|
||||
|
||||
Object value = toRow.getCellValue(toColumn.getCellIndex());
|
||||
if (ExpressionUtils.isNonBlankData(value) && join.valueToRowIndices.containsKey(value)) {
|
||||
join.valueToRowIndices.get(value).add(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
124
main/src/com/google/refine/LookupCacheManager.java
Normal file
124
main/src/com/google/refine/LookupCacheManager.java
Normal file
@ -0,0 +1,124 @@
|
||||
package com.google.refine;
|
||||
|
||||
import com.google.refine.expr.ExpressionUtils;
|
||||
import com.google.refine.expr.HasFieldsListImpl;
|
||||
import com.google.refine.expr.WrappedRow;
|
||||
import com.google.refine.model.Column;
|
||||
import com.google.refine.model.Project;
|
||||
import com.google.refine.model.Row;
|
||||
import com.google.refine.util.LookupException;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Manage the cache of project's lookups.
|
||||
*
|
||||
* @author Lu Liu
|
||||
*/
|
||||
public class LookupCacheManager {
|
||||
|
||||
protected final Map<String, ProjectLookup> _lookups = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Computes the ProjectLookup based on combination key,
|
||||
* returns the cached one from the HashMap if already computed.
|
||||
*
|
||||
* @param targetProject the project to look up
|
||||
* @param targetColumn the column of the target project to look up
|
||||
* @return a {@link ProjectLookup} instance of the lookup result
|
||||
*/
|
||||
public ProjectLookup getLookup(long targetProject, String targetColumn) throws LookupException {
|
||||
String key = targetProject + ";" + targetColumn;
|
||||
if (!_lookups.containsKey(key)) {
|
||||
ProjectLookup lookup = new ProjectLookup(targetProject, targetColumn);
|
||||
computeLookup(lookup);
|
||||
|
||||
synchronized (_lookups) {
|
||||
_lookups.put(key, lookup);
|
||||
}
|
||||
}
|
||||
|
||||
return _lookups.get(key);
|
||||
}
|
||||
|
||||
public void flushLookupsInvolvingProject(long projectID) {
|
||||
synchronized (_lookups) {
|
||||
for (Iterator<Map.Entry<String, ProjectLookup>> it = _lookups.entrySet().iterator(); it.hasNext(); ) {
|
||||
Map.Entry<String, ProjectLookup> entry = it.next();
|
||||
ProjectLookup lookup = entry.getValue();
|
||||
if (lookup.targetProjectID == projectID) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void flushLookupsInvolvingProjectColumn(long projectID, String columnName) {
|
||||
synchronized (_lookups) {
|
||||
for (Iterator<Map.Entry<String, ProjectLookup>> it = _lookups.entrySet().iterator(); it.hasNext(); ) {
|
||||
Map.Entry<String, ProjectLookup> entry = it.next();
|
||||
ProjectLookup lookup = entry.getValue();
|
||||
if (lookup.targetProjectID == projectID && lookup.targetColumnName.equals(columnName)) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void computeLookup(ProjectLookup lookup) throws LookupException {
|
||||
if (lookup.targetProjectID < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Project targetProject = ProjectManager.singleton.getProject(lookup.targetProjectID);
|
||||
ProjectMetadata targetProjectMetadata = ProjectManager.singleton.getProjectMetadata(lookup.targetProjectID);
|
||||
if (targetProject == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Column targetColumn = targetProject.columnModel.getColumnByName(lookup.targetColumnName);
|
||||
if (targetColumn == null) {
|
||||
throw new LookupException("Unable to find column " + lookup.targetColumnName + " in project " + targetProjectMetadata.getName());
|
||||
}
|
||||
|
||||
// We can't use for-each here, because we'll need the row index when creating WrappedRow
|
||||
int count = targetProject.rows.size();
|
||||
for (int r = 0; r < count; r++) {
|
||||
Row targetRow = targetProject.rows.get(r);
|
||||
Object value = targetRow.getCellValue(targetColumn.getCellIndex());
|
||||
if (ExpressionUtils.isNonBlankData(value)) {
|
||||
lookup.valueToRowIndices.putIfAbsent(value, new ArrayList<>());
|
||||
lookup.valueToRowIndices.get(value).add(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static public class ProjectLookup {
|
||||
|
||||
final public long targetProjectID;
|
||||
final public String targetColumnName;
|
||||
|
||||
final public Map<Object, List<Integer>> valueToRowIndices = new HashMap<>();
|
||||
|
||||
ProjectLookup(long targetProjectID, String targetColumnName) {
|
||||
this.targetProjectID = targetProjectID;
|
||||
this.targetColumnName = targetColumnName;
|
||||
}
|
||||
|
||||
public HasFieldsListImpl getRows(Object value) {
|
||||
if (ExpressionUtils.isNonBlankData(value) && valueToRowIndices.containsKey(value)) {
|
||||
Project targetProject = ProjectManager.singleton.getProject(targetProjectID);
|
||||
if (targetProject != null) {
|
||||
HasFieldsListImpl rows = new HasFieldsListImpl();
|
||||
for (Integer r : valueToRowIndices.get(value)) {
|
||||
Row row = targetProject.rows.get(r);
|
||||
rows.add(new WrappedRow(targetProject, r, row));
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -84,9 +84,9 @@ public abstract class ProjectManager {
|
||||
final static Logger logger = LoggerFactory.getLogger("ProjectManager");
|
||||
|
||||
/**
|
||||
* What caches the joins between projects.
|
||||
* What caches the lookups of projects.
|
||||
*/
|
||||
transient protected InterProjectModel _interProjectModel = new InterProjectModel();
|
||||
transient protected LookupCacheManager _lookupCacheManager = new LookupCacheManager();
|
||||
|
||||
/**
|
||||
* Flag for heavy operations like creating or importing projects. Workspace saves are skipped while it's set.
|
||||
@ -345,14 +345,13 @@ public abstract class ProjectManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the InterProjectModel from memory
|
||||
* Gets the LookupCacheManager from memory
|
||||
*/
|
||||
@JsonIgnore
|
||||
public InterProjectModel getInterProjectModel() {
|
||||
return _interProjectModel;
|
||||
public LookupCacheManager getLookupCacheManager() {
|
||||
return _lookupCacheManager;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the project metadata from memory
|
||||
* Requires that the metadata has already been loaded from the data store
|
||||
|
@ -35,73 +35,62 @@ package com.google.refine.expr.functions;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import com.google.refine.InterProjectModel.ProjectJoin;
|
||||
import com.google.refine.LookupCacheManager.ProjectLookup;
|
||||
import com.google.refine.ProjectManager;
|
||||
import com.google.refine.expr.EvalError;
|
||||
import com.google.refine.expr.WrappedCell;
|
||||
import com.google.refine.grel.ControlFunctionRegistry;
|
||||
import com.google.refine.grel.Function;
|
||||
import com.google.refine.model.Project;
|
||||
import com.google.refine.util.GetProjectIDException;
|
||||
import com.google.refine.util.JoinException;
|
||||
import com.google.refine.util.LookupException;
|
||||
|
||||
public class Cross implements Function {
|
||||
|
||||
|
||||
@Override
|
||||
public Object call(Properties bindings, Object[] args) {
|
||||
if (args.length == 3) {
|
||||
// 1st argument can take either value or cell(for backward compatibility)
|
||||
Object v = args[0];
|
||||
Object toProjectName = args[1];
|
||||
Object toColumnName = args[2];
|
||||
Long toProjectID;
|
||||
ProjectJoin join;
|
||||
|
||||
if (v != null &&
|
||||
( v instanceof String || v instanceof WrappedCell ) &&
|
||||
toProjectName != null && toProjectName instanceof String &&
|
||||
toColumnName != null && toColumnName instanceof String) {
|
||||
Object targetProjectName = args[1];
|
||||
Object targetColumnName = args[2];
|
||||
long targetProjectID;
|
||||
ProjectLookup lookup;
|
||||
|
||||
if (v != null &&
|
||||
(v instanceof String || v instanceof WrappedCell) &&
|
||||
targetProjectName != null && targetProjectName instanceof String &&
|
||||
targetColumnName != null && targetColumnName instanceof String) {
|
||||
try {
|
||||
toProjectID = ProjectManager.singleton.getProjectID((String) toProjectName);
|
||||
} catch (GetProjectIDException e){
|
||||
targetProjectID = ProjectManager.singleton.getProjectID((String) targetProjectName);
|
||||
} catch (GetProjectIDException e) {
|
||||
return new EvalError(e.getMessage());
|
||||
}
|
||||
// add a try/catch here - error should bubble up from getInterProjectModel.computeJoin once that's modified
|
||||
|
||||
try {
|
||||
join = ProjectManager.singleton.getInterProjectModel().getJoin(
|
||||
// getJoin(Long fromProject, String fromColumn, Long toProject, String toColumn) {
|
||||
// source project name
|
||||
(Long) ((Project) bindings.get("project")).id,
|
||||
// source column name
|
||||
(String) bindings.get("columnName"),
|
||||
// target project name
|
||||
toProjectID,
|
||||
// target column name
|
||||
(String) toColumnName
|
||||
);
|
||||
} catch (JoinException e) {
|
||||
lookup = ProjectManager.singleton.getLookupCacheManager().getLookup(targetProjectID, (String) targetColumnName);
|
||||
} catch (LookupException e) {
|
||||
return new EvalError(e.getMessage());
|
||||
}
|
||||
if(v instanceof String) {
|
||||
return join.getRows(v);
|
||||
if (v instanceof String) {
|
||||
return lookup.getRows(v);
|
||||
} else {
|
||||
return join.getRows(((WrappedCell) v).cell.value);
|
||||
return lookup.getRows(((WrappedCell) v).cell.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects a string or cell, a project name to join with, and a column name in that project");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "join with another project by column";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getParams() {
|
||||
return "cell c or string value, string projectName, string columnName";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getReturns() {
|
||||
return "array";
|
||||
|
@ -45,7 +45,6 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.google.refine.InterProjectModel;
|
||||
import com.google.refine.model.recon.ReconConfig;
|
||||
import com.google.refine.util.ParsingUtilities;
|
||||
|
||||
@ -122,8 +121,8 @@ public class Column {
|
||||
* <p>
|
||||
* If you are modifying something that requires this to be called, you
|
||||
* probably also need to call
|
||||
* {@link InterProjectModel#flushJoinsInvolvingProjectColumn(long, String)}.
|
||||
* e.g. ProjectManager.singleton.getInterProjectModel().flushJoinsInvolvingProjectColumn(project.id, column.getName())
|
||||
* {@link com.google.refine.LookupCacheManager#flushLookupsInvolvingProjectColumn(long, String)}
|
||||
* e.g. ProjectManager.singleton.getLookupCacheManager().flushLookupsInvolvingProjectColumn(project.id, column.getName())
|
||||
*/
|
||||
public void clearPrecomputes() {
|
||||
if (_precomputes != null) {
|
||||
|
@ -105,7 +105,7 @@ public class Project {
|
||||
logger.warn("Error signaling overlay model before disposing", e);
|
||||
}
|
||||
}
|
||||
ProjectManager.singleton.getInterProjectModel().flushJoinsInvolvingProject(this.id);
|
||||
ProjectManager.singleton.getLookupCacheManager().flushLookupsInvolvingProject(this.id);
|
||||
// The rest of the project should get garbage collected when we return.
|
||||
}
|
||||
|
||||
|
@ -64,7 +64,7 @@ public class CellChange implements Change {
|
||||
|
||||
Column column = project.columnModel.getColumnByCellIndex(cellIndex);
|
||||
column.clearPrecomputes();
|
||||
ProjectManager.singleton.getInterProjectModel().flushJoinsInvolvingProjectColumn(project.id, column.getName());
|
||||
ProjectManager.singleton.getLookupCacheManager().flushLookupsInvolvingProjectColumn(project.id, column.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -73,7 +73,7 @@ public class CellChange implements Change {
|
||||
|
||||
Column column = project.columnModel.getColumnByCellIndex(cellIndex);
|
||||
column.clearPrecomputes();
|
||||
ProjectManager.singleton.getInterProjectModel().flushJoinsInvolvingProjectColumn(project.id, column.getName());
|
||||
ProjectManager.singleton.getLookupCacheManager().flushLookupsInvolvingProjectColumn(project.id, column.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -55,7 +55,7 @@ public class ColumnRenameChange extends ColumnChange {
|
||||
@Override
|
||||
public void apply(Project project) {
|
||||
synchronized (project) {
|
||||
ProjectManager.singleton.getInterProjectModel().flushJoinsInvolvingProjectColumn(project.id, _oldColumnName);
|
||||
ProjectManager.singleton.getLookupCacheManager().flushLookupsInvolvingProjectColumn(project.id, _oldColumnName);
|
||||
project.columnModel.getColumnByName(_oldColumnName).setName(_newColumnName);
|
||||
project.columnModel.update();
|
||||
}
|
||||
@ -64,7 +64,7 @@ public class ColumnRenameChange extends ColumnChange {
|
||||
@Override
|
||||
public void revert(Project project) {
|
||||
synchronized (project) {
|
||||
ProjectManager.singleton.getInterProjectModel().flushJoinsInvolvingProjectColumn(project.id, _newColumnName);
|
||||
ProjectManager.singleton.getLookupCacheManager().flushLookupsInvolvingProjectColumn(project.id, _newColumnName);
|
||||
project.columnModel.getColumnByName(_newColumnName).setName(_oldColumnName);
|
||||
project.columnModel.update();
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ public class ColumnSplitChange implements Change {
|
||||
project.columnModel.allocateNewCellIndex();
|
||||
}
|
||||
|
||||
ProjectManager.singleton.getInterProjectModel().flushJoinsInvolvingProjectColumn(project.id, _columnName);
|
||||
ProjectManager.singleton.getLookupCacheManager().flushLookupsInvolvingProjectColumn(project.id, _columnName);
|
||||
_column = project.columnModel.getColumnByName(_columnName);
|
||||
_columnIndex = project.columnModel.getColumnIndexByName(_columnName);
|
||||
|
||||
@ -240,7 +240,7 @@ public class ColumnSplitChange implements Change {
|
||||
|
||||
for (int i = 0; i < _columnNames.size(); i++) {
|
||||
project.columnModel.columns.remove(_columnIndex + 1);
|
||||
ProjectManager.singleton.getInterProjectModel().flushJoinsInvolvingProjectColumn(project.id, _columnNames.get(i));
|
||||
ProjectManager.singleton.getLookupCacheManager().flushLookupsInvolvingProjectColumn(project.id, _columnNames.get(i));
|
||||
}
|
||||
|
||||
project.columnModel.columnGroups.clear();
|
||||
|
@ -94,7 +94,7 @@ public class MassCellChange implements Change {
|
||||
if (_commonColumnName != null) {
|
||||
Column column = project.columnModel.getColumnByName(_commonColumnName);
|
||||
column.clearPrecomputes();
|
||||
ProjectManager.singleton.getInterProjectModel().flushJoinsInvolvingProjectColumn(project.id, _commonColumnName);
|
||||
ProjectManager.singleton.getLookupCacheManager().flushLookupsInvolvingProjectColumn(project.id, _commonColumnName);
|
||||
}
|
||||
|
||||
if (_updateRowContextDependencies) {
|
||||
@ -115,7 +115,7 @@ public class MassCellChange implements Change {
|
||||
if (_commonColumnName != null) {
|
||||
Column column = project.columnModel.getColumnByName(_commonColumnName);
|
||||
column.clearPrecomputes();
|
||||
ProjectManager.singleton.getInterProjectModel().flushJoinsInvolvingProjectColumn(project.id, _commonColumnName);
|
||||
ProjectManager.singleton.getLookupCacheManager().flushLookupsInvolvingProjectColumn(project.id, _commonColumnName);
|
||||
}
|
||||
|
||||
if (_updateRowContextDependencies) {
|
||||
|
@ -82,7 +82,7 @@ public class MassReconChange implements Change {
|
||||
// skip the flushing if already done
|
||||
String columnName = project.columnModel.getColumnByCellIndex(c).getName();
|
||||
if (!flushedColumn.contains(columnName)) {
|
||||
ProjectManager.singleton.getInterProjectModel().flushJoinsInvolvingProjectColumn(project.id,
|
||||
ProjectManager.singleton.getLookupCacheManager().flushLookupsInvolvingProjectColumn(project.id,
|
||||
columnName);
|
||||
flushedColumn.add(columnName);
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ public class MassRowChange implements Change {
|
||||
project.rows.addAll(_newRows);
|
||||
|
||||
project.columnModel.clearPrecomputes();
|
||||
ProjectManager.singleton.getInterProjectModel().flushJoinsInvolvingProject(project.id);
|
||||
ProjectManager.singleton.getLookupCacheManager().flushLookupsInvolvingProject(project.id);
|
||||
|
||||
project.update();
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ public class MassRowColumnChange implements Change {
|
||||
project.rows.clear();
|
||||
project.rows.addAll(_newRows);
|
||||
|
||||
ProjectManager.singleton.getInterProjectModel().flushJoinsInvolvingProject(project.id);
|
||||
ProjectManager.singleton.getLookupCacheManager().flushLookupsInvolvingProject(project.id);
|
||||
|
||||
project.update();
|
||||
}
|
||||
@ -99,7 +99,7 @@ public class MassRowColumnChange implements Change {
|
||||
project.rows.clear();
|
||||
project.rows.addAll(_oldRows);
|
||||
|
||||
ProjectManager.singleton.getInterProjectModel().flushJoinsInvolvingProject(project.id);
|
||||
ProjectManager.singleton.getLookupCacheManager().flushLookupsInvolvingProject(project.id);
|
||||
|
||||
project.update();
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ public class ReconChange extends MassCellChange {
|
||||
column.setReconStats(_newReconStats);
|
||||
|
||||
column.clearPrecomputes();
|
||||
ProjectManager.singleton.getInterProjectModel().flushJoinsInvolvingProjectColumn(project.id, _commonColumnName);
|
||||
ProjectManager.singleton.getLookupCacheManager().flushLookupsInvolvingProjectColumn(project.id, _commonColumnName);
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,7 +123,7 @@ public class ReconChange extends MassCellChange {
|
||||
column.setReconStats(_oldReconStats);
|
||||
|
||||
column.clearPrecomputes();
|
||||
ProjectManager.singleton.getInterProjectModel().flushJoinsInvolvingProjectColumn(project.id, _commonColumnName);
|
||||
ProjectManager.singleton.getLookupCacheManager().flushLookupsInvolvingProjectColumn(project.id, _commonColumnName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ public class RowRemovalChange implements Change {
|
||||
}
|
||||
|
||||
project.columnModel.clearPrecomputes();
|
||||
ProjectManager.singleton.getInterProjectModel().flushJoinsInvolvingProject(project.id);
|
||||
ProjectManager.singleton.getLookupCacheManager().flushLookupsInvolvingProject(project.id);
|
||||
|
||||
project.update();
|
||||
}
|
||||
|
@ -1,53 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019, Owen Stephens
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* The name of the contributor may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
package com.google.refine.util;
|
||||
|
||||
/**
|
||||
* Thrown when there is an error on a project Join.
|
||||
*/
|
||||
public class JoinException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 1553348086L;
|
||||
|
||||
/**
|
||||
* Default JoinException format exception.
|
||||
*/
|
||||
public JoinException() { super(); }
|
||||
|
||||
/**
|
||||
* JoinException exception.
|
||||
*
|
||||
* @param message error message
|
||||
*/
|
||||
public JoinException(String message) { super(message); }
|
||||
}
|
19
main/src/com/google/refine/util/LookupException.java
Normal file
19
main/src/com/google/refine/util/LookupException.java
Normal file
@ -0,0 +1,19 @@
|
||||
package com.google.refine.util;
|
||||
|
||||
/**
|
||||
* Thrown when there is an error on a project lookup.
|
||||
*/
|
||||
public class LookupException extends Exception {
|
||||
|
||||
/**
|
||||
* Default LookupException format exception.
|
||||
*/
|
||||
public LookupException() { super(); }
|
||||
|
||||
/**
|
||||
* LookupException exception.
|
||||
*
|
||||
* @param message error message
|
||||
*/
|
||||
public LookupException(String message) { super(message); }
|
||||
}
|
@ -133,7 +133,29 @@ public class CrossTests extends RefineTest {
|
||||
Assert.assertEquals(((EvalError) invoke("cross", "mary", projectName, nonExistentColumn)).message,
|
||||
"Unable to find column " + nonExistentColumn + " in project " + projectName);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void crossFunctionSameColumnTest() throws Exception {
|
||||
Project project = (Project) bindings.get("project");
|
||||
Cell c = project.rows.get(0).cells.get(1);
|
||||
WrappedCell lookup = new WrappedCell(project, "recipient", c);
|
||||
Row row = ((Row)((WrappedRow) ((HasFieldsListImpl) invoke("cross", lookup, "My Address Book", "friend")).get(0)).row);
|
||||
String address = row.getCell(1).value.toString();
|
||||
Assert.assertEquals(address, "50 Broadway Ave.");
|
||||
}
|
||||
|
||||
@Test
|
||||
// cross result shouldn't depend on the based column in "bindings" when the first argument is a WrappedCell instance
|
||||
public void crossFunctionDifferentColumnTest() throws Exception {
|
||||
Project project = (Project) bindings.get("project");
|
||||
bindings.put("columnName", "gift"); // change the based column
|
||||
Cell c = project.rows.get(0).cells.get(1);
|
||||
WrappedCell lookup = new WrappedCell(project, "recipient", c);
|
||||
Row row = ((Row)((WrappedRow) ((HasFieldsListImpl) invoke("cross", lookup, "My Address Book", "friend")).get(0)).row);
|
||||
String address = row.getCell(1).value.toString();
|
||||
Assert.assertEquals(address, "50 Broadway Ave.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void crossFunctionOneToOneTest() throws Exception {
|
||||
Row row = ((Row)((WrappedRow) ((HasFieldsListImpl) invoke("cross", "mary", "My Address Book", "friend")).get(0)).row);
|
||||
|
Loading…
Reference in New Issue
Block a user