Skip to content
99 changes: 97 additions & 2 deletions api/src/org/labkey/api/data/CompareType.java
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,39 @@ protected Collection getCollectionParam(Object value)
* <xsd:enumeration value="arrayisempty"/>
* <xsd:enumeration value="arrayisnotempty"/>
*/


public static final CompareType ARRAY_IS_EMPTY = new CompareType("Is Empty", "arrayisempty", "ARRAYISEMPTY", false, null, OperatorType.ARRAYISEMPTY)
{
@Override
public ArrayIsEmptyClause createFilterClause(@NotNull FieldKey fieldKey, Object value)
{
return new ArrayIsEmptyClause(fieldKey);
}

@Override
public boolean meetsCriteria(ColumnRenderProperties col, Object value, Object[] filterValues)
{
throw new UnsupportedOperationException("Conditional formatting not yet supported for Multi Choices");
}
};


public static final CompareType ARRAY_IS_NOT_EMPTY = new CompareType("Is Not Empty", "arrayisnotempty", "ARRAYISNOTEMPTY", false, null, OperatorType.ARRAYISNOTEMPTY)
{
@Override
public ArrayIsEmptyClause createFilterClause(@NotNull FieldKey fieldKey, Object value)
{
return new ArrayIsNotEmptyClause(fieldKey);
}

@Override
public boolean meetsCriteria(ColumnRenderProperties col, Object value, Object[] filterValues)
{
throw new UnsupportedOperationException("Conditional formatting not yet supported for Multi Choices");
}
};

public static final CompareType ARRAY_CONTAINS_ALL = new CompareType("Contains All", "arraycontainsall", "ARRAYCONTAINSALL", true, null, OperatorType.ARRAYCONTAINSALL)
{
@Override
Expand Down Expand Up @@ -934,7 +967,7 @@ public String getValueSeparator()

public static abstract class ArrayClause extends SimpleFilter.MultiValuedFilterClause
{
public static final String ARRAY_VALUE_SEPARATOR = ",";
public static final String ARRAY_VALUE_SEPARATOR = ";";

public ArrayClause(@NotNull FieldKey fieldKey, CompareType comparison, Collection<?> params, boolean negated)
{
Expand All @@ -958,7 +991,7 @@ public SQLFragment[] getParamSQLFragments(SqlDialect dialect)
}

for (int i = 0; i < params.length; i++)
fragments[i] = new SQLFragment().append(escapeLabKeySqlValue(params[i], type));
fragments[i] = SQLFragment.unsafe(escapeLabKeySqlValue(params[i], type));

return fragments;
}
Expand All @@ -981,6 +1014,68 @@ public Pair<SQLFragment, SQLFragment> getSqlFragments(Map<FieldKey, ? extends Co

}

private static class ArrayIsEmptyClause extends ArrayClause
{
public ArrayIsEmptyClause(@NotNull FieldKey fieldKey, CompareType comparison, boolean negated)
{
super(fieldKey, comparison, null, negated);
}

public ArrayIsEmptyClause(@NotNull FieldKey fieldKey)
{
this(fieldKey, CompareType.ARRAY_IS_EMPTY, false);
}

@Override
public SQLFragment toSQLFragment(Map<FieldKey, ? extends ColumnInfo> columnMap, SqlDialect dialect)
{
ColumnInfo colInfo = columnMap != null ? columnMap.get(_fieldKey) : null;
var alias = SimpleFilter.getAliasForColumnFilter(dialect, colInfo, _fieldKey);

SQLFragment columnFragment = new SQLFragment().appendIdentifier(alias);

SQLFragment sql = dialect.array_is_empty(columnFragment);
if (!_negated)
return sql;
return new SQLFragment(" NOT (").append(sql).append(")");
}

@Override
public String getLabKeySQLWhereClause(Map<FieldKey, ? extends ColumnInfo> columnMap)
{
return "array_is_empty(" + getLabKeySQLColName(_fieldKey) + ")";
}

@Override
public void appendFilterText(StringBuilder sb, ColumnNameFormatter formatter)
{
sb.append("is empty");
}

}

private static class ArrayIsNotEmptyClause extends ArrayIsEmptyClause
{

public ArrayIsNotEmptyClause(@NotNull FieldKey fieldKey)
{
super(fieldKey, CompareType.ARRAY_IS_NOT_EMPTY, true);
}

@Override
public String getLabKeySQLWhereClause(Map<FieldKey, ? extends ColumnInfo> columnMap)
{
return "NOT array_is_empty(" + getLabKeySQLColName(_fieldKey) + ")";
}

@Override
public void appendFilterText(StringBuilder sb, ColumnNameFormatter formatter)
{
sb.append("is not empty");
}

}

private static class ArrayContainsAllClause extends ArrayClause
{

Expand Down
2 changes: 1 addition & 1 deletion api/src/org/labkey/api/data/SimpleFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -620,7 +620,7 @@ public static abstract class MultiValuedFilterClause extends CompareType.Abstrac
public MultiValuedFilterClause(@NotNull FieldKey fieldKey, CompareType comparison, Collection<?> params, boolean negated)
{
super(fieldKey);
params = new ArrayList<>(params); // possibly immutable
params = params == null ? new ArrayList<>() : new ArrayList<>(params); // possibly immutable
if (params.contains(null)) //params.size() == 0 ||
{
_includeNull = true;
Expand Down
12 changes: 12 additions & 0 deletions api/src/org/labkey/api/data/TableChange.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.labkey.api.data.PropertyStorageSpec.Index;
import org.labkey.api.data.TableInfo.IndexDefinition;
import org.labkey.api.exp.PropertyDescriptor;
import org.labkey.api.exp.PropertyType;
import org.labkey.api.exp.property.Domain;
import org.labkey.api.exp.property.DomainKind;
import org.labkey.api.util.logging.LogHelper;
Expand Down Expand Up @@ -58,6 +59,7 @@ public class TableChange
private Collection<Constraint> _constraints;
private Set<String> _indicesToBeDroppedByName;
private IndexSizeMode _sizeMode = IndexSizeMode.Auto;
private Map<String, PropertyType> _oldPropTypes;

/** In most cases, domain knows the storage table name **/
public TableChange(Domain domain, ChangeType changeType)
Expand Down Expand Up @@ -329,6 +331,11 @@ public void setForeignKeys(Collection<PropertyStorageSpec.ForeignKey> foreignKey
_foreignKeys = foreignKeys;
}

public Map<String, PropertyType> getOldPropTypes()
{
return _oldPropTypes;
}

public final List<PropertyStorageSpec> toSpecs(Collection<String> columnNames)
{
final Domain domain = _domain;
Expand All @@ -349,6 +356,11 @@ public final List<PropertyStorageSpec> toSpecs(Collection<String> columnNames)
.collect(Collectors.toList());
}

public void setOldPropertyTypes(Map<String, PropertyType> oldPropTypes)
{
_oldPropTypes = oldPropTypes;
}
Comment on lines +359 to +362
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate method definition. The method setOldPropertyTypes is defined twice in this class - once at lines 339-342 as setOldPropTypes and again at lines 364-367 as setOldPropertyTypes. Remove one of these duplicate methods.

Copilot uses AI. Check for mistakes.

public enum ChangeType
{
CreateTable,
Expand Down
6 changes: 6 additions & 0 deletions api/src/org/labkey/api/data/dialect/SqlDialect.java
Original file line number Diff line number Diff line change
Expand Up @@ -2200,6 +2200,12 @@ public SQLFragment array_construct(SQLFragment[] elements)
throw new UnsupportedOperationException(getClass().getSimpleName() + " does not implement");
}

public SQLFragment array_is_empty(SQLFragment a)
{
assert !supportsArrays();
throw new UnsupportedOperationException(getClass().getSimpleName() + " does not implement");
}

// element a is in array b
public SQLFragment element_in_array(SQLFragment a, SQLFragment b)
{
Expand Down
6 changes: 3 additions & 3 deletions api/src/org/labkey/api/query/AbstractQueryChangeListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ public void queryCreated(User user, Container container, ContainerFilter scope,
protected abstract void queryCreated(User user, Container container, ContainerFilter scope, SchemaKey schema, String query);

@Override
public void queryChanged(User user, Container container, ContainerFilter scope, SchemaKey schema, @NotNull QueryProperty property, @NotNull Collection<QueryPropertyChange<?>> changes)
public void queryChanged(User user, Container container, ContainerFilter scope, SchemaKey schema, String queryName, @NotNull QueryProperty property, @NotNull Collection<QueryPropertyChange<?>> changes)
{
for (QueryPropertyChange<?> change : changes)
queryChanged(user, container, scope, schema, change);
queryChanged(user, container, scope, schema, queryName, change);
}

protected abstract void queryChanged(User user, Container container, ContainerFilter scope, SchemaKey schema, QueryPropertyChange<?> change);
protected abstract void queryChanged(User user, Container container, ContainerFilter scope, SchemaKey schema, String queryName, QueryPropertyChange<?> change);

@Override
public void queryDeleted(User user, Container container, ContainerFilter scope, SchemaKey schema, @NotNull Collection<String> queries)
Expand Down
Loading