Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
a066d53
Support field type conversion for Multi Choice fields
XingY Jan 22, 2026
fc22b72
crlf
XingY Jan 22, 2026
cbb199b
Port Is empty filter changes from fb_mvtc_empty branch
XingY Jan 23, 2026
98f19f2
fix display
XingY Jan 24, 2026
beefa2a
Merge remote-tracking branch 'origin/develop' into fb_mvtc_convert
XingY Jan 25, 2026
9fa7270
Handle special characters
XingY Jan 26, 2026
e717afa
Merge remote-tracking branch 'origin/develop' into fb_mvtc_convert
XingY Jan 26, 2026
4c4d519
clean
XingY Jan 27, 2026
b8a163d
Merge remote-tracking branch 'origin/develop' into fb_mvtc_convert
XingY Jan 27, 2026
5a79008
Merge remote-tracking branch 'origin/develop' into fb_mvtc_convert
XingY Jan 28, 2026
6d55319
merge from develop
XingY Jan 28, 2026
002fe51
Merge branch 'develop' into fb_mvtc_convert
labkey-danield Jan 29, 2026
1837728
Merge remote-tracking branch 'origin/develop' into fb_mvtc_convert
XingY Jan 30, 2026
0674ec9
fix column name with space
XingY Jan 30, 2026
4273019
fix schema name
XingY Jan 30, 2026
3bb0c5f
fix encoding
XingY Jan 30, 2026
f6a4e81
merge from develop
XingY Feb 1, 2026
d205e32
Enable MVTC fields in sample finder. Remove experimental flag
XingY Feb 1, 2026
6aa0ee7
crlf
XingY Feb 2, 2026
e75c688
skip sql server
XingY Feb 2, 2026
dc1bd5d
merge from develop
XingY Feb 3, 2026
4934b5e
Switch to use columnInfo.convert
XingY Feb 3, 2026
2a293ed
Code review changes
XingY Feb 3, 2026
daff069
Fix type
XingY Feb 3, 2026
e3d9a7c
Fix biologics vector selection BiologicsAPITest.setVectorAliasViaLega…
XingY Feb 4, 2026
646a3bf
Fix dataclass update
XingY Feb 4, 2026
4e66d33
bug fixes
XingY Feb 5, 2026
79863e8
fix date format in name expression
XingY Feb 5, 2026
bd11124
bug fixes
XingY Feb 5, 2026
4a5a3e1
merge from develop
XingY Feb 5, 2026
901cd43
bug fixes: natural sorting with upper case first, remove default valu…
XingY Feb 6, 2026
c34f952
Disallow multi choice
XingY Feb 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions api/src/org/labkey/api/data/CompareType.java
Original file line number Diff line number Diff line change
Expand Up @@ -966,7 +966,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 @@ -990,7 +990,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 Down
2 changes: 1 addition & 1 deletion api/src/org/labkey/api/data/DataColumn.java
Original file line number Diff line number Diff line change
Expand Up @@ -750,7 +750,7 @@ private void renderSelectFormInput(HtmlWriter out, String formFieldName, Object
List<OptionBuilder.Option> options = new ArrayList<>();

// add empty option
if (!isMultiple)
if (!_boundColumn.isRequired() || !isMultiple)
options.add(new OptionBuilder().build());

Set<String> selectedValues = strValues.isEmpty() ? Set.of() :
Expand Down
3 changes: 3 additions & 0 deletions api/src/org/labkey/api/data/ExcelCellUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

/**
* This is a utility class that contains the necessary methods for writing properly formatted values to Excel cells.
Expand Down Expand Up @@ -68,6 +69,8 @@ else if (Boolean.class.isAssignableFrom(valueClass) || Boolean.TYPE.isAssignable
return TYPE_BOOLEAN;
else if (File.class.isAssignableFrom(valueClass))
return TYPE_FILE;
else if (List.class.isAssignableFrom(valueClass) || valueClass.isArray())
return TYPE_MULTILINE_STRING;
else
{
return TYPE_UNKNOWN;
Expand Down
3 changes: 2 additions & 1 deletion api/src/org/labkey/api/data/MultiChoice.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import static org.labkey.api.util.DOM.DIV;
import static org.labkey.api.util.DOM.SPAN;
import static org.labkey.api.util.DOM.at;
import static org.labkey.api.util.SortHelpers.CASE_INSENSITIVE_UPPERCASE_FIRST;

public class MultiChoice
{
Expand Down Expand Up @@ -213,7 +214,7 @@ public static class Array implements List<String>, java.sql.Array

protected Array(Stream<Object> str)
{
TreeSet<String> setCaseSensitive = new TreeSet<>();
TreeSet<String> setCaseSensitive = new TreeSet<>(CASE_INSENSITIVE_UPPERCASE_FIRST);
str.filter(Objects::nonNull)
.map(s -> StringUtils.trimToNull(s.toString()))
.filter(Objects::nonNull)
Expand Down
7 changes: 7 additions & 0 deletions api/src/org/labkey/api/data/MultiValuedRenderContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.apache.commons.collections4.iterators.ArrayIterator;
import org.junit.Assert;
import org.junit.Test;
import org.labkey.api.exp.PropertyType;
import org.labkey.api.query.FieldKey;

import java.util.HashMap;
Expand Down Expand Up @@ -113,6 +114,12 @@ public Object get(Object key)
if (getFieldMap() != null)
{
ColumnInfo columnInfo = getFieldMap().get(key);
if (columnInfo != null && columnInfo.getPropertyType() == PropertyType.MULTI_CHOICE && value instanceof String strVal)
{
// Multi-choice values array is converted to string: "{value1,value2,...}", so strip off the braces before converting
Copy link
Contributor

Choose a reason for hiding this comment

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

Are these comma separated or semi-colon separated?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This '{a, b}' format is what's returned by MVFK when casting array to string array_to_string(core.sort(array_agg(field))). @labkey-matthewb did mention possibly have MVFK to return ARRAY[] instead of string for the array type columns in the future.

if (strVal.startsWith("{") && strVal.endsWith("}"))
return columnInfo.convert(strVal.substring(1, strVal.length() - 1));
}
// The value was concatenated with others, so it's become a string.
// Do conversion to switch it back to the expected type.
if (value != null && columnInfo != null && !columnInfo.getJavaClass().isInstance(value))
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
9 changes: 7 additions & 2 deletions api/src/org/labkey/api/exp/property/DomainUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -436,8 +436,6 @@ public static boolean allowMultiChoice(DomainKind<?> kind)
{
if (!kind.allowMultiChoiceProperties())
return false;
if (!OptionalFeatureService.get().isFeatureEnabled(AppProps.MULTI_VALUE_TEXT_CHOICE))
return false;
return CoreSchema.getInstance().getSqlDialect().isPostgreSQL();
}

Expand Down Expand Up @@ -1446,6 +1444,7 @@ public static ValidationException validateProperties(@Nullable Domain domain, @N
ValidationException exception = new ValidationException();
Map<Integer, String> propertyIdNameMap = getOriginalFieldPropertyIdNameMap(orig);//key: orig property id, value : orig field name

boolean allowMultiChoice = domainKind != null ? domainKind.allowMultiChoiceProperties() : updates.isAllowMultiChoiceProperties();
for (GWTPropertyDescriptor field : updates.getFields(true))
{
String name = field.getName();
Expand All @@ -1461,6 +1460,12 @@ public static ValidationException validateProperties(@Nullable Domain domain, @N
exception.addError(new SimpleValidationError(getDomainErrorMessage(updates, "The field name '" + name + "' is not allowed.")));
}

if (!allowMultiChoice && PropertyType.MULTI_CHOICE.getTypeUri().equals(field.getRangeURI()))
{
exception.addError(new SimpleValidationError(getDomainErrorMessage(updates, "The field '" + name + "' does not support multiple values.")));
continue;
}

Matcher expMatcher = SUBSTITUTION_EXP_PATTERN.matcher(name);
if (expMatcher.find())
{
Expand Down
70 changes: 0 additions & 70 deletions api/src/org/labkey/api/query/AbstractQueryChangeListener.java

This file was deleted.

4 changes: 2 additions & 2 deletions api/src/org/labkey/api/query/DefaultQueryUpdateService.java
Original file line number Diff line number Diff line change
Expand Up @@ -780,7 +780,7 @@ protected boolean validMissingValue(Container c, String mv)

final protected void convertTypes(User user, Container c, Map<String,Object> row) throws ValidationException
{
convertTypes(user, c, row, getDbTable(), null);
convertTypes(user, c, row, getQueryTable(), null);
}

// TODO Path->FileObject
Expand Down Expand Up @@ -826,7 +826,7 @@ else if (null != value)
row.put(col.getMvColumnName().getName(), mv);
}

value = null==value ? null : convertColumnValue(col, value, user, c, fileLinkDirPath);
value = convertColumnValue(col, value, user, c, fileLinkDirPath);
row.put(col.getName(), value);
}
}
Expand Down
Loading